using System.Collections.Generic; using System; using UnityEngine; public class RecordAction { public int actionID; public ulong tracePackUID = 0; private static int autoincreser = 0; protected BattleField battleField; // 本次Action的主角 protected BattleObject battleObject; protected bool isFinish = false; protected bool isRunOnce = false; #if UNITY_EDITOR // 是否已打印首次运行日志(仅用于调试) private bool hasLoggedFirstRun = true; #endif public RecordAction waitingAnimeAction = null; // ===== 父子关系和等待机制 ===== // 父RecordAction引用(如果是通过其他RecordAction内部触发的) public RecordAction parentAction; // 子RecordAction列表(此RecordAction内部触发的其他RecordAction) protected List childActionList = new List(); // 是否是WaitingPlay模式(需要等待父节点动作完成) public bool isWaitingPlay = false; // 自身动作是否完成(不包括子节点的完成状态) protected bool isActionCompleted = false; // ===== 卡死检测机制 ===== // 累计运行时间(仅在Run()被调用时累加,暂停时不计时) private float accumulatedRunTime = 0f; // 最大允许运行时长(秒),超过则强制结束 protected virtual float MaxActionDuration => 15f; // ===== 内部RecordPlayer机制 ===== // 内部RecordPlayer:���于播放由此RecordAction内部产生的RecordAction // 当RecordAction内部产生新的RecordAction时(如PackageRegedit.Distribute触发的), // 这些RecordAction应该由当前RecordAction的innerRecordPlayer管理,而不是BattleField的主RecordPlayer // 这样可以保证: // 1. 内部产生的RecordAction生命周期与父RecordAction绑定 // 2. ForceFinish时可以一并处理内部的RecordAction // 3. 不会干扰BattleField主RecordPlayer的播放队列 protected RecordPlayer innerRecordPlayer; public RecordPlayer actionOwner { get; set; } public RecordAction(RecordActionType _actionType, BattleField _battleField, BattleObject _battleObj) { actionID = autoincreser++; actionType = _actionType; battleField = _battleField; battleObject = _battleObj; // 初始化内部RecordPlayer // 每个RecordAction都有自己的RecordPlayer来管理内部产生的RecordAction if (_battleField != null) { innerRecordPlayer = new RecordPlayer(); innerRecordPlayer.Init(_battleField); } } public virtual void AfterAddToQueue() { } 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 IsFinished() { // 首先自身动作必须完成 if (!isActionCompleted && !isFinish) { return false; } // 检查内部RecordPlayer是否还在播放 // 原因:内部产生的RecordAction必须全部播放完成后,当前RecordAction才算完成 if (innerRecordPlayer != null && innerRecordPlayer.IsPlaying()) { return false; } // 检查所有子节点是否完成 foreach (var child in childActionList) { if (!child.IsFinished()) { return false; } } return true; } // 检测当前Action是否卡死(运行时间超过允许上限) // 注意:使用累计时间而非Time.time,这样暂停期间不会计时 public bool IsStuck() { if (accumulatedRunTime <= 0f) return false; if (isFinish || isActionCompleted) return false; return accumulatedRunTime > MaxActionDuration; } // 获取已运行时长 public float GetRunDuration() { return accumulatedRunTime; } public virtual void Run() { // 累加运行时间(暂停时BattleField.Run不调用RecordPlayer,所以此处不会累加) accumulatedRunTime += Time.deltaTime; #if UNITY_EDITOR // 首次运行时打印调试信息 if (!hasLoggedFirstRun) { hasLoggedFirstRun = true; PrintFirstRunLog(); } #endif // 先运行内部RecordPlayer // 原因:内部产生的RecordAction需要先执行,确保内部逻辑按正确顺序播放 // 例如:技能内部产生的Buff添加、子技能等都由innerRecordPlayer管理 innerRecordPlayer?.Run(); } #if UNITY_EDITOR /// /// 首次运行时打印日志(仅编辑器) /// 子类可以重写此方法自定义打印内容 /// protected virtual void PrintFirstRunLog() { Debug.LogError($"[RecordAction首次Run] {GetType().Name}"); } #endif public virtual void ForceFinish() { isFinish = true; isActionCompleted = true; // 强制结束内部RecordPlayer // 原因:RecordAction被ForceFinish时,其内部产生的所有RecordAction也必须强制结束 // 这样才能保证整个RecordAction树的完整性和一致性 innerRecordPlayer?.ForceFinish(); // 强制结束所有子节点 for (int i = childActionList.Count - 1; i >= 0; i--) { var child = childActionList[i]; child?.ForceFinish(); } // 清理父子引用,防止内存泄漏 childActionList.Clear(); parentAction = null; } public virtual string GetBattleFieldGuid() { if (battleField == null) { return string.Empty; } return battleField.guid; } // 获取内部RecordPlayer // 用于外部代码需要将RecordAction添加到此RecordAction的内部播放器时使用 public virtual RecordPlayer GetInnerRecordPlayer() { return innerRecordPlayer; } public virtual bool NeedWaitSibling() { return true; } }