Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB430_tagSCTurnFightReport.cs
@@ -86,6 +86,10 @@ } } #if UNITY_EDITOR // 解析所有vPackList里的每个字段(深度)并且输出到Application.dataPath + "/../BattleReport/PackageDetailAnalysis_时间戳.txt文件里 string originPack = string.Empty; BattleField battleField = BattleManager.Instance.GetBattleField(guid); @@ -172,7 +176,23 @@ } #endif #region Start Print Pack List Detail if (Launch.Instance.isOpenSkillLogFile) { try { string detailAnalysis = PrintPackageDetailAnalysis(vPackList, guid); string filePath = Application.dataPath + "/../BattleReport/PackageDetailAnalysis_" + 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 for (int i = 0; i < vPackList.Count; i++) { @@ -571,4 +591,253 @@ } return returnList; } #if UNITY_EDITOR /// <summary> /// 深度解析包列表中的所有字段 /// </summary> private string PrintPackageDetailAnalysis(List<GameNetPackBasic> packList, string guid) { StringBuilder sb = new StringBuilder(); sb.AppendLine("====================================================="); sb.AppendLine("战报包详细分析 - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); sb.AppendLine("GUID: " + guid); sb.AppendLine("包总数: " + packList.Count); sb.AppendLine("=====================================================\n"); BattleField battleField = BattleManager.Instance.GetBattleField(guid); for (int i = 0; i < packList.Count; i++) { sb.AppendLine($"【包 #{i}】 =========================================="); PrintObjectDetail(sb, packList[i], 0, battleField, new HashSet<object>()); sb.AppendLine(); } return sb.ToString(); } /// <summary> /// 递归打印对象的所有字段和属性 /// </summary> private void PrintObjectDetail(StringBuilder sb, object obj, int indent, BattleField battleField, HashSet<object> visitedObjects) { if (obj == null) { sb.AppendLine(GetIndent(indent) + "null"); return; } Type type = obj.GetType(); string indentStr = GetIndent(indent); // 防止循环引用 if (visitedObjects.Contains(obj)) { sb.AppendLine(indentStr + $"<循环引用: {type.Name}>"); return; } // 基本类型和字符串直接输出 if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal)) { sb.AppendLine(indentStr + obj.ToString()); return; } // 枚举类型 if (type.IsEnum) { sb.AppendLine(indentStr + $"{obj} ({(int)obj})"); return; } // 添加到已访问集合(仅对引用类型) if (!type.IsValueType) { visitedObjects.Add(obj); } // 输出类型名 sb.AppendLine(indentStr + $"[{type.Name}]"); // 处理数组 if (type.IsArray) { Array array = obj as Array; sb.AppendLine(indentStr + $"Length: {array.Length}"); if (array.Length > 0) { for (int i = 0; i < array.Length; i++) { sb.AppendLine(indentStr + $" [{i}]:"); PrintObjectDetail(sb, array.GetValue(i), indent + 2, battleField, visitedObjects); } } return; } // 处理List、HashSet等集合 if (obj is System.Collections.IEnumerable && !(obj is string)) { var enumerable = obj as System.Collections.IEnumerable; int count = 0; var enumerator = enumerable.GetEnumerator(); while (enumerator.MoveNext()) count++; sb.AppendLine(indentStr + $"Count: {count}"); if (count > 0) { int index = 0; foreach (var item in enumerable) { sb.AppendLine(indentStr + $" [{index}]:"); PrintObjectDetail(sb, item, indent + 2, battleField, visitedObjects); index++; } } return; } // 获取所有公共字段 var fields = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); foreach (var field in fields) { // 跳过Unity和System库的复杂类型(但保留基本类型) Type fieldType = field.FieldType; if (ShouldSkipType(fieldType)) { continue; } try { object value = field.GetValue(obj); // 特殊处理:显示ObjID对应的武将名字 if (field.Name == "ObjID" && value is uint objId && battleField != null) { var battleObj = battleField.battleObjMgr.GetBattleObject((int)objId); string heroName = battleObj?.teamHero?.name ?? "Unknown"; sb.AppendLine(indentStr + $" {field.Name} ({fieldType.Name}): {value} [{heroName}]"); } // 特殊处理:显示SkillID对应的技能名字 else if (field.Name == "SkillID" && value is uint skillId) { string skillName = SkillConfig.Get((int)skillId)?.SkillName ?? "Unknown"; sb.AppendLine(indentStr + $" {field.Name} ({fieldType.Name}): {value} [{skillName}]"); } // 特殊处理:显示HeroID对应的英雄名字 else if (field.Name == "HeroID" && value is uint heroId) { string heroName = HeroConfig.Get((int)heroId)?.Name ?? "Unknown"; sb.AppendLine(indentStr + $" {field.Name} ({fieldType.Name}): {value} [{heroName}]"); } else if (IsSimpleType(fieldType)) { sb.AppendLine(indentStr + $" {field.Name} ({fieldType.Name}): {value}"); } else { sb.AppendLine(indentStr + $" {field.Name} ({fieldType.Name}):"); PrintObjectDetail(sb, value, indent + 2, battleField, visitedObjects); } } catch (Exception e) { sb.AppendLine(indentStr + $" {field.Name}: <解析错误: {e.Message}>"); } } // 获取所有公共属性 var properties = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); foreach (var prop in properties) { // 跳过索引器 if (prop.GetIndexParameters().Length > 0) { continue; } // 跳过Unity和System库的复杂类型 Type propType = prop.PropertyType; if (ShouldSkipType(propType)) { continue; } // 只读取有getter的属性 if (!prop.CanRead) { continue; } try { object value = prop.GetValue(obj, null); if (IsSimpleType(propType)) { sb.AppendLine(indentStr + $" {prop.Name} ({propType.Name}): {value}"); } else { sb.AppendLine(indentStr + $" {prop.Name} ({propType.Name}):"); PrintObjectDetail(sb, value, indent + 2, battleField, visitedObjects); } } catch (Exception e) { sb.AppendLine(indentStr + $" {prop.Name}: <解析错误: {e.Message}>"); } } } /// <summary> /// 判断是否为简单类型(直接输出值) /// </summary> private bool IsSimpleType(Type type) { return type.IsPrimitive || type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime) || type.IsEnum; } /// <summary> /// 判断是否应该跳过该类型(Unity和System库的复杂类型) /// </summary> private bool ShouldSkipType(Type type) { if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal) || type.IsEnum) { return false; } string typeNamespace = type.Namespace ?? ""; // 跳过Unity相关类型(除了基本类型) if (typeNamespace.StartsWith("UnityEngine") || typeNamespace.StartsWith("Unity.") || typeNamespace.StartsWith("System.") && !typeNamespace.StartsWith("System.Collections")) { return true; } return false; } /// <summary> /// 获取缩进字符串 /// </summary> private string GetIndent(int indent) { return new string(' ', indent * 2); } #endif } Main/System/Battle/BattleField/BattleField.cs
@@ -510,7 +510,7 @@ } } public virtual void OnObjsDead(List<BattleDeadPack> deadPackList) public virtual void OnObjsDead(List<BattleDeadPack> deadPackList, RecordAction causingRecordAction = null) { if (deadPackList.Count > 0) { @@ -545,7 +545,15 @@ if (validDeadList.Count > 0) { DeathRecordAction recordAction = new DeathRecordAction(this, validDeadList); recordPlayer.ImmediatelyPlay(recordAction); // 如果有导致死亡的技能,将DeathRecordAction作为其子节点,并设置为WaitingPlay if (causingRecordAction != null) { recordPlayer.ImmediatelyPlay(recordAction, causingRecordAction, true); } else { recordPlayer.ImmediatelyPlay(recordAction); } } } } Main/System/Battle/BattleField/RecordActions/BattleEndAction.cs
@@ -22,6 +22,7 @@ { base.Run(); isActionCompleted = true; isFinish = true; onComplete?.Invoke(); } @@ -34,6 +35,11 @@ onComplete?.Invoke(); } public override bool IsActionCompleted() { return isActionCompleted || isFinish; } public override bool IsFinished() { return isFinish; Main/System/Battle/BattleField/RecordActions/BattleStartAction.cs
@@ -16,6 +16,11 @@ return isFinish; } public override bool IsActionCompleted() { return isActionCompleted || isFinish; } public override void Run() { @@ -55,6 +60,7 @@ private void StartBattleCallback() { isActionCompleted = true; isFinish = true; EventBroadcast.Instance.Broadcast(EventName.DISPLAY_BATTLE_UI, battleField.guid, true); battleField.DistributeNextPackage(); Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs
@@ -15,10 +15,28 @@ protected Dictionary<int, bool> dropStateDict = new Dictionary<int, bool>(); public DeathRecordAction(BattleField _battleField, List<BattleDeadPack> _deadPackList) protected RecordAction causingRecordAction = null; protected bool hasDeathTriggerSkill = false; public DeathRecordAction(BattleField _battleField, List<BattleDeadPack> _deadPackList, RecordAction _causingRecordAction = null) : base(RecordActionType.Death, _battleField, null) { deadPackList = _deadPackList; causingRecordAction = _causingRecordAction; CheckHasDeathTriggerSkill(); } protected void CheckHasDeathTriggerSkill() { foreach (var battleDeadPack in deadPackList) { if (battleDeadPack.deadTriggerSkill != null) { hasDeathTriggerSkill = true; break; } } } @@ -42,6 +60,10 @@ if (null != skillAction) { deathActionDict.Add(battleDeadPack, skillAction); // 死亡触发技能都设置WaitingPlay=true,等待父节点动作完成 // 如果DeathRecordAction有父节点(导致死亡的技能),则等待那个父节点 // 否则等待DeathRecordAction本身 battleField.recordPlayer.ImmediatelyPlay(skillAction, causingRecordAction == null ? this : causingRecordAction, true); } } else @@ -78,6 +100,11 @@ deathActionDict.Remove(key); } if (0 == deathActionDict.Count) { hasDeathTriggerSkill = false; } int completeNum = 0; foreach (var kv in deadActionStatesDict) @@ -90,9 +117,18 @@ if (completeNum == deadPackList.Count) { isActionCompleted = true; isFinish = true; } } } // 重写IsActionCompleted,死亡动作是否完成 public override bool IsActionCompleted() { return isActionCompleted || isFinish; } private Func<bool> CreateDeadActionState(BattleDeadPack deadPack, bool withoutAnime = false) @@ -166,4 +202,39 @@ deadObj.PerformDrop(); } } protected bool HasDeathTriggerSkill() { return hasDeathTriggerSkill; } public override bool CanStartExecution() { // 如果不是WaitingPlay模式,直接可以执行 if (!isWaitingPlay) { return true; } // 如果没有父节点,也可以执行 if (parentAction == null) { return true; } // 可以先执行没有死亡触发技能的死亡动作 if (!HasDeathTriggerSkill()) { return true; } // WaitingPlay模式下,需要等待直接父节点的动作完成(不管父节点是否WaitingPlay) if (!parentAction.IsActionCompleted()) { BattleDebug.LogError($"RecordAction.CanStartExecution: {this.GetType().Name} 等待父节点 {parentAction.GetType().Name} 动作完成"); return false; } return true; } } Main/System/Battle/BattleField/RecordActions/RebornRecordAction.cs
@@ -36,6 +36,12 @@ } } // 重写IsActionCompleted,当动画播放结束时标记为完成 public override bool IsActionCompleted() { return isActionCompleted || isFinish; } // 做一个从透明到恢复的渐变的同时 播放特效 public void PlayRebornEffect() { @@ -58,6 +64,7 @@ battleObject?.AfterReborn(); actionCallback?.Invoke(); actionCallback = null; isActionCompleted = true; // 标记动作完成 isFinish = true; })); Main/System/Battle/BattleField/RecordActions/RoundChangeAction.cs
@@ -18,6 +18,7 @@ return; roundChangeCallback?.Invoke(); isActionCompleted = true; isFinish = true; } @@ -27,6 +28,12 @@ return; base.Run(); roundChangeCallback?.Invoke(); isActionCompleted = true; isFinish = true; } public override bool IsActionCompleted() { return isActionCompleted || isFinish; } } Main/System/Battle/BattleField/RecordActions/SkillRecordAction.cs
@@ -5,6 +5,8 @@ { protected SkillBase skillBase; public HB427_tagSCUseSkill hB427_TagSCUseSkill; private bool isCast = false; public SkillBase fromSkill = null; @@ -15,12 +17,26 @@ // Debug.LogError("_caster == null : " + (_caster == null)); skillBase = SkillFactory.CreateSkill(_caster, vNetData, packList, _battleField); hB427_TagSCUseSkill = vNetData; if (null == skillBase) { BattleUtility.ForceFinishBattlePackList(battleField, packList); } else { // 让SkillBase知道自己的RecordAction skillBase.SetParentRecordAction(this); } } public override bool IsNeedWaiting() { if (skillBase == null) { return false; } return !string.IsNullOrEmpty(skillBase.skillConfig.SkillMotionName); } public override bool IsFinished() { @@ -29,6 +45,16 @@ return true; } return skillBase.IsFinished(); } // 检查自身动作是否完成(不包括子节点) public override bool IsActionCompleted() { if (null == skillBase) { return true; } return skillBase.IsFinishedForJudge(); } public bool IsFinishedForJudge() @@ -49,6 +75,23 @@ } base.ForceFinish(); } public override bool CanStartExecution() { if (null == skillBase) { return false; } if (!skillBase.CanStartExecution()) { return false; } return base.CanStartExecution(); } public override void Run() { @@ -67,6 +110,8 @@ if (isCast) return; Played(); if (fromSkill != null) { BattleDebug.LogError("cast skill from skill : " + fromSkill.skillConfig.SkillID); Main/System/Battle/BattleObject/BattleObject.cs
@@ -315,7 +315,7 @@ return true; } public virtual void Hurt(BattleHurtParam battleHurtParam) public virtual void Hurt(BattleHurtParam battleHurtParam, RecordAction causingRecordAction = null) { bool isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillConfig.DamageDivide.Length - 1; bool firstHit = battleHurtParam.hitIndex == 0; @@ -352,7 +352,7 @@ { PushDropItems(battleHurtParam.battleDrops); } battleField.OnObjsDead(new List<BattleDeadPack>() { battleHurtParam.deadPack }); battleField.OnObjsDead(new List<BattleDeadPack>() { battleHurtParam.deadPack }, causingRecordAction); } else Main/System/Battle/Motion/MotionBase.cs
@@ -2,6 +2,7 @@ using System.Collections.Generic; using UnityEngine; using Spine.Unity; using Cysharp.Threading.Tasks; public class MotionBase { @@ -64,6 +65,7 @@ PlayAnimation(MotionName.idle, true); SetupAnimationHandlers(); skillTrack = null; if (skelAnim.gameObject != null) illusionShadow = skelAnim.gameObject.AddMissingComponent<SkeletonIllusionShadow>(); @@ -173,6 +175,9 @@ 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) { @@ -215,10 +220,22 @@ } } Spine.TrackEntry skillTrack = null; if (hasAnim) { if (null != skillTrack) { //等待上一技能动画结束 暂时处理办法 UniTaskExtension.DelayFrames((GameObject)null, 1, () => { if (skillBase != null && !skillBase.IsFinished()) { PlaySkillAnimation(skillConfig, skillBase, isSubSkill, onComplete); } }); return null; } skillTrack = animState.SetAnimation(trackIndex, targetAnim, false); if (null == skillTrack) { @@ -441,6 +458,7 @@ RemoveAction(frameHandler); onComplete?.Invoke(); skillBase.OnFinalFrameEnd(); skillTrack = null; } } }; @@ -599,6 +617,8 @@ availableSubTracks.Enqueue(i); currentTrack = null; skillTrack = null; playingSkillAnim = false; PlayAnimation(MotionName.idle, true); @@ -657,7 +677,7 @@ skeleton.SetToSetupPose(); // skeleton.UpdateWorldTransform(); } skillTrack = null; // 10. 播放待机动画 PlayAnimation(MotionName.idle, true); skeletonAnim.LateUpdate(); @@ -678,4 +698,9 @@ } } public bool CanCastSkill() { // 上次释放的技能 释放结束了没有 return !playingSkillAnim; } } Main/System/Battle/RecordPlayer/RecordAction.cs
@@ -14,6 +14,19 @@ protected bool isRunOnce = false; // ===== 父子关系和等待机制 ===== // 父RecordAction引用(如果是通过其他RecordAction内部触发的) public RecordAction parentAction; // 子RecordAction列表(此RecordAction内部触发的其他RecordAction) protected List<RecordAction> childActionList = new List<RecordAction>(); // 是否是WaitingPlay模式(需要等待父节点动作完成) public bool isWaitingPlay = false; // 自身动作是否完成(不包括子节点的完成状态) protected bool isActionCompleted = false; public RecordAction(RecordActionType _actionType, BattleField _battleField, BattleObject _battleObj) { actionType = _actionType; @@ -21,11 +34,105 @@ battleObject = _battleObj; } public virtual void Played() { } public RecordActionType actionType; // 添加子RecordAction public virtual void AddChildAction(RecordAction child) { if (child == null) return; // 防止重复添加 if (childActionList.Contains(child)) return; // 防止循环依赖 if (child == this) { BattleDebug.LogError("RecordAction.AddChildAction: 不能将自己添加为子节点"); return; } childActionList.Add(child); BattleDebug.LogError($"RecordAction.AddChildAction: {this.GetType().Name} 添加子节点 {child.GetType().Name}"); } // 设置父RecordAction public virtual void SetParentAction(RecordAction parent) { parentAction = parent; if (parent != null) { BattleDebug.LogError($"RecordAction.SetParentAction: {this.GetType().Name} 的父节点设置为 {parent.GetType().Name}"); } } // 设置WaitingPlay标记 public virtual void SetWaitingPlay(bool waiting) { isWaitingPlay = waiting; BattleDebug.LogError($"RecordAction.SetWaitingPlay: {this.GetType().Name} WaitingPlay={waiting}"); } // 检查自身动作是否完成(不包括子节点) // 子类应该重写此方法来实现自己的动作完成判断 public virtual bool IsActionCompleted() { return isActionCompleted; } // 检查是否可以开始执行(WaitingPlay条件检查) public virtual bool CanStartExecution() { // 如果不是WaitingPlay模式,直接可以执行 if (!isWaitingPlay) { return true; } // 如果没有父节点,也可以执行 if (parentAction == null) { return true; } // WaitingPlay模式下,需要等待直接父节点的动作完成(不管父节点是否WaitingPlay) if (!parentAction.IsActionCompleted()) { BattleDebug.LogError($"RecordAction.CanStartExecution: {this.GetType().Name} 等待父节点 {parentAction.GetType().Name} 动作完成"); return false; } return true; } public virtual bool IsNeedWaiting() { return false; } // 检查是否完全完成(包括所有子节点) public virtual bool IsFinished() { return isFinish; // 首先自身动作必须完成 if (!isActionCompleted && !isFinish) { return false; } // 检查所有子节点是否完成 foreach (var child in childActionList) { if (!child.IsFinished()) { return false; } } return true; } public virtual void Run() @@ -36,6 +143,18 @@ public virtual void ForceFinish() { isFinish = true; isActionCompleted = true; // 强制结束所有子节点 for (int i = childActionList.Count - 1; i >= 0; i--) { var child = childActionList[i]; child?.ForceFinish(); } // 清理父子引用,防止内存泄漏 childActionList.Clear(); parentAction = null; } public virtual string GetBattleFieldGuid() Main/System/Battle/RecordPlayer/RecordPlayer.cs
@@ -43,7 +43,7 @@ public void PlayRecord(RecordAction recordAction) { if (recordAction == null) return; BattleDebug.LogError("Enqueue record action " + recordAction.GetType()); // Debug.LogError("Enqueue record action " + recordAction.GetType() + " to queue"); if (isForceFinish || stepForcefinish) { recordAction.ForceFinish(); @@ -69,7 +69,7 @@ return; } BattleDebug.LogError("Insert record action " + recordAction.GetType()); // Debug.LogError("Insert record action " + recordAction.GetType() + " at front of queue"); if (currentRecordAction != null) { Queue<RecordAction> tempQueue = new Queue<RecordAction>(); @@ -97,13 +97,39 @@ immediatelyActionList.Add(recordAction); } // 增强版本:支持父子关系和WaitingPlay标记 public void ImmediatelyPlay(RecordAction recordAction, RecordAction parentAction, bool isWaitingPlay) { if (recordAction == null) return; if (isForceFinish || stepForcefinish) { recordAction.ForceFinish(); return; } // Debug.LogError("insert recordAction ImmediatelyPlay: " + recordAction.GetType().Name + " parentAction: " + (parentAction != null ? parentAction.GetType().Name : "null") + " isWaitingPlay: " + isWaitingPlay); // 设置父子关系 if (parentAction != null) { recordAction.SetParentAction(parentAction); parentAction.AddChildAction(recordAction); } // 设置WaitingPlay标记 recordAction.SetWaitingPlay(isWaitingPlay); immediatelyActionList.Add(recordAction); } protected void ImmediatelyPlayRun() { if (immediatelyActionList.Count > 0) { List<int> removeIndexList = new List<int>(); for (int i = immediatelyActionList.Count - 1; i >= 0; i--) // 关键修复:从前往后遍历,确保按加入顺序执行 for (int i = 0; i < immediatelyActionList.Count; i++) { var action = immediatelyActionList[i]; if (action == null) @@ -111,6 +137,38 @@ removeIndexList.Add(i); continue; } // 检查是否可以开始执行(WaitingPlay条件检查) if (!action.CanStartExecution()) { continue; } // 检查同级的前置兄弟节点:如果有相同父节点且索引更小的节点还在执行,则等待 bool shouldWaitForSibling = false; if (action.isWaitingPlay && action.parentAction != null) { for (int j = 0; j < i; j++) { var prevAction = immediatelyActionList[j]; if (prevAction != null && prevAction.parentAction == action.parentAction) { // 找到同级前置节点,如果它还在执行中,则当前节点需要等待 if (!prevAction.IsFinished()) { shouldWaitForSibling = true; // BattleDebug.LogError($"RecordPlayer: {action.GetType().Name} 等待同级前置节点 {prevAction.GetType().Name} 完成"); break; } } } } if (shouldWaitForSibling) { continue; } if (!action.IsFinished()) { action.Run(); @@ -120,6 +178,7 @@ removeIndexList.Add(i); } // 从后往前删除,确保索引不会因为删除而错位 for (int i = removeIndexList.Count - 1; i >= 0; i--) { int index = removeIndexList[i]; @@ -166,7 +225,7 @@ if (currentRecordAction != null && currentRecordAction.IsFinished()) { var guid = currentRecordAction.GetBattleFieldGuid(); BattleDebug.LogError("record action " + currentRecordAction.GetType() + " play finished"); // BattleDebug.LogError("record action " + currentRecordAction.GetType() + " play finished"); currentRecordAction = null; isWaitingNextAction = true; waitTimer = 0f; @@ -179,7 +238,7 @@ if (recordActionQueue.Count > 0) { currentRecordAction = recordActionQueue.Dequeue(); BattleDebug.LogError("play record action " + currentRecordAction.GetType()); // BattleDebug.LogError("play record action " + currentRecordAction.GetType()); } } } Main/System/Battle/Skill/SkillBase.cs
@@ -28,11 +28,18 @@ protected List<H0704_tagRolePackRefresh> dropPackList = new List<H0704_tagRolePackRefresh>(); protected List<HB405_tagMCAddExp> expPackList = new List<HB405_tagMCAddExp>(); protected List<BattleDeadPack> endDeadPackList = new List<BattleDeadPack>(); protected List<SkillRecordAction> waitingCastSkillRecordAction = new List<SkillRecordAction>(); protected bool moveFinished = false; public SkillBase fromSkill; public bool isPlay = false; // 父RecordAction(SkillRecordAction),用于子技能建立父子关系 protected RecordAction parentRecordAction; // 技能动画是否播放完成(针对有动画的技能) protected bool isMotionCompleted = false; private float MoveSpeed = 750f; @@ -59,12 +66,12 @@ } SafetyCheck(); #if UNITY_EDITOR if (Launch.Instance.isOpenSkillLogFile) { PinrtHB427Hp(); } #endif } // 设置父RecordAction public void SetParentRecordAction(RecordAction recordAction) { parentRecordAction = recordAction; } #if UNITY_EDITOR @@ -144,6 +151,13 @@ private void SafetyCheck() { #if UNITY_EDITOR if (Launch.Instance.isOpenSkillLogFile) { PinrtHB427Hp(); } #endif bool safety = caster != null && skillConfig != null && tagUseSkillAttack != null @@ -485,24 +499,60 @@ skillEffect = SkillEffectFactory.CreateSkillEffect(this, caster, skillConfig, tagUseSkillAttack); skillEffect.Play(OnHitTargets); ProcessSubSkill(); HandleWaitingCastSkill(); isPlay = true; } protected void ProcessSubSkill() { foreach (var subSkillPack in tagUseSkillAttack.subSkillList) { SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, new List<GameNetPackBasic>() { subSkillPack }); recordAction.fromSkill = this; otherSkillActionList.Add(recordAction); battleField.recordPlayer.ImmediatelyPlay(recordAction); // 子技能设置WaitingPlay=true,等待父技能动作完成 waitingCastSkillRecordAction.Add(recordAction); battleField.recordPlayer.ImmediatelyPlay(recordAction, parentRecordAction, true); } tagUseSkillAttack.subSkillList.Clear(); foreach (var subCombinePack in tagUseSkillAttack.subSkillCombinePackList) { SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, subCombinePack.packList); recordAction.fromSkill = this; otherSkillActionList.Add(recordAction); battleField.recordPlayer.ImmediatelyPlay(recordAction); // 子技能设置WaitingPlay=true,等待父技能动作完成 waitingCastSkillRecordAction.Add(recordAction); } tagUseSkillAttack.subSkillCombinePackList.Clear(); isPlay = true; waitingCastSkillRecordAction.OrderBy(recordAction => recordAction.hB427_TagSCUseSkill.packUID); } protected void HandleWaitingCastSkill() { RecordAction waitingRecordAction = null; for (int i = 0; i < waitingCastSkillRecordAction.Count; i++) { var recordAction = waitingCastSkillRecordAction[i]; if (waitingRecordAction != null) { // 每个都应该等前一个结束后 battleField.recordPlayer.ImmediatelyPlay(recordAction, waitingRecordAction, true); } else { battleField.recordPlayer.ImmediatelyPlay(recordAction, parentRecordAction, true); } if (recordAction.IsNeedWaiting()) { waitingRecordAction = recordAction; } } } // 技能前摇结束回调 @@ -529,6 +579,9 @@ // 技能后摇结束回调:通知技能效果处理后摇结束 public virtual void OnFinalFrameEnd() { // 标记动画播放完成 isMotionCompleted = true; BattleDebug.LogError($"SkillBase.OnFinalFrameEnd: 技能 {skillConfig?.SkillID} 动画播放完成"); skillEffect?.OnFinalFrameEnd(); // 修复:添加空值检查 } @@ -728,7 +781,7 @@ #endif // 先调用目标受伤 target.Hurt(hurtParam); target.Hurt(hurtParam, parentRecordAction); // 再调用施法者吸血/反伤 caster.OnHurtTarget(hurtParam); @@ -1008,6 +1061,16 @@ return false; } // 如果技能有动画(SkillMotionName不为空),需要等待动画播放完成 if (skillConfig != null && !string.IsNullOrEmpty(skillConfig.SkillMotionName)) { if (!isMotionCompleted) { BattleDebug.LogError($"SkillBase.IsFinishedForJudge: 技能 {skillConfig.SkillID} 等待动画播放完成"); return false; } } return true; } @@ -1067,6 +1130,7 @@ { battleField.RemoveCastingSkill(caster.ObjID, this); // 传递parentRecordAction,让死亡技能等待当前技能完成 battleField.OnObjsDead(new List<BattleDeadPack>(tempDeadPackList.Values)); } @@ -1089,7 +1153,8 @@ battleField.RemoveCastingSkill(caster.ObjID, this); } battleField.OnObjsDead(new List<BattleDeadPack>(tempDeadPackList.Values)); // 传递parentRecordAction,让死亡技能等待当前技能完成 battleField.OnObjsDead(new List<BattleDeadPack>(tempDeadPackList.Values), parentRecordAction); // 1. 强制结束技能效果 skillEffect?.ForceFinished(); @@ -1100,7 +1165,8 @@ SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, new List<GameNetPackBasic>() { subSkillPack }); recordAction.fromSkill = this; otherSkillActionList.Add(recordAction); battleField.recordPlayer.ImmediatelyPlay(recordAction); // 子技能设置WaitingPlay=true,等待父技能动作完成 battleField.recordPlayer.ImmediatelyPlay(recordAction, parentRecordAction, true); } tagUseSkillAttack.subSkillList.Clear(); foreach (var subCombinePack in tagUseSkillAttack.subSkillCombinePackList) @@ -1108,7 +1174,8 @@ SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, subCombinePack.packList); recordAction.fromSkill = this; otherSkillActionList.Add(recordAction); battleField.recordPlayer.ImmediatelyPlay(recordAction); // 子技能设置WaitingPlay=true,等待父技能动作完成 battleField.recordPlayer.ImmediatelyPlay(recordAction, parentRecordAction, true); } tagUseSkillAttack.subSkillCombinePackList.Clear(); @@ -1173,6 +1240,9 @@ isFinished = true; moveFinished = true; isPlay = true; // 强制结束时,无论是否有动画,都标记动画完成 isMotionCompleted = true; // 6. 处理所有剩余包(包括 buff 包) // 先处理 buffPackCollections @@ -1377,6 +1447,26 @@ } } public virtual bool CanStartExecution() { if (null == caster) { return false; } if (null == skillConfig) { return false; } if (string.IsNullOrEmpty(skillConfig.SkillMotionName)) { return true; } return !battleField.IsCastingSkill(caster.ObjID); } #endregion }