simulation done

This commit is contained in:
Boki 2026-03-07 09:53:57 -05:00
parent 0e7de0a5f3
commit 05bbcb244f
55 changed files with 4367 additions and 756 deletions

180
docs/simulator.md Normal file
View file

@ -0,0 +1,180 @@
# 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