extends Node ## Save/load skeleton — version field, file IO, save-between-ticks contract. ## ## Saves only happen between sim ticks (Sim owns the loop). JobRunner mid-toil ## state must round-trip from day one — see docs/architecture.md. ## ## Phase 0: file-IO smoke test only. Phase 3 expands to real entity state. ## Phase 16 closes coverage of every system. const SAVE_VERSION: int = 1 const SAVE_PATH: String = "user://save_slot.json" func write_save() -> bool: # Smoke-test payload. Phase 3 expands this. var payload := { "version": SAVE_VERSION, "sim_tick": Sim.tick, "game_state": GameState.save_dict(), } var f := FileAccess.open(SAVE_PATH, FileAccess.WRITE) if f == null: push_error("SaveSystem.write_save: cannot open %s" % SAVE_PATH) return false f.store_string(JSON.stringify(payload)) return true func read_save() -> Dictionary: if not FileAccess.file_exists(SAVE_PATH): return {} var f := FileAccess.open(SAVE_PATH, FileAccess.READ) if f == null: return {} var raw := f.get_as_text() var parsed: Variant = JSON.parse_string(raw) if typeof(parsed) != TYPE_DICTIONARY: push_error("SaveSystem.read_save: corrupt save") return {} if int(parsed.get("version", 0)) != SAVE_VERSION: push_warning( "SaveSystem.read_save: version mismatch (%s vs %s)" % [parsed.get("version", "?"), SAVE_VERSION] ) return parsed