Formalised by ADR-0002. Gameplay tuning (ship stats, weapon parameters, etc.) splits into two tiers. Keep them separate.
Template — api/src/main/java/infinity/config/*Config
- Immutable Java records, one per type (e.g. one
ShipConfigper entry inShipsenum). - Produced by the config layer (Groovy script today, possibly INI import later).
- Stored in a per-arena
ConfigRegistry. - Never read on the hot path.
Instance — components in api/src/main/java/infinity/es/...
- Zay-ES components, one per entity, mutable across the entity's lifetime.
- Seeded from the template at ship spawn.
- Mutated by gameplay: upgrades raise
Thrust, damage dropsEnergy, power-ups can raiseThrustMax, etc.
| Code location | Reads template? | Reads components? |
|---|---|---|
| Hot-path consumers (PlayerDriver, weapons firing) | No | Yes |
| Spawn systems | Yes | Writes |
| Admin / live-reload reconcilers | Yes | Writes |
| Clients (HUD, bars) | No (template is server-only) | Yes (via Zay-ES sync) |
Hot-path consumers must not import from infinity.config. Spawn systems are the only boundary where template → component projection happens.
- Per-entity divergence is real gameplay (upgrades, buffs, damage). Template alone can't model it.
- Template alone would force hot-path code to do
registry.get(arena).get(type).stat()every tick. - Components alone would force live-reload to walk all entities, and lose the "what are a Warbird's defaults?" answer.
- Template is shared (1 per type); components are per-entity (N). No duplication on the hot path.
- Network sync is automatic via Zay-ES — clients see effective instance values without any template awareness.
- Ephemeral runtime state (current velocity, cooldowns, last-shot time) → component only, no template.
- Arena-global state (map file, arena name, zone config) → read from
SettingsSystemdirectly. - Per-player / per-client state (keybinds, HUD preferences) → not arena-scoped; client-side.
- Add the field to the appropriate
*Configrecord inapi/src/main/java/infinity/config/. - Confirm (or add) the per-entity component in
api/src/main/java/infinity/es/.... - Have the spawn system project template → component.
- Consumer reads the component (never the template).
See ShipConfig / ShipStat in api/src/main/java/infinity/config/ for the canonical shape, and ADR-0002 for the full rationale this page summarises.