refactor: clarify simulation ownership
This commit is contained in:
@@ -68,8 +68,23 @@ It also publishes the latest `ActionSelectionResult` for presentation; the UI
|
||||
does not recompute decisions. At completion it atomically pays any
|
||||
definition-backed stored-resource cost before applying the action effect. A
|
||||
late shortfall suppresses the effect and records a `task_blocked` fact.
|
||||
Further decomposition should follow measured pressure rather than splitting it
|
||||
into managers for their own sake.
|
||||
|
||||
### VillageEconomy
|
||||
|
||||
- owns storage and NPC-inventory transfer operations;
|
||||
- keeps `village.food` and `village.wood` synchronized as aggregate views;
|
||||
- validates and pays definition-backed completion costs;
|
||||
- emits completed transaction facts without owning their history.
|
||||
|
||||
### SimulationEventLog
|
||||
|
||||
- owns ordered economic and narrative event identity;
|
||||
- answers recent-history, actor-history, and consumption-rate queries;
|
||||
- restores persisted history without performing or replaying transactions.
|
||||
|
||||
These collaborators are `RefCounted` rule services, not additional scene-tree
|
||||
managers. Further decomposition should follow measured pressure and a proven
|
||||
gameplay consumer.
|
||||
|
||||
## Active-position contract
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# The Steward — Architecture Overview
|
||||
|
||||
This project is organized around gameplay ownership, not scene-tree location.
|
||||
Serializable simulation records are authoritative; loaded Godot nodes present
|
||||
that state and contribute active-world facts such as positions and navigation
|
||||
results.
|
||||
|
||||
## Runtime flow
|
||||
|
||||
```text
|
||||
SimulationClock
|
||||
-> SimulationManager orchestrates one deterministic tick
|
||||
-> ActionExecutionSystem advances needs and work
|
||||
-> ActionSelectionSystem chooses an action
|
||||
-> ActionTargetResolver resolves a stable target ID
|
||||
-> VillageEconomy performs inventory/storage transactions
|
||||
-> SimulationEventLog records completed facts
|
||||
-> WorldViewManager presents travel and NPC state
|
||||
-> ActiveWorldAdapter supplies loaded-world positions/capacity
|
||||
-> NpcVisual performs local navigation and animation
|
||||
```
|
||||
|
||||
`SimulationManager` is the scene-tree façade for the simulation. It owns the
|
||||
tick lifecycle, authoritative NPC/village/resource records, reservations, and
|
||||
the signals consumed by presentation. Focused collaborators own rules that
|
||||
would otherwise obscure that lifecycle:
|
||||
|
||||
- `simulation/actions/` owns selection, progress, and target resolution;
|
||||
- `simulation/economy/VillageEconomy.gd` owns storage/inventory transactions
|
||||
and keeps village resource summaries synchronized;
|
||||
- `simulation/events/SimulationEventLog.gd` owns ordered event identity,
|
||||
history queries, and rate calculations;
|
||||
- `simulation/persistence/` owns save-slot file safety;
|
||||
- `simulation/state/` owns versioned serialized record contracts;
|
||||
- `simulation/definitions/` owns stable IDs and immutable action/profession
|
||||
definitions.
|
||||
|
||||
The manager deliberately remains a façade instead of being split into a
|
||||
collection of scene-tree manager nodes. A new collaborator is justified when
|
||||
one cohesive rule set has several real consumers or makes the tick lifecycle
|
||||
hard to read.
|
||||
|
||||
## Folder ownership
|
||||
|
||||
| Path | Responsibility |
|
||||
| --- | --- |
|
||||
| `simulation/` | Headless-capable orchestration and core models |
|
||||
| `simulation/actions/` | Action decisions, execution, and target queries |
|
||||
| `simulation/economy/` | Authoritative inventory and storage transactions |
|
||||
| `simulation/events/` | Immutable event history and derived event queries |
|
||||
| `simulation/state/` | Versioned, serializable mutable records |
|
||||
| `simulation/definitions/` | Stable IDs and immutable gameplay definitions |
|
||||
| `simulation/persistence/` | Validated local save-file storage |
|
||||
| `world/` | Loaded-world interaction geometry and presentation adapters |
|
||||
| `world/resource_nodes/` | Finite resource presentation bound by stable ID |
|
||||
| `world/storage/` | Storage interaction geometry, never stored quantities |
|
||||
| `world/activity/` | Rest/study/patrol interaction sites and capacity facts |
|
||||
| `player/` | Player input, camera, and active NPC presentation |
|
||||
| `tests/` | Deterministic headless gameplay scenarios |
|
||||
|
||||
Top-level core model scripts keep their stable paths because Godot's global
|
||||
class cache records `class_name` locations. Moving them solely for cosmetic
|
||||
nesting can break editor and headless startup for existing workspaces without
|
||||
improving ownership.
|
||||
|
||||
## Dependency rules
|
||||
|
||||
- Simulation code must run without `main.tscn` or loaded world nodes.
|
||||
- Persistent references are stable IDs, never `Node`, `NodePath`, or scene
|
||||
ownership.
|
||||
- Presentation may report facts and submit commands; it does not choose NPC
|
||||
actions or own resource, storage, inventory, event, or reservation state.
|
||||
- Resource changes go through `ResourceStateRecord`, NPC inventory, and
|
||||
`VillageEconomy`; `village.food` and `village.wood` are synchronized views.
|
||||
- New mutable features define serialization and deterministic continuation at
|
||||
the same time as their first gameplay use.
|
||||
- Prefer one tested vertical behavior over a generic framework with no proven
|
||||
consumers.
|
||||
|
||||
## Where new code goes
|
||||
|
||||
Put a rule beside the state it governs. A relationship consequence belongs in
|
||||
a focused simulation system plus serialized relationship records; its icon or
|
||||
animation belongs in presentation. Add a world node only when the behavior
|
||||
needs loaded-world geometry. Add a stable ID or definition when content must be
|
||||
referenced across saves, scenes, or unloaded simulation.
|
||||
|
||||
The architectural decision and detailed contracts live in
|
||||
[ADR 0001](decisions/0001-simulation-authority-boundary.md),
|
||||
[the action system architecture](ACTION_SYSTEM_ARCHITECTURE.md), and
|
||||
[the simulation state schema](SIMULATION_STATE_SCHEMA.md).
|
||||
@@ -20,6 +20,11 @@ Events are immutable facts about completed transfers. They do not perform the
|
||||
transaction and are not replayed to reconstruct current state. Resource,
|
||||
inventory, and storage records remain authoritative.
|
||||
|
||||
`SimulationEventLog` owns ordered event identity, append/restore behavior, and
|
||||
history/rate queries. `VillageEconomy` performs transactions and requests event
|
||||
records only after state changes succeed; `SimulationManager` remains the
|
||||
public signal boundary used by presentation.
|
||||
|
||||
An action whose definition-backed completion cost becomes unavailable records
|
||||
a zero-amount `task_blocked` narrative fact with the action and shortfall
|
||||
reason. This makes late contention inspectable without pretending that a
|
||||
|
||||
@@ -20,8 +20,10 @@ world only when consumed.
|
||||
|
||||
- `StorageStateRecord` owns pantry and woodpile contents and capacity.
|
||||
- `SimNPC.inventory` owns carried item amounts.
|
||||
- `SimulationManager` performs deposit, withdrawal, and consumption
|
||||
transactions.
|
||||
- `VillageEconomy` performs deposit, withdrawal, consumption, and
|
||||
definition-backed completion-cost transactions.
|
||||
- `SimulationManager` coordinates action lifecycle and exposes the transaction
|
||||
results to presentation.
|
||||
- `village.food` and `village.wood` are synchronized aggregate views used by
|
||||
the existing UI, priorities, and utility scoring. They are not second
|
||||
mutation paths.
|
||||
@@ -45,6 +47,8 @@ Transactions apply the amount actually available:
|
||||
|
||||
- extraction cannot exceed the source;
|
||||
- deposit cannot exceed storage capacity;
|
||||
- player extraction is limited to storage capacity until player inventory
|
||||
exists, so overflow remains at the source;
|
||||
- withdrawal cannot exceed pantry contents;
|
||||
- eating succeeds only when the NPC carries one food.
|
||||
|
||||
|
||||
@@ -29,9 +29,8 @@ Each milestone should produce five outcomes:
|
||||
Do not advance because files exist. Advance when the exit test passes.
|
||||
|
||||
The current implementation has completed ResourceNode migration through player
|
||||
parity plus the minimal Jajce scaffold and navigation proof. The architecture
|
||||
gate below is now active and must pass before beauty production or broader
|
||||
simulation features. See
|
||||
parity, the Jajce scaffold/navigation proof, and the mandatory architecture
|
||||
gate below. See
|
||||
[ADR 0001](decisions/0001-simulation-authority-boundary.md).
|
||||
|
||||
## Mandatory architecture gate
|
||||
@@ -660,6 +659,12 @@ The practical next sequence is:
|
||||
|
||||
Recently completed:
|
||||
|
||||
- Simulation responsibility cleanup: storage/inventory transactions now live
|
||||
in `VillageEconomy`, ordered history and rate queries live in
|
||||
`SimulationEventLog`, and `SimulationManager` exposes a shorter tick
|
||||
lifecycle while remaining the scene-tree façade. Dead prototype APIs and
|
||||
unused scene artifacts were removed, with the ownership map documented in
|
||||
`ARCHITECTURE_OVERVIEW.md`.
|
||||
- `F10` cinematic/debug presentation toggle that hides development UI, world
|
||||
labels, and NPC name/profession labels without changing simulation state;
|
||||
- `F12` repeatable simulation-garden demo reset by reloading the current scene
|
||||
|
||||
+30
-19
@@ -375,40 +375,46 @@ glyphs.
|
||||
### `simulation/SimNPC.gd`
|
||||
|
||||
`SimNPC` is a `RefCounted` simulation model. It owns needs, task selection,
|
||||
task progression, profession affinity, starvation, and death.
|
||||
task state, profession affinity, carried inventory, starvation, and death.
|
||||
|
||||
This separation from the visual node is an important architectural seed and
|
||||
should be preserved.
|
||||
|
||||
### `simulation/SimVillage.gd`
|
||||
|
||||
`SimVillage` is a `RefCounted` aggregate for shared resources, modifiers,
|
||||
priorities, and applying completed NPC work.
|
||||
`SimVillage` is a `RefCounted` aggregate for synchronized village resource
|
||||
views, modifiers, and priorities.
|
||||
|
||||
### `simulation/SimulationManager.gd`
|
||||
|
||||
`SimulationManager` is currently a scene-tree `Node` that:
|
||||
|
||||
- owns the village and NPC array;
|
||||
- advances a tick approximately every 1.2 seconds;
|
||||
- advances deterministic ticks through `SimulationClock`;
|
||||
- creates NPCs;
|
||||
- coordinates task completion;
|
||||
- coordinates selection, travel, reservations, and task completion;
|
||||
- emits village, task, and death signals;
|
||||
- exposes direct resource-changing methods to the player.
|
||||
- exposes the bounded player/simulation command API.
|
||||
|
||||
It currently combines clock, orchestration, event publication, population
|
||||
creation, and some gameplay API responsibilities.
|
||||
Focused `RefCounted` collaborators keep rule ownership visible:
|
||||
|
||||
- action systems own selection, execution progress, and target resolution;
|
||||
- `VillageEconomy` owns storage/inventory transactions and synchronized
|
||||
village resource views;
|
||||
- `SimulationEventLog` owns deterministic event history and queries.
|
||||
|
||||
`SimulationManager` remains the scene-tree façade and signal boundary rather
|
||||
than duplicating these responsibilities across additional manager nodes.
|
||||
|
||||
### `world/world_view_manager.gd`
|
||||
|
||||
`WorldViewManager` bridges simulation data to visible NPC nodes. It:
|
||||
|
||||
- instantiates `NpcVisual` scenes;
|
||||
- resolves resource nodes, random wander targets, and remaining activity
|
||||
markers;
|
||||
- writes the selected ResourceNode ID onto the NPC as a transitional behavior;
|
||||
- sends targets to visuals;
|
||||
- supplies active visual positions for simulation-owned target resolution;
|
||||
- sends resolved travel destinations to visuals;
|
||||
- reports arrival and navigation failure back to `SimulationManager`;
|
||||
- synchronizes successful visual movement into authoritative NPC position;
|
||||
- applies visual death state.
|
||||
|
||||
### `player/npc/NpcVisual.gd`
|
||||
@@ -456,7 +462,9 @@ NpcVisual navigates through the active world
|
||||
| Later ticks complete work
|
||||
| |
|
||||
| v
|
||||
| ResourceStateRecord.extract() -> village.apply_resource_delta()
|
||||
| ResourceStateRecord.extract() -> NPC inventory
|
||||
| -> VillageEconomy transfers inventory/storage as actions complete
|
||||
| -> SimulationEventLog appends completed facts
|
||||
| |
|
||||
| v
|
||||
| village_changed signal updates the UI
|
||||
@@ -488,6 +496,9 @@ NpcVisual navigates through the active world
|
||||
│ ├── SimulationManager.gd
|
||||
│ ├── actions/ Selection, execution, and target resolution
|
||||
│ ├── definitions/ Stable IDs and custom definition resources
|
||||
│ ├── economy/ Inventory and storage transactions
|
||||
│ ├── events/ Ordered event history and queries
|
||||
│ ├── persistence/ Validated local save-slot storage
|
||||
│ └── state/ Versioned simulation-state records
|
||||
├── tests/
|
||||
│ ├── action_system_boundaries_test.gd
|
||||
@@ -538,9 +549,9 @@ These are expected prototype constraints, not necessarily isolated bugs:
|
||||
- Automated coverage includes deterministic same-seed and save/restore
|
||||
continuation checks, player-parity/resource-contention, flat-map, and Jajce
|
||||
scaffold scenarios; broader gameplay coverage is still missing.
|
||||
- Resources are global floating-point counters rather than items in locations
|
||||
and inventories, except food, which now moves through sources, NPC inventory,
|
||||
and the village pantry.
|
||||
- Food and wood now move through finite sources, NPC inventory, and typed
|
||||
village storage. Other village metrics remain aggregate values rather than
|
||||
located items.
|
||||
- NPCs do not have homes, schedules, possessions, memories, relationships,
|
||||
goals, or social knowledge.
|
||||
- The reason inspector exposes current decisions, but deeper historical traces
|
||||
@@ -549,9 +560,9 @@ These are expected prototype constraints, not necessarily isolated bugs:
|
||||
- Unloaded traveling NPCs preserve their state but do not yet advance through
|
||||
abstract travel time.
|
||||
- There is no spatial query/index layer for large populations.
|
||||
- SimulationManager still orchestrates multiple systems and player-facing
|
||||
mutation APIs, but selection, execution, target resolution, and active-world
|
||||
queries now have focused collaborators.
|
||||
- SimulationManager still coordinates the tick lifecycle and bounded
|
||||
player-facing commands, while action rules, active-world queries, economic
|
||||
transactions, and event history have focused collaborators.
|
||||
- Path failure and interruption emit a `navigation_failed` signal and send the NPC to wander; this is functional but not yet polished.
|
||||
- The old greybox navigation source has been replaced by a project-owned
|
||||
Terrain3D-derived navigation resource. The current bake is still a first
|
||||
|
||||
+7
-5
@@ -6,22 +6,24 @@ sources of truth.
|
||||
1. [`PROJECT_CONTEXT.md`](PROJECT_CONTEXT.md) is the canonical description of
|
||||
the vision, current implementation, target architecture, and active
|
||||
constraints.
|
||||
2. [`LEARNING_ROADMAP.md`](LEARNING_ROADMAP.md) owns milestone order,
|
||||
2. [`ARCHITECTURE_OVERVIEW.md`](ARCHITECTURE_OVERVIEW.md) is the concise map of
|
||||
runtime ownership, folder responsibilities, and dependency rules.
|
||||
3. [`LEARNING_ROADMAP.md`](LEARNING_ROADMAP.md) owns milestone order,
|
||||
architecture gates, reusable-system exit tests, and intentionally deferred
|
||||
work.
|
||||
3. [`BUILD_IN_PUBLIC_PLAN.md`](BUILD_IN_PUBLIC_PLAN.md) owns the scoped Jajce
|
||||
4. [`BUILD_IN_PUBLIC_PLAN.md`](BUILD_IN_PUBLIC_PLAN.md) owns the scoped Jajce
|
||||
visual slice. It must respect the architecture gates in the learning
|
||||
roadmap.
|
||||
4. [`RESOURCE_NODE_MIGRATION.md`](RESOURCE_NODE_MIGRATION.md) is a focused
|
||||
5. [`RESOURCE_NODE_MIGRATION.md`](RESOURCE_NODE_MIGRATION.md) is a focused
|
||||
migration plan. Phases 1–6 are complete; follow-up work should expand
|
||||
resource discovery without reintroducing abstract resource zones.
|
||||
5. [`ACTION_SYSTEM_ARCHITECTURE.md`](ACTION_SYSTEM_ARCHITECTURE.md),
|
||||
6. [`ACTION_SYSTEM_ARCHITECTURE.md`](ACTION_SYSTEM_ARCHITECTURE.md),
|
||||
[`ECONOMIC_EVENTS.md`](ECONOMIC_EVENTS.md),
|
||||
[`FOOD_STORAGE_ARCHITECTURE.md`](FOOD_STORAGE_ARCHITECTURE.md),
|
||||
[`SIMULATION_DEFINITIONS.md`](SIMULATION_DEFINITIONS.md), and
|
||||
[`SIMULATION_STATE_SCHEMA.md`](SIMULATION_STATE_SCHEMA.md) document the
|
||||
current data contracts.
|
||||
6. [`decisions/`](decisions/) contains durable architectural decisions,
|
||||
7. [`decisions/`](decisions/) contains durable architectural decisions,
|
||||
including consequences and revisit conditions.
|
||||
|
||||
When documents disagree:
|
||||
|
||||
@@ -60,9 +60,10 @@ destination. This allows a reloaded visual to resume travel without changing
|
||||
target selection or deterministic RNG state.
|
||||
|
||||
NPCStateRecord v3 adds carried inventory. SimulationStateRecord v2 adds
|
||||
StorageStateRecord entries; world-schema v1 migrates legacy village food into
|
||||
the stable `village_pantry` record. Parsed storage values are canonicalized so
|
||||
save/restore continuation retains byte-stable checksums.
|
||||
StorageStateRecord entries; world-schema v1 migrates legacy village food and
|
||||
wood into the stable `village_pantry` and `village_woodpile` records. Parsed
|
||||
storage values are canonicalized so save/restore continuation retains
|
||||
byte-stable checksums.
|
||||
|
||||
SimulationStateRecord v3 adds ordered `EconomicEventRecord` entries and
|
||||
`next_event_id`. World schemas v1 and v2 migrate explicitly to an empty event
|
||||
|
||||
@@ -54,7 +54,7 @@ random streams, and no dependency on a loaded gameplay scene.
|
||||
5. ✅ Split action selection, execution, and presentation travel.
|
||||
6. ✅ Synchronize active position and prove visual unload/reload
|
||||
invariance.
|
||||
7. Add save-slot persistence before schedules or relationships
|
||||
7. ✅ Add save-slot persistence before schedules or relationships
|
||||
substantially expand mutable state.
|
||||
|
||||
Schema v1 and its deterministic continuation contract are documented in
|
||||
|
||||
Reference in New Issue
Block a user