using System.Collections.Generic; namespace Ichni.RhythmGame { /// /// 单首歌曲的持久化容器。 /// 表示玩家曾确认进入过该歌曲; 只表示玩家曾完成过一次有效结算。 /// Story SongBlock 使用 isTried,而具体难度的成绩、Revision 与 Max Combo /// 由 中对应稳定难度 ID 的 管理。 /// public class SongStatusSave { /// /// 玩家是否曾确认进入过本曲的 GameScene。 /// 该字段不代表结算成功,也不要求存在判定;它让 Story SongBlock 能在切场景、退出游戏或重新打开章节后, /// 通过持久化的歌曲记录稳定恢复“已尝试”状态。 /// public bool isTried; /// 至少有一次有效结算完成;谱面 Revision 变化不会回退该流程状态。 public bool isCompleted; /// 预留的歌曲级扩展字段;赋予新语义前须评估 Schema Version 是否需要递增。 public string additionalInfo; /// /// 以 DifficultyData.saveDifficultyId 为 Key 的谱面成绩。 /// Key 不依赖选曲列表位置,因此重排、隐藏或删除中间难度不会让其他难度的成绩错位。 /// 被内容定义移除的 Key 暂时保留在存档中,但 UI 与章节完成度只读取当前仍存在的难度。 /// public Dictionary beatmapSavesByDifficultyId = new(); public SongStatusSave() { } public SongStatusSave(bool isCompleted, string additionalInfo, Dictionary beatmapSavesByDifficultyId) { // 已拥有有效结算的歌曲必然也已尝试,避免两个状态出现矛盾。 isTried = isCompleted; this.isCompleted = isCompleted; this.additionalInfo = additionalInfo; this.beatmapSavesByDifficultyId = beatmapSavesByDifficultyId; } /// 只读查询当前定义的难度成绩;不会因 UI 展示而创建新的存档记录。 public bool TryGetBeatmapSave(int saveDifficultyId, out BeatmapSave beatmapSave) { beatmapSave = null; return saveDifficultyId >= 0 && beatmapSavesByDifficultyId != null && beatmapSavesByDifficultyId.TryGetValue(saveDifficultyId, out beatmapSave) && beatmapSave != null; } /// /// 获取或创建指定稳定难度 ID 的成绩容器。 /// 仅存档写入/内容对账可调用此方法;选曲 UI 应使用 。 /// public BeatmapSave GetOrCreateBeatmapSave(int saveDifficultyId) { if (saveDifficultyId < 0) { return null; } beatmapSavesByDifficultyId ??= new Dictionary(); if (!beatmapSavesByDifficultyId.TryGetValue(saveDifficultyId, out BeatmapSave beatmapSave) || beatmapSave == null) { beatmapSave = new BeatmapSave(0f, false, false); beatmapSavesByDifficultyId[saveDifficultyId] = beatmapSave; } return beatmapSave; } } }