22 KiB
YouleNexus 现代化框架与子游戏零实现耦合迁移设计
状态:已由用户确认采用(2026-09-04)。
本文是 framework 逻辑迁移、公共界面/资源升级、子游戏接入与独立打包的权威架构规范。
服务器协议的最高权威仍是
docs/protocol/;原生与远程配置契约的最高权威仍是原工程对应源码和仓库native-bridge-contract技能。
本文替代以下包含旧工程布局或运行时多游戏注册假设的文档:
docs/superpowers/specs/2026-09-04-platform-vertical-slice-design.mddocs/superpowers/specs/2026-09-04-platform-vertical-slice-contract-inventory.md中的目标架构与建议列;其中旧源码证据仍可作为取证索引docs/superpowers/plans/2026-09-04-platform-vertical-slice.md
1. 背景与目标
YouleNexus 已完成主要公共界面资源迁移,下一阶段开始迁移平台和子游戏逻辑。新架构不要求复制旧工程内部设计,但必须让服务器、远程配置服务和原生 App 无法观察到实现替换。
本设计同时达成以下目标:
- 服务器零改动:协议字段、类型、结构、route/rpc、序列化结果和可观察时序与旧客户端一致。
- 配置服务零改动:
gameserver获取、URL 构造、GET 请求和data.urlserver解析保持一致。 - 原生 App 零改动:
window.settings和 WVJB handler 名称、数据、方向、回调约定保持一致。 - framework 唯一真源:公共代码、界面和资源只在
YouleNexus/assets/framework维护。 - 子游戏零实现耦合:framework 内部重构、公共 Prefab 调整或公共资源替换时,已有子游戏源码无需修改。
- 单游戏独立发布:一款子游戏与当前 framework 构建为一个完整 ZIP,ZIP 不包含其它子游戏。
- 高效高性能:单路由、最少复制、状态单源、按帧合并渲染和确定性生命周期。
2. 术语与精确定义
2.1 “零耦合”的精确定义
绝对零依赖不成立:子游戏必须通过某种契约调用平台能力。本设计所称“零耦合”是零实现耦合:
- 子游戏只依赖稳定、最小、纯 TypeScript 的 Game SDK 公共契约。
- 子游戏不依赖 framework 的网络实现、Store、Router、Session、公共 Prefab 节点结构或原始 WVJB 对象。
- framework 不导入任何具体子游戏实现。
- 双方只在编译期 Composition Root 组合。
- Game SDK 契约保持兼容时,framework 的代码、界面和资源可以独立升级,子游戏源码无需修改。
2.2 发布单位
每次构建只选择一个 games/<name>:
当前 framework + 选中的一款子游戏 -> 一个自包含构建工作区 -> 一个完整 ZIP
不同子游戏共享 framework 源码,但不共享发布包。framework 不单独发布,也不热更新。
2.3 两类兼容层
External Contract Adapters是永久架构:负责服务器、配置和原生 App 的精确兼容。Legacy Compatibility Facade只在迁移期存在:将少量旧调用翻译为新 Command/Port;新代码和新子游戏禁止依赖,迁移完成后删除。
3. 选定方案与否决方案
采用“外部契约冻结 + 现代内核 + 纵向切片替换”。旧工程只作为行为 Oracle,新工程从第一天使用最终目标架构。
不采用以下路线:
- 完整忠实迁移后再整体重构:会重复开发,并使全局状态、动态钩子和 UI 节点耦合进入新工程。
- 脱离旧工程一次性重写:难以发现旧协议、切服、重连、配置和原生桥的隐藏时序。
- 运行时多游戏插件系统:每个发布包只有一款游戏,不需要 GameRegistry、动态发现、版本协商或远程 Bundle。
- framework 热更新:framework 与选中游戏始终一起构建和发布。
4. 总体架构
服务器 / 配置服务 / 原生 App
|
v
External Compatibility Adapters
Wire Codec / Remote Config / Native Bridge
|
v
Platform Application Core
Commands / Use Cases / Session / Stores / Router
|
+------+------+
| |
v v
Framework UI Game SDK Public Contracts
Presenter/View GameEntry/GameHost/GameModule
|
v
当前单款子游戏
推荐目录:
cocoscreator_projects/
├── YouleNexus/assets/framework/
│ ├── sdk/ # 唯一公共 API;不得依赖 framework 内部模块或 cc
│ ├── application/ # 平台用例、Command、Session 编排
│ ├── domain/ # 平台状态和不变量
│ ├── adapters/ # server/config/native/Cocos 边界适配
│ ├── presentation/ # 公共 UI Presenter、ViewModel、Slot Host
│ ├── ui/ # 公共 Prefab、主题默认值和资源
│ └── compat/legacy/ # 迁移期适配;禁止新代码依赖
├── games/<name>/assets/
│ ├── app/CompositionRoot.ts
│ └── game/
│ ├── GameEntry.ts
│ ├── protocol/
│ ├── domain/
│ ├── application/
│ ├── presentation/
│ └── assets/
├── build-workspace/<name>/ # 发布期实体化工程
└── dist/<name>/ # 独立 ZIP 与构建清单
CompositionRoot.ts 是唯一允许同时引用 framework bootstrap 和本游戏 GameEntry 的文件。它不包含业务逻辑,由模板创建并由工具链校验。framework 与游戏实现本身均不得跨边界引用。
5. 依赖规则
5.1 子游戏允许依赖
framework/sdk暴露的公共契约。- Cocos Creator
cc,仅用于本游戏节点、组件、动画和资源。 - 本游戏
assets/game下的模块和资源。
5.2 子游戏禁止依赖
framework/net、protocol、application、domain、platform、presentation、ui、core、compat等内部路径。- framework 的 Store、Reactive、Router、Session、EventBus 或 WebSocket。
- framework 公共 Prefab 的节点名、层级、组件实例或 UUID。
- 原始
window.settings、WVJB、JSB bridge 对象。 - 任意平台 route/rpc 的原始发送能力。
5.3 framework 禁止依赖
games/<name>或任何具体游戏符号。- 游戏内部协议 DTO、玩法状态、组件和资源。
- 通过游戏名、路径扫描或反射发现实现。
5.4 自动门禁
静态 import-boundary 测试必须扫描 TypeScript import。除 Composition Root 外,发现跨边界导入立即失败。禁止用 barrel 重导出、动态 import 字符串或路径别名绕过规则。
6. 外部兼容边界
6.1 服务器
必须保持:
- 客户端信封
{app, route, rpc, data},app仍为旧协议要求的值。 - 服务器下行单层结构及浏览器
MessageEvent.data的处理语义。 - platform、agent、room 和游戏 route 的原字符串。
- 所有业务字段名称、类型、可选性、数组嵌套和发送顺序。
- 心跳、断线、重连、agent/room 切服、关闭旧连接再连接新地址的时序。
roomtype的完整嵌套数组结构。deskinfo的原始结构和旧工程真值触发语义。
平台层不解析游戏专属 roomtype 内容,不解析或重写 deskinfo,不对游戏 payload 增删字段。游戏 payload 从 Envelope 路由到当前 GameSession 时保持同一引用。
每款游戏的 protocol/ 是该游戏对局 route/rpc、roomtype、deskinfo 的唯一前端来源;其内容必须来自真实旧子游戏源码或抓包,不得从模板臆测。
6.2 远程配置
永久适配器必须复刻以下流程:
Game_Config.Debugger.gameserver 等价来源
-> URL 参数 gameconfig 或 window.settings.getothername("gameserver") 覆盖
-> 保持旧 ifast_random() 防缓存语义构造 URL
-> GET 远程 txt
-> 读取响应 data.urlserver
-> 进入连接流程
请求方式、覆盖优先级、URL 字符串和解析字段都属于外部契约。适配器可把成功结果转换成内部只读 RuntimeConfig,但下游不得补服务器地址默认值。
6.3 原生 App
永久适配器必须保持:
window.settings.getothername(name)的同步调用名称和返回数据。setupWebViewJavascriptBridge初始化语义。window.WVJBCallbacks、WebViewJavascriptBridgeReady和wvjbscheme://__BRIDGE_LOADED__兼容流程。registerHandler/callHandler的原 handler 名、方向、payload、responseCallback 数据结构、次数和时机。- 分享、视频、语音、电话、通讯录、电量、wifi、网络、摇一摇等现有 handler。
TypedNativeBridge 只增加编译期映射和能力限制,不改变任何运行时名称或数据。子游戏拿不到原始 bridge。
7. Platform Application Core
7.1 单一 Router
所有网络业务消息只经过一个 Router:
Envelope
-> route 属于 platform/agent/room:查平台 rpc Map
-> route 等于当前 GameEntry.route:交给当前 GameSession
-> 其它 route 或未注册平台 rpc:显式报错
现有 Router 与 RoomRPCBus 的并行分发职责须合并。Router 只负责分类,不持有业务状态,不更新 UI。
7.2 Session 状态机
PlatformSession 负责连接和平台生命周期;GameSessionHost 负责当前桌游戏生命周期。推荐状态:
idle -> attaching -> active -> restoring -> disposing -> idle
每次进入牌桌创建新的 GameModule 实例;退出、切服、被踢或销毁时统一 dispose。GameSession 不跨桌复用。
7.3 状态唯一来源
AppState:运行模式、连接阶段、渠道身份和启动信息。PlayerState:玩家身份和资产。RoomState:房间、座位、玩家公共状态和准备状态。GameState:仅由当前 GameModule 私有持有,framework 不复制。
一次业务事件只允许一次原子状态提交。UI 和游戏只能读取投影或不可变快照,不得反向修改平台状态。缺失或非法的必需数据在边界或权威来源处显式失败,下游不猜值。
7.4 Command 与 Port
UI 和子游戏不直接发送平台协议。它们调用语义明确的 Command,例如登录、准备、退出房间、发起解散。Application Use Case 负责读取当前状态、构造完全一致的 Wire DTO 并通过发送 Port 输出。
游戏自定义包使用独立受限通道 server.send(rpc, data);route 由 GameEntry 在组合期绑定,游戏不能指定 platform/agent/room route。
8. Game SDK 公共契约
framework/sdk 必须是纯 TypeScript 公共层:
- 不 import framework 内部模块。
- 不 import Cocos
cc。 - 不暴露 Reactive、EventBus、Store 或实现类。
- 只包含 DTO、窄接口和生命周期契约。
概念能力如下,具体签名在实施计划中以测试先行确定:
8.1 GameEntry
- 唯一游戏标识和服务器 game route。
createModule()工厂。- 支持的座位数/房间人数声明。
roomtype解释和展示能力入口。- 主题、语义资源和 Extension Slot 声明。
每个子游戏工程只有一个 GameEntry。没有 GameRegistry、运行时发现或版本协商。
8.2 GameModule
- attach/enter:接收 GameHost,初始化该桌私有状态。
- receive:接收本游戏 rpc 和原始 data。
- restore:用服务器
deskinfo完整恢复对局。 - platform event:接收玩家加入、离开、准备、上下线、解散等必要事件。
- pause/resume:处理前后台切换,仅在旧行为确有对应语义时提供。
- dispose:释放监听、计时器、Tween、节点引用和本桌资源。
旧 Game_Modify 的大钩子表不原样成为永久 SDK。迁移时先按真实调用行为归类为少量 typed event、query 和 command;只有无法立即改写的调用进入 Legacy Facade。
8.3 GameHost
server.send(rpc, data):只能发送当前游戏 route。platform:准备、退出、解散等白名单 Command。snapshot:Player、Room、App 的只读公共投影。seat:绝对座位与视图座位转换。native:按旧 handler 名调用或注册的受限 typed API。ui:公共提示、确认框等稳定服务,不暴露节点。
GameHost 生命周期与 GameSession 一致。dispose 后继续调用必须显式失败。
9. 公共 UI、资源与子游戏扩展
9.1 framework 所有权
登录、大厅、房间公共区域、玩家公共信息、聊天、设置、分享、断线、重连等公共 Prefab 和资源归 framework 所有。子游戏不得复制后修改公共 Prefab。
公共 UI 只通过 Presenter/ViewModel 消费平台状态,不 import NetClient,不直接发包,不读取游戏内部状态。
9.2 三种稳定扩展方式
ThemeTokens:颜色、字体、间距、声音和视觉参数。SemanticAssetKey:如room.background、player.avatarFrame;调用方不依赖真实路径和 UUID。ExtensionSlot:只有玩法确实不同的区域由游戏注入独立 Prefab/Presenter,framework 管理挂载和销毁。
子游戏通过 ViewModel 给公共 UI 提供纯数据;禁止查找公共 Prefab 节点、改写组件或依赖节点层级。
9.3 路径覆盖的定位
现有 assets/game/override 构建期合成机制保留,用于已迁移皮肤和必须保持 UUID 的资源替换,但定位为兼容通道:
- framework 真源始终只读。
- 覆盖只在
build-workspace/<name>发生。 - 构建前校验目标存在、尺寸、meta、Spine 成套关系和孤儿覆盖。
- framework 升级后输出覆盖影响报告。
- 新功能优先使用 ThemeTokens、SemanticAssetKey 和 ExtensionSlot,不扩大裸路径依赖。
所有资源和本地 Asset Bundle 都进入所选游戏 ZIP;不从远程加载 framework,不单独更新 Bundle。
10. 开发、构建与发布
10.1 开发期
YouleNexus/assets/framework是唯一真源。games/<name>/assets/framework使用 junction 指向真源,实现即时共享。- 子游戏私有内容只在
games/<name>/assets/game。 - 所有工程使用同一 Cocos Creator 版本。
10.2 发布期
沿用现有 build-game <name> 和 materialize 思路:
YouleNexus/assets/framework
+
games/<name>/assets/game
|
v
build-workspace/<name>
|
+-- 皮肤/资源构建期合成
+-- 生成或校验 Composition Root
+-- Cocos Creator CLI 构建
+-- 协议、引用、依赖和内容审计
v
dist/<name>/<name>.zip
发布链路不依赖 junction。构建脚本直接从 framework 真源和所选游戏复制实体文件。
10.3 ZIP 验收
每个 ZIP 必须:
- 可独立运行。
- 只包含当前 framework 和当前一款游戏。
- 不包含其它游戏源码、资源、配置或入口。
- 不依赖远程 framework/Bundle。
- 包含
build-info.json,至少记录 game、framework commit、Cocos 版本、构建时间、目标平台和资源合成摘要。 - 通过资源引用、入口唯一性、脚本编译、敏感文件和其它游戏残留审计。
11. framework 升级模型
11.1 普通升级
framework 的代码、公共 Prefab、公共资源和默认主题都在唯一真源修改。只要 Game SDK、ThemeToken、SemanticAssetKey 和 Slot 契约保持兼容,各子游戏源码无需修改,只需分别与新 framework 重新构建 ZIP。
升级门禁:
framework tests
-> external contract golden replay
-> import-boundary
-> 每款游戏 TypeScript compile + SDK conformance
-> 每款游戏独立 Cocos build
-> package audit
11.2 破坏性升级
不做运行时多版本兼容。确需改变公共契约时:
- 在同一个仓库变更中迁移全部受影响游戏。
- 编译和 conformance matrix 必须阻止遗漏。
- 完成后仓库仍只保留一套现行契约。
契约版本只用于构建信息和变更审计,不用于运行时协商。
11.3 Cocos Creator 升级
先统一更新宿主和全部游戏的 creator.version,再逐工程由编辑器执行必要迁移。禁止不同 Cocos 版本共享同一 framework 资源。任何 .scene、.prefab、.anim、.meta 变更继续通过 funplay-cocos MCP 或 Cocos 编辑器完成,禁止文本修改序列化资源。
12. 性能设计
- 单 Router + route/rpc Map,避免全局广播和重复分发。
- Envelope 只解析一次;游戏 payload 和
deskinfo不深拷贝、不重复 JSON 转换。 - 高频 GameState 私有化,不进入平台 Store。
- 平台状态采用结构共享,一次业务事件一次提交。
- 网络回调只更新模型;Presenter 在同一帧合并节点刷新。
- 资源按场景/功能划分本地 Bundle,按需加载和释放,但随 ZIP 一起发布。
- GameSession dispose 统一释放计时器、监听、Tween、动画、节点和资源句柄。
- 禁止反射式 DI、通用全局业务 EventBus、运行时插件扫描和远程模块加载。
性能优化不得改变协议时序、回调次数或原生 App 可观察行为。优化前后必须通过同一黄金回放。
13. 错误处理与可观测性
- 必需配置、协议字段或契约数据缺失时在权威边界显式失败,不在下游使用猜测默认值。
- 未注册的平台 rpc、错误游戏 route、dispose 后调用和重复 Session 激活必须报出包含 route/rpc/session/game 的诊断。
- 旧协议明确允许缺省的字段,只在其权威解析器中实现一次缺省语义。
- 日志不得改写业务数据;敏感身份和原生数据按现有安全要求脱敏。
- 构建失败必须保留足够的 build-info 和审计输出,但不得污染 framework 真源。
14. 测试与质量门禁
14.1 外部契约
- Server Golden:旧客户端真实收发包逐字段、逐类型、逐顺序回放。
- Timing Replay:连接、登录、心跳、切服、关闭、重连和
deskinfo恢复时序。 - Remote Config Golden:请求 URL、覆盖顺序、GET 行为、
data.urlserver解析。 - Native Contract Matrix:全部 settings/handler 的名称、方向、payload、callback 次数和结果。
14.2 内部架构
- Import Boundary:双方无实现层跨界依赖。
- SDK Conformance:GameEntry、GameHost、GameModule 生命周期和能力限制。
- Session Isolation:连续进退桌、重连、切房后没有状态和监听泄漏。
- State Ownership:平台 Store 只能由平台用例写入,GameState 不进入平台 Store。
- Router Ownership:每个入站业务包只处理一次。
14.3 UI、资源与发布
- ViewModel/Slot contract 测试。
- 资源覆盖和 SemanticAssetKey 完整性检查。
- 已迁移 Prefab 的关键视觉和交互回归。
- 每游戏 Cocos 构建矩阵。
- ZIP 内容、唯一 GameEntry、无其它游戏残留和自包含运行审计。
15. 迁移路线
迁移采用纵向切片,每个切片固定执行:
旧源码/抓包取证 -> 契约样本 -> 新用例与状态 -> Presenter/UI -> 新旧回放 -> 接管并删除对应兼容路径
阶段 0:冻结契约
- 汇总服务器报文、roomtype、deskinfo、远程配置和原生桥矩阵。
- 建立黄金样本、时序回放和差异报告。
- 未从真实子游戏确认的游戏协议不得进入实现。
阶段 1:收口公共契约与依赖边界
- 将现有 SDK 改为纯 contracts,移除 Store、Reactive 和 EventBus 泄漏。
- 定义 GameEntry、GameModule、GameHost 和 Composition Root。
- 建立 import-boundary 与 conformance harness。
阶段 2:平台第一条纵向链路
- 统一 Config、Native、Net adapters。
- 合并 Router 与 RoomRPCBus。
- 建立 PlatformSession、GameSessionHost、App/Player/Room 单一状态源。
- 跑通配置、连接、登录、大厅、进房、准备、断线、切服和重连。
阶段 3:公共界面接线
- 为已迁移 Prefab 建立 Presenter/ViewModel。
- UI 事件转成 Command,不直接发包或写 Store。
- 建立 ThemeToken、SemanticAssetKey 和 ExtensionSlot host。
阶段 4:首款真实子游戏
- 从其旧工程和抓包提取游戏协议、roomtype 和 deskinfo。
- 以新 Game SDK 实现完整 GameModule。
- 完成正常对局、结算、断线恢复和新旧结果回放。
阶段 5:固化脚手架和逐游戏迁移
- 更新
new-game,生成可编译 GameEntry、Composition Root 和测试骨架。 - 逐款迁移,每款游戏有独立协议契约、资源、测试和 ZIP。
- framework 不为具体游戏增加条件分支。
阶段 6:发布和清理
- 补齐 dist ZIP、build-info 和 package audit。
- 建立构建缓存性能基线,验证 Cocos library 的安全增量复用后再启用。
- 删除 Legacy Compatibility Facade 和未使用旧钩子。
16. 实施拆分
本规范是跨阶段架构总纲,不应由一个超大实现计划一次完成。后续按以下独立批次分别编写计划和验收:
- 公共契约与架构门禁。
- 平台配置/登录/进房/重连纵向链路。
- 公共 UI Presenter 与扩展机制。
- 首款真实子游戏迁移。
- 构建、ZIP 与发布审计。
- 后续子游戏迁移批次。
第一份实施计划只覆盖批次 1 和批次 2,不提前实现具体子游戏和完整平台功能。
17. 非目标
- 同一 ZIP 包含多款子游戏。
- 运行时游戏发现、GameRegistry 或插件市场。
- framework、SDK 或 Asset Bundle 热更新。
- 运行时 SDK 版本协商或多版本共存。
- 为现代实现复刻旧 spid、自研渲染循环或全局函数组织方式。
- 在未取得真实子游戏协议前推测对局字段。
18. 完成定义
架构迁移完成必须同时满足:
- 原服务器、配置服务和原生 App 不修改代码即可运行。
- 所有外部黄金报文、URL、handler 和时序回放通过。
- framework 与子游戏之间只有公共 SDK 契约依赖,静态扫描无实现跨界。
- framework 代码、公共 UI 和公共资源普通升级后,已有子游戏源码无需修改。
- 每款游戏独立通过协议、SDK、UI、资源、性能和重连验证。
- 每次构建只选择一款游戏,并生成包含当前 framework 的独立完整 ZIP。
- ZIP 不包含其它游戏且不依赖 framework 热更新或远程 Bundle。
- Legacy Compatibility Facade 清零。