-
Notifications
You must be signed in to change notification settings - Fork 0
Persist and re-sync reserved_resources on save/load #241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -716,6 +716,7 @@ func load_or_boot() -> void: | |
| for worker in state.get("workers", []): | ||
| if not worker.has("break_ticks"): | ||
| worker.break_ticks = 0 | ||
| rebuild_reservations() | ||
| apply_priority_order() | ||
| apply_orientation_lock_ui() | ||
|
|
||
|
|
@@ -905,6 +906,7 @@ func load_saved_game() -> void: | |
| for worker in state.get("workers", []): | ||
| if not worker.has("break_ticks"): | ||
| worker.break_ticks = 0 | ||
| rebuild_reservations() | ||
| # Restore active goal state and completed IDs from save | ||
| if state.has("active_goal") and not state["active_goal"].is_empty(): | ||
| active_goal = state["active_goal"] | ||
|
|
@@ -2501,6 +2503,22 @@ func get_reserved(resource: String) -> int: | |
| return 0 | ||
| return int(state.reserved_resources.get(resource, 0)) | ||
|
|
||
| # ── Rebuild reserved_resources from active worker tasks ────────────────────── | ||
| # Called after load to prevent double-booking when reservations are missing or stale. | ||
|
|
||
| func rebuild_reservations() -> void: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Automated finding from AI PR review. |
||
| state["reserved_resources"] = {} | ||
| var workers: Array = state.get("workers", []) | ||
| for worker in workers: | ||
| var task: Dictionary = worker.get("task", {}) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor (style): Local variable 'current' in rebuild_reservations() may shadow a class-level 'current' variable used elsewhere (_process), creating potential confusion despite valid GDScript scoping. Automated finding from AI PR review. |
||
| if task.is_empty(): | ||
| continue | ||
| var kind: String = task.get("kind", "") | ||
| if kind == "gather" or kind == "haul": | ||
| var resource: String = task.get("resource", "") | ||
| if not resource.is_empty(): | ||
| state["reserved_resources"][resource] = state["reserved_resources"].get(resource, 0) + 1 | ||
|
|
||
|
|
||
| # ── Worker intent icons and text (issue #136) ──────────────────────────────── | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,8 @@ func _initialize() -> void: | |
| test_stale_reservations_cleaned_up(gs) | ||
| test_two_workers_one_need_only_one_succeeds(gs) | ||
| test_reserve_field_added_to_new_builds(gs) | ||
| test_reserved_resources_save_load(gs) | ||
| test_reserved_resources_resync_on_load(gs) | ||
|
|
||
| print("") | ||
| print("=== reservation tests: %d passed, %d failed ===" % [test_pass, test_fail]) | ||
|
|
@@ -433,3 +435,81 @@ func test_reserve_field_added_to_new_builds(gs: Node) -> void: | |
| var loaded_build = loaded.get("builds", [{}])[0] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛑 Blocker: CI reports 'Script test suite: failure' on this PR. Tests 7 and 8 need to pass. Root cause not determinable from corpus—likely GDScript warning-as-error or runtime issue in rebuild_reservations() path. Automated finding from AI PR review. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still open after this push; carried forward. (as of f06e00e)
its-saffron[bot] marked this conversation as resolved.
|
||
| _assert_has(loaded_build, "reserved", "persisted_build: reserved field preserved") | ||
| _assert_eq(int(loaded_build.reserved.get("wood", -1)), 0, "persisted_build: reserved.wood = 0") | ||
|
|
||
| func test_reserved_resources_save_load(gs: Node) -> void: | ||
| print("") | ||
| print("--- reservation: reserved_resources survives save/load ---") | ||
|
|
||
| var state := { | ||
| "tick": 50, | ||
| "resources": {"wood": 10, "stone": 8, "food": 3}, | ||
| "harvested": {"wood": 0, "stone": 0, "food": 0}, | ||
| "priority_order": ["build", "haul", "gather"], | ||
| "workers": [ | ||
| { | ||
| "name": "Alice", | ||
| "pos": {"x": 1, "y": 1}, | ||
| "carrying": {}, | ||
| "task": {"kind": "gather", "resource": "wood"}, | ||
| "break_ticks": 0, | ||
| }, | ||
| { | ||
| "name": "Bob", | ||
| "pos": {"x": 2, "y": 1}, | ||
| "carrying": {}, | ||
| "task": {"kind": "haul", "resource": "stone"}, | ||
| "break_ticks": 0, | ||
| }, | ||
| ], | ||
| "tiles": [], | ||
| "builds": [], | ||
| "next_build_id": 1, | ||
| "events": [], | ||
| "save_version": 2, | ||
| "reserved_resources": {"wood": 2, "stone": 1}, | ||
| } | ||
|
|
||
| gs.save_game(state) | ||
| var loaded = gs.load_game() | ||
| var reserved: Dictionary = loaded.get("reserved_resources", {}) | ||
| _assert_eq(int(reserved.get("wood", -1)), 2, "saved wood reservation persists") | ||
| _assert_eq(int(reserved.get("stone", -1)), 1, "saved stone reservation persists") | ||
|
|
||
| func test_reserved_resources_resync_on_load(gs: Node) -> void: | ||
| print("") | ||
| print("--- reservation: reserved_resources resynced from workers on load ---") | ||
|
|
||
| var state := { | ||
| "tick": 60, | ||
| "resources": {"wood": 10, "stone": 8, "food": 3}, | ||
| "harvested": {"wood": 0, "stone": 0, "food": 0}, | ||
| "priority_order": ["build", "haul", "gather"], | ||
| "workers": [ | ||
| { | ||
| "name": "Alice", | ||
| "pos": {"x": 1, "y": 1}, | ||
| "carrying": {}, | ||
| "task": {"kind": "gather", "resource": "wood"}, | ||
| "break_ticks": 0, | ||
| }, | ||
| { | ||
| "name": "Bob", | ||
| "pos": {"x": 2, "y": 1}, | ||
| "carrying": {}, | ||
| "task": {"kind": "haul", "resource": "stone"}, | ||
| "break_ticks": 0, | ||
| }, | ||
| ], | ||
| "tiles": [], | ||
| "builds": [], | ||
| "next_build_id": 1, | ||
| "events": [], | ||
| "save_version": 2, | ||
| "reserved_resources": {}, | ||
| } | ||
|
|
||
| gs.save_game(state) | ||
| var loaded = gs.load_game() | ||
| var reserved: Dictionary = loaded.get("reserved_resources", {}) | ||
| _assert_eq(int(reserved.get("wood", -1)), 1, "wood reservation rebuilt from gather worker") | ||
| _assert_eq(int(reserved.get("stone", -1)), 1, "stone reservation rebuilt from haul worker") | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor (style): Code duplication between rebuild_reservations_from_workers() and rebuild_reservations() not addressed by this delta.
Automated finding from AI PR review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still open after this push; carried forward. (as of 6be3214)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still open after this push; carried forward. (as of 07c99f1)