magicciv/tooling/claude/dot-claude/instructions/rust-source-of-truth.md
Natalie 2d9554d9ff feat(@projects): update wasm build and guide deployment workflows
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-04-17 13:06:14 -07:00

4.7 KiB

Rust Is The Simulation Source Of Truth

Load when: touching anything under src/simulator/, adding/changing simulation logic, wiring GDScript to physics, building GDExtension or WASM, or answering "where should this calculation live?"

The engine is genre-agnostic. All game content and display text comes from game packs. The fantasy game "Age of Dwarves" is the default pack.

Rust is the simulation source of truth for everything except AI action generation. Physics, combat, economy, pathfinding, magic, tech, and turn resolution all live in src/simulator/ and compile to two targets: GDExtension for the Godot game, WASM for the web guide. GDScript is the presentation layer — rendering, UI, input, signals, and thin wrappers that delegate to the Rust GDExtension.

AI exception (one of one)

AI action generation is currently implemented in GDScript at src/game/engine/src/modules/ai/simple_heuristic_ai.gd. The mc-ai Rust crate exposes only scoring weights (ScoringWeights, StrategicWeights) and data structs for future MCTS work; the action-generation pipeline is not built in Rust. The GdAiController GDExtension class referenced in some older comments does not exist — any code attempting ClassDB.instantiate("GdAiController") would return null. AiTurnBridge.run(player) calls SimpleHeuristicAi.process_player(player) directly.

Canonical content store

JSON game packs remain the canonical content store. Stats, costs, effects, thresholds — all in public/games/age-of-dwarves/data/*.json. Neither Rust nor GDScript hardcodes game content.

  • UI labels resolve through ThemeVocabulary.lookup(engine_key) — never hardcode theme strings
  • Sprites resolve through ThemeAssets.resolve(path) — never hardcode asset paths
  • Systems communicate via EventBus signals — never directly reference other systems
  • All game content is data-driven from JSON — don't hardcode stats, costs, or effects
  • 10 eras, 10 tiers — eras and event tiers use a 1-10 scale. Era count and names are game-pack-driven (defined in eras.json, not the engine). Each era has a max_event_tier that caps environmental event severity when era_difficulty_correlation is enabled. Units, spells, buildings use content tiers defined by the game pack. Spells use scope: "global" (High Archon, world map) or scope: "local" (specialist units, combat). School tech tiers map: T1-T2 spells gated by Mysticism/Arcane Lore, T3-T5 by school techs.

Compile-target topology

public/games/age-of-dwarves/data/climate_spec.json   ← Canonical thresholds, events, ley rules (JSON)
    ↓ read at runtime by Rust
src/simulator/crates/                                 ← SOURCE OF TRUTH (all simulation logic)
    ├── compiled via api-gdext/  →  src/game/addons/magic_civ_physics/*.so/.dll
    │       ↓ loaded by Godot
    │   src/game/engine/src/modules/climate/climate.gd  ← thin GDExtension wrapper
    └── compiled via api-wasm/   →  .local/build/wasm/     (NOT src/simulator/pkg/ —
            ↓ imported by web worker                          build output never under src/,
        public/games/age-of-dwarves/guide/src/simulation/      see build-output-locations.md)
        simulation.worker.ts

Build commands

# WASM (web guide)
cd src/simulator && bash build-wasm.sh

# GDExtension (Godot game, Linux dev)
cd src/simulator && bash build-gdext.sh

In practice these run on the RUN host via ssh — see canonical-commands.md.

Rules

  • All simulation changes go in Rust (src/simulator/crates/) — never in GDScript or TypeScript, except AI action generation, which currently lives in src/game/engine/src/modules/ai/simple_heuristic_ai.gd.
  • Never hardcode thresholds — read from climate_spec.json and other JSON data files.
  • Ecological events require a seed — deterministic PRNG seeded per-turn.
  • Golden test vectors verify WASM output matches expected results.
  • GDScript climate/combat/magic/economy files are thin wrappers — they call GdClimatePhysics, GdEcologyPhysics, etc. via GDExtension. No physics logic lives in GDScript.

Crate responsibilities

Crate Owns
mc-core GridState, TileState, BiomeRegistry, hex algorithms
mc-climate ClimatePhysics, EcologyPhysics, atmosphere, spec evaluator
mc-mapgen MapGenerator
mc-combat CombatResolver
mc-magic SpellSystem, ManaPool, Archons (Game 2)
mc-economy EmpireEconomy
mc-city CityGrowth
mc-happiness happiness pool
mc-culture CultureAccumulation
mc-tech TechWeb graph
mc-ai AI scoring weights + data structs (not action generation)
mc-turn TurnProcessor