feat: Round 52 narrative systems improvements

P1-A: QuestManager.OnLoad Enum.TryParse failure warning (dev builds)
P1-B: SaveData.QuestState ObjectiveCompleted dict; BuildObjectiveCompleted
       helper; OnSave/OnLoad wiring (DataVersion 2→3)
P2-A: Quest start/complete timestamps (_startedAtUtc/_completedAtUtc dicts;
       StartedAtUtc/CompletedAtUtc in SaveData; AcceptQuest/CompleteQuest/
       OnSave/OnLoad wiring)
P2-B: DialogueManager pending queue Queue→List + priority-eviction on full
       (lowest-priority item evicted when higher-priority request arrives)
P2-C: NpcSO.localizationTable field; NpcSOEditor uses npc.localizationTable
       in TryResolveNameKey, PingLocalizationFile, and button label
P3-A: QuestSO.failConditions[] multi-fail array; Obsolete failCondition;
       DispatchEvent updates fail check to any-of-array logic with fallback
P3-B: QuestObjectiveSO.prerequisiteObjectiveId; DispatchEvent gates objective
       event routing behind prerequisite completed check
P3-C: IQuestEventPayload interface + StringQuestPayload struct; QuestObjectiveSO
       typed TryHandleEvent(IQuestEventPayload) overload; DispatchEvent string
       overload delegates to typed IQuestEventPayload overload

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-05-25 00:47:44 +08:00
parent 48f018f4b8
commit 0b28cabba4
8 changed files with 189 additions and 25 deletions

View File

@@ -138,13 +138,23 @@ namespace BaseGames.Core.Save
/// 此 QuestState 数据格式版本号。
/// 1 = 原始格式ProgressCounts 按索引,已弃用)
/// 2 = Round 24+ 格式ObjectiveProgress 按 objectiveId 键值对)
/// 3 = Round 52+ 格式(新增 ObjectiveCompleted、StartedAtUtc、CompletedAtUtc
/// OnLoad 按此字段显式选择解析路径,杜绝依赖 Count > 0 的隐式推断。
/// </summary>
public int DataVersion = 2;
public string Status; // "Unavailable"|"Available"|"Active"|"Paused"|"Completed"|"Failed"
public int DataVersion = 3;
/// <summary>任务运行时状态字符串。有效值:Unavailable|Available|Active|Paused|Completed|Failed
/// OnLoad 通过 Enum.TryParse 解析;无效值将触发开发模式警告并降级为 Unavailable。</summary>
public string Status;
public int ObjectiveIndex;
/// <summary>新格式(Round 24+DataVersion=2objectiveId → progressCount重排目标顺序后存档不会错位。</summary>
/// <summary>新格式DataVersion2objectiveId → progressCount重排目标顺序后存档不会错位。</summary>
public Dictionary<string, int> ObjectiveProgress = new();
/// <summary>各目标是否已判定完成objectiveId → completed
/// 防止 GetRequiredCount 在版本迭代中变更后重新计算结果与存档实际状态不一致。DataVersion≥3 写入。</summary>
public Dictionary<string, bool> ObjectiveCompleted = new();
/// <summary>任务接取时间Unix 秒时间戳UTC。0 = 未记录旧存档。DataVersion≥3 写入。</summary>
public long StartedAtUtc;
/// <summary>任务完成时间Unix 秒时间戳UTC。0 = 未完成或未记录。DataVersion≥3 写入。</summary>
public long CompletedAtUtc;
/// <summary>旧格式按数组索引DataVersion=1仅用于迁移旧版存档新存档不再写入。已弃用将在后续版本移除。</summary>
[System.Obsolete("旧格式存档兼容字段,仅供 OnLoad DataVersion=1 迁移使用。新存档改用 ObjectiveProgressobjectiveId 键值对)。")]
public List<int> ProgressCounts = new();