125 战斗 修复内嵌技能中死亡播放技能的顺序问题(司马懿) 修复卑弥呼复活报错的问题
8个文件已修改
2个文件已添加
580 ■■■■■ 已修改文件
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DataToCtl/PackageRegeditEx.cs 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DataToCtl/PackageRegeditEx.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObject.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Buff/BattleObjectBuffMgr.cs 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Define/BattleDeadPack.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Motion/MotionBase.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/RecordPlayer/RecordAction.cs 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillBase.cs 232 ●●●● 补丁 | 查看 | 原始文档 | 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);
        }
    }