using System;
using System.Collections.Generic;
using AibisDream.FixSystem;
using Newtonsoft.Json;
namespace AibisDream.SaveSystem
{
///
/// 当前快照 schema 的版本号。结构变更时递增。
///
public static class SaveSnapshotSchema
{
public const int CurrentVersion = 2;
}
///
/// 存档快照根对象:描述「进入可存节点那一刻」的完整游戏状态。
///
/// 与槽位/文件路径解耦;序列化后写入 JSON。对应需求§3 四分类:
/// anchor(恢复锚点)、sections(表现类 + 维修子模块)、yarnVariables。
///
///
/// 宏观阶段(场景 / 章节 SO / YarnProject)不单独冗余存储,统一以 sections["scene"] / sections["macro"]
/// 为唯一来源;槽位 UI 等需要摘要时通过 现算派生,避免重复字段漂移。
///
///
[Serializable]
public class SaveSnapshot
{
/// 快照结构版本,对应 。
public int schemaVersion = SaveSnapshotSchema.CurrentVersion;
/// 保存时的 Application.version。
public string gameVersion;
/// 保存时间(本地),格式 yyyy-MM-dd HH:mm:ss。
public string savedAt;
/// 当前场景(恢复的第一步)。
public SceneSnapshotDto scene = new();
/// 恢复锚点:章节、YarnProject、来源节点与显式恢复动作。
public AnchorSnapshot anchor = new();
/// 全部 Yarn 运行时变量(来自 )。
public YarnVariablesSnapshot yarnVariables = new();
///
/// 各子系统快照,key 为 中的稳定 id。
/// 表现层与维修模块(含 BlockPuzzle / Memory 等)均在此注册,按 RestoreOrder 还原。
///
public Dictionary sections = new();
}
///
/// 恢复锚点:节点名始终记录存档来源;是否重新进入节点由
/// 独立决定。
///
[Serializable]
public class AnchorSnapshot
{
/// 当前章节 TalkSceneSO 名称,由读档预检解析为目标章节。
public string sceneSoName;
public string yarnProjectId;
public string nodeName;
[JsonProperty(Required = Required.Always)]
public bool startDialogueOnRestore;
}
/// Yarn 变量三分组,与 Yarn Spinner 支持的类型一致。
[Serializable]
public class YarnVariablesSnapshot
{
public Dictionary floats = new();
public Dictionary strings = new();
public Dictionary bools = new();
}
#region Provider DTOs
/// sections["scene"]:当前加载的场景。
[Serializable]
public class SceneSnapshotDto
{
public string sceneName;
}
/// sections["env"]:环境时间/天气。
[Serializable]
public class EnvironmentSnapshotDto
{
/// 枚举名。
public string curTime;
/// 枚举名。
public string curWeather;
public bool isInitialized;
}
/// sections["actor"]:场景中所有角色的逐项状态。
[Serializable]
public class ActorSnapshotDto
{
public List actors = new();
}
/// 单个角色的快照条目。
[Serializable]
public class ActorEntrySnapshotDto
{
public string actorName;
public string slotName;
public string actorType;
public string stateName;
/// Anima:Animator layer 0 当前状态的 normalizedTime。
public float stateNormalizedTime;
public float alpha;
/// AnimaEx:最后一次 set_actor_face 的表情名。
public string faceName;
/// AnimaEx:Animator "Is Talking" 参数。
public bool isTalking;
}
///
/// sections["audio"]:FMOD 音乐/SFX 终态、AMB 状态与 Yarn 全局参数 finalValue
/// (不记 Event 播放进度)。
///
[Serializable]
public class AudioSnapshotDto
{
/// key → FMOD event path。
public Dictionary musicPaths = new();
public Dictionary sfxPaths = new();
/// 枚举名。
public string ambState;
/// 由 Yarn set_global_param 修改过的参数名 → 捕获时的 FMOD finalValue。
public Dictionary yarnGlobalParameters = new();
}
///
/// Timeline 终/初态标记(决策 D1.1:不按时间轴逐帧还原)。
/// 序列化进 JSON 时使用字符串形式存入 。
///
public enum TimelinePlaybackPhase
{
AtStart,
AtEnd,
/// 从未 Evaluate 过 Timeline 绑定(untouched);非播放中途 Stop。
Stopped
}
/// sections["timeline"]:各 PlayableDirector 的终/初态。
[Serializable]
public class TimelineSnapshotDto
{
public List entries = new();
}
[Serializable]
public class TimelineEntrySnapshotDto
{
public string directorName;
public bool isActive;
/// 的字符串名。
public string phase;
/// 若由 Addressables 加载 Timeline,记录 key;否则为空。
public string loadedAddressableKey;
/// 是否曾通过 Play/Reset/RestoreAtEnd 等路径 Evaluate 过 Timeline。
public bool hasEverAppliedPlayback;
}
/// sections["screen"]:屏幕饱和度与演出淡入淡出遮罩。
[Serializable]
public class ScreenSnapshotDto
{
/// Post-process Volume weight(0=正常,1=完全褪色)。
public float saturationWeight;
///
/// 全局遮罩终态:true = 画面被完全盖住;
/// false = 画面可见(FadeOut 完成或遮罩未启用)。不记录转场中间 alpha。
///
public bool isFadeScreenCovered;
}
/// sections["playTool"]:常驻演出 UI 中的物品图与全屏图终态。
[Serializable]
public class PlayToolSnapshotDto
{
public bool isObjVisible;
public string objPicName;
public bool objIsLocalized;
public bool isFullScreenVisible;
public string fullScreenPicName;
public bool fullScreenIsLocalized;
}
public enum ShowcaseDisplayMode
{
None,
Small,
Large
}
/// sections["showcase"]:梦境通用静态图片与背景终态。
[Serializable]
public class ShowcaseSnapshotDto
{
public string displayMode;
public string picName;
public bool isBackgroundVisible;
}
public enum Day2SleepPresentationMode
{
None,
SmallMotion,
Kite,
LargeEffects
}
/// sections["day2SleepPresentation"]:D2 Sleep 动态表现语义终态。
[Serializable]
public class Day2SleepPresentationSnapshotDto
{
public string mode;
public string picName;
public string motionProfile;
public float kiteHeight;
public int kiteWind;
public float kiteTurbulence;
public bool largeAnimationActive;
public string largeAnimationPrefix;
public int largeAnimationFrameCount;
public float largeAnimationSecondsPerFrame;
public float largeBlurAmount;
public float largeBlurSize;
public float largeScaleMultiplier = 1f;
public float largeAlpha = 1f;
}
/// sections["subway"]:地铁场景宏观状态(SubwayCenter / OutSideState)。
[Serializable]
public class SubwaySnapshotDto
{
/// 枚举名。
public string state;
/// 状态参数(预留,当前各 State 未使用)。
public string args;
/// 当前新闻图片 Addressable id(Sprite/News[{id}] 中的 id)。
public string newsSpriteId;
}
/// sections["fix"]:Fix 场景宏观 Cue(FixSceneDirector),不含面板壳层。
[Serializable]
public class FixSnapshotDto
{
/// 枚举名。
public string state;
/// 状态参数(如 BodyModule 的 ModuleState 字符串)。
public string args;
}
/// TaskPanel 单条任务条目快照。
[Serializable]
public class TaskEntrySnapshotDto
{
/// Yarn 行 id,如 line:01dade5。
public string lineId;
/// 存档时已完成 substitutions 的本地化文本,不含 UI 圆点前缀。
public string text;
}
/// sections["fixPanel"]:FixPanel 壳层 + 线缆/插头 + TaskPanel 状态。
[Serializable]
public class FixPanelSnapshotDto
{
public bool isSystemOn;
/// 当前目标灯态;旧存档缺失时按 Normal 处理。
public string lightState;
/// RepairSystemManager 当前激活系统类型名;空则默认 BodyModuleSystem。
public string currentRepairSystemType;
public bool isCableRetracted;
/// 插头插入的 BodyModule 名(data.moduleName);null/空 = 未插入。
public string pluggedModuleName;
/// 剧情是否要求 TaskPanel 展开;Memory 等临时隐藏状态不写入存档。
public bool isTaskPanelRequestedVisible;
/// TaskPanel 当前未完成任务列表(保持插入顺序)。
public List tasks = new();
}
/// sections["bodyModule"]:插线模块持久物理状态。
[Serializable]
public class BodyModuleSnapshotDto
{
/// 枚举名(Body / Head)。
public string moduleState;
public bool isUFCoverRemoved;
public bool isUFRemoved;
public bool isColorRemoved;
public bool isChipRemoved;
/// 高亮中的模块名(data.moduleName)。
public List highlightedModules = new();
/// 报警中的模块名(data.moduleName)。
public List alarmedModules = new();
/// 模块名 → 枚举名;旧存档缺失时按 Normal 处理。
public Dictionary moduleConditions = new();
}
/// sections["eye"]:Eye 维修叙事阶段。
[Serializable]
public class EyeSnapshotDto
{
/// Eye 颜色阶段枚举名。
public string eyeColorState;
}
/// sections["punchTape"]:打孔带收藏列表。
[Serializable]
public class PunchTapeSnapshotDto
{
public List favorites = new();
}
#endregion
///
/// 从 根对象直接读取的宏观摘要(场景 / 章节 SO / YarnProject)。
///
/// scene 与 anchor 已提升到根对象,无需再从 sections 字典派生。
/// 槽位 / 「继续游戏」等 UI 在需要展示时调用 即可。
///
///
public readonly struct SaveSnapshotSummary
{
/// Addressable 场景 key(来自 )。
public readonly string SceneName;
/// 当前 TalkSceneSO 的 asset 名称(来自 )。
public readonly string SceneSoName;
/// 当前 YarnProject 的 name(来自 )。
public readonly string YarnProjectId;
public SaveSnapshotSummary(string sceneName, string sceneSoName, string yarnProjectId)
{
SceneName = sceneName;
SceneSoName = sceneSoName;
YarnProjectId = yarnProjectId;
}
/// 从快照根对象直接读取宏观摘要。
public static SaveSnapshotSummary From(SaveSnapshot snapshot)
{
if (snapshot == null)
{
return new SaveSnapshotSummary(null, null, null);
}
var sceneName = snapshot.scene?.sceneName;
var sceneSoName = snapshot.anchor?.sceneSoName;
var yarnProjectId = snapshot.anchor?.yarnProjectId;
return new SaveSnapshotSummary(sceneName, sceneSoName, yarnProjectId);
}
}
}