84 lines
3.1 KiB
Markdown
84 lines
3.1 KiB
Markdown
# The Steward — Simulation State Schema
|
|
|
|
## Current contract
|
|
|
|
`SimulationStateRecord` is the versioned JSON boundary for the current
|
|
simulation. Schema v1 captures:
|
|
|
|
- simulation seed, tick interval, tick count, clock remainder, and elapsed
|
|
clock ticks;
|
|
- every NPC's identity, needs, attributes, task lifecycle, target, position,
|
|
starvation state, and decision RNG stream;
|
|
- village resource counters;
|
|
- controlled per-NPC wander RNG streams;
|
|
- scene-independent resource state plus the definition facts needed while its
|
|
ResourceNode is unloaded.
|
|
|
|
The top-level identity is:
|
|
|
|
```json
|
|
{
|
|
"schema": "the_steward.simulation",
|
|
"schema_version": 1
|
|
}
|
|
```
|
|
|
|
Unknown schema versions and structurally incomplete records are rejected. Add
|
|
an explicit migration function before accepting a future version; never
|
|
silently reinterpret old data as the newest layout.
|
|
|
|
NPC action and profession references are serialized as stable strings and
|
|
restored as `StringName`. Records referencing unknown executable actions or
|
|
professions are rejected against the validated definition registry. See
|
|
[the simulation definitions](SIMULATION_DEFINITIONS.md).
|
|
|
|
## Deterministic continuation
|
|
|
|
RNG seeds and internal states are encoded as decimal strings. They are signed
|
|
64-bit values and cannot safely pass through every JSON number implementation
|
|
without precision loss. Converting them to ordinary JSON numbers caused a
|
|
restored simulation to retain the same visible state while silently changing
|
|
its future random sequence.
|
|
|
|
`tests/simulation_state_serialization_test.gd` protects this contract by:
|
|
|
|
1. running a fixed-seed scenario for 48 ticks without interruption;
|
|
2. running the same scenario for 24 ticks;
|
|
3. serializing and restoring into a fresh manager;
|
|
4. running the remaining 24 ticks;
|
|
5. requiring the complete final-state checksums to match.
|
|
|
|
It also verifies clock remainder, resource amount/reservation/enabled
|
|
round-tripping, presentation unload/rebind, and rejection of unsupported
|
|
schemas.
|
|
|
|
## Resource authority
|
|
|
|
`SimulationManager` owns `ResourceStateRecord` instances independently of the
|
|
scene tree. Amount, reservation, enabled state, action/resource identity,
|
|
yield, and usage permissions remain available and serializable while no
|
|
ResourceNode is loaded.
|
|
|
|
ResourceNode binds to a record by stable ID and provides presentation,
|
|
interaction transforms, and active-world discoverability. Unloading a node does
|
|
not delete its record. Loading another node with the same stable ID rebinds to
|
|
the existing record and cannot overwrite its amount or reservation with scene
|
|
defaults.
|
|
|
|
ResourceStateRecord v2 adds the definition facts needed while unloaded. Nested
|
|
v1 resource records are migrated explicitly and hydrate their missing
|
|
definition from a matching presentation node when one becomes available.
|
|
|
|
## Deliberately out of scope
|
|
|
|
This phase does not yet provide:
|
|
|
|
- save-slot files, metadata, thumbnails, or atomic disk writes;
|
|
- backward migrations beyond schema v1;
|
|
- inventory, relationship, schedule, or history records;
|
|
- a player-facing load flow;
|
|
- save-slot persistence for scene-independent resource state.
|
|
|
|
Those features should build on this boundary rather than inventing parallel
|
|
serialization paths.
|