XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/DeathMod

改用专用网络包同步领域斩击特效

3efd867
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

4 个文件 +272 -38
Modified Common/MyPlayer.cs +56 -31
@@ -416,23 +416,38 @@ public class MyPlayer : ModPlayer
416 416 continue;
417 417
418 418 float rotation = Main.rand.NextFloat(MathHelper.TwoPi);
419 int projectileIndex = Projectile.NewProjectile(
420 Player.GetSource_Misc("DeathMod:DeathDomainTelegraph"),
421 target.Center,
422 Vector2.Zero,
423 ModContent.ProjectileType<DeathDomainHarvestTelegraphProjectile>(),
424 0,
425 0f,
426 Player.whoAmI,
427 target.whoAmI,
428 remainingFrames,
429 necklace.SlashCount + visualMastery * 0.1f);
430 if (projectileIndex >= 0 && projectileIndex < Main.maxProjectiles)
419 float scale = MathHelper.Clamp(Math.Max(target.width, target.height) / 52f, 0.85f, 2.4f);
420 int projectileIndex = -1;
421 if (Main.netMode == NetmodeID.Server)
422 {
423 DeathMod.BroadcastDeathDomainTelegraph(
424 Player,
425 target,
426 remainingFrames,
427 necklace.SlashCount,
428 visualMastery,
429 rotation,
430 scale);
431 }
432 else
431 433 {
432 Projectile telegraph = Main.projectile[projectileIndex];
433 telegraph.rotation = rotation;
434 telegraph.scale = MathHelper.Clamp(Math.Max(target.width, target.height) / 52f, 0.85f, 2.4f);
435 SynchronizeDeathDomainVisual(projectileIndex);
434 projectileIndex = Projectile.NewProjectile(
435 Player.GetSource_Misc("DeathMod:DeathDomainTelegraph"),
436 target.Center,
437 Vector2.Zero,
438 ModContent.ProjectileType<DeathDomainHarvestTelegraphProjectile>(),
439 0,
440 0f,
441 Player.whoAmI,
442 target.whoAmI,
443 remainingFrames,
444 necklace.SlashCount + visualMastery * 0.1f);
445 if (projectileIndex >= 0 && projectileIndex < Main.maxProjectiles)
446 {
447 Projectile telegraph = Main.projectile[projectileIndex];
448 telegraph.rotation = rotation;
449 telegraph.scale = scale;
450 }
436 451 }
437 452 deathDomainPendingCuts[target.whoAmI] = new PendingDeathDomainCut(rotation, projectileIndex);
438 453 }
@@ -441,6 +456,9 @@ public class MyPlayer : ModPlayer
441 456 private void SpawnDeathDomainHarvestSlash(NPC target, DeathNecklace necklace, float visualMastery, bool requiem, float rotation)
442 457 {
443 458 int slashDamage = CalculateDeathDomainSlashDamage(target, necklace);
459 float scale = MathHelper.Clamp(Math.Max(target.width, target.height) / 52f, 0.85f, 2.4f);
460 float visualState = visualMastery + (requiem ? 2f : 0f);
461 bool serverController = Main.netMode == NetmodeID.Server;
444 462 int projectileIndex = Projectile.NewProjectile(
445 463 Player.GetSource_Misc("DeathMod:DeathDomain"),
446 464 target.Center,
@@ -451,25 +469,28 @@ public class MyPlayer : ModPlayer
451 469 Player.whoAmI,
452 470 target.whoAmI,
453 471 necklace.SlashCount,
454 visualMastery + (requiem ? 2f : 0f));
472 visualState + (serverController ? 10f : 0f));
455 473 if (projectileIndex < 0 || projectileIndex >= Main.maxProjectiles)
456 474 return;
457 475
458 476 Projectile visual = Main.projectile[projectileIndex];
459 477 visual.rotation = rotation;
460 visual.scale = MathHelper.Clamp(Math.Max(target.width, target.height) / 52f, 0.85f, 2.4f);
461 SynchronizeDeathDomainVisual(projectileIndex);
462 }
463
464 private static void SynchronizeDeathDomainVisual(int projectileIndex)
465 {
466 if (Main.netMode != NetmodeID.Server)
467 return;
468
469 // Domain visuals are short lived, so send the complete state in their spawn
470 // tick rather than waiting for the periodic projectile synchronization pass.
471 NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null, projectileIndex);
472 Main.projectile[projectileIndex].netUpdate = false;
478 visual.scale = scale;
479 if (serverController)
480 {
481 // The server projectile is only a staggered damage scheduler. Clients
482 // receive an explicit, local-only visual through the mod packet below.
483 visual.netUpdate = false;
484 visual.netImportant = false;
485 DeathMod.BroadcastDeathDomainHarvestSlash(
486 Player,
487 target,
488 necklace.SlashCount,
489 visualMastery,
490 requiem,
491 rotation,
492 scale);
493 }
473 494 }
474 495
475 496 private void ClearDeathDomainTelegraphs()
@@ -477,8 +498,11 @@ public class MyPlayer : ModPlayer
477 498 if (deathDomainPendingCuts.Count == 0)
478 499 return;
479 500
480 foreach (PendingDeathDomainCut pending in deathDomainPendingCuts.Values)
501 foreach ((int npcIndex, PendingDeathDomainCut pending) in deathDomainPendingCuts)
502 {
481 503 KillDeathDomainTelegraph(pending.ProjectileIndex);
504 DeathMod.BroadcastDeathDomainTelegraphClear(Player, npcIndex);
505 }
482 506 deathDomainPendingCuts.Clear();
483 507 }
484 508
@@ -487,6 +511,7 @@ public class MyPlayer : ModPlayer
487 511 if (!deathDomainPendingCuts.Remove(npcIndex, out PendingDeathDomainCut pending))
488 512 return;
489 513 KillDeathDomainTelegraph(pending.ProjectileIndex);
514 DeathMod.BroadcastDeathDomainTelegraphClear(Player, npcIndex);
490 515 }
491 516
492 517 private void KillDeathDomainTelegraph(int projectileIndex)
Modified DeathMod.cs +204 -1
@@ -25,7 +25,15 @@ public class DeathMod : Mod
25 25 SyncInventorySlot,
26 26 SyncDeathMark,
27 27 SyncAltarItem,
28 SyncDeathDomainState
28 SyncDeathDomainState,
29 SyncDeathDomainVisual
30 }
31
32 internal enum DeathDomainVisualAction : byte
33 {
34 SpawnTelegraph,
35 SpawnHarvestSlash,
36 ClearTelegraph
29 37 }
30 38
31 39 internal enum OperationResult : byte
@@ -191,6 +199,41 @@ public class DeathMod : Mod
191 199 }
192 200 break;
193 201 }
202 case MessageType.SyncDeathDomainVisual:
203 {
204 DeathDomainVisualAction action = (DeathDomainVisualAction)reader.ReadByte();
205 byte playerIndex = reader.ReadByte();
206 short npcIndex = reader.ReadInt16();
207 Vector2 position = new(reader.ReadSingle(), reader.ReadSingle());
208 float rotation = reader.ReadSingle();
209 float scale = reader.ReadSingle();
210 byte slashCount = reader.ReadByte();
211 float mastery = reader.ReadSingle();
212 short duration = reader.ReadInt16();
213 bool requiem = reader.ReadBoolean();
214 if (Main.netMode == NetmodeID.MultiplayerClient)
215 {
216 if (action == DeathDomainVisualAction.ClearTelegraph)
217 {
218 ClearClientDeathDomainTelegraph(playerIndex, npcIndex);
219 }
220 else
221 {
222 SpawnClientDeathDomainVisual(
223 action,
224 playerIndex,
225 npcIndex,
226 position,
227 rotation,
228 scale,
229 slashCount,
230 mastery,
231 duration,
232 requiem);
233 }
234 }
235 break;
236 }
194 237 default:
195 238 Logger.Warn($"Unknown DeathMod packet: {messageType}");
196 239 break;
@@ -260,6 +303,166 @@ public class DeathMod : Mod
260 303 packet.Send(-1, playerIndex);
261 304 }
262 305
306 internal static void BroadcastDeathDomainTelegraph(
307 Player player,
308 NPC target,
309 int duration,
310 int slashCount,
311 float mastery,
312 float rotation,
313 float scale)
314 {
315 BroadcastDeathDomainVisual(
316 DeathDomainVisualAction.SpawnTelegraph,
317 player.whoAmI,
318 target.whoAmI,
319 target.Center,
320 rotation,
321 scale,
322 slashCount,
323 mastery,
324 duration,
325 requiem: false);
326 }
327
328 internal static void BroadcastDeathDomainHarvestSlash(
329 Player player,
330 NPC target,
331 int slashCount,
332 float mastery,
333 bool requiem,
334 float rotation,
335 float scale)
336 {
337 BroadcastDeathDomainVisual(
338 DeathDomainVisualAction.SpawnHarvestSlash,
339 player.whoAmI,
340 target.whoAmI,
341 target.Center,
342 rotation,
343 scale,
344 slashCount,
345 mastery,
346 duration: 0,
347 requiem);
348 }
349
350 internal static void BroadcastDeathDomainTelegraphClear(Player player, int npcIndex)
351 {
352 BroadcastDeathDomainVisual(
353 DeathDomainVisualAction.ClearTelegraph,
354 player.whoAmI,
355 npcIndex,
356 Vector2.Zero,
357 0f,
358 1f,
359 1,
360 0f,
361 0,
362 requiem: false);
363 }
364
365 private static void BroadcastDeathDomainVisual(
366 DeathDomainVisualAction action,
367 int playerIndex,
368 int npcIndex,
369 Vector2 position,
370 float rotation,
371 float scale,
372 int slashCount,
373 float mastery,
374 int duration,
375 bool requiem)
376 {
377 if (Main.netMode != NetmodeID.Server
378 || playerIndex < 0
379 || playerIndex >= Main.maxPlayers
380 || npcIndex < 0
381 || npcIndex >= Main.maxNPCs)
382 {
383 return;
384 }
385
386 ModPacket packet = ModContent.GetInstance<DeathMod>().GetPacket();
387 packet.Write((byte)MessageType.SyncDeathDomainVisual);
388 packet.Write((byte)action);
389 packet.Write((byte)playerIndex);
390 packet.Write((short)npcIndex);
391 packet.Write(position.X);
392 packet.Write(position.Y);
393 packet.Write(rotation);
394 packet.Write(scale);
395 packet.Write((byte)Math.Clamp(slashCount, 1, 5));
396 packet.Write(MathHelper.Clamp(mastery, 0f, 1f));
397 packet.Write((short)Math.Clamp(duration, 0, short.MaxValue));
398 packet.Write(requiem);
399 packet.Send();
400 }
401
402 private static void SpawnClientDeathDomainVisual(
403 DeathDomainVisualAction action,
404 int playerIndex,
405 int npcIndex,
406 Vector2 position,
407 float rotation,
408 float scale,
409 int slashCount,
410 float mastery,
411 int duration,
412 bool requiem)
413 {
414 if (playerIndex < 0 || playerIndex >= Main.maxPlayers
415 || npcIndex < 0 || npcIndex >= Main.maxNPCs
416 || action is not (DeathDomainVisualAction.SpawnTelegraph or DeathDomainVisualAction.SpawnHarvestSlash))
417 {
418 return;
419 }
420
421 int projectileType = action == DeathDomainVisualAction.SpawnTelegraph
422 ? ModContent.ProjectileType<DeathDomainHarvestTelegraphProjectile>()
423 : ModContent.ProjectileType<DeathDomainHarvestSlashProjectile>();
424 float ai1 = action == DeathDomainVisualAction.SpawnTelegraph
425 ? Math.Max(1, duration)
426 : Math.Clamp(slashCount, 1, 5);
427 float ai2 = action == DeathDomainVisualAction.SpawnTelegraph
428 ? Math.Clamp(slashCount, 1, 5) + MathHelper.Clamp(mastery, 0f, 1f) * 0.1f
429 : MathHelper.Clamp(mastery, 0f, 1f) + (requiem ? 2f : 0f);
430 int projectileIndex = Projectile.NewProjectile(
431 Main.LocalPlayer.GetSource_Misc("DeathMod:NetworkDomainVisual"),
432 position,
433 Vector2.Zero,
434 projectileType,
435 0,
436 0f,
437 Main.myPlayer,
438 npcIndex,
439 ai1,
440 ai2);
441 if (projectileIndex < 0 || projectileIndex >= Main.maxProjectiles)
442 return;
443
444 Projectile visual = Main.projectile[projectileIndex];
445 visual.rotation = rotation;
446 visual.scale = MathHelper.Clamp(scale, 0.5f, 3f);
447 visual.localAI[1] = playerIndex + 1;
448 visual.netUpdate = false;
449 visual.netImportant = false;
450 }
451
452 private static void ClearClientDeathDomainTelegraph(int playerIndex, int npcIndex)
453 {
454 float visualOwnerTag = playerIndex + 1;
455 foreach (Projectile projectile in Main.ActiveProjectiles)
456 {
457 if (projectile.ModProjectile is DeathDomainHarvestTelegraphProjectile
458 && (int)projectile.ai[0] == npcIndex
459 && Math.Abs(projectile.localAI[1] - visualOwnerTag) < 0.1f)
460 {
461 projectile.active = false;
462 }
463 }
464 }
465
263 466 internal static void BroadcastDeathMark(NPC npc, bool marked)
264 467 {
265 468 if (Main.netMode != NetmodeID.Server || npc.whoAmI < 0 || npc.whoAmI >= Main.maxNPCs)
Modified Projectiles/DeathDomainHarvestSlashProjectile.cs +11 -5
@@ -24,8 +24,10 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
24 24
25 25 private int TargetIndex => (int)Projectile.ai[0];
26 26 private int SlashCount => Math.Clamp((int)Projectile.ai[1], 1, MaximumSlashCount);
27 private bool IsRequiem => Projectile.ai[2] >= 2f;
28 private float Mastery => MathHelper.Clamp(IsRequiem ? Projectile.ai[2] - 2f : Projectile.ai[2], 0f, 1f);
27 private bool IsServerController => Projectile.ai[2] >= 10f;
28 private float VisualState => IsServerController ? Projectile.ai[2] - 10f : Projectile.ai[2];
29 private bool IsRequiem => VisualState >= 2f;
30 private float Mastery => MathHelper.Clamp(IsRequiem ? VisualState - 2f : VisualState, 0f, 1f);
29 31 private int TotalLifetime => SlashActiveFrames + (SlashCount - 1) * SlashDelayFrames + EndLingerFrames;
30 32
31 33 public override string Texture => "Terraria/Images/Projectile_0";
@@ -45,7 +47,7 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
45 47 Projectile.ignoreWater = true;
46 48 Projectile.penetrate = -1;
47 49 Projectile.timeLeft = 60;
48 Projectile.netImportant = true;
50 Projectile.netImportant = false;
49 51 }
50 52
51 53 public override void OnSpawn(IEntitySource source)
@@ -74,6 +76,7 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
74 76
75 77 int age = TotalLifetime - Projectile.timeLeft;
76 78 int emittedMask = (int)Projectile.localAI[0];
79 bool createClientEffects = !Main.dedServ && !IsServerController;
77 80 for (int slash = 0; slash < SlashCount; slash++)
78 81 {
79 82 int slashAge = age - slash * SlashDelayFrames;
@@ -82,11 +85,11 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
82 85 {
83 86 emittedMask |= bit;
84 87 ApplyHarvestDamage();
85 if (!Main.dedServ)
88 if (createClientEffects)
86 89 SpawnExecutionBurst(slash);
87 90 }
88 91
89 if (!Main.dedServ && slashAge is >= 0 and < 9)
92 if (createClientEffects && slashAge is >= 0 and < 9)
90 93 SpawnTravellingEdge(slash, slashAge / 8f);
91 94 }
92 95 Projectile.localAI[0] = emittedMask;
@@ -94,6 +97,9 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
94 97
95 98 public override bool PreDraw(ref Color lightColor)
96 99 {
100 if (IsServerController)
101 return false;
102
97 103 int age = TotalLifetime - Projectile.timeLeft;
98 104 for (int slash = 0; slash < SlashCount; slash++)
99 105 {
Modified Projectiles/DeathDomainHarvestTelegraphProjectile.cs +1 -1
@@ -39,7 +39,7 @@ public class DeathDomainHarvestTelegraphProjectile : ModProjectile
39 39 Projectile.ignoreWater = true;
40 40 Projectile.penetrate = -1;
41 41 Projectile.timeLeft = 120;
42 Projectile.netImportant = true;
42 Projectile.netImportant = false;
43 43 }
44 44
45 45 public override void OnSpawn(IEntitySource source)