SuperAPI AI 工具集

save-load

编程与开发

查看项目

更新于 10-16 09:06

技能介绍

用途

Godot 4.3+ 存档/读档系统实现辅助技能,帮助开发者针对不同数据类型选择正确的序列化策略。所有示例均面向 Godot 4.3+,不使用已废弃 API。

相关技能:resource-pattern(自定义 Resource 数据容器)、inventory-system(背包序列化模式)、godot-project-setup(SaveManager autoload 设置)、popochiu(冒险框架存档)。

策略对比

策略 最适合 可读性 编辑器支持 备注
ConfigFile 设置、简单键值数据 是 否 内置 INI 风格,无额外依赖
JSON 游戏存档、灵活结构 是 否 跨平台,可做版本迁移
Resource .tres 编辑器集成的数据 是 是 不安全——绝不加载不可信文件
Resource .res 快速二进制数据 否 是 不安全——绝不加载不可信文件

推荐策略时应指出被排除的方案及其决定因素,例如“选 JSON 而非 Resource 文件,因为存档由用户可写,而加载 Resource 会执行代码”。未指明替代方案的选择无法被推翻。

安全警告:加载 .tres 或 .res 文件会执行资源中内嵌的任意 GDScript。绝不从不可信来源(用户上传文件、下载的模组)加载 Resource 文件。用户生成的存档数据应使用 ConfigFile 或 JSON。

ConfigFile —— 设置

ConfigFile 写入 INI 风格的分节,适合音频/视频/控制设置(体积小、便于设计师调试)。使用 set_value(section, key, value) 后 save(path);用 load(path) 和 get_value(section, key, default) 读取。完整 GDScript + C# 设置存读及典型设置菜单接线见 references/configfile.md。

JSON —— 游戏存档

用 JSON.stringify(dict) 序列化,JSON.parse_string(text) 反序列化,通过 FileAccess 读写。适合需要人类可读文件的游戏存档。构建一个捕获全部游戏状态的 Dictionary(玩家位置、背包、世界标记),序列化后写入 user://save_<slot>.json。完整 GDScript + C# 实现(含 FileAccess 封装与错误处理)见 references/json-saves.md。

Godot 4.7 变更:JSON.stringify(data, indent = "", sort_keys = true, full_precision = false) 现在即使传入 indent,也会将空 Dictionary 紧凑序列化为 {}(GH-115883)。升级后,带 indent 写出的存档中空字典字段格式会变化——任何逐字节 diff 或哈希存档输出的逻辑必须容忍新格式。解析不受影响。

存档架构模式

对较大的游戏,为每个持久化节点附加 SaveableComponent。每个组件声明 save_callable 与 load_callable。存档管理器按 ID 遍历组件,调用各自的 save 可调用对象,构建主 Dictionary。完整的 SaveableComponent + 存档管理器实现见 references/save-architecture.md。

存档文件位置

user:// 解析为项目文件夹之外、平台特定的可写目录。

平台 路径
Windows %APPDATA%\Godot\app_userdata<project-name>\
macOS ~/Library/Application Support/Godot/app_userdata/<project-name>/
Linux ~/.local/share/godot/app_userdata/<project-name>/

存档数据始终使用 user://,绝不使用 res://。导出构建中 res:// 路径为只读。

版本迁移

存档文件的生命周期长于写入它的 schema。始终在存档 Dictionary 顶部包含 "version": <int>;加载时按版本 switch,将旧存档增量向前迁移(v1 → v2 → v3 → 当前)。绝不破坏旧存档,始终迁移。完整迁移助手模式见 references/version-migration.md。

实现检查清单

  • 设置用 ConfigFile,游戏存档用 JSON(不用 Resource)
  • 每个存档文件包含 version 整数字段
  • 存档路径使用 user://,绝不使用 res://
  • 写入存档前调用 DirAccess.make_dir_recursive_absolute()
  • Vector2/Vector3 序列化为独立的 x/y/z 浮点数(JSON 无 Vector 类型)
  • 所有文件操作检查返回码,失败时调用 push_error()
  • _migrate() 处理从 0 到当前的所有版本,增量应用
  • 玩家可控的存档数据绝不使用 Resource 文件(.tres/.res)
  • 提供 get_save_slots() 与 delete_save() 辅助函数用于 UI 槽位管理
  • 可存档节点使用会话间不变动的稳定 ID