Mostly vibe-coded with Claude.
A modern rewrite of D2Bot - a Diablo II bot manager. Built with .NET 10 and React, hopes to provide full D2BS compatibility with a clean web-based interface.
![]() Profiles - manage bot instances with live status, run stats, and bulk actions | ![]() Items - search muled items with DC6-rendered sprites and D2 tooltips |
![]() Equipment & inventory - live gear, inventory, and stash | ![]() Stats & skills - attributes and skill allocation |
![]() Quests & waypoints - per-character progression | ![]() Analytics - lifetime kills and time spent per area |
Download the latest release from the Releases page. Two versions are available:
| Version | Size | Requirements |
|---|---|---|
| Self-contained | Larger | Windows 10/11 (x64) — just run, no prerequisites |
| Framework-dependent | Smaller | Windows 10/11 (x64) + .NET 10 Runtime |
To get started:
- Download the
.exefor your preferred version - Place it in a directory of your choice and run it — the web UI opens automatically in a desktop window
- Configure your Diablo II path and base path in Settings
- Add profiles and start botting
The web UI is also available at http://localhost:5000 from any browser.
For headless/server use (no GUI window), run with --headless. See Command Line for all options.
App settings are stored in d2botng.json next to the exe (server, Discord, display, base path). Game and botting-framework configuration (game directory, D2BS path, inject DLLs, game version, health thresholds, cleanup) lives per framework, managed on the Frameworks tab: a built-in Default framework is created on first run and new profiles use it automatically. Add more frameworks (e.g. different kolbot installs or D2 versions) and a per-profile framework picker appears so you can assign them.
Bot data files are stored under the base path in data/ng/ (protobuf JSON format). The base path defaults to the exe directory but can be changed in Settings:
| File | Purpose |
|---|---|
<base path>/data/ng/profiles.json | Bot profiles |
<base path>/data/ng/keylists.json | CD key lists |
<base path>/data/ng/frameworks.json | Frameworks (game/d2bs/dll/version bundles) |
<base path>/data/ng/proxies.json | Proxies |
<base path>/data/ng/characters.json | Character snapshots from running bots |
<base path>/data/ng/schedules.json | Schedule configs |
<base path>/data/ng/patches.json | Memory patches (version-specific) |
<base path>/data/ng/captures.db | SQLite: character captures from newer d2bsng builds, with items broken out so they can be searched by stat |
<base path>/images/ | Item PNGs from the D2BS saveItem message |
captures.db is derived state, not a record: a bot re-reports its whole character on the next game it enters, so deleting it costs only the kill and area-time totals of profiles that are not currently running.
Legacy D2Bot data files (JSONL format in data/) are automatically migrated to data/ng/ on first startup. Migration also runs when the base path is changed from the Settings page.
- Non-destructive - Original
data/files are left intact - Per-file - Each file is migrated independently; existing files in
data/ng/are skipped. Delete a specific file to re-migrate it - IRC profiles dropped - Legacy IRC-type profiles are not migrated
- Legacy API migrated -
server.jsonusers and profiles are imported into Legacy API settings when no existing configuration is found - Settings not migrated - Other settings did not exist in the legacy format;
d2botng.jsonis created fresh - Frameworks migrated - On first run of a frameworks-aware build, a
Defaultframework is created from the previous game/engine settings (install path, game version, retention, health thresholds) and assigned to all existing profiles - Format change - Legacy JSONL (one JSON object per line) is converted to protobuf JSON (single document with typed wrapper messages)
No manual steps are required. To force re-migration of a specific file, delete it from data/ng/ and restart.
Character Viewer, Item Search and SOCKS5 Proxy require the d2bsng engine (the modern C++ D2BS rewrite that reports character-state telemetry and supports proxy hooking). They stay inactive on legacy D2BS; everything else works on both.
- Character Viewer(d2bsng) - Live per-character equipment, inventory, stash, stats, skills, and quest/waypoint progression, plus analytics: lifetime monster kills and time spent per area. Newer engine builds report each item's raw stats rather than a finished tooltip, so gear is rendered from the game's own tables — and holding Ctrl over an item swaps the tooltip for a breakdown: the range each modifier could have rolled within, the item level that decided them, and one labelled block per gem or rune instead of a merged total.
- Item Search(d2bsng) - Search every character's gear by modifier, not just by name: "at least two resistances over 30", "any Amazon skill", "a Shako with 4 sockets". The ~1,200 searchable modifiers are derived from the game's own
ItemStatCosttable rather than written out by hand, so they are worded as the game words them. Conditions can be grouped with at-least-N and NOT, filtered by base item, type, tier, quality, runeword, item level and requirements, and the results sorted by clicking any modifier on them. - SOCKS5 Proxy(d2bsng) - Per-profile SOCKS5 proxy routing with a central Proxies tab for management, bulk import, and live connection testing.
- Web UI - React frontend with Tailwind CSS, dark Diablo-inspired theme
- Remote Access - Password-protected web interface accessible from anywhere
- Real-time Updates - gRPC streaming for live profile status, console output, item drops
- Item Rendering - DC6 sprite rendering with proper D2 color palettes and socket overlays
- Discord Integration - Slash commands for remote control (/list, /status, /start, /stop, /restart, /mule, /schedule, /identify) and webhooks for items, console, and announcements
- Key Management - Visual dashboard with round-robin rotation, usage tracking, hold/release
- Scheduling - Automated profile scheduling with time-based rules (supports overnight ranges)
- Drag & Drop - Reorder profiles and groups with drag-and-drop
- Dual Mode - GUI (WebView2 desktop app) or headless server
- Crash Safety - Job objects auto-kill child game processes if the manager crashes
- Console - Real-time console output with source filtering, regex search, D2 color codes
- Legacy API - Backwards-compatible D2Bot# HTTP API for external tools (Limedrop, D2BS scripts) with AES session auth, webhooks, and game action scheduling
- Usage Statistics - Anonymous, opt-out counts of how the app is configured (how many profiles, which features are in use, Windows version) plus a periodic heartbeat. Never a name, path, key or address. See Usage Statistics
Edit d2botng.json or use the Settings page in the UI:
{
"server": {
"host": "0.0.0.0",
"port": 5000,
"password": "your-secret"
}
}When a password is set, the web UI will prompt for it on connection.
The Discord bot password is separate from the UI password — configure it independently in the Discord settings section.
{
"discord": {
"enabled": true,
"token": "your-bot-token",
"serverId": "123456789"
}
}Use the Test Discord button in the Settings page to verify your configuration.
| Command | Description |
|---|---|
/list | List all profiles with status |
/status <profile|all> | Detailed profile status with stats |
/start <profile|all> | Start profile(s) |
/stop <profile|all> | Stop profile(s) |
/restart <profile|all> | Restart profile(s) |
/mule <profile|all> | Trigger mule run |
/schedule <enable|disable> <profile|all> | Control scheduling |
/identify <password> | Authenticate for privileged commands |
Privileged commands (start, stop, restart, mule, schedule) require /identify first when a server password is set.
Official releases report anonymous usage to help decide what to work on. Turn it off in Settings → General → Usage Statistics; the switch applies immediately, to both the manager and the next game launched, with no restart.
What is sent is counts and yes/no answers — never a name, path, CD key, account or address:
- Once per start: how many profiles, keys, schedules and frameworks exist, how many of them use each feature (proxies, Discord, scheduling), the game versions configured, and the machine's Windows version, core count, memory and whether it is running under Wine.
- Every 12 hours: how many profiles are running, and how long the manager has been up.
Installs are counted by a hash of machine identifiers, so a returning install is not counted twice. The hash is derived on the fly and never stored.
Builds you compile yourself send nothing at all — the reporting key is baked in at build time from a secret that is not in this repository, and without it the whole feature is inert. D2BOTNG_ANALYTICS_HOST points a build at a different ingest host.
D2BotNG.exe [options]
--headless Run as server only (no GUI window)
--dev-ui Proxy UI requests to Vite dev server
Full compatibility with D2BS:
- Same command-line arguments (
-d2c,-d2x,-handle,-profile) - WM_COPYDATA IPC messaging
- DLL injection (LoadLibraryW remote thread)
- Memory patches for various D2 versions
- d2bs.ini generation with game paths and CD keys
- All D2BS message types supported (heartbeat, status, console, items, key rotation, etc.)
Note: Built for x64, but still injects the 32-bit D2BS into the 32-bit game (it resolves the game's
LoadLibraryaddress across the bitness boundary).
- Windows 10/11 (x64)
- .NET 10 SDK
- Node.js 20+
# Build frontendcd src/D2BotNG.UI
npm install
npm run build
# Build and run backendcd ../D2BotNG
dotnet runThe web UI will be available at http://localhost:5000.
# Terminal 1 - Vite dev server with hot reloadcd src/D2BotNG.UI
npm run dev
# Terminal 2 - Backend with UI proxycd src/D2BotNG
dotnet run -- --dev-uiThe Vite dev server runs on port 4200, and the backend proxies UI requests to it in --dev-ui mode.
The same gates CI runs on every pull request. SkipUIBuild matters for the C# ones: the app project builds the frontend by default, which the backend checks do not need.
# C#
dotnet build src/D2BotNG/D2BotNG.csproj -p:SkipUIBuild=true
dotnet test tests/D2BotNG.Tests/D2BotNG.Tests.csproj -p:SkipUIBuild=true
dotnet format D2BotNG.sln --verify-no-changes
dotnet jb inspectcode D2BotNG.sln --project=D2BotNG --properties:SkipUIBuild=true --severity=WARNING
# TypeScriptcd src/D2BotNG.UI
npm run build
npx eslint src --max-warnings 0
npx prettier --check "src/**/*.{ts,tsx,css}"dotnet build -p:RunFormat=true formats the solution before compiling, and -p:RunInspect=true writes an inspection report to src/D2BotNG/obj/inspect.sarif. Close the app first — a running D2BotNG.exe holds its own bin/ directory open and the build cannot replace it.
Build produces a single D2BotNG.exe with the UI and all game assets embedded.
cd src/D2BotNG
# Self-contained — bundles .NET runtime, no prerequisites on target machine
dotnet publish -c Release --self-contained
# Framework-dependent — smaller exe, requires .NET 10 runtime installed
dotnet publish -c Release --no-self-containedOutput: bin/Release/net10.0-windows/win-x64/publish/D2BotNG.exe
protos/ # Protobuf service definitions (source of truth)
src/
D2BotNG/ # .NET 10 backend
Services/ # gRPC service implementations
Engine/ # Profile lifecycle, scheduling
Windows/ # Win32 interop, DLL injection, IPC
Data/ # Protobuf JSON persistence (data/ng/)
Capture/ # Character captures: ingest, SQLite storage, stat search
Rendering/ # DC6 sprite decoding
Legacy/ # D2Bot# API compatibility (middleware, handler, models, migration)
UI/ # WinForms + WebView2 host
D2BotNG.UI/ # React 18 frontend
src/
features/ # Page components per feature
components/ # UI component library + layout
stores/ # Zustand state stores
hooks/ # React Query mutations
lib/ # gRPC client, auth, rendering
generated/ # Protobuf-generated TypeScript types
tests/
D2BotNG.Tests/ # xUnit — contract and invariant tests
Resources/ # DC6 sprites, palettes, fonts
| Layer | Technology |
|---|---|
| Backend | .NET 10, C# 13, ASP.NET Core, gRPC, Serilog |
| Frontend | React 18, TypeScript, Vite 6, Tailwind CSS |
| State | Zustand (real-time events), TanStack React Query (mutations) |
| Communication | gRPC-Web via Connect-RPC |
| Desktop | WebView2, WinForms, system tray |
| Windows | P/Invoke, WM_COPYDATA IPC |
The backend manages Diablo II game processes through Win32 APIs:
- Launch - Creates a suspended game process, applies memory patches, resumes, injects D2BS.dll
- Communicate - D2BS scripts send messages back via WM_COPYDATA (JSON payloads)
- Monitor - Heartbeat tracking detects hung processes, crash recovery auto-restarts
- Stream - All state changes broadcast to connected web clients via a single gRPC server-stream
The frontend connects to a single StreamEvents gRPC call and receives all updates in real-time. Mutations (create, update, delete) return empty responses - the UI updates arrive through the event stream.
See LICENSE file.





