Scriptable bot framework for Diablo II 1.14d. Write bots in TypeScript, inject via DLL, hot-reload on save.
User Scripts import { createBot } from "diablo:game" yield* move.walkTo(x, y) ──────────────────────────────────────────────────────── SDK (diablo:game) Game object, Unit classes, UnitCollection, aether/sdk/ createBot/createService, generator-based tick system ──────────────────────────────────────────────────────── Daemon WebSocket server, TS→JS bundler, hot-reload watcher packages/daemon/ Resolves imports, transpiles, serves bundles to DLL ──────────────────────────────────────────────────────── Native DLL SpiderMonkey 60 (ES2015 modules), D2 hooks, packages/native/ Zig cross-compiled to x86 Windows, dbghelp proxy loader -
Native DLL (
packages/native/) — Zig-based DLL that hooks into the game loop. Embeds SpiderMonkey 60 for JavaScript execution. Exposes ~40 native bindings (diablo:native) for game state, unit iteration, movement, skills, and interaction. -
Daemon (
packages/daemon/) — Node.js WebSocket server. Bundles TypeScript entry points with all dependencies, transpiles via SWC, and serves them to the DLL. Watches for file changes and pushes hot-reloaded bundles. -
SDK (
sdk/) — TypeScript library exported asdiablo:game. Provides theGameobject, typedUnitclasses (PlayerUnit,Monster,ItemUnit,ObjectUnit,Missile,Tile),UnitCollectionwith iteration/filtering,createBot/createServicepatterns, and generator-based tick control. -
User Scripts (
scripts/) — Bot entry points. UsecreateBotto define a generator function that runs one step per game tick.yieldpauses until next tick,yield*delegates to sub-generators. Services provide reusable behaviors (movement, attack, pickit).
# Prerequisites: Zig 0.15+, Node.js 20+, Wine (for macOS) # Build the native DLL cd packages/native zig build -Doptimize=ReleaseSmall # Start the daemon cd packages/daemon npm run build && node dist/index.js # Run the game with injection export GAME_DIR=~/path/to/diablo2 bash packages/native/run.sh// scripts/main.ts import { createBot, uiFlags } from "diablo:game" import { Movement } from "./services/movement.js" export default createBot('farmer', function*(game, services) { const move = services.get(Movement) while (true) { if (!game.inGame) { yield; continue } // Walk to waypoint const wp = game.findPreset(2, 119) if (wp) yield* move.walkTo(wp.x, wp.y) // Interact const obj = game.objects.find(o => o.classid === 119) if (obj) game.interact(obj) yield* game.delay(3000) } })yield— pause until next game tick (~40ms)yield*— delegate to a sub-generator (e.g.yield* move.walkTo(x, y))yield* game.delay(ms)— wait N milliseconds worth of game tickscreateService— define reusable service objects with DI viaservices.get(Token)game.objects / game.monsters / game.items— lazy unit collections withfind,filter,closest
| Category | Functions |
|---|---|
| State | getArea, getAct, getDifficulty, inGame, getTickCount |
| Player | getUnitX/Y, getUnitHP/MP, getUnitStat, meGetCharName |
| Units | unitCount, unitAtIndex, unitValid, unitGetX/Y/Mode/ClassId/Stat/Name/Area/Flags |
| Monsters | monGetSpecType, monGetEnchants |
| Items | itemGetQuality/Flags/Location/Code |
| Objects | tileGetDestArea |
| Actions | clickMap, move, selectSkill, castSkillAt, interact, say |
| Map | getExits, findPath, findPreset |
| UI | getUIFlag, getSkillLevel |
| Package | Description |
|---|---|
packages/native | Zig DLL — game hooks, SpiderMonkey 60, native bindings |
packages/daemon | Node.js — WebSocket server, TS bundler, hot-reload |
packages/spidermonkey | SM60 ESR — CMake cross-build for MinGW |
packages/protocol | Shared message types for DLL↔daemon communication |
sdk/ | TypeScript SDK — diablo:game module |
scripts/ | User bot scripts |
- Generator-based tick system — no async/await, pure ES2015 generators bound to game ticks
- Hot-reload — save a file, bot restarts with new code instantly
- Headless mode — run without rendering for faster execution
- A* pathfinding — built-in pathfinder using collision grid data
- Unit enumeration — typed access to all game units (players, monsters, objects, items, missiles, tiles)
- Preset search — find waypoints, exits, and special objects via DRLG preset data
- Service DI —
createServicepattern with lazy instantiation and hot-reload safety