yyl
2026-01-15 bface07b5ea879e40f5be8d082bfa77fb873b0bd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
 
using System.Collections.Generic;
using System;
 
 
public class RecordAction
{
    protected BattleField battleField;
 
    //  本次Action的主角
    protected BattleObject battleObject;
 
    protected bool isFinish = false;
 
    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;
 
    //  ===== 内部RecordPlayer机制 =====
    //  内部RecordPlayer:用于播放由此RecordAction内部产生的RecordAction
    //  当RecordAction内部产生新的RecordAction时(如PackageRegedit.Distribute触发的),
    //  这些RecordAction应该由当前RecordAction的innerRecordPlayer管理,而不是BattleField的主RecordPlayer
    //  这样可以保证:
    //  1. 内部产生的RecordAction生命周期与父RecordAction绑定
    //  2. ForceFinish时可以一并处理内部的RecordAction
    //  3. 不会干扰BattleField主RecordPlayer的播放队列
    protected RecordPlayer innerRecordPlayer;
 
    public RecordAction(RecordActionType _actionType, BattleField _battleField, BattleObject _battleObj)
    {
        actionType = _actionType;
        battleField = _battleField;
        battleObject = _battleObj;
 
        //  初始化内部RecordPlayer
        //  每个RecordAction都有自己的RecordPlayer来管理内部产生的RecordAction
        if (_battleField != null)
        {
            innerRecordPlayer = new RecordPlayer();
            innerRecordPlayer.Init(_battleField);
        }
    }
 
    public virtual void Played()
    {
 
    }
 
    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()
    {
        //  首先自身动作必须完成
        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;
    }
 
    public virtual void Run()
    {
        //  先运行内部RecordPlayer
        //  原因:内部产生的RecordAction需要先执行,确保内部逻辑按正确顺序播放
        //  例如:技能内部产生的Buff添加、子技能等都由innerRecordPlayer管理
        innerRecordPlayer?.Run();
    }
 
    public virtual void ForceFinish()
    {
        isFinish = true;
        isActionCompleted = true;
        
        //  强制结束内部RecordPlayer
        //  原因:RecordAction被ForceFinish时,其内部产生的所有RecordAction也必须强制结束
        //  这样才能保证整个RecordAction树的完整性和一致性
        innerRecordPlayer?.ForceFinish();
        
        //  强制结束所有子节点
        for (int i = childActionList.Count - 1; i >= 0; i--)
        {
            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;
    }
}