# Nexus.Simulator — Standalone Game World ## Purpose Test bot systems (combat, navigation, threat assessment) without the real game. Replaces the memory-reading pipeline with a procedural game world. Bot systems run unmodified — they see identical `GameState` objects and emit actions to `IInputController`. ## Architecture ``` SimWorld (game tick loop) │ ├── SimPoller (60Hz background thread) │ ├── FlushToWorld() → transfer input to SimWorld │ ├── Tick(dt) → advance simulation │ ├── SimStateBuilder.Build() → SimWorld → GameState │ └── Push to GameDataCache │ ├── SimInputController (captures bot actions) │ ├── WASD → MoveDirection vector (45° isometric conversion) │ ├── Skills → QueueSkill(scanCode, targetWorldPos) │ ├── Mouse → track position, screen↔world conversion │ └── Flash timers for input visualization │ ├── Bot Logic Thread (60Hz) │ ├── GameStateEnricher.Enrich(state) │ ├── All 6 systems: Threat, Movement, Navigation, Combat, Resource, Loot │ ├── NavigationController.Update() │ └── ExecuteActions() → SimInputController │ └── Render Thread (ImGui + Veldrid) ├── TerrainRenderer (diamond cells, isometric) ├── EntityRenderer (player, enemies, health bars) ├── EffectRenderer (melee cones, AOE circles, projectile lines) ├── PathRenderer (A* waypoints) ├── InputOverlayRenderer (keyboard + mouse state) └── DebugPanel (system toggles, stats, spawn controls) ``` ## SimWorld — Game Loop ### Tick (dt-based, 60Hz) ``` 1. CheckAndExpandTerrain() → expand when player within 50 cells of edge 2. MovePlayer(dt) → WASD direction × speed × dt, collision with terrain 3. ProcessSkills() → dequeue skill casts, dispatch by scan code 4. UpdateProjectiles(dt) → move, check terrain/enemy collisions 5. UpdateEffects(dt) → decay visual effects (0.3s duration) 6. UpdateEnemies(dt) → AI state machine per enemy 7. UpdateRespawns(dt) → cull far enemies, spawn new groups ``` ### Terrain - Procedural: all walkable with scattered obstacles (rock clusters, wall segments, pillars) - 500×500 initial grid, `WorldToGrid = 23/250` - **Infinite expansion**: Expands 250 cells per side when player within 50 cells of edge - Preserves existing data via array copy with offset adjustment ### Player - Position (Vector2), Health/Mana with regen (5 HP/s, 10 MP/s) - Move speed: 400 world units/s - Collision: slide-along-X / slide-along-Y fallback if direct move blocked ### Skills | Scan Code | Type | Behavior | |-----------|------|----------| | Q (0x10), R (0x13) | AOE | Damage all enemies within 250u of target position | | E (0x12), T (0x14) | Projectile | Spawn projectile, 1200 speed, 800 range, 80u hit radius | | LMB, RMB | Melee | 150u cone, 120° angle from player toward target | Base damage: 200 per hit. Configurable via SimConfig. ### Enemy AI ``` State machine per SimEnemy: Idle → wander randomly within 200u of spawn, new target every 2-5s │ player within 600u (aggro range) ▼ Chasing → move toward player at 75% player speed │ player within 100u (attack range) ▼ Attacking → stand still, deal 30 damage every 1.5s │ player escapes attack range ▼ back to Chasing │ health ≤ 0 ▼ Dead → visible for 2s → queue for respawn (5s delay) ``` ### Enemy Spawning - **Groups**: 3-7 enemies per spawn, leader keeps rolled rarity, rest are Normal - **Rarity distribution**: 70% Normal, 20% Magic, 8% Rare, 2% Unique - **HP multipliers**: Magic=1.5×, Rare=3×, Unique=5× base (200) - **Spawn ring**: 800-2000 world units from player - **Direction bias**: ±90° cone ahead of player's movement direction - **Culling**: Remove enemies > 3000u from player - **Population**: Maintain 25 enemies, spawn new groups as needed ## Bridge Layer ### SimPoller Replaces MemoryPoller. Background thread at 60Hz: 1. `FlushToWorld()` — transfer accumulated input 2. `world.Tick(dt)` — advance simulation (dt clamped to 0.1s max) 3. `SimStateBuilder.Build()` — convert to GameState 4. Push to GameDataCache (same fields as production) ### SimStateBuilder Converts SimWorld state → GameState: - Each SimEnemy → EntitySnapshot (with rarity, threat level, AI state, HP) - SimPlayer → PlayerState (position, vitals, skills) - Camera matrix: orthographic projection (12800×7200 world units → 2560×1440 screen) ### SimInputController Implements IInputController, captures actions instead of sending Win32 input: - WASD → direction vector (with 45° isometric inversion) - Skills → `SimWorld.QueueSkill(scanCode, worldPos)` - Mouse → screen position tracking, inverse camera transform for world coords - Input visualization: flash timers for keyboard/mouse overlay ## Rendering ### ViewTransform (Isometric Camera) 45° counter-clockwise rotation matching the game's camera: ``` World → Grid: gx = worldX × WorldToGrid Grid → Screen: rx = (gx - gy) × cos(45°) ry = -(gx + gy) × cos(45°) Screen = canvasOrigin + viewOffset + (rx, ry) × zoom ``` ### Renderers | Renderer | Draws | |----------|-------| | TerrainRenderer | Diamond cells (rotated grid), explored overlay, minimap | | EntityRenderer | Player (green circle), enemies (colored by rarity), health/mana bars | | EffectRenderer | Melee cones (red triangle fan), AOE circles (blue), projectile lines (cyan) | | PathRenderer | Cyan waypoint lines and dots from A* path | | InputOverlayRenderer | Keyboard (3 rows: 1-5, QWERT, ASDF) + mouse (L/R/M buttons) | | DebugPanel | Pause/speed, player stats, enemy counts, system toggles, threat info | ### VeldridImGuiRenderer Custom ImGui backend for Veldrid 4.9.0 + D3D11: - HLSL shaders compiled at runtime via D3DCompiler P/Invoke - Dynamic vertex/index buffers, font texture from ImGui atlas - Alpha blending pipeline with scissor rect support ## SimConfig ``` Terrain: 500×500, WorldToGrid=23/250, ExpandThreshold=50, ExpandAmount=250 Player: Speed=400, HP=1000, MP=500, HPRegen=5/s, MPRegen=10/s Enemies: Count=25, Aggro=600u, Attack=100u, Speed=75%, HP=200, Damage=30 Spawning: Ring=800-2000u, Groups=3-7, Cull=3000u Skills: Melee=150u/120°, AOE=250u, Projectile=1200speed/800range, Damage=200 Rarity: Normal=70%, Magic=20%, Rare=8%, Unique=2% Simulation: SpeedMultiplier=1×, Pauseable ``` ## Running ``` dotnet run --project src/Nexus.Simulator ``` Dependencies: Core, Data, Systems, Pathfinding, ImGui.NET, Veldrid, Veldrid.StartupUtilities Does NOT depend on: Memory, Input, Screen, Game, Bot, Ui, Trade