Files
gamedev-the-steward/docs/SIMULATION_DEFINITIONS.md
T
2026-08-12 21:15:58 +02:00

7.7 KiB

The Steward — Simulation Definitions

Purpose

Stable IDs and immutable definitions form the vocabulary shared by simulation state, systems, world adapters, scenes, tests, and save migrations.

SimulationIds remains the append-only source for code-facing compatibility IDs. SimulationContentPack is the no-code authoring manifest and ContentCatalog transactionally validates and publishes typed definitions in stable-ID order. The current core pack contains actions, professions, capability tags, items, resources, storage policies, and enemies. A failed pack publishes nothing: duplicate IDs, unknown references, unsupported handlers, or missing presentation cues are authoring errors rather than silent overrides.

Simulation code resolves definitions through the catalog. Presentation cue IDs remain headless strings and are mapped separately to scenes, materials, icons, or animation hooks. Runtime quantities and ownership stay in state records; saves do not contain .tres paths or copied definition balance.

Content-pack contract

Each pack has a stable pack_id, display name, explicit pack dependencies, required handler IDs, and typed definition arrays. Pack and definition IDs are unique across the whole catalog. Packs cannot override each other in the first version, and enumeration is sorted independently of resource load order.

Adding data-only content is:

  1. create a typed .tres definition;
  2. add it to an explicit pack;
  3. optionally register its stable presentation cue in the presentation layer;
  4. place or spawn an instance with its own canonical runtime ID.

Adding a fundamentally new mechanic still requires one bounded reusable handler. The pack declares that dependency so missing runtime support fails validation rather than becoming a partially functioning object.

Action contract

Each executable ActionDefinition contains:

  • stable action ID and display name;
  • duration and optional preferred profession;
  • target family and resource-action metadata;
  • optional completion cost;
  • actor and target capability tags;
  • selection, target, and completion handler IDs;
  • reusable typed effects;
  • event and presentation cue IDs.

Reusable ActionEffect definitions cover metric/need change, exact inventory transfer, damage/healing, relationship-dimension change, scheduling an ordinary action, and site-condition change. ActionCommand carries stable actor/action/ target/item IDs, amount, and expected revision; ActionOffer and ActionResult are copy-only values. ActionCommandService is the authority boundary and must revalidate range, capabilities, reservation, permission, cost, and target state at execution time for either a player or NPC caller.

The current actions are gather food, gather wood, feed animal, deposit food, deposit wood, withdraw food, patrol, study, eat, rest, sleep, wander, and defend. Idle and dead are state sentinels, not executable definitions. The two-leg animal-feeding transaction remains a custom completion handler because it has a real compound pickup/delivery contract and no second shared consumer yet.

Items, resources, and storage

ItemDefinition validates fields by category. Weapons require damage, reach, cooldown, and an equip slot; materials and consumables do not carry fake weapon fields. The core pack contains food, wood, herb, sword, and claw. Herb proves a new non-weapon item and route without a manager branch.

ResourceDefinition owns yielded item, gather action, capability tags, base capacity/yield/regrowth, access policy, and presentation cue. Placement/state records retain unique contextual IDs and overrides such as safety risk, comfort, and discovery priority. Berry patches, trees, and herb patches share this contract.

StorageDefinition declares accepted item IDs/tags, policy priority, capacity, settlement scope, deposit/withdraw actions, and presentation cue. StorageRoutingPolicy ranks compatible destinations deterministically by priority then stable target ID. Food-to-pantry and wood-to-woodpile remain covered; herb-to-apothecary proves data-only routing beyond those legacy cases.

Professions and capabilities

Each ProfessionDefinition contains a stable ID, display name, body color, and prop color. Farmer, woodcutter, guard, scholar, and wanderer are registered in the core pack. NPC state saves only the ID and rejects unknown definitions.

CapabilityTagDefinition gives actions and targets a validated shared vocabulary. Tags express composable affordances; they do not mutate state or replace concrete authority checks.

Enemies and combat

EnemyDefinition carries a behavior profile, combatant ID prefix, faction, hostility, weapon, health, movement, and visual parameters. CombatantFactory creates/restores every hostile and rebuilds collision-free per-prefix allocators. The core boar reuses the wolf-hunt behavior without a new manager or combat switch; raider and wolf compatibility spawn APIs delegate to the same factory.

Combatant and faction state use stable IDs. NPC combatants point to their person ID; hostile records persist enemy_definition_id. Weapons resolve through the same item catalog used by inventory rather than a parallel combat item table.

Animals

AnimalDefinition + AnimalCatalog + AnimalFactory apply the same definition-instance-state-presentation contract to domestic animals. Goat and sheep reuse the grazer_routine, feeding capability, generic CozyGrazer scene, state migration, and care system; definition and visual parameters are the only type-specific pieces. The animal catalog remains isolated until the next shared content-pack migration adds that record family without destabilizing the already validated core pack.

Situations and dialogue

Legacy OpportunityStateRecord vocabulary remains for save compatibility. New emergent content uses typed SituationDefinition resources: reusable predicates, evidence requirements, dedupe fields, priority/severity, alternative objectives, exact ordinary resolution patterns, expiry/cooldown, and dialogue topic IDs. Situation state saves the definition ID and causal facts; progress is re-derived from authoritative state and WorldEventStore.

DialogueIntentDefinition owns semantic preconditions, score, response intent IDs, template variants, and optional action metadata. Stable hashing selects a variant from conversation/turn/intent/topics without consuming shared RNG. Rendered prose and Dialogue Manager resources are presentation and never authoritative state.

Validation and authoring report

The catalog rejects:

  • missing, empty, or duplicate pack/definition IDs;
  • silent cross-pack overrides;
  • unknown pack, handler, capability, item, profession, action, storage, behavior-profile, or presentation-cue references;
  • category-invalid item fields;
  • incomplete or non-positive costs/effects;
  • resources or storage routes with inconsistent item/action contracts;
  • definition resources that fail to load.

ContentCatalog.get_authoring_report() exposes validity, sorted published IDs, and exact errors for CLI/editor tooling. Tests prove transactional failure, deterministic enumeration, core cross-references, boar behavior reuse, shared goat/sheep behavior, and herb routing.

Deliberate boundary

Definitions own reusable static metadata, not mutable inventory, reservations, relationships, situation progress, entity ownership, or presentation nodes. Handler implementations remain bounded typed strategies. A universal reflection DSL, arbitrary scripts embedded in saves, and a full ECS are outside the contract.

Selection, execution, target resolution, simulation authority, and visual travel remain separate responsibilities. Extend definitions only after a real consumer proves a stable shared field; extend a handler when the mechanic itself is genuinely new.