# Nexus — Architecture Overview ## What Is This A modular C# automation framework for POE2. The system reads game memory, builds a structured game state, runs AI systems (combat, navigation, threat assessment), and emits input commands. A separate trade pipeline monitors the trade site via a Node.js daemon and executes buy flows. When the real game isn't available, a standalone **Simulator** replaces the memory layer with a procedural game world — same bot systems, same interfaces, zero game dependency. ## Solution Structure ``` Nexus.sln (net8.0-windows10.0.19041.0) │ ├── Core Layer (shared types, no dependencies) │ └── Nexus.Core │ ├── Infrastructure Layer (reads from external sources) │ ├── Nexus.GameOffsets Pure offset structs for memory reading │ ├── Nexus.Memory Process memory reading (RPM, pattern scan) │ ├── Nexus.Screen Screen capture, OCR, grid detection │ ├── Nexus.Log Client.txt game log watcher │ └── Nexus.Input Win32 SendInput / Interception driver │ ├── Data Layer (transforms raw data into typed game state) │ └── Nexus.Data EntityMapper, EntityClassifier, GameDataCache, MemoryPoller, GameStateEnricher │ ├── Logic Layer (AI systems that decide what to do) │ ├── Nexus.Systems ThreatSystem, MovementSystem, CombatSystem, ResourceSystem, LootSystem │ ├── Nexus.Engine BotEngine (orchestrator), AreaProgressionSystem, MovementKeyTracker │ └── Nexus.Pathfinding NavigationController, A* PathFinder │ ├── Game Interaction Layer (acts on the game) │ ├── Nexus.Game Window focus, input sending, clipboard │ ├── Nexus.Items Item parsing via Sidekick │ ├── Nexus.Inventory Stash/inventory grid management │ ├── Nexus.Navigation Minimap-based real-time navigation │ └── Nexus.Trade Trade daemon IPC (Node.js Playwright) │ ├── Orchestration Layer (top-level coordination) │ ├── Nexus.Bot BotOrchestrator, Trade/Mapping/Crafting executors │ └── Nexus.Ui Avalonia 11.2 desktop GUI (entry point) │ └── Testing Layer └── Nexus.Simulator Standalone game world for bot testing ``` ## Dependency Flow ``` Nexus.Core │ ├── Nexus.GameOffsets ──→ Nexus.Memory ──→ Nexus.Data ──→ Nexus.Engine │ │ │ ├── Nexus.Input │ Nexus.Systems │ │ │ ├── Nexus.Screen ◄───────────────────────────────┘ │ ├── Nexus.Game │ ├── Nexus.Log │ │ │ ├── Nexus.Pathfinding ◄─────────────────────────────────────────┘ │ ├── Nexus.Items, Nexus.Inventory, Nexus.Navigation, Nexus.Trade │ ├── Nexus.Bot (consumes all above) │ ├── Nexus.Ui (DI hub, entry point, consumes all) │ └── Nexus.Simulator (Core, Data, Systems, Pathfinding — NOT Memory/Input/Screen) ``` ## Data Flow — Per Tick ``` ┌─────────────────────────────────────────────────────────────────────┐ │ MemoryPoller Thread (60Hz hot / 10Hz cold) │ │ │ │ Hot tick (4 RPM calls): │ │ Camera matrix, Player position, Player vitals, Loading state │ │ │ │ Cold tick (full hierarchical read): │ │ Entity tree traversal → classification → EntitySnapshot[] │ │ Terrain grid, Skills, Quests, UI elements │ │ │ │ Writes to GameDataCache (volatile references, lock-free) │ └────────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ BotEngine Logic Thread (25Hz default) │ │ │ │ 1. Read latest GameState from cache │ │ 2. GameStateEnricher → NearestEnemies, ThreatMap, DangerLevel │ │ 3. Clear ActionQueue │ │ 4. NavigationController.Update() → path, DesiredDirection │ │ 5. Run systems in priority order: │ │ ThreatSystem (50) → MovementSystem (100) → │ │ AreaProgressionSystem (199) → NavigationSystem (200) → │ │ CombatSystem (300) → ResourceSystem (400) → LootSystem (500) │ │ 6. ActionQueue.Resolve() → conflict resolution │ │ 7. ExecuteActions() → IInputController │ └────────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ IInputController (Win32 SendInput or Interception driver) │ │ │ │ WASD keys (scan codes), mouse movement (Bézier curves), │ │ skill casts, flask presses, clicks │ └─────────────────────────────────────────────────────────────────────┘ ``` ## Action Resolution Systems submit actions to a shared `ActionQueue`. The queue resolves conflicts: | Action Type | Behavior | |-------------|----------| | FlaskAction | Always passes through | | MoveAction (priority ≤ 10) | Urgent flee — blocks CastAction | | MoveAction (priority > 10) | Normal move — allows CastAction alongside | | CastAction | Passes unless blocked by urgent flee | | Other (Key, Click, Chat) | Always passes through | Priority values: lower number = higher priority. ThreatSystem uses priority 5 for emergency flee (blocks all casting). ## System Priority Table | Priority | System | Purpose | |----------|--------|---------| | 50 | ThreatSystem | Emergency flee on High/Critical danger | | 100 | MovementSystem | Soft avoidance via inverse-square repulsion | | 199 | AreaProgressionSystem | Quest-driven area traversal and transitions | | 200 | NavigationSystem | Submits NavigationController's direction | | 300 | CombatSystem | Skill rotation, target selection, kiting | | 400 | ResourceSystem | Flask usage on life/mana thresholds | | 500 | LootSystem | Item pickup (stub) | ## Thread Model | Thread | Rate | Responsibility | |--------|------|----------------| | MemoryPoller | 60Hz hot, 10Hz cold | Read game memory → GameDataCache | | BotEngine Logic | 25Hz | Run AI systems → emit actions | | Render (Simulator only) | vsync | ImGui + Veldrid drawing | | Trade Daemon | event-driven | Node.js Playwright → stdin/stdout JSON IPC | | Log Watcher | 200ms poll | Client.txt → area/whisper/trade events | Cross-thread safety: GameDataCache uses `volatile` references. No locks — writer (MemoryPoller) atomically swaps reference types, readers (BotEngine) get consistent snapshots. ## Simulator Architecture When the real game isn't available, `Nexus.Simulator` replaces the memory pipeline: ``` ┌─────────────────────────────────────────────────────┐ │ Nexus.Simulator.exe │ │ │ │ ┌──────────┐ GameState ┌──────────────────┐ │ │ │ SimWorld │───────────────►│ GameDataCache │ │ │ │ (terrain, │ SimPoller + │ (same as prod) │ │ │ │ enemies, │ StateBuilder └────────┬─────────┘ │ │ │ player) │ │ │ │ └─────┬────┘ ┌────────▼─────────┐ │ │ │ │ Bot Systems │ │ │ │◄─────────────────────│ (unchanged) │ │ │ │ SimInputController └──────────────────┘ │ │ │ │ │ ┌─────▼───────────────────────────────────────┐ │ │ │ ImGui + Veldrid Renderer (isometric 2D) │ │ │ └─────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────┘ ``` Bot systems don't know they're in a simulation — they see identical `GameState` objects and emit actions to `IInputController`. ## Key Design Decisions | Decision | Rationale | |----------|-----------| | Immutable records (GameState, EntitySnapshot) | Thread-safe sharing without locks | | Priority-based ActionQueue | Natural conflict resolution without hardcoded if-else | | Two-tier memory polling (hot/cold) | Balance responsiveness (position at 60Hz) with CPU cost (entities at 10Hz) | | Scan codes over virtual keys | Games read hardware scan codes, not VK codes | | Separate Memory → Data layers | Memory reads raw bytes; Data interprets and classifies. Clean testability. | | IInputController interface | Swap real Win32 input for simulated input without changing bot logic | | BFS exploration + A* pathfinding | BFS finds what to explore; A* finds how to get there | | CharacterProfile auto-detection | Automatically applies combat/flask settings per character name | | External daemons (Trade, OCR) | Isolate browser/OCR concerns from main process |