Docs Tools

Gateway

WebSocket-/JSON-Gateway: Die öffentlichen APIs, die das Python-SDK aufrufen kann, stehen auch JS, C#, Go, Rust, Browserseiten und Programmen auf anderen Rechnern offen. Drei Rollen, mit JS-Client und Demoseite für den Browser; die Latenz ist die der Schnellspur plus ca. 1 ms.

Das Gateway verpackt Schnellspur und gepushten Zustand als WebSocket / JSON. Die öffentlichen APIs aus dem API-Katalog, die das Python-SDK aufrufen kann, stehen damit auch JS, C#, Go, Rust, Browserseiten, Programmen auf anderen Rechnern und LLMs offen – mit denselben Methodennamen und Parametern. Die Latenz ist die der Schnellspur plus ca. 1 ms.

Am einfachsten: „Kontrollzentrum“ auf der Startseite von Farsight → Gateway → Starten (Stoppen, Neu starten, Logs ansehen und die Demoseite öffnen gehen ebenfalls über diese Karte). Über die Kommandozeile:

python gateway/server.py                 # ws://127.0.0.1:8870/ws (Port unter ports.gateway in openwar3.json)
python gateway/server.py --open          # wie oben, öffnet die Demoseite http://127.0.0.1:8870/demo, sobald der Port lauscht
python gateway/server.py --host 0.0.0.0  # fürs LAN: verlangt automatisch ein Token (bin/gateway/token.txt)
python gateway/server.py --allow-origin http://localhost:5173   # damit sich auch deine eigene Webseite verbinden kann

Verbindung und Rollen

Verbindungsadresse: ws://127.0.0.1:8870/ws?inst=9&role=dev (statt inst= geht auch pid=; wird ein Token verlangt, &token= anhängen).

RolleDarf aufrufenGeeignet für
devalles: Beobachten, Befehle, Spielsteuerung, Sandbox (Welt per JASS verändern), Oberfläche zeichnenlokale Tools, Gameplay-Mods, Begleiter
player (mit &player=N)Beobachten, Einheiten von Spieler N befehligen, Oberfläche zeichnen; standardmäßig im Fair-Modus, sieht nur, was in der Sicht von Spieler N liegt (&fair=0 schaltet das ab)Bots oder LLMs, die für einen bestimmten Spieler antreten
observernur lesen (die Runtime lehnt seine Befehle direkt ab)Zuschauen, Kommentar, Datenerfassung

player bekommt nicht: Spielsteuerung wie Spiel beenden, Tempo ändern oder Pausieren, players und enemy_ai_plan, die die verdeckten Karten der anderen zeigen, canvas.image, das den Spielprozess eine lokale Datei öffnen ließe, und JASS. Abfragen mit Spielernummer wie resources, tech und stats gehen nur für den eigenen Spieler.

Eine Verbindung ist eine Sitzung und belegt eine Schnellspur (die Runtime hat insgesamt 16). Das Gateway erlaubt höchstens 12 Sitzungen gleichzeitig, damit ein paar für Bots, Mods und Farsight frei bleiben. Beim Trennen wird nur entfernt, was diese Sitzung selbst gezeichnet hat, samt ihren Hotkeys; was andere Programme gezeichnet haben, bleibt.

Nachrichten

Nach dem Verbinden kommt zuerst hello: Protokollversion, Rolle, Prozess-ID des Spiels und die Liste der Methoden, die diese Rolle aufrufen darf. Danach trägt jede Anfrage eine id, und die Antwort trägt dieselbe id:

→ {"id": 1, "op": "call", "method": "units", "args": ["me"]}
← {"id": 1, "ok": true, "result": [{"addr": 123456, "type": "hpea", "owner": 0, "x": -4480, "y": 2120, "hp": 220, "hp_max": 220}]}

→ {"id": 2, "op": "call", "method": "move", "args": [[{"unit": 123456}], 100, 200]}
→ {"id": 3, "op": "call", "method": "ui.button", "args": ["shop", "Trank kaufen"], "kwargs": {"screen": [40, 300]}}
→ {"id": 4, "op": "subscribe", "state": {"hz": 4, "units": "mine"}, "events": true}
← {"type": "state", ...}    {"type": "events", ...}        danach laufend gepusht
→ {"id": 5, "op": "overview"}                             Lage auf einer Seite: Ressourcen, Einheitenzahlen, Helden, sichtbare Gegner, Produktion
→ {"id": 6, "op": "jass", "code": "call PingMinimapEx(0, 0, 3, 255, 0, 0, false)"}    nur für dev
→ {"id": 7, "op": "api"}                                  Methodenkatalog (außerdem ping / unsubscribe)
  • Einheitenparameter schreibst du als {"unit": Adresse}; die Adresse ist addr aus dem Einheiten-JSON. Optional mit "handle": [lo, hi], um zu prüfen, dass die Adresse nicht von einer anderen Einheit wiederverwendet wurde.
  • Methodennamen sind die öffentlichen Methoden von Game, dazu ui.* (button / choice / toast / hotkey / mouse / cursor …), canvas.* (text / panel / bar / image / circle / path / remove …) und jass.<Funktionsname> (nur für dev).
  • Callback-Funktionen lassen sich von entfernt nicht übergeben: Klicks und Hotkeys kommen über die Event-Pushes, das ui.click-Event trägt den key. Siehe Oberfläche & Eingabe.
  • Schlägt ein Aufruf fehl, betrifft die Antwort nur diesen einen (ok: false plus error); die Verbindung bleibt bestehen. Das gilt auch, wenn das Gesendete kein JSON ist.
  • Die Felder im Event-JSON entsprechen dem W3P-Protokoll, dazu kommen Komfortfelder (spell, key, text, chat, button, player, mods).

HTTP geht auch, praktisch für einzelne Aufrufe und curl: GET /api?role=player listet den Methodenkatalog, POST /call mit inst, role, method, args, kwargs ruft einmal auf. /call verwendet Sitzungen wieder: Startet das Spiel neu und läuft in einem neuen Prozess, wird automatisch eine neue Sitzung geöffnet; Sitzungen, die 10 Minuten untätig waren, werden geschlossen.

Clients

JS (Browser oder Node 22+, ohne Abhängigkeiten): gateway/clients/js/openwar3.mjs

import { OpenWar3, unit } from "./openwar3.mjs";

const ow = new OpenWar3("ws://127.0.0.1:8870/ws", { inst: 9, role: "dev" });
await ow.connect();
const mine = await ow.api.units("me");
await ow.api.move(mine.slice(0, 3).map(unit), 100, 200);
await ow.api.ui.button("hi", "Klick mich", { screen: [40, 300] });   // letztes einfaches Objekt = Keyword-Argumente
ow.on("event:ui.click", (e) => console.log("Geklickt:", e.key));
await ow.subscribe({ state: { hz: 2, units: "mine" }, events: true });

Node 20 / 21 braucht --experimental-websocket. Ein vollständiges Beispiel liegt in gateway/clients/js/example.mjs.

Demoseite für den Browser http://127.0.0.1:8870/demo: Lage, Tabelle der eigenen Einheiten, einen Button ins Spiel setzen, Event-Stream – alles auf einer Seite.

Andere Sprachen: Eine beliebige WebSocket-Bibliothek + das JSON oben genügt; Shared Memory musst du nicht anfassen.

LLMs: Nimm direkt den MCP-Server – er stellt die häufigen Aufgaben als fertige Tools bereit.

Gemessen

2026-09-25, Punkt für Punkt an einer echten Partie geprüft: 16/16 (Gateway 9 + MCP 7): Handshake (Rolle dev mit 121 Methoden), units('me'), Lage auf einer Seite, Bildschirmhinweis, Button setzen; nach dem Abonnieren den Button im Spiel angeklickt → ui.click wird zum Client gepusht; JASS; eine ungültige Einheit führt nur bei diesem einen Aufruf zu einem Fehler; HTTP /call (Rolle observer).

Auch der JS-Client (Node) und die Demoseite wurden getestet: Der von der Webseite gesetzte Button wurde im Spiel angeklickt, und das Event-Log der Webseite hat ui.click empfangen.

Sicherheit

  • Standardmäßig lauscht es nur lokal auf 127.0.0.1, ohne Token (wie Farsight). Ist --host keine lokale Adresse, wird automatisch ein Token verlangt; --auth verlangt es auch lokal.
  • Andere Websites im Browser kommen nicht rein: Verbindungen aus dem Browser tragen immer eine Herkunft (Origin); das Gateway akzeptiert nur seine eigene Demoseite und die mit --allow-origin angegebenen Adressen. Programme wie Python, Node oder curl senden keine Herkunft und verbinden sich ganz normal. Lauscht es nur lokal, prüft es zusätzlich Host und blockt so Angriffe, die eine externe Domain auf den lokalen Rechner auflösen lassen.
  • Die Rolle deklariert der Client beim Verbinden selbst: Im lokalen Modus ist sie eine Konvention, keine Sicherheitsgrenze. In der Arena muss der Schiedsrichter-Prozess entscheiden, wer welche Rolle bekommt, siehe Arena.