feat: Round 51 narrative systems improvements

- SaveData: update QuestState.Status comment to include Paused state
- QuestManager: add inline comment on AcceptQuest duplicate-accept guard
- QuestManager: wrap reward.Apply() in try-catch so exceptions don't
  corrupt already-committed Completed state
- QuestManager.UnlockBranches: support new conditionFlagEntries (invert/
  NOT logic) with graceful fallback to legacy conditionFlags
- QuestGiver: cache IQuestManager field in OnEnable; subscribe to
  OnQuestStateChanged for automatic cache invalidation instead of manual
  _cacheDirty = true after each Interact; remove per-call SL.GetOrDefault
- QuestGiver: replace hardcoded Chinese prompt strings with
  LocalizationManager.Get(key, 'UI') + inline fallback via GetPrompt()
- QuestSO: add BranchFlagEntry struct (flagId + invert) for NOT-logic
  branch conditions; add conditionFlagEntries to QuestBranch with
  HideInInspector on legacy conditionFlags for backward compat
- QuestModule: add static TTL cache (5 s) for FindAll<QuestSO>() in
  PopulateDependencyGraph to avoid re-scanning disk on every foldout open
- NpcSOEditor: add 'jump to localization file' button that pings and
  selects the UI table JSON in the Project window

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-05-25 00:34:59 +08:00
parent 9c1e70fdeb
commit 48f018f4b8
6 changed files with 181 additions and 43 deletions

View File

@@ -31,6 +31,11 @@ namespace BaseGames.Editor.Modules
// playModeStateChanged 订阅的字段引用,便于在重建 ActionBar 时退订旧订阅,避免内存泄漏
private System.Action<UnityEditor.PlayModeStateChange> _playModeHandler;
// 依赖关系图中 FindAll<QuestSO>() 的静态缓存,同一编辑器会话内复用,避免重复扫描磁盘
private static QuestSO[] s_allQuestCache;
private static double s_allQuestCacheTime;
private const double k_AllQuestCacheTtl = 5.0; // 秒;超时后下次打开 foldout 时刷新
public void Initialize()
{
_listPane = new SoListPane<QuestSO>(
@@ -421,7 +426,14 @@ namespace BaseGames.Editor.Modules
private static void PopulateDependencyGraph(VisualElement container, QuestSO s)
{
var allQuests = AssetOperations.FindAll<QuestSO>();
// 静态 TTL 缓存5 秒内复用上次 FindAll 结果,避免每次展开 foldout 都扫描全量资产
if (s_allQuestCache == null ||
EditorApplication.timeSinceStartup - s_allQuestCacheTime > k_AllQuestCacheTtl)
{
s_allQuestCache = AssetOperations.FindAll<QuestSO>();
s_allQuestCacheTime = EditorApplication.timeSinceStartup;
}
var allQuests = s_allQuestCache;
// ── 前置任务(上游)────────────────────────────────────────────────
bool hasPrereqs = s.prerequisiteQuests != null && s.prerequisiteQuests.Length > 0;