using Ichni.Story.Dialogue; using Ichni.Story.UI; using UnityEngine; using UnityEngine.Localization.Settings; using Yarn.Unity; namespace Ichni.Story.YarnFunctions { /// /// 包含与故事树节点控制、全局进程、存档交互相关的 Yarn 自定义命令注册器。 /// public static class StoryTreeCommands { // ── Yarn Commands ──────────────────────────────────────────────────────── /// /// 兼容既有 Yarn 脚本:授予歌曲相关的解锁 Key,并在当前对话结束后弹出提示。 /// 格式: <<unlock_song unlock_key>> /// Key 必须使用小写字母、数字和下划线,例如 story_ch0_prologue_completed /// 新内容若不需要歌曲提示,优先使用 。 /// /// 要授予的稳定解锁 Key,而不是歌曲显示名称。 [YarnCommand("unlock_song")] public static void UnlockSong(string songUnlockKey) { if (!TryGrantUnlockKey(songUnlockKey, out bool wasNewlyGranted) || !wasNewlyGranted) { return; } // 将歌曲提示加入对话结束队列。弹窗本地化将由后续 Localization 阶段替换, // 这里不参与内容是否解锁的授权判断。 if (StoryDialogueController.instance != null) { StoryDialogueController.instance.dialogueEndActions.Add(() => { if (MessageUIPage.instance != null) { MessageUIPage.instance.ShowUnlockMessage(songUnlockKey); } else { Debug.LogError("[StoryTreeCommands] 弹窗失败:场景中未找到 StoryMessageBoxUIPage 实例!"); } }); } else { Debug.LogError("[StoryTreeCommands] 弹窗队列注册失败:未找到 StoryDialogueController 实例!"); } } /// /// 通用内容解锁命令,可用于章节、歌曲、教程及未来内容。 /// 格式: <<grant_unlock unlock_key>>。 /// 本命令只授予并保存 Key,不绑定任何 UI 提示;需要提示时应由 Yarn 额外调用 show_message。 /// /// 符合 的稳定解锁 Key。 [YarnCommand("grant_unlock")] public static void GrantUnlock(string unlockKey) { TryGrantUnlockKey(unlockKey, out _); } /// /// 在对话结束后,弹出一个自定义 MessageBox 提示。 /// 会尝试使用 Unity Localization 进行翻译,如果找不到对应条目则回退显示原文本(Key)。 /// 格式: <<show_message titleKey contentKey [tableName]>> /// /// 标题文本或本地化键 /// 正文文本或本地化键 /// Unity Localization 中的 String Table 名称 [YarnCommand("show_message")] public static void ShowMessage(string titleKey, string contentKey, string tableName = "Message") { string translatedTitle = GetTranslatedText(tableName, titleKey); string translatedContent = GetTranslatedText(tableName, contentKey); Debug.Log($"[StoryTreeCommands] 准备在对话结束后显示自定义弹窗:标题='{translatedTitle}',内容='{translatedContent}'"); StoryDialogueController.instance.dialogueEndActions.Add(() => { MessageUIPage.instance.ShowCustomMessage(translatedTitle, translatedContent); }); } /// /// 所有 Yarn 解锁命令共用的授予入口。它负责模块存在性检查、重复授予的幂等处理及立即 ES3 保存。 /// /// 模块已正常处理该 Key 时返回 true;Key 非法或模块尚未初始化时返回 false。 private static bool TryGrantUnlockKey(string unlockKey, out bool wasNewlyGranted) { wasNewlyGranted = false; UnlockSaveModule unlockSaveModule = GameSaveManager.instance?.UnlockSaveModule; if (unlockSaveModule == null) { Debug.LogError("[StoryTreeCommands] 无法授予解锁 Key:UnlockSaveModule 尚未初始化!"); return false; } if (unlockSaveModule.HasKey(unlockKey)) { Debug.Log($"[StoryTreeCommands] 解锁 Key 已存在:{unlockKey}"); return true; } wasNewlyGranted = unlockSaveModule.GrantKey(unlockKey); if (wasNewlyGranted) { Debug.Log($"[StoryTreeCommands] 已成功写入并保存解锁 Key:{unlockKey}"); } return wasNewlyGranted; } // ── 内部辅助 ───────────────────────────────────────────────────────────── private static string GetTranslatedText(string tableName, string key) { if (string.IsNullOrEmpty(key)) return string.Empty; try { // 尝试从 Unity Localization 中获取翻译文本 string translated = LocalizationSettings.StringDatabase.GetLocalizedString(tableName, key); // 若获取失败或为空,则直接原样返回 key 作为兜底文本 return string.IsNullOrEmpty(translated) ? key : translated; } catch { // 如果表不存在或其他异常,返回原 key return key; } } } }