feat: Round 50 narrative systems improvements

IQuestManager+QuestManager: add FillQuestsInState/FillFilterQuests buffer overloads (no-alloc hot path); remove R49 duplicate implementations.

QuestGiver: cache current quest result (_cachedQuest/_cachedState/_cacheDirty) to avoid per-frame foreach in InteractPrompt; invalidate on OnEnable and Interact_Internal state changes.

IDialogueService+DialogueManager: add StartDialogue(..., Action onComplete) overload; callback fires once on ForceEnd (covers both normal end and interrupt); supports chained callbacks via += accumulation.

DialogueVariantPreviewWindow: add 'Copy CSV' button in matrix section; exports all 2^N flag combinations with winner column; handles N>10 guard and CSV-safe escaping.

WorldStateRegistry: add TryGetCategory(id, out category) reverse lookup for debug tools.

NpcSOEditor: new CustomEditor for NpcSO showing live nameKey localization preview in Inspector (green label or warning box if Key not found).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-05-25 00:24:20 +08:00
parent 3c3ea1ead6
commit 9c1e70fdeb
8 changed files with 283 additions and 37 deletions

View File

@@ -65,6 +65,10 @@ namespace BaseGames.Dialogue
/// </summary>
private int _playbackId;
// ── 一次性对话完成回调 ────────────────────────────────────────────────
// 通过 StartDialogue(..., onComplete) 注册OnDialogueEnded 触发后调用一次后清空。
private System.Action _onCompleteCallback;
// ── 子协程通信字段(避免协程间 ref/out 参数)─────────────────────────
/// <summary>HandleChoices 子协程写入结果玩家选中选项后的后续序列null = 无后续)。</summary>
private DialogueSequenceSO _choiceBranchResult;
@@ -186,6 +190,17 @@ namespace BaseGames.Dialogue
PlayImmediate(sequence, npcId, priority);
}
/// <inheritdoc cref="IDialogueService.StartDialogue(DialogueSequenceSO,string,int,System.Action)"/>
public void StartDialogue(DialogueSequenceSO sequence, string npcId, int priority, System.Action onComplete)
{
if (onComplete != null)
{
// 若已有待回调,链式追加(不覆盖),保证先来先到
_onCompleteCallback += onComplete;
}
StartDialogue(sequence, npcId, priority);
}
private void PlayImmediate(DialogueSequenceSO sequence, string npcId, int priority = 0)
{
IsDialogueActive = true;
@@ -239,6 +254,11 @@ namespace BaseGames.Dialogue
_onDialogueEnded?.Raise();
if (_onDialogueEnded == null) _inputReader?.EnableGameplayInput();
OnDialogueEnded?.Invoke();
// 触发一次性完成回调(正常结束和强制中断均触发)
var cb = _onCompleteCallback;
_onCompleteCallback = null;
cb?.Invoke();
}
// ── 输入回调 ──────────────────────────────────────────────────────