Files
zeling_v2/Assets/_Game/Scripts/Dialogue/NpcSO.cs
Joywayer da2948dff8 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>
2026-05-25 01:00:32 +08:00

92 lines
4.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
namespace BaseGames.Dialogue
{
/// <summary>
/// NPC 元数据资产(架构 14_NarrativeModule §2
/// 将 NPC 的唯一 ID、本地化名称 Key、头像、好感度上限集中在一处管理。
///
/// 关联:
/// • <see cref="InteractableNPC"/> 通过 _npcId 字段与此 SO 对应。
/// • <see cref="DialogueActorSO"/> 管理对话 UI 侧头像/颜色(二者可共享同一 Sprite或独立维护
/// • <see cref="BaseGames.Quest.QuestSO"/> 的 <c>giverNpc</c> 字段直接引用此 SO避免手填字符串。
///
/// 资产路径Assets/_Game/Data/NPC/NPC_{npcId}.asset
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/NPC/NPC")]
public class NpcSO : ScriptableObject
{
[Header("标识")]
[Tooltip("NPC 唯一 ID如 \"NPC_Elder\"。需与 InteractableNPC._npcId 保持一致。")]
public string npcId;
[Header("显示")]
[Tooltip("本地化 Key如 \"NPC_Elder_Name\"。通过 LocalizationManager 解析为实际名称。")]
public string nameKey;
[Tooltip("NPC 头像用于地图、任务日志、DataHub 等 UI。")]
public Sprite portrait;
[Header("好感度")]
[Tooltip("该 NPC 的好感度上限0 = 无上限)。\n" +
"QuestManager.CompleteQuest 发放 affinityBonus 时,不超过此数值。\n" +
"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 回退到内置字符串 \"对话\"。")]
public string interactPromptKey = "INTERACT_Talk";
#if UNITY_EDITOR
// npcId → 资产路径5 秒 TTL跨所有 NpcSO.OnValidate 共用O(1) 重复检测。
private static System.Collections.Generic.Dictionary<string, string> s_npcIdToPath;
private static double s_npcIdsCacheTime = -10.0;
private static System.Collections.Generic.Dictionary<string, string> GetNpcIdCache()
{
double now = UnityEditor.EditorApplication.timeSinceStartup;
if (s_npcIdToPath != null && now - s_npcIdsCacheTime < 5.0)
return s_npcIdToPath;
s_npcIdToPath = new System.Collections.Generic.Dictionary<string, string>(System.StringComparer.Ordinal);
string[] guids = UnityEditor.AssetDatabase.FindAssets("t:NpcSO");
foreach (var guid in guids)
{
var path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
var npc = UnityEditor.AssetDatabase.LoadAssetAtPath<NpcSO>(path);
if (npc != null && !string.IsNullOrEmpty(npc.npcId) && !s_npcIdToPath.ContainsKey(npc.npcId))
s_npcIdToPath[npc.npcId] = path;
}
s_npcIdsCacheTime = now;
return s_npcIdToPath;
}
private void OnValidate()
{
if (string.IsNullOrWhiteSpace(npcId))
{
UnityEditor.EditorUtility.SetDirty(this);
npcId = name;
}
var cache = GetNpcIdCache();
string myPath = UnityEditor.AssetDatabase.GetAssetPath(this);
if (!string.IsNullOrEmpty(myPath) &&
cache.TryGetValue(npcId, out var existingPath) &&
existingPath != myPath)
{
Debug.LogError(
$"[NpcSO] npcId '{npcId}' 与 " +
$"'{System.IO.Path.GetFileNameWithoutExtension(existingPath)}' 重复!请修改其中一个。", this);
s_npcIdsCacheTime = -10.0;
}
}
#endif
}
}