| Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/BattleObject/HeroBattleObject.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/Motion/MotionBase.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/Skill/SkillBase.Cast.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| Main/System/Battle/Skill/SkillBase.Finish.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs
@@ -24,6 +24,12 @@ private SkillRecordAction playSkillRecordAction = null; #if UNITY_EDITOR private int deathDebugNotFinishedCount = 0; private const int DeathDebugFirstDumpCount = 120; private const int DeathDebugRepeatDumpCount = 180; #endif public DeathRecordAction(BattleField _battleField, List<BattleDeadPack> _deadPackList, SkillRecordAction _parentSkillAction = null, SkillRecordAction _playSkillRecordAction = null) : base(RecordActionType.Death, _battleField, null) { @@ -68,6 +74,10 @@ { isRunOnce = true; #if UNITY_EDITOR // DumpDeathDebugState("首次Run"); #endif SkillRecordAction waitingAnimeAction = playSkillRecordAction; foreach (var battleDeadPack in deadPackList) @@ -78,6 +88,10 @@ if (null != skillAction) { deathActionDict.Add(battleDeadPack, skillAction); #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 创建死亡触发技能 {FormatDeadPackForDebug(battleDeadPack)} -> {FormatSkillActionForDebug(skillAction)} waitingAnimeAction={(waitingAnimeAction == null ? "null" : FormatSkillActionForDebug(waitingAnimeAction))}"); #endif // 【使用 BattleField.recordPlayer】 // 原因:死亡触发技能是顶层的RecordAction,不是在某个RecordAction内部产生的 @@ -99,9 +113,18 @@ waitingAnimeAction = skillAction; } } #if UNITY_EDITOR else { // BattleDebug.LogError($"[DeathRecordAction诊断] 死亡触发技能创建失败 {FormatDeadPackForDebug(battleDeadPack)}"); } #endif } else { #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 创建普通死亡状态 {FormatDeadPackForDebug(battleDeadPack)}"); #endif deadActionStatesDict.Add(battleDeadPack, CreateDeadActionState(battleDeadPack)); } } @@ -149,6 +172,10 @@ } } #if UNITY_EDITOR // ReportDeathNotFinishedIfNeeded(completeNum); #endif if (completeNum == deadPackList.Count) { // 死亡处理完成后,分发死亡后的包 @@ -177,12 +204,46 @@ BattleObject deadObj = battleField.battleObjMgr.GetBattleObject((int)deadPack.deadPack.ObjID); if (null == deadObj) { #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 死亡对象不存在,直接视为完成 {FormatDeadPackForDebug(deadPack)}"); #endif return () => true; } if (deadObj.IsReborning()) { #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 创建死亡状态时对象已在复活流程,直接视为完成 {FormatDeadPackForDebug(deadPack)} withoutAnime={withoutAnime}"); #endif return () => true; } if (deadObj.GetCurHp() > 0) { #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 创建死亡状态时对象血量已回正,直接视为完成 {FormatDeadPackForDebug(deadPack)} withoutAnime={withoutAnime}"); #endif return () => true; } if (deadObj.IsDead()) { #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 创建死亡状态时对象已死亡,直接视为完成 {FormatDeadPackForDebug(deadPack)} withoutAnime={withoutAnime}"); #endif return () => true; } bool playDeath = false; bool isComplete = false; #if UNITY_EDITOR bool loggedWaitingCanStartDeath = false; bool loggedReborningComplete = false; bool loggedHpRestoredComplete = false; bool loggedAlreadyDeadComplete = false; #endif // 如果没有释放技能 则直接死亡 if (deadObj.CanStartDeath()) @@ -191,10 +252,23 @@ deadObj.OnDeath(() => { isComplete = true; #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 死亡动画回调完成 {FormatDeadPackForDebug(deadPack)} withoutAnime={withoutAnime}"); #endif }, withoutAnime); playDeath = true; #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 开始播放死亡表现 {FormatDeadPackForDebug(deadPack)} withoutAnime={withoutAnime}"); #endif } #if UNITY_EDITOR else { loggedWaitingCanStartDeath = true; // BattleDebug.LogError($"[DeathRecordAction诊断] 暂不能播放死亡表现,等待 CanStartDeath {FormatDeadPackForDebug(deadPack)} deadObj.CanStartDeath={deadObj.CanStartDeath()} isReborning={deadObj.IsReborning()} isDead={deadObj.IsDead()}"); } #endif @@ -207,14 +281,58 @@ deadObj.OnDeath(() => { isComplete = true; #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 延迟死亡动画回调完成 {FormatDeadPackForDebug(deadPack)} withoutAnime={withoutAnime}"); #endif }, withoutAnime); playDeath = true; #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 延迟开始播放死亡表现 {FormatDeadPackForDebug(deadPack)} withoutAnime={withoutAnime}"); #endif } #if UNITY_EDITOR else if (!playDeath && !loggedWaitingCanStartDeath) { loggedWaitingCanStartDeath = true; // BattleDebug.LogError($"[DeathRecordAction诊断] 仍不能播放死亡表现,等待 CanStartDeath {FormatDeadPackForDebug(deadPack)} deadObj.CanStartDeath={deadObj.CanStartDeath()} isReborning={deadObj.IsReborning()} isDead={deadObj.IsDead()}"); } #endif if (deadObj.IsReborning()) { isComplete = true; #if UNITY_EDITOR if (!loggedReborningComplete) { loggedReborningComplete = true; // BattleDebug.LogError($"[DeathRecordAction诊断] 死亡对象已进入复活流程,死亡状态视为完成 {FormatDeadPackForDebug(deadPack)}"); } #endif } if (!isComplete && deadObj.GetCurHp() > 0) { isComplete = true; #if UNITY_EDITOR if (!loggedHpRestoredComplete) { loggedHpRestoredComplete = true; // BattleDebug.LogError($"[DeathRecordAction诊断] 死亡对象血量已回正,死亡状态视为完成 {FormatDeadPackForDebug(deadPack)}"); } #endif } if (!isComplete && deadObj.IsDead()) { isComplete = true; #if UNITY_EDITOR if (!loggedAlreadyDeadComplete) { loggedAlreadyDeadComplete = true; // BattleDebug.LogError($"[DeathRecordAction诊断] 死亡对象已处于死亡状态,死亡状态视为完成 {FormatDeadPackForDebug(deadPack)}"); } #endif } return isComplete; @@ -284,18 +402,19 @@ // 遍历所有死亡包,分发它们的 packListAfterDeath foreach (var deadPack in deadPackList) { #if UNITY_EDITOR // BattleDebug.LogError($"[DeathRecordAction诊断] 准备分发死亡后包 {FormatDeadPackForDebug(deadPack)} afterDeathCount={deadPack.packListAfterDeath?.Count ?? 0}"); #endif if (deadPack.packListAfterDeath != null && deadPack.packListAfterDeath.Count > 0) { foreach (var pack in deadPack.packListAfterDeath) { // 获取包的类型和UID用于调试 #if UNITY_EDITOR string packType = pack.GetType().Name; ulong packUID = 0; var packUIDField = pack.GetType().GetField("packUID"); if (packUIDField != null) { packUID = (ulong)packUIDField.GetValue(pack); } ulong packUID = GetPackUIDForDebug(pack); // BattleDebug.LogError($"[DeathRecordAction诊断] 分发死亡后包 objId={GetDeadObjIdForDebug(deadPack)} packType={packType} packUID={packUID} playSkillRecordAction={(playSkillRecordAction == null ? "null" : FormatSkillActionForDebug(playSkillRecordAction))}"); #endif // 特殊处理 CustomHB426CombinePack:使用其自己的 Distribute 方法 @@ -379,6 +498,141 @@ } #if UNITY_EDITOR private void ReportDeathNotFinishedIfNeeded(int completeNum) { if (isFinish || isActionCompleted) { deathDebugNotFinishedCount = 0; return; } deathDebugNotFinishedCount++; bool firstDump = deathDebugNotFinishedCount == DeathDebugFirstDumpCount; bool repeatDump = deathDebugNotFinishedCount > DeathDebugFirstDumpCount && (deathDebugNotFinishedCount - DeathDebugFirstDumpCount) % DeathDebugRepeatDumpCount == 0; if (!firstDump && !repeatDump) { return; } DumpDeathDebugState($"未完成 completeNum={completeNum}/{deadPackList.Count} checkCount={deathDebugNotFinishedCount}"); } private void DumpDeathDebugState(string reason) { var sb = new System.Text.StringBuilder(); sb.Append($"[DeathRecordAction诊断] {reason} actionID={actionID} "); sb.Append($"deadPackList.Count={deadPackList?.Count ?? 0} "); sb.Append($"deathActionDict.Count={deathActionDict.Count} "); sb.Append($"deadActionStatesDict.Count={deadActionStatesDict.Count} "); sb.Append($"hasDeathTriggerSkill={hasDeathTriggerSkill} "); sb.Append($"hasDistributedPacksAfterDeath={hasDistributedPacksAfterDeath} "); sb.Append($"parentSkillAction={(parentSkillAction == null ? "null" : FormatSkillActionForDebug(parentSkillAction))} "); sb.Append($"playSkillRecordAction={(playSkillRecordAction == null ? "null" : FormatSkillActionForDebug(playSkillRecordAction))}"); if (deadPackList != null) { for (int i = 0; i < deadPackList.Count; i++) { BattleDeadPack deadPack = deadPackList[i]; sb.Append("\n [").Append(i).Append("] ").Append(FormatDeadPackForDebug(deadPack)); if (deathActionDict.TryGetValue(deadPack, out var skillAction)) { sb.Append(" deathSkill=").Append(FormatSkillActionForDebug(skillAction)); } sb.Append(" hasState=").Append(deadActionStatesDict.ContainsKey(deadPack)); } } // BattleDebug.LogError(sb.ToString()); } private string FormatDeadPackForDebug(BattleDeadPack deadPack) { ulong objId = GetDeadObjIdForDebug(deadPack); BattleObject deadObj = null; if (battleField != null && battleField.battleObjMgr != null && objId > 0) { deadObj = battleField.battleObjMgr.GetBattleObject((int)objId); } string objName = deadObj?.GetName() ?? "null"; bool canStartDeath = deadObj != null && deadObj.CanStartDeath(); bool isReborning = deadObj != null && deadObj.IsReborning(); bool isDead = deadObj != null && deadObj.IsDead(); long curHp = deadObj != null ? deadObj.GetCurHp() : 0; int afterDeathCount = deadPack?.packListAfterDeath?.Count ?? 0; string triggerTag = deadPack?.deadTriggerSkill?.startTag?.Tag ?? "null"; return $"objId={objId} name={objName} hp={curHp} isDead={isDead} canStartDeath={canStartDeath} isReborning={isReborning} hasDeadTriggerSkill={deadPack?.deadTriggerSkill != null} triggerTag={triggerTag} isPlaySkill={deadPack?.isPlaySkill ?? false} afterDeathCount={afterDeathCount}"; } private ulong GetDeadObjIdForDebug(BattleDeadPack deadPack) { if (deadPack == null || deadPack.deadPack == null) { return 0; } return deadPack.deadPack.ObjID; } private string FormatSkillActionForDebug(SkillRecordAction skillAction) { if (skillAction == null) { return "null"; } SkillBase skillBase = skillAction.skillBase; if (skillBase == null) { return $"SkillRecordAction(actionID={skillAction.actionID}, skillBase=null)"; } int skillId = skillBase.skillConfig != null ? skillBase.skillConfig.SkillID : 0; ulong casterId = skillBase.tagUseSkillAttack != null ? skillBase.tagUseSkillAttack.ObjID : 0; return $"SkillRecordAction(actionID={skillAction.actionID}, skillId={skillId}, caster={casterId}, StateFlags={skillBase.StateFlagsForDebug}, IsActionCompleted={skillAction.IsActionCompleted()})"; } private ulong GetPackUIDForDebug(GameNetPackBasic pack) { if (pack == null) { return 0; } if (pack is HB422_tagMCTurnFightObjDead deadPack) { return deadPack.packUID; } if (pack is CustomHB426CombinePack combinePack) { return combinePack.packUID; } var packUIDField = pack.GetType().GetField("packUID"); if (packUIDField == null) { return 0; } object value = packUIDField.GetValue(pack); if (value is ulong ulongValue) { return ulongValue; } if (value is uint uintValue) { return uintValue; } if (value is int intValue) { return (ulong)intValue; } return 0; } /// <summary> /// 首次运行时打印日志(仅编辑器) /// 打印死亡对象的名字 Main/System/Battle/BattleObject/HeroBattleObject.cs
@@ -476,6 +476,12 @@ public override void OnDeath(Action _onDeathAnimationComplete, bool withoutAnime = false) { #if UNITY_EDITOR if (Launch.Instance != null && Launch.Instance.isOpenBattleDebug) { // BattleDebug.LogError($"[HeroBattleObject死亡诊断] OnDeath objId={ObjID} name={GetName()} hp={GetCurHp()} isDead={IsDead()} isReborning={IsReborning()} withoutAnime={withoutAnime} motionHash={motionBase?.GetHashCode() ?? 0}"); } #endif buffMgr.RemoveAllBuff(); battleField.soundManager.PlayEffectSound(teamHero.heroConfig.DeathSFX, false); if (withoutAnime) @@ -487,6 +493,12 @@ { motionBase.PlayDeadAnimation(() => { #if UNITY_EDITOR if (Launch.Instance != null && Launch.Instance.isOpenBattleDebug) { // BattleDebug.LogError($"[HeroBattleObject死亡诊断] 死亡动画回调 objId={ObjID} name={GetName()} hp={GetCurHp()} isDead={IsDead()} isReborning={IsReborning()} motionHash={motionBase?.GetHashCode() ?? 0}"); } #endif SetDeath(); _onDeathAnimationComplete?.Invoke(); }); @@ -511,6 +523,12 @@ // 释放者就是复活者时调用 public override void PreReborn(bool reviveSelf = false) { #if UNITY_EDITOR if (Launch.Instance != null && Launch.Instance.isOpenBattleDebug) { // BattleDebug.LogError($"[HeroBattleObject死亡诊断] PreReborn objId={ObjID} name={GetName()} hp={GetCurHp()} isDead={IsDead()} isReborning={IsReborning()} reviveSelf={reviveSelf} motionHash={motionBase?.GetHashCode() ?? 0}"); } #endif heroGo.SetActive(true); motionBase.skeletonAnim.skeleton.A = 0f; motionBase.skeletonAnim.LateUpdate(); @@ -521,6 +539,12 @@ // 复活action public override void OnReborn(HB427_tagSCUseSkill.tagSCUseSkillHurt vNetData, bool reviveSelf = false, RecordAction parentAction = null) { #if UNITY_EDITOR if (Launch.Instance != null && Launch.Instance.isOpenBattleDebug) { // BattleDebug.LogError($"[HeroBattleObject死亡诊断] OnReborn objId={ObjID} name={GetName()} hp={GetCurHp()} isDead={IsDead()} isReborning={IsReborning()} reviveSelf={reviveSelf} motionHash={motionBase?.GetHashCode() ?? 0}"); } #endif isReborning = true; heroGo.SetActive(true); motionBase.ResetForReborn(reviveSelf); @@ -531,6 +555,12 @@ public override void AfterReborn() { #if UNITY_EDITOR if (Launch.Instance != null && Launch.Instance.isOpenBattleDebug) { // BattleDebug.LogError($"[HeroBattleObject死亡诊断] AfterReborn objId={ObjID} name={GetName()} hp={GetCurHp()} isDead={IsDead()} isReborning={IsReborning()} motionHash={motionBase?.GetHashCode() ?? 0}"); } #endif // 清空所有 motionBase.ResetForReborn(false); isReborning = false; Main/System/Battle/Motion/MotionBase.cs
@@ -63,8 +63,8 @@ { string owner = skeletonAnim != null && skeletonAnim.gameObject != null ? skeletonAnim.gameObject.name : "(no-skel)"; // 每次变更打印栈,定位到底是谁把 playingSkillWithAnim 设 true 了、谁清/不清 BattleDebug.LogError($"[MotionBase owner={owner} hash={GetHashCode()}] playingSkillWithAnim {_playingSkillWithAnim} -> {value}\n" + UnityEngine.StackTraceUtility.ExtractStackTrace()); // BattleDebug.LogError($"[MotionBase owner={owner} hash={GetHashCode()}] playingSkillWithAnim {_playingSkillWithAnim} -> {value}\n" // + UnityEngine.StackTraceUtility.ExtractStackTrace()); } // [卡死诊断] 维护锁的持有者信息(上一轮的字段被回滚了,这里是最小必要集合) if (value && !_playingSkillWithAnim) @@ -161,7 +161,14 @@ public virtual Spine.TrackEntry PlayDeadAnimation(Action onComplete = null) { if (animState == null) return null; if (animState == null) { #if UNITY_EDITOR LogDeathTrackDebug("PlayDeadAnimation animState=null,直接完成死亡回调", null, false); #endif onComplete?.Invoke(); return null; } // 使用轨道9作为死亡动画专用轨道(独立于主轨道0和子技能轨道1-8) @@ -169,7 +176,12 @@ if (activeSkillTracks.TryGetValue(DeathTrackIndex, out var oldDeathTrack)) { if (trackEntryCallbacks.ContainsKey(oldDeathTrack)) { #if UNITY_EDITOR LogDeathTrackDebug("PlayDeadAnimation 替换旧死亡轨道,移除旧回调", oldDeathTrack, true); #endif trackEntryCallbacks.Remove(oldDeathTrack); } } Spine.Animation deadAnim = FindAnim(MotionName.dead.ToString()); @@ -189,9 +201,42 @@ if (onComplete != null) trackEntryCallbacks[deathTrack] = onComplete; } #if UNITY_EDITOR LogDeathTrackDebug("PlayDeadAnimation 创建死亡轨道", deathTrack, onComplete != null && deathTrack != null); #endif if (deathTrack == null) { onComplete?.Invoke(); } return deathTrack; } #if UNITY_EDITOR private void LogDeathTrackDebug(string reason, Spine.TrackEntry trackEntry, bool hasCallback) { if (Launch.Instance == null || !Launch.Instance.isOpenBattleDebug) { return; } string owner = skeletonAnim != null && skeletonAnim.gameObject != null ? skeletonAnim.gameObject.name : "(no-skel)"; // BattleDebug.LogError($"[MotionBase死亡诊断] {reason} owner={owner} hash={GetHashCode()} track={FormatTrackForDebug(trackEntry)} hasCallback={hasCallback} callbacks={trackEntryCallbacks.Count} activeSkillTracks={activeSkillTracks.Count}"); } private string FormatTrackForDebug(Spine.TrackEntry trackEntry) { if (trackEntry == null) { return "null"; } string animName = trackEntry.Animation != null ? trackEntry.Animation.Name : "(null)"; float duration = trackEntry.Animation != null ? trackEntry.Animation.Duration : -1f; return $"hash={trackEntry.GetHashCode()} anim={animName} TrackTime={trackEntry.TrackTime:F3} duration={duration:F3} isComplete={trackEntry.IsComplete} timeScale={trackEntry.TimeScale}"; } #endif private void AddAction(Action action) => runningActions.Add(action); private void RemoveAction(Action action) => runningActions.Remove(action); @@ -636,6 +681,13 @@ string animName = trackEntry.Animation.Name.ToLower(); #if UNITY_EDITOR if (animName == MotionName.dead.ToString().ToLower()) { LogDeathTrackDebug("OnAnimationComplete 收到死亡动画完成", trackEntry, trackEntryCallbacks.ContainsKey(trackEntry)); } #endif if (AttackMotionList.Contains(animName)) { OnAttackAnimationComplete?.Invoke(); @@ -734,7 +786,7 @@ if (Launch.Instance != null && Launch.Instance.isOpenBattleDebug) { string owner = skeletonAnim != null && skeletonAnim.gameObject != null ? skeletonAnim.gameObject.name : "(no-skel)"; BattleDebug.LogError($"[MotionBase.HaveRest owner={owner} hash={GetHashCode()}] 调用栈:\n{UnityEngine.StackTraceUtility.ExtractStackTrace()}"); // BattleDebug.LogError($"[MotionBase.HaveRest owner={owner} hash={GetHashCode()}] 调用栈:\n{UnityEngine.StackTraceUtility.ExtractStackTrace()}"); } #endif // 先强制结束所有正在运行的 skillBase,避免清字典后这些 skillBase 的 frameHandler 被删但自身 StateFlags 永远停在 Started @@ -789,7 +841,14 @@ if (Launch.Instance != null && Launch.Instance.isOpenBattleDebug) { string owner = skeletonAnim != null && skeletonAnim.gameObject != null ? skeletonAnim.gameObject.name : "(no-skel)"; BattleDebug.LogError($"[MotionBase.ResetForReborn owner={owner} hash={GetHashCode()}] reviveSelf={reviveSelf} 调用栈:\n{UnityEngine.StackTraceUtility.ExtractStackTrace()}"); // BattleDebug.LogError($"[MotionBase.ResetForReborn owner={owner} hash={GetHashCode()}] reviveSelf={reviveSelf} 调用栈:\n{UnityEngine.StackTraceUtility.ExtractStackTrace()}"); Spine.TrackEntry deathTrack = null; bool hasDeathTrack = activeSkillTracks.TryGetValue(DeathTrackIndex, out deathTrack); bool hasDeathCallback = hasDeathTrack && deathTrack != null && trackEntryCallbacks.ContainsKey(deathTrack); if (hasDeathTrack || hasDeathCallback || trackEntryCallbacks.Count > 0) { // BattleDebug.LogError($"[MotionBase死亡诊断] ResetForReborn 即将清理轨道 owner={owner} hash={GetHashCode()} reviveSelf={reviveSelf} hasDeathTrack={hasDeathTrack} hasDeathCallback={hasDeathCallback} callbacks={trackEntryCallbacks.Count} activeSkillTracks={activeSkillTracks.Count} deathTrack={FormatTrackForDebug(deathTrack)}"); } } #endif // 跟 HaveRest 同理:先强制结束所有正在运行的 skillBase, Main/System/Battle/Skill/SkillBase.Cast.cs
@@ -18,7 +18,7 @@ ? caster.GetRectTransform().anchoredPosition : Vector2.zero; bool casterTweening = caster != null && caster.GetRectTransform() != null && DG.Tweening.DOTween.IsTweening(caster.GetRectTransform()); BattleDebug.LogError($"[前冲诊断] Cast 入口 skillId={skillConfig?.SkillID} caster={caster?.ObjID} battleType={tagUseSkillAttack?.BattleType} castMode={skillSkinConfig?.castMode} anchoredPos={castEntryPos} casterTweening={casterTweening}"); // BattleDebug.LogError($"[前冲诊断] Cast 入口 skillId={skillConfig?.SkillID} caster={caster?.ObjID} battleType={tagUseSkillAttack?.BattleType} castMode={skillSkinConfig?.castMode} anchoredPos={castEntryPos} casterTweening={casterTweening}"); } #endif // 广播技能释放事件 @@ -175,13 +175,13 @@ private void ExecuteMoveAndCastSequence(RectTransform target, Action onReturnComplete) { #if UNITY_EDITOR BattleDebug.LogError($"[前冲诊断] ExecuteMoveAndCastSequence 开始 skillId={skillConfig?.SkillID} caster={caster?.ObjID} battleType={tagUseSkillAttack?.BattleType} CastDistance={skillSkinConfig?.CastDistance} castMode={skillSkinConfig?.castMode}"); // BattleDebug.LogError($"[前冲诊断] ExecuteMoveAndCastSequence 开始 skillId={skillConfig?.SkillID} caster={caster?.ObjID} battleType={tagUseSkillAttack?.BattleType} CastDistance={skillSkinConfig?.CastDistance} castMode={skillSkinConfig?.castMode}"); #endif ShadowIllutionCreate(true); MoveToTarget(target, new Vector2(skillSkinConfig.CastDistance, 0), () => { #if UNITY_EDITOR BattleDebug.LogError($"[前冲诊断] 前冲完成 skillId={skillConfig?.SkillID} caster={caster?.ObjID} 准备 CastImpl"); // BattleDebug.LogError($"[前冲诊断] 前冲完成 skillId={skillConfig?.SkillID} caster={caster?.ObjID} 准备 CastImpl"); #endif if (skillSkinConfig.CastDistance < 9999 && skillSkinConfig.SkinllSFX2 != 0) { @@ -220,12 +220,12 @@ ? caster.GetRectTransform().anchoredPosition : Vector2.zero; bool mttTweening = caster != null && caster.GetRectTransform() != null && DG.Tweening.DOTween.IsTweening(caster.GetRectTransform()); BattleDebug.LogError($"[前冲诊断] MoveToTarget 入口 skillId={skillConfig?.SkillID} caster={caster?.ObjID} battleType={tagUseSkillAttack?.BattleType} CastDistance={skillSkinConfig?.CastDistance} offset={offset} speed={speed} fromPos={fromPos} casterTweening={mttTweening}"); // BattleDebug.LogError($"[前冲诊断] MoveToTarget 入口 skillId={skillConfig?.SkillID} caster={caster?.ObjID} battleType={tagUseSkillAttack?.BattleType} CastDistance={skillSkinConfig?.CastDistance} offset={offset} speed={speed} fromPos={fromPos} casterTweening={mttTweening}"); #endif if (skillSkinConfig.CastDistance >= 9999) { #if UNITY_EDITOR BattleDebug.LogError($"[前冲诊断] CastDistance>=9999 直接跳过移动 skillId={skillConfig?.SkillID} caster={caster?.ObjID}"); // BattleDebug.LogError($"[前冲诊断] CastDistance>=9999 直接跳过移动 skillId={skillConfig?.SkillID} caster={caster?.ObjID}"); #endif _onComplete?.Invoke(); return; @@ -238,14 +238,14 @@ Vector3 targetWorld = target != null ? target.position : Vector3.zero; Vector3 targetLossyScale = target != null ? (Vector3)target.lossyScale : Vector3.one; Vector2 targetAnchored = target != null ? target.anchoredPosition : Vector2.zero; BattleDebug.LogError($"[前冲诊断] target信息 skillId={skillConfig?.SkillID} caster={caster?.ObjID} casterCamp={caster?.Camp} target.name={targetName} target.anchoredPos={targetAnchored} target.worldPos={targetWorld} target.lossyScale={targetLossyScale}"); // BattleDebug.LogError($"[前冲诊断] target信息 skillId={skillConfig?.SkillID} caster={caster?.ObjID} casterCamp={caster?.Camp} target.name={targetName} target.anchoredPos={targetAnchored} target.worldPos={targetWorld} target.lossyScale={targetLossyScale}"); #endif var tweener = BattleUtility.MoveToTarget(caster.GetRectTransform(), target, offset, () => { #if UNITY_EDITOR Vector2 toPos = caster != null && caster.GetRectTransform() != null ? caster.GetRectTransform().anchoredPosition : Vector2.zero; BattleDebug.LogError($"[前冲诊断] MoveToTarget 完成 skillId={skillConfig?.SkillID} caster={caster?.ObjID} toPos={toPos}"); // BattleDebug.LogError($"[前冲诊断] MoveToTarget 完成 skillId={skillConfig?.SkillID} caster={caster?.ObjID} toPos={toPos}"); #endif // tween 完成时清除 caster 上的 activeMoveTween 句柄,放开 CanCastSkillAnimation 的闸门。 if (caster != null) @@ -283,7 +283,7 @@ ? caster.GetRectTransform().anchoredPosition : Vector2.zero; bool finTweening = caster != null && caster.GetRectTransform() != null && DG.Tweening.DOTween.IsTweening(caster.GetRectTransform()); BattleDebug.LogError($"[前冲诊断] OnAttackFinish skillId={skillConfig?.SkillID} caster={caster?.ObjID} battleType={tagUseSkillAttack?.BattleType} anchoredPos={finPos} casterTweening={finTweening}"); // BattleDebug.LogError($"[前冲诊断] OnAttackFinish skillId={skillConfig?.SkillID} caster={caster?.ObjID} battleType={tagUseSkillAttack?.BattleType} anchoredPos={finPos} casterTweening={finTweening}"); } #endif TurnBack(null, 1f); Main/System/Battle/Skill/SkillBase.Finish.cs
@@ -131,7 +131,7 @@ /// </summary> private void ReportStuckIfNeeded(string reason) { #if UNITY_EDITOR #if false && UNITY_EDITOR _stuckCheckCount++; // 阻塞原因切换了 → 立刻打一次,并重置计数 @@ -210,19 +210,19 @@ string skinInfo = $" skillSkinConfig.SkillMotionName={(skillSkinConfig == null ? "null" : (string.IsNullOrEmpty(skillSkinConfig.SkillMotionName) ? "(空)" : skillSkinConfig.SkillMotionName))}"; string skillEffectDump = skillEffect == null ? " skillEffect=null" : $" skillEffect: {skillEffect.DumpState()}"; BattleDebug.LogError( "SkillBase.IsFinished 疑似卡死 (持续 " + _stuckCheckCount + " 次未完成)\n" + $" skillId={skillId} caster={casterId} 原因: {reason}\n" + $" StateFlags={_stateFlags}\n" + $"{skillEffectDump}\n" + $"{skinInfo}\n" + $"{casterAnim}\n" + $" currentWaitingSkill.Count={currentWaitingSkill.Count}\n{subSkillDump}\n" + $" packList.Count={(packList?.Count ?? 0)}\n{packListDump}\n" + $" innerRecordPlayer.IsPlaying={innerPlaying}\n" + $"{innerPlayerDump}\n" + $" tempDeadPackList.Count={tempDeadPackList.Count}\n" + $" buffPackCollections.Count={buffPackCollections.Count}"); // BattleDebug.LogError( // "SkillBase.IsFinished 疑似卡死 (持续 " + _stuckCheckCount + " 次未完成)\n" + // $" skillId={skillId} caster={casterId} 原因: {reason}\n" + // $" StateFlags={_stateFlags}\n" + // $"{skillEffectDump}\n" + // $"{skinInfo}\n" + // $"{casterAnim}\n" + // $" currentWaitingSkill.Count={currentWaitingSkill.Count}\n{subSkillDump}\n" + // $" packList.Count={(packList?.Count ?? 0)}\n{packListDump}\n" + // $" innerRecordPlayer.IsPlaying={innerPlaying}\n" + // $"{innerPlayerDump}\n" + // $" tempDeadPackList.Count={tempDeadPackList.Count}\n" + // $" buffPackCollections.Count={buffPackCollections.Count}"); #endif }