poe2-bot/docs/core.md
2026-03-07 09:53:57 -05:00

158 lines
6 KiB
Markdown

# Nexus.Core — Shared Types & Abstractions
The foundation layer. Every other project depends on Core. Contains no logic — only types, interfaces, configuration, and utilities.
## GameState
Central immutable snapshot updated once per tick. All systems read from this; none mutate it.
```
GameState
├── Timing: TickNumber, DeltaTime, TimestampMs
├── Player: PlayerState
│ ├── CharacterName, Position, Z, HasPosition
│ ├── Life/Mana/ES: Current, Total, Percent (derived)
│ ├── ActionId (actor animation state)
│ ├── Skills: SkillState[] (cooldowns, charges, cast state)
│ ├── Flasks: FlaskState[] (charges, active, cooldown)
│ └── Buffs: Buff[] (name, duration, charges, isDebuff)
├── Entities: EntitySnapshot[] (all game entities)
├── HostileMonsters: EntitySnapshot[] (alive monsters, filtered)
├── NearbyLoot: EntitySnapshot[] (world items, filtered)
├── NearestEnemies: EntitySnapshot[] (sorted by distance — enriched)
├── Terrain: WalkabilitySnapshot (grid, offsets)
├── Area: AreaHash, AreaLevel, CurrentAreaName
├── UI: IsLoading, IsEscapeOpen, CameraMatrix
├── Quests: ActiveQuests[], UiQuests[], Quests[] (enriched with paths)
├── Threats: ThreatMap (zone buckets, centroid, rarity flags)
├── Danger: DangerLevel (Safe/Low/Medium/High/Critical — enriched)
└── GroundEffects: GroundEffect[] (hazard positions)
```
## EntitySnapshot
Immutable record for any game entity:
- **Identity**: Id (uint), Path, Metadata, Category (EntityCategory enum)
- **Spatial**: Position (Vector2), Z, DistanceToPlayer
- **Combat**: IsAlive, LifeCurrent/Total, IsTargetable, ThreatLevel, Rarity, ModNames
- **State**: ActionId, IsAttacking, IsMoving, Components (HashSet)
- **Special**: TransitionName/State, ItemBaseName, IsQuestItem, LabelOffset
**EntityCategory** (17 types): Unknown, Player, Monster, Npc, WorldItem, Chest, Shrine, Portal, AreaTransition, Effect, Terrain, MiscObject, Waypoint, Door, Doodad, TownPortal, Critter
**MonsterRarity**: White, Magic, Rare, Unique
**MonsterThreatLevel**: None, Normal, Magic, Rare, Unique
## Actions
Polymorphic action system. All inherit from `BotAction` with a `Priority` field.
| Action | Fields | Purpose |
|--------|--------|---------|
| MoveAction | Direction (Vector2) | WASD movement |
| CastAction | SkillScanCode, TargetScreenPos or TargetEntityId | Skill usage |
| FlaskAction | FlaskScanCode | Flask consumption |
| KeyAction | ScanCode, Type (Press/Down/Up) | Raw keyboard |
| ClickAction | ScreenPosition, Type (Left/Right/Middle) | Mouse click |
| ChatAction | Message | Send chat message |
| WaitAction | DurationMs | Delay |
## ActionQueue
Manages conflict resolution between competing system outputs.
**Resolve() rules:**
1. FlaskActions always pass through
2. Get highest-priority MoveAction and CastAction
3. If MoveAction priority ≤ 10 (urgent flee): include move, **block** cast
4. Else: include both move and cast
5. All other action types pass through
## ISystem Interface
```csharp
public interface ISystem
{
int Priority { get; } // Execution order (lower = first)
string Name { get; }
bool IsEnabled { get; set; }
void Update(GameState state, ActionQueue actions);
}
```
**SystemPriority constants**: Threat=50, Movement=100, Navigation=200, Combat=300, Resource=400, Loot=500
## IInputController Interface
Abstraction over Win32 input. Two implementations: SendInputController (vanilla), InterceptionInputController (driver).
```csharp
public interface IInputController
{
bool IsInitialized { get; }
void KeyDown(ushort scanCode);
void KeyUp(ushort scanCode);
void KeyPress(ushort scanCode, int holdMs = 50);
void MouseMoveTo(int x, int y);
void SmoothMoveTo(int x, int y); // Bézier curve interpolation
void LeftClick(int x, int y);
void RightClick(int x, int y);
void MiddleClick(int x, int y);
void LeftDown(); void LeftUp();
void RightDown(); void RightUp();
}
```
## WalkabilitySnapshot
Grid-based terrain with offset support for infinite expansion:
```csharp
public record WalkabilitySnapshot
{
public int Width, Height;
public byte[] Data; // Row-major; 0=wall, nonzero=walkable
public int OffsetX, OffsetY; // Absolute grid coords of top-left corner
public bool IsWalkable(int gx, int gy)
{
var lx = gx - OffsetX; // Absolute → local
var ly = gy - OffsetY;
if (out of bounds) return false;
return Data[ly * Width + lx] != 0;
}
}
```
Coordinate conversion: `WorldToGrid = 23f / 250f ≈ 0.092`
- World → Grid: `gx = (int)(worldX * WorldToGrid)`
- Grid → World: `worldX = gx / WorldToGrid`
## Configuration
**BotConfig** — Static bot parameters:
- Tick rates: LogicTickRateHz=60, MemoryPollRateHz=30
- Movement: SafeDistance=400, RepulsionWeight=1.5, WaypointReachedDistance=80
- Humanization: MinReactionDelayMs=50, MaxReactionDelayMs=150, ClickJitterRadius=3, MaxApm=250
**CharacterProfile** — Per-character settings:
- Skills (8 slots: LMB, RMB, MMB, Q, E, R, T, F) with priority, cooldown, range, target selection
- Flasks (thresholds, scan codes, cooldown)
- Combat (global cooldown, attack/safe/kite ranges)
**SkillProfile** — Per-skill configuration:
- InputType (KeyPress/LeftClick/RightClick/MiddleClick)
- TargetSelection (Nearest/All/Rarest/MagicPlus/RarePlus/UniqueOnly)
- RequiresTarget, IsAura, IsMovementSkill, MaintainPressed
- MinMonstersInRange (AOE threshold)
## Utilities
- **WorldToScreen.Project()** — Matrix projection: world coords → screen coords via camera matrix
- **TerrainQuery.HasLineOfSight()** — Bresenham line walk on walkability grid
- **TerrainQuery.FindWalkableDirection()** — Rotates direction ±45°/90°/135°/180° to find clear path
- **Helpers.Sleep()** — Task delay with ±10% variance
- **DangerLevel**: Safe, Low, Medium, High, Critical
- **ThreatMap**: TotalHostiles, CloseRange(<300), MidRange(300-600), FarRange(600-1200), ClosestDistance, ThreatCentroid, HasRareOrUnique