Skip to content

Chapter 4 — The Simulation Core

Part II — Engine Architecture

The simulation core is the runtime that powers every AI RPG Engine world. It manages world state, processes actions, emits events, and advances time. Everything else — modules, rulesets, presentation — builds on top of this foundation.


All simulation truth lives in a single WorldState object:

FieldTypePurpose
metaWorldMetaWorld ID, game ID, tick counter, RNG seed, active ruleset and modules
playerIdstringThe player entity ID
locationIdstringCurrent player zone
entitiesRecord<string, EntityState>All actors, objects, and interactables
zonesRecord<string, ZoneState>Spatial containers with properties and connections
questsRecord<string, QuestState>Active and completed quest state
factionsRecord<string, FactionState>Faction definitions and relationships
globalsRecord<string, ScalarValue>Arbitrary key-value state (flags, counters)
modulesRecord<string, unknown>Per-module namespaced state
eventLogResolvedEvent[]Complete history of all events
pendingPendingEffect[]Delayed effects scheduled for future ticks
narratorNarratorState?Optional narrator state for presentation layers

The WorldStore class wraps WorldState and provides typed operations for entity lookup, resource modification, stat queries, zone management, event recording, and serialization.


Every actor, object, and interactable in the world is an EntityState:

FieldTypePurpose
idstringUnique identifier
blueprintIdstringContent definition this entity was created from
typestringCategory: "npc", "enemy", "item", "object"
namestringDisplay name
tagsstring[]Searchable labels ("hostile", "merchant", "quest-giver")
statsRecord<string, number>Stable capabilities (vigor, reflex, will)
resourcesRecord<string, number>Trackable pools (hp, stamina, heat)
statusesAppliedStatus[]Active status effects with duration
inventorystring[]?Item entity IDs
equipmentRecord<string, string>?Slot-to-item ID mapping
zoneIdstring?Current location
aiAIState?AI profile, goals, fears, alert level, knowledge
customRecord<string, ScalarValue>?Ruleset-specific data

Stats and resources are genre-neutral. A fantasy ruleset defines vigor, instinct, will as stats and hp, stamina as resources. A cyberpunk ruleset defines chrome, reflex, netrunning as stats and hp, heat as resources. The engine treats them identically.


Every state change flows through the action pipeline. There are no backdoors.

ActionIntent --> Validation --> Resolution --> Events --> Presentation

An action starts as an ActionIntent with a verb, actor, optional targets, and parameters. The engine emits an action.declared event immediately.

Every registered validator runs against the action and current world state. Validators check things like: does the actor have enough stamina? Is the target in the same zone? Is this verb legal in the current context?

If any validator fails, the engine emits action.rejected with a structured reason and stops. No state changes occur.

The verb handler (registered by a module) executes the action against the world state and returns resolved events. For example, the combat module’s attack handler calculates damage, applies it, checks for defeat, and returns events describing what happened.

All resolved events are recorded in the event log and emitted through the event bus. Other modules can listen and react — cognition updates beliefs, perception filters check visibility, environment tracks noise.

After resolution, the engine processes any pending effects that are due at the current tick. Pending effects are delayed consequences — a poison tick, a timed explosion, a status expiration.

The tick counter increments after each action. This provides a discrete, deterministic time axis that all systems reference.


The engine uses discrete ticks rather than real-time. Each call to processAction() advances the tick by one.

Ticks serve as the universal clock:

  • Events record which tick they occurred at
  • Statuses track their start tick and duration
  • Pending effects specify which tick to execute at
  • AI memories record when they were formed
  • Knowledge decay references tick distances

This makes the simulation fully deterministic — given the same seed and the same sequence of actions, the engine produces identical results every time.


The Engine class ties everything together. It creates a WorldStore, an ActionDispatcher, and a ModuleManager. Modules register their verbs, event listeners, rules, formulas, and persistence namespaces during construction.

The engine exposes:

Method / PropertyPurpose
submitAction(verb, options)Process a player action
processAction(action)Process any action (player, AI, or system)
getAvailableActions()List all registered verbs
serialize()Full state snapshot for save/load
worldRead-only access to current WorldState
tickCurrent tick number
formulasAccess to the formula registry

Because every state change flows through processAction() and the RNG is seeded, the engine supports deterministic replay:

  1. Record the seed and every ActionIntent in order
  2. Create a new engine with the same seed
  3. Replay each action — the world state will be identical

This is the foundation of the engine’s debugging and testing workflow. The portability tests verify that two engines created with the same seed and given the same actions produce byte-identical serialized state.


Each module can register a namespaced state slot in world.modules. The engine deep-clones default state during initialization (via structuredClone), so module state must be serializable — no functions, no circular references.

Modules that need runtime-only data (like function references) use the registry pattern: store a serializable key in module state, keep the actual functions in a module-level Map outside the world state.


The simulation core provides five guarantees:

  1. Single entry point — all state changes go through the action pipeline
  2. Structured events — every change produces queryable, replayable events
  3. Determinism — same seed + same actions = same results
  4. Serialization — full state can be saved, loaded, and compared
  5. Modularity — the core knows nothing about combat, dialogue, or any specific system