using System; using System.Collections; using System.Collections.Generic; using BaseGames.Core; using BaseGames.Core.Events; using BaseGames.Core.Save; using UnityEngine; namespace BaseGames.EventChain { /// /// 世界事件链管理器(架构 14_NarrativeModule §10)。 /// 订阅游戏各系统的 SO 事件频道,转发为中继 C# 事件供 ChainCondition.Register() 绑定。 /// 每当收到新事件时,检查所有链的触发条件。 /// public class EventChainManager : MonoBehaviour, ISaveable { [Header("所有事件链")] [SerializeField] private EventChainSO[] _chains; [Header("执行保护")] [Tooltip("单个 Action 的最长执行时长(秒,unscaled time)。超时后强制跳过并记录警告。0 = 不限时。")] [Min(0f)] [SerializeField] private float _maxActionTimeout = 30f; [Header("事件频道(中继)")] [SerializeField] private StringEventChannelSO _onBossDefeated; // EVT_EnemyDied(bossId) [SerializeField] private StringEventChannelSO _onCollectiblePickedUp; // EVT_CollectiblePickup [SerializeField] private StringEventChannelSO _onAbilityUnlocked; // EVT_AbilityUnlocked [SerializeField] private StringEventChannelSO _onRoomEntered; // EVT_SceneLoaded [SerializeField] private StringEventChannelSO _onDialogueCompleted; // EVT_NpcDialogueCompleted // ── 中继 C# 事件,供 ChainCondition.Register() 订阅 ────────────── public event Action OnBossDefeated; public event Action OnCollectiblePickedUp; public event Action OnAbilityUnlocked; public event Action OnRoomEntered; public event Action OnDialogueCompleted; /// 链执行完成时广播 chainId(供 ChainCompletedCondition)。 public event Action OnChainCompleted; /// /// 世界标志变更事件(供 FlagSetCondition 事件驱动订阅,避免每帧轮询)。 /// 由 SetFlagAction.ExecuteAsync 在写入标志后调用 NotifyFlagChanged 触发。 /// public event Action OnWorldFlagChanged; /// 通知所有 FlagSetCondition 指定标志已变更,并立即重评估标志相关链条件。 public void NotifyFlagChanged(string flagId) { OnWorldFlagChanged?.Invoke(flagId); EvaluateForMask(ChainEventMask.FlagChanged); } /// /// 强制执行指定链,完全跳过条件检查。 /// 用于调试、关卡测试,或 QA 快速验证后续事件逻辑。 /// 仅在 Play Mode 中有效(链执行需要运行时环境)。 /// public void ForceExecute(string chainId) { if (_chains == null) { Debug.LogWarning("[EventChainManager] ForceExecute: _chains 为空,没有可执行的事件链。", this); return; } foreach (var chain in _chains) { if (chain == null || chain.chainId != chainId) continue; StartCoroutine(ExecuteChain(chain)); return; } Debug.LogWarning($"[EventChainManager] ForceExecute: 未找到 chainId='{chainId}' 的事件链。", this); } #if UNITY_EDITOR /// /// Editor 专用静态事件:链执行完成时向编辑器窗口推送日志。 /// 仅在编辑器构建中存在,不产生运行时开销。 /// EventChainEditorWindow 在 OnEnable 中订阅此事件。 /// public static event Action OnChainExecutedInEditor; #endif private readonly HashSet _completedChains = new(); private readonly CompositeDisposable _subs = new(); // 每个链对应的事件掩码:OnEnable 后通过 BuildChainMasks 构建 private List _chainMasks; private struct ChainMaskEntry { public EventChainSO chain; public ChainEventMask mask; } // ── 生命周期 ────────────────────────────────────────────────────── private void Awake() { // 不在此处读取存档数据——LoadAsync 尚未完成,_current 为 null。 // 已完成链的恢复由 ISaveable.OnLoad 在 LoadAsync 完成后处理。 } private void OnEnable() { _onBossDefeated?.Subscribe(id => { OnBossDefeated?.Invoke(id); EvaluateForMask(ChainEventMask.Boss); }).AddTo(_subs); _onCollectiblePickedUp?.Subscribe(id => { OnCollectiblePickedUp?.Invoke(id); EvaluateForMask(ChainEventMask.Collectible); }).AddTo(_subs); _onAbilityUnlocked?.Subscribe(id => { OnAbilityUnlocked?.Invoke(id); EvaluateForMask(ChainEventMask.Ability); }).AddTo(_subs); _onRoomEntered?.Subscribe(id => { OnRoomEntered?.Invoke(id); EvaluateForMask(ChainEventMask.Room); }).AddTo(_subs); _onDialogueCompleted?.Subscribe(id => { OnDialogueCompleted?.Invoke(id); EvaluateForMask(ChainEventMask.Dialogue); }).AddTo(_subs); ServiceLocator.GetOrDefault()?.Register(this); // 向每个 Condition 注册中继事件 // 先重置 SO 资产上的运行时状态,防止跨 PlayMode 会话或多场景加载时状态残留 if (_chains == null) return; foreach (var chain in _chains) { // 旧版 conditions[] 字段 if (chain?.conditions != null) foreach (var cond in chain.conditions) { cond?.ResetState(); cond?.Register(this); } // 新版 conditionGroups[] 字段 if (chain?.conditionGroups != null) foreach (var group in chain.conditionGroups) if (group?.conditions != null) foreach (var cond in group.conditions) { cond?.ResetState(); cond?.Register(this); } } BuildChainMasks(); } private void OnDisable() { _subs.Clear(); ServiceLocator.GetOrDefault()?.Unregister(this); if (_chains == null) return; foreach (var chain in _chains) { if (chain?.conditions != null) foreach (var cond in chain.conditions) cond?.Unregister(this); if (chain?.conditionGroups != null) foreach (var group in chain.conditionGroups) if (group?.conditions != null) foreach (var cond in group.conditions) cond?.Unregister(this); } } // ── ISaveable ───────────────────────────────────────────────────────── /// /// SetChainCompleted 通过 ISaveService 直接写入 SaveData,OnSave 无需操作。 /// public void OnSave(SaveData data) { } /// /// LoadAsync 完成后由 GameSaveManager.Register 补发,恢复本会话前已完成的链。 /// 仅恢复状态为 "Completed" 的条目;其他状态(如未来扩展的 "Failed")不影响重入检查。 /// public void OnLoad(SaveData data) { _completedChains.Clear(); if (data?.EventChains?.ChainStates == null) return; foreach (var kv in data.EventChains.ChainStates) if (kv.Value == "Completed") _completedChains.Add(kv.Key); } // ── 评估逻辑 ────────────────────────────────────────────────────── /// /// 构建每条链的 ChainEventMask(链内所有条件 RelevantEvents 的并集)。 /// OnEnable 在所有条件 Register 完毕后调用,之后事件触发只评估掩码相交的链。 /// private void BuildChainMasks() { _chainMasks = new List(_chains?.Length ?? 0); if (_chains == null) return; foreach (var chain in _chains) { if (chain == null) continue; ChainEventMask mask = ChainEventMask.None; bool hasGroups = chain.conditionGroups != null && chain.conditionGroups.Length > 0; if (hasGroups) { foreach (var group in chain.conditionGroups) if (group?.conditions != null) foreach (var cond in group.conditions) if (cond != null) mask |= cond.RelevantEvents; } else if (chain.conditions != null) { foreach (var cond in chain.conditions) if (cond != null) mask |= cond.RelevantEvents; } // 无条件链:任何事件均可触发(等同 Any) if (mask == ChainEventMask.None) mask = ChainEventMask.Any; _chainMasks.Add(new ChainMaskEntry { chain = chain, mask = mask }); } } /// /// 懒评估:仅评估 mask 与 相交的链。 /// ChainEventMask.Any(-1)与任何非零 mask 均相交,确保自定义条件链不被跳过。 /// private void EvaluateForMask(ChainEventMask triggerMask) { if (_chainMasks == null) return; foreach (var entry in _chainMasks) { if ((entry.mask & triggerMask) == 0) continue; var chain = entry.chain; if (!chain.repeatable && _completedChains.Contains(chain.chainId)) continue; if (EvaluateChainConditions(chain)) StartCoroutine(ExecuteChain(chain)); } } /// /// 评估链的所有触发条件。 /// 若链配置了 ,按组逻辑评估(组内 And/Or,组间 And); /// 否则回退到旧版 隐式 And 逻辑。 /// private static bool EvaluateChainConditions(EventChainSO chain) { bool hasGroups = chain.conditionGroups != null && chain.conditionGroups.Length > 0; if (hasGroups) { // 组间为 And:所有组均须通过 foreach (var group in chain.conditionGroups) { if (group?.conditions == null || group.conditions.Length == 0) continue; if (!EvaluateConditionGroup(group)) return false; } return true; } // 旧版:conditions[] 隐式 And if (chain.conditions != null) foreach (var cond in chain.conditions) if (cond != null && !cond.IsMet()) return false; return true; } /// 按组内 logic(And/Or)评估单个条件组是否通过。 private static bool EvaluateConditionGroup(ConditionGroup group) { if (group.logic == WorldStateFlagLogic.Or) { foreach (var cond in group.conditions) if (cond != null && cond.IsMet()) return true; return false; } // And(默认) foreach (var cond in group.conditions) if (cond != null && !cond.IsMet()) return false; return true; } private IEnumerator ExecuteChain(EventChainSO chain) { // 防重入:一次性链立即标记为已完成 if (!chain.repeatable) _completedChains.Add(chain.chainId); if (chain.actions != null) foreach (var action in chain.actions) { if (action == null) continue; bool actionFailed = false; if (_maxActionTimeout > 0f) { bool finished = false; Coroutine co = null; try { co = StartCoroutine(SetTrueOnFinish(action.ExecuteAsync(this), () => finished = true)); } catch (System.Exception ex) { Debug.LogError( $"[EventChainManager] 链 '{chain.chainId}' 动作 '{action.GetType().Name}' 启动异常:{ex.Message}", this); actionFailed = true; } if (!actionFailed) { // 用 realtimeSinceStartup 计时,确保 PlayMode 暂停时超时仍能触发 float deadline = Time.realtimeSinceStartup + _maxActionTimeout; while (!finished) { if (Time.realtimeSinceStartup >= deadline) { if (co != null) StopCoroutine(co); Debug.LogWarning( $"[EventChainManager] 链 '{chain.chainId}' 的动作 '{action.GetType().Name}' " + $"执行超时({_maxActionTimeout}s),已强制跳过。"); #if UNITY_EDITOR OnChainExecutedInEditor?.Invoke(chain.chainId, $"超时跳过:{action.GetType().Name}(>{_maxActionTimeout}s)"); #endif break; } yield return null; } } } else { bool exceptionThrown = false; IEnumerator routine = null; try { routine = action.ExecuteAsync(this); } catch (System.Exception ex) { Debug.LogError( $"[EventChainManager] 链 '{chain.chainId}' 动作 '{action.GetType().Name}' 异常:{ex.Message}", this); exceptionThrown = true; } if (!exceptionThrown && routine != null) yield return routine; } if (chain.actionDelay > 0f) yield return new WaitForSeconds(chain.actionDelay); } ServiceLocator.GetOrDefault()?.SetChainCompleted(chain.chainId); OnChainCompleted?.Invoke(chain.chainId); #if UNITY_EDITOR OnChainExecutedInEditor?.Invoke(chain.chainId, "执行完成"); #endif } /// /// 将 inner 协程执行完毕后触发 onFinish 回调,供超时保护使用。 /// StopCoroutine 此协程时,内嵌的 inner(通过 yield return 直接展开)也会一并停止。 /// private static IEnumerator SetTrueOnFinish(IEnumerator inner, Action onFinish) { yield return inner; onFinish(); } } }