# SimpleFarm 项目长期约定
## 是什么
终端农场经营游戏 + 小型多人游戏服务器(v2.0)。游戏跑在服务端进程里,
TUI 是纯客户端,同时开放 HTTP + WebSocket 接口给 AI/脚本调用(服务端不内置 AI)。
## 运行方式
- 依赖放隔离 venv:`C:/Users/Administrator/.workbuddy/binaries/python/envs/default/Scripts/python.exe`
(服务端需要 fastapi + uvicorn[standard] + websockets;客户端与 TUI 只用标准库)
- 服务端:`python main.py serve --daemon`,网页 ,文档 /docs
- 玩:`python main.py play --farm 名字`;单机:`python main.py solo`
- AI/脚本入口:`main.py actions | do <动作> '' | batch | state --json | watch | bot`
- 测试:`python -m unittest discover -s tests`(97 项;不需要 FastAPI 时只跑 test_engine.py)
## 架构约定(改动时必须遵守)
- **分层**:`farm.engine` 只管规则,不认识网络/终端;`farm.tui` 不认识 socket;
`farm/server/*` 不认识终端。新增玩法动作只改 `farm/server/actions.py` 一张表。
- **接口同构**:`farm.client.RemoteFarm` 必须与 `FarmEngine` 同名同语义,
这样 `tui.py` 不需要区分本地/远程。加动作时两边都要补。
- **多牧场**:一个 farm = 一个玩家 = 一份 `saves/<名字>.json` + 一个引擎 + 独立时钟;
时钟由**一个** `FarmClock` 线程统一驱动,不要给每个牧场开线程。
- **存档类动作**:`save` / `reset` 必须由会话(FarmSession)处理,
不能直接落到 `engine.save()`(会写默认路径、覆盖别人的档)。
- **实时通道**:WebSocket(`/ws`)是唯一实时通道,推送节流 250ms,消息带自增 `seq`。
写操作优先走 WS(带 `id` 回执与 `snapshot`),只有 ws_closed/timeout/network
才退回 HTTP 重试;**业务错误必须原样抛出,不能重试**。
## 环境禁忌(本机特有)
- Bash 的 coreutils 残缺(`ls`/`head`/`tail`/`grep` 缺失),**不要用管道**,会整条命令失败;
查看/删除文件一律写 Python 脚本。
- 环境设了 `HTTP_PROXY` 但没有 `no_proxy`:任何本机 HTTP 访问都要走 `farm/net.py` 的
`open_url()`(回环直连),否则会拿到 502 并误判为"服务器没起来"。
- Windows 下守护进程的 pid 必须由**服务进程自己**写(见 `farm/server/__main__.py`),
父进程的 `Popen().pid` 不可信。
## 相关文档
- 项目入口文档:`README.md`(接口表、WS 协议、边界处理、设计取舍全在里面)
- 当天工作记录:`.workbuddy/memory/2026-09-18.md`