188 lines
12 KiB
Markdown
188 lines
12 KiB
Markdown
# 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 |
|