# wuxia-time **Repository Path**: aowind/wuxia-time ## Basic Information - **Project Name**: wuxia-time - **Description**: 武侠时光 · 门派经营 —— 3D 武侠门派经营游戏(FastAPI 权威世界 + three.js 渲染视窗) - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-20 - **Last Updated**: 2026-10-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 岁月 · 江湖 > 一款用浏览器打开的 **3D 武侠门派经营** 游戏 —— 开山立派、招贤纳士、营建山门、经营田产、铸兵研武。 > 后端是一个**权威世界**,前端只是一扇**渲染视窗**。 > > 🔴 **2026-09-27 门派改造落地**:门派场景整体重构为《了不起的修仙模拟器》式的**殖民地模拟** > —— 蓝图建造 / 房间环境 / 弟子需求与心情 / 时辰日程 / 内外门修炼 / 敌袭防御。 > 旧的「点一下盖楼」体系已退役,详见 `docs/参考-了不起的修仙模拟器-拆解与门派改造方案.md` > 与决策台账 `docs/game-design-decisions.md`(D-001~D-028)。

Python FastAPI three.js Vite

**🎮 线上体验:**(共享服务器 · 子路径部署;同机 AIGPart 平台首页仍是 ) > 🔑 **已接 AIGPart 单点登录**:平台账号从 AIGPart 点进游戏会自动登录(`/play/menpai/sso`);老账号按已验证邮箱首次 SSO 自动绑定,进度不变;邮箱密码登录保留。详见 [SSO 接入清单](docs/设计-AIGPart SSO 接入清单.md)。 --- ## 一、这是什么 一个完整的 3D 门派经营游戏,也是**一整套 AI 资产生产线**的落地现场。 玩家从一座荒山起家:营建大殿与库房、招揽门人、开垦农田、参悟武学;门人会自己走动、 做事、成长。世界按真实时间推进,玩家不在线时门派照常运转。 除经营之外,还有一条**完整的主线剧情**:点右下角的「**岁月**」进面板, 顶部三枚**卷页签**可切 —— 三卷各自独立推进、进度分开记: | 卷 | 章 / 战 | 战斗等级 | 讲什么 | 卷末奖励 | |---|---|---|---|---| | **第一章《岁月》** | 5 层 60 章 / 30 战 | 3 → 66 | 雨夜收留华山弟子**令狐冲**,陪他走完华山、福州、洛阳、西湖、黑木崖 | 天资质剑客**令狐冲** | | **第二章《天龙八部》** | 3 层 12 章 / 6 战 | 68 → 98 | 无量山遇**段誉**、杏子林看**乔峰**被逐、雁门关外并肩御敌 | 天资质**虚竹**(少林禅杖) | | **第三章《雪山飞狐》** | 3 层 12 章 / 6 战 | 102 → 122 | 辽东道上识**胡斐**、苗家揭开二十年前的毒刀旧账、雪谷决战 | 天资质刀客**胡斐** | 难度是**连续**的(3 → 66 → 98 → 122),数据体检专门查"卷间不许回退"。 对话有**人物立绘与场景背景**(57 张 AI 出图,与全项目同一套画风), 文案支持**行内 markdown**(`**粗体**` 会真的渲染成粗体,而不是把星号打出来); 对话**整层可点**——点画面任意处(场景、立绘、空白)都算"下一步", 只有 ✕ / 跳过 / 继续 三个按钮各管各的。 门派之外还有一片**江湖**:点右下角的「**江湖**」(罗盘)推开**世界大地图** —— **另一套 3D 视窗**,**648 米见方的连续地形**(山峦、林地、河湖、城池, 是一整张曲面而不是一格格方块),城镇之间由**自动生成的道路网**相连。 派**队伍出城游历**:左键点地即出发,途中会遇上随机游荡的**山匪流寇**,撞上便触发**遭遇战**; 可同时派出**多支队伍**,随时挑一支指挥(脚下铺出**脚印虚线**标出去向), 左下角一张**缩略舆图**实时框出你正在看的范围。 > 💡 项目最初是为了**给自家孩子做一款能长期玩的游戏**,因此格外在意: > 数值要看得懂、操作要直接、进度要能累积。 ### 玩法循环:殖民地的每一天 > 🔴 旧「8 步新手引导」已随旧建筑体系退役(D-020)——新玩法靠**默认日程与自动认领** > 即可自转,玩家按需介入。 早上辰时,弟子们从卧房醒来(精力回满,心情因「睡在自己的床上」+3)。外门弟子按日程 进入工作:有人去柴房外砍树,木料落地成堆;搬运工把木料搬进仓库;昨天画的 3 间卧房 蓝图开始有人搬料、砌墙、盖顶。巳时,新卧房落成;内门弟子整个上午在静室打坐,修为 随房间环境与功法匹配度缓慢累积;外门弟子在演武场练武攒**筑基值**,攒满换一次晋升 内门的机会。午时按日程去膳堂吃灶台做好的熟食。傍晚,打造台前的铁匠交出一把宝器 长剑(手感好还能出神兵)。入夜,山贼摸到山门外(声望越高来得越强),护山阵给全门 加防御……体力不济、心情低落的弟子会怠工甚至叛逃——经营就是让这一切良性循环。 ### 玩法入口(主界面左侧与右侧的常驻按钮) | 入口 | 干什么 | |---|---| | **营造 / 蓝图** | 殖民地营造:家具/生产/功能建筑点地落蓝图,墙/门/地板拖拽连画 | | **规划** | 范围指令:砍伐 / 开采 / 采集 / 清树桩 / 圈田(谷子·棉花·药草·灵芝) | | **工坊** | 熔炉/灶台/药炉/织机/打造台的配方队列(含兵器谱与神兵) | | **工作** | 每位门人的活计优先级(搬运/建造/采集农活/生产炊事)+ **时辰日程表** | | **账房 / 镖局 / 藏经阁** | 旧功能入口迁移(货架求购 / 镖局任务板 / 研习) | --- ## 二、玩法系统 | 系统 | 内容 | 配置 | |---|---|---| | **殖民地营造**(批1/2) | **蓝图建造**:画蓝图 → 弟子搬运 → 施工竣工(1 格 = 1 段墙,拖拽连画);26 种 v2 建筑(结构/家具/生产/功能/阵法),部分有声望门槛 | `buildings_v2.json` | | **弟子需求**(批3) | 饱食/精力/心情衰减与自动吃睡;**心情词条**驱动心情;床位认领与单间卧房;心情过低怠工、**叛逃**判定 | `colony_balance.json` `thoughts.json` | | **采集种植**(批4) | 门派内资源实体(树/岩/铁矿脉/玉脉/药草丛/浆果丛,砍树留桩复生);**范围指令**(砍/挖/采/清);**农田**四种作物按天生长 | `colony_balance.json` | | **生产打造**(批4) | 五产出台配方队列(熔炉/灶台/药炉/织机/打造台):缺料备料→工时→**品质 roll**(手艺+心情);打造台兵器谱:品阶看材料、**品质与材料无关**、宝器概率出**神兵** | `recipes.json` | | **时辰日程**(批5) | 每位门人 12 时辰 × 8 档,3 套模板 + 逐格编辑;日程即命令;**参研**在藏经阁产参悟点 | `colony_balance.json#schedule_templates` | | **内外门双轨**(批6) | 外门练武攒**筑基值**,满门槛+筑基丹+静室+席位**晋升内门**;内门修习**心法**(6 本,参悟解锁武技)、打坐修为、**闭关突破**(走火入魔赌局)、**心魔**(清心丹解) | `gongfa.json` | | **灵气场**(批6) | 地脉×2 + 聚灵阵:静室灵气浓度与陈设美观决定修炼系数 | `colony_balance.json` | | **敌袭防御**(批7) | 声望越高来犯越强(惯匪→强盗头子):预警→徘徊→**攻墙拆墙**→山门决战(护山阵防+15%);战胜掉落落地堆、战败被掠 | `colony_balance.json#raid_templates` | | **离线留任**(批8) | 离线按**每时辰一粗步**补演(封顶 48 时辰):吃睡/打坐/练武/工台照常运转,登录收**离线简报** | `colony_balance.json` | | **招募** | 招贤榜刷新,按声望解锁档位,门人有资质与专长;**超编自动转客卿**(价 ×1.5,只走大地图) | `recruit.json` | | **镖局** | 派门人出镖赚声望与资源,有任务轮换与在途任务卡(入口:**镖局**按钮) | `tasks.json` | | **账房** | 货架出售 + 求购交付(入口:**账房**按钮,保底 1 级开放) | `balance.json#shop` | | **武学** | 19 门门派武学(3 大学派)+ 10 门武器技能(**研习+参悟解锁**) | `techs.json` `skills.json` `gongfa.json` | | **装备** | **7 个槽位** × 5 档品质(凡品→良品→精品→宝器→神兵);打造台产出入库 | `equipment.json` | | **成长** | **110 级 = 11 境界 × 10 小级**(境门上闸+闭关突破),老档自动迁移;外功等级终身成长 | `realms.json` | | **资源** | **10 种资源**(基础 6 + 玉石/铁锭/布匹/寒玉)的生产、采集与消耗闭环 | `resources.json` | | **景致** | 植被 / 装饰可拖动、染色、删除(删除记法为黑名单) | `scene.py` | | **游历 · 世界大地图** | **独立 3D 视窗**:648 米见方**连续地形**(山 / 林 / 水 / 城池)+ 自动生成的**道路网**(城镇互通);派队伍出城,遇**山匪流寇**即触发遭遇战;**多队并行**、选一支指挥、脚印虚线标去向、角落**缩略舆图**。**行军耗粮**(粮尽则饥饿减速) | `balance.json#world` | | **大地图经营**(2026-09-24) | **采集派遣**:点资源点=派队开采,货载满/矿枯竭自动停,收队自动交货(离匪巢近的矿风险高);**城镇委托板**:每镇常驻 2 条委托(剿匪 / 寻药 / 送信 / 护送),完成即补、涨**城镇好感**(好感「友善」后该镇休整免费);**驿站休整**:队伍停在城旁可付银当场痊愈伤员;**游历奇遇**:离路野行按地形概率触发**随机事件**(17 条池:奇遇 / 危机 / 人情 / 环境),奖励资源 / 经验 / 好感,甚至**奇人入伙** | `events.json` `balance.json#world` | | **战术战斗** | **3D 全屏战场**:10×10 格子**只做布阵占位**,开战后人物**自由移动**(连续坐标,不按格子走)、主动靠近敌人、**CD 一到就出手不等别人**;兵器决定射程与攻击表现 | `battle.json` | | **主线「岁月」** | **三卷 84 章 / 42 战**(岁月 60+30 · 天龙八部 12+6 · 雪山飞狐 12+6)。面板顶部**卷页签**切换,每卷进度独立;本章对话 → 开战 → 打赢结算(资源/经验/装备)。对话支持**行内 md**、**整层点击**推进。每卷通关迎一位**天资质**伙伴入派(令狐冲 / 虚竹 / 胡斐) | `mainline.json` | | **剧情战斗与结算** | 战场有**悬停人物 tips**(名字/阵营/生命/内力)、**脚下阵营环**(我方绿 / 敌方红 / 我方 NPC 蓝,随尸体消失)、**头顶生命值小条**、**左侧双方统计面板**(头像 / 名称 / 生命 / 内力 / **累计伤害** / 当前释放的武学);**没有回合**——各按兵器 CD 出手,同刻并发不排队;章节战斗打完**自动收起剧情层**。战报进「汇报簿」(游历遭遇战有**独立版式**:遭遇对象 / 双方人数 / 交手次数 / 缴获折损 / 谁负了伤) | `battle.json` | | **音画** | 2 首 BGM + **15 段过场视频**(任务成败)+ Web Audio 合成音效 | `audio.js` `scene.py` | > 🔴 **数值全部外置**在 `game/data/*.json` —— 改玩法不用动代码。这是项目最硬的一条规矩。 --- ### 界面与规则(2026-09-24 / 25 两批) | 改动 | 要点 | |---|---| | **门人卡牌** | 人物牌收敛成**一个共享模块**(`ui/member_card.js`)——主界面门人条、**游历选人**、战斗牌条同源;悬停 tips 给**完整信息**(身份 / 境界 / 资质 / 战力 / 四维含「外物」加成 / 体力经验 / 擅长 / 随身 / 武艺 / 此刻在做什么) | | **游历选人** | 用**人物卡牌**选人(红框 + ✓ 选中、负伤压灰);**已在其它队伍里的人不出现在候选**(并写明"另有 N 人已在游历队伍中");队伍卡点一下即**镜头对准该队**,卡上列着**正在跑的委托**,点任务看详情与"怎么完成" | | **大地图** | 地面**压平到同一平面**(林地/山地不再各自鼓包)、**道路贴地**(原先抬高 0.9 米,会把行走的队伍下半身盖住)、据点标记按**插值地面**摆放不陷地、**小地图像素级重绘**(1 格 = 1 像素 + 双线性放大 + 山体阴影,不再是一格格方块)、水面顶点级渐变 | | **大地图交互** | 右侧**据点图标栏**(按 本门/城镇/门派/山匪/官府 分列);点图标或点据点弹**交互菜单**(定位 / 查看委托 / 驿站休整 / 征讨 / 派队采集,够不着的事项置灰并写明原因);点地目标圈缩到**直径 3.8 米** | | **大殿升级** | 新增**下行锁的完整口径**:非资源、非景观的建筑**必须都已建成**(没建造按 **0 级**算)且等级 ≥ 大殿当前等级,大殿才能升级;理由里会点名"还差谁、现几级 / 尚未建造" | | **营建收尾** | 位置选定、动工成功 ⇒ **收摆放态 + 关建筑浮窗**,但**保留营造模式与建造坞**(建完接着建下一座是常态) | | **城内门人** | 走位三约束:不穿建筑(落在任何建筑占地里就换落脚点)、不出城墙(越界钳回院内)、做事时站在**对应建筑旁**(锚点由后端按活动下发) | ### 大地图 / 走镖收口(2026-09-26) | 改动 | 要点 | |---|---| | **押镖到达即交割** | 抵达判定从「端点 → 城心」改成**本 tick 走过的折线**扫掠(擦着城畿过去也算到);遭遇/商队交涉造成的**临时停车**记下目的地,交涉一结束**自动续行**(旧版停一次就永远停在半路 ⇒ 委托永远不完成);「金镖缺镖头 / 护队人数不够」不再静默 continue,改为事件流 + 日志簿一行 | | **去掉 18 米格子** | 遭遇 / 光点 / 抵达的判定半径改成**米口径**(travel_encounter_radius_m 1.0 米、world_event_spot_radius_m 1.0 米、town_arrive_radius_m 36 米);队伍每 tick 的轨迹按 travel_event_resolution_m(0.5 米)**重采样**,遭遇判定吃这条亚米级折线;山匪漫游目标点改**连续浮点**(不再抽整数格心)。老格口径键保留为兜底(只在米键缺席时才读) | | **左键按住拖动移图** | 左键与中/右键一样映射 PAN(enablePan 显式打开);_bindMouse 仍按位移 + 时长区分「拖动」与「轻点派队」,底部提示补上「左键按住拖动 = 移图」 | | **奇遇 3D 问号** | 每个事件光点旁立一枚 **3.0 米**高的立体问号(圆环 + 短竖 + 圆点三件基本体,无外部资产),绕 Y 轴朝向镜头、按事件类别着色、夜里自发光更亮 | | **大地图昼夜** | 与城池同一套 game_minutes → solar → t 公式(MapScene3D.applyDaylight):主光/半球光/补光的颜色与强度、天空盒压暗、雾色转深蓝;各城池与据点夜里挂**暖色光晕**(白天整组隐藏)+ 固定 3 盏**点光源池**(数量恒定 ⇒ 不触发全场景着色器重编译),按镜头就近分配 | ## 三、成长体系:一条不断档的成长轴 游戏的"耐玩"全压在成长轴上 —— 从掌门到门人、从建筑到武学,每一层都在涨: ``` 门派规模 ← 营建 27 座 × 10 档 ← 资源产出 ↑ ↑ ↑ 门人数量 ← 建筑容量 资源积累 ↑ ↑ 门人战力 ← 四维属性 + 装备 7 槽 ← 打造 / 掉落 ↑ ↑ 110 级境界(11 境 × 10 级) ← 历练 / 出镖 ``` | 轴 | 阶梯 | 说明 | |---|---|---| | **境界** | **110 级 = 11 境界 × 10 小级** | 菜鸟 → … → 武圣;**境门上闸**:每境第 10 级需**闭关突破**(走火入魔赌局) | | **外功** | 每门 **10 级** | 等级由**累计熟练度**现推;练武档在演武场累积 | | **内功** | 6 本心法 × 参悟 | 打坐修为(五系数公式)+ 参悟**逐级解锁武技**;匹配度看资质与兵器契合 | | **生产手艺** | 0~100 | 干生产/打造活累积,喂品质与工时 | | **筑基值** | 0~100(外门) | 练武/淬体汤累积;满门槛+筑基丹+静室**晋升内门** | | **武器技能** | 每门 **10 级** | 5 种兵器各 2 门;**参悟解锁** + 练武熟练度 | | **装备** | 5 档品质 × 7 槽位 | 凡品 → 良品 → 精品 → 宝器 → 神兵(打造台出品) | > 🔴 **老档必须能无损迁移**。等级制从「55 级(11 境 × 5 小级)」升到「110 级(11 境 × 10 小级)」时, > 换算规则是 **`L → 2L − 1`** —— 保境界内相对位置, > 「老 55 级(武圣圆满)」→「新 109 级(武圣归元)」,**境界一寸不退**。 > 存档用 `realm_ver` 版本号识别老档(缺键视作 1),迁移一次后写回 2,**幂等**。 --- ## 四、架构:后端是权威世界,前端只是视窗 这是整个项目最重要的设计决定。 ``` ┌─────────────────────────────────────────────────────────────┐ │ 浏览器(渲染视窗) │ │ three.js 场景 · HUD · 拾取 · 过场视频 · 卡片与浮窗 │ │ —— 不持有任何游戏逻辑,只负责「把世界画出来」 │ └───────────────────────────┬─────────────────────────────────┘ │ WebSocket(全量快照)+ HTTP(命令) ┌───────────────────────────▼─────────────────────────────────┐ │ 游戏后端 gamenet(权威世界 · Python/FastAPI) │ │ 时间推进 · 建造校验 · 门人行为 · 资源产出 · 存档落盘 │ │ 零第三方逻辑依赖:游戏数值与规则全部自己实现 │ └─────────────────────────────────────────────────────────────┘ ▲ │ 读取 game/data/*.json(数值配置 · 唯一真相源) ``` **为什么要这么分?** - **反作弊与一致性**:前端改任何变量都无法欺骗后端,一切以服务端状态为准。 - **进度不丢**:刷新、换设备、断线重连,世界都从后端快照恢复。 - **可测试**:数值与规则是纯逻辑,能在**不开浏览器**的前提下跑完 **1,074 条断言**(2026-10-18 实测)。 - **离线推进**:时间由后端按真实时间推进,关掉页面门派仍在运转。 --- ## 五、技术栈 | 层 | 选型 | 说明 | |---|---|---| | 权威世界 | **Python 3.11 + FastAPI + uvicorn** | 纯自研逻辑,零游戏引擎依赖 | | 实时同步 | **WebSocket** | 后端推全量快照,前端重放 | | 渲染 | **three.js 0.186 + Vite 8** | 正交相机、InstancedMesh、动态昼夜 | | 数值配置 | **`game/data/*.json`** | 建筑 / 门人 / 武学 / 境界,改这里即改玩法 | | 资产 | **GLB(AI 生成)+ PNG** | 由项目内资产生产线产出,见第九节 | | 部署 | **Nginx + PM2** | Nginx 单入口(静态直出 + 反代),PM2 守护后端 | ### 代码规模 | 部分 | 规模 | |---|---| | 后端逻辑 `gamenet` | **42 个 `.py` · 34,176 行** | | 前端渲染 `frontend/src` | **26 个 `.js` · 28,748 行** | | 无头浏览器探针 `web/tools` | **184 个 `.cjs`**(其中 `probe_*.cjs` **89** 个,其余是共享 helper / 门禁 / 断言台账工具) | | 工具链 `tools/` | **84 个 `.py`**(顶层一级;资产导入 / 减面 / 图标生成 / 视频转码 / 表格生成;另有 13 个 `_` 前缀的一次性脚本不计) | | 逻辑自检断言 | `selftest.py` · **1,074 条**(2026-10-18 实测 1,074 通过 / 0 失败;同日两次计时 **393.4s / 328.6s**;静态 `check()` 调用点 **1,069**) | | 游戏资产 | **177.9 MB**(**128 个 GLB** + 112 张图标 + **57 张剧情美术** + 15 段过场视频 + 2 首 BGM) | > 📏 **统计口径(2026-10-18 实测)**:行数按换行符计、**含空行**;资产体积按 1024 进制(字节 ÷ 1024²)。 > PowerShell 的 `Measure-Object -Line` 会漏掉空行,**不要用它核数**。 --- ## 六、目录结构 ``` . ├── web/ # ★ 游戏本体(唯一主线) │ ├── backend/ │ │ └── gamenet/ # 权威世界:逻辑 / 存档 / 账户 / 场景常量 │ │ └── world/ # · 世界大地图:地形生成 / 道路网(MST+A*)/ 游历与遭遇 │ ├── frontend/ # 渲染视窗:three.js 场景 + HUD │ │ ├── src/ │ │ │ ├── scene/ # · map3d.js —— 大地图渲染器(独立 renderer,不借主场景) │ │ │ └── ui/ # · worldmap.js —— 大地图面板 / 指令 / 缩略舆图 │ │ └── public/ │ └── tools/ # 无头浏览器探针 + 验收门禁 │ ├── game/ │ ├── data/ # ★ 数值配置(唯一真相源,改了立刻生效) │ └── assets/ # ★ 游戏资产(177.9 MB) │ ├── models/ # · 128 个 GLB(建筑 / 景物 / 门人 · 批18 另加 12 绑定 + 12 动作包) │ ├── ui/ # · 界面图 + icons/(112 张图标)+ videos/(15 段过场) │ ├── story/ # · 主线剧情美术:28 张人物立绘 + 29 张场景背景 │ ├── audio/ # · 2 首 BGM(山居 / 夜阑) │ └── textures/ # · 贴图 │ ├── tools/ # Python 工具链:资产导入 / 减面 / 校验 / 服务管理 ├── docs/ # 设计总纲 / 接口契约 / 部署与资产文档 ├── deploy/ # 部署配置:PM2 / Nginx / 推送脚本 │ ├── asset-forge/ # 资产生产线:文生图 → 图生3D ├── rig-forge/ # 骨骼绑定工坊 ├── model-forge/ # Blender 建模脚本生成 └── audio-forge/ # BGM / 音效合成(纯 numpy) ``` > 🔴 `game/data/*.json` 与 `game/assets/` 是**不可再生的核心资产**,请勿随手删除。 > 具体说:`game/data/*.json` · `game/assets/models/*.glb` · `game/assets/ui/*.png` > · `game/assets/story/*` · `web/backend/{accounts,saves}/` —— **绝不 `rm -rf game/`**。 > > 📌 **两个"立绘"不是一回事**(代码与文档里都会出现): > `assets/ui/icons/body_*.png` 是**装备界面的人形剪影**(纯色、无细节,上面压 7 个孔位); > `assets/story/portrait_*.png` 是**剧情对话的人物立绘**(五官清晰、要认出谁在说话)。 --- ## 七、快速开始 ### 前置 - Python **3.11+** - Node.js **18+** - 首次运行前安装依赖: ```bash # 后端(零游戏依赖,只需要 Web 框架) cd web/backend && pip install -r requirements.txt # 前端 cd web/frontend && npm install ``` ### 一键启动(推荐) ```bash # Linux / macOS bash run_all.sh # Windows run_all.bat ``` 脚本会依次:构建前端 → 拉起游戏后端 → 拉起资源生成器 → 起单入口代理。 打开 **** 即可游玩。 ### 手动启动(调试用) ```bash # ① 游戏后端 → :8001(本地默认;生产用 GAMENET_PORT=8000) cd web/backend && python -m gamenet.server # ② 资源生成器 → :8788(可选,只有要产资产时才需要) cd asset-forge/backend && ASSET_FORGE_BASE=/forge python run.py # ③ 单入口代理 → :8080(把上面两个合成一个入口) python tools/serve_single_entry.py --host 0.0.0.0 --port 8080 ``` ### 服务与端口 | 服务 | 端口 | 说明 | |---|---|---| | 游戏后端 `gamenet` | **8001** | 权威世界 + WebSocket(本地与当前生产服务器都是 8001;8000 留给同机 idle-wuxia) | | 资源生成器 `asset-forge` | **8788** | 挂 `/forge` 前缀,产 2D/3D 资产 | | 骨骼绑定工坊 `rig-forge` | **8789** | 模型绑骨 | | 单入口代理 | **8080** | 对外统一入口(生产交给 Nginx) | > Windows 上有一套常驻服务管理(脱离终端、不弹窗、输出入日志): > `python tools/services.py {status|start|stop|restart|logs}` > 💡 **本地端口已避开 :8000**(2026-10-18):本机 :8000 被 `D:\idle-wuxia` 的 `node server/index.mjs` 占用, > 游戏后端默认改 **8001**,:8080 反代指到 8001 —— 打开 :8080 仍是本游戏;生产服务器 8.134.249.230 的 :8000 也被 idle-wuxia 占用,因此同样是 **8001**。 > ⚠️ `services.py status` 只按端口判断:若 :8001 被别的进程占用,`services.py start` 会误判「已在运行」并跳过 gamenet。 > 排查:`Get-NetTCPConnection -LocalPort 8001` 拿 PID → `Get-Process -Id | fl Path`;或看 `_logs\game.log`。 --- ## 八、测试与验收 项目有**三层验收**,改完代码请按顺序跑: ### ① 纯逻辑自检(约 6 分钟,首选) ```bash # 约 6 分钟(2026-10-18 两次实测 393.4s / 328.6s) cd web/backend && python -m gamenet.selftest ``` > ⚠️ **验收命令建议带 `PYTHONIOENCODING=utf-8`**(PowerShell:`$env:PYTHONIOENCODING="utf-8"`;cmd:`set PYTHONIOENCODING=utf-8`)—— > 否则 GBK 控制台会在含「⇒」的断言文案处直接 `UnicodeEncodeError` 崩掉,看着像断言失败,其实是编码崩了。 > ⚠️ 必须用 `-m` 模块方式跑。直接 `python web/backend/gamenet/selftest.py` 会因相对导入报错。 覆盖时间推进、建造校验、资源产出、门人行为、存档往返、主线推进、大地图游历与遭遇等 **1,074 条断言**(2026-10-18 实测;含主线**逐卷**体检:每卷的章号连续 / 层次对齐 / 敌人与说话人引用有效 / 难度单调且卷间攀升 / 卷末奖励齐备)。 ### ② 定点探针(无头浏览器) `web/tools/` 下是针对各模块的无头浏览器探针(共 **184 个** `.cjs`,其中 `probe_*.cjs` **89** 个),只在你改动的那块跑即可: ```bash # 殖民地模拟(门派改造批 1-8 · colony 组,串行跑) node web/tools/run_parallel.cjs --suite colony # 10 探针组:营造/暂停/房间/心跳/生产链×2/日程/修炼/敌袭 node web/tools/probe_colony_build.cjs # 蓝图 → 搬料施工 → 竣工 node web/tools/probe_colony_produce.cjs # 砍树→木桌 端到端(--timeout 900000) node web/tools/probe_colony_forge.cjs # 铁锭→兵器 端到端(--timeout 900000) node web/tools/probe_colony_schedule.cjs # 时辰日程 + 练武外功 node web/tools/probe_colony_cultivate.cjs # 打坐修为 / 参悟 node web/tools/probe_colony_raid.cjs # 敌袭状态机 node web/tools/probe_colony_unlock.cjs # 声望解锁 python tools/bench_colony.py # 性能压测:48 弟子满载 tick / 快照体积 # 主线「岁月」(三卷 84 章 / 42 战 / 立绘 / 场景背景) node web/tools/probe_years.cjs # 63 判据:卷页签 / 目录 / 对话 / 立绘 / 背景 / 整层点击 / md 渲染 / 滚动位置 / 战斗链路 python tools/verify_mainline.py # **逐卷**数据体检(引用 / 层号 / 难度 / 奖励) node web/tools/probe_battle.cjs # 139 判据:布阵 / 3D 战场 / 自由移动 / 并发出手 / 兵器表现 / 结算 # 成长与卡片 node web/tools/probe_skill_level.cjs # 武学熟练度等级 node web/tools/probe_tech_cards.cjs # 武学卡片(学派配色) node web/tools/probe_equip_cards.cjs # 装备卡片(品质配色) node web/tools/probe_equip_skill_ui.cjs # 装备与技能面板 # 门人与江湖 node web/tools/probe_members.cjs # 门人渲染与标签 node web/tools/probe_task_card_dock.cjs # 在途任务卡 node web/tools/probe_log_dock.cjs # 日志坞与未读图标 node web/tools/probe_worldmap.cjs # 世界大地图:连续地形 / 45° 锁死 / 派队游历 / 脚印 / 多队 / 缩略舆图 / 遭遇链路(123 判据) node web/tools/probe_wmap_time.cjs # 大地图时辰与昼夜 / 各城池据点夜灯 / 奇遇 3D 问号 / 左键按住拖动移图(19 判据) # 音视频 node web/tools/probe_audio.cjs # BGM 与音效 node web/tools/probe_video_shield.cjs # 过场视频屏蔽 # 界面细节 node web/tools/probe_button_text.cjs # 按钮文案 node web/tools/probe_flyout_scroll.cjs # 浮窗滚动 node web/tools/probe_member_lv.cjs # 门人等级显示 node web/tools/probe_member_tag_badge.cjs # 门人头标 node web/tools/probe_body_figure.cjs # 人物立绘 # 基础 node web/tools/probe_camera_buttons.cjs # 左键 / 右键相机操作 node web/tools/probe_boot_time.cjs # 首屏耗时 ``` > 🔴 **探针不要串跑**(一个循环里连续跑多个)。大场景冷启动会互相污染, > 导致失败点游走、出现**假红**。一次只跑一个。 ### ③ 门禁(四道,改完探针各跑一次) ```bash node web/tools/_chk_shot_timeout.cjs # ① 截图超时必须显式给足 node web/tools/_chk_probe_backtick.cjs # ② 模板串内禁写反引号(探针 + 前端源码) node web/tools/_chk_shared_imports.cjs # ③ 共享 helper 用了必须导入 node web/tools/_chk_probe_eval.cjs # ④ 模板串里的行尾注释必须补 \n(本轮 191 处) node web/tools/_chk_asset_paths.cjs # 诊断:前端源码禁相对 assets/ 路径(子路径部署会 404) ``` 四道门禁(另加 `_chk_mat.cjs`、`_chk_asset_paths.cjs` 两条诊断)守的都是**同一类坑:静默失败** —— 测试还绿着,但证据已经不可信了。 **① 截图超时**:本场景是 **2000 万面级软渲染**,整页截图实测可超 15 秒, 而 Playwright 默认只给 30 秒。超时的后果**不是报错而是静默** —— 截图异常被 `catch` 吞成一行 `[warn]`,**判据照样全绿,图却没出(或还是上一轮的旧图)**。 > 记住那句话:**判据全绿 ≠ 图是新的。** > 规则:**落盘的截图**(带 `path`)必须显式 `timeout ≥ 60000`;不落盘的逼帧截图自动豁免。 **② 反引号**:探针把页面侧代码写成模板字符串,若在那段代码的**注释里**写了反引号, 会**提前把串闭合**。后面内容变成普通 JS —— **语法仍然合法**, `node --check` 一声不响,报出来的是别处某个变量 `not defined`,跟真因隔着十万八千里。 (**前端源码同样受管** —— 那里也大量使用模板串。) **③ 共享导入**:用了没导入只是语法合法、**运行时才** `ReferenceError`。 而探针普遍要跑几分钟(等建造 / 等结算),崩在第五分钟, 症状看着像"产品功能坏了",排查方向整条跑偏。 **④ 拼接串里的行尾注释**:探针把页面侧代码拼成长串交给浏览器执行,串里 `//` 之后 **必须补 `\n`** —— 否则拼出来是**一整行**,把后面的 `return` 与收尾括号一起注释掉。 最毒的地方在于:`READ_MAP` 这类**公共读数**一旦坏,二十多条断言会**一起假红**, 看着像"整个功能都坏了"。`_chk_probe_eval.cjs` 把全部拼接串抽出来逐个 `node --check`。 **诊断 ⑤ 相对 assets 路径**(2026-10-18 生产事故):前端源码里出现 `` `assets/…` `` 这种**相对字面量**时, 根路径部署(本地)看着一切正常,子路径部署却会解析成 `/play/menpai/app/assets/…`(多一段 `/app`)→ 404。 资源 URL 只能走 `appUrl('/assets/…')`(`src/base.js`)或后端下发的 `ui_dir` / `models_dir`。 `_chk_asset_paths.cjs` 静态扫全部前端源码,命中即红。 > 📌 这些门禁的共同点是:**把规矩写成断言,别写成提醒**。 > ② 的注释里明写着"这条警告本来就在文档里写着,本轮还是又踩了一次 —— 靠记性守不住"。 ### 关于 `e2e.cjs` `web/tools/e2e.cjs` 是完整端到端脚本(真点按钮 + 截图),但**成本极高**: 首屏 50 秒以上、一轮十几分钟、多会话并发常把后端重启掉。 ⇒ **已降级为"按需"**。日常验收请用 ① + ②,只在确有必要时跑整轮 e2e。 --- ## 九、AI 资产生产线 游戏里的建筑、景物、门人形象、图标、BGM 与过场视频,都由项目内这套**生产线**产出: ``` 建筑 / 景物 / 门人(128 GLB): 提示词 → [asset-forge] 文生图 → 图生3D → GLB ↓ [rig-forge] 骨骼绑定 ↓ [model-forge] Blender 脚本生成 / 规整 ↓ tools/ 导入 → game/assets/models/ 图标(112 张): tools/gen_*.py → [asset-forge] 豆包 Seedream → PNG ↓ game/assets/ui/icons/ ├── gen_building_icons.py 建筑 25 张 ├── gen_realm_icons.py 境界 11 张 ├── gen_equip_icons.py 装备 70 张 ├── gen_ui_icons.py 界面 4 张 └── gen_body_figures.py 装备界面「人形剪影」2 张 ⚠️ 与下面的「剧情立绘」**不是一回事**: 剪影要"无细节、低对比"(上面压 7 个孔位图标); 剧情立绘要"五官清晰、认得出是谁在说话"。 剧情美术(57 张 = **人物立绘 28** + **场景背景 29**): tools/gen_story_art_plan.py ← 从 mainline.json 算出"需要哪些"(清单可复算) → game/data/story_art.json tools/gen_story_art.py → Seedream 出图 → _tmp/story_art/ tools/make_story_art.py --auto-pick ← 打分自动挑图(+ --overview 出总览给人看) tools/make_story_art.py --install ← 抠白 / 满幅 → game/assets/story/ 过场视频(15 段): tools/prep_task_videos.py(从原片转码)→ MP4 → game/assets/ui/videos/ BGM / 音效: [audio-forge](纯 numpy 合成)→ WAV → game/assets/audio/ ``` | 组件 | 职责 | 依赖 | |---|---|---| | `asset-forge` | 文生图(豆包 Seedream)+ 图生3D(腾讯混元生3D) | 需自行配置密钥 | | `rig-forge` | 给静态模型程序化绑定骨架,导出可动 GLB | Blender | | `model-forge` | 用文本模型生成 Blender 建模脚本并执行 | Blender + 文本模型 | | `audio-forge` | BGM 与音效合成(无缝循环 `wrap_tail`) | 纯 numpy | | `tools/gen_*_icons.py` | 批量生成各类图标(建筑 / 境界 / 装备 / 界面 / 立绘) | 同 asset-forge | | `tools/prep_task_videos.py` | 过场视频转码入库(7 种任务 × 成败 + 入场) | ffmpeg | | `tools/art_style.py` | **美术风格锚点** —— 出图前统一风格,保证一整套像一家人 | 纯 Python | | `tools/gen_buildings.py` · `gen_realms.py` | **从公式生成数值表**(十档 / 110 级) | 纯 Python | | `tools/gen_story_art_plan.py` | **从 `mainline.json` 反算美术清单**(该画哪些人、哪些景) | 纯 Python | | `tools/gen_mainline_volumes.py` | **主线多卷的真相源**:把 `mainline.json` 升级成 `volumes` 并写入卷二/卷三(改台词改这里重跑;**永不重建卷一**) | 纯 Python | | `tools/verify_mainline.py` | **主线数据体检**(逐卷:引用完整性 / 章号连续 / 层与章对齐 / 难度单调与卷间攀升 / 奖励键 / 模型存在) | 纯 Python | | `tools/gen_story_art.py` | 剧情立绘 / 场景出图(支持 `--shard` 分片并行、`--skip-existing`) | 同 asset-forge | | `tools/make_story_art.py` | 立绘抠白 + 场景满幅;**打分自动挑图** + 总览图 | Pillow | | `tools/gen_master_avatar.py` | **掌门头像出图**(男/女候选 + 新旧 76px 对比图;2026-09-24 头像年轻化) | 同 asset-forge | **剧情美术的三个关键取舍**(详见 `docs/剧情美术规划.md`): 1. **"立绘"与"装备界面的剪影"是两套相反的要求**,别混: 剪影要"无细节"(上面压孔位图标),立绘要"五官清晰"(要认出谁在说话)。 ⇒ 所以 `art_style.py` 里是**两个独立风格句**(`STYLE_BODY` / `STYLE_PORTRAIT`), 不共用"画法"部分(只共用题材与画风内核)。 2. **抠图的阈值要按题材定,不能沿用图标的**:图标那套把掩码放宽到 2.2 倍色距 (为吃掉 AI 画的浅灰衬纸框),而"浅灰"正好等于**人物身上的浅色衣料** ⇒ 会把衣服抠出洞。剧情立绘改用**窄阈值 + 不放宽**, 并带一条可量化判据(**"吃掉非背景像素"的比例 < 1%**)。 3. **白晕要去"混合",不是去"像素"**(2026-09-24 抠图换代):窄阈值抠白后,人物边缘 总有 1~3px 的"人物色+白底"**混合带** —— 不够白、抠不掉,原样留着就是 叠在深色场景上的一圈白毛边。新算法(`make_story_art.py#_defringe_white`)按 `观测色 = a·人物色 + (1−a)·纯白` **反解**出人物真色与透明度: 白晕物理消失,且**一粒人物像素都不用吃**(28 张立绘实测"吃掉非背景" 最高 0.03%,红线 1%)。对比"腐蚀 1px"方案:腐蚀会把发丝啃秃,这个不会。 **装备图标的一个巧思**:Seedream **不产透明底**(回的是 JPEG),所以图标做成 「**底色牌 + 中央物品**」的形态 —— **底色直接就是品质色**。 于是"品质不同、边框色不同"由底色承担,**省掉整条抠图链路**, 也避开了抠图边缘毛刺这类经典翻车点。 > 🔁 前端 `equip_card.js` 留了「**有 `icon` 就出 ``,否则回落 SVG**」的口子 —— > 真图没到位时自动降级,**主流程不会被图标阻塞**。 > 🔁 **2026-09-28 出图模型换成豆包 Seedream 5.0 Flash**(`doubao-seedream-5-0-flash-260915`)。 > 同区域 / 同提示词实测(脚本留档 `_tmp/seedream_probe/`): > **4 张候选墙钟 14.3s**(旧 4.0 组图 93.7s,快 6 倍)· 单图 2K 11~15s · `1024x1024` / `2304x1440` 按显式尺寸原样出图。 > 两个坑(`ark_client.py` 里已有挡与兜底,这里记一笔免得再踩): > ① 5.0 Flash **不支持组图** —— `sequential_image_generation` 连传 `"disabled"` 都回 400, > `ArkClient` 因此把 n>1 自动改走「**N 路并发单图**」(实测 4 张两两灰度均差 15~30/255,不是重复图); > ② **不支持 `size="4K"`** —— 预设只认 1K / 1.5K / 2K,或显式 `宽x高`(总像素 921,600~4,624,220); > 传 4K 在本地就报错,不浪费一次请求。 > 📌 **换模型只改 `asset-forge/backend/.env` 的 `ARK_MODEL_ID`** —— asset-forge 与 `tools/gen_*.py` > 全部共用 `ArkClient`,没有第二处硬编码。 > ⚠️ **单价必须同步改 `ARK_PRICE_PER_IMAGE`**(4.0 = ¥0.20、5.0 Pro = ¥0.30;5.0 Flash 的官方价 > 以火山方舟控制台账单为准,当前沿用 ¥0.20 **宁高不低**),否则台账记账会失真 —— > 后端 `COST.PRICE_2D_PER_IMAGE` 与各工具的预估打印都从这里读。 > 🔴 **使用资产生产线前需自备密钥**:复制 `asset-forge/backend/.env.example` > 为 `.env` 并填入自己的凭证。`.env` 已被 `.gitignore` 忽略,**不会入库**。 > > 🔴 **提示词里别写字面色号 / 数字年龄**(2026-09-24 实测):模型会把 > "近似 #F0E3CF" 当画面元素**原样画进图里**(右缘出现色号字样), > 把"三十二岁"画成背景题字 —— 色用文字描述("老宣纸浅米色"), > 年龄用"而立之年"这类**无数字**的说法。发现这类泄漏,重出前先除掉病根。 > > 💡 连登录页的背景图都是 AI 生成的(`game/assets/ui/login_bg.jpg`,1920×1200), > 且是**图生图**产出 —— 拿加载图当参考图,才能保证"跟原画风一致"。 > > 📖 出图前先读 **`docs/美术风格设定.md`** —— 纸色 / 墨色 / 画风的统一口径在那儿。 > > ⏸️ **未接线**:`audio-forge` 已产出第三首 `bgm_menpai_jianghu.wav`(江湖), > 但**尚未接入游戏音频表** —— 目前线上只有「山居(昼)」「夜阑(夜)」两首。 > 接线方式见 `audio.js` 顶部注释(拷进 `game/assets/audio/` + `TRACKS` 加一条)。 --- ## 十、部署 生产环境是一台**共享服务器**(8.134.249.230,同机还有 AIGPart / idle-wuxia / occ-game / dsh-relay): ``` 公网 :80 ─► AIGPart 的 Nginx ─┬─► /play/wuxia/ 别的游戏(idle-wuxia :8000) ├─► /play/menpai/ 本项目 → 127.0.0.1:8001 └─► / AIGPart 平台首页 ▲ PM2: menpai-game(127.0.0.1:8001,autorestart + 开机自启) ``` **要点**: - 本项目**不占 80 根路径、不新增监听端口、不改别人的 location**:只在 AIGPart 的 :80 server 块里加一行 `include /etc/nginx/conf.d/menpai-locations.inc;`,该文件由 `deploy/prod/nginx-menpai-locations.inc` 维护(proxy_pass 末尾的 `/` 会剥掉 `/play/menpai` 前缀)。 - 后端固定 `127.0.0.1:8001`(同机 8000 已被 idle-wuxia 占用),:80 由 Nginx 收口。 - 前端用 `web/frontend/public/app-base.js` 在**运行时**补挂载前缀:同一份代码既能跑根路径(本地 / 单入口反代),也能跑 `/play/menpai/` 子路径;生产构建带 `VITE_BASE=/play/menpai/app/`。 - 静态、API、WebSocket 全部走 `/play/menpai/` 子路径反代;`/play/menpai/` 会 301 到 `/play/menpai/app/`。 - PM2 的 `interpreter: 'none'` **必写** —— 否则它拿 node 去解释 Python,进程秒退。 线上入口:(同机 AIGPart:;江湖:)。 详细运维见 `docs/生产部署-阿里云.md` 与 `deploy/prod/`。 ### 更新线上 ```bash bash deploy/prod/push.sh # 同步代码 + 重建前端 + 重启后端 bash deploy/prod/push.sh --no-build # 只改后端时用(快) bash deploy/prod/push.sh --data # 改了 game/data/*.json 数值 bash deploy/prod/push.sh --assets # 新增/替换了 GLB 或界面图(整包 116M,较慢) ``` > ⚠️ 推送脚本同步代码时会**主动避开** `web/backend/{accounts,saves}/` —— > 那是玩家活数据,覆盖等于**玩家进度归零**。 > > 💡 **只改了几个资产时,别用 `--assets` 传整包**。先算差异再单独传(清单 + 同名大小两层): > ```bash > find game/assets -type f -printf '%P\n' | sort > /tmp/l.txt > ssh 'cd /opt/menpai/game/assets && find . -type f -printf "%P\n" | sort' > /tmp/r.txt > comm -23 /tmp/l.txt /tmp/r.txt # 服务器缺的 > ``` > 实测一次发布只缺 63 个文件(18 MB),省下 100 MB 传输。 ### 发布后验收 ```bash node web/tools/probe_prod_assets.cjs # ① 资产**全量对账** —— 纯读,不污染数据 node web/tools/probe_prod_tutorial.cjs # ② 端到端链路 —— ⚠️ 会注册账号,跑完必清 ``` **① 资产全量对账**:读本地 `game/assets` 目录树 → 逐个查线上能否取到。 **新增任何资产都自动被覆盖,零维护**(早期版本是硬编码抽样清单,加一类资产就要 回来手工补样本 —— "忘了补"的后果是"新资产坏了但探针全绿")。 实测 220 个文件约 **5 秒**跑完。 🔴 必须用浏览器而不是 `curl` —— 图标 / 视频文件名含**中文**(`weapon_神兵.png`), curl 在 Git Bash 下传中文路径会 **404**,那是 **curl 的编码问题**,不是产品故障; 浏览器发请求时**必然 URL 编码**,才与服务端 UTF-8 文件名对得上。 **② 端到端链路**:注册 → 立派开宗 → 进 3D 场景 → 新手任务卡片与浮窗,**31 项判据**。 判据全绿的标准:`CONSOLE_ERRORS` / `HTTP_BAD` / `REQ_FAILED` **三项全空**。 > ⚠️ ②**会往生产库注册真账号** ⇒ 跑完必须清理(三处对账:账号 / 会话 / 存档): > ```bash > ssh menpai-aliyun 'pm2 stop menpai-game' # ① 先停(引擎会把内存写回磁盘) > scp deploy/prod/clean_test_accounts.py menpai-aliyun:/opt/menpai/web/backend/_c.py > ssh menpai-aliyun 'cd /opt/menpai/web/backend && python3 _c.py && rm -f _c.py' > ssh menpai-aliyun 'pm2 start menpai-game' # ③ 再起 > ``` > 清理脚本按**有效用户名单反查孤儿**,`aowind@qq.com` 白名单永不删。 ### 🔴 改了地形 / 放置区之后的额外一步 挪了河道、城墙、放置边界之后,**已建建筑不会被回溯检查** —— `placement_check` 只在**新放置**时跑。于是楼可能"长在河里"却不报任何错, 要等玩家自己看见。 发版前用**新代码**验一遍**真实存档**: ```bash python tools/verify_buildings_in_zone.py <存档目录> # 只读 ``` 它复用产品的 `placement_check()` —— **不自己重写一份几何** (两处各写一份 = 判据迟早分家)。输出每座建筑合法 / 非法, 非法时会提示"别直接把新代码发上去当无事发生"。 > 💡 取证方式:把线上存档 `scp` 到本地临时目录,用本地(新)代码验。 > 无 `x/z` 的建筑(如城墙,位置由代码按常量算)会自动跳过。 --- ## 十一、注意事项 ### 🔴 绝不入库的三样东西 | 路径 | 内容 | 后果 | |---|---|---| | `web/backend/accounts/` | 真人账号与会话 | 隐私泄露 | | `web/backend/saves/` | 玩家存档 | 隐私泄露 + 进度污染 | | `asset-forge/backend/.env` | 云端 API 密钥 | 密钥泄露、被盗刷 | 三者均已在 `.gitignore` 中排除。**新增敏感文件时,请同步补规则。** > ⚠️ **`.gitignore` 不支持行尾注释**。写成 `web/render/ # 出图目录` 会被当成 > 字面模式(连空格和井号一起),规则**永远匹配不上** —— 而且不报错。 > 注释必须独占一行。改完用 `git check-ignore --no-index -v <路径>` 验证。 > > ⚠️ **探针出图目录有三个落点**,新增探针时别只加一个: > `web/render/` · `web/tools/_shots/` · **`web/tools/render/`**(多数探针的默认输出)。 > 排查已入库的出图:`git ls-files <目录> | wc -l`; > 找还有哪些落点:`grep -rn "'render'" web/tools/*.cjs`。 ### 改代码前请留意 1. **改常量 / 规格后,务必跑依赖它的测试** —— 断言是跟着规格走的。 2. **新增 HTTP 接口必须鉴权**(`require_session`),免鉴权的只有 `/api/auth/*` 与 `/api/health|scene|meta`。 3. **前端使用的字段名必须与后端 `scene.py` 逐字一致** —— 拼错不会报错,会静默退回旧行为,非常难查。 4. **`game/data/*.json` 是数值唯一真相源**,不要在代码里再写一份。 5. **改 `web/tools/` 下的探针后,跑一次三道门禁**(截图超时 / 反引号 / 共享导入)。 6. **布局常量的唯一真相源是 `web/backend/gamenet/scene.py`**。 7. 🔴 **改「等级 / 档位」这类数字轴之前,先想老档怎么办** —— 存档里的数字**含义**变了,不迁移就是"老玩家一夜掉五个境界"。 正确姿势:给存档加**版本号**(`realm_ver` 那样),缺键视作老版 ⇒ 走迁移 ⇒ 写回新版号(幂等)。 发版前**用真实存档验一遍迁移**,别只在合成数据上跑(合成用例只能证明公式对, 证明不了"线上那几份老档真被迁移了")。 ```bash # 发版前:先备份,再验(脚本是只读的) ssh 'cd /opt/menpai/web/backend && cp -r accounts saves /opt/menpai/_bak_$(date +%s)' scp tools/verify_legacy_migration.py :/opt/menpai/_v.py ssh 'cd /opt/menpai/web/backend && python3 /opt/menpai/_v.py; rm -f /opt/menpai/_v.py' ``` 8. 🔴 **老档迁移的表在 `web/backend/gamenet/core/models.py` 的 `RealmSystem`** —— 老公式(`legacy_exp_needed`)要**固化在迁移器里**,不能跟着新公式一起改, 否则再也算不出老档的"当前级内进度"。 ### 环境说明 本项目的画面在**软件渲染(SwiftShader)**下也要求可用,因此对性能与等待上限格外敏感: 无头环境下一切"等待上限"都必须比实测最慢值留足余量,否则会得到**假红**。 --- ## 十二、文档索引 | 文档 | 内容 | |---|---| | `docs/参考-了不起的修仙模拟器-拆解与门派改造方案.md` | **门派改造总方案**(竞品拆解 / 八批计划 / 分系统设计) | | `docs/game-design-decisions.md` | **决策台账**(D-001~D-028 全部拍板 · 批 1–18 验收与 2026-10-18 落库记录) | | `docs/设计-AIGPart SSO 接入清单.md` | **AIGPart 单点登录接入**:江湖侧三处改动 + 老账号按 email 迁移 platformUid 方案(待拍板) | | `docs/游戏设计总纲.md` | 玩法与数值的权威定义(含公式) | | `docs/技术架构总纲.md` | 前后端分工与通信协议 | | `docs/*-接口契约.md` | 门人 / 招募 / 日志等模块的接口约定 | | `docs/生产部署-阿里云.md` | 生产环境部署与运维 | | `docs/一体部署与运维.md` | 本地一键部署原理 | | `docs/资产总表.md` · `资产台账.md` | 资产清单与成本台账 | | `docs/3D资产生产体系-总体建设方案.md` | 资产生产线设计 | | `docs/剧情美术规划.md` | **主线立绘 / 场景**的清单、规格、生产链路与"挑图边界" | | `docs/项目全景-功能与模块总览.md` | 一页看懂全部功能与模块边界(新人/OX 交接用) | | `docs/设计-走镖系统融入方案.md` | 走镖(押镖 / 期限 / 镖职 / 分号 / 商队)的设计与数值落点 | | `docs/参考-运镖天下之四大镖局-设定整理.md` | 走镖系统的参考素材整理(非权威,仅背景) | --- ## 许可 - 本项目(代码与项目自产资产)以 **MIT License** 开源,完整条款见 [LICENSE](LICENSE)。 - `vendor/` 下的第三方素材保留其原始许可(如 KayKit Character Animations 为 CC0 1.0), 出处与许可声明见 [vendor/dl/CREDITS.md](vendor/dl/CREDITS.md)。