Skip to content

Commit 092ab17

Browse files
authored
Merge pull request #75 from hocha113/8075
8075
2 parents a10e85b + 26b7fd2 commit 092ab17

27 files changed

+314
-128
lines changed

CWRNetWork.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ public enum CWRMessageType : byte
4040
RequestOldDukeCampsiteData,
4141
HandleOldDukeCampsiteDataServer,
4242
HandleOldDukeCampsiteDataClient,
43-
SpwanOldDukeWannaToFight,
4443
StartCampsiteFindMeScenario,
4544
ResurrectionRate,
4645
DespawnDestroyer,
@@ -83,9 +82,6 @@ public static void HandlePacket(Mod mod, BinaryReader reader, int whoAmI) {
8382
else if (type == CWRMessageType.HandleOldDukeCampsiteDataClient) {
8483
OldDukeCampsite.HandleOldDukeCampsiteDataClient(reader, whoAmI);
8584
}
86-
else if (type == CWRMessageType.SpwanOldDukeWannaToFight) {
87-
ModifyOldDuke.SpwanOldDukeByWannaToFightNetWork(reader, whoAmI);
88-
}
8985
else if (type == CWRMessageType.OldDukeCampsiteDecorationsSync) {
9086
OldDukeCampsiteDecoration.ReceiveDecorationsSync(reader);
9187
}

CWRRef.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
using CalamityMod.DataStructures;
66
using CalamityMod.Events;
77
using CalamityMod.Graphics.Metaballs;
8-
using CalamityMod.Items.Accessories;
98
using CalamityMod.Items.Weapons.Magic;
109
using CalamityMod.NPCs;
1110
using CalamityMod.NPCs.ExoMechs;
1211
using CalamityMod.NPCs.SupremeCalamitas;
13-
using CalamityMod.NPCs.TownNPCs;
1412
using CalamityMod.Particles;
1513
using CalamityMod.Projectiles;
1614
using CalamityMod.TileEntities;

Content/ADV/Scenarios/Abysses/OldDukes/CampsiteInteractionDialogue.cs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -306,25 +306,12 @@ protected override void OnScenarioComplete() {
306306
return;
307307
}
308308

309-
//必须在生成NPC之前设置WannaToFight,否则NPC首帧AI会因为
310-
//ShouldLeaveAfterCooperation()返回true而立即进入LeavingDive消失
311-
OldDukeCampsite.WannaToFight = true;
312-
313-
if (VaultUtils.isSinglePlayer) {
314-
//单人模式:先设置标记,再生成NPC
315-
NPC.NewNPC(NPC.GetBossSpawnSource(Main.myPlayer),
316-
(int)Main.LocalPlayer.Center.X, (int)Main.LocalPlayer.Center.Y - 200,
317-
CWRID.NPC_OldDuke);
318-
}
319-
else {
320-
//多人模式:发包给服务端,服务端先设置WannaToFight再生成NPC
321-
var netMessage = CWRMod.Instance.GetPacket();
322-
netMessage.Write((byte)CWRMessageType.SpwanOldDukeWannaToFight);
323-
netMessage.Write(Main.myPlayer);
324-
netMessage.Send();
325-
//Send()同步本地WannaToFight=true到服务端
326-
OldDukeEffect.Send();
327-
}
309+
//通过弹幕的全端同步机制实现切磋生成:
310+
//弹幕AI在所有端先设置WannaToFight=true,再由服务端/单人生成NPC,
311+
//保证NPC到达各客户端时WannaToFight已为true,避免首帧消失
312+
Projectile.NewProjectile(Main.LocalPlayer.FromObjectGetParent(),
313+
Main.LocalPlayer.Center, Vector2.Zero,
314+
ModContent.ProjectileType<SpawnOldDukeWannaToFight>(), 0, 0, Main.myPlayer);
328315
}
329316
}
330317

Content/ADV/Scenarios/Abysses/OldDukes/Campsites/OldDukeCampsite.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,15 @@ public override void NetSend(BinaryWriter writer) {
8888
if (IsGenerated) {
8989
writer.WriteVector2(CampsitePosition);
9090
}
91+
writer.Write(WannaToFight);
9192
}
9293

9394
public override void NetReceive(BinaryReader reader) {
9495
IsGenerated = reader.ReadBoolean();
9596
if (IsGenerated) {
9697
CampsitePosition = reader.ReadVector2();
9798
}
99+
WannaToFight = reader.ReadBoolean();
98100
}
99101

100102
public override void SetStaticDefaults() {
@@ -365,6 +367,9 @@ private static void CheckWannaToFight() {
365367
WannaToFight = false;
366368
//OldDukeEffect.IsActive由声明式计算自动管理
367369
//NPC消失后ComputeShouldBeActive()将返回false
370+
if (VaultUtils.isServer) {
371+
NetMessage.SendData(MessageID.WorldData);
372+
}
368373
}
369374
}
370375
}
@@ -382,6 +387,10 @@ private static bool CanTriggerInteraction() {
382387
return false;//如果硫磺海效果已经启用,就不要进行交互
383388
}
384389

390+
if (NPC.AnyNPCs(CWRID.NPC_OldDuke)) {
391+
return false;//如果老公爵还在,就不要进行交互
392+
}
393+
385394
if (Main.LocalPlayer.mouseInterface) {
386395
return false;//鼠标正在交互状态下,就不要进行交互
387396
}

Content/ADV/Scenarios/Abysses/OldDukes/ModifyOldDuke.cs

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ private enum OldDukeAIState
6868
#region 生命周期
6969

7070
public override bool CanOverride() {
71+
if (!CWRRef.Has) {//如果没有灾厄Mod,就不覆盖AI,避免潜在的兼容性问题
72+
return false;
73+
}
7174
if (CWRRef.GetBossRushActive()) {
7275
return false;
7376
}
@@ -205,42 +208,6 @@ internal static void StartCampsiteFindMeScenarioNetWork(BinaryReader reader, int
205208
}
206209
}
207210

208-
/// <summary>
209-
/// 处理切磋生成老公爵的网络消息。
210-
/// 服务端收到后设置状态并生成NPC
211-
/// </summary>
212-
/// <summary>
213-
/// 处理切磋生成老公爵的网络消息。
214-
/// 服务端收到后:先广播WannaToFight=true给所有客户端,再生成NPC。
215-
/// 这样保证所有客户端在NPC到达前就已知道这是切磋模式,
216-
/// 避免NPC首帧AI因ShouldLeaveAfterCooperation()而消失。
217-
/// </summary>
218-
internal static void SpwanOldDukeByWannaToFightNetWork(BinaryReader reader, int whoAmI) {
219-
int playerIndex = reader.ReadInt32();
220-
Player player = Main.player[playerIndex];
221-
222-
if (!VaultUtils.isServer) {
223-
return;
224-
}
225-
226-
//步骤1:先设置服务端状态
227-
OldDukeCampsite.WannaToFight = true;
228-
229-
//步骤2:先广播WannaToFight=true给所有客户端
230-
//这样客户端在收到NPC同步包之前就已经知道这是切磋模式
231-
ModPacket packet = CWRMod.Instance.GetPacket();
232-
packet.Write((byte)CWRMessageType.OldDukeEffect);
233-
packet.Write(false); //IsActive由声明式计算管理,这里写false
234-
packet.Write(true); //WannaToFight = true
235-
packet.Write(playerIndex);
236-
packet.Write((byte)OldDukeInteractionState.AcceptedCooperation);
237-
packet.Send();
238-
239-
//步骤3:最后才生成NPC(NPC同步包会在OldDukeEffect包之后到达客户端)
240-
NPC.NewNPC(NPC.GetBossSpawnSource(player.whoAmI),
241-
(int)player.Center.X, (int)player.Center.Y - 200, CWRID.NPC_OldDuke);
242-
}
243-
244211
/// <summary>
245212
/// 根据当前是否在酸雨事件中,触发对应的营地场景对话
246213
/// </summary>
@@ -268,6 +235,10 @@ public override bool AI() {
268235
return RunStorylineAI();
269236
}
270237

238+
if (CWRRef.GetBossRushActive()) {
239+
return true;//以防万一,虽然CanOverride已经禁止了这种情况,但多一层保险总是好的
240+
}
241+
271242
npc.TargetClosest();
272243
Player target = Main.player[npc.target];
273244

Content/ADV/Scenarios/Abysses/OldDukes/OldDukeEffect.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -559,12 +559,7 @@ internal class OldDukeEffect : ModSystem
559559
/// 这是唯一决定IsActive的地方,不依赖任何手动开关
560560
/// </summary>
561561
private static bool ComputeShouldBeActive() {
562-
//条件1:老公爵NPC存在
563-
if (NPC.AnyNPCs(CWRID.NPC_OldDuke)) {
564-
return true;
565-
}
566-
567-
//条件2:老公爵相关对话场景正在运行
562+
//条件:老公爵相关对话场景正在运行
568563
if (ScenarioManager.IsActive()) {
569564
//检查是否是老公爵相关的场景
570565
if (IsOldDukeScenarioRunning()) {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using CalamityOverhaul.Content.ADV.Scenarios.Abysses.OldDukes.Campsites;
2+
using Terraria;
3+
using Terraria.ID;
4+
using Terraria.ModLoader;
5+
6+
namespace CalamityOverhaul.Content.ADV.Scenarios.Abysses.OldDukes
7+
{
8+
/// <summary>
9+
/// 切磋生成老公爵的弹幕载体
10+
/// <para>利用弹幕自带的全端同步机制,在AI中先设置WannaToFight=true,再由服务端/单人生成NPC</para>
11+
/// <para>这样保证所有客户端在NPC到达前就已知道这是切磋模式,
12+
/// 避免NPC首帧AI因ShouldLeaveAfterCooperation()而消失</para>
13+
/// </summary>
14+
internal class SpawnOldDukeWannaToFight : ModProjectile
15+
{
16+
public override string Texture => CWRConstant.Placeholder;
17+
18+
public override void SetDefaults() {
19+
Projectile.width = 2;
20+
Projectile.height = 2;
21+
Projectile.friendly = false;
22+
Projectile.hostile = false;
23+
Projectile.tileCollide = false;
24+
Projectile.ignoreWater = true;
25+
Projectile.timeLeft = 360;
26+
Projectile.penetrate = -1;
27+
Projectile.netImportant = true;
28+
}
29+
30+
public override void AI() {
31+
//所有端先设置切磋标记,保证NPC同步到达时各端已知道是切磋模式
32+
OldDukeCampsite.WannaToFight = true;
33+
34+
//仅在服务端或单人模式下生成NPC,避免重复生成
35+
if (Projectile.ai[0] == 0 && !VaultUtils.isClient) {
36+
if (VaultUtils.isServer) {
37+
NetMessage.SendData(MessageID.WorldData);
38+
}
39+
40+
Player player = Main.player[Projectile.owner];
41+
if (player.Alives() && !NPC.AnyNPCs(CWRID.NPC_OldDuke)) {
42+
NPC.NewNPC(NPC.GetBossSpawnSource(player.whoAmI),
43+
(int)player.Center.X, (int)player.Center.Y - 200, CWRID.NPC_OldDuke);
44+
}
45+
}
46+
47+
Projectile.ai[0]++;
48+
}
49+
50+
public override bool ShouldUpdatePosition() => false;
51+
52+
public override bool PreDraw(ref Color lightColor) => false;
53+
}
54+
}

Content/CWRWorld.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,15 @@ public override void PostUpdateEverything() {
169169

170170
public override void NetSend(BinaryWriter writer) {
171171
BitsByte flags1 = new BitsByte();
172-
flags1[0] = MachineRebellionDowned;
172+
flags1[0] = MachineRebellion;
173+
flags1[1] = MachineRebellionDowned;
173174
writer.Write(flags1);
174175
}
175176

176177
public override void NetReceive(BinaryReader reader) {
177178
BitsByte flags1 = reader.ReadByte();
178-
MachineRebellionDowned = flags1[0];
179+
MachineRebellion = flags1[0];
180+
MachineRebellionDowned = flags1[1];
179181
}
180182

181183
public override void SaveWorldData(TagCompound tag) {

Content/LegendWeapon/HalibutLegend/UI/HalibutUI.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,11 @@ public override void Update() {
505505

506506
Sengs = Math.Clamp(Sengs, 0f, 1f);
507507

508+
//面板关闭时兜底清除悬停状态
509+
if (Sengs <= 0f) {
510+
SkillSlot.ClearHoveredState();
511+
}
512+
508513
Size = Panel.Size();
509514
int leftWeith = (int)(20 - 200 * (1f - Sengs));
510515
int topHeight = (int)Size.Y;
@@ -563,6 +568,10 @@ public override void Update() {
563568
anySlotHovered = true;
564569
}
565570
}
571+
//兜底:如果HoveredSlot引用了不在主面板列表中的槽位,强制清除
572+
if (SkillSlot.HoveredSlot != null && !halibutUISkillSlots.Contains(SkillSlot.HoveredSlot)) {
573+
SkillSlot.ClearHoveredState();
574+
}
566575
if (!anySlotHovered) {
567576
SkillTooltipPanel.Instance.Hide();//如果没有槽位被悬停,隐藏介绍面板(带延迟)
568577
}
@@ -574,7 +583,7 @@ public override void Update() {
574583
draggingSlot.DrawPosition = new Vector2(dragVisualX, MathHelper.Lerp(draggingSlot.DrawPosition.Y, mouse.Y, 0.5f));
575584

576585
//拖拽时清除悬停状态,防止提示窗口残留
577-
SkillSlot.HoveredSlot = null;
586+
SkillSlot.ClearHoveredState();
578587
SkillTooltipPanel.Instance.ForceHide();
579588

580589
//检测是否悬停在技能库区域,设置高亮
@@ -667,9 +676,10 @@ public void MoveSlotToFront(SkillSlot slot) {
667676
}
668677
halibutUISkillSlots.RemoveAt(idx);
669678
halibutUISkillSlots.Insert(0, slot);
670-
//重新设置出现动画:被移动的放大闪动
679+
//重新设置出现动画:被移动的放大闪动(动画期间不响应悬停)
671680
slot.appearProgress = 0f;
672681
slot.isAppearing = true;
682+
SkillSlot.ClearHoveredState();
673683
//为了视觉平滑, 将滚动偏移重置到0并快速过渡
674684
scrollOffset = 0;
675685
//辅以轻微提示音

Content/LegendWeapon/HalibutLegend/UI/SkillLibraryUI.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,11 @@ public void MoveToLibrary(SkillSlot slot) {
321321
return;
322322
}
323323

324+
//移除前清除悬停状态,避免引用悬空
325+
if (SkillSlot.HoveredSlot == slot) {
326+
SkillSlot.ClearHoveredState();
327+
}
328+
324329
mainSlots.Remove(slot);
325330
LibrarySlots.Add(slot);
326331

@@ -346,6 +351,11 @@ public void MoveToLibraryWithAnimation(SkillSlot slot, Vector2 startPosition) {
346351
return;
347352
}
348353

354+
//移除前清除悬停状态,避免引用悬空
355+
if (SkillSlot.HoveredSlot == slot) {
356+
SkillSlot.ClearHoveredState();
357+
}
358+
349359
mainSlots.Remove(slot);
350360

351361
//计算目标位置(技能库中的位置)
@@ -394,6 +404,11 @@ public void MoveToMainList(SkillSlot slot) {
394404
return;
395405
}
396406

407+
//移除前清除悬停状态
408+
if (SkillSlot.HoveredSlot == slot) {
409+
SkillSlot.ClearHoveredState();
410+
}
411+
397412
LibrarySlots.Remove(slot);
398413
var mainSlots = player.GetModPlayer<HalibutSave>().halibutUISkillSlots;
399414
mainSlots.Add(slot);
@@ -414,6 +429,11 @@ public void MoveToMainListWithAnimation(SkillSlot slot, Vector2 startPosition) {
414429
return;
415430
}
416431

432+
//移除前清除悬停状态
433+
if (SkillSlot.HoveredSlot == slot) {
434+
SkillSlot.ClearHoveredState();
435+
}
436+
417437
LibrarySlots.Remove(slot);
418438

419439
//计算目标位置(主面板技能列表中的位置)

0 commit comments

Comments
 (0)