| Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/Core/NetworkPackage/DataToCtl/PackageRegeditEx.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/Core/NetworkPackage/DataToCtl/PackageRegeditEx.cs.meta | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/BattleObject/BattleObject.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/Buff/BattleObjectBuffMgr.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/Define/BattleDeadPack.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/Motion/MotionBase.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/RecordPlayer/RecordAction.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/Skill/SkillBase.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs
@@ -366,6 +366,10 @@ else { pack.commonMark = true; // 【使用 BattleField.recordPlayer】 // 原因:这里是在CreateSkillAction静态方法中,还没有创建SkillRecordAction // 这些包是在找到技能包之前遇到的,需要提前处理掉 // 此时没有RecordAction上下文,应该使用BattleField的主RecordPlayer PackageRegedit.Distribute(pack); } } @@ -414,6 +418,10 @@ else { pack.commonMark = true; // 【使用 BattleField.recordPlayer】 // 原因:这里是在CreateSkillAction方法中,还没有创建SkillRecordAction // 这些包是在找到技能包之前遇到的(如Buff包),需要提前处理 // 此时没有RecordAction上下文,应该使用BattleField的主RecordPlayer PackageRegedit.Distribute(pack); } } Main/Core/NetworkPackage/DataToCtl/PackageRegeditEx.cs
New file @@ -0,0 +1,145 @@ using UnityEngine; using System; /// <summary> /// PackageRegedit的扩展类 /// 提供新的包分发接口,支持将包分发到RecordAction的内部RecordPlayer /// 不修改原有的PackageRegedit.Distribute接口,采用新接口绕过 /// </summary> public class PackageRegeditEx { /// <summary> /// 将包分发到指定RecordAction的内部RecordPlayer /// 这个方法用于处理RecordAction内部产生的包(如技能内部的Buff添加、子技能等) /// /// 使用场景: /// 1. SkillBase中通过PackageRegedit.Distribute产生的包,应该使用SkillRecordAction的innerRecordPlayer /// 2. 确保这些包的生命周期与父RecordAction绑定 /// 3. ForceFinish时可以一并处理 /// </summary> /// <param name="pack">要分发的包</param> /// <param name="parentRecordAction">父RecordAction,包应该由它的innerRecordPlayer管理</param> public static void DistributeToRecordAction(GameNetPackBasic pack, RecordAction parentRecordAction) { if (pack == null) { Debug.LogError("PackageRegeditEx.DistributeToRecordAction: pack is null"); return; } if (parentRecordAction == null) { // 如果没有父RecordAction,使用原有的分发逻辑(会使用BattleField的主RecordPlayer) Debug.LogWarning("PackageRegeditEx.DistributeToRecordAction: parentRecordAction is null, 使用默认分发"); PackageRegedit.Distribute(pack); return; } // 标记这个包是在RecordAction内部处理的 // 这样可以在PackageRegedit的处理逻辑中识别并使用正确的RecordPlayer pack.commonMark = true; // 临时保存当前正在处理的RecordAction上下文 // 这样在DTC处理类中可以获取到父RecordAction,从而使用正确的RecordPlayer CurrentRecordActionContext.Push(parentRecordAction); try { // 调用原有的分发逻辑 PackageRegedit.Distribute(pack); } finally { // 恢复上下文 CurrentRecordActionContext.Pop(); } } /// <summary> /// 获取当前应该使用的RecordPlayer /// /// 判断逻辑: /// 1. 如果有当前RecordAction上下文,使用RecordAction.innerRecordPlayer(RecordAction内部产生的) /// 2. 否则使用BattleField.recordPlayer(顶层包,直接从服务器来的) /// </summary> /// <param name="battleField">战场</param> /// <returns>应该使用的RecordPlayer</returns> public static RecordPlayer GetTargetRecordPlayer(BattleField battleField) { if (battleField == null) { Debug.LogError("PackageRegeditEx.GetTargetRecordPlayer: battleField is null"); return null; } // 检查是否在RecordAction上下文中 var currentRecordAction = CurrentRecordActionContext.Current; if (currentRecordAction != null) { // 使用RecordAction的innerRecordPlayer // 原因:这个包是在RecordAction内部产生的,应该由RecordAction管理 var innerPlayer = currentRecordAction.GetInnerRecordPlayer(); if (innerPlayer != null) { return innerPlayer; } else { Debug.LogWarning($"PackageRegeditEx.GetTargetRecordPlayer: RecordAction {currentRecordAction.GetType().Name} 的 innerRecordPlayer 为 null,使用 BattleField.recordPlayer"); } } // 使用BattleField的主RecordPlayer // 原因:这是顶层包,直接从服务器来的,或者没有RecordAction上下文 return battleField.recordPlayer; } } /// <summary> /// 当前RecordAction上下文 /// 使用栈结构管理嵌套的RecordAction上下文 /// 这样可以在包分发过程中知道当前处于哪个RecordAction内部 /// </summary> public static class CurrentRecordActionContext { private static System.Collections.Generic.Stack<RecordAction> contextStack = new System.Collections.Generic.Stack<RecordAction>(); public static RecordAction Current { get { if (contextStack.Count > 0) { return contextStack.Peek(); } return null; } } public static void Push(RecordAction recordAction) { if (recordAction != null) { contextStack.Push(recordAction); } } public static void Pop() { if (contextStack.Count > 0) { contextStack.Pop(); } } public static void Clear() { contextStack.Clear(); } public static int Depth { get { return contextStack.Count; } } } Main/Core/NetworkPackage/DataToCtl/PackageRegeditEx.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: 7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs
@@ -19,6 +19,9 @@ protected bool hasDeathTriggerSkill = false; // 标记是否已经分发了死亡后的包 protected bool hasDistributedPacksAfterDeath = false; public DeathRecordAction(BattleField _battleField, List<BattleDeadPack> _deadPackList, RecordAction _causingRecordAction = null) : base(RecordActionType.Death, _battleField, null) { @@ -60,9 +63,13 @@ if (null != skillAction) { deathActionDict.Add(battleDeadPack, skillAction); // 死亡触发技能都设置WaitingPlay=true,等待父节点动作完成 // 如果DeathRecordAction有父节点(导致死亡的技能),则等待那个父节点 // 否则等待DeathRecordAction本身 // 【使用 BattleField.recordPlayer】 // 原因:死亡触发技能是顶层的RecordAction,不是在某个RecordAction内部产生的 // 虽然可能是因为技能导致的死亡,但死亡触发的技能本身应该是独立的 // 使用ImmediatelyPlay并设置WaitingPlay=true,可以让死亡技能等待导致死亡的技能完成 // 如果DeathRecordAction有父节点(导致死亡的技能),则等待那个父节点 // 否则等待DeathRecordAction本身 battleField.recordPlayer.ImmediatelyPlay(skillAction, causingRecordAction == null ? this : causingRecordAction, true); } } @@ -117,8 +124,25 @@ if (completeNum == deadPackList.Count) { // 死亡处理完成后,分发死亡后的包 if (!hasDistributedPacksAfterDeath) { hasDistributedPacksAfterDeath = true; DistributePacksAfterDeath(); } isActionCompleted = true; isFinish = true; } } // 确保在innerRecordPlayer中执行死亡后的包 if (hasDistributedPacksAfterDeath && causingRecordAction != null) { var innerPlayer = causingRecordAction.GetInnerRecordPlayer(); if (innerPlayer != null && innerPlayer.IsPlaying()) { innerPlayer.Run(); } } } @@ -186,6 +210,13 @@ } } // 强制分发死亡后的包 if (!hasDistributedPacksAfterDeath) { hasDistributedPacksAfterDeath = true; DistributePacksAfterDeath(); } base.ForceFinish(); } @@ -208,6 +239,66 @@ return hasDeathTriggerSkill; } // 分发死亡后的包 protected void DistributePacksAfterDeath() { // 遍历所有死亡包,分发它们的 packListAfterDeath foreach (var deadPack in deadPackList) { if (deadPack.packListAfterDeath != null && deadPack.packListAfterDeath.Count > 0) { BattleDebug.LogError($"DeathRecordAction.DistributePacksAfterDeath: 开始分发死亡后的包,共 {deadPack.packListAfterDeath.Count} 个包"); foreach (var pack in deadPack.packListAfterDeath) { // 获取包的类型和UID用于调试 string packType = pack.GetType().Name; ulong packUID = 0; var packUIDField = pack.GetType().GetField("packUID"); if (packUIDField != null) { packUID = (ulong)packUIDField.GetValue(pack); } BattleDebug.LogError($"DeathRecordAction: 分发死亡后的包 - Type: {packType}, UID: {packUID}, causingRecordAction: {causingRecordAction?.GetType().Name}"); // 特殊处理 CustomHB426CombinePack:使用其自己的 Distribute 方法 if (pack is CustomHB426CombinePack combinePack) { BattleDebug.LogError($"DeathRecordAction: 死亡后的包是 CustomHB426CombinePack,使用其 Distribute 方法"); combinePack.Distribute(); } // 特殊处理 HB427_tagSCUseSkill:创建技能包并分发 else if (pack is HB427_tagSCUseSkill skillPack) { BattleDebug.LogError($"DeathRecordAction: 死亡后的包是 HB427_tagSCUseSkill,创建 SkillRecordAction"); var skillAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, new List<GameNetPackBasic>() { skillPack }); if (skillAction != null) { battleField.PlayRecord(skillAction); } } else { // 【使用 causingRecordAction 或 battleField.recordPlayer】 // 原因:死亡后的包应该回到导致死亡的技能所在的上下文 // 如果有 causingRecordAction(导致死亡的技能),则分发到它的 innerRecordPlayer // 否则分发到 battleField.recordPlayer(顶层) if (causingRecordAction != null) { PackageRegeditEx.DistributeToRecordAction(pack, causingRecordAction); } else { // 如果没有 causingRecordAction,直接分发(使用原始的 PackageRegedit) PackageRegedit.Distribute(pack); } } } } } } public override bool CanStartExecution() { // 如果不是WaitingPlay模式,直接可以执行 Main/System/Battle/BattleObject/BattleObject.cs
@@ -335,6 +335,10 @@ if (isLastHit) { DodgeFinishAction dodgeFinish = new DodgeFinishAction(battleField, this); // 【使用 BattleField.recordPlayer】 // 原因:闪避完成动作是目标角色的独立行为,不是技能内部产生的 // 虽然是在Hurt过程中触发,但是闪避动作本身是目标的反应,应该由主RecordPlayer管理 // 使用InsertRecord可以插到队列最前面,保证闪避表现的优先级 battleField.recordPlayer.InsertRecord(dodgeFinish); } @@ -506,6 +510,10 @@ teamHero.isDead = false; }); // 【使用 BattleField.recordPlayer】 // 原因:复活是角色的独立行为,不是技能内部产生的 // 复活可能是被动触发的(如死亡后服务器发来的复活包),应该由主RecordPlayer管理 // 使用InsertRecord可以插到队列最前面,保证复活表现的优先级 battleField.recordPlayer.InsertRecord(recordAction); } Main/System/Battle/Buff/BattleObjectBuffMgr.cs
@@ -154,10 +154,15 @@ OnBuffChanged(); }); // 【根据上下文选择 RecordPlayer】 // 原因:Buff移除可能是技能效果的一部分(技能内部触发),也可能是独立的(Buff自然到期) // 如果有当前RecordAction上下文,则使用innerRecordPlayer,确保Buff移除与技能生命周期绑定 // 否则使用BattleField的主RecordPlayer var targetPlayer = PackageRegeditEx.GetTargetRecordPlayer(battleObject.battleField); if (insert) battleObject.battleField.recordPlayer.ImmediatelyPlay(buffRemoveAction); targetPlayer.ImmediatelyPlay(buffRemoveAction); else battleObject.battleField.recordPlayer.PlayRecord(buffRemoveAction); targetPlayer.PlayRecord(buffRemoveAction); } @@ -187,10 +192,15 @@ OnBuffChanged(); }); // 【根据上下文选择 RecordPlayer】 // 原因:Buff添加可能是技能效果的一部分(技能内部触发),也可能是独立的 // 如果有当前RecordAction上下文,则使用innerRecordPlayer // 否则使用BattleField的主RecordPlayer var targetPlayer = PackageRegeditEx.GetTargetRecordPlayer(battleObject.battleField); if (insert) battleObject.battleField.recordPlayer.ImmediatelyPlay(buffMountAction); targetPlayer.ImmediatelyPlay(buffMountAction); else battleObject.battleField.recordPlayer.PlayRecord(buffMountAction); targetPlayer.PlayRecord(buffMountAction); } else { @@ -231,10 +241,15 @@ OnBuffChanged(); }); // 【根据上下文选择 RecordPlayer】 // 原因:Buff批量添加可能是技能效果的一部分,也可能是独立的 // 如果有当前RecordAction上下文,则使用innerRecordPlayer // 否则使用BattleField的主RecordPlayer var targetPlayer = PackageRegeditEx.GetTargetRecordPlayer(battleObject.battleField); if (insert) battleObject.battleField.recordPlayer.ImmediatelyPlay(buffMountAction); targetPlayer.ImmediatelyPlay(buffMountAction); else battleObject.battleField.recordPlayer.PlayRecord(buffMountAction); targetPlayer.PlayRecord(buffMountAction); } // 处理只刷新数据的buff (IsAdd == 0) Main/System/Battle/Define/BattleDeadPack.cs
@@ -1,6 +1,7 @@ using System; using System.Collections.Generic; public class BattleDeadPack { @@ -8,6 +9,9 @@ public CustomHB426CombinePack deadTriggerSkill; // 存储死亡包之后的所有包,这些包需要等待死亡完成后再分发 public List<GameNetPackBasic> packListAfterDeath = new List<GameNetPackBasic>(); public bool isPlaySkill = false; public bool IsOwnSkill(HB427_tagSCUseSkill hB427_TagSCUseSkill) Main/System/Battle/Motion/MotionBase.cs
@@ -65,7 +65,6 @@ PlayAnimation(MotionName.idle, true); SetupAnimationHandlers(); skillTrack = null; if (skelAnim.gameObject != null) illusionShadow = skelAnim.gameObject.AddMissingComponent<SkeletonIllusionShadow>(); @@ -175,8 +174,6 @@ return ExecuteSkillAnim(skillConfig, skillBase, onComplete, targetAnim, true, isSubSkill); } private Spine.TrackEntry skillTrack = null; private Spine.TrackEntry ExecuteSkillAnim(SkillConfig skillConfig, SkillBase skillBase, Action onComplete, Spine.Animation targetAnim, bool hasAnim, bool isSubSkill) @@ -220,6 +217,7 @@ } } Spine.TrackEntry skillTrack = null; if (hasAnim) { @@ -619,7 +617,6 @@ currentTrack = null; skillTrack = null; playingSkillAnim = false; PlayAnimation(MotionName.idle, true); @@ -677,7 +674,6 @@ skeleton.SetToSetupPose(); // skeleton.UpdateWorldTransform(); } skillTrack = null; // 10. 播放待机动画 PlayAnimation(MotionName.idle, true); skeletonAnim.LateUpdate(); Main/System/Battle/RecordPlayer/RecordAction.cs
@@ -27,11 +27,29 @@ // 自身动作是否完成(不包括子节点的完成状态) protected bool isActionCompleted = false; // ===== 内部RecordPlayer机制 ===== // 内部RecordPlayer:用于播放由此RecordAction内部产生的RecordAction // 当RecordAction内部产生新的RecordAction时(如PackageRegedit.Distribute触发的), // 这些RecordAction应该由当前RecordAction的innerRecordPlayer管理,而不是BattleField的主RecordPlayer // 这样可以保证: // 1. 内部产生的RecordAction生命周期与父RecordAction绑定 // 2. ForceFinish时可以一并处理内部的RecordAction // 3. 不会干扰BattleField主RecordPlayer的播放队列 protected RecordPlayer innerRecordPlayer; public RecordAction(RecordActionType _actionType, BattleField _battleField, BattleObject _battleObj) { actionType = _actionType; battleField = _battleField; battleObject = _battleObj; // 初始化内部RecordPlayer // 每个RecordAction都有自己的RecordPlayer来管理内部产生的RecordAction if (_battleField != null) { innerRecordPlayer = new RecordPlayer(); innerRecordPlayer.Init(_battleField); } } public virtual void Played() @@ -123,6 +141,13 @@ return false; } // 检查内部RecordPlayer是否还在播放 // 原因:内部产生的RecordAction必须全部播放完成后,当前RecordAction才算完成 if (innerRecordPlayer != null && innerRecordPlayer.IsPlaying()) { return false; } // 检查所有子节点是否完成 foreach (var child in childActionList) { @@ -137,13 +162,21 @@ public virtual void Run() { // 先运行内部RecordPlayer // 原因:内部产生的RecordAction需要先执行,确保内部逻辑按正确顺序播放 // 例如:技能内部产生的Buff添加、子技能等都由innerRecordPlayer管理 innerRecordPlayer?.Run(); } public virtual void ForceFinish() { isFinish = true; isActionCompleted = true; // 强制结束内部RecordPlayer // 原因:RecordAction被ForceFinish时,其内部产生的所有RecordAction也必须强制结束 // 这样才能保证整个RecordAction树的完整性和一致性 innerRecordPlayer?.ForceFinish(); // 强制结束所有子节点 for (int i = childActionList.Count - 1; i >= 0; i--) @@ -166,6 +199,13 @@ return battleField.guid; } // 获取内部RecordPlayer // 用于外部代码需要将RecordAction添加到此RecordAction的内部播放器时使用 public virtual RecordPlayer GetInnerRecordPlayer() { return innerRecordPlayer; } public virtual bool NeedWaitSibling() { return true; Main/System/Battle/Skill/SkillBase.cs
@@ -28,9 +28,6 @@ protected List<H0704_tagRolePackRefresh> dropPackList = new List<H0704_tagRolePackRefresh>(); protected List<HB405_tagMCAddExp> expPackList = new List<HB405_tagMCAddExp>(); protected List<SkillRecordAction> waitingCastSkillRecordAction = new List<SkillRecordAction>(); protected bool moveFinished = false; public SkillBase fromSkill; public bool isPlay = false; @@ -500,44 +497,48 @@ skillEffect = SkillEffectFactory.CreateSkillEffect(this, caster, skillConfig, tagUseSkillAttack); skillEffect.Play(OnHitTargets); ProcessSubSkill(); HandleWaitingCastSkill(); isPlay = true; } protected void ProcessSubSkill() { // 按packUID排序所有子技能 var allSubSkills = new List<(ulong packUID, SkillRecordAction action)>(); foreach (var subSkillPack in tagUseSkillAttack.subSkillList) { SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, new List<GameNetPackBasic>() { subSkillPack }); recordAction.fromSkill = this; // 子技能设置WaitingPlay=true,等待父技能动作完成 waitingCastSkillRecordAction.Add(recordAction); battleField.recordPlayer.ImmediatelyPlay(recordAction, parentRecordAction, true); if (recordAction != null) { recordAction.fromSkill = this; allSubSkills.Add((subSkillPack.packUID, recordAction)); } } tagUseSkillAttack.subSkillList.Clear(); foreach (var subCombinePack in tagUseSkillAttack.subSkillCombinePackList) { SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, subCombinePack.packList); recordAction.fromSkill = this; // 子技能设置WaitingPlay=true,等待父技能动作完成 waitingCastSkillRecordAction.Add(recordAction); if (recordAction != null) { recordAction.fromSkill = this; ulong packUID = subCombinePack.packList.Count > 0 ? GetPackUID(subCombinePack.packList[0]) : 0; allSubSkills.Add((packUID, recordAction)); } } tagUseSkillAttack.subSkillCombinePackList.Clear(); waitingCastSkillRecordAction.OrderBy(recordAction => recordAction.hB427_TagSCUseSkill.packUID); // 按packUID排序 allSubSkills.Sort((a, b) => a.packUID.CompareTo(b.packUID)); } protected void HandleWaitingCastSkill() { // 依次添加到recordPlayer,每个等待前一个完成 RecordAction waitingRecordAction = null; for (int i = 0; i < waitingCastSkillRecordAction.Count; i++) foreach (var (packUID, recordAction) in allSubSkills) { var recordAction = waitingCastSkillRecordAction[i]; // 【使用 BattleField.recordPlayer】 // 原因:子技能是独立的SkillRecordAction,应该是顶层RecordAction,由BattleField的主RecordPlayer管理 // 通过设置父子关系和WaitingPlay,可以控制子技能的执行时机 if (waitingRecordAction != null) { // 每个都应该等前一个结束后 @@ -561,19 +562,19 @@ // 技能中摇开始回调:通知技能效果处理中摇开始 public virtual void OnMiddleFrameStart(int times) { skillEffect?.OnMiddleFrameStart(times); // 修复:添加空值检查 skillEffect.OnMiddleFrameStart(times); // 修复:添加空值检查 } // 技能中摇结束回调:通知技能效果处理中摇结束 public virtual void OnMiddleFrameEnd(int times, int hitIndex) { skillEffect?.OnMiddleFrameEnd(times, hitIndex); // 修复:添加空值检查 skillEffect.OnMiddleFrameEnd(times, hitIndex); // 修复:添加空值检查 } // 技能后摇开始回调:通知技能效果处理后摇开始 public virtual void OnFinalFrameStart() { skillEffect?.OnFinalFrameStart(); // 修复:添加空值检查 skillEffect.OnFinalFrameStart(); // 修复:添加空值检查 } // 技能后摇结束回调:通知技能效果处理后摇结束 @@ -899,7 +900,10 @@ if (refreshPack != null) { // 分发HP刷新包 PackageRegedit.Distribute(refreshPack); // 【使用 parentRecordAction.innerRecordPlayer】 // 原因:HP刷新包是技能内部产生的,应该由当前SkillRecordAction的innerRecordPlayer管理 // 这样可以确保HP刷新与技能的生命周期绑定,ForceFinish时一并处理 PackageRegeditEx.DistributeToRecordAction(refreshPack, parentRecordAction); packList.Remove(refreshPack); } } @@ -910,13 +914,123 @@ List<BattleDeadPack> deadPackList = BattleUtility.FindDeadPack(packList); if (deadPackList.Count <= 0) return; // 找到最大的死亡包 packUID(包括死亡包和死亡触发技能) ulong maxDeathPackUID = 0; foreach (var deadPack in deadPackList) { if (deadPack.deadPack != null && deadPack.deadPack.packUID > maxDeathPackUID) { maxDeathPackUID = deadPack.deadPack.packUID; } if (deadPack.deadTriggerSkill != null) { var skillPack = deadPack.deadTriggerSkill.GetMainHB427SkillPack(); if (skillPack != null && skillPack.packUID > maxDeathPackUID) { maxDeathPackUID = skillPack.packUID; } } } // 如果找到了死亡包,收集所有 packUID > maxDeathPackUID 的包 if (maxDeathPackUID > 0) { BattleDebug.LogError($"SkillBase.HandleDead: 找到死亡包,maxDeathPackUID = {maxDeathPackUID},开始收集死亡后的包"); // 1. 收集 packList 中 packUID 大于死亡包的包 List<GameNetPackBasic> packsToRemove = new List<GameNetPackBasic>(); foreach (var pack in packList) { ulong packUID = GetPackUID(pack); if (packUID > maxDeathPackUID) { BattleDebug.LogError($"SkillBase.HandleDead: 从packList收集死亡后的包 - Type: {pack.GetType().Name}, UID: {packUID}"); foreach (var deadPack in deadPackList) { deadPack.packListAfterDeath.Add(pack); } packsToRemove.Add(pack); } } // 从 packList 中移除这些包 foreach (var pack in packsToRemove) { packList.Remove(pack); } // 2. 收集 subSkillList 中 packUID 大于死亡包的子技能 if (tagUseSkillAttack.subSkillList != null && tagUseSkillAttack.subSkillList.Count > 0) { var subSkillsToRemove = new List<HB427_tagSCUseSkill>(); foreach (var subSkillPack in tagUseSkillAttack.subSkillList) { ulong subSkillUID = GetPackUID(subSkillPack); if (subSkillUID > maxDeathPackUID) { BattleDebug.LogError($"SkillBase.HandleDead: 从subSkillList收集死亡后的包 - Type: {subSkillPack.GetType().Name}, UID: {subSkillUID}"); foreach (var deadPack in deadPackList) { deadPack.packListAfterDeath.Add(subSkillPack); } subSkillsToRemove.Add(subSkillPack); } } // 从 subSkillList 中移除这些子技能 foreach (var subSkill in subSkillsToRemove) { tagUseSkillAttack.subSkillList.Remove(subSkill); } } // 3. 收集 subSkillCombinePackList 中 packUID 大于死亡包的组合包 if (tagUseSkillAttack.subSkillCombinePackList != null && tagUseSkillAttack.subSkillCombinePackList.Count > 0) { var combinePacksToRemove = new List<CustomHB426CombinePack>(); foreach (var subCombinePack in tagUseSkillAttack.subSkillCombinePackList) { // 找到组合包中的最小 packUID(组合包的 packUID 以第一个包为准) ulong combinePackUID = 0; if (subCombinePack.packList != null && subCombinePack.packList.Count > 0) { combinePackUID = GetPackUID(subCombinePack.packList[0]); } if (combinePackUID > maxDeathPackUID) { BattleDebug.LogError($"SkillBase.HandleDead: 从subSkillCombinePackList收集死亡后的包 - UID: {combinePackUID}, 包含 {subCombinePack.packList.Count} 个子包"); // 将组合包中的所有包都添加到 packListAfterDeath foreach (var pack in subCombinePack.packList) { foreach (var deadPack in deadPackList) { deadPack.packListAfterDeath.Add(pack); } } combinePacksToRemove.Add(subCombinePack); } } // 从 subSkillCombinePackList 中移除这些组合包 foreach (var combinePack in combinePacksToRemove) { tagUseSkillAttack.subSkillCombinePackList.Remove(combinePack); } } } CheckAfterDeadhPack(); // 修复:先收集要删除的包,避免在foreach中修改集合 var dropPacksToRemove = new List<H0704_tagRolePackRefresh>(dropPackList); foreach (var _dropPack in dropPacksToRemove) { PackageRegedit.Distribute(_dropPack); // 【使用 parentRecordAction.innerRecordPlayer】 // 原因:掉落包是技能效果的一部分,应该由当前SkillRecordAction管理 // 掉落包的分发与技能完成绑定,确保在技能ForceFinish时正确处理 PackageRegeditEx.DistributeToRecordAction(_dropPack, parentRecordAction); packList.Remove(_dropPack); } @@ -991,6 +1105,48 @@ for (int i = 0; i < itemList.Count; i++) dropAssign[i % deadCount].Add(itemList[i]); return dropAssign; } // 获取包的 packUID protected ulong GetPackUID(GameNetPackBasic pack) { if (pack == null) return 0; if (pack is HB422_tagMCTurnFightObjDead deadPack) return deadPack.packUID; if (pack is CustomHB426CombinePack combinePack) { var mainSkillPack = combinePack.GetMainHB427SkillPack(); return mainSkillPack?.packUID ?? 0; } if (pack is HB427_tagSCUseSkill skillPack) return skillPack.packUID; if (pack is HB428_tagSCBuffRefresh buffRefresh) return buffRefresh.packUID; if (pack is HB429_tagSCBuffDel buffDel) return buffDel.packUID; if (pack is HB419_tagSCObjHPRefresh hpRefresh) return hpRefresh.packUID; if (pack is HB405_tagMCAddExp expPack) return expPack.packUID; if (pack is H0704_tagRolePackRefresh dropPack) return dropPack.packUID; // 尝试通过反射获取 packUID var packUIDField = pack.GetType().GetField("packUID"); if (packUIDField != null) { return (ulong)packUIDField.GetValue(pack); } return 0; } // 分配经验值:将经验包平均分配给每个死亡对象 @@ -1198,7 +1354,10 @@ SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, new List<GameNetPackBasic>() { subSkillPack }); recordAction.fromSkill = this; otherSkillActionList.Add(recordAction); // 子技能设置WaitingPlay=true,等待父技能动作完成 // 【使用 BattleField.recordPlayer】 // 原因:即使在ForceFinished中,子技能也是顶层RecordAction,应该由主RecordPlayer管理 // 这些子技能会立即被ForceFinish,但仍需要正确的播放器上下文 battleField.recordPlayer.ImmediatelyPlay(recordAction, parentRecordAction, true); } tagUseSkillAttack.subSkillList.Clear(); @@ -1207,7 +1366,9 @@ SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, subCombinePack.packList); recordAction.fromSkill = this; otherSkillActionList.Add(recordAction); // 子技能设置WaitingPlay=true,等待父技能动作完成 // 【使用 BattleField.recordPlayer】 // 原因:即使在ForceFinished中,子技能也是顶层RecordAction,应该由主RecordPlayer管理 battleField.recordPlayer.ImmediatelyPlay(recordAction, parentRecordAction, true); } tagUseSkillAttack.subSkillCombinePackList.Clear(); @@ -1298,7 +1459,10 @@ { if (pack is CustomB421ActionPack actionPack) actionPack.Distribute(); PackageRegedit.Distribute(pack); // 【使用 parentRecordAction.innerRecordPlayer】 // 原因:ForceFinished时剩余的包也是技能内部产生的,应该由innerRecordPlayer管理 // 这样可以确保即使强制结束,包的处理也在正确的上下文中 PackageRegeditEx.DistributeToRecordAction(pack, parentRecordAction); } } } @@ -1408,7 +1572,10 @@ } else { PackageRegedit.Distribute(pack); // 【使用 parentRecordAction.innerRecordPlayer】 // 原因:技能执行过程中的包(Buff、属性刷新等)是技能效果的一部分 // 应该由SkillRecordAction的innerRecordPlayer管理,确保与技能生命周期一致 PackageRegeditEx.DistributeToRecordAction(pack, parentRecordAction); } } @@ -1476,7 +1643,10 @@ foreach (var pack in buffPacks) { PackageRegedit.Distribute(pack); // 【使用 parentRecordAction.innerRecordPlayer】 // 原因:Buff包是技能效果的核心组成部分,应该由SkillRecordAction管理 // 即使是强制分发的情况,也要保持在正确的RecordAction上下文中 PackageRegeditEx.DistributeToRecordAction(pack, parentRecordAction); } }