diff --git a/README.md b/README.md index cf79c79..3dea5af 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ uv run main.py solo # 本地引擎 + 终端界面,不开 **TUI 是纯客户端**:它通过 WebSocket 订阅状态、通过 WebSocket/HTTP 提交动作, 自己不持有任何游戏状态。所以: -* 服务端可以在另一台机器上,`python main.py play --url http://10.0.0.5:8765 --farm alice`; +* 服务端可以在另一台机器上,`uv run main.py play --url http://10.0.0.5:8765 --farm alice`; * 关掉 TUI 不会影响服务器,你的牧场继续按时间生长; * 你在 TUI 里操作的同时,AI 可以对同一个牧场操作,双方立刻能看到对方的结果。 @@ -113,7 +113,7 @@ uv run main.py solo # 本地引擎 + 终端界面,不开 实例: ```bash -$ python main.py actions +$ uv run main.py actions 牧场 default · 第 3 天 · 金币 96 · 行动点 7/10 共 9 个候选动作: @@ -123,7 +123,7 @@ $ python main.py actions 4 号地空闲,可种小麦 ... -$ python main.py do harvest '{"plot":2}' +$ uv run main.py do harvest '{"plot":2}' ✓ 收获 2 份胡萝卜(丰收!),获得 104 金币 (0.01s) 第 3 天 · 金币 200 · 行动点 7/10 · 净资产 512.0 ``` @@ -347,7 +347,7 @@ farm/ hub.py WebSocket 连接池与状态推送(线程 → 事件循环的桥) daemon.py 守护进程:start / stop / status / 日志 / pid webui.py 内嵌网页客户端(单页,原生 JS + WebSocket) - __main__.py python -m farm.server(前台运行) + __main__.py uv run python -m farm.server(前台运行) tools/ preview_tui.py 把 TUI 渲染成文本(--url 可连真实服务器) ws_demo.py 最小 WebSocket 客户端,验证协议 diff --git a/ai_player.py b/ai_player.py index ea92321..bf7338f 100644 --- a/ai_player.py +++ b/ai_player.py @@ -6,9 +6,9 @@ 用法 ---- - python ai_player.py # 连本机 default 牧场 - python ai_player.py --farm ai-1 --minutes 5 # 经营 ai-1 五分钟 - python ai_player.py --url http://10.0.0.5:8765 --farm my-bot + uv run ai_player.py # 连本机 default 牧场 + uv run ai_player.py --farm ai-1 --minutes 5 # 经营 ai-1 五分钟 + uv run ai_player.py --url http://10.0.0.5:8765 --farm my-bot 策略在哪里 ---------- @@ -32,7 +32,7 @@ from farm.engine import GameError def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( - prog="python ai_player.py", + prog="uv run ai_player.py", description="通过 HTTP/WebSocket 接口参与 SimpleFarm 的机器人玩家", ) parser.add_argument("--url", default="http://127.0.0.1:8765", help="服务器地址") @@ -59,7 +59,7 @@ def main(argv=None) -> int: ) except GameError as exc: print(f"✗ 连不上服务器:{exc.message}", file=sys.stderr) - print(" 先启动:python main.py serve --daemon", file=sys.stderr) + print(" 先启动:uv run main.py serve --daemon", file=sys.stderr) return 2 snapshot = client.snapshot() diff --git a/farm/client.py b/farm/client.py index ea06832..e763a56 100644 --- a/farm/client.py +++ b/farm/client.py @@ -322,7 +322,7 @@ class RemoteFarm: self.connected = False raise GameError( "network", - f"连不上服务器 {self.endpoint}({exc})。请先启动:python main.py serve --daemon", + f"连不上服务器 {self.endpoint}({exc})。请先启动:uv run main.py serve --daemon", status=503, ) from exc try: diff --git a/farm/server/__init__.py b/farm/server/__init__.py index 22f8454..cffb9a1 100644 --- a/farm/server/__init__.py +++ b/farm/server/__init__.py @@ -13,7 +13,7 @@ * :mod:`farm.server.webui` —— 内嵌网页客户端 ``app`` 依赖 FastAPI,而 ``daemon`` 只依赖标准库。为了让 -``python main.py stop`` 在没有装 FastAPI 的机器上也能用,这里采用**惰性导出**: +``uv run main.py stop`` 在没有装 FastAPI 的机器上也能用,这里采用**惰性导出**: 真正 import 到用例时才加载对应子模块。 """ diff --git a/farm/server/__main__.py b/farm/server/__main__.py index eab5f7c..138ea5b 100644 --- a/farm/server/__main__.py +++ b/farm/server/__main__.py @@ -1,4 +1,4 @@ -"""``python -m farm.server`` —— 服务器进程入口(前台运行)。 +"""``uv run python -m farm.server`` —— 服务器进程入口(前台运行)。 守护进程模式会由 :class:`farm.server.daemon.DaemonManager` 用同样的命令行 再拉起一个本模块的实例,只是不带 ``--daemon``。 @@ -17,7 +17,7 @@ from .daemon import DEFAULT_LOG_FILE, DEFAULT_PID_FILE, PROJECT_ROOT, DaemonMana def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( - prog="python -m farm.server", + prog="uv run python -m farm.server", description="SimpleFarm 游戏服务器:HTTP 接口给 AI,WebSocket 给实时界面。", formatter_class=argparse.RawDescriptionHelpFormatter, ) @@ -50,7 +50,7 @@ def build_parser() -> argparse.ArgumentParser: parser.add_argument("--access-log", action="store_true", help="打印每个 HTTP 请求") parser.add_argument("--no-remote-control", action="store_true", help="禁止通过接口停机") parser.add_argument( - "--daemon", action="store_true", help="转到后台运行(等价于 python main.py serve --daemon)" + "--daemon", action="store_true", help="转到后台运行(等价于 uv run main.py serve --daemon)" ) parser.add_argument( "--pid-file", default=None, help="把本进程 pid 写到该文件(守护进程模式会自动指定)" diff --git a/farm/server/daemon.py b/farm/server/daemon.py index 229316e..b145b4d 100644 --- a/farm/server/daemon.py +++ b/farm/server/daemon.py @@ -231,7 +231,7 @@ class DaemonManager: f"服务器已在后台启动(pid {pid})\n" f" 网页 http://{self.host}:{self.port}/\n" f" 日志 {self.log_file}\n" - f" 停止 python main.py stop" + f" 停止 uv run main.py stop" ) if process.poll() is not None and self.read_pid() is None: return False, ( diff --git a/main.py b/main.py index 75d88da..52e4376 100644 --- a/main.py +++ b/main.py @@ -88,7 +88,7 @@ def die(message: str, hint: str = "", code: int = 1) -> int: # ---------------------------------------------------------------------- 参数 def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( - prog="python main.py", + prog="uv run main.py", description="SimpleFarm:终端农场游戏 + 小型多人游戏服务器(HTTP/WebSocket 供 AI 调用)", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=BANNER, @@ -222,8 +222,8 @@ def make_client(args, realtime: bool = False): except GameError as exc: hint = ( f"服务器地址:{args.url}\n" - "先启动服务器:python main.py serve --daemon\n" - "再确认地址端口:python main.py status" + "先启动服务器:uv run main.py serve --daemon\n" + "再确认地址端口:uv run main.py status" ) raise SystemExit(die(f"无法连接服务器:{exc.message}", hint)) from None @@ -286,7 +286,7 @@ def cmd_status(args) -> int: if not info["running"]: print(warn("• 服务器未运行")) - print(dim(" 启动:python main.py serve --daemon")) + print(dim(" 启动:uv run main.py serve --daemon")) print(dim(f" 地址:http://{args.host}:{args.port}/")) return 1 @@ -336,7 +336,7 @@ def cmd_play(args) -> int: if not (sys.stdin is not None and sys.stdin.isatty()): return die( "当前终端不是交互式终端,无法启动界面。", - "在真实终端里运行,或用命令行模式:python main.py actions / do / watch", + "在真实终端里运行,或用命令行模式:uv run main.py actions / do / watch", ) client = make_client(args, realtime=not args.no_realtime) label = f"{client.farm} @ {client.host}" @@ -392,7 +392,7 @@ def cmd_do(args) -> int: except json.JSONDecodeError as exc: return die( f"参数不是合法 JSON:{exc}", - '例子:python main.py do plant \'{"plot":1,"crop":"wheat"}\'', + '例子:uv run main.py do plant \'{"plot":1,"crop":"wheat"}\'', ) if not isinstance(params, dict): return die("参数必须是 JSON 对象") @@ -403,7 +403,7 @@ def cmd_do(args) -> int: except GameError as exc: return die( f"{args.action} 失败({exc.code}):{exc.message}", - "看看现在能做什么:python main.py actions", + "看看现在能做什么:uv run main.py actions", ) print(ok("✓ ") + str(result.get("message", "完成")) + dim(f" ({time.time() - started:.2f}s)")) @@ -432,7 +432,7 @@ def cmd_batch(args) -> int: except json.JSONDecodeError as exc: return die( f"actions 不是合法 JSON:{exc}", - "例子:python main.py batch " + "例子:uv run main.py batch " '\'[{"action":"harvest_all"},{"action":"buy_feed","params":{"quantity":5}}]\'', ) if not isinstance(items, list): @@ -458,7 +458,7 @@ def cmd_actions(args) -> int: ) if not items: print(warn("• 当前没有可执行的动作")) - print(dim(" 试试:python main.py do sleep (推进一天)")) + print(dim(" 试试:uv run main.py do sleep (推进一天)")) return 0 print(f"共 {len(items)} 个候选动作:\n") for index, item in enumerate(items, start=1): @@ -467,7 +467,7 @@ def cmd_actions(args) -> int: params_text = json.dumps(item["params"], ensure_ascii=False) print(f" [{index:>2}] {item['action']:<12} {params_text:<42} ({cost_text})") print(dim(f" {item.get('reason', '')}")) - print(dim("\n执行方式:python main.py do <动作名> '<参数JSON>'")) + print(dim("\n执行方式:uv run main.py do <动作名> '<参数JSON>'")) return 0 @@ -561,7 +561,7 @@ def cmd_bot(args) -> int: print("\n已中断。") summary = {"actions": bot.actions_executed, "failures": bot.failures} print(json.dumps(summary, ensure_ascii=False)) - print(dim("提示:机器人和你调的是同一套接口,随时可以用 python main.py actions 接手。")) + print(dim("提示:机器人和你调的是同一套接口,随时可以用 uv run main.py actions 接手。")) return 0 @@ -670,7 +670,7 @@ def main(argv=None) -> int: handler = handlers.get(args.command) if handler is None: - return die(f"未知命令 {args.command}", "python main.py --help 查看全部命令") + return die(f"未知命令 {args.command}", "uv run main.py --help 查看全部命令") try: return handler(args) except SystemExit as exc: # make_client 里的友好退出