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:
@@ -244,6 +244,7 @@ namespace BaseGames.Quest
|
||||
public void AcceptQuest(string questId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(questId)) return;
|
||||
// CanAccept 内部已通过 GetState() != Available 检查,防止重复接取 Active/Completed 任务产生重复事件
|
||||
if (!CanAccept(questId)) return;
|
||||
var oldState = GetState(questId);
|
||||
_questStates[questId] = QuestStateEnum.Active;
|
||||
@@ -361,7 +362,13 @@ namespace BaseGames.Quest
|
||||
Chan_QuestCompleted?.Raise(questId);
|
||||
OnQuestCompleted?.Invoke(questId);
|
||||
|
||||
quest.reward?.Apply(rewardTarget);
|
||||
// 奖励发放:用 try-catch 包裹,防止 Apply 异常导致好感度/对话解锁等后续逻辑中断
|
||||
try { quest.reward?.Apply(rewardTarget); }
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"[QuestManager] 任务 '{questId}' 奖励发放时抛出异常(任务状态已提交为 Completed):{ex.Message}\n{ex.StackTrace}");
|
||||
}
|
||||
ApplyAffinity(quest);
|
||||
UnlockDialogueKey(quest);
|
||||
UnlockBranches(questId, quest);
|
||||
@@ -425,38 +432,62 @@ namespace BaseGames.Quest
|
||||
if (!conditionMet) continue;
|
||||
|
||||
// 世界状态标志条件(And/Or 由 conditionFlagsLogic 决定)
|
||||
// 优先用新版 conditionFlagEntries(支持 invert/NOT 取反),若为空则回退到旧版 conditionFlags
|
||||
// saveService 未注入时降级:跳过标志检查,仅由 conditionQuest 决定分支
|
||||
if (branch.conditionFlags != null && branch.conditionFlags.Length > 0
|
||||
&& saveService != null)
|
||||
bool hasFlagEntries = branch.conditionFlagEntries != null && branch.conditionFlagEntries.Length > 0;
|
||||
bool hasLegacyFlags = branch.conditionFlags != null && branch.conditionFlags.Length > 0;
|
||||
bool hasFlagConds = hasFlagEntries || hasLegacyFlags;
|
||||
|
||||
if (hasFlagConds && saveService != null)
|
||||
{
|
||||
if (branch.conditionFlagsLogic == BaseGames.Core.WorldStateFlagLogic.Or)
|
||||
{
|
||||
conditionMet = false;
|
||||
foreach (var flag in branch.conditionFlags)
|
||||
if (hasFlagEntries)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(flag) && saveService.GetFlag(flag))
|
||||
foreach (var entry in branch.conditionFlagEntries)
|
||||
{
|
||||
conditionMet = true;
|
||||
break;
|
||||
if (string.IsNullOrEmpty(entry.flagId)) continue;
|
||||
bool raw = saveService.GetFlag(entry.flagId);
|
||||
if (entry.invert ? !raw : raw) { conditionMet = true; break; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var flag in branch.conditionFlags)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(flag) && saveService.GetFlag(flag))
|
||||
{ conditionMet = true; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// AND(默认):全部标志均须满足
|
||||
foreach (var flag in branch.conditionFlags)
|
||||
// AND(默认):全部标志均须满足(支持 invert 取反)
|
||||
if (hasFlagEntries)
|
||||
{
|
||||
if (string.IsNullOrEmpty(flag)) continue;
|
||||
if (!saveService.GetFlag(flag)) { conditionMet = false; break; }
|
||||
foreach (var entry in branch.conditionFlagEntries)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entry.flagId)) continue;
|
||||
bool raw = saveService.GetFlag(entry.flagId);
|
||||
if (entry.invert ? raw : !raw) { conditionMet = false; break; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var flag in branch.conditionFlags)
|
||||
{
|
||||
if (string.IsNullOrEmpty(flag)) continue;
|
||||
if (!saveService.GetFlag(flag)) { conditionMet = false; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
else if (branch.conditionFlags != null && branch.conditionFlags.Length > 0
|
||||
&& saveService == null)
|
||||
else if (hasFlagConds && saveService == null)
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"[QuestManager] 任务 '{questId}' 分支配置了 conditionFlags,但 ISaveService 未注册," +
|
||||
$"[QuestManager] 任务 '{questId}' 分支配置了标志条件,但 ISaveService 未注册," +
|
||||
"标志条件已跳过(降级为仅 conditionQuest 判断)。");
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user