На этой странице
Документация Инструменты

Шлюз

Шлюз WebSocket / JSON: публичный API, доступный из Python SDK, можно вызывать из JS, C#, Go, Rust, со страницы в браузере или из программы на другой машине. Три роли, в комплекте JS-клиент и демо-страница для браузера; задержка — быстрая полоса плюс около 1 ms.

Шлюз оборачивает быструю полосу и публикуемое состояние в WebSocket / JSON. Публичные методы Python SDK из каталога API можно вызывать из JS, C#, Go, Rust, со страницы в браузере, из программы на другой машине и из LLM — с теми же именами методов и параметрами. Задержка — быстрая полоса плюс около 1 ms.

Проще всего: главная страница Farsight «Центр управления» → Шлюз → «Запустить» (остановка, перезапуск, логи и открытие демо-страницы — на той же карточке). Из командной строки:

python gateway/server.py                 # ws://127.0.0.1:8870/ws (порт — ports.gateway в openwar3.json)
python gateway/server.py --open          # то же самое, а когда порт начнёт слушать, открывает демо-страницу http://127.0.0.1:8870/demo
python gateway/server.py --host 0.0.0.0  # для локальной сети: токен требуется автоматически (bin/gateway/token.txt)
python gateway/server.py --allow-origin http://localhost:5173   # чтобы подключаться могла и ваша собственная веб-страница

Подключение и роли

Адрес подключения: ws://127.0.0.1:8870/ws?inst=9&role=dev (вместо inst= можно указать pid=; если нужен токен, добавьте &token=).

РольЧто можно вызыватьДля чего
devВсё: наблюдение, команды, управление игрой, песочница (JASS, меняющий мир), отрисовка интерфейсаЛокальные инструменты, игровые моды, компаньоны
player (с &player=N)Наблюдение, команды юнитам игрока N, отрисовка интерфейса; по умолчанию честный режим — видно только то, что в обзоре игрока N (&fair=0 — выключить)Бот или LLM, играющие за конкретного игрока
observerТолько чтение (рантайм сразу отклоняет его команды)Наблюдение за матчем, комментирование, сбор данных

Роли player недоступны: управление игрой — завершение игры, смена скорости, пауза; players и enemy_ai_plan, которые раскрывают чужие карты; canvas.image, из-за которого процесс игры открыл бы локальный файл; и JASS. Запросы с номером игрока, такие как resources, tech и stats, работают только для своего игрока.

Одно подключение — один сеанс, он занимает одну быструю полосу (всего в рантайме их 16). Одновременно шлюз держит не больше 12 сеансов, чтобы несколько полос оставалось ботам, модам и Farsight. При отключении убирается только то, что нарисовал сам этот сеанс, и его горячие клавиши; нарисованное другими программами остаётся.

Сообщения

Сразу после подключения приходит hello: версия протокола, роль, идентификатор процесса игры и список методов, доступных этой роли. Дальше в каждом запросе передаётся id, а ответ приходит с тем же 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", "Купить зелье"], "kwargs": {"screen": [40, 300]}}
→ {"id": 4, "op": "subscribe", "state": {"hz": 4, "units": "mine"}, "events": true}
← {"type": "state", ...}    {"type": "events", ...}        дальше приходят постоянно
→ {"id": 5, "op": "overview"}                             обстановка на одной странице: ресурсы, число юнитов по типам, герои, видимые враги, производство
→ {"id": 6, "op": "jass", "code": "call PingMinimapEx(0, 0, 3, 255, 0, 0, false)"}    только для dev
→ {"id": 7, "op": "api"}                                  каталог методов (есть ещё ping / unsubscribe)
  • Юнит в аргументах задаётся как {"unit": адрес}, где адрес — это addr из JSON юнита; можно добавить "handle": [lo, hi], чтобы проверить, что этот адрес не занял уже другой юнит.
  • Имена методов — это публичные методы Game, а также ui.* (button / choice / toast / hotkey / mouse / cursor…), canvas.* (text / panel / bar / image / circle / path / remove…) и jass.<имя_функции> (только для dev).
  • Передать функцию-обработчик удалённо нельзя: клики и горячие клавиши приходят в потоке событий, событие ui.click содержит key. См. Интерфейс и ввод.
  • Ошибка в одном вызове возвращается только для этого вызова (ok: false и error), соединение не рвётся; то же самое, если прислали не JSON.
  • Поля событий в JSON совпадают с протоколом W3P, плюс удобные поля (spell, key, text, chat, button, player, mods).

Работает и HTTP — удобно для разовых вызовов и curl: GET /api?role=player выдаёт каталог методов, POST /call с inst, role, method, args, kwargs выполняет один вызов. /call переиспользует сеансы: если игру перезапустили и сменился процесс, автоматически открывается новый сеанс, а сеансы, простаивающие 10 минут, закрываются.

Клиенты

JS (браузер или Node 22+, без зависимостей): 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", "Нажми меня", { screen: [40, 300] });     // последний простой объект = именованные аргументы
ow.on("event:ui.click", (e) => console.log("Нажато:", e.key));
await ow.subscribe({ state: { hz: 2, units: "mine" }, events: true });

В Node 20 / 21 нужен флаг --experimental-websocket. Полный пример — в gateway/clients/js/example.mjs.

Демо-страница в браузере http://127.0.0.1:8870/demo: обстановка, таблица наших юнитов, кнопка, которую можно поставить в игру, поток событий — всё на одной странице.

Другие языки: хватит любой библиотеки WebSocket и JSON, показанного выше, — трогать общую память не нужно.

LLM: используйте сразу MCP-сервер — частые задачи в нём уже оформлены как готовые инструменты.

Замеры

2026-09-25, по пунктам на живом матче, 16/16 (шлюз — 9 пунктов, MCP — 7): рукопожатие (у роли dev — 121 метод), units('me'), обстановка на одной странице, подсказка на экране, кнопка; после подписки клик по этой кнопке в игре → ui.click доходит до клиента; JASS; неверный юнит даёт ошибку только для этого вызова; HTTP /call (роль observer).

JS-клиент (Node) и демо-страница в браузере тоже проверены: по кнопке, поставленной с веб-страницы, кликнули в игре, и журнал событий страницы получил ui.click.

Безопасность

  • По умолчанию шлюз слушает только локальный 127.0.0.1 и токен не требует (как и Farsight). Если --host — не локальный адрес, токен требуется автоматически; с --auth токен нужен и локально.
  • Другие сайты в браузере подключиться не могут: у любого подключения из браузера есть источник (Origin), а шлюз принимает только свою демо-страницу и адреса, переданные через --allow-origin; программы вроде Python, Node или curl источник не передают и подключаются как обычно. Когда шлюз слушает только локально, он ещё проверяет Host и так блокирует атаки, при которых внешний домен резолвится на локальную машину.
  • Роль клиент объявляет сам при подключении: в локальном режиме это соглашение, а не граница безопасности. На Арене роли будет раздавать процесс-судья, см. Арена.