#!/usr/bin/env python3 """把 TUI 渲染结果输出到终端,用于检查排版与配色。 不进入交互循环,也不读取键盘——只是把某一时刻的完整画面画出来。 用法: python tools/preview_tui.py # 使用默认的中等规模农场(本地引擎) python tools/preview_tui.py --width 100 # 指定终端宽度 python tools/preview_tui.py --color # 输出带 ANSI 颜色 python tools/preview_tui.py --scene empty # 初始状态 python tools/preview_tui.py --scene rich # 后期大农场 python tools/preview_tui.py --scene menu # 播种菜单 python tools/preview_tui.py --url http://127.0.0.1:8765 --farm alice # 渲染**真实服务器**上的牧场 """ from __future__ import annotations import argparse import contextlib import io import os import random import re import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from farm.engine import FarmEngine # noqa: E402 from farm.tui import TuiApp # noqa: E402 SCENES = ("empty", "mixed", "rich", "menu", "help") def build_remote(url: str, farm: str, token: str | None) -> tuple[object, TuiApp]: """连到真实服务器,取一份现状来渲染。""" from farm.client import RemoteFarm client = RemoteFarm(endpoint=url, farm=farm, token=token, realtime=False) app = TuiApp(client, use_color=True, autosave=False, server_label=f"{client.farm} @ {client.host}") return client, app def build_engine(scene: str) -> tuple[FarmEngine, TuiApp]: random.seed(42) engine = FarmEngine(tick_seconds=15) app = TuiApp(engine, use_color=True, autosave=False) if scene == "empty": return engine, app # ---- 制造一个"进行中"的农场 engine.state.level = 2 engine.state.gold = 340 engine.state.feed = 4 engine.plant(1, "wheat") engine.water(1) engine.plant(2, "carrot") engine.plant(3, "wheat") engine.plant(4, "carrot") engine.advance_day() engine.advance_day() engine.buy_animal("chicken") engine.feed(1) if scene == "rich": engine.state.level = 4 engine.state.gold = 2400 engine.state.feed = 22 for i in range(2): engine.state.gold = 99999 engine.buy_plot() engine.plant(5, "corn") engine.plant(6, "tomato") engine.water(5) engine.state.gold = 2400 engine.buy_animal("sheep") engine.buy_animal("cow") engine.advance_day() engine.advance_day() engine.add_log("收获 2 份小麦(丰收!),+31 金币", "good") engine.add_log("升级到 Lv.4!奖励 240 金币,解锁:南瓜", "good") if scene == "menu": # 找第一块空地,把播种菜单打开 empty = next((p.index for p in engine.state.plots if p.is_empty), 0) app.plot_cursor = empty app._open_crop_menu() if scene == "help": app.mode = "help" return engine, app def main() -> int: parser = argparse.ArgumentParser(description="渲染一帧 TUI 画面") parser.add_argument("--width", type=int, default=112, help="终端宽度") parser.add_argument("--height", type=int, default=32, help="终端高度") parser.add_argument("--scene", choices=SCENES, default="mixed", help="场景") parser.add_argument("--color", action="store_true", help="保留 ANSI 颜色") parser.add_argument("--url", default=None, help="连到真实服务器渲染(例如 http://127.0.0.1:8765)") parser.add_argument("--farm", default="default", help="--url 模式下要看的牧场") parser.add_argument("--token", default=None, help="--url 模式下的访问令牌") args = parser.parse_args() os.environ["COLUMNS"] = str(args.width) os.environ["LINES"] = str(args.height) if args.url: engine, app = build_remote(args.url, args.farm, args.token) state = engine.snapshot() print(f"# 来自真实服务器 {args.url} · 牧场 {args.farm} · 第 {state.get('day')} 天 · " f"金币 {state.get('gold')} · 在线 {state.get('online')}\n") else: engine, app = build_engine(args.scene) # 预览脚本没有跑 Scheduler,这里手动给个倒计时,让画面更接近真实运行状态 if engine.next_tick_at is None and not engine.paused: import time as _time engine.next_tick_at = _time.time() + 8.4 app.use_color = args.color buffer = io.StringIO() with contextlib.redirect_stdout(buffer): app._render() output = buffer.getvalue() # 去掉清屏、光标控制与行尾清理符,预览里只保留可见内容 output = re.sub(r"\x1b\[[0-9;?]*[A-Za-z]", "", output) print(output) return 0 if __name__ == "__main__": sys.exit(main())