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:
@@ -104,8 +104,9 @@ namespace BaseGames.Dialogue
|
||||
/// 当 IsDialogueActive 时排队等待的对话请求。
|
||||
/// 支持脚本触发的连续对话序列(如剧情链、事件链触发的对话),
|
||||
/// 但容量上限为 8,避免因误触导致无限排队。
|
||||
/// 使用 List 而非 Queue,以支持基于优先级的抢占式淘汰(队满时丢弃最低优先级项目)。
|
||||
/// </summary>
|
||||
private readonly Queue<(DialogueSequenceSO seq, string npcId, int priority)> _pending = new();
|
||||
private readonly List<(DialogueSequenceSO seq, string npcId, int priority)> _pending = new();
|
||||
|
||||
/// <summary>当前是否有对话正在播放。</summary>
|
||||
public bool IsDialogueActive { get; private set; }
|
||||
@@ -178,13 +179,35 @@ namespace BaseGames.Dialogue
|
||||
}
|
||||
|
||||
if (_pending.Count < _pendingQueueCapacity)
|
||||
_pending.Enqueue((sequence, npcId, priority));
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
{
|
||||
_pending.Add((sequence, npcId, priority));
|
||||
}
|
||||
else
|
||||
Debug.LogWarning(
|
||||
$"[DialogueManager] 待播队列已满(容量 {_pendingQueueCapacity})," +
|
||||
$"序列 '{sequence.sequenceId}' 被丢弃。可在 Inspector 中调大 _pendingQueueCapacity。");
|
||||
{
|
||||
// 队满时:查找优先级最低的项目,若新请求优先级更高则淘汰之,否则丢弃新请求
|
||||
int minIdx = 0;
|
||||
for (int i = 1; i < _pending.Count; i++)
|
||||
{
|
||||
if (_pending[i].priority < _pending[minIdx].priority) minIdx = i;
|
||||
}
|
||||
if (priority > _pending[minIdx].priority)
|
||||
{
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
Debug.LogWarning(
|
||||
$"[DialogueManager] 待播队列已满(容量 {_pendingQueueCapacity})," +
|
||||
$"序列 '{_pending[minIdx].seq.sequenceId}'(优先级 {_pending[minIdx].priority})" +
|
||||
$"被优先级更高的 '{sequence.sequenceId}'(优先级 {priority})淘汰。");
|
||||
#endif
|
||||
_pending.RemoveAt(minIdx);
|
||||
_pending.Add((sequence, npcId, priority));
|
||||
}
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
else
|
||||
Debug.LogWarning(
|
||||
$"[DialogueManager] 待播队列已满(容量 {_pendingQueueCapacity})," +
|
||||
$"序列 '{sequence.sequenceId}'(优先级 {priority})被丢弃,队列中最低优先级为 {_pending[minIdx].priority}。");
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
PlayImmediate(sequence, npcId, priority);
|
||||
@@ -412,8 +435,9 @@ namespace BaseGames.Dialogue
|
||||
// 自动播放队首等待中的对话(脚本触发的连续序列)
|
||||
if (_pending.Count > 0)
|
||||
{
|
||||
var (seq, id, pri) = _pending.Dequeue();
|
||||
PlayImmediate(seq, id, pri);
|
||||
var item = _pending[0];
|
||||
_pending.RemoveAt(0);
|
||||
PlayImmediate(item.seq, item.npcId, item.priority);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,11 @@ namespace BaseGames.Dialogue
|
||||
"UI 侧可用此值绘制好感度进度条满格。")]
|
||||
[Min(0)] public int maxAffinity = 0;
|
||||
|
||||
[Header("本地化")]
|
||||
[Tooltip("nameKey 所在的本地化表名(默认 \"UI\")。\n" +
|
||||
"若 NPC 名称存储在非默认表(如 \"Character\"),在此修改后 NpcSOEditor 预览和跳转按钮将使用正确的表。")]
|
||||
public string localizationTable = "UI";
|
||||
|
||||
[Header("交互提示")]
|
||||
[Tooltip("与此 NPC 交互时显示的提示本地化 Key(如 \"INTERACT_Talk\")。\n" +
|
||||
"留空时 InteractableNPC 回退到内置字符串 \"对话\"。")]
|
||||
|
||||
Reference in New Issue
Block a user