Files
aibis-dream/Assets/Scripts/SaveSystem/README.md
T

149 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SaveSystem 存档快照层
> P1 实现:纯数据快照 + 逐项还原。设计文档见 [`Docs/存档系统设计方案.md`](../../../Docs/存档系统设计方案.md)**§4.1 / D6** 描述读档编排终态)。
## 职责边界
| 模块 | 位置 | 做什么 |
| --- | --- | --- |
| Yarn 变量 | `Game Loop/YarnVariableStorage.cs` | 运行时 `$` / `$global_` 读写 |
| **本目录** | `SaveSystem/` | 快照结构、捕获/还原、落盘、流程编排 |
| 深度维修(旧) | `DeepRepairDataRegistry.cs` | FixSystem 等 IDataP5 前临时保留 |
| 槽位 / 截图 | P2 待做 | 接管 `SnapshotPersistence` 与目录布局 |
**不要**再往 `YarnVariableStorage` 上堆存档逻辑。
## 对外入口
```csharp
// 存盘(<<auto_save>>、调试)
SaveRestoreOrchestrator.SaveToTestPath();
// 读盘
yield return SaveRestoreOrchestrator.RestoreFromFile(path);
// 仅内存快照(P2 手动档固化等)
var snap = SnapshotService.Capture();
yield return SnapshotService.Restore(snap);
// Yarn 变量(与存档无关)
YarnVariableStorage.Instance.SetValue("$foo", 1f);
```
P1 测试落盘路径:`persistentDataPath/AllOurBrokenParts/snapshot_test/latest_snapshot.json`
## 目录结构
```
SaveSystem/
├── README.md ← 本文件
├── ISnapshotProvider.cs 契约:Capture / RestoreP1 临时形态,见下)
├── SaveSnapshot.cs 快照根对象 + 各 section DTO
├── SnapshotProviderIds.cs section 稳定 id"actor" 等)
├── SnapshotRegistry.cs provider 注册表
├── SnapshotBootstrap.cs 启动时注册 7 个 provider
├── SnapshotCapture.cs 组装 SaveSnapshot
├── SnapshotRestore.cs 写回运行时 + 锚点重进节点
├── SnapshotService.cs Capture / Restore 对外 API
├── SnapshotPersistence.cs 文件读写、旧档检测
├── SnapshotSerializer.cs JSON + schemaVersion
├── SnapshotSectionDeserializer.cs JObject → 强类型 DTO
├── SaveRestoreOrchestrator.cs UI + 落盘 + 读盘编排
├── DeepRepairSnapshot.cs 深度维修占位(P5)
├── DeepRepairDataRegistry.cs 旧 IData 容器(P5 前)
├── ScreenSnapshotHelper.cs screen section 实现细节
└── Providers/ 各子系统薄适配层
├── SceneSnapshotProvider.cs order 10
├── EnvironmentSnapshotProvider.cs order 20
├── MacroSnapshotProvider.cs order 30
├── ActorSnapshotProvider.cs order 40
├── AudioSnapshotProvider.cs order 50
├── TimelineSnapshotProvider.cs order 60
└── ScreenSnapshotProvider.cs order 70
```
## 存盘 / 读盘流程
```
存盘:
SaveRestoreOrchestrator
→ SnapshotService.Capture()
→ SnapshotCapture(锚点 + Yarn 变量 + 各 Provider
→ SnapshotPersistence.Save()
读盘:
SaveRestoreOrchestrator
→ SnapshotPersistence.Load() (或 legacy 分支)
→ SnapshotService.Restore()
→ SnapshotRestore(见「读档还原编排」)
```
## 读档还原编排(终态 vs P1 代码)
> **勿将当前代码当作终态。** P1 中 `ISnapshotProvider.Restore` 统一返回 `IEnumerator``SnapshotRestore` 对每个 Provider 做 `yield return`——这是受旧 `IData.Load()` 影响的**临时 scaffolding**。终态见设计文档 **§4.1 / D6**P4 实施前应 refactor。
### 终态:Phase + Barrier
读档不是「每个 Provider 串行协程链」,而是分阶段推进,仅在**必须等待**的边界上 `yield`
```
Phase 0 Yarn 变量(sync
Phase 1 场景加载(BarrierLoadSceneAsync
Phase 2 macro / env / actor / audio / timeline / screensync 批量,同帧连续调用)
Phase 2 可选 Barrier(如 Timeline Addressable 须显式等待)
Phase 3 RestoreAnchorBarrierStartDialogue
Phase 4 P4:淡入淡出等演出时序
```
- **逐项还原(D1)**指各子系统各自写回状态,**不是** Provider 之间逐步 `yield return`
- **`RestoreOrder`** 表示同 Phase 内的建议顺序或软依赖(scene 先于 env/actor 等),**不是**「每步必须挂协程」。硬依赖用 Phase / Barrier 表达。
### P1 临时形态 vs P4 目标
| | P1(当前) | P4 目标 |
| --- | --- | --- |
| Provider 还原 | 全部 `IEnumerator Restore` | 默认 `void Restore`;仅 scene 等实现显式 async |
| 编排 | `foreach` 逐步 `yield return` | Phase 编排,仅 Barrier 步骤 `yield` |
| Manager | 部分 `IEnumerator RestoreSnapshot``yield break` | 默认 `void`;真有 async 才保留协程 |
### 已知偏离(tech debt
- `DirectorHandler` 在 Addressable Timeline 路径下内部 `StartCoroutine`,Provider 已返回,编排层无法感知——P4 应改为可等待路径。
- P2/P3 新增代码**不要**再复制「全 Provider 协程链」模式。
## 快照 JSON 结构(schemaVersion = 1
| 字段 | 含义 |
| --- | --- |
| `anchor` | 恢复锚点:`nodeName` + `yarnProjectId`(独立阶段重进节点的自洽校验) |
| `yarnVariables` | floats / strings / bools |
| `sections` | key 为 `SnapshotProviderIds`,值为各 DTO**宏观信息(场景/SceneSO/YarnProject)以 `scene`/`macro` 两节为唯一来源** |
| `deepRepair` | P1 通常为空,P5 再填 |
> 宏观阶段摘要不再冗余到顶层;槽位 / 「继续游戏」UI 需要展示场景名、章节、YarnProject 时,调用 `SaveSnapshotSummary.From(snapshot)` 从 `sections` 现算派生。
## 新增一个可存子系统
1.`SaveSnapshot.cs` 增加 DTO 类。
2.`SnapshotProviderIds` 增加稳定 id,并加入 `RequiredForCapture`(若 P1 必须存)。
3. 在对应 Manager 实现 `CaptureSnapshot` / `RestoreSnapshot`**默认 sync `void`**;仅确有 async 加载/状态切换时用 `IEnumerator` 并向编排层上报)。
4. 新建 `Providers/XxxSnapshotProvider.cs` 实现 `ISnapshotProvider`P4 后:sync 默认 + 显式 async 接口)。
5.`SnapshotBootstrap.EnsureInitialized``Register`
6.`SnapshotSectionDeserializer.Coerce` 增加 JObject 转换分支。
**禁止**在 Provider 内私自 `StartCoroutine` 而不纳入编排 Barrier。
## 相关阶段(未在本目录完整实现)
| 阶段 | 内容 |
| --- | --- |
| P2 | 槽位、原子写、截图 sidecar → 扩展 `SnapshotPersistence` |
| P3 | 可存点判定、写盘门控 |
| P4 | 按 §4.1 重写 `SnapshotRestore`Phase + Barrier);refactor Provider 契约;`SaveRestoreOrchestrator` 接入淡入淡出 |
| P5 | `deepRepair` 段、维修模块清单;还原模型单独定案,不默认套用 P1 Provider 协程链 |