Gateway
Gateway WebSocket / JSON: as APIs públicas que o SDK em Python chama também podem ser chamadas de JS, C#, Go, Rust, páginas de navegador e programas em outra máquina. Três papéis, com cliente JS e página de demonstração no navegador incluídos; a latência é a da via rápida mais cerca de 1 ms.
O gateway empacota a via rápida e o estado enviado como WebSocket / JSON. As APIs públicas do catálogo da API que o SDK em Python chama podem ser chamadas de JS, C#, Go, Rust, páginas de navegador, programas em outra máquina e LLMs, com os mesmos nomes de método e parâmetros. A latência é a da via rápida mais cerca de 1 ms.
O jeito mais fácil: página inicial do Farsight, “Central de controle” → Gateway → Iniciar (parar, reiniciar, ver os logs e abrir a página de demonstração também ficam nesse cartão). Pela linha de comando:
python gateway/server.py # ws://127.0.0.1:8870/ws (a porta fica em ports.gateway no openwar3.json)
python gateway/server.py --open # o mesmo, e quando a porta já está escutando abre a página de demonstração http://127.0.0.1:8870/demo
python gateway/server.py --host 0.0.0.0 # para a rede local: exige token automaticamente (bin/gateway/token.txt)
python gateway/server.py --allow-origin http://localhost:5173 # para a sua própria página web também conseguir conectar
Conexão e papéis
Endereço de conexão: ws://127.0.0.1:8870/ws?inst=9&role=dev (também dá para usar pid= em vez de inst=; quando for preciso token, acrescente &token=).
| Papel | O que pode chamar | Indicado para |
|---|---|---|
dev | Tudo: observação, comandos, controle do jogo, sandbox (alterar o mundo via JASS), desenhar interface | Ferramentas locais, mods de jogabilidade, companheiros |
player (com &player=N) | Observação, comandar as unidades do jogador N, desenhar interface; modo justo por padrão, só enxerga o que está na visão do jogador N (&fair=0 desliga) | Bots ou LLMs que jogam no lugar de um jogador |
observer | Só leitura (o runtime rejeita direto os comandos que ele enviar) | Assistir, narrar, coletar dados |
O que player não recebe: controle do jogo, como encerrar a partida, mudar a velocidade ou pausar; players e enemy_ai_plan, que mostram as cartas dos outros; canvas.image, que faz o processo do jogo abrir arquivos locais; e JASS. Consultas que levam número de jogador, como resources, tech e stats, só podem consultar o próprio jogador.
Uma conexão é uma sessão e ocupa uma via rápida (o runtime tem 16 no total). O gateway aceita no máximo 12 sessões ao mesmo tempo, para deixar algumas vias para Bots, mods e o Farsight. Ao desconectar, só é removido o que essa sessão desenhou e as teclas de atalho dela; o que outros programas desenharam fica intacto.
Mensagens
Ao conectar, a primeira mensagem recebida é hello: versão do protocolo, papel, PID do processo do jogo e a lista de métodos que esse papel pode chamar. Depois disso, cada requisição leva um id, e a resposta volta com o mesmo 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 poção"], "kwargs": {"screen": [40, 300]}}
→ {"id": 4, "op": "subscribe", "state": {"hz": 4, "units": "mine"}, "events": true}
← {"type": "state", ...} {"type": "events", ...} daí em diante, envio contínuo
→ {"id": 5, "op": "overview"} resumo da partida numa página: recursos, contagem por tipo de unidade, heróis, inimigos visíveis, produção
→ {"id": 6, "op": "jass", "code": "call PingMinimapEx(0, 0, 3, 255, 0, 0, false)"} só para dev
→ {"id": 7, "op": "api"} catálogo de métodos (há também ping / unsubscribe)
- Parâmetros de unidade são escritos como
{"unit": endereço}, em que o endereço é oaddrdo JSON da unidade; dá para incluir"handle": [lo, hi]para conferir que esse endereço não foi reaproveitado por outra unidade. - Nomes de método são os métodos públicos de Game, mais
ui.*(button / choice / toast / hotkey / mouse / cursor…),canvas.*(text / panel / bar / image / circle / path / remove…) ejass.<nome da função>(só para dev). - Um cliente remoto não pode passar funções de callback: cliques e teclas de atalho chegam pelos eventos enviados, e o evento
ui.clicktraz akey. Veja Interface e entrada. - Se uma chamada der erro, só aquela chamada responde com erro (
ok: falsemaiserror); a conexão continua. O mesmo vale quando o que chega não é JSON. - Os campos do JSON de eventos são os mesmos do Protocolo W3P, com campos de conveniência adicionais (
spell,key,text,chat,button,player,mods).
HTTP também funciona, bom para chamadas avulsas e curl: GET /api?role=player lista o catálogo de métodos, e POST /call com inst, role, method, args e kwargs faz uma chamada. /call reaproveita a sessão: se o jogo for reaberto e o processo mudar, ele troca para uma nova automaticamente, e sessões paradas há 10 minutos são encerradas.
Clientes
JS (navegador ou Node 22+, zero dependências): 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", "Clique aqui", { screen: [40, 300] }); // o último objeto simples = argumentos nomeados
ow.on("event:ui.click", (e) => console.log("clicou em", e.key));
await ow.subscribe({ state: { hz: 2, units: "mine" }, events: true });
No Node 20 / 21, acrescente --experimental-websocket. O exemplo completo está em gateway/clients/js/example.mjs.
Página de demonstração no navegador http://127.0.0.1:8870/demo: a situação da partida, a tabela das nossas unidades, um botão posto dentro do jogo e o fluxo de eventos, tudo numa página.
Outras linguagens: qualquer biblioteca de WebSocket + o JSON acima bastam, sem tocar na memória compartilhada.
LLMs: use direto o servidor MCP, que transforma as tarefas comuns em ferramentas prontas.
Medições
2026-09-25, conectado a uma partida real, verificação item por item 16/16 (9 do gateway + 7 do MCP): handshake (121 métodos no papel dev), units('me'), resumo da partida, aviso na tela, pôr um botão; depois de assinar, clicar nesse botão dentro do jogo → ui.click enviado ao cliente; JASS; passar uma unidade inválida só gera erro naquela chamada; HTTP /call (papel observer).
O cliente JS (Node) e a página de demonstração no navegador também foram testados: o botão posto pela página foi clicado dentro do jogo, e o log de eventos da página recebeu ui.click.
Segurança
- Por padrão, só escuta na máquina local
127.0.0.1e não exige token (igual ao Farsight). Quando--hostnão é um endereço local, o token passa a ser exigido automaticamente;--authexige token também na máquina local. - Outros sites abertos no navegador não conseguem conectar: toda conexão iniciada por um navegador leva a origem (
Origin), e o gateway só aceita a própria página de demonstração e os endereços passados em--allow-origin; programas como Python, Node e curl não enviam origem e conectam normalmente. Quando escuta só na máquina local, ele também confere oHost, bloqueando ataques que fazem um domínio externo resolver para a máquina local. - O papel é declarado pelo próprio cliente ao conectar: no modo local, ele é uma convenção, não uma fronteira de segurança. Na Arena, quem decide o papel de cada um é o processo árbitro; veja Arena.