Files
youle_cocos/cocoscreator_projects/docs/framework/integration
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
..

子游戏接入与目录约定

返回文档首页。后续阅读:创建房间、版本与构建。

1. gameKey、目录、gameid、route 分别是什么

gameKey 是子游戏入口和 Bundle 的选择键,负责选择游戏实现和版本资源。目录只是文件位置。gameid 是服务器游戏身份,由 XML 提供。route 是游戏入口的路由标识,必须遵循实际消息契约,不能因重命名目录而修改。

当前二七王:

  • 注册键和 definition.key:erqiwang。
  • 源码目录:assets/games/erqiwang。
  • gameid:读取该游戏 XML 的 game/game@id,不是字符串 erqiwang。
  • 当前 definition.route:erqiwang;不要因此把平台创建房间请求的 route 改为 erqiwang,该请求仍是 agent/create_room。

当前模板:

  • 注册键和 definition.key:Game_Surface_3。
  • 源码目录:assets/games/template。
  • 版本路径仍使用 Game_Surface_3,不是 template。

两者通过子游戏入口定义和 Bundle 名称建立关联,所以目录和 gameKey 目前允许不同。不能只把模板 gameKey 改成 template;现有注册项、资源路径与 bundle 名称不会自动跟随。

新游戏建议统一 目录名 = gameKey = definition.key。这是前端命名约定,不影响服务器 gameid 或协议路由。当前构建扩展允许 gameKey 使用英文字母、数字、下划线、连字符。

2. 建议目录

以下是新游戏 mygame 的组织示例,不表示该游戏已经存在:

YouleNexus/assets/
  app/composition/
    game-definitions.ts           # 通用入口解析,不引用具体游戏
    SubgameAssets.ts              # 动态加载目标游戏及版本
  games/mygame/
    game-config.ts                # 定位版本 XML 和私有资源根
    game-definition.ts            # 本游戏定义
    GameEntry.ts                  # 注册 GameEntry_mygame
    mygame-game.ts                # GameBinding / GameEntry / GameModule
    mygame-room-rules.ts          # 自己解释和生成 roomtype
    room-chat-config.ts           # 自己的聊天配置
    MyGameCreateRoomView.ts
    MyGameCreateRoom.prefab
    MyGameRoomView.ts
    MyGameRoom.prefab
    resources/                    # 编辑器设置为 version-mygame bundle
      mygame/version.xml          # 身份和版本唯一来源

框架中不添加 mygame 的游戏 ID、玩法开关、节点查找路径或特殊 RPC 分支。需要扩展公共契约时,应作为独立框架能力设计,而不是每接入一个游戏就改框架。

3. 配置与应用注册

游戏配置可参照 erqiwang/game-config.ts:

export const gameConfig = Object.freeze({
  versionResource: 'mygame/version',
  assetRoot: 'games/mygame',
});

当前运行时要求 versionResource 精确等于 <gameKey>/version。XML 和资源包准备见构建文档。

在自己的 assets/games/mygame/game-definition.ts 导入本游戏工厂、配置和聊天配置,导出只包含本游戏的 GAME_DEFINITIONS。公共应用层不添加注册项。需要提供的完整字段以 GameDefinition 为准:

  • key:与注册键及场景 gameKey 一致。
  • route:核对既有游戏路由,不自动从目录推导。
  • config:自己的版本资源定位配置。
  • createGame(gameId):接收已解析的游戏身份,返回 GameBinding,不另写一份 gameid。
  • roomMenu:显式提供 mainSceneButton、vipInfinite 两个布尔策略。
  • chat:按 RoomChatConfig 提供该游戏聊天配置。
  • createPageClass、roomViewClass:相应 Cocos 组件类名,注意 @ccclass 名称。
  • resources.createRoom、resources.room、resources.roomScene:资源路径描述,参照已有注册项。

createRoom 和 room 按定义从目标游戏 Bundle 自动加载,不再绑定到启动场景。 创建页面运行时是通过 CreateRoomPage 基类取组件;仅填写 createPageClass 不能替代继承该基类及在游戏 prefab 挂载组件。房间视图按 roomViewClass 取组件。

4. 实现房间入口和生命周期

参考 erqiwang-game.ts,但不要把其中尚未实现的玩法处理当成完整游戏模板。

GameBinding 提供 entry、mount(view)、restoredSnapshot、roomProjection。GameEntry 提供 key、gameId、route,以及:

  • resolveSeatCount(roomtype):解析真实服务器返回的本游戏 roomtype,返回座位数;输入非法时显式报错。平台不负责解释玩法字段。
  • createModule():为房间创建独立的 GameModule,不在模块间共享上一房间的可变状态。

GameModule 生命周期:

  • attach(host):接收平台能力并订阅状态。
  • handlePlatformEvent(event):处理平台转交的房间事件。
  • handleGameMessage(message):按本游戏协议处理玩法消息。
  • restore(deskinfo):按本游戏快照契约恢复状态和视图。只保存原始数据不等于完成重连恢复。
  • dispose():解除订阅、定时器与界面引用,结束后不继续发送或响应旧会话操作。

通过 requireRoomCapabilities(host) 使用 room/messages/ui/scope 能力,不从游戏中访问 PlatformRuntime、平台 Store、WebSocket 或另一款游戏的模块。

  • room:快照、订阅、座位映射、准备、退出、解散。
  • messages:发送符合本游戏协议的消息。
  • ui:业务提示、具有所有权的 loading、数字输入及倍数选择;输入取消是正常结果,应处理取消分支。
  • scope:注册房间结束时的清理逻辑。

完整接口见 game-capabilities.ts。当前未提供可用的房间音频所有权能力,不假设它存在。

5. 编辑器绑定与选中游戏

打开 assets/scenes/PlatformStartup.scene,在挂有 SubgameAssets 的节点配置:

  1. gameKey:目标游戏键。
  2. 创建页面 prefab 在本游戏定义中声明,根节点挂自己的 CreateRoomPage 子类。
  3. 房间 prefab 在本游戏定义中声明,根节点挂匹配 roomViewClass 的组件。
  4. roomScene:用于承载房间的 SceneAsset。
  5. 保存场景;构建扩展读取磁盘中已保存的场景,而不是未保存的 Inspector 状态。

两款现有游戏当前都使用 TemplateRoom.scene 作为承载场景,场景名称不意味着二七王使用模板的玩法逻辑。现有二七王房间视图继承 CommonRoomViewBase,公共控制通过已有属性绑定。

6. 接入验收

  • 注册键、definition.key、gameKey、版本资源路径与 bundle 名称一致。
  • 创建页面重复打开/关闭不重复注册监听;忙碌时不能重复提交。
  • 抓取实际 create_room 出包确认 roomtype,而不仅检查 UI 选项。
  • 验证成功、服务器拒绝、重连已有房间、退出后再进房间。
  • 游戏解析自己真实的 deskinfo;公共平台不转换子游戏快照格式。
  • 切换至另一款游戏并验证其身份、创建页面与版本 XML,避免留下另一款游戏的绑定。
  • 控制台无异常,业务提示不承载调试输出,房间释放后无旧订阅和迟到回调。

当前二七王 handleGameMessage 与解散结算仍有显式“尚未接入”分支,房间视图标识“玩法尚未接入”并隐藏准备按钮。这些是后续子游戏工作,不应宣称创建房间成功就已完成牌局迁移。

7. Bundle 入口

游戏根目录设置为 game-<gameKey> Bundle,优先级 1;版本子目录保持 version-<gameKey> Bundle,优先级 2。版本包必须比游戏包优先,保证 XML 属于版本包,不被父目录包提前收走。

import {_decorator} from 'cc';
import {GAME_DEFINITIONS} from './game-definition.ts';
@_decorator.ccclass('GameEntry_mygame')
export class MyGameEntry {
  static readonly definition = GAME_DEFINITIONS.mygame;
}

启动等待目标 Bundle 加载完成,通过公开类注册 API 读取入口定义,然后加载私有 prefab 和版本 XML。入口缺失、键不匹配、资源越界或加载失败均显式报错,不回退到其他游戏。新增游戏不修改 app/framework/scripts 或公共资源。