From f4722cdf64e404ff1c460abeb39832e291c59b9f Mon Sep 17 00:00:00 2001 From: Courier Date: Tue, 13 Oct 2026 16:09:56 +0000 Subject: [PATCH] docs: refresh save-format section against current validation/migration behavior (issue #416) - v1 saves are migrated in place, not reset; future/0 versions fail the load - migration bullet lists what migrate_v1_to_v2() actually writes - persisted key list now includes colony_stance, reserved_resources, active_rewards, milestone fields, and migration_log, and points to validate_save_schema() as the source of truth --- docs/DESIGN.md | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 7d5386d..6895de4 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -46,7 +46,7 @@ The world grid is dynamically generated at runtime — `build_world()` creates a `game_state.gd` exposes `save_game()`, `load_game()`, `save_settings()`, `load_settings()`, and `clear_game()`. Desktop builds write JSON to `user://windowstead.save` and `user://windowstead.settings`. Web builds use `localStorage` via `JavaScriptBridge`. -Save format is a single JSON dictionary with keys: `tick`, `harvested`, `resources`, `priority_order`, `dock_anchor`, `workers`, `tiles`, `builds`, `next_build_id`, `events`, `active_goal`, `completed_goal_ids`, `save_version`. +Save format is a single JSON dictionary. `validate_save_schema()` in `scripts/game_state.gd` is the source of truth for the validated fields. Persisted keys: `tick`, `harvested`, `resources`, `priority_order`, `colony_stance`, `dock_anchor`, `workers`, `tiles`, `builds`, `next_build_id`, `reserved_resources`, `events`, `active_goal`, `completed_goal_ids`, `active_rewards`, `current_milestone_id`, `completed_milestone_ids`, `save_version`, plus `migration_log` on saves upgraded from version 1. ### Grid dimensions @@ -73,6 +73,7 @@ The window is borderless + always-on-top by default. Transparent window mode is "harvested": {"wood": int, "stone": int, "food": int}, "resources": {"wood": int, "stone": int, "food": int}, "priority_order": ["build", "haul", "gather"], + "colony_stance": String, "dock_anchor": "bottom" | "left" | "right", "workers": [ { @@ -82,7 +83,7 @@ The window is borderless + always-on-top by default. Transparent window mode is "carrying": {"": int}, "task": {"kind": String, "target": {"x": int, "y": int}, "resource": String, "build_id": int}, "break_ticks": int, - "spawn_tick": int + "spawn_tick": int // optional; set on recruit, backfilled by the v1 → 2 migration } ], "tiles": [ @@ -103,6 +104,16 @@ The window is borderless + always-on-top by default. Transparent window mode is "reward": String // Optional reward label }, "completed_goal_ids": [String], + "active_rewards": [ + {"type": String, "remaining": int, "duration": int, + "label": String, "trickle_ticks": int, "resource": String} // "resource" only on trickle rewards + ], + "current_milestone_id": String, + "completed_milestone_ids": [String], + "reserved_resources": {"": int}, + "migration_log": [ + {"from_version": int, "to_version": int, "step": String} + ], "save_version": int } ``` @@ -129,8 +140,10 @@ Each structure has build costs in wood and stone. Workers must haul resources to ## Save format -- Versioned with `save_version` (currently 2). -- On load, version mismatch triggers a colony reset. +- Versioned with `save_version` (currently 2). A save with no `save_version` key is treated as the current version. +- On load, every save passes through `validate_save_schema()` and then `migrate_save()` (shared by the desktop and web paths). +- Version 1 saves are migrated in place to version 2 by `migrate_v1_to_v2()` and load normally — nothing is reset. +- Future or unknown versions (greater than the current `SAVE_VERSION`) and version 0 are rejected: `migrate_save()` returns an empty dictionary, the load fails with an error message, and the running colony is left untouched. No reset happens on any load path. +- `migrate_v1_to_v2()` writes `migration_log` (appending a step entry) and backfills `spawn_tick` on workers that lack it. The other newer fields (`active_goal`, `completed_goal_ids`, `active_rewards`, `current_milestone_id`, `completed_milestone_ids`, `colony_stance`, `reserved_resources`) are backfilled separately by `ColonySim.ensure_defaults()` after load, not by the migration. - Layout compatibility is checked: tile array size must match current grid, worker/build positions must be in bounds. - Settings are stored separately from game state. -- Save version 1 → 2 migration adds `active_goal`, `completed_goal_ids`, and `spawn_tick` fields.