【免费下载链接】openfootmanager
An open source soccer/football manager game
OpenFootManager 是一款开源足球经理游戏(soccer/football manager),由 Rust + Tauri + React 构建。它的存档系统采用「每个存档一个 SQLite 数据库文件」的设计,配合 6 个版本化迁移、SHA-256 校验和与可自动重建的save_index.json索引,保证老玩家升级不丢档、损坏文件不崩游戏。本文带你完整看懂这套机制背后的设计与实现。
🎯 为什么要"每档一库"?告别 JSON 大杂烩
早期版本的存档方式很简单:单个saves.db文件里,把整个游戏状态序列化成一个 JSON 文本列存起来。问题也很明显:
- 没有结构校验,JSON 一损坏整个存档直接报废;
- 没有校验和,无法判断文件是否被篡改或写坏;
- 没有迁移机制,字段一加,老档就读不出来了。
新设计(见 docs/SAVE_SYSTEM_DESIGN.md)把思路整个翻转:每个存档会话拥有独立的.db文件,内部是清晰的关系型表结构。一个档坏了,只影响一个档;列表页不需要打开任何数据库;升级时靠迁移脚本平滑过渡。
📁 存档目录结构:N 个 .db 文件 + 一份 save_index.json
Linux 下所有存档都放在应用数据目录里,结构一目了然:
~/.local/share/com.openfootmanager/ ├── saves/ │ ├── <uuid1>.db # 存档 1:独立的 SQLite 文件 │ ├── <uuid2>.db # 存档 2 │ └── ... ├── save_index.json # 全部存档的清单(索引) ├── settings.json # 应用设置 ├── databases/ # 用户导入的世界数据库 └── saves.db.migrated # 旧版存档文件(迁移后改名保留)save_index.json是全部存档的"目录页",每条记录包含存档名、经理名、库文件名和 SHA-256 校验和等元数据:
{ "version": 1, "saves": [ { "id": "uuid-1", "name": "John's Career", "manager_name": "John Smith", "db_filename": "uuid-1.db", "checksum": "sha256hex...", "created_at": "2026-03-05T18:00:00Z", "last_played_at": "2026-03-05T19:30:00Z" } ] }这个设计带来一个很实际的收益:列出存档时只读这份小 JSON,完全不打开数据库,存档再多也秒开。索引的读写与重建逻辑集中在 src-tauri/crates/db/src/save_index.rs。
🗂️ 每个存档库里的 12 张核心表
打开任意一个<uuid>.db,你会看到 12 张表(由 src-tauri/crates/db/src/sql/v001_initial_schema.sql 定义):
| 表名 | 存放内容 |
|---|---|
game_meta | 存档元信息:存档名、开始/当前日期、经理 ID 等 |
managers | 经理资料、声望、满意度、生涯数据 |
teams | 球队:财务、战术、训练设置、阵容等 |
players | 球员:能力值、状态、伤病、合同、数据 |
staff | 教练组人员及其能力 |
league/fixtures/standings | 联赛、赛程与积分排名 |
messages/news | 收件箱消息与新闻 |
board_objectives | 董事会目标 |
scouting_assignments | 球探任务 |
值得一提的是混合存储策略:球员能力值、近期状态、生涯记录这类结构复杂的嵌套数据,仍以 JSON 形式存在 TEXT 列里(如players.attributes、teams.form)。核心关系用真正的表格表达,嵌套细节用 JSON 兜底——既保留了查询能力,又避免了过度拆表,是关系型存档里很实用的折中。
🚀 数据库迁移机制:6 个迁移如何保证旧档不断档
每个存档库的表结构由 src-tauri/crates/db/src/migrations.rs 统一管理,基于rusqlite_migration实现,目前共 6 个迁移:
| 版本 | 迁移文件 | 作用 |
|---|---|---|
| V1 | v001_initial_schema.sql | 初始 schema:全部 12 张游戏实体表 |
| V2 | v002_training_groups.sql | 每队训练分组 |
| V3 | v003_alternate_positions.sql | 球员副位置 |
| V4 | v004_natural_position.sql | 球员天然/首选位置 |
| V5 | v005_player_training_focus.sql | 按球员的训练专注度覆盖 |
| V6 | v006_team_match_roles.sql | 球队比赛角色默认值 |
关键保障有三点:
- 打开即迁移:src-tauri/crates/db/src/game_database.rs 中
GameDatabase::open打开任何存档库时都会执行to_latest,老档被读入的瞬间就自动升级到最新结构; - 幂等可重放:迁移已经应用过再执行一遍是空操作,重复读档不会产生副作用(有专门的测试覆盖);
- 版本可校验:
rusqlite_migration会把已应用的迁移数写入 SQLite 的user_version,validate_schema()用它和MIGRATION_COUNT比对,不一致就判定为"Schema version mismatch"。
🔍 校验机制:SHA-256 校验和 + 索引重建自救
保存时算校验和。每次保存(create_save/save_game),src-tauri/crates/db/src/save_manager.rs 会先写完全部实体表,再对整个.db文件计算 SHA-256,把 64 位十六进制摘要写回save_index.json。数据一变,摘要必变——测试里专门验证了"游戏推进 7 天后 checksum 不同"。
索引丢失时自动重建。如果save_index.json不在了,启动流程会扫描saves/目录里的每个.db文件:逐个打开、校验 schema 版本、读取game_meta提取元数据、重算校验和,最后重建并写回索引。
损坏文件不会让游戏崩掉。无法打开、schema 版本不符、或缺少game_meta的文件,会被标记为Invalid { filename, reason },记录 warn 日志并在界面里显示为损坏——其余正常存档照常列出和读取。这就是"每档一库"隔离性的直接回报。
🕰️ 老版本 saves.db 自动迁移:升级不丢档
如果你从使用旧版 JSON 大杂烩存档的时代升级过来,src-tauri/crates/db/src/legacy_migration.rs 会在启动时接管:
- 检测应用数据目录里是否存在
saves.db; - 打开旧库,按最近游玩时间倒序取出全部存档行(
id / name / manager_name / game_data / created_at / last_played_at); - 每行的
game_dataJSON 反序列化成Game,走标准的SaveManager::create_save写入独立的新.db; - 全部处理完成后,把
saves.db改名为saves.db.migrated防止重复迁移,并生成新的save_index.json。
单条存档 JSON 损坏只会把该条标记为Failed(附原因),不阻断其他存档的迁移——坏档隔离,好档照迁。
💾 一次"保存"与"读档"背后的数据流
- 保存:内存中的
Game→ 逐个 upsert 写入 12 张表 → 关闭连接 → 计算.db的 SHA-256 → 更新save_index.json; - 读档:按 id 从索引查到文件名 → 打开对应
.db→ 自动迁移到最新 schema → 逐表读回组装成Game放入内存状态; - 从已有存档开新局:
new_game_from_save会剥掉消息、新闻、球探任务、董事会目标等"局内数据",重置时钟回赛季开始、清空玩家赛季数据与球队赛季财务,保留世界与阵容——相当于"继承班底,重开一局"。
🧭 关键文件导航(想深入源码从这里开始)
- 存档总设计文档:docs/SAVE_SYSTEM_DESIGN.md
- 存档编排(创建/保存/读取/删除):src-tauri/crates/db/src/save_manager.rs
- 索引与校验和:src-tauri/crates/db/src/save_index.rs
- 数据库打开与 schema 校验:src-tauri/crates/db/src/game_database.rs
- 迁移定义(6 个版本):src-tauri/crates/db/src/migrations.rs
- 旧版 saves.db 迁移:src-tauri/crates/db/src/legacy_migration.rs
- 仓库整体架构:docs/ARCHITECTURE.md
小结:OpenFootManager 的存档系统用"每档一库 + 版本化迁移 + SHA-256 校验 + 可重建索引"四件套,把最让人头疼的存档损坏与版本升级问题变成了可预期、可自愈的工程行为。理解了这套设计,你也能把它当作其他桌面游戏做持久层的参考模板。
【免费下载链接】openfootmanager
An open source soccer/football manager game
相关推荐
RealChar数据库设计终极指南:SQLite与Alembic迁移管理详解
RealChar数据库设计终极指南:SQLite与Alembic迁移管理详解 🎙️🤖 RealChar是一个强大的实时AI角色对话平台,让你能够创建、定制并
AI 应用语音大模型实时AI AgentRAG终极存档保护指南:揭秘Zelda64Recomp校验和加密机制
终极存档保护指南:揭秘Zelda64Recomp校验和加密机制 还在担心游戏存档被恶意篡改?Zelda64Recomp通过先进的校验和机制,为你的《塞尔达传说:
游戏开发艾尔登法环存档管理终极指南:一键安全备份与迁移
艾尔登法环存档管理终极指南:一键安全备份与迁移 还在为辛苦打拼的存档突然丢失而心痛吗?每次游戏更新都像在赌博,担心存档损坏?想在不同设备间无缝切换游戏进度?这些
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考