在引入 uv 依赖管理、ruff 静态检查与格式化、pyright 类型检查之前, 先把当前可正常运行的状态固定下来,作为后续大规模自动改动的回滚点。 此时状态:97 项测试全绿,HTTP + WebSocket 多牧场服务器可用。
3.9 KiB
3.9 KiB
2026-09-18 · SimpleFarm 从单机 TUI 改造为小型多人游戏服务器
需求
用户先要求"CLI/TUI 农场游戏 + HTTP/gRPC 接口让 AI 参与";中途改方向: 放弃 gRPC,改用 FastAPI/aiohttp,要求:守护进程可后台运行、SSE 或 WS 二选一、 TUI 只在用户玩时作为客户端、用户也能用 HTTP 调用、支持多用户(小型游戏服务器)。
最终架构(v2.0)
- 服务端
farm/server/:app.py(FastAPI REST+WS) /actions.py(动作表) /session.py(多牧场会话 + 单一 FarmClock 统一时钟) /hub.py(WS 连接池 + 250ms 节流推送) /daemon.py(守护进程) /webui.py(内嵌网页客户端)。 - 客户端
farm/client.py的RemoteFarm:与FarmEngine接口同构, 所以tui.py不用改渲染逻辑就能从"本地引擎"切到"远程服务器"。 写操作优先走 WS(带 id 回执),通道类错误自动退回 HTTP;读数靠 WS 推送。 farm/bot.py规则机器人 +ai_player.py外挂机器人:只调接口,不 import 游戏规则。- 统一入口
main.py:serve/stop/status/logs/play/solo/do/batch/actions/state/log/watch/bot/farms/help。
关键决策
- 选 WebSocket 而非 SSE:这个游戏动作上行和状态下行是同一件业务的两半, SSE 只能下行,等于要维护两套鉴权/重连。
- 删掉 gRPC(
farm/api.py旧 stdlib HTTP 层、farm/grpc_server.py、proto/、tools/gen_proto.py): 接口主要喂 LLM/脚本,它们只会捏 HTTP+JSON。 - 多牧场模型:一个牧场 = 一个玩家 = 一份存档 + 一个引擎;空闲 30 分钟先落盘再移出内存。
- 动作表
server/actions.py是所有入口(HTTP / WS / CLI / 机器人)的唯一执行通道,参数校验只写一次。
踩过的坑(重要,可复用)
- 本地请求被系统代理截走:机器上设了
HTTP_PROXY但没有no_proxy,urllib把发给 127.0.0.1 的请求也交给代理,本机服务器报502 upstream connect failed。 解决:farm/net.py的open_url(),回环地址走ProxyHandler({})直连。 - pid 归属:起初父进程把
Popen().pid写进 pid 文件,但 Windows 上 venv 的python.exe可能是转发器,os.getpid()(40564)≠ 父进程看到的 pid(20244),stop会杀错进程。 解决:--pid-file传给子进程,子进程在 lifespan 启动(端口已绑定)后写自己的 pid,退出时删除;stop优先走 HTTP/api/admin/shutdown优雅停机(能落盘),拿不到 pid 也能停。 - 精简状态会清空视图:动作回执里的
state是精简版(无plots/animals), 客户端若整体替换就会把农田格子清空。解决:StateView.apply()按"含 plots 即整体替换, 否则合并字段",并且 HTTP 动作带full=1/ WS 回执带snapshot让客户端立刻刷新。 save动作必须由会话处理:engine.save()会写默认路径,多牧场下会互相覆盖; 在app.execute_action()里把 save/reset 拦截为会话级操作。- 本机 Bash 的 coreutils 坏了(
ls/head/tail/grep都不存在), 所有查看/清理动作改用 Python 脚本完成;管道会直接让命令失败,不要用管道。
验证
- 97 项测试全绿(引擎 45 + 服务器 52),含真 uvicorn + 真客户端 + 真 WebSocket 端到端。
- 实测:daemon 启动 → status 正确 pid → actions/do/batch → 两牧场隔离与排行榜 → WS 收到 welcome/state/result/day → 机器人 120→197 金币 → stop 优雅停机落盘。
- TUI 远程渲染验证:
tools/preview_tui.py --url http://127.0.0.1:8793 --farm alice(112 列 / 76 列都正常,头部显示牧场名 @ 服务器)。 - 依赖装在隔离 venv:
C:/Users/Administrator/.workbuddy/binaries/python/envs/default/Scripts/python.exe(fastapi 0.141.1 / uvicorn 0.53 / websockets 17.1 / httpx 0.28)。