En esta página
Docs Herramientas

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=).

RolQué puede llamarIdeal para
devTodo: observación, comandos, control del juego, sandbox (cambiar el mundo con JASS), dibujar interfazHerramientas 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
observerSolo 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 el addr del 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…) y jass.<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.click lleva la key. Ver Interfaz y entrada.
  • Si una llamada falla, solo se responde con error a esa llamada (ok: false más error) 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.1 y no pide token (igual que Farsight). Si --host no es una dirección local, exige token automáticamente; --auth lo 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 comprueba Host, 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.