refactor: Round 53 remove all legacy backward-compatibility code
- QuestSO: remove giverNpcId, prerequisiteQuests/Flags/FlagsLogic, failCondition, conditionFlags, npcDialogueKey fields; simplify GiverNpcId property to giverNpc?.npcId; clean ValidatePrerequisiteCycles/HasPrerequisiteCycle to use prerequisites.questDependencies; remove ValidateBranchDialogueKeys migration warning block; clean QuestPrerequisite doc - QuestManager: remove OnLoad DataVersion 1/2 migration paths (ProgressCounts, hasNewFormat/ useNewFormat); remove CheckQuestDepsAndFlags old-field fallback (prerequisiteQuests/Flags); remove UnlockBranches conditionFlags fallback; remove DispatchEvent failCondition fallback; fix ValidatePrerequisites DFS to scan prerequisites.questDependencies - SaveData: remove ProgressCounts (Obsolete), ObjectiveIndex (unused), GiverNpcId (never written) fields from QuestState; simplify DataVersion doc comment - QuestSOEditor: replace migration-only editor with minimal DrawDefaultInspector - QuestModule: update all prerequisiteQuests/conditionFlags/npcDialogueKey/failCondition references to canonical new fields; update ValidateBranchFlags check 10 - FlagAuditModule: replace conditionFlags/prerequisiteFlags scans with conditionFlagEntries/ prerequisites.flagCondition.flags - NpcSO: remove QuestSO.giverNpcId reference from npcId tooltip - NpcAffinityEvent/RewardSO: update doc comments to reference giverNpc instead of giverNpcId Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -438,59 +438,34 @@ namespace BaseGames.Quest
|
||||
if (!conditionMet) continue;
|
||||
|
||||
// 世界状态标志条件(And/Or 由 conditionFlagsLogic 决定)
|
||||
// 优先用新版 conditionFlagEntries(支持 invert/NOT 取反),若为空则回退到旧版 conditionFlags
|
||||
// saveService 未注入时降级:跳过标志检查,仅由 conditionQuest 决定分支
|
||||
bool hasFlagEntries = branch.conditionFlagEntries != null && branch.conditionFlagEntries.Length > 0;
|
||||
bool hasLegacyFlags = branch.conditionFlags != null && branch.conditionFlags.Length > 0;
|
||||
bool hasFlagConds = hasFlagEntries || hasLegacyFlags;
|
||||
bool hasFlagEntries = branch.conditionFlagEntries != null && branch.conditionFlagEntries.Length > 0;
|
||||
|
||||
if (hasFlagConds && saveService != null)
|
||||
if (hasFlagEntries && saveService != null)
|
||||
{
|
||||
if (branch.conditionFlagsLogic == BaseGames.Core.WorldStateFlagLogic.Or)
|
||||
{
|
||||
conditionMet = false;
|
||||
if (hasFlagEntries)
|
||||
foreach (var entry in branch.conditionFlagEntries)
|
||||
{
|
||||
foreach (var entry in branch.conditionFlagEntries)
|
||||
{
|
||||
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; }
|
||||
}
|
||||
if (string.IsNullOrEmpty(entry.flagId)) continue;
|
||||
bool raw = saveService.GetFlag(entry.flagId);
|
||||
if (entry.invert ? !raw : raw) { conditionMet = true; break; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// AND(默认):全部标志均须满足(支持 invert 取反)
|
||||
if (hasFlagEntries)
|
||||
foreach (var entry in branch.conditionFlagEntries)
|
||||
{
|
||||
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 (string.IsNullOrEmpty(entry.flagId)) continue;
|
||||
bool raw = saveService.GetFlag(entry.flagId);
|
||||
if (entry.invert ? raw : !raw) { conditionMet = false; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
else if (hasFlagConds && saveService == null)
|
||||
else if (hasFlagEntries && saveService == null)
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"[QuestManager] 任务 '{questId}' 分支配置了标志条件,但 ISaveService 未注册," +
|
||||
@@ -700,14 +675,8 @@ namespace BaseGames.Quest
|
||||
var quest = GetQuestSO(id);
|
||||
if (quest?.objectives == null) continue;
|
||||
|
||||
bool hasNewFormat = saved.ObjectiveProgress != null && saved.ObjectiveProgress.Count > 0;
|
||||
// DataVersion >= 2:新格式(objectiveId 键值对);DataVersion <= 1 或遗留存档:旧格式(按索引)
|
||||
// Count > 0 作为无 DataVersion 字段时的兼容兜底
|
||||
bool useNewFormat = saved.DataVersion >= 2 || hasNewFormat;
|
||||
|
||||
if (useNewFormat && saved.ObjectiveProgress != null)
|
||||
if (saved.ObjectiveProgress != null)
|
||||
{
|
||||
// 新格式:objectiveId → count,重排顺序后仍可正确恢复
|
||||
foreach (var obj in quest.objectives)
|
||||
{
|
||||
if (obj == null) continue;
|
||||
@@ -716,29 +685,12 @@ namespace BaseGames.Quest
|
||||
if (!_objectiveStates.TryGetValue(compositeKey, out var os))
|
||||
os = _objectiveStates[compositeKey] = new QuestObjectiveState();
|
||||
os.progressCount = count;
|
||||
// DataVersion >= 3:从存档恢复 completed 标志(防止 GetRequiredCount 变更后判定漂移)
|
||||
if (saved.ObjectiveCompleted != null &&
|
||||
saved.ObjectiveCompleted.TryGetValue(obj.objectiveId, out bool done))
|
||||
os.completed = done;
|
||||
}
|
||||
}
|
||||
else if (saved.ProgressCounts != null
|
||||
#pragma warning disable CS0618 // ProgressCounts 弃用字段:仅在此处读取用于旧存档迁移,不再写入
|
||||
&& saved.ProgressCounts.Count > 0)
|
||||
{
|
||||
// 旧格式兼容(按数组索引):迁移旧存档用,不再写入新存档
|
||||
for (int i = 0; i < quest.objectives.Length && i < saved.ProgressCounts.Count; i++)
|
||||
{
|
||||
var obj = quest.objectives[i];
|
||||
if (obj == null) continue;
|
||||
string compositeKey = GetCompositeKey(id, obj.objectiveId);
|
||||
if (!_objectiveStates.TryGetValue(compositeKey, out var os))
|
||||
os = _objectiveStates[compositeKey] = new QuestObjectiveState();
|
||||
os.progressCount = saved.ProgressCounts[i];
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
// DataVersion >= 3:恢复任务开始 / 完成时间戳(0 = 旧存档未记录,跳过)
|
||||
|
||||
if (saved.StartedAtUtc != 0) _startedAtUtc[id] = saved.StartedAtUtc;
|
||||
if (saved.CompletedAtUtc != 0) _completedAtUtc[id] = saved.CompletedAtUtc;
|
||||
}
|
||||
@@ -775,7 +727,7 @@ namespace BaseGames.Quest
|
||||
/// <summary>
|
||||
/// 初始化(或修正)所有任务的 Available/Unavailable 状态。
|
||||
/// 在 Awake(冷启动)和 OnLoad(存档恢复)后调用。
|
||||
/// OnLoad 后 ISaveService 已就绪,会重新评估 prerequisiteFlags,
|
||||
/// OnLoad 后 ISaveService 已就绪,会重新评估 prerequisites.flagCondition.flags,
|
||||
/// 修正 Awake 期间因服务未就绪而被跳过的标志检查。
|
||||
/// Active/Completed/Failed 状态来自存档,不重置。
|
||||
/// </summary>
|
||||
@@ -794,7 +746,7 @@ namespace BaseGames.Quest
|
||||
// _affinityInitialized 为 true 说明是 OnLoad 后调用,Awake 期间不打此日志
|
||||
bool isNewToSave = !_questStates.ContainsKey(q.questId) && _affinityInitialized;
|
||||
#endif
|
||||
// Available/Unavailable 均重新评估,确保 prerequisiteFlags 变更后状态正确
|
||||
// Available/Unavailable 均重新评估,确保 prerequisites.flagCondition.flags 变更后状态正确
|
||||
_questStates[q.questId] = MeetsPrerequisites(q) ? QuestStateEnum.Available : QuestStateEnum.Unavailable;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
if (isNewToSave)
|
||||
@@ -824,64 +776,28 @@ namespace BaseGames.Quest
|
||||
{
|
||||
if (quest == null) return new QuestLockInfo { Reason = QuestLockReason.NotFound };
|
||||
|
||||
if (quest.prerequisites.HasAny)
|
||||
{
|
||||
if (quest.prerequisites.questDependencies != null)
|
||||
foreach (var dep in quest.prerequisites.questDependencies)
|
||||
{
|
||||
if (dep == null) continue;
|
||||
if (string.IsNullOrEmpty(dep.questId))
|
||||
{
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
Debug.LogWarning($"[QuestManager] 任务 '{quest.questId}' 的 prerequisites.questDependencies 含 questId 为空的条目,已跳过。");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (GetState(dep.questId) != QuestStateEnum.Completed)
|
||||
return new QuestLockInfo { Reason = QuestLockReason.RequiresQuest, Param = dep.questId };
|
||||
}
|
||||
|
||||
var fc = quest.prerequisites.flagCondition;
|
||||
if (fc.flags != null && fc.flags.Length > 0)
|
||||
if (quest.prerequisites.questDependencies != null)
|
||||
foreach (var dep in quest.prerequisites.questDependencies)
|
||||
{
|
||||
var svc = BaseGames.Core.ServiceLocator.GetOrDefault<ISaveService>();
|
||||
// ISaveService 未就绪(Awake 阶段)→ 保守跳过;OnLoad 后重新评估
|
||||
if (svc != null && !EvaluateFlagPrerequisites(fc.flags, fc.logic, svc))
|
||||
return new QuestLockInfo { Reason = QuestLockReason.FlagConditionNotMet };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 旧版字段回退(兼容现有资产)
|
||||
#pragma warning disable CS0618
|
||||
if (quest.prerequisiteQuests != null)
|
||||
foreach (var pre in quest.prerequisiteQuests)
|
||||
if (dep == null) continue;
|
||||
if (string.IsNullOrEmpty(dep.questId))
|
||||
{
|
||||
if (pre == null) continue;
|
||||
if (string.IsNullOrEmpty(pre.questId))
|
||||
{
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
Debug.LogWarning($"[QuestManager] 任务 '{quest.questId}' 的 prerequisiteQuests 含 questId 为空的条目,已跳过该前置条件。");
|
||||
Debug.LogWarning($"[QuestManager] 任务 '{quest.questId}' 的 prerequisites.questDependencies 含 questId 为空的条目,已跳过。");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (GetState(pre.questId) != QuestStateEnum.Completed)
|
||||
return new QuestLockInfo { Reason = QuestLockReason.RequiresQuest, Param = pre.questId };
|
||||
continue;
|
||||
}
|
||||
if (GetState(dep.questId) != QuestStateEnum.Completed)
|
||||
return new QuestLockInfo { Reason = QuestLockReason.RequiresQuest, Param = dep.questId };
|
||||
}
|
||||
|
||||
if (quest.prerequisiteFlags != null && quest.prerequisiteFlags.Length > 0)
|
||||
{
|
||||
var svc = BaseGames.Core.ServiceLocator.GetOrDefault<ISaveService>();
|
||||
if (svc != null)
|
||||
{
|
||||
if (!EvaluateFlagPrerequisites(quest.prerequisiteFlags, quest.prerequisiteFlagsLogic, svc))
|
||||
return new QuestLockInfo { Reason = QuestLockReason.FlagConditionNotMet };
|
||||
}
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
else Debug.LogWarning($"[QuestManager] 任务 '{quest.questId}' 的 prerequisiteFlags 需要 ISaveService,但服务未注册,标志检查已跳过。");
|
||||
#endif
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
var fc = quest.prerequisites.flagCondition;
|
||||
if (fc.flags != null && fc.flags.Length > 0)
|
||||
{
|
||||
var svc = BaseGames.Core.ServiceLocator.GetOrDefault<ISaveService>();
|
||||
// ISaveService 未就绪(Awake 阶段)→ 保守跳过;OnLoad 后重新评估
|
||||
if (svc != null && !EvaluateFlagPrerequisites(fc.flags, fc.logic, svc))
|
||||
return new QuestLockInfo { Reason = QuestLockReason.FlagConditionNotMet };
|
||||
}
|
||||
|
||||
return new QuestLockInfo { Reason = QuestLockReason.None };
|
||||
@@ -1065,22 +981,14 @@ namespace BaseGames.Quest
|
||||
// 设计意图:暂停期间目标冻结,失败条件也不判定,恢复后再继续检查。
|
||||
if (quest.canFail)
|
||||
{
|
||||
// P3-A:多失败条件支持——failConditions 数组中任意一个达成即失败
|
||||
bool triggered = false;
|
||||
if (quest.failConditions != null && quest.failConditions.Length > 0)
|
||||
if (quest.failConditions != null)
|
||||
{
|
||||
foreach (var fc in quest.failConditions)
|
||||
{
|
||||
if (fc != null && CheckObjective(qid, fc)) { triggered = true; break; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 向后兼容旧版单一 failCondition 字段(Obsolete,将在后续版本移除)
|
||||
#pragma warning disable CS0618
|
||||
triggered = quest.failCondition != null && CheckObjective(qid, quest.failCondition);
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
if (triggered)
|
||||
{
|
||||
toFail ??= new List<string>();
|
||||
@@ -1181,7 +1089,7 @@ namespace BaseGames.Quest
|
||||
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
/// <summary>
|
||||
/// 通过 DFS 后序遍历检测 prerequisiteQuests 中是否存在循环引用。
|
||||
/// 通过 DFS 后序遍历检测 prerequisites.questDependencies 中是否存在循环引用。
|
||||
/// 在编辑器 OnValidate 及开发构建 Awake 时调用,发现问题立即打 LogError。
|
||||
/// </summary>
|
||||
[UnityEngine.ContextMenu("校验前置任务循环引用")]
|
||||
@@ -1219,10 +1127,10 @@ namespace BaseGames.Quest
|
||||
color[startId] = 1;
|
||||
path.Add(startId);
|
||||
|
||||
var prereqs = index[startId].prerequisiteQuests;
|
||||
if (prereqs != null)
|
||||
var prereqDeps = index[startId].prerequisites.questDependencies;
|
||||
if (prereqDeps != null)
|
||||
{
|
||||
foreach (var pre in prereqs)
|
||||
foreach (var pre in prereqDeps)
|
||||
{
|
||||
if (pre == null || string.IsNullOrEmpty(pre.questId)) continue;
|
||||
if (HasCycle(pre.questId, path)) return true;
|
||||
|
||||
Reference in New Issue
Block a user