存档重构,游戏内容解锁机制;教程完善(未完成)
This commit is contained in:
@@ -15,6 +15,12 @@ namespace Ichni
|
||||
private const string ChapterStoryKey = "ChapterStory";
|
||||
private const string VariablesKey = "StoryVariables";
|
||||
|
||||
// 每个剧情存档文件都保存自己的 Schema Version;不要把它与歌曲成绩存档的 Version 混用。
|
||||
// 当前项目尚未正式发布,剧情存档统一从 v1 开始;非 v1 的测试存档会被直接重置。
|
||||
// 正式发布后升级 Schema 时,必须用非破坏性迁移替代当前的重置策略。
|
||||
private const string StorySaveSchemaVersionKey = "StorySaveSchemaVersion";
|
||||
private const int CurrentStorySaveSchemaVersion = 1;
|
||||
|
||||
// 已加载章节的内存缓存(chapterIndex -> 章节存档)
|
||||
private readonly Dictionary<string, ChapterStorySave> _chapterSaves =
|
||||
new Dictionary<string, ChapterStorySave>();
|
||||
@@ -28,31 +34,67 @@ namespace Ichni
|
||||
private static string VariablesPath =>
|
||||
Application.persistentDataPath + "/StorySaves/StoryVariables.json";
|
||||
|
||||
/// <summary>
|
||||
/// 补齐章节存档的可空集合,并以文件名对应的 chapterIndex 作为唯一归属。
|
||||
/// 当前用于保证新建 v1 存档的运行时集合非空;未来迁移逻辑应单独实现,不应依赖此方法隐式转换。
|
||||
/// </summary>
|
||||
private static ChapterStorySave NormalizeChapterSave(ChapterStorySave save, string chapterIndex)
|
||||
{
|
||||
save ??= new ChapterStorySave();
|
||||
save.chapterIndex = chapterIndex;
|
||||
save.completedBlockIds ??= new List<string>();
|
||||
save.selectedChoices ??= new Dictionary<string, int>();
|
||||
return save;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 补齐全局剧情变量字典,保证新建 v1 存档可被 Yarn 变量访问。
|
||||
/// </summary>
|
||||
private static StoryVariablesSave NormalizeVariables(StoryVariablesSave storyVariables)
|
||||
{
|
||||
storyVariables ??= new StoryVariablesSave();
|
||||
storyVariables.floatVariables ??= new Dictionary<string, float>();
|
||||
storyVariables.stringVariables ??= new Dictionary<string, string>();
|
||||
storyVariables.boolVariables ??= new Dictionary<string, bool>();
|
||||
return storyVariables;
|
||||
}
|
||||
|
||||
// ── 故事树 + 选项(按章节)────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// 判断某章节是否尚无存档(首次进入)。
|
||||
/// 判断某章节是否尚无可用的 v1 存档(首次进入或旧测试存档待重置)。
|
||||
/// </summary>
|
||||
public bool IsNewChapter(string chapterIndex) =>
|
||||
!ES3.FileExists(GetChapterSavePath(chapterIndex));
|
||||
public bool IsNewChapter(string chapterIndex)
|
||||
{
|
||||
string path = GetChapterSavePath(chapterIndex);
|
||||
return !ES3.FileExists(path) || !ES3.KeyExists(ChapterStoryKey, path) ||
|
||||
!ES3.KeyExists(StorySaveSchemaVersionKey, path) ||
|
||||
ES3.Load<int>(StorySaveSchemaVersionKey, path) != CurrentStorySaveSchemaVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载指定章节的存档容器;无存档时返回一个新的空容器。加载结果会写入内存缓存。
|
||||
/// 加载指定章节的 v1 存档容器;无存档或非 v1 的预发布测试存档会直接重置为空容器。
|
||||
/// 加载结果会写入内存缓存。
|
||||
/// </summary>
|
||||
public ChapterStorySave LoadChapter(string chapterIndex)
|
||||
{
|
||||
string path = GetChapterSavePath(chapterIndex);
|
||||
bool hasExistingFile = ES3.FileExists(path);
|
||||
int loadedSchemaVersion = hasExistingFile && ES3.KeyExists(StorySaveSchemaVersionKey, path)
|
||||
? ES3.Load<int>(StorySaveSchemaVersionKey, path)
|
||||
: 0;
|
||||
|
||||
ChapterStorySave save;
|
||||
if (ES3.FileExists(path) && ES3.KeyExists(ChapterStoryKey, path))
|
||||
if (hasExistingFile && loadedSchemaVersion != CurrentStorySaveSchemaVersion)
|
||||
{
|
||||
save = ES3.Load<ChapterStorySave>(ChapterStoryKey, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
save = new ChapterStorySave { chapterIndex = chapterIndex };
|
||||
Debug.LogWarning($"Resetting pre-release chapter story save '{chapterIndex}' from schema v{loadedSchemaVersion} to v{CurrentStorySaveSchemaVersion}.");
|
||||
ES3.DeleteFile(path);
|
||||
hasExistingFile = false;
|
||||
}
|
||||
|
||||
ChapterStorySave save = hasExistingFile && ES3.KeyExists(ChapterStoryKey, path)
|
||||
? ES3.Load<ChapterStorySave>(ChapterStoryKey, path)
|
||||
: new ChapterStorySave();
|
||||
save = NormalizeChapterSave(save, chapterIndex);
|
||||
_chapterSaves[chapterIndex] = save;
|
||||
return save;
|
||||
}
|
||||
@@ -62,8 +104,17 @@ namespace Ichni
|
||||
/// </summary>
|
||||
public void SaveChapter(ChapterStorySave save)
|
||||
{
|
||||
if (save == null || string.IsNullOrEmpty(save.chapterIndex))
|
||||
{
|
||||
Debug.LogWarning("Cannot save a chapter story record without a chapterIndex.");
|
||||
return;
|
||||
}
|
||||
|
||||
save = NormalizeChapterSave(save, save.chapterIndex);
|
||||
_chapterSaves[save.chapterIndex] = save;
|
||||
ES3.Save(ChapterStoryKey, save, GetChapterSavePath(save.chapterIndex));
|
||||
string path = GetChapterSavePath(save.chapterIndex);
|
||||
ES3.Save(ChapterStoryKey, save, path);
|
||||
ES3.Save(StorySaveSchemaVersionKey, CurrentStorySaveSchemaVersion, path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,14 +152,22 @@ namespace Ichni
|
||||
/// </summary>
|
||||
public void LoadVariables()
|
||||
{
|
||||
if (ES3.FileExists(VariablesPath) && ES3.KeyExists(VariablesKey, VariablesPath))
|
||||
bool hasExistingFile = ES3.FileExists(VariablesPath);
|
||||
int loadedSchemaVersion = hasExistingFile && ES3.KeyExists(StorySaveSchemaVersionKey, VariablesPath)
|
||||
? ES3.Load<int>(StorySaveSchemaVersionKey, VariablesPath)
|
||||
: 0;
|
||||
|
||||
if (hasExistingFile && loadedSchemaVersion != CurrentStorySaveSchemaVersion)
|
||||
{
|
||||
variables = ES3.Load<StoryVariablesSave>(VariablesKey, VariablesPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
variables = new StoryVariablesSave();
|
||||
Debug.LogWarning($"Resetting pre-release global story variables from schema v{loadedSchemaVersion} to v{CurrentStorySaveSchemaVersion}.");
|
||||
ES3.DeleteFile(VariablesPath);
|
||||
hasExistingFile = false;
|
||||
}
|
||||
|
||||
variables = hasExistingFile && ES3.KeyExists(VariablesKey, VariablesPath)
|
||||
? ES3.Load<StoryVariablesSave>(VariablesKey, VariablesPath)
|
||||
: new StoryVariablesSave();
|
||||
variables = NormalizeVariables(variables);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -116,7 +175,9 @@ namespace Ichni
|
||||
/// </summary>
|
||||
public void SaveVariables()
|
||||
{
|
||||
variables = NormalizeVariables(variables);
|
||||
ES3.Save(VariablesKey, variables, VariablesPath);
|
||||
ES3.Save(StorySaveSchemaVersionKey, CurrentStorySaveSchemaVersion, VariablesPath);
|
||||
}
|
||||
|
||||
// ── 清档 ────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user