文档 工具

网关

WebSocket / JSON 网关:Python SDK 能调的公开接口,JS、C#、Go、Rust、浏览器页面、另一台机器上的程序都能调。三种角色,自带 JS 客户端和浏览器演示页;延迟是快车道再加约 1 ms。

网关把快车道和推送状态包成 WebSocket / JSON。接口目录 里 Python SDK 能调的公开接口,JS、C#、Go、Rust、浏览器页面、另一台机器上的程序、大模型都能调,方法名和参数都一样。延迟是快车道再加约 1 ms。

最省事:远见首页「控制中心」→ 网关 → 启动(停止、重启、看日志、打开演示页也在那张卡片上)。命令行:

python gateway/server.py                 # ws://127.0.0.1:8870/ws(端口在 openwar3.json 的 ports.gateway)
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(也可以用 pid= 代替 inst=;要令牌时加 &token=)。

角色能调适合
dev全部:观察、命令、游戏控制、沙盒(JASS 改世界)、画界面本机工具、玩法模组、玩伴
player(加 &player=N)观察、指挥 N 号玩家的单位、画界面;默认公平模式,只看得见 N 号玩家视野里的东西(&fair=0 关掉)替某个玩家下场的 Bot 或大模型
observer只读(运行时直接拒绝它下的命令)观战、解说、数据采集

player 拿不到:结束游戏、改速度、暂停这类游戏控制,看得见别人底牌的 players、enemy_ai_plan,会让游戏进程打开本机文件的 canvas.image,还有 JASS。resources、tech、stats 这类带玩家号的查询只能查自己。

一个连接就是一个会话,占一条快车道(运行时一共 16 条)。网关同时最多 12 个会话,给 Bot、模组和远见留几条。断开时只收掉这个会话自己画的东西和热键,别的程序画的不动。

消息

连上之后先收到 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": 地址},地址就是单位 JSON 里的 addr;可以带上 "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 就够了,不用碰共享内存。

大模型:直接用 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,不要令牌(和远见一样)。--host 不是本机地址时自动要求令牌;--auth 让本机也要。
  • 浏览器里别的网站连不上:浏览器发起的连接都带来源(Origin),网关只认自己的演示页和 --allow-origin 给的网址;Python、Node、curl 这类程序不带来源,照常连。只听本机时还会核对 Host,挡住把外部域名解析到本机的攻击。
  • 角色是连接时自己声明的:本机模式下它是约定,不是安全边界。对战平台要由裁判进程决定谁拿什么角色,见 对战平台。