# 09 存档与后端 本文档定义新项目的存档模型与后端接口。目标:稳定、可迁移、可扩展、可观测。即使是单机为主,也建议提供云端存档能力以支持跨设备与版本兼容。 ## 9.1 存档设计目标 - 数据完整:可恢复到任意一个确定状态 - 可迁移:版本升级可做增量迁移 - 可校验:避免异常/作弊数据导致崩档 - 可压缩:存档体积可控,读写快速 ## 9.2 存档分层与结构 存档建议由三部分组成: - `meta`:版本、时间戳、校验、内容包版本 - `player`:玩家状态与资产 - `world`:世界状态(时间、地点资源、灾害、标记) ```json { "meta": { "saveVersion": 3, "contentVersion": {"base": "1.0.0", "packs": {"event_pack_01": "1.0.0"}}, "createdAt": 1730000000000, "updatedAt": 1730001234000, "checksum": "sha256:..." }, "player": { "name": "Player", "placeId": "home", "stats": {"life": 80, "hunger": 40, "thirst": 60, "energy": 30, "san": 50, "radiation": 10}, "attributes": {"str": 4, "agi": 5, "int": 6, "per": 5, "luck": 3}, "inventory": [{"itemId": "water_purified", "count": 2, "durability": null}], "equipment": {"weapon": "knife_01", "body": "jacket_01"}, "buffs": [{"buffId": "infection_1", "startedAt": 1730000500000, "stacks": 1}], "quests": {"active": ["q_main_01"], "completed": ["q_tutorial_01"]} }, "world": { "time": {"baseTime": 0, "minutesFromStart": 1234}, "flags": {"met_trader": true}, "places": { "ruins_store": { "heat": 3, "resourceStock": {"water_dirty": 0, "scrap_metal": 2}, "lastRefreshAt": 1730001200000 } }, "disaster": {"activeId": "sandstorm", "endsAt": 1730003000000} } } ``` ## 9.3 存档写入策略 - 自动存档触发点(建议): - 回到基地 - 完成任务步骤 - 战斗结束 - 灾害开始/结束 - 重要事件选择后 - 快速保存: - UI 提供手动保存按钮 - 保存期间不阻塞主线程(使用异步/worker) - 防止坏档: - 写入采用“双缓冲”:先写临时,再替换正式 - 写入失败保留上一份 ## 9.4 存档校验与迁移 ### 9.4.1 校验(客户端与服务端) - Schema 校验:字段类型、必填字段、范围 - 引用校验:itemId/placeId/questId 必须存在于内容库 - 数值校验:状态上下限、背包容量、堆叠上限 ### 9.4.2 迁移(SaveVersion) - 每次内容/结构变化提升 `saveVersion` - 迁移必须是纯函数:`migrate(save_vN) -> save_vN+1` - 迁移记录: - 变更点 - 默认值策略 - 兼容策略(删字段/改名/拆分) ## 9.5 后端能力范围(建议) 后端建议至少提供: - 账号与鉴权(匿名账号也可) - 云端存档 CRUD - 内容包版本与更新清单(可选) - 运行日志/错误上报(可选) ## 9.6 API 约定(REST 示例) ### 9.6.1 鉴权 - 登录(匿名/设备绑定): - `POST /api/v1/auth/anonymous` - 返回 `accessToken/refreshToken` - 请求头: - `Authorization: Bearer ` ### 9.6.2 存档接口 - 列表: - `GET /api/v1/saves` - 读取: - `GET /api/v1/saves/{slotId}` - 写入(覆盖): - `PUT /api/v1/saves/{slotId}` - Body:完整存档 JSON - 服务端校验通过后写入 - 删除: - `DELETE /api/v1/saves/{slotId}` ### 9.6.3 并发与冲突 使用乐观锁: - 存档 meta 带 `etag` 或 `rev` - 更新时带 `If-Match: ` - 冲突返回 409,客户端提示“本地与云端不一致” ## 9.7 速率限制与滥用防护 - 写入频率限制:例如每分钟最多 10 次 - 存档大小限制:例如 1MB - 结构化错误码,避免泄漏服务端信息 ## 9.8 旧版 PHP 存档参考(当前仓库) 当前仓库包含简单的 PHP+MySQL 存档端点: - [save.php](file:///Users/virtheart/Documents/CloneProjects/TinyWaste/save.php):按 `key/data/overwrite` 写入 `record(key,data)`,并校验 `data` 是 JSON - [load.php](file:///Users/virtheart/Documents/CloneProjects/TinyWaste/load.php):按 `key` 读取 新项目不建议继续沿用 SAE 环境变量模式与弱协议,建议升级为标准鉴权、版本控制与迁移机制。 ```mermaid sequenceDiagram participant C as Client participant API as Save API participant DB as Database C->>API: PUT /saves/{slotId} (save, If-Match) API->>API: 校验Schema/引用/数值 API->>DB: 写入(事务) DB-->>API: ok API-->>C: 200 (new etag) ``` 对应源文件:[save-flow.mmd](./diagrams/save-flow.mmd)