feat(engine): Implement TurnManager and WorldSimState for core turn-based simulation and world state management

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-06-06 17:46:38 -07:00
parent 5a6f9ffb67
commit e9b76ecdd6
3 changed files with 85 additions and 0 deletions

View file

@ -293,6 +293,14 @@ func next_player() -> void:
var fauna_grid: RefCounted = climate_node.get("_grid") as RefCounted var fauna_grid: RefCounted = climate_node.get("_grid") as RefCounted
if fauna_grid != null: if fauna_grid != null:
EcologyState.tick(fauna_grid, GameState.map_seed + GameState.turn_number) EcologyState.tick(fauna_grid, GameState.map_seed + GameState.turn_number)
# Increment 3b: world-event dispatch (geological / biological /
# anomalous) against the SAME live grid, after climate + ecology
# ticks. Accumulates per-tile eco-damage into WorldsimState's
# eco_map (persisted in the save). Production thresholds make
# events deliberately rare; this is the missing worldsim layer.
WorldsimState.dispatch(
fauna_grid, GameState.turn_number, GameState.map_seed
)
GameState.current_player_index = 0 GameState.current_player_index = 0
GameState.turn_number += 1 GameState.turn_number += 1
# Check victory conditions after all players have moved # Check victory conditions after all players have moved

View file

@ -0,0 +1,76 @@
extends Node
## Session-scoped GdWorldSim singleton (Increment 3b).
##
## Owns the continuous-worldsim EVENT layer that runs after the per-turn climate
## + ecology ticks: geological / biological / anomalous event dispatch, which
## accumulates per-tile eco-damage into an owned `eco_map`. This is the layer
## the live `turn_manager.gd::next_player()` was missing — climate and ecology
## (incl. migration) already tick via ClimatePhysics + EcologyState, but no
## world events fired in-game.
##
## Lifecycle:
## _ready() → reset() builds a fresh GdWorldSim + loads thresholds
## dispatch(grid, seed) → one world-event pass against the LIVE grid
## (read-modify-write; see GdWorldSim::dispatch_on_grid)
## to_save_json()/restore_from_save_json() → eco_map save round-trip
##
## Thresholds are loaded from the canonical JSON pack (Rail 2) at production
## rates — events are deliberately rare (~0.003/turn seismic). Proof scenes /
## tests boost thresholds so events fire reliably in a short run.
const GEO_THRESHOLDS_PATH: String = "res://public/resources/events/geological_thresholds.json"
const BIO_THRESHOLDS_PATH: String = (
"res://public/games/age-of-dwarves/data/balance/biological_events.json"
)
var worldsim: RefCounted = null
func _ready() -> void:
reset()
## Discard the current GdWorldSim and build a fresh one with production
## thresholds loaded. Called on new game / load so eco_map does not carry across
## sessions (the saved eco_map is injected via restore_from_save_json on load).
func reset() -> void:
if not ClassDB.class_exists("GdWorldSim"):
worldsim = null
return
worldsim = ClassDB.instantiate("GdWorldSim") as RefCounted
var geo: String = FileAccess.get_file_as_string(GEO_THRESHOLDS_PATH)
var bio: String = FileAccess.get_file_as_string(BIO_THRESHOLDS_PATH)
# Anomalous has no authored JSON yet — pass "" to keep Rust Default.
worldsim.call("load_thresholds_from_json", geo, bio, "")
## Run one world-event dispatch pass against the live shared grid. Caller is
## `turn_manager.gd::next_player()` after the climate + ecology ticks. Returns
## the number of events dispatched this turn.
func dispatch(grid: RefCounted, turn: int, seed: int) -> int:
if worldsim == null or grid == null:
return 0
return int(worldsim.call("dispatch_on_grid", grid, turn, seed))
## Serialize the eco-damage map for the save envelope. Empty string when no
## worldsim is active.
func to_save_json() -> String:
if worldsim == null:
return ""
return String(worldsim.call("eco_map_to_json"))
## Restore the eco-damage map from a save envelope payload. No-op on empty input.
func restore_from_save_json(json: String) -> void:
if worldsim == null or json.is_empty():
return
worldsim.call("restore_eco_map_from_json", json)
## Tiles carrying accumulated eco-damage — cheap probe for HUD / tests.
func eco_damage_tile_count() -> int:
if worldsim == null:
return 0
return int(worldsim.call("eco_map_len"))

View file

@ -0,0 +1 @@
uid://b8d8hc2h052uk