Clean-room architecture
The clean-room four-layer stack, module list, and build roadmap — the design north-star.
Mission: A modular, super-configurable, monetizable DayZ survivor-bot product that beats DayZ Expansion AI on every axis, with an optional LLM/Rust brain (dynamic personalities, dialogue, memory, relationships) layered on a fast scripted reflex core that also runs standalone without the LLM — exactly like the competitor, but cleaner. Game-agnostic brain + per-game bridge for multi-game later.
TL;DR — headline takeaways
- De-god the entity: their 11.8k-line
eAIBasebecomes our thin sensor/intent shim — all brains move out-of-process into a game-agnostic Rust core with a per-game bridge. - Two-tier brain by design: a deterministic Rust reactive tier (10–20 Hz) is a COMPLETE standalone product that already beats Expansion; the LLM tier is opt-in goal/dialogue/memory on top and removable without breaking anything.
- Win every scripted axis with data: relationship MATRIX + reputation vs their hardcoded
IsFriendlycascade; utility/BT scored intents vs fixed XML FSM; persistent convergent aim vs memoryless Gaussian; parametric steered formations vs enum-toggle flanking. - Configurability is the moat: hot-reload + serde-default migrations +
Option<T>inheritance + per-feature opt-in (vanilla server runs ZERO code), with an EAI-parity numeric tier to convert migrators and an LLM persona tier they structurally cannot express. - Ship order: MVP = walk+spawn+combat+factions (no LLM, full parity, cleaner) → dynamic reputation → LLM brain → productize; DEFER survival-misc + vehicle driving as their own milestones.
- Respect the risk: ranged combat through DayZ's brittle weapon FSM is the load-bearing, highest-bug-surface module — keep firing server-authoritative, drop their desync/teleport hacks, prove the no-LLM fallback in CI.
1. Competitor module map (DayZ Expansion AI)
| # | Subsystem | What it does | Core engine APIs | Data-driven? | Complexity | MVP? |
|---|---|---|---|---|---|---|
| 1 | core-bot / eAIBase | The god-entity. eAIBase : PlayerBase = a fake networked player; the engine grants inventory, anim/locomotion, ragdoll, damage, netsync; perception→decision→actuation bolted on. ~11.8k LOC. | PlayerBase/DayZPlayerImplement, CommandHandler, AimingModel, RaycastRV, AIWorld navmesh, netsync+RPC | Partial: FSM topology in XML; thresholds hardcoded | High | Yes (chassis to reuse) |
| 2 | Locomotion | Per-anim-tick body movement: navmesh path → locomotion inputs. Obstacle pinball + 4m teleport "unbug" hack. ~2500 LOC. | OverrideMovementSpeed/Angle, SetCurrentMovement, GetCommand_Move, AIWorld.FindPath | Barely — magic numbers in code | High | Yes |
| 3 | Navigation | A→B pathing; vault/climb/ladder/door/swim via poly flags. Roads graph mostly dead. | AIWorld.FindPath/RaycastNavMesh, PGFilter, PGPolyFlags | Low; costs hardcoded | High | Yes |
| 4 | Behavior FSM | Hierarchical XML FSM, per-tick state: idle/follow/flank/fight/reload/bandage. ~23 states. No planning/learning. | Enforce VM, GetCommand_*, weapon/inventory APIs, RaycastRV | Structure=XML (hot-reload); decisions hardcoded | High | Yes |
| 5 | Perception / Targeting | Sense entities, score continuous threat, rank, track with LOS+decay; squad shares discovery. | RaycastRV (LOS), SceneGetEntitiesInBox, FOV/dot math | Partial JSON; threat curves = magic numbers across 14 files | High | Yes |
| 6 | Combat | Fight like a player through the SAME weapon/melee pipelines: aim w/ human error, real WeaponManager.Fire, recoil/ammo/jam/mag, ballistics + bullet-drop. | WeaponManager.Fire, weapon FSM, StartCommand_Melee2, ProcessDirectDamage | Moderate; AI "personality" = scattered magic numbers | High (most load-bearing) | Yes |
| 7 | Groups & Formations | Ordered squad (leader=idx0) + faction + waypoints + 12 geometric formations (leader-anchored 4×4 matrix). | vector matrix math, typename reflection, FileSerializer | Composition=JSON; geometry/factions=code | Low / Med-High | Yes |
| 8 | Factions | Pairwise asymmetric friend/foe + behavioral traits. No central matrix; IsFriendly() hardcoded per class. | class-attribute registry, typename reflection, net-sync hashed id | Partial: membership=JSON; relations+roster hardcoded | Low-Moderate | Yes |
| 9 | Patrols / Spawn | Data-driven population: waypoint/roaming/object patrols, proximity triggers, load balancing, despawn/respawn. | Trigger/SetCollisionSphere, CreateObjectEx, CallQueue, Timer, JSON loader | Extremely (~50 fields/patrol) | High | Yes |
| 10 | Settings / Config | Operator JSON: global knobs, roaming whitelist, patrol defs + overrides, load-balancing caps. | JsonFileLoader, StringToEnum, selective RPC sync | Highly data-driven; NO hot-reload; hand-coded migrations | Medium | Yes |
| 11 | Survival-misc | Bots reuse vanilla UserActions/modifiers/symptoms/bleeding/vehicle commands — "lives like a player". | ActionManagerBase, GameInventory, StartCommand_Vehicle, CarScript | Lightly — mostly hardcoded | Mixed (driving=High) | Defer |
2. Our clean-room modular architecture
2.0 The core architectural bet
Expansion's fatal flaw is the god-object: eAIBase is an 11.8k-line PlayerBase
subclass mixing perception, pathfinding, ladder bugs, emotes, melee, inventory, and netsync.
We reject that. Our entity is a thin actuator/sensor shim with one stable contract:
- Sensor snapshot OUT — visible entities, threats, self-state, inventory, nav context.
- Intent IN — move-to, aim-at, fire, use-item, board, say.
Everything above that boundary lives out of the hot per-frame path. The brain is a separate Rust process (game-agnostic) with two tiers:
- Reactive tier (deterministic utility/BT, 10–20 Hz, <100 ms): aim, take-cover, reload, evade — the no-LLM fallback. A complete product on its own.
- Deliberative tier (LLM, async, 0.5–2 Hz): goals, squad tactics, dialogue, relationships, memory — strictly optional, opt-in.
2.1 Four-layer stack
LAYER D — LLM DELIBERATIVE BRAIN (optional, async 0.5–2 Hz)
personas · goal selection · squad cognition · dialogue ·
relationships/reputation · memory · narrative director
→ emits STRUCTURED INTENTS onto the blackboard. If absent, Layer C runs the show.
LAYER C — RUST REACTIVE BRAIN (game-agnostic, deterministic, 10–20 Hz)
ECS world-model · perception/threat · utility-AI/BT reflexes · steering ·
path-corridor · combat profile · group tactics · relationship matrix ·
spawn director · config engine → consumes snapshots, produces intents. Headless-testable.
LAYER B — REST/IPC BRIDGE (per-game, stable contract)
sensor snapshot ↑ · intent ↓ · batched, budgeted, stall-tolerant · versioned schema
LAYER A — IN-ENGINE ENFORCE AGENT RUNTIME (DayZ-specific, thin)
entity shim (PlayerBase subclass) · sensor sampler · intent executor ·
engine-glue commands (move/aim/fire/board) · reflex raycasts · netsync · spawn host2.2 Module list
Layer A — In-Engine Enforce Agent Runtime (the "chassis", DayZ-specific)
| Module | Responsibility |
|---|---|
A1 · ObAgentEntity | Thin PlayerBase subclass: free inventory/anim/ragdoll/damage/netsync. No brain logic. Only engine handles + sensor/intent boundary (~1–2k LOC glue, not 11.8k). |
| A2 · Sensor Sampler | Budgeted per-tick snapshot: nearby entities (shared spatial grid), self-state, inventory, nav context, reflex raycasts. |
| A3 · Intent Executor | Apply brain intents → engine commands: move/orient/stance/aim/fire/reload/board/use/say. No UserAction-manager hack. |
| A4 · Engine-Glue Move Command | ObCommandMove: read next path point, push speed/angle/heading/stance into anim graph. No SetPosition teleport hack. |
| A5 · Combat Glue | Drive WeaponManager.Fire + weapon FSM + Melee2; ballistics/bullet-drop/shot recon + noise. Drop client-fire RPC desync hack. |
| A6 · Spawn/Lifecycle Host | Create/delete entities, deferred one-per-frame spawn, ground-snap, water filter, persistence. No per-spawn Timer churn. |
| A7 · Reflex Safety Net | Cheap engine raycasts surviving a bridge stall: collision-avoid, ground-clamp, fall-safety; can hold last intent. |
Layer B — Bridge
| Module | Responsibility |
|---|---|
| B1 · Transport | Local-loopback IPC/REST, batched, FPS-budgeted, backpressure-aware. One round-trip per brain tick, not per bot per frame. |
| B2 · Schema/Contract | Versioned SensorSnapshot/Intent/Blackboard types — the game-agnostic boundary; a per-game bridge implements only this. |
Layer C — Rust Reactive Brain (game-agnostic, the standalone product)
| Module | Responsibility |
|---|---|
| C1 · World-Model (ECS) | Data-oriented store: per-agent Perception (TargetBelief), self-state, squad refs. |
| C2 · Threat & Sensing | Data-driven threat curves (RON/JSON: FOV, sense range, weapon-lethality, decay, faction matrix). Budgeted LOS. |
| C3 · Reactive Decision (utility/BT) | Typed HSM/BT + utility scorer: engage, cover, reload, unjam, evade-grenade, investigate. The no-LLM fallback. |
| C4 · Steering | Pure-pursuit along path + velocity smoothing + context-steering/light RVO → single (heading, speed) vector. |
| C5 · Path-Corridor Mgr | Typed PathRequest/PathResult, funnel/string-pull smoothing, Ok/Blocked/Unreachable enum, hot-reloadable costs. |
| C6 · Combat Profile | Declarative CombatProfile per archetype. Persistent convergent aim-error (PD/Kalman, panic, suppress). |
| C7 · Group Tactics | Formation trait (parametric slots) + leader isometry; boids separation/cohesion; role assignment (flank/suppress/hold). |
| C8 · Relationship Engine | Config faction registry + dynamic matrix (FactionId,FactionId)→Relation + per-actor reputation mutating from events with decay. |
| C9 · Spawn Director | Global tick over a player quadtree; budget scaled by player count + density + time-of-day + recent combat (L4D-style). |
| C10 · Config Engine | serde #[serde(default)] auto-backfill + Option<T> inheritance + typed flag arrays + file-watcher atomic hot-reload. |
Layer D — LLM Deliberative Brain (optional, opt-in)
| Module | Responsibility |
|---|---|
| D1 · Cognition / Goal Selection | Low-cadence world summary → goals/plans. Structured intents to blackboard. |
| D2 · Squad Cognition | Group-brain: per-member intents, formation choice by terrain/threat, leader succession. |
| D3 · Dialogue & Persona | Contextual NL chatter, callouts, taunts, parley/surrender, per-bot personality. |
| D4 · Relationship/Reputation Policy | Slow strategic posture: grudges, truces, pre-emptive hostility; mutates C8's matrix. |
| D5 · Memory | Per-bot/per-faction episodic memory of encounters. (Nonexistent in competitor.) |
| D6 · Narrative Director | Reads server events, spawns thematically appropriate named patrols with intent + backstory + difficulty. |
2.3 Integration seam
The blackboard is the single seam: Layer C always writes it; Layer D optionally overrides high-level goals. Remove Layer D entirely and the product still ships full reactive AI — the no-LLM fallback guarantee, enforced architecturally, not by convention.
3. Where we are "в разы круче"
The rule everywhere: the LLM only sets goals / mutates slow state / produces dialogue at low cadence. The Rust reactive tier owns all twitch decisions and runs fully without it. Disabling D degrades richness, never function.
| Area | Competitor (scripted) | Obscurum reactive (no LLM) | Obscurum + LLM |
|---|---|---|---|
| Factions/relationships | brittle if-cascade, 14 hardcoded classes, no memory | data-driven matrix + reputation + event standing w/ decay | runtime authored: pre-emptive hostility, parley, grudge/redemption arcs |
| Decision-making | fixed XML FSM | utility/BT scored intents, hot-swappable, headless-testable | high-level cognition, novel-situation reasoning, ambush planning |
| Squad tactics | geometric slots + 3-value enum | steered slots (no wall-clip) + Rust role assignment | LLM picks who flanks/suppresses, formation by terrain, leader succession |
| Dialogue/social | random-int "manners/emotes" | optional canned barks by threat state | contextual NL dialogue, taunts, surrender/parley, persona |
| Memory | none — amnesiac | short belief decay (investigate last-known) | episodic memory: grudges, recognition, learned habits |
| Combat feel | memoryless per-shot Gaussian | persistent convergent aim + archetypes | combat intent: when to melee, fall back, regroup |
| Spawn/population | static count→patrols table | director budget (count+density+time+combat) | event-aware named, intent-driven, backstoried squads |
4. Configurability — an order of magnitude beyond theirs
Their config is the ceiling of their AI. Ours is a thin host over a far higher ceiling.
Fix every competitor config sin: hot-reload (file-watcher + atomic swap); serde-default
migrations (not a 32-version if(version<N) ladder); Option<T> inheritance
(zone→faction→global, not -1 sentinels); typed flag arrays (not pipe-delimited strings).
Modular + opt-in per feature (the monetization & "vanilla runs nothing" requirement): each module (combat, groups, factions, patrols, driving, LLM brain) independently toggleable; a fully-off server runs zero Obscurum code paths.
Two-tier schema: EAI-parity numeric tier (accuracy/damage/spawn-density/formations/loadouts)
- LLM persona tier (a patrol points at persona + system-prompt + tool-set + goal + memory + relationship graph).
Monetization tie-in: free tier = reactive AI + EAI-parity config; paid tiers gate the LLM brain, persona packs, narrative director, cross-game bridges. Opt-in per feature maps cleanly to entitlements.
5. Build roadmap
Principle: ship a complete reactive product first (no LLM), then layer the brain. Each milestone ends green before the next.
- Milestone 0 — Boundary & Bridge: A1 shim · A2 sampler · A3 executor · B1/B2 schema · C1 world-model · C10 config. Gate: bot spawns, streams a snapshot to Rust, executes a move-to intent round-trip; headless tests for C1/C10.
- Milestone 1 — MVP: walk + spawn + basic combat + factions. A4 move-glue + A7 reflex + C4 steering + C5 path (engine FindPath, string-pull, no teleport) · C2 threat + spatial grid + LOS budget · A5 combat-glue + C3 engage/reload + C6 CombatProfile + convergent aim · C8 static relationship matrix · C7 parametric formations · C9 director + A6 host + parity patrol config. Gate: full parity, cleaner, no LLM.
- Milestone 2 — Reactive polish & dynamic relationships: C8 dynamic reputation + decay · C7 role assignment + terrain-aware collapse · C3 expanded reflexes · full two-tier config + opt-in toggles. Gate: emergent betrayal/aggro-propagation; vanilla-off = zero overhead.
- Milestone 3 — The Brain (LLM, optional): D1 cognition · D2 squad · D3 dialogue · D4 relationship policy · D5 memory. Gate: LLM on → richer; LLM off → Milestone-2 product intact (fallback proven by test).
- Milestone 4 — Productize: D6 narrative director · persona packs · entitlement gating · live config UI · game-agnostic hardening (formalize B2, spec a second-game bridge).
DEFER (explicitly): survival-misc layer; roads hierarchical graph; cross-squad/narrative/ second-game = M4. Never reuse the vanilla UserAction state machine as the brain — keep only the engine verb contract.
6. Riskiest / most-complex modules to respect
- Combat — ranged firing (A5 + C6): the most load-bearing AI feature, highest bug surface. Mitigation: strictly server-authoritative firing; isolate weapon-FSM glue behind A5 with heavy integration tests.
- Locomotion (A4 + C4): their 2500-LOC engine-fight capped by a
SetPositionteleport. Mitigation: thin engine-glue + A7 reflex net; deterministic Rust steering tested headless; never teleport. - Navigation (C5): engine
FindPathis free/correct, but off-roof recovery / vault-door-ladder / swim are raycast-and-pray. Mitigation: cleanBlocked/Unreachablesurfaced as a high-level replan; delete script A* + O(n) PQ. - Perception broad-phase + budget (A2 + C2): per-bot box query + global scan won't scale. Mitigation: one shared spatial structure, batch all bots, budgeted LOS.
- Spawn director scaling (C9): one global player-quadtree tick must be correct under high patrol counts + churn. Mitigation: single tick, budget model, isolated tests.
- Bridge under load + the no-LLM fallback seam (B1 + blackboard): prove Layer D is removable. Mitigation: budgeted one-round-trip transport; CI test running the full reactive product with Layer D disabled.
- Vehicle driving (deferred, flagged): its own milestone; never blocks the agent loop.
7. Engineering requirements (the quality bar EVERY module must meet)
A living checklist. Every module is reviewed against it; no module ships violating the 🔴 ones.
Design principles (foundational)
- Unified data flows — one canonical path:
SensorSnapshot → World-Model → reactive/LLM → Intent. No side-channels. - Single source of truth — all config/state has exactly one authoritative home.
- DRY — shared logic factored once: one config engine, threat curves table, parametric formation specs, faction matrix.
- Abstraction / OOP-by-traits — behaviors, formations, threat models, transports are
traits/interfaces, swappable; data-driven, not
if-cascades. - Modularity + per-feature opt-in — each module independently toggleable; a fully-off server runs zero code paths.
- Game-agnostic purity (🔴) — DayZ types NEVER leak into the Rust core. Enforced by crate
boundaries (separate
corevs per-gamebridge).
Non-functional (domain-critical for a SOLD server mod)
- 🔴 Performance budgets / scale — explicit per-tick CPU+RAM budgets; "N bots @ M players, no server-FPS regression"; profiled; budgeted LOS/spawn/bridge.
- 🔴 Resilience / fault isolation — our code must NEVER crash the operator's server. Graceful degradation (brain stall ⇒ last-intent), timeouts, backpressure, panics caught at the bridge boundary.
- 🔴 Security — LLM prompt-injection from in-game chat must be sanitized. Brain auth, tenant isolation (multi-server SaaS), zero RCE via config/persona, rate limiting.
- 🔴 Versioned contracts + migrations — bridge, config, and save schemas are semver-versioned with serde-default auto-migration.
- Determinism + testability — reactive tier is deterministic (same input ⇒ same output), seedable RNG, replay/record; fully headless-testable without DayZ.
- Persistence — bot memory / relationships / reputation survive restarts.
Process & maintainability
- Testing + CI — unit + integration + property tests + headless sim; full suite green on every commit before merge.
- Observability — structured logging, per-bot/per-server metrics, tracing.
- Extensibility — operators/3rd-parties add behaviors/personas/archetypes without forking.
- Config UX — validate config at load (fail loud at startup); sane defaults; presets; hot-reload.
- Docs — code docs + architecture + API + operator + modder docs. For a sold product, docs are a feature.
- Dependencies & licensing — minimal vetted deps; license compatibility (no GPL contamination); clean-room IP.
Most-forgotten, highest-impact: performance budgets, resilience (never crash the host), and LLM-chat prompt-injection. Easy to skip, fatal to a commercial product.