feat: Round 49 narrative systems improvements
QuestManager: extract CheckQuestDepsAndFlags shared method, simplify GetQuestLockInfo/CanAccept/MeetsPrerequisites; add GetQuestsInState+FilterQuests implementations; fix extra brace compile bug; add _pauseTimestamps logging; use actualDelta in ApplyAffinity event. QuestSO: add depth>32 guard to HasPrerequisiteCycle and HasBranchCycle to prevent editor freeze on deep chains. EventChainModule: replace FindObjectOfType with ServiceLocator.GetOrDefault in ForceExecute; add self-trigger flag detection (check 6) in ValidateAllChains using reflection. DialogueVariantPreviewWindow: add matrix analysis section enumerating all 2^N flag combinations (N<=10) with table showing winning variant per combination. WorldStateRegistry: LoadFromSave null guard on data.World sub-collections (P0 fix). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -431,10 +431,10 @@ namespace BaseGames.Editor.Modules
|
||||
var capturedC = c;
|
||||
var forceBtn = new Button(() =>
|
||||
{
|
||||
var mgr = UnityEngine.Object.FindObjectOfType<EventChainManager>();
|
||||
var mgr = BaseGames.Core.ServiceLocator.GetOrDefault<EventChainManager>();
|
||||
if (mgr == null)
|
||||
{
|
||||
Debug.LogWarning("[EventChainModule] 场景中未找到 EventChainManager,无法强制触发。");
|
||||
Debug.LogWarning("[EventChainModule] ServiceLocator 中未找到 EventChainManager,无法强制触发。请确认场景中已挂载并注册。");
|
||||
return;
|
||||
}
|
||||
Debug.Log($"[EventChainModule] 强制触发链:{capturedC.chainId}");
|
||||
@@ -519,6 +519,48 @@ namespace BaseGames.Editor.Modules
|
||||
AddError($"{c.chainId}: actions[{i}] 为 null,运行时将触发 NullReferenceException。", c);
|
||||
}
|
||||
|
||||
// ⑥ 自触发检测:某条件检查的标志由同一链的 Action 写入(可能造成链被自身条件阻断或无限反复触发)
|
||||
var flagFieldFlags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance;
|
||||
foreach (var c in allChains)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(c.chainId)) continue;
|
||||
var writtenFlags = new System.Collections.Generic.HashSet<string>(StringComparer.Ordinal);
|
||||
var readFlags = new System.Collections.Generic.HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
if (c.actions != null)
|
||||
foreach (var action in c.actions)
|
||||
{
|
||||
if (action == null) continue;
|
||||
foreach (var field in action.GetType().GetFields(flagFieldFlags))
|
||||
if ((field.Name.Contains("flag", System.StringComparison.OrdinalIgnoreCase) ||
|
||||
field.Name.Contains("Flag", System.StringComparison.OrdinalIgnoreCase))
|
||||
&& field.FieldType == typeof(string))
|
||||
{
|
||||
var val = field.GetValue(action) as string;
|
||||
if (!string.IsNullOrEmpty(val)) writtenFlags.Add(val);
|
||||
}
|
||||
}
|
||||
|
||||
if (c.conditions != null)
|
||||
foreach (var cond in c.conditions)
|
||||
{
|
||||
if (cond == null) continue;
|
||||
foreach (var field in cond.GetType().GetFields(flagFieldFlags))
|
||||
if ((field.Name.Contains("flag", System.StringComparison.OrdinalIgnoreCase) ||
|
||||
field.Name.Contains("Flag", System.StringComparison.OrdinalIgnoreCase))
|
||||
&& field.FieldType == typeof(string))
|
||||
{
|
||||
var val = field.GetValue(cond) as string;
|
||||
if (!string.IsNullOrEmpty(val)) readFlags.Add(val);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var flagId in readFlags)
|
||||
if (writtenFlags.Contains(flagId))
|
||||
AddWarn($"{c.chainId}: 条件读取的标志 '{flagId}' 同时被本链的 Action 写入。" +
|
||||
"若该标志在触发前已被设置,链将永远无法执行或会产生意外的循环行为。", c);
|
||||
}
|
||||
|
||||
Debug.Log($"[EventChainModule] 验证完成:{allChains.Count} 条事件链,{errorCount} 个错误,{warnCount} 个警告。");
|
||||
QuestValidationResultWindow.Show(issues, errorCount, warnCount, allChains.Count, "事件链批量验证结果", "事件链");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user