Files
youle_cocos/docs/superpowers/implementations/2026-09-08-room-platform-refactor.md
joywayer 35216f75e7 feat: integrate room framework and isolated subgame bundles
Complete room UI and protocol integration, move game definitions and resources behind bundle entries, publish authoritative version XML, and document single-game builds. Include all current resource changes and experiment artifacts.
2026-09-09 03:13:18 +08:00

104 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 房间平台重构实施记录
日期:2026-09-08。工作区:主 checkout;分支 `codex/web-native-settings`。本次仅修改前端,没有修改服务器、原工程或协议字段。
## 已落地的结构
### 游戏装配
唯一注册入口是 `assets/app/composition/game-definitions.ts`。游戏 key、route、工厂、聊天配置、创建页/房间组件名称及资源路径在这里关联。工厂接收装配身份,不再各自重复定义 key/route。
公共 `PlatformStartup` 依赖 `GameComposition`,不导入具体游戏或应用注册表。原 `SubgameAssets` 已通过 Cocos asset-db 移到组合根,UUID 保持 `ec19e470-cf36-40e8-b420-e4314e5fbf07`。模板与二七王房间视图共用 `CommonRoomViewBase`,二七王不再继承另一个游戏。
聊天内容与敏感词迁到对应游戏目录;SDK 只持有聊天配置契约。边界检查扫描 framework、实际 assets/games 和公共 scripts,禁止公共层依赖游戏/组合根、禁止游戏相互依赖。旧版 LoginFlow/RoomEventProbe/RoomSceneStart 明确隔离,现代代码不能导入这些原型入口。
资源检查直接读取同一注册表,再解析 TypeScript 继承关系及 meta UUID,验证组件唯一、根节点挂载、脚本可解析、资源类型和所属游戏一致。检查不会自动删除资源组件。装配校验不预执行游戏工厂,真实 open 时才创建并校验模块;100 次 Runtime 进退恰好创建、挂载、释放各 100 次。
### 协议与输入
`Roomtype = JsonValue`。平台验证可传输的有限、无循环 JSON,保留值与类型;不读取配置位、长度或推断游戏规则。非法 undefined、稀疏数组、非有限数字、访问器和非 JSON 对象在边界拒绝。保存配置读取和 VIP 入口也不再限制为 string/array。
`room.entered.entry` 保留 created、login-waiting、login-restored、joined-waiting、joined-snapshot、joined-started 来源。原始载荷和快照不因内部事件转换而丢失。
`room.started` 覆盖 self_makewar、other_makewar,以及 self_join_room / other_join_room / player_prepare 携带 deskwar 的路径。原工程 `makewar` 是处理函数名,线上 RPC 是 `other_makewar`。准备状态提交先于开战通知;deskwar 优先于 deskinfo,避免同一加入包同时执行 StartWar 和恢复。
兼容期保留现有 `restore(deskinfo)`。当前游戏只记录恢复快照,不宣称已有二七王牌桌恢复显示。
### 房间生命周期
`RoomCoordinator`、`RoomScope`、`RoomMailbox` 管理异步挂载、generation、排队和清理。实际 Runtime 已接入,不是独立未使用的工具类。
房间业务包在挂载期间排队;就绪后按整包执行 Router、Store 提交及游戏回调。同一个包的游戏回调在该事务内执行,因此第一条 player_prepare 的处理器不会读到第二条包提交后的状态。游戏路由采用相同顺序。登录/入房替换、踢出和换服等控制消息按原协议屏障处理,不被慢场景阻塞。
挂载、UI 绑定完成后才投递进入/恢复事件。退出或进入失败先撤销现有 Host 租约,再释放所属 UI、队列、订阅和计时器。旧 Promise 晚到不能绑定新房间;多项清理继续执行,保留原始错误。同步异常仍由调用链报告,异步失败走统一 fatal 诊断。
普通换服与解散换服分开:后者仍保留服务端结算所需的房间上下文。没有实现的游戏结算继续显式报错,不用空处理器冒充接入。
队列预算单独声明于 `framework/config/room-lifecycle.ts`:256 项、等待 30000 ms。这是可调整的客户端运行预算,不是测得的设备性能阈值。
### SDK 能力与事实投影
生产 Host 提供 `room / messages / ui / scope` 分组能力。准备与退出复用平台身份填充和命令策略;两个游戏工厂已迁移到这些能力。旧 Host 方法仍作为兼容表面存在,`requireRoomCapabilities` 在缺少新端口时显式报错,不提供伪默认实现。
数字、数字文本、倍率请求返回 confirmed/cancelled。取消原因是 user、scope-ended、replaced。同类重叠请求拒绝;离房、替换和用户关闭都有确定结果;迟到确认不能继续回调。数字工具的等待绑定机制受同一租约清理。
loading 与业务 tips 已接入真实 FeedbackPanels 的所有者句柄。一个来源结束不会关闭其他 loading,也不会关闭更新的业务提示。`Layer612_Tips` 仍只显示面向玩家的业务内容,程序错误走诊断。
游戏投影由游戏模型拥有,消费者只读;完整版本含 revision、roundPhase、selfParticipation、scoresBySeat、restrictions。投影不修改平台玩家、准备状态或资产。命令发送及公共按钮都消费 deny-only 限制,游戏不能放开平台已经禁止的操作。当前两款游戏没有已迁移的局内模型,明确返回 null;不从平台 stage 猜出局内事实。
**音频所有者端口未发布**:现有 RoomVoiceAdapter 的原生契约没有播放停止接口,不能承诺“释放句柄即可停止原生音频”。原有语音适配保持工作,未修改原生接口,也未构造空 audio 能力。
### 展示与资源
Store 为聊天消息分配客户端本地稳定 ID,不改变收发包。RoomChatPanel 按 ID 增量维护历史行;公告也保留已有节点。同帧状态变化合并为一次历史刷新。用户上翻历史时保留滚动位置,位于底部时继续跟随新消息。
RoomUi 通过共享头像租约缓存去重请求和 SpriteFrame/Texture2D。URL 替换和节点释放撤销旧所有者,迟到加载不能覆盖新头像。空闲缓存上限 32 项;活动引用不因缓存淘汰被销毁。资源关闭逐项执行,异常不会阻止其余清理。
投票倒计时仍依据 deadline 与 Date.now 计算,后台恢复后重新计算剩余时间;计时器不决定服务端结算。当前数据规模未提供可变行高虚拟列表的必要证据,因此没有引入虚拟化。
## 验证与性能证据
- 实施前相关基线:137 项通过。已有未提交修改 131 项、序列化资产哈希 47 项已记录于 `out/room-platform-refactor/`。
- 最终完整 Node 测试 **950/950 通过**;framework 与 Cocos 两套 TypeScript 检查通过;导入边界和两游戏资源装配检查通过。
- 通过 Cocos builder 生成独立 `build/web-mobile-room-refactor`,任务 `1788869153827` 成功(19 s)。产物启动场景为 PlatformStartup,主脚本包含新的 GameComposition、房间队列和生命周期代码;工程保持 `script.loose=false`。构建成功不代表已经完成真实账号整局联调。
- 真实 Runtime 测试覆盖创建/加入/登录恢复、开战、投票/结算边界、退出、慢挂载、踢出、断线、换服、队列超限、清理失败、整包状态顺序和 100 次进退。
- Cocos Creator 3.8.8 / Windows / Electron 31.3.1 的 Game View:二七王实际提交按钮的 32 种组合均输出 11 位字符串;模板提交自己的数组。
- 实际聊天预览:50 行追加到 51 行,原 50 个 Node 均保留;5 次同帧更新产生 1 次历史刷新;上翻位置保持。Cocos 有 3 次 Layout 检查、2 次实际布局,不能把“1 次历史刷新”写成“引擎只布局 1 次”。测量包含人工等待帧的 82 ms,不作为渲染耗时指标。
- 真实头像测试:相同 URL 的两个节点共用同一个 SpriteFrame;100 次 Cocos RoomScope + 房间聊天 UI 挂载/释放后,Canvas 节点数 8 → 8,活动头像租约为 0,保留 1 个有界空闲缓存资源。
- 预览复现脚本:`scripts/verify-room-refactor-preview.mjs`、`scripts/verify-room-resource-cycles.mjs`;原始结果:`out/room-platform-refactor/preview-result.json`、`resource-cycles.json`。测试停止真实 socket,使用本地夹具,没有向真实账号创建房间或扣卡。
这里只报告当前 Windows/Cocos 测量。未据此承诺移动设备帧率、内存上限或线上吞吐量。
## 尚未覆盖的业务与验收
- 二七王完整出牌、牌桌 deskinfo 恢复渲染、结算界面、回放、未支持的 VIP/百人场不属于本次平台核心接入成果。
- 没有进行真实服务器账号的创建/开战/重连整局联调,也没有执行 Android/iOS 原生设备验收。
- `room.entered.entry` 与 Host 旧方法保留兼容期。新接入使用来源事件和分组能力;后续迁移全部旧调用方后再移除兼容表面。
- 游戏投影为 null 的当前游戏不能展示未实现的局内数据;接入模型时由该游戏提供源,公共命令和视图已经消费该源。
## 工作区保护
没有提交、合并、stash 或服务器改动。没有手改 prefab、scene、anim、meta。原装配脚本通过编辑器移动并保留 UUID;旧公共敏感词模块通过编辑器删除,由对应游戏文件接管。
资产基线对比中,已有场景/prefab/动画等哈希保持;两处原路径不存在:迁出的公共敏感词模块 meta,以及编辑器 refresh 清理的 `assets/.meta` 孤立文件。详细差异保留在 `baseline-asset-differences.json`,不以批量 restore 覆盖工作区。
## 2026-09-08 补充:子游戏身份与导出选择边界
接入、切换子游戏不得修改 framework 代码或资源。框架只消费应用注入的完整身份和 GameDefinition,不内置具体 gameid。
- 各子游戏的 gameid 唯一来源为 `assets/games/<game>/game-config.ts`。
- 应用注册表 `assets/app/composition/game-definitions.ts` 引用对应配置。
- 当前游戏唯一选择项是启动场景应用组件 `SubgameAssets.gameKey`;当前为 `erqiwang`。在 Cocos 编辑器配置该组件并绑定对应 createRoom、room、roomScene 资源。禁止手改场景或 meta。
- 应用层 `assets/app/composition/build-identity.ts` 保存渠道默认值,组合所选游戏身份;`PlatformStartup` 经 `GameComposition` 契约注入 `resolveRuntimeConfig`。
- H5 保持 agentid/channelid/marketid/version 的 URL 覆盖。gameid 不接受 URL 覆盖。原生仍从原接口读取渠道,仅 gameid/version 来自注入配置;没有原生渠道时显式报错,不回退到 H5 渠道默认值。
- 缺少身份或游戏配置直接报错;不猜测默认游戏。旧 bootstrap 入口也必须显式注入身份。
- 二七王保留当前联调注册 ID。template ID 来自原工程 Game_Surface_3/version.js,其在当前开发服务器的注册状态未验证。
本次落实选择与身份注入,未新增按游戏裁剪构建产物的工具。当前注册表仍引用两个游戏;实际导出包是否排除未选游戏代码和资源,需要在后续构建隔离流程中单独落实与检查,不能以运行时只选一个游戏作为裁剪证明。
验证:953/953 自动测试通过;框架与 Cocos 严格类型检查通过;import boundaries、两套房间资源检查和 diff whitespace 检查通过。Cocos MCP 已导入三个新增脚本并生成 meta;重启 Game View 后,PlatformLogin 中 SubgameAssets.gameKey=erqiwang,注入身份与 PlatformStartup 实际解析身份的 gameid 一致,均为当前二七王注册值。未发送创建房间请求,未验证 template 当前服务器注册。
## 后续修订:version.xml 单一来源
以上“game-config.ts 保存 gameid、build-identity.ts 保存渠道和版本”的阶段方案已被 `2026-09-08-version-xml.md` 替代。当前身份与版本唯一来源是各游戏 version.xml;game-config.ts 只定位资源,build-identity.ts 仅保留 XML 没有的网页 marketid。XML value 映射 versionCode(登录协议数值 version),XML name 映射展示 version。此前将原生更新版本与协议版本分别配置的建议不适用,以用户最终确认的映射为准。