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:
- FlaskActions always pass through
- Get highest-priority MoveAction and CastAction
- If MoveAction priority ≤ 10 (urgent flee): include move, block cast
- Else: include both move and cast
- 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