Pasarela
Pasarela WebSocket / JSON: las interfaces públicas que puede llamar el SDK de Python también las pueden llamar JS, C#, Go, Rust, páginas web o programas en otra máquina. Tres roles, con cliente JS y página de demostración incluidos; la latencia es la del carril rápido más ~1 ms.
La pasarela envuelve el carril rápido y el estado publicado en WebSocket / JSON. Las interfaces públicas del Catálogo de API que puede llamar el SDK de Python también las pueden llamar JS, C#, Go, Rust, páginas web, programas en otra máquina y LLM, con los mismos nombres de método y los mismos parámetros. La latencia es la del carril rápido más ~1 ms.
Lo más cómodo: en la página de inicio de Farsight, “Centro de control” → “Pasarela” → “Iniciar” (en esa misma tarjeta también puedes detenerla, reiniciarla, ver el log y abrir la página de demostración). Desde la línea de comandos:
python gateway/server.py # ws://127.0.0.1:8870/ws (el puerto está en ports.gateway de openwar3.json)
python gateway/server.py --open # lo mismo, y cuando el puerto ya escucha abre la página de demostración http://127.0.0.1:8870/demo
python gateway/server.py --host 0.0.0.0 # para la LAN: exige token automáticamente (bin/gateway/token.txt)
python gateway/server.py --allow-origin http://localhost:5173 # para que también se conecte tu propia página web
Conexión y roles
Dirección de conexión: ws://127.0.0.1:8870/ws?inst=9&role=dev (también puedes usar pid= en lugar de inst=; si hace falta token, añade &token=).
| Rol | Qué puede llamar | Ideal para |
|---|---|---|
dev | Todo: observación, comandos, control del juego, sandbox (cambiar el mundo con JASS), dibujar interfaz | Herramientas locales, mods de juego, compañeros |
player (con &player=N) | Observación, dar órdenes a las unidades del jugador N, dibujar interfaz; modo justo por defecto: solo ve lo que está en la visión del jugador N (&fair=0 lo desactiva) | Bots o LLM que juegan por un jugador |
observer | Solo lectura (el runtime rechaza directamente los comandos que envíe) | Espectadores, comentaristas, recogida de datos |
Lo que player no puede usar: el control del juego, como terminar la partida, cambiar la velocidad o pausar; players y enemy_ai_plan, que dejan ver las cartas de los demás; canvas.image, que hace que el proceso del juego abra archivos locales; y JASS. Las consultas que llevan número de jugador, como resources, tech o stats, solo pueden consultar el propio.
Cada conexión es una sesión y ocupa un carril rápido (el runtime tiene 16 en total). La pasarela admite como máximo 12 sesiones a la vez, para dejar algunos carriles a los Bots, los mods y Farsight. Al desconectarse solo se retira lo que dibujó esa sesión y sus atajos de teclado; lo que dibujaron otros programas no se toca.
Mensajes
Al conectar, lo primero que llega es hello: versión del protocolo, rol, ID del proceso del juego y la lista de métodos que ese rol puede llamar. Después, cada petición lleva un id y la respuesta lleva el mismo 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", "Comprar poción"], "kwargs": {"screen": [40, 300]}}
→ {"id": 4, "op": "subscribe", "state": {"hz": 4, "units": "mine"}, "events": true}
← {"type": "state", ...} {"type": "events", ...} a partir de aquí se envían continuamente
→ {"id": 5, "op": "overview"} la partida en una página: recursos, unidades por tipo, héroes, enemigos visibles, producción
→ {"id": 6, "op": "jass", "code": "call PingMinimapEx(0, 0, 3, 255, 0, 0, false)"} solo para dev
→ {"id": 7, "op": "api"} catálogo de métodos (también hay ping / unsubscribe)
- Parámetros de unidad: se escriben
{"unit": dirección}, donde la dirección es eladdrdel JSON de la unidad; puedes añadir"handle": [lo, hi]para comprobar que esa dirección no la ha reutilizado otra unidad. - Nombres de método: son los métodos públicos de Game, más
ui.*(button / choice / toast / hotkey / mouse / cursor…),canvas.*(text / panel / bar / image / circle / path / remove…) yjass.<nombre de función>(solo para dev). - Un cliente remoto no puede aportar funciones de callback: los clics y los atajos de teclado se reciben en los eventos enviados, y el evento
ui.clicklleva lakey. Ver Interfaz y entrada. - Si una llamada falla, solo se responde con error a esa llamada (
ok: falsemáserror) y la conexión sigue abierta; lo mismo si lo que se envía no es JSON. - Los campos del JSON de eventos coinciden con el Protocolo W3P, con campos de conveniencia adicionales (
spell,key,text,chat,button,player,mods).
También funciona por HTTP, útil para llamadas sueltas y para curl: GET /api?role=player lista el catálogo de métodos y POST /call con inst, role, method, args y kwargs hace una llamada. /call reutiliza la sesión: si el juego se reinicia y cambia de proceso, pasa automáticamente a una nueva, y las que llevan 10 minutos inactivas se cierran.
Clientes
JS (navegador o Node 22+, sin dependencias): 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", "Púlsame", { screen: [40, 300] }); // el último objeto plano = argumentos con nombre
ow.on("event:ui.click", (e) => console.log("Pulsado", e.key));
await ow.subscribe({ state: { hz: 2, units: "mine" }, events: true });
Con Node 20 / 21 hay que añadir --experimental-websocket. El ejemplo completo está en gateway/clients/js/example.mjs.
Página de demostración en el navegador http://127.0.0.1:8870/demo: la partida, la tabla de unidades propias, poner un botón en el juego y el flujo de eventos, todo en una página.
Otros lenguajes: basta con cualquier biblioteca de WebSocket + el JSON de arriba; no hace falta tocar la memoria compartida.
LLM: usa directamente el servidor MCP, que convierte las tareas habituales en herramientas listas para usar.
Medido
2026-09-25, verificación punto por punto conectada a una partida real, 16/16 (9 de la pasarela + 7 de MCP): handshake (rol dev, 121 métodos), units('me'), la partida en una página, aviso en pantalla, poner un botón; tras suscribirse, clic en ese botón dentro del juego → ui.click llega al cliente; JASS; pasar una unidad no válida solo da error en esa llamada; HTTP /call (rol observer).
También se probaron el cliente JS (Node) y la página de demostración: un botón puesto desde la web recibe un clic en el juego y el registro de eventos de la web recibe ui.click.
Seguridad
- Por defecto solo escucha en
127.0.0.1y no pide token (igual que Farsight). Si--hostno es una dirección local, exige token automáticamente;--authlo exige también en local. - Otros sitios web abiertos en el navegador no pueden conectarse: todas las conexiones que inicia un navegador llevan su origen (
Origin), y la pasarela solo acepta su propia página de demostración y las direcciones dadas con--allow-origin. Programas como Python, Node o curl no envían origen y se conectan con normalidad. Cuando solo escucha en local, además compruebaHost, lo que bloquea los ataques que hacen resolver un dominio externo a la máquina local. - El rol lo declara el propio cliente al conectar: en modo local es una convención, no una frontera de seguridad. En la Arena, el proceso árbitro decidirá qué rol recibe cada uno; ver Arena.