using System.Collections.Generic; using Ichni.Menu; using Ichni.Story; using UnityEngine; namespace Ichni { /// /// 剧情存档模块。 /// 故事树状态与对话选项 按章节 保存(单文件、单 ES3 key)。 /// 剧情变量 全局 保存,可跨章节引用,契合 Yarn 变量模型。 /// public class StorySaveModule { private const string ChapterStoryKey = "ChapterStory"; private const string VariablesKey = "StoryVariables"; // 已加载章节的内存缓存(chapterIndex -> 章节存档) private readonly Dictionary _chapterSaves = new Dictionary(); // 全局剧情变量(float / string / bool 三类型,匹配 Yarn 契约) public StoryVariablesSave variables = new StoryVariablesSave(); private static string GetChapterSavePath(string chapterIndex) => Application.persistentDataPath + "/StorySaves/" + chapterIndex + ".json"; private static string VariablesPath => Application.persistentDataPath + "/StorySaves/StoryVariables.json"; // ── 故事树 + 选项(按章节)──────────────────────────────────────────────── /// /// 判断某章节是否尚无存档(首次进入)。 /// public bool IsNewChapter(string chapterIndex) => !ES3.FileExists(GetChapterSavePath(chapterIndex)); /// /// 加载指定章节的存档容器;无存档时返回一个新的空容器。加载结果会写入内存缓存。 /// public ChapterStorySave LoadChapter(string chapterIndex) { string path = GetChapterSavePath(chapterIndex); ChapterStorySave save; if (ES3.FileExists(path) && ES3.KeyExists(ChapterStoryKey, path)) { save = ES3.Load(ChapterStoryKey, path); } else { save = new ChapterStorySave { chapterIndex = chapterIndex }; } _chapterSaves[chapterIndex] = save; return save; } /// /// 保存整章存档(blocks + connectors + choices),单次 ES3 写入。 /// public void SaveChapter(ChapterStorySave save) { _chapterSaves[save.chapterIndex] = save; ES3.Save(ChapterStoryKey, save, GetChapterSavePath(save.chapterIndex)); } /// /// 获取内存中的章节存档;若未加载则从磁盘加载。 /// public ChapterStorySave GetChapter(string chapterIndex) { return _chapterSaves.TryGetValue(chapterIndex, out ChapterStorySave save) ? save : LoadChapter(chapterIndex); } // ── 对话选项(按章节)────────────────────────────────────────────────────── /// /// 记录某章节内一次对话选项的选择结果。 /// public void SetChoice(string chapterIndex, string choiceKey, int optionIndex) { GetChapter(chapterIndex).selectedChoices[choiceKey] = optionIndex; } /// /// 读取某章节内已记录的对话选项选择结果。 /// public bool TryGetChoice(string chapterIndex, string choiceKey, out int optionIndex) { return GetChapter(chapterIndex).selectedChoices.TryGetValue(choiceKey, out optionIndex); } // ── 剧情变量(全局)────────────────────────────────────────────────────── /// /// 从磁盘加载全局剧情变量(启动时调用)。 /// public void LoadVariables() { if (ES3.FileExists(VariablesPath) && ES3.KeyExists(VariablesKey, VariablesPath)) { variables = ES3.Load(VariablesKey, VariablesPath); } else { variables = new StoryVariablesSave(); } } /// /// 将全局剧情变量写入磁盘。 /// public void SaveVariables() { ES3.Save(VariablesKey, variables, VariablesPath); } // ── 清档 ──────────────────────────────────────────────────────────────── /// /// 清除所有章节的故事树存档与全局剧情变量。 /// public void ClearAllStoryline() { if (ChapterSelectionManager.instance != null) { foreach (ChapterSelectionUnit chapter in ChapterSelectionManager.instance.chapters) { string path = GetChapterSavePath(chapter.chapterIndex); if (ES3.FileExists(path)) ES3.DeleteFile(path); } } _chapterSaves.Clear(); if (ES3.FileExists(VariablesPath)) ES3.DeleteFile(VariablesPath); variables = new StoryVariablesSave(); Debug.Log("Cleared all story saves (chapters + global variables)."); } } }