快速开始¶
本指南面向第一次使用本 SDK 的读者。读完后你将能够:
- 安装
mcbe-ws-sdk - 把基岩版 Minecraft 连到本机 Python 服务
- 用
tellraw把玩家聊天回显进游戏 - 理解需要实现的两个接口:
ConnectionHook与ResponseSink
环境准备¶
| 项目 | 要求 |
|---|---|
| Python | 3.11+(python --version) |
| 操作系统 | Windows / macOS / Linux |
| Minecraft | 基岩版(手机 / Win10·11 商店版 / 教育版等),能进一个有作弊权限的世界 |
| 网络 | 游戏与 Python 在同一台机器,或同一局域网;防火墙放行监听端口 |
/wsserver 是怎么工作的
基岩版的 /wsserver 是客户端命令:玩家在世界里输入后,这台客户端会连到
你的 Python 服务。不需要开专用服务器,单人世界也能用。
安装¶
从 PyPI¶
从源码可编辑安装(开发 / 跑示例推荐)¶
cd mcbe-ws-sdk
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev,docs]"
验证:
能打印版本号(例如 0.1.0)就说明安装成功。
5 分钟上手:跑通第一个示例¶
仓库自带一个「收到聊天就原样回复」的示例,建议先跑通它,再自己写代码。
第 1 步 — 启动 Python 服务¶
在 mcbe-ws-sdk 目录下:
看到类似输出就表示在听了:
[info] listening host=0.0.0.0 port=8080 url=ws://0.0.0.0:8080
[info] connect_hint command=/wsserver <this-machine-ip>:8080
[info] ready stop_with=Ctrl+C
可选参数:
python examples/basic-server/server.py --host 0.0.0.0 --port 8080
python examples/basic-server/server.py --log-level DEBUG # 看更细的帧日志
第 2 步 — 查自己的 IP¶
| 场景 | 在游戏里写什么 |
|---|---|
| 游戏和 Python 同一台电脑 | /wsserver 127.0.0.1:8080 |
| 游戏在手机 / 另一台电脑 | /wsserver 192.168.x.x:8080(换成电脑的局域网 IP) |
找类似 192.168.1.23 的地址,不要用 127.0.0.1 给另一台设备连。
第 3 步 — 在游戏里连接¶
- 打开一个基岩版世界(需要能输入命令:创造模式,或开了作弊)。
- 在聊天框输入(把 IP 换成上一步的):
-
连接成功时:
-
游戏里会出现一条提示(示例会发欢迎通知);
- Python 终端会打印
connected。
第 4 步 — 发消息试一下¶
在聊天框随便打点字,例如 你好。
- 游戏内应收到:
收到 <你的名字> 的消息:你好 - 终端应打印一条
chat日志
发 帮助 或 !help 会看到示例帮助文案。
第 5 步 — 停止服务¶
在跑 Python 的终端按 Ctrl+C 即可优雅退出。
手写一个最小回声机器人¶
下面这份代码可以保存成 my_bot.py,在任意目录运行(需已 pip install mcbe-ws-sdk)。
"""最小回声机器人:玩家说话,原样回复。"""
import asyncio
from mcbe_ws_sdk import (
DefaultResponseSink,
FlowControlSettings,
GatewaySettings,
McbeOutboundDelivery,
McbeServerFacade,
NoOpHook,
OutboundText,
WebsocketTransportConfig,
enqueue_response,
)
# ── 1. 出站:把 SDK 消息变成游戏里的 tellraw ─────────────────
class MinecraftSink(DefaultResponseSink):
def __init__(self, flow: FlowControlSettings) -> None:
self._flow = flow
def _delivery(self, state):
if state.send_payload is None:
return None
return McbeOutboundDelivery(
connection_id=state.id,
send_payload=state.send_payload,
settings=self._flow,
)
async def on_outbound_text(self, state, message: OutboundText) -> None:
delivery = self._delivery(state)
if delivery is not None:
await delivery.send_outbound_text(message)
async def on_system_notification(self, state, message) -> None:
delivery = self._delivery(state)
if delivery is not None:
await delivery.send_system_notification(message)
# ── 2. 入站:继承 NoOpHook,只覆盖你关心的钩子 ───────────────
class EchoHook(NoOpHook):
async def on_connected(self, state) -> None:
print(f"[+] 已连接: {state.id}")
async def on_disconnected(self, state) -> None:
print(f"[-] 已断开: {state.id}")
async def on_player_message(self, state, event, parsed=None) -> None:
# Bedrock 会把我们自己的 tellraw 回显成 sender=「外部」
if event.sender in {"外部", "External"}:
return
text = event.message.strip()
if not text:
return
print(f"[chat] {event.sender}: {text}")
# 用 event.sender 当目标:一条 /wsserver 可能有多名玩家
enqueue_response(
state,
OutboundText(
content=f"收到 {event.sender} 的消息:{text}",
channel="echo",
player_name=event.sender,
target=event.sender,
),
)
# ── 3. 启动 ───────────────────────────────────────────────────
async def main() -> None:
settings = GatewaySettings(
websocket=WebsocketTransportConfig(host="0.0.0.0", port=8080),
)
facade = McbeServerFacade(
settings=settings,
hook=EchoHook(),
sink=MinecraftSink(settings.flow),
)
print("监听 ws://0.0.0.0:8080 ,游戏里执行 /wsserver <本机IP>:8080")
await facade.run_lifetime()
if __name__ == "__main__":
asyncio.run(main())
代码在干什么?¶
| 部分 | 作用 |
|---|---|
EchoHook(NoOpHook) |
只覆盖关心的钩子:连接 / 断开 / 收到聊天;其余钩子保持空实现 |
MinecraftSink |
实现 ResponseSink:把 OutboundText 真正发成游戏命令 |
enqueue_response(...) |
把回复放进该连接的发送队列,由 SDK 后台协程发出 |
McbeServerFacade |
一站式入口:监听端口、握手、订阅 PlayerMessage、分发事件 |
event.sender |
玩家身份。不要用 state.player_name(一条连接可多人) |
优先继承 NoOpHook
ConnectionHook 是协议接口;日常开发请继承 NoOpHook,只重写需要的方法,
不必六个钩子全写。
默认值¶
构造器是 keyword-only 的。每个参数在 None 时会折叠回网关默认值,因此
McbeServerFacade() 即可启动一个带中性 sink、空命令注册表与默认安全 addon 桥的
可运行 facade:
facade = McbeServerFacade(
settings=None, # → GatewaySettings()
hook=None, # → NoOpHook()
sink=None, # → DefaultResponseSink()
addon=None, # → AddonBridgeService(settings.addon)
registry=None, # → CommandRegistry()
)
通过 await facade.stop() 可从另一个任务停止运行中的 facade(run_lifetime
会干净地展开为优雅关闭;直接取消该任务同样有效)。
宿主通常注入的接口¶
| 表面 | 作用 |
|---|---|
ConnectionHook |
六个生命周期钩子(on_connected、on_disconnected、on_player_message、on_ui_chat_reassembled、on_command_response、on_error) |
ResponseSink |
将 OutboundText / SystemNotification 路由为 Minecraft 命令 |
AddonBridgeService |
ScriptEvent 能力请求/响应(无全局单例) |
CommandRegistry |
前缀/别名命令解析(默认为空) |
MCBEWS_V1 |
内置 mcbews v1 协议 profile |
双层接口¶
| 层级 | 用法 | 适合 |
|---|---|---|
| 高层 | 实现 ConnectionHook + ResponseSink,交给 McbeServerFacade |
绝大多数宿主(推荐) |
| 低层 | 订阅 EventBus(按 WsEventType) |
需要自己拼装生命周期时 |
多人 isolation 提醒¶
基岩版一个世界里通常只有一条 /wsserver 连接,多名玩家共用它。
- 会话、历史、锁请按
(connection_id, player_name)分桶 - 身份一律用本次消息的
event.sender,不要用连接级ConnectionState.player_name
更多示例¶
| 示例 | 路径 | 说明 |
|---|---|---|
| 基础回声服务器 | examples/basic-server/ |
最小可运行宿主,推荐先看 |
| Addon 能力演示 | examples/addon-server/ |
聊天命令查玩家 / 背包、发 WS 命令 |
| 内存能力往返 | examples/addon-capability-call/ |
不连游戏,单测式走通 bridge API |
想调用游戏内能力时¶
需要额外构建并启用配套 addon:
把生成的 .mcaddon 导入世界并启用该包,再跑 examples/addon-server。
必须开启「测试版 API」
在世界设置的 实验 中打开 测试版 API(Beta APIs)。 本 addon 依赖 Minecraft Script API;未开启时脚本不会加载,能力请求会超时。 建议使用专用测试世界——实验性玩法可能影响成就 / 功能。
细节见 addon README 与示例内 README。
常见问题¶
游戏里提示连接失败?
- 确认 Python 已启动且打印了
listening - 端口是否被占用 / 防火墙是否放行
- 跨设备时是否用了局域网 IP(不要用
127.0.0.1) - 手机与电脑是否同一 Wi-Fi,是否开了 AP 隔离
连上了但发消息没回复?
- 看 Python 终端有没有
chat日志 - 若只有
external_echo_ignored,说明过滤了自己的 tellraw 回显,属正常 - 用
--log-level DEBUG看是否收到PlayerMessage
一条消息被拆成好几段?
- 正常现象。Bedrock 的
commandLine实测安全上限约 461 字节,SDK 会自动分片并按间隔发送。
可以同时给多名玩家用吗?
- 可以。同一
/wsserver连接上的多名玩家都会触发on_player_message;请始终用event.sender定位玩家。
怎么安全地挂到公网?
- 示例没有鉴权。公网部署前请在
ConnectionHook里自己做登录 / 权限校验,并配合防火墙与反向代理。Addon 桥不是安全边界。
on_player_message 里能直接 await 很久的操作吗?
- 不要在 hook 里长时间阻塞等待(例如等 addon 响应或
commandResponse)。 facade 是串行处理入站帧的;阻塞会饿死接收循环。请用asyncio.create_task(...)丢到后台,示例addon-server展示了正确写法。
Addon 能力请求超时?
- 本世界是否已启用 bridge 行为包?
- 实验 → 测试版 API 是否已打开?未开启时脚本不会加载。
/wsserver是否仍然连着?