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

6 KiB

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

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).

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:

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