yyl
2026-01-21 6bc8a17ed56027c54cdd523dda04a049f5e2e8dd
125 战斗 修复战斗卡死问题 并移除了子技能的设计 只有内嵌技能
2个文件已删除
15个文件已修改
1047 ■■■■ 已修改文件
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomHB427_tagSCUseSkill.cs 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB422_tagMCTurnFightObjDead.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB430_tagSCTurnFightReport.cs 425 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/BattleField.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs 101 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/RebornRecordAction.cs 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/SkillRecordAction.cs 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleManager.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObject.cs 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleTweenMgr.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleUtility.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/RecordPlayer/RecordAction.cs 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/RecordPlayer/RecordPlayer.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/RebornSkill.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs
File was deleted
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs.meta
File was deleted
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -100,8 +101,6 @@
        Dictionary<int, GameNetPackBasic> indexDict = new Dictionary<int, GameNetPackBasic>();
        Dictionary<uint, HB427_tagSCUseSkill> skillDict = new Dictionary<uint, HB427_tagSCUseSkill>();
        for (int i = 0; i < b421SeriesPackList.Count; i++)
        {
            var pack = b421SeriesPackList[i];
@@ -137,42 +136,7 @@
            }
            else
            {
                if (pack is HB427_tagSCUseSkill skillPack)
                {
                    //  处理技能之间的链接关系
                    if (skillPack.RelatedSkillID > 0)
                    {
                        // 如果是被 HB426_tagSCTurnFightTag 包裹的第一个技能包 并且前面没有CustomHB426CombinePack
                        // 则需要把CustomHB426CombinePack加入skillPack的subSkillCombinePackList里
                        // 同时 需要把indexDict里删掉对应的subSkillCombinePackList
                        // subSkillList删掉对应skillPack,但是skillPack的parentSkill不变
                        skillDict.TryGetValue(skillPack.RelatedSkillID, out var parentSkill);
                        if (parentSkill != null && skillPack.BattleType == 4)//4=子技能
                        {
                            parentSkill.subSkillList.Add(skillPack);
                            skillPack.parentSkill = parentSkill;
                        }
                        indexDict.Add(i, pack);
                    }
                    else
                    {
                        indexDict.Add(i, pack);
                    }
                    if (skillDict.ContainsKey(skillPack.SkillID))
                    {
                        skillDict[skillPack.SkillID] = skillPack;
                    }
                    else
                    {
                        skillDict.Add(skillPack.SkillID, skillPack);
                    }
                }
                else
                {
                    indexDict.Add(i, pack);
                }
                indexDict.Add(i, pack);
            }
        }
@@ -195,70 +159,6 @@
                        //  如果是嵌套的包 加入之后 调整i
                        i = cbPack.toIndex;
                    }
                }
            }
        }
        for (int i = 0; i < b421SeriesPackList.Count; i++)
        {
            if (indexDict.TryGetValue(i, out var pack))
            {
                if (pack is CustomHB426CombinePack cbPack)
                {
                    HB427_tagSCUseSkill skillPack = cbPack.GetMainHB427SkillPack();
                    if (null == skillPack)
                    {
                        continue;
                    }
                    //  如果是子技能
                    if (skillPack.isSubSkill)
                    {
                        //  让别人来处理
                        continue;
                    }
                    else
                    {
                        //  处理子技能
                        if (skillPack.subSkillList.Count > 0)
                        {
                            var parentSkill = skillPack;
                            List<HB427_tagSCUseSkill> toRemoveSubSkills = new List<HB427_tagSCUseSkill>();
                            foreach (var subSkill in parentSkill.subSkillList)
                            {
                                CustomHB426CombinePack innerCBPack = null;
                                if (cbPack.IsInnerCBPackContainsSkill(subSkill, ref innerCBPack))
                                {
                                    if (cbPack.GetMainHB427SkillPack() == subSkill)
                                    {
                                        parentSkill.subSkillList.Remove(subSkill);
                                        Debug.LogError("子技能不能是主技能: " + subSkill.SkillID);
                                        continue;
                                    }
                                    subSkill.parentCombinePack = innerCBPack;
                                    cbPack.packList.Remove(innerCBPack);
                                    toRemoveSubSkills.Add(subSkill);
                                    parentSkill.subSkillCombinePackList.Add(innerCBPack);
                                    indexDict.Remove(innerCBPack.fromIndex);
                                }
                            }
                            foreach (var subSkill in toRemoveSubSkills)
                            {
                                parentSkill.subSkillList.Remove(subSkill);
                            }
                        }
                        else
                        {
                            // 主技能没有子技能 直接跳过
                            continue;
                        }
                    }
                }
                else if (pack is HB427_tagSCUseSkill skillPack)
                {
                    // Debug.LogError("落单的技能");
                }
            }
        }
@@ -316,7 +216,7 @@
        }
        return false;
    }
    public void Distribute()
    public void Distribute(RecordAction parentAction = null)
    {
        BattleField battleField = BattleManager.Instance.GetBattleField(guid);
@@ -329,7 +229,14 @@
        var skillAction = CreateSkillAction();
        if (null != skillAction)
        {
            battleField.PlayRecord(skillAction);
            if (parentAction != null)
            {
                parentAction.GetInnerRecordPlayer().PlayRecord(skillAction);
            }
            else
            {
                battleField.PlayRecord(skillAction);
            }
        }
        else
        {
@@ -434,6 +341,8 @@
                return null;
            }
            HB427_tagSCUseSkill skill = packList[0] as HB427_tagSCUseSkill;
            packList.RemoveAt(0);
            if (null == skill)
            {
@@ -467,5 +376,42 @@
        return pack;
    }
    public bool NeedWaiting()
    {
        bool needWaiting = false;
        HB427_tagSCUseSkill hB427_TagSCUseSkill = GetMainHB427SkillPack();
        for (int i = 0; i < packList.Count; i++)
        {
            var pack = packList[i];
            if (pack is HB427_tagSCUseSkill skillPack && skillPack != hB427_TagSCUseSkill)
            {
                SkillConfig ssc = SkillConfig.Get((int)skillPack.SkillID);
                if (!string.IsNullOrEmpty(ssc.SkillMotionName))
                {
                    needWaiting = true;
                    break;
                }
            }
            else if (pack is HB422_tagMCTurnFightObjDead dead)
            {
                needWaiting = true;
                break;
            }
            else if (pack is CustomHB426CombinePack combinePack)
            {
                if (combinePack.NeedWaiting())
                {
                    needWaiting = true;
                    break;
                }
            }
        }
        return needWaiting;
    }
#endif
}
Main/Core/NetworkPackage/CustomServerPack/CustomHB427_tagSCUseSkill.cs
@@ -9,39 +9,6 @@
    //  裸露在外的技能不考虑子技能 跟 parentSkill ( CustomHB426CombinePack )
    //-------------------------------------------//
    public HashSet<HB427_tagSCUseSkill> subSkillList
    {
        get;
        set;
    } = new HashSet<HB427_tagSCUseSkill>();
    public HashSet<CustomHB426CombinePack> subSkillCombinePackList
    {
        get;
        set;
    } = new HashSet<CustomHB426CombinePack>();
    public HB427_tagSCUseSkill parentSkill
    {
        get;
        set;
    } = null;
    public CustomHB426CombinePack parentCombinePack
    {
        get;
        set;
    } = null;
    public bool isSubSkill
    {
        get
        {
            return parentSkill != null;
        }
    }
    public partial class tagSCUseSkillHurt {
        public bool isChangedRawAttackType = false;
    }
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB422_tagMCTurnFightObjDead.cs
@@ -15,7 +15,11 @@
        // 由技能去通知战场死亡 battleField.OnObjsDead(deadList)
#if UNITY_EDITOR
        BattleDebug.LogError("编辑器下的死亡测试");
        battleField?.OnObjsDead(new List<BattleDeadPack>(){ new BattleDeadPack(){ deadPack = vNetData}});
        RecordAction rc = battleField?.OnObjsDead(new List<BattleDeadPack>(){ new BattleDeadPack(){ deadPack = vNetData}});
        if (null != rc)
        {
            battleField?.recordPlayer.ImmediatelyPlay(rc);
        }
#endif
        if (!vNetPack.commonMark)
            battleField?.DistributeNextPackage();
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB430_tagSCTurnFightReport.cs
@@ -4,189 +4,51 @@
using System.Text;
using System.Collections.Generic;
using System.Linq;
// B4 30 查看战报结果 #tagSCTurnFightReportRet
/// <summary>
/// B4 30 战报结果处理类
/// 负责解析服务器返回的战报数据包,并分发到战场系统
/// </summary>
public class DTCB430_tagSCTurnFightReport : DtcBasic
{
    private static byte[] vCmdBytes = new byte[2];
    private bool canAddPack = false;
    static byte[] vCmdBytes = new byte[2];
    bool canAddPack = false;
    /// <summary>
    /// 战报数据包处理主入口
/// 解析战报字节流,提取所有战斗包,并按顺序分发到战场
    /// </summary>
    public override void Done(GameNetPackBasic vNetPack)
    {
        base.Done(vNetPack);
        HB430_tagSCTurnFightReport vNetData = vNetPack as HB430_tagSCTurnFightReport;
        // 战报结果
        string guid = UIHelper.ServerStringTrim(vNetData.GUID);
        canAddPack = false;
        Debug.Log("战斗时序 B430 开始处理战斗 " + Time.time);
        //约定 B430 内容(小包1长度WORD + 包1 + 小包2长度WORD + 包2)
        //约定第一个包是B424,先发过来的过滤报错通知
        try
        {
            int vReadIndex = 0;
            byte[] vPackBytes;
            int vLeavingLeng = 0;
            int vBodyLeng = 0;
            int vTotalLeng = vNetData.reportBytes.Length;
            List<GameNetPackBasic> vPackList = new List<GameNetPackBasic>();
            while (vReadIndex < vTotalLeng)
            {
                vLeavingLeng = vTotalLeng - vReadIndex;
                if (vLeavingLeng < 4)
                {
                    //包头至少需要4字节
                    Debug.LogError("DTCB430_tagSCTurnFightReport: vLeavingLeng < 2 解包失败");
                    break;
                }
                //约定小封包的长度
                vBodyLeng = BitConverter.ToInt16(vNetData.reportBytes, vReadIndex);
                if (vBodyLeng > vLeavingLeng)// 未完整的包 报错
                {
                    Debug.LogError("DTCB430_tagSCTurnFightReport: vBodyLeng > vLeavingLeng解包失败");
                    break;
                }
                vPackBytes = new byte[vBodyLeng];
                Array.Copy(vNetData.reportBytes, vReadIndex + 2, vPackBytes, 0, vBodyLeng);
                Array.Copy(vPackBytes, 0, vCmdBytes, 0, 2);
                var cmd = (ushort)((ushort)(vCmdBytes[0] << 8) + vCmdBytes[1]);
                bool isRegist = false;  // 未注册封包处理
                if (PackageRegedit.Contain(cmd))
                {
                    GameNetPackBasic npk = PackageRegedit.TransPack(ServerType.B430, cmd, vPackBytes);
                    if (npk != null)
                    {
                        if (!FilterBeforeB424(npk))
                        {
                            npk.socketType = ServerType.B430;
                            vPackList.Add(npk);
                            BattleManager.Instance.PushPackUID(guid, npk.packUID);
                        }
                        isRegist = true;
                    }
                }
                vReadIndex += 2 + vBodyLeng;
                // 未注册封包处理
                if (!isRegist)
                {
#if UNITY_EDITOR
                    PackageRegedit.TransPack(ServerType.B430, cmd, vPackBytes);
#endif
                }
            }
#if UNITY_EDITOR
            //  解析所有vPackList里的每个字段(深度)并且输出到Application.dataPath + "/../BattleReport/PackageDetailAnalysis_时间戳.txt文件里
            string originPack = string.Empty;
            BattleField battleField = BattleManager.Instance.GetBattleField(guid);
            for (int i = 0; i < vPackList.Count; i++)
            {
                var pack = vPackList[i];
                if (pack is HB427_tagSCUseSkill skill)
                {
                    string heroName = skill.ObjID.ToString();
                    if (battleField != null)
                    {
                        var battleObj = battleField.battleObjMgr.GetBattleObject((int)skill.ObjID);
                        if (battleObj != null && battleObj.teamHero != null)
                        {
                            heroName = battleObj.teamHero.name;
                        }
                    }
                    string skillName = SkillConfig.Get((int)skill.SkillID)?.SkillName ?? "Unknown";
                    originPack += $"[{pack.packUID}] HB427_tagSCUseSkill - ObjID:{skill.ObjID} HeroName:{heroName} SkillID:{skill.SkillID} SkillName:{skillName}\n";
                }
                else if (pack is HB426_tagSCTurnFightTag tag)
                {
                    string signText = tag.Sign == 0 ? "Start" : tag.Sign == 1 ? "End" : "Unknown";
                    originPack += $"[{pack.packUID}] HB426_tagSCTurnFightTag - Tag:{tag.Tag} Sign:{tag.Sign}({signText})\n";
                }
                else if (pack is HB422_tagMCTurnFightObjDead deadPack)
                {
                    string heroName = deadPack.ObjID.ToString();
                    if (battleField != null)
                    {
                        var battleObj = battleField.battleObjMgr.GetBattleObject((int)deadPack.ObjID);
                        if (battleObj != null && battleObj.teamHero != null)
                        {
                            heroName = battleObj.teamHero.name;
                        }
                    }
                    originPack += $"[{pack.packUID}] HB422_tagMCTurnFightObjDead - ObjID:{deadPack.ObjID} HeroName:{heroName}\n";
                }
                else
                {
                    originPack += $"[{pack.packUID}] {pack.GetType().Name}\n";
                }
            }
#endif
            // 1. 解析战报字节流,提取所有包
            List<GameNetPackBasic> vPackList = ParseReportBytes(vNetData.reportBytes, guid);
#if UNITY_EDITOR
            DebugingBuffStatus(vPackList);
            // 2. 保存解析前的包详情(调试用)
            SavePackageDetailBeforeAnalysis(vPackList, guid);
#endif
#if UNITY_EDITOR
#region Start Print Before Pack List Detail
            if (Launch.Instance.isOpenSkillLogFile)
            {
                try
                {
                    string detailAnalysis = PrintPackageDetailAnalysis(vPackList, guid);
                    string filePath = Application.dataPath + "/../BattleReport/PackageBeforeDetailAnalysis_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".txt";
                    System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filePath));
                    System.IO.File.WriteAllText(filePath, detailAnalysis);
                    Debug.Log("包详细分析已保存到: " + filePath);
                }
                catch (Exception e)
                {
                    Debug.LogError("保存包详细分析失败: " + e.Message);
                }
            }
#endregion
#endif
            // 3. 分析并组合包队列
            vPackList = AnalysisPackQueueAndDistribute(guid, vPackList);
#if UNITY_EDITOR
#region Start Print Pack List Detail
            if (Launch.Instance.isOpenSkillLogFile)
            {
                try
                {
                    string detailAnalysis = PrintPackageDetailAnalysis(vPackList, guid);
                    string filePath = Application.dataPath + "/../BattleReport/PackageAfterDetailAnalysis_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".txt";
                    System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filePath));
                    System.IO.File.WriteAllText(filePath, detailAnalysis);
                    Debug.Log("包详细分析已保存到: " + filePath);
                }
                catch (Exception e)
                {
                    Debug.LogError("保存包详细分析失败: " + e.Message);
                }
            }
#endregion
            // 4. 保存解析后的包详情(调试用)
            SavePackageDetailAfterAnalysis(vPackList, guid);
#endif
            for (int i = 0; i < vPackList.Count; i++)
            {
                BattleManager.Instance.PushPackage(guid, vPackList[i]);
            }
            // 5. 将包推送到战场队列
            PushPackagesToBattle(guid, vPackList);
            // 6. 通知战场开始分发包
            canAddPack = false;
            BattleManager.Instance.DistributeNextReportPackage(guid);
        }
@@ -196,9 +58,135 @@
        }
    }
    /// <summary>
    /// 解析战报字节流,提取所有战斗数据包
    /// 约定:B430 内容格式为(小包1长度WORD + 包1 + 小包2长度WORD + 包2...)
    /// </summary>
    private List<GameNetPackBasic> ParseReportBytes(byte[] reportBytes, string guid)
    {
        List<GameNetPackBasic> vPackList = new List<GameNetPackBasic>();
        int vReadIndex = 0;
        int vTotalLeng = reportBytes.Length;
        while (vReadIndex < vTotalLeng)
        {
            int vLeavingLeng = vTotalLeng - vReadIndex;
            // 包头至少需要4字节
            if (vLeavingLeng < 4)
            {
                Debug.LogError("DTCB430_tagSCTurnFightReport: vLeavingLeng < 2 解包失败");
                break;
            }
            // 读取包体长度
            int vBodyLeng = BitConverter.ToInt16(reportBytes, vReadIndex);
            if (vBodyLeng > vLeavingLeng)
            {
                Debug.LogError("DTCB430_tagSCTurnFightReport: vBodyLeng > vLeavingLeng解包失败");
                break;
            }
            // 提取包体数据
            byte[] vPackBytes = new byte[vBodyLeng];
            Array.Copy(reportBytes, vReadIndex + 2, vPackBytes, 0, vBodyLeng);
            // 解析包类型命令
            Array.Copy(vPackBytes, 0, vCmdBytes, 0, 2);
            var cmd = (ushort)((ushort)(vCmdBytes[0] << 8) + vCmdBytes[1]);
            // 转换为游戏包对象
            if (PackageRegedit.Contain(cmd))
            {
                GameNetPackBasic npk = PackageRegedit.TransPack(ServerType.B430, cmd, vPackBytes);
                if (npk != null && !FilterBeforeB424(npk))
                {
                    npk.socketType = ServerType.B430;
                    vPackList.Add(npk);
                    BattleManager.Instance.PushPackUID(guid, npk.packUID);
                }
            }
#if UNITY_EDITOR
            else
            {
                PackageRegedit.TransPack(ServerType.B430, cmd, vPackBytes);
            }
#endif
            vReadIndex += 2 + vBodyLeng;
        }
        return vPackList;
    }
    /// <summary>
    /// 保存解析前的包详情到文件(仅在编辑器且开启日志时)
    /// </summary>
    private void SavePackageDetailBeforeAnalysis(List<GameNetPackBasic> vPackList, string guid)
    {
#if UNITY_EDITOR
        if (Launch.Instance.isOpenSkillLogFile)
        {
            try
            {
                string detailAnalysis = PrintPackageDetailAnalysis(vPackList, guid);
                string filePath = Application.dataPath + "/../BattleReport/PackageBeforeDetailAnalysis_" +
                                 DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".txt";
                System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filePath));
                System.IO.File.WriteAllText(filePath, detailAnalysis);
                Debug.Log("包详细分析已保存到: " + filePath);
            }
            catch (Exception e)
            {
                Debug.LogError("保存包详细分析失败: " + e.Message);
            }
        }
        DebugingBuffStatus(vPackList);
#endif
    }
    /// <summary>
    /// 保存解析后的包详情到文件(仅在编辑器且开启日志时)
    /// </summary>
    private void SavePackageDetailAfterAnalysis(List<GameNetPackBasic> vPackList, string guid)
    {
#if UNITY_EDITOR
        if (Launch.Instance.isOpenSkillLogFile)
        {
            try
            {
                string detailAnalysis = PrintPackageDetailAnalysis(vPackList, guid);
                string filePath = Application.dataPath + "/../BattleReport/PackageAfterDetailAnalysis_" +
                                 DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".txt";
                System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filePath));
                System.IO.File.WriteAllText(filePath, detailAnalysis);
                Debug.Log("包详细分析已保存到: " + filePath);
            }
            catch (Exception e)
            {
                Debug.LogError("保存包详细分析失败: " + e.Message);
            }
        }
#endif
    }
    /// <summary>
    /// 将所有包推送到战场管理器队列
    /// </summary>
    private void PushPackagesToBattle(string guid, List<GameNetPackBasic> vPackList)
    {
        for (int i = 0; i < vPackList.Count; i++)
        {
            BattleManager.Instance.PushPackage(guid, vPackList[i]);
        }
    }
#if UNITY_EDITOR
    /// <summary>
    /// 调试输出Buff状态变更日志到文件
    /// 包括Buff刷新和删除的详细信息,按英雄分组
    /// </summary>
    private void DebugingBuffStatus(List<GameNetPackBasic> vPackList)
    {
        if (!Launch.Instance.isOpenSkillLogFile)
@@ -322,9 +310,12 @@
        System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filePath));
        System.IO.File.WriteAllText(filePath, debugInfo);
    }
#endif
    /// <summary>
    /// 打印包列表的详细信息,支持递归展开子包
    /// 用于调试战斗包的层级结构和内容
    /// </summary>
    private string PrintPackListDetail(List<GameNetPackBasic> packList, int indent, string guid = "")
    {
        string result = string.Empty;
@@ -412,39 +403,6 @@
                        result += $"{indentStr}    [{j}] ExTarget - ObjID:{hurtEx.ObjID} Name:{targetExName} HurtHP:{hurtEx.HurtHP} AttackTypes:{hurtEx.AttackTypes}\n";
                    }
                }
                // 打印子技能列表
                if (skill.subSkillList != null && skill.subSkillList.Count > 0)
                {
                    result += $"{indentStr}  SubSkills ({skill.subSkillList.Count}):\n";
                    int j = 0;
                    foreach (var subSkill in skill.subSkillList)
                    {
                        string subSkillName = SkillConfig.Get((int)subSkill.SkillID)?.SkillName ?? "Unknown";
                        result += $"{indentStr}    [{j}] SubSkill - SkillID:{subSkill.SkillID} SkillName:{subSkillName} RelatedSkillID:{subSkill.RelatedSkillID}\n";
                        j++;
                    }
                }
                // 打印子技能CombinePack列表
                if (skill.subSkillCombinePackList != null && skill.subSkillCombinePackList.Count > 0)
                {
                    result += $"{indentStr}  SubSkillCombinePacks ({skill.subSkillCombinePackList.Count}):\n";
                    int j = 0;
                    foreach (var subCombinePack in skill.subSkillCombinePackList)
                    {
                        var subMainSkill = subCombinePack.GetMainHB427SkillPack();
                        string subMainSkillName = subMainSkill != null ? (SkillConfig.Get((int)subMainSkill.SkillID)?.SkillName ?? "Unknown") : "N/A";
                        result += $"{indentStr}    [{j}] SubCombinePack - Tag:{subCombinePack.startTag?.Tag} MainSkill:{subMainSkill?.SkillID} SkillName:{subMainSkillName} PackCount:{subCombinePack.packList.Count}\n";
                        // 递归打印子CombinePack内部
                        if (subCombinePack.packList.Count > 0)
                        {
                            result += PrintPackListDetail(subCombinePack.packList, indent + 3, guid);
                        }
                        j++;
                    }
                }
            }
            else if (pack is CustomHB426CombinePack combinePack)
            {
@@ -493,7 +451,10 @@
        return result;
    }
    //约定第一个包是B424,先发过来的过滤报错通知
    /// <summary>
    /// 过滤B424初始化包之前的所有包
    /// 约定第一个包必须是B424,之前的包都是错误数据需要过滤
    /// </summary>
    bool FilterBeforeB424(GameNetPackBasic npk)
    {
        if (npk is HB424_tagSCTurnFightInit)
@@ -510,7 +471,10 @@
        return false;
    }
    /// <summary>
    /// 分析并重组包队列
    /// 将服务器原始包列表转换为客户端可执行的战斗包结构
    /// </summary>
    protected List<GameNetPackBasic> AnalysisPackQueueAndDistribute(string guid, List<GameNetPackBasic> vPackList)
    {
        // 建议前端做一个防范机制:当连续多次请求得到空的战斗片段封包时(不包含B425标记的开始跟结束封包,即开始跟中间没有任何封包),强制自动帮玩家回城休息,
@@ -518,72 +482,21 @@
        // 为防止死循环,可强制回城休息,让玩家重新点击关卡战斗或挑战boss,
        // 正常情况下在战锤足够时理论上都可以一直循环刷怪,如果连续多次没有战斗片段封包,比如限制个连续10次以内,就可以理解为异常了
        // const int MaxContinousEmptyCount = 10; // 连续空包最大次数
        List<GameNetPackBasic> packQueueSnapshot = new List<GameNetPackBasic>(vPackList);
        List<GameNetPackBasic> newPackList = BattleManager.ParseBattlePackList(guid, packQueueSnapshot);
        // List<GameNetPackBasic> newPackList = new List<GameNetPackBasic>();
        // HashSet<int> skipIndexes = new HashSet<int>();
        // // 这里已经是按照Dequeue的顺序了
        // for (int i = 0; i < packQueueSnapshot.Count; i++)
        // {
        //     if (skipIndexes.Contains(i)) continue;
        //     GameNetPackBasic pack = packQueueSnapshot[i];
        //     // 碰到B421 截断 往下收集b421里的全部内容
        //     if (pack is HB421_tagMCTurnFightObjAction)
        //     {
        //         HB421_tagMCTurnFightObjAction b421Pack = pack as HB421_tagMCTurnFightObjAction;
        //         List<GameNetPackBasic> b421PackList = new List<GameNetPackBasic>();
        //         i++;    // 跳过当前的B421包
        //         // 收集所有非B421包,直到遇到下一个B421或队列结束
        //         for (; i < packQueueSnapshot.Count; i++)
        //         {
        //             GameNetPackBasic nextPack = packQueueSnapshot[i];
        //             if (nextPack is HB421_tagMCTurnFightObjAction)
        //             {
        //                 i--; // 回退一个位置,留给外层循环处理
        //                 break;
        //             }
        //             else
        //             {
        //                 b421PackList.Add(nextPack);
        //                 skipIndexes.Add(i); // 标记已被合包
        //             }
        //         }
        //         // 合并所有相关包
        //         CustomB421ActionPack actionPack = CustomB421ActionPack.CreateB421ActionPack(guid, b421PackList);
        //         newPackList.Add(actionPack);
        //     }
        //     else
        //     {
        //         newPackList.Add(pack);
        //     }
        // }
        List<GameNetPackBasic> returnList = new List<GameNetPackBasic>();
        for (int i = 0; i < newPackList.Count; i++)
        {
            var pack = newPackList[i];
            returnList.Add(pack);
            returnList.Add(newPackList[i]);
        }
        return returnList;
    }
#if UNITY_EDITOR
    /// <summary>
    /// 深度解析包列表中的所有字段
    /// 深度解析战报包列表的所有字段
    /// 生成详细的包内容分析报告,包括所有字段值
    /// </summary>
    private string PrintPackageDetailAnalysis(List<GameNetPackBasic> packList, string guid)
    {
@@ -608,6 +521,7 @@
    /// <summary>
    /// 递归打印对象的所有字段和属性
    /// 支持基本类型、数组、集合、自定义类型等
    /// </summary>
    private void PrintObjectDetail(StringBuilder sb, object obj, int indent, BattleField battleField, HashSet<object> visitedObjects)
    {
@@ -787,7 +701,8 @@
    }
    /// <summary>
    /// 判断是否为简单类型(直接输出值)
    /// 判断类型是否为简单类型(基本类型、字符串、枚举等)
    /// 简单类型可以直接输出值,不需要递归展开
    /// </summary>
    private bool IsSimpleType(Type type)
    {
@@ -799,7 +714,8 @@
    }
    /// <summary>
    /// 判断是否应该跳过该类型(Unity和System库的复杂类型)
    /// 判断类型是否应该跳过解析
    /// Unity和System库的复杂类型会被跳过以提高性能
    /// </summary>
    private bool ShouldSkipType(Type type)
    {
@@ -822,7 +738,8 @@
    }
    /// <summary>
    /// 获取缩进字符串
    /// 生成指定缩进级别的空格字符串
    /// 用于格式化输出的层级结构
    /// </summary>
    private string GetIndent(int indent)
    {
Main/System/Battle/BattleField/BattleField.cs
@@ -510,8 +510,9 @@
        }
    }
    public virtual void OnObjsDead(List<BattleDeadPack> deadPackList, RecordAction causingRecordAction = null)
    public virtual DeathRecordAction OnObjsDead(List<BattleDeadPack> deadPackList, RecordAction _causingRecordAction = null)
    {
        DeathRecordAction deathRecordAction = null;
        if (deadPackList.Count > 0)
        {
            // 过滤掉正在处理死亡的角色,避免重复处理
@@ -546,19 +547,12 @@
            // 只处理有效的死亡消息
            if (validDeadList.Count > 0)
            {
                DeathRecordAction recordAction = new DeathRecordAction(this, validDeadList, causingRecordAction);
                //  如果有导致死亡的技能,将DeathRecordAction作为其子节点,并设置为WaitingPlay
                if (causingRecordAction != null)
                {
                    recordPlayer.ImmediatelyPlay(recordAction, causingRecordAction, true);
                }
                else
                {
                    recordPlayer.ImmediatelyPlay(recordAction);
                }
                DeathRecordAction recordAction = new DeathRecordAction(this, validDeadList, _causingRecordAction);
                deathRecordAction = recordAction;
            }
        }
        return deathRecordAction;
    }
    public virtual void OnObjReborn(uint objId)
Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs
@@ -15,8 +15,6 @@
    protected Dictionary<int, bool> dropStateDict = new Dictionary<int, bool>();
    protected RecordAction causingRecordAction = null;
    protected bool hasDeathTriggerSkill = false;
    // 标记是否已经分发了死亡后的包
@@ -26,8 +24,16 @@
        : base(RecordActionType.Death, _battleField, null)
    {
        deadPackList = _deadPackList;
        causingRecordAction = _causingRecordAction;
        CheckHasDeathTriggerSkill();
        for (int i = 0; i < deadPackList.Count; i++)
        {
            BattleObject battleObject = battleField.battleObjMgr.GetBattleObject((int)deadPackList[i].deadPack.ObjID);
            Debug.LogError($"DeathRecordAction: 初始化死亡动作,死亡对象名字={battleObject?.teamHero.name}, hasDeathTriggerSkill={deadPackList[i].deadTriggerSkill != null}");
        }
        SetParentAction(_causingRecordAction);
    }
    protected void CheckHasDeathTriggerSkill()
@@ -45,6 +51,8 @@
    public override void Run()
    {
        base.Run();
        //  该死的正常死
        //  有技能的则按照顺序播放死亡技能 后再正常死
        if (isFinish)
@@ -70,7 +78,7 @@
                        // 使用ImmediatelyPlay并设置WaitingPlay=true,可以让死亡技能等待导致死亡的技能完成
                        // 如果DeathRecordAction有父节点(导致死亡的技能),则等待那个父节点
                        // 否则等待DeathRecordAction本身
                        battleField.recordPlayer.ImmediatelyPlay(skillAction, causingRecordAction == null ? this : causingRecordAction, true);
                        battleField.recordPlayer.ImmediatelyPlay(skillAction, parentAction == null ? this : parentAction, true);
                    }
                }
                else
@@ -137,9 +145,9 @@
        }
        
        // 确保在innerRecordPlayer中执行死亡后的包
        if (hasDistributedPacksAfterDeath && causingRecordAction != null)
        if (hasDistributedPacksAfterDeath && parentAction != null)
        {
            var innerPlayer = causingRecordAction.GetInnerRecordPlayer();
            var innerPlayer = parentAction.GetInnerRecordPlayer();
            if (innerPlayer != null && innerPlayer.IsPlaying())
            {
                innerPlayer.Run();
@@ -163,16 +171,38 @@
            return () => true;
        }
        PerformDrop(deadObj);
        bool playDeath = false;
        bool isComplete = false;
        deadObj.OnDeath(() => {
            isComplete = true;
        }, withoutAnime);
        //  如果没有释放技能 则直接死亡
        if (!battleField.IsCastingSkill(deadObj.ObjID))
        {
            PerformDrop(deadObj);
            deadObj.OnDeath(() => {
                isComplete = true;
            }, withoutAnime);
            playDeath = true;
        }
        return () =>
        {
            //  还没播放死亡 并且没释放其他技能
            if (!playDeath && !battleField.IsCastingSkill(deadObj.ObjID))
            {
                PerformDrop(deadObj);
                deadObj.OnDeath(() => {
                    isComplete = true;
                }, withoutAnime);
                playDeath = true;
            }
            if (deadObj.isReborning)
            {
                isComplete = true;
@@ -247,8 +277,6 @@
        {
            if (deadPack.packListAfterDeath != null && deadPack.packListAfterDeath.Count > 0)
            {
                BattleDebug.LogError($"DeathRecordAction.DistributePacksAfterDeath: 开始分发死亡后的包,共 {deadPack.packListAfterDeath.Count} 个包");
                foreach (var pack in deadPack.packListAfterDeath)
                {
                    // 获取包的类型和UID用于调试
@@ -260,33 +288,37 @@
                        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();
                        combinePack.Distribute(parentAction);
                    }
                    // 特殊处理 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);
                            if (parentAction != null)
                            {
                                parentAction.GetInnerRecordPlayer().PlayRecord(skillAction);
                            }
                            else
                            {
                                battleField.PlayRecord(skillAction);
                            }
                        }
                    }
                    else
                    {
                        // 【使用 causingRecordAction 或 battleField.recordPlayer】
                        // 原因:死亡后的包应该回到导致死亡的技能所在的上下文
                        // 如果有 causingRecordAction(导致死亡的技能),则分发到它的 innerRecordPlayer
                        // 如果有 parentAction(导致死亡的技能),则分发到它的 innerRecordPlayer
                        // 否则分发到 battleField.recordPlayer(顶层)
                        if (causingRecordAction != null)
                        if (parentAction != null)
                        {
                            PackageRegeditEx.DistributeToRecordAction(pack, causingRecordAction);
                            PackageRegeditEx.DistributeToRecordAction(pack, parentAction);
                        }
                        else
                        {
@@ -295,6 +327,9 @@
                        }
                    }
                }
                // 分发完成后清理列表,防止重复分发和内存泄漏
                deadPack.packListAfterDeath.Clear();
            }
        }
    }
@@ -333,4 +368,30 @@
    {
        return HasDeathTriggerSkill();
    }
#if UNITY_EDITOR
    /// <summary>
    /// 首次运行时打印日志(仅编辑器)
    /// 打印死亡对象的名字
    /// </summary>
    protected override void PrintFirstRunLog()
    {
        if (deadPackList != null && deadPackList.Count > 0)
        {
            string deadNames = "";
            foreach (var deadPack in deadPackList)
            {
                BattleObject deadObj = battleField.battleObjMgr.GetBattleObject((int)deadPack.deadPack.ObjID);
                string name = deadObj?.teamHero?.name ?? "Unknown";
                deadNames += name + ",";
            }
            deadNames = deadNames.TrimEnd(',');
            Debug.LogError($"[DeathRecordAction首次Run] 死亡对象:{deadNames} 数量:{deadPackList.Count}");
        }
        else
        {
            base.PrintFirstRunLog();
        }
    }
#endif
}
Main/System/Battle/BattleField/RecordActions/RebornRecordAction.cs
@@ -15,16 +15,30 @@
    private Sequence tweenSeq = DOTween.Sequence();
    private List<BattleObject> rebornObjs = new List<BattleObject>();
    public RebornRecordAction(BattleField _battleField, BattleObject rebornObj, Action _callback)
        : base(RecordActionType.Reborn, _battleField, rebornObj)
    public RebornRecordAction(BattleField _battleField, List<BattleObject> _rebornObjs, Action _callback)
        : base(RecordActionType.Reborn, _battleField, null)
    {
        if (_rebornObjs != null)
        {
            foreach (var obj in _rebornObjs)
            {
                if (obj != null)
                {
                    rebornObjs.Add(obj);
                }
            }
        }
        actionCallback = _callback;
    }
    public override void Run()
    {
        base.Run();
        if (isFinish)
            return;
@@ -45,23 +59,45 @@
    //  做一个从透明到恢复的渐变的同时 播放特效
    public void PlayRebornEffect()
    {
        //  播放复活特效
        battleField.battleEffectMgr.PlayEffect(battleObject, BattleConst.RebornEffectID, battleObject.heroRectTrans, battleObject.Camp, battleObject.teamHero.modelScale);
        //  渐变
        battleObject.motionBase.skeletonAnim.skeleton.A = 0f;
        if (rebornObjs.Count == 0)
        {
            actionCallback?.Invoke();
            actionCallback = null;
            isActionCompleted = true;
            isFinish = true;
            return;
        }
        battleField.battleTweenMgr.OnKillTween(tweenSeq);
        tweenSeq = DOTween.Sequence();
        tweenSeq.Append(DOVirtual.Float(0f, 1f, tweenDuration / battleField.speedRatio, value =>
        foreach (var bo in rebornObjs)
        {
            battleObject.motionBase.skeletonAnim.skeleton.A = value;
        }));
            var battleObj = bo;
            Sequence sequence = DOTween.Sequence();
            //  播放复活特效
            battleField.battleEffectMgr.PlayEffect(battleObj, BattleConst.RebornEffectID, battleObj.heroRectTrans, battleObj.Camp, battleObj.teamHero.modelScale);
            //  渐变
            battleObj.motionBase.skeletonAnim.skeleton.A = 0f;
            sequence.Append(DOVirtual.Float(0f, 1f, tweenDuration / battleField.speedRatio, value =>
            {
                battleObj.motionBase.skeletonAnim.skeleton.A = value;
            }));
            tweenSeq.Join(sequence);
        }
        tweenSeq.Append(DOVirtual.DelayedCall(keepDuration / battleField.speedRatio, () =>
        {
            battleObject?.AfterReborn();
            foreach (var bo in rebornObjs)
            {
                var battleObj = bo;
                battleObj?.AfterReborn();
            }
            actionCallback?.Invoke();
            actionCallback = null;
            isActionCompleted = true;  // 标记动作完成
@@ -81,9 +117,12 @@
        battleField.battleTweenMgr.OnKillTween(tweenSeq);
        battleObject.motionBase.skeletonAnim.skeleton.A = 1f;
        battleObject?.AfterReborn();
        foreach (var bo in rebornObjs)
        {
            var battleObj = bo;
            battleObj.motionBase.skeletonAnim.skeleton.A = 1f;
            battleObj.AfterReborn();
        }
        actionCallback?.Invoke();
Main/System/Battle/BattleField/RecordActions/SkillRecordAction.cs
@@ -3,7 +3,12 @@
public class SkillRecordAction : RecordAction
{
    protected SkillBase skillBase;
#if UNITY_EDITOR
    public
#else
    protected
#endif
        SkillBase skillBase;
    public HB427_tagSCUseSkill hB427_TagSCUseSkill;
@@ -28,6 +33,13 @@
            skillBase.SetParentRecordAction(this);
        }
    }
    public override void AfterAddToQueue()
    {
        base.AfterAddToQueue();
        skillBase?.AfterAddToQueue();
    }
    public override bool IsNeedWaiting()
    {
        if (skillBase == null)
@@ -92,7 +104,6 @@
        return base.CanStartExecution();
    }
    public override void Run()
    {
        base.Run();
@@ -121,4 +132,25 @@
            isCast = true;
        }
    }
#if UNITY_EDITOR
    /// <summary>
    /// 首次运行时打印日志(仅编辑器)
    /// 打印施法者名字、技能ID和技能名字
    /// </summary>
    protected override void PrintFirstRunLog()
    {
        if (skillBase != null && skillBase.caster != null)
        {
            string casterName = skillBase.caster.teamHero?.name ?? "Unknown";
            int skillId = skillBase.skillConfig?.SkillID ?? 0;
            string skillName = skillBase.skillConfig?.SkillName ?? "Unknown";
            Debug.LogError($"[SkillRecordAction首次Run] 施法者:{casterName} 技能ID:{skillId} 技能名:{skillName}");
        }
        else
        {
            base.PrintFirstRunLog();
        }
    }
#endif
}
Main/System/Battle/BattleManager.cs
@@ -192,10 +192,6 @@
                {
                    temp += "  pack type is " + pack.GetType().Name + " tag is " + (b426Pack.startTag != null ? b426Pack.startTag.Tag : "null") + "\n";
                }
                else if (pack is CustomB421ActionPack b421Pack)
                {
                    temp += "  pack type is " + pack.GetType().Name + " guid is " + b421Pack.guid + "\n";
                }
                else
                {
                    temp += "  pack type is " + pack.GetType().Name + "\n";
@@ -336,10 +332,6 @@
            if (pack is CustomHB426CombinePack combinePack)
            {
                combinePack.Distribute();
            }
            else if (pack is CustomB421ActionPack actionPack)
            {
                actionPack.Distribute();
            }
            else
            {
@@ -482,10 +474,6 @@
            if (pack is CustomHB426CombinePack combinePack)
            {
                combinePack.Distribute();
            }
            else if (pack is CustomB421ActionPack actionPack)
            {
                actionPack.Distribute();
            }
            else
            {
Main/System/Battle/BattleObject/BattleObject.cs
@@ -315,8 +315,9 @@
        return true;
    }
    public virtual void Hurt(BattleHurtParam battleHurtParam, RecordAction causingRecordAction = null)
    public virtual RecordAction Hurt(BattleHurtParam battleHurtParam, RecordAction _causingRecordAction = null)
    {
        RecordAction recordAction = null;
        bool isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillConfig.DamageDivide.Length - 1;
        bool firstHit = battleHurtParam.hitIndex == 0;
        
@@ -356,7 +357,7 @@
            {
                PushDropItems(battleHurtParam.battleDrops);
            }
            battleField.OnObjsDead(new List<BattleDeadPack>() { battleHurtParam.deadPack }, causingRecordAction);
            recordAction = battleField.OnObjsDead(new List<BattleDeadPack>() { battleHurtParam.deadPack }, _causingRecordAction);
        }
        else
@@ -378,6 +379,8 @@
            // }
        }
        return recordAction;
    }
    /// <summary>
@@ -493,7 +496,7 @@
    }
    //  复活action
    public void OnReborn(HB427_tagSCUseSkill.tagSCUseSkillHurt vNetData, bool reviveSelf = false)
    public void OnReborn(HB427_tagSCUseSkill.tagSCUseSkillHurt vNetData, bool reviveSelf = false, RecordAction parentAction = null)
    {
        isReborning = true;
        heroGo.SetActive(true);
@@ -501,20 +504,7 @@
        heroRectTrans.anchoredPosition = Vector2.zero;
        motionBase.skeletonAnim.skeleton.A = 0f;
        motionBase.skeletonAnim.LateUpdate();
        RebornRecordAction recordAction = new RebornRecordAction(battleField, this, () =>
        {
            battleField.OnObjReborn((uint)ObjID);
            teamHero.curHp = GeneralDefine.GetFactValue(vNetData.CurHP, vNetData.CurHPEx);
            // Debug.LogError("OnReborn " + teamHero.curHp);
            teamHero.isDead = false;
        });
        // 【使用 BattleField.recordPlayer】
        // 原因:复活是角色的独立行为,不是技能内部产生的
        // 复活可能是被动触发的(如死亡后服务器发来的复活包),应该由主RecordPlayer管理
        // 使用InsertRecord可以插到队列最前面,保证复活表现的优先级
        battleField.recordPlayer.InsertRecord(recordAction);
    }
    public void AfterReborn()
Main/System/Battle/BattleTweenMgr.cs
@@ -56,9 +56,9 @@
        tween.Play();
    }
    public void OnKillTween(Tween tween)
    public void OnKillTween(Tween tween, bool complete = false)
    {
        tween?.Kill();
        tween?.Kill(complete);
        if (tween != null && tweenList.Contains(tween))
        {
            tweenList.Remove(tween);
Main/System/Battle/BattleUtility.cs
@@ -259,7 +259,7 @@
                    BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                    if (target == null)
                    {
                        Debug.LogError("GetMainTargetPositionNum 找不到目标 ObjId : " + hurt.ObjID);
                        Debug.LogError("GetMainTargetPositionNum 找不到目标 ObjId : " + hurt.ObjID + " skill id " + skillConfig.SkillID);
                        continue;
                    }
                    else
@@ -281,7 +281,7 @@
                }
                else
                {
                    Debug.LogError("GetMainTargetPositionNum 找不到跟随主技能的目标");
                    Debug.LogError("GetMainTargetPositionNum 找不到跟随主技能的目标 " + skillConfig.SkillID);
                    returnIndex = 0;
                }
                break;
Main/System/Battle/RecordPlayer/RecordAction.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System;
using UnityEngine;
public class RecordAction
{
@@ -13,6 +13,12 @@
    protected bool isFinish = false;
    protected bool isRunOnce = false;
#if UNITY_EDITOR
    //  是否已打印首次运行日志(仅用于调试)
    private bool hasLoggedFirstRun = true;
#endif
    //  ===== 父子关系和等待机制 =====
    //  父RecordAction引用(如果是通过其他RecordAction内部触发的)
@@ -37,6 +43,8 @@
    //  3. 不会干扰BattleField主RecordPlayer的播放队列
    protected RecordPlayer innerRecordPlayer;
    public RecordPlayer actionOwner { get; set; }
    public RecordAction(RecordActionType _actionType, BattleField _battleField, BattleObject _battleObj)
    {
        actionType = _actionType;
@@ -50,6 +58,11 @@
            innerRecordPlayer = new RecordPlayer();
            innerRecordPlayer.Init(_battleField);
        }
    }
    public virtual void AfterAddToQueue()
    {
    }
    public virtual void Played()
@@ -162,12 +175,32 @@
    public virtual void Run()
    {
#if UNITY_EDITOR
        // 首次运行时打印调试信息
        if (!hasLoggedFirstRun)
        {
            hasLoggedFirstRun = true;
            PrintFirstRunLog();
        }
#endif
        //  先运行内部RecordPlayer
        //  原因:内部产生的RecordAction需要先执行,确保内部逻辑按正确顺序播放
        //  例如:技能内部产生的Buff添加、子技能等都由innerRecordPlayer管理
        innerRecordPlayer?.Run();
    }
#if UNITY_EDITOR
    /// <summary>
    /// 首次运行时打印日志(仅编辑器)
    /// 子类可以重写此方法自定义打印内容
    /// </summary>
    protected virtual void PrintFirstRunLog()
    {
        Debug.LogError($"[RecordAction首次Run] {GetType().Name}");
    }
#endif
    public virtual void ForceFinish()
    {
        isFinish = true;
Main/System/Battle/RecordPlayer/RecordPlayer.cs
@@ -43,6 +43,7 @@
    public void PlayRecord(RecordAction recordAction)
    {
        if (recordAction == null) return;
        recordAction.actionOwner = this;
        // Debug.LogError("Enqueue record action " + recordAction.GetType() + " to queue");
        if (isForceFinish || stepForcefinish)
        {
@@ -50,6 +51,7 @@
            return;
        }
        recordActionQueue.Enqueue(recordAction);
        recordAction.AfterAddToQueue();
    }
    public void PlayRecord(List<RecordAction> recordActions)
@@ -60,9 +62,10 @@
        }
    }
    public void InsertRecord(RecordAction recordAction)
    public void InsertRecord(RecordAction recordAction, int position = 0)
    {
        if (recordAction == null) return;
        recordAction.actionOwner = this;
        if (isForceFinish || stepForcefinish)
        {
            recordAction.ForceFinish();
@@ -73,22 +76,33 @@
        if (currentRecordAction != null)
        {
            Queue<RecordAction> tempQueue = new Queue<RecordAction>();
            for (int i = 0; i < position && recordActionQueue.Count > 0; i++)
            {
                tempQueue.Enqueue(recordActionQueue.Dequeue());
            }
            tempQueue.Enqueue(recordAction);
            while (recordActionQueue.Count > 0)
            {
                tempQueue.Enqueue(recordActionQueue.Dequeue());
            }
            recordActionQueue = tempQueue;
        }
        else
        {
            recordActionQueue.Enqueue(recordAction);
        }
        recordAction.AfterAddToQueue();
    }
    public void ImmediatelyPlay(RecordAction recordAction)
    {
        if (recordAction == null) return;
        recordAction.actionOwner = this;
        if (isForceFinish || stepForcefinish)
        {
            recordAction.ForceFinish();
@@ -101,6 +115,7 @@
    public void ImmediatelyPlay(RecordAction recordAction, RecordAction parentAction, bool isWaitingPlay)
    {
        if (recordAction == null) return;
        recordAction.actionOwner = this;
        if (isForceFinish || stepForcefinish)
        {
            recordAction.ForceFinish();
@@ -238,7 +253,16 @@
            if (recordActionQueue.Count > 0)
            {
                currentRecordAction = recordActionQueue.Dequeue();
                // BattleDebug.LogError("play record action " + currentRecordAction.GetType());
                #if UNITY_EDITOR
                // if (currentRecordAction is SkillRecordAction skillRecordAction)
                // {
                //     Debug.LogError("RecordPlayer Run Play SkillRecordAction skillname " + skillRecordAction.skillBase.skillConfig.SkillName + " caster " + skillRecordAction.skillBase.caster.teamHero.name);
                // }
                // else
                #endif
                {
                    BattleDebug.LogError("play record action " + currentRecordAction.GetType());
                }
            }
        }
    }
Main/System/Battle/Skill/RebornSkill.cs
@@ -14,17 +14,45 @@
    }
    public override void AfterAddToQueue()
    {
        base.AfterAddToQueue();
    }
    protected override void OnHitTargets(int _hitIndex, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hitList)
    {
        List<BattleObject> rebornTargets = new List<BattleObject>();
        for (int i = 0; i < hitList.Count; i++)
        {
            var hurt = hitList[i];
            BattleObject battleObject = battleField.battleObjMgr.GetBattleObject((int)hitList[i].ObjID);
            if (battleObject != null)
            {
                battleObject.OnReborn(hurt, hurt.ObjID == caster.teamHero.ObjID);
                battleObject.OnReborn(hurt, hurt.ObjID == caster.teamHero.ObjID, parentRecordAction);
                rebornTargets.Add(battleObject);
            }
        }
        RebornRecordAction recordAction = new RebornRecordAction(battleField, rebornTargets, () =>
        {
            for (int i = 0; i < tagUseSkillAttack.HurtList.Length; i++)
            {
                var hurt = tagUseSkillAttack.HurtList[i];
                BattleObject battleObject = battleField.battleObjMgr.GetBattleObject((int)tagUseSkillAttack.HurtList[i].ObjID);
                if (battleObject != null)
                {
                    battleField.OnObjReborn(tagUseSkillAttack.HurtList[i].ObjID);
                    battleObject.teamHero.curHp = GeneralDefine.GetFactValue(hurt.CurHP, hurt.CurHPEx);
                    // Debug.LogError("OnReborn " + teamHero.curHp);
                    battleObject.teamHero.isDead = false;
                }
            }
        });
        battleField.recordPlayer.ImmediatelyPlay(recordAction);
        bool vValue = true;
@@ -80,20 +108,5 @@
        return false;
    }
    public override void OnMiddleFrameStart(int times)
    {
        skillEffect.OnMiddleFrameStart(times); // 修复:添加空值检查
    }
    // 技能中摇结束回调:通知技能效果处理中摇结束
    public override void OnMiddleFrameEnd(int times, int hitIndex)
    {
        skillEffect.OnMiddleFrameEnd(times, hitIndex); // 修复:添加空值检查
    }
    public override void OnFinalFrameEnd()
    {
        skillEffect?.OnFinalFrameEnd(); // 修复:添加空值检查
    }
}