One runtime, one protocol, turning the game into a programmable environment
W3 Runtime is injected into the original game, where it captures the whole world, executes commands and reports results on the game thread. Your AI only has to say what to do, talking to it through a versioned shared-memory protocol.
Lower layers don't know upper layers exist
The interface layer contains not a single line of “should we fight” logic; brains never import each other and depend only on the SDK. That's what makes the Arena possible — the platform only needs the interface layer plus a referee, and anyone's brain can plug in.
The whole map, every 50 ms
The runtime captures everything in one pass on the game thread and pushes it into shared memory; clients read it directly instead of queueing on the game thread. A capture takes a median of 0.5–0.9 ms (100–120 units), and per-stage timings are always written into the world block header.
Players ×16
Gold, lumber, food and food cap, total gathered, race
Units ×1024
Type, owner, position, HP/mana, current order and target, what it's actually attacking, level/XP/skill points, each player's visibility of it
Unit details ×256
12 abilities (level, remaining cooldown), 8 buffs, 6 inventory slots; heroes first
Production table ×128
Train / research / build / upgrade: queue, total duration, elapsed time, whether blocked
Ground items ×256
Type, position, durability; events fire when picked up or used
Trees ×4096
Destructible positions and HP, refreshed every 2 seconds
Map
128-unit walkable / buildable grid, playable area, start locations; computed within seconds of game start
Time
Engine game clock, in-game time (day/night), game speed, whether a game is in progress
The runtime picks the path
Gathering, retreating, casting… each is just “make a unit do something,” yet each takes a different path inside the engine. All of that know-how lives in the runtime. You say what to do; it executes with a verified recipe and, in the same frame, reads back the order before and after as the receipt.
- Submit a batch at once, executed in the same frame
- Every command gets a receipt: status code + engine reason code + execution time
- Shift-queueing, waypoints, chained builds
- Queries: tech counts, feasibility, visibility, gold remaining, the computer opponent's attack target
Crossing processes was never the slow part
Shared-memory reads and writes take nanoseconds, and reading a snapshot takes ~0.05 ms. The old channel was slow because every request had to grab one machine-wide lock and then wait for the game's next message fetch (once per frame, 16–33 ms). The reference brain spent 93% of its wall-clock time waiting on it.
- Grab a machine-wide mutex
- Post a message to the game thread
- Wait for the game's next message fetch (once per frame)
- Wait for the completion event, release the lock
With 6 processes sharing it, throughput tops out at about 88 calls/s.
- Each client owns its own lane: one writer, one reader, no locks
- Execution happens inside the game thread's event dispatch (hundreds of times per second); with nothing submitted, the overhead is just a few integer comparisons
- 16 commands submitted at once all execute in the same dispatch; each drain has a 4 ms time budget
- Every command carries a deadline: after a pause and resume, expired commands never execute
Every command's receipt includes its execution time, and the lane header records the slowest command and how long the last drain took — so you can see exactly where the time goes.
| Tier | Channel | Latency | Used by | Status |
|---|---|---|---|---|
| 0 | Pushed snapshot + event stream | ~0.4 ms per read; a new one every 50 ms (adjustable down to 16 ms) | All bots | Verified |
| 1 | Fast lane | ~1 frame; median 0.06 ms with 6 concurrent processes, ~3000 calls/s throughput | SDK default | Verified |
| 2 | Control channel | 20–40 ms | Fallback, a few UI-type operations | Verified |
| 3 | Gateway (WebSocket / JSON) | Tier 1 + ~1 ms | Any language, browser pages, LLMs (MCP), another machine | Verified |
Measured (1.27 test instance, 2026-09-23 / 24)
Engineering note: for the first 3 minutes, every command was 1000× slower
After we added per-command execution time, we found that during the first few minutes of a game, every command from the second one in a batch onward took 4–10 ms, then suddenly dropped to a few microseconds at around 180 seconds of game time. The runtime's built-in game-thread sampler collected 1700 samples, and 93% of them landed in the runtime's own logging function — every line written opened and closed the log file synchronously, and at game start every engine order wrote a line. With debug logging off by default and logs flushed to disk asynchronously, even commands at second 14 of a game take only 4–8 µs.
We trust measured numbers, not guesses.
Every lane has a role
Ownership checks and vision filtering happen in the runtime — the engine's execution layer doesn't check unit ownership itself, so it has to be done here. Two AIs fighting each other is just two player lanes in the same game.
| Role | Can see | Can do |
|---|---|---|
| player | All own units + enemy and neutral units within vision (fair mode) | Command own units only Players, your bot |
| observer | The whole map | No commands; can query, control the camera and read the HUD Director, commentary, post-game review |
No guessing, no crashing
Versions 1.24–1.28 share the same engine structure, which suits “one runtime + multiple profiles.” 1.29 and later, as well as Reforged, use a different engine, and automatic compatibility isn't promised.
- Identify Read Game.dll's version resource and file hash, then pick a profile
- Symbol table Recipes reference symbol names, not raw numbers; each symbol carries its calling convention and argument shape
- Signature-scan fallback On unknown versions, scan for byte signatures at the start of functions, and use a match only if it's unique
- Startup self-check Each symbol is verified without side effects; capabilities that fail are marked unavailable
- Capability list When the SDK sees that a capability is unavailable, calling it raises a clear error instead of quietly returning 0
One bot's bug shouldn't crash the whole game
That's also why every AI runs in its own process — a null pointer inside the game process crashes the whole game, but when a separate process crashes, only that side stops.
| Mechanism | How | Status |
|---|---|---|
| Never drag down the game | Every game call is exception-guarded; each drain has a 4 ms time budget (high-resolution timer) | Shipped |
| Clients isolated from each other | One lane per client, each with its own quota; one stuck client doesn't block the others | Shipped |
| Expired means skipped | Every command carries a deadline; expired ones are only marked, never executed, and aren't replayed after a pause and resume | Shipped |
| Observable | Execution time for every command; per-stage timings for every capture written into the world block header | Shipped |
| Auto-reconnect | The SDK follows game restarts and process changes and reconnects automatically | Partial |
| Capability circuit breaker | A capability that fails N times in a row → marked unavailable and an event fires; other capabilities keep working | Planned |
Build your own things inside the game
Semantic commands let an AI play like a player; the extension layer lets you change what players see and experience — draw your own clickable UI, call every function map makers have. The two paths are split by whether they're safe in multiplayer.
- Text boxes, panels, progress bars, images, terrain-hugging circles, arrowed routes
- Anchored to units, world coordinates or screen positions; CJK fonts, rounded corners, translucency, any color
- Drawn by the runtime itself — no game objects created, no game state changed
- One line of Python per element, or go through HTTP, or write shared memory directly
- Buttons and choice cards are clickable and highlight on hover; drawn under the mouse cursor, and the game never receives the click that lands on one
- Spawn units, change stats, effects, boards, dialogs, sounds, camera, fog, weather…
- Farsight console, command line, HTTP, Python — the same script syntax everywhere
- Common effects in one line each: floating text, lightning links, range circles, portrait dialogue, full-screen filters
- In multiplayer, only read-only functions are allowed, to avoid desyncs
| Canvas | JASS display functions | |
|---|---|---|
| Who draws it | The runtime | The game itself |
| Multiplayer | Safe: drawn only on your own screen | Single-player only |
| Styling | Anything: fonts, rounded corners, translucency, images | Native game look |
| Follows things | Units / world coordinates / screen positions | Depends on the function |
| Cost | 0.2–0.35 ms per frame | ~13 ms per call |
What the player does goes straight into the event stream
The runtime reports player actions directly: which drawn button they clicked, which hotkey they pressed, where they clicked on the ground, who they selected, what spell they cast, and what they typed in the chat box. The game's own trigger events (entering regions, dialog buttons, arrow keys) can still be hooked with an empty trigger: register only the event, with no conditions or actions, then count how many times it has run.