godot-save-load-systems
Expert blueprint for save/load systems using JSON/binary serialization, PERSIST group pattern, versioning, and migration. Covers player progress, se…
它会碰到什么
这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。
技能内容
NEVER Do
- NEVER save without a version field — When you update your game's data structure, old saves will break. Always include a
"version": "1.0.0"field and implement migration logic. - NEVER use absolute OS paths — Hardcoding
C:/Users/...will break on every other machine. Always use theuser://protocol, which Godot maps to the correct OS-specific app data folder. - NEVER attempt to save Node references directly — Nodes are objects, not raw data. Extract the necessary primitive data (positions, health, levels) into a
DictionaryorResourceinstead. - NEVER forget to close FileAccess handles — Leaving a file open can lead to handle leaks and save-file corruption. In Godot 4, files auto-close when the variable goes out of scope, but explicit
close()is safer for long-running logic. - NEVER use JSON for very large binary data — Storing 10MB of texture data as Base64 in JSON is slow and bloats file size. Use binary
store_var()or separate dedicated asset files. - NEVER trust loaded data without validation — Users can edit save files. Always use
data.get("field", default_value)and validate that numbers are within expected ranges to prevent crashes. - NEVER trigger a save during high-frequency physics or animation updates — A crash mid-write will corrupt the file. Save only on explicit game events like entering a menu, finishing a level, or at a checkpoint.
- NEVER modify a save Dictionary while iterating over its keys — Calling
erase()oradd()inside a loop over the same dictionary causes iteration errors. Usedata.duplicate()to iterate safely. - NEVER store raw passwords or sensitive credentials in unencrypted JSON — If you have sensitive data, use
FileAccess.open_encrypted_with_pass()to secure it. - NEVER use ResourceLoader.load() for massive scenes on the main thread — It causes a visible freeze. Use
ResourceLoader.load_threaded_request()to load levels in the background. - NEVER rely on get_instance_id() for cross-session identification — These IDs are assigned at runtime and change every time the game restarts. Generate your own persistent
StringUUIDs for game objects. - NEVER forget to call duplicate(true) on a loaded Resource stats block — If multiple enemies load the same "goblin_stats.tres", they will all share the same health pool unless duplicated.
- NEVER use the "allow_objects" flag in store_var/get_var for untrusted data — Setting this to
trueallows full object decoding, which is a major security risk for saves downloaded from the web. - NEVER use JSON for data requiring strict type preservation — JSON converts
Vector3to a string or dictionary. For strict data types, usevar_to_bytes()or a binary format. - NEVER leave internal metadata (set_meta) in persistent dictionaries — This unnecessarily inflates save file size. Clean your dictionaries before serialization.
Available Scripts
> MANDATORY: Read the script for the chosen format before writing SaveManager code.
[save_load_patterns.gd](scripts/save_load_patterns.gd)
MANDATORY for JSON / binary / PERSIST collect — patterns default store_var(..., false).
[save_migration_manager.gd](scripts/save_migration_manager.gd)
MANDATORY when any save has a version field that can lag the build.
[save_system_encryption.gd](scripts/save_system_encryption.gd)
MANDATORY before encrypted slots — password from secure storage / user secret, never hardcoded in examples.
[save_integrity_validator.gd](scripts/save_integrity_validator.gd)
Rolling .bak + SHA-256 verify before trusting a slot; fall back to backup on mismatch.
Deep dive (load on demand)
MANDATORY for JSON/PERSIST walkthroughs, binary examples, gotchas, and elite encrypted paths — [references/save-patterns-deep.md](references/save-patterns-deep.md). Do not paste Step 1–3 Autoload tutorials into scenes.
Expert WHY (critical)
> CAUTION: Baseline tutorials used store_var(data, true). Untrusted user:// saves must allow_objects=false — RCE risk on modded/workshop files.
- Vectors in JSON — store
{x,y,z}components; JSON does not round-tripVector3faithfully. - Rolling backup — crash mid-write corrupts primary; copy to
.bakbefore overwrite ([save_integrity_validator.gd](scripts/save_integrity_validator.gd)). - When to save — menu/checkpoint/level complete only — never per physics frame.
Decision Tree: Pick a Persistence Shape
| Need | Format | MANDATORY |
|------|--------|-----------|
| Human-readable, small/medium progress | JSON + version | [save_load_patterns.gd](scripts/save_load_patterns.gd) |
| Type-faithful Variants / larger blobs | Binary store_var with allow_objects=false | same |
| Typed Resource trees / inspector schemas | ResourceSaver / .tres/.res | Peer godot-resource-data-patterns |
| Many scene nodes auto-collect | PERSIST group + save()/load() | [save_load_patterns.gd](scripts/save_load_patterns.gd) |
| Schema evolved | Migrate then load | [save_migration_manager.gd](scripts/save_migration_manager.gd) |
| Anti-tamper / sensitive fields | Encrypted FileAccess | [save_system_encryption.gd](scripts/save_system_encryption.gd) |
Do not paste Step 1–3 JSON Autoload tutorials here — implement from the scripts.
allow_objects Trust Boundary
Default always store_var(data, false) / get_var(false).
| Case | allow_objects | Rule |
|------|-----------------|------|
| Player user:// saves, workshop mods, downloads | false | NEVER true — RCE risk |
| Trusted local only (your own tooling, offline debug fixtures you control) | true only if unavoidable | Document why; never ship as default; prefer Resources / Dictionaries of primitives |
Encrypted elite paths still use false unless the payload is explicitly trusted-local and non-user-editable.
Golden Path (version → migrate → backup → atomic write)
- Version field on every save blob.
- Migrate via [save_migration_manager.gd](scripts/save_migration_manager.gd) when versions differ.
- Backup existing file (
DirAccess.copy_absoluteto.bak) before overwrite. - Write to temp then rename, or write-after-backup; validate open errors.
- Integrity optional:
FileAccess.get_sha256compare; fall back to backup on mismatch. - Paths only
user://— never absolute OS paths. - When to save — menu, checkpoint, level complete — never per physics frame.
Settings may use ConfigFile separately from run-progress JSON/binary.
Reference
> Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing to a peer domain — do not preload the whole lattice.
Official Documentation
- Saving games — Persist group serialization, JSON line format, and the canonical save/load loop this skill builds on.
- File paths in Godot —
user://vsres://mapping across OS app-data folders; never hardcode absolute paths. - Binary serialization API —
store_var/get_varVariant encoding, type fidelity, and whyallow_objectsis unsafe for untrusted saves. - Background loading —
ResourceLoader.load_threaded_requestfor hitch-free level/resource loads after a save restore. - File system — FileAccess/DirAccess workflow for existence checks, backups, and safe overwrite patterns.
- Resources — Resource vs Dictionary persistence,
duplicate(true), and when.tres/.resbeats hand-rolled JSON. - Groups — SceneTree group membership used by the Persist/PERSIST auto-collect pattern.
- FileAccess — Open modes, encrypted-with-pass AES helpers, SHA-256, compression flags, and buffer I/O.
- JSON —
stringify/parse/parse_stringfor human-readable saves and validation of parse errors. - ConfigFile — INI-style settings (
user://settings.cfg) separate from full game-state saves. - ResourceSaver — Persist typed Resources/custom Resource trees when JSON type loss is unacceptable.
- AESContext — Low-level AES block encrypt/decrypt used by custom compressed encrypted save pipelines.
Related Skills
Prerequisites
- godot-project-foundations — ProjectSettings, Autoload registration, and
user://project identity must exist before a SaveManager can own paths. - godot-gdscript-mastery — Typed Dictionaries, Resources, and error-handling patterns for versioned serialize/deserialize code.
- godot-autoload-architecture — SaveManager is almost always an Autoload; use this for singleton ownership, boot order, and scene-change survival.
Complements
- godot-resource-data-patterns — Custom Resource schemas and
.tresworkflows that pair with ResourceSaver instead of flattening everything to JSON. - godot-scene-management — Threaded scene swaps and wipe/rebuild Persist nodes after load without leaking old world state.
- godot-signal-architecture —
game_saved/game_loadedevent buses so UI and systems react without hard-wiring SaveManager. - godot-ui-containers — Settings menus that write ConfigFile/volume keys this skill persists separately from run progress.
- godot-inventory-system — Item stacks and equipment dictionaries are the heaviest Persist payloads; share ID schemes with save migration.
- godot-quest-system — Quest flags/stage IDs must round-trip through versioned saves without breaking journal UI.
- godot-economy-system — Currency wallets and shop unlocks need the same version field and validation as player progress.
Downstream / consumers
- godot-adapt-single-to-multiplayer — Local save patterns become host-authoritative state sync; never trust client-edited JSON in multiplayer.
- godot-monte-carlo-balancer — Use when progression/economy curves stored in saves need simulated balance passes against migration defaults.
- godot-multiplayer-networking — Server-side validation and snapshot formats that replace plaintext
user://saves for competitive modes.
Master
- godot-master — Library router and mirrored module entry; open when discovering which Domain Skill owns persistence vs content systems.
想直接用这个技能?
本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。