主要改动: - 切到 funplay-cocos-mcp v0.5.1 (用户级配置, 项目级 .mcp.json 删除) - 仓库文档/CLAUDE.md/.gitignore 等清理过时 cocos-mcp-server 引用 - memory 文件同步: cocos-mcp-setup/path/blocker/spriteframe-uuid/prefab-persist 等加 funplay 实测警告 - memory 新建 funplay-cocos-mcp-pending-verification.md (后已被实测覆盖) - spec/plan/data: - docs/superpowers/specs/2026-09-02-legacy-layer-migration-design.md - docs/superpowers/plans/2026-09-02-legacy-layer-migration.md - docs/superpowers/data/layer-spirit-summary.json - YouleNexus: profiles.ts / defaults.ts / PlayerInfoView.prefab / scene 改动 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
277 lines
23 KiB
Markdown
277 lines
23 KiB
Markdown
# 旧 gameabc 平台逻辑 → Cocos TypeScript 移植(子系统 C·平台逻辑移植)
|
||
|
||
> 状态:已逆向、待与用户确认。
|
||
> 适用工程:`cocoscreator_projects/YouleNexus`(框架真源)。
|
||
> 数据源:`projects/Game_Surface_3/js/00_Surface/`(12 文件)、`js/gamemain.js`、`js/gameabc.min.js`(均逐行逆向,行号见各节引用)。
|
||
> 关联:本文是 A §0.1 定义的**第三个子系统**,依赖 **A(`2026-08-28-legacy-ui-migration-design.md`)** 与 **B(`2026-08-30-legacy-engine-api-mapping.md`)**;目标分层落到 **框架 spec(`2026-06-28-cocos-framework-design.md`)** 的 §3/§4。
|
||
> 范围:旧工程的**逻辑流程与逻辑架构**——四层结构、数据流向、状态归属、核心流程、平台层对引擎 API 的依赖清单——到 Cocos 的移植。**不含**单条 API 的属性号语义(B §3)与渲染等价物(B §5),本文只引用。
|
||
|
||
---
|
||
|
||
## 0. 最高原则
|
||
|
||
承接 A/B 的两条原则(**原理等价**、**表现等效原理自由**),本文新增第三条,专门约束「逻辑流程一致性」:
|
||
|
||
> **原则三 · 复刻业务逻辑,不复刻引擎机制**:旧引擎的主循环、双缓冲、帧内事件派发、层叠渲染、对象注册表等,都是「无 Cocos 时手工搭的引擎」——Cocos 引擎**自带等价物**,一律交给 Cocos 运行时,**不得在 TypeScript 里重写一遍渲染循环 / 命中检测 / 定时器调度**。要复刻的是**业务逻辑流程**:启动门控、登录/进房/重连状态机、收发包路由、状态归属边界、界面切换时机——这些是协议契约与业务正确性的承重墙,必须逐条对齐。
|
||
|
||
判定「该复刻还是该交给引擎」的判据:**看它属不属于协议契约 / 业务状态机**。是 → 复刻;只是旧引擎的实现手段 → 交给 Cocos。
|
||
|
||
---
|
||
|
||
## 1. 四层架构 → Cocos 框架分层
|
||
|
||
旧前端是**四层**(自底向上);目标框架 spec §3 已定义 **6 层**(`core/net/protocol/platform/ui/sdk`)。两者不是 1:1,映射如下:
|
||
|
||
| 旧层 | 旧文件 | 在 Cocos 的落点 | 说明 |
|
||
|---|---|---|---|
|
||
| **引擎层** | `js/gameabc.min.js` + Spine + Canvas | **无对应**,由 Cocos 引擎接管 | 主循环/渲染/命中/定时器/资源/对象注册全是引擎机制(§2) |
|
||
| **桥接层** | `js/gamemain.js`(306 行) | `core/EventBus` + `sdk/` 回调钩子分发 | `gameabc_face` 全局回调表 → 事件总线;三方扇出 → `IGameModule` 钩子(§1.1) |
|
||
| **平台层** | `js/00_Surface/*`(12 文件) | `net` + `protocol` + `platform` + `ui` 四层 | 见 §3 逐文件映射 |
|
||
| **子游戏层** | `js/01_SubGame/*`(3 文件) | `sdk/`(子游戏实现 `IGameModule`) | 对局态 + `serialize()/restore(deskinfo)`(框架 spec §3 零耦合规则 3) |
|
||
|
||
> 关键澄清:旧「桥接层」`gamemain.js` **没有业务逻辑**,只是「把引擎回调扇出到三个命名空间」的接线盒。Cocos 里它**消失**了——引擎回调变成 Cocos 事件,扇出变成 `IGameModule` 的一组具名钩子(`onPlayerJoin`/`onReady`/`onDissolve`/`onOffline`…)。不要为它单独建一个「gamemain 模块」。
|
||
|
||
### 1.1 桥接层 `gameabc_face` → 事件分发
|
||
|
||
旧 `gamemain.js` 的机制是「引擎反射调用 `gameabc_face.<事件名>` 具名函数,函数内部按固定三方扇出」。Cocos 对应为**两种机制**,各管一半:
|
||
|
||
| 旧引擎回调(`gameabc_face.*`) | 旧扇出目标 | Cocos 对应 |
|
||
|---|---|---|
|
||
| `gamestart` | 仅 `Logic.AppStart()` | 引擎 `onLoad`/启动时序 → `platform` 启动编排 |
|
||
| `onloadurl`(资源加载进度) | `GameUI.onloadurl` | Cocos 资源系统 `Resources.load` 的 `onProgress`,**无需逐张计数** |
|
||
| `ontimer` / `ontimer_<objid>`(每精灵定时器) | 仅 `GameUI.utlontimer` | `component.schedule`(B §3 cpid=57 已映射) |
|
||
| `mousedown`/`mousedown_nomove`/`mouseup`/`mousemove` | `GameUI` + `Game_Modify` + `gameCombat` 三方 | Cocos 节点 `Button`/`EventTouch` 事件 + `IGameModule` 钩子 |
|
||
| `ani_doend`/`box_doend`(动画结束) | `GameUI` + `gameCombat` | `Animation`/`Tween` 完成回调 |
|
||
| `gamemydraw`/`gamemydrawbegin`/`gamebegindraw`/`gameenddraw` | 三方 | **无对应**(渲染循环交给引擎,业务「帧同步」需求另议) |
|
||
| `onresize` / `chongzhi` / `tcp*` / `httpmessage` | 空桩 | 不迁移(空实现) |
|
||
|
||
> 「初始化 / 定时器」旧只走平台层;「触屏 / 动画 / 绘制」旧三方扇出。Cocos 里前者是 `platform` 内部事务,后者是 `IGameModule` 的具名钩子(子游戏按 spid 过滤是否处理)——这一「按 spid 过滤」的模式在 Cocos 里**不再需要**,因为钩子是类型化的、子游戏只收自己关心的。
|
||
|
||
---
|
||
|
||
## 2. 引擎运行时机制:引擎自带 vs 业务复刻
|
||
|
||
任务逆向出的引擎运行时(33fps 主循环、backBuffer 双缓冲、帧内事件派发、层管理、`sp+id` 对象注册表、100 并发资源加载),逐条判定归属:
|
||
|
||
| 旧引擎机制 | 源码位置 | 判定 | Cocos 等价物 |
|
||
|---|---|---|---|
|
||
| 33fps `requestAnimationFrame` 主循环(`FPS=33` 硬编码,忽略数据 `fps=30`) | `tick()` `:1954`、`checkrun()` `:1858` | **引擎自带,不复刻** | Cocos 渲染循环(`director`) |
|
||
| backBuffer 双缓冲 + 脏标记 blit | `drawone()` `:1874`、`draw()` | **引擎自带,不复刻** | Cocos 场景图局部重绘 |
|
||
| 帧内事件派发(DOM 只记 `g_mouse`,回调在 `draw()` 里派发) | `gameabc_check_click` `:4095`、`check_click1` `:4068` | **引擎自带,不复刻** | Cocos 事件系统(`EventTouch`) |
|
||
| 每精灵定时器 `ontime`/`click_time` | `drawone` `:1878-1900` | 引擎自带 | `component.schedule`(B §3 cpid=57) |
|
||
| 层管理 `LayerList`/`showorder`/`set_level`/`set_level_up` | `:3102`/`:3114` | **引擎自带,且平台层从未直接调用**(§6.5) | Cocos 节点树 + `node.active` |
|
||
| `sp+id` 对象注册表 / `levelobj` 反向引用 | — | 引擎自带 | Cocos 节点树 + `manifest.json`(A §1.3) |
|
||
| 100 张并发 + 10ms 节流资源加载 | `load_img1` `:4454`/`load_img2` `:4597` | 引擎自带 | Cocos `Resources`/`Asset Bundle` |
|
||
|
||
**结论**:上表**没有一条需要复刻**。引擎层的价值在「协议无关的渲染/输入/资源」,Cocos 引擎整体接管;真正要搬到 TypeScript 的是 §3–§6 的平台层业务。
|
||
|
||
---
|
||
|
||
## 3. 平台层模块 → framework 分层落点
|
||
|
||
平台层 12 个文件,逐个落到框架 6 层(框架 spec §3 的映射表已给粗对应,本文精确到「文件 → 模块」):
|
||
|
||
| 旧文件(行数) | 职责 | framework 层 | 落点模块(示意) |
|
||
|---|---|---|---|
|
||
| `02_Const.js`(822) | 协议常量 + 静态配置 | `protocol` + `core` | `protocol/routes.ts`、`protocol/rpc.ts`(唯一来源);UI 常量 → `ui/theme` |
|
||
| `00_minhttp.js`(656) | WebSocket/XHR 封装 + 工具 | `net` + `core` | `net/NetClient` + `core/utils`(`min_*` 40+ 工具) |
|
||
| `09_Net.js`(897) | 收发信封 + 路由表 | `protocol` + `net` | `protocol/platform-rpc.ts`(`send_*`/`handle_*`) |
|
||
| `04_Data.js`(584) | 全局态 `GameData` | `platform` | `platform/stores/app-store.ts`(`AppStore`) |
|
||
| `06_Player.js`(575) | 玩家结构 `Player`/`C_Player` | `platform` | `platform/stores/player-store.ts`(`PlayerStore`) |
|
||
| `07_Desk.js`(1427) | 房间状态机 `Desk` | `platform` | `platform/stores/room-store.ts`(`RoomStore`) |
|
||
| `12_Logic.js`(2444) | 连接/重连/分发编排 | `platform` + `net` | `platform/session.ts`(登录/重连编排)+ `net/NetClient` |
|
||
| `11_GameUI.js`(9862) | 平台全部 UI | `ui` | `ui/` 下 Prefab + 各界面控制器 |
|
||
| `08_Utl_Output.js`(1034) | 平台对子游戏的输出/工具 API | `sdk`(facade) | `sdk/GameContext`(`getMyInfo`/`getRoomcode`/`getPlayerList`…) |
|
||
| `05_Func.js`(4185) | 原生/系统能力封装 | `platform` + `sdk` | 原生桥接归 `sdk`;纯工具归 `core/utils` |
|
||
| `03_Banwords.js` | 违禁词 | `core` | `core/utils` |
|
||
| `10_Game.js` | (零散 `set_self/get_self`) | `ui` | 并入对应界面控制器 |
|
||
|
||
### 3.1 三个状态机的职责与唯一归属(框架 spec §3 零耦合规则 3 的细化)
|
||
|
||
| 状态机 | 旧归属 | framework Store | 唯一职责 |
|
||
|---|---|---|---|
|
||
| `GameData` | 连接/配置/资产/面板态 | `AppStore` | `Server/AjaxUrl/AgentId/ChannelId/GameId`、`hallConfig/sysConfig`、各类列表 |
|
||
| `Desk` | 房间/座位/局状态 | `RoomStore` | `PlayerList[]`、`roomcode/stage/state/roomtype/warcnt`、解散投票 `AgreeList` |
|
||
| `C_Player` | 自己的状态 | `PlayerStore` | `playerid/bean/roomcard/seat/status/isprepare/state` |
|
||
|
||
> 旧 `C_Player` 与 `Desk.PlayerList[C_Player.seat]` 是**同一玩家的两份镜像**,靠 `Player.SetDeskInfo/getDeskInfo` 手工同步(`06_Player.js:177-180` 改 bean 时显式回写 `Desk.PlayerList[seat].bean`)。Cocos 里这是**单一来源原则的反例**:`PlayerStore` 应持有「座位 → 玩家」的**唯一**响应式映射,自己的座位只是其中一个下标;消除双份镜像的手工同步。
|
||
|
||
---
|
||
|
||
## 4. 数据流向与调用方向(谁调谁、谁改谁)
|
||
|
||
```
|
||
旧(四层 + 双向手工刷新) Cocos(单向依赖 + 响应式)
|
||
────────────────────────────── ──────────────────────────────
|
||
引擎回调 ─► gamemain 扇出 ─► GameUI/Logic/子游戏 事件/钩子 ─► 单一 handler
|
||
收包 onmessage ─► Net.<rpc> 薄转发 ─► Desk/C_Player 收包 ─► Router ─► Store 更新 ─► UI 响应式刷新
|
||
└► 改状态后 手工调 GameUI.* 刷界面 └► (无手工刷 UI,Store 变化自动驱动)
|
||
```
|
||
|
||
**关键差异(移植时必须理解的)**:
|
||
- 旧是「改状态 → 手工调 `GameUI.xxx()` 刷新」。Cocos 是「Store 响应式 → UI 自动刷新」,**消灭 `Desk`/`C_Player` 方法里那批 `GameUI.setHallRoomCard`/`setHallStar` 手工回调**。
|
||
- 旧 `Net.<rpc>` 收包函数几乎全是「薄转发 + 菊花」(`Desk.<rpc>(_msg)` 或 `C_Player.<xxx>` 或 `gameCombat.<xxx>`,夹 `GameUI.StartLoad()/EndLoad()`)。Cocos 里「薄转发」退化为 `protocol` 层的 typed handler → 直接调 Store 方法,「菊花」变成全局 loading 态。
|
||
|
||
### 4.1 收包路由分界(协议契约,必须逐字对齐)
|
||
|
||
`12_Logic.js:258-264` 的分发是**平台/子游戏的分水岭**:
|
||
|
||
```
|
||
route ∈ { platform, agent, room } ─► 平台层 Net.<rpc>(protocol/platform-rpc)
|
||
route = <game route> ─► 子游戏 Game_Modify._ReceiveData(sdk → IGameModule.onReceive)
|
||
```
|
||
|
||
框架 spec §4 已把这条分界固化为 `Router`,本文只强调:**这个三分支的 route 判定是协议红线**,`platform/agent/room` 之外的任何 route 都不得被平台层拦截或解析。
|
||
|
||
### 4.2 发包信封(协议契约,逐字节对齐)
|
||
|
||
`Net._SendData`(`09_Net.js:12`)组装 `{app:"youle", route, rpc, data}`;`netType==0` 走 WebSocket,`netType==1` 走 `Func.AjaxHttp2`(HTTP 兜底,`player_login` 特判 `putMsg="playerLogin"`)。Cocos 侧 `net/NetClient` + `protocol` 编码必须保持信封结构与两条传输路径(含 HTTP 兜底),见框架 spec §4 与 `native-bridge-contract` 技能。
|
||
|
||
---
|
||
|
||
## 5. 状态归属与边界
|
||
|
||
| 归属 | 状态 | 旧位置 | Cocos 位置 |
|
||
|---|---|---|---|
|
||
| 平台-连接/配置/资产 | `Server/AgentId/ChannelId/GameId`、`hallConfig/sysConfig`、列表 | `GameData` | `AppStore` |
|
||
| 平台-房间 | `PlayerList[]`、`roomcode/stage/state`、`AgreeList`、`roomtype` | `Desk` | `RoomStore` |
|
||
| 平台-自己 | `playerid/bean/roomcard/seat/status/isprepare` | `C_Player` | `PlayerStore` |
|
||
| 平台-UI 瞬态 | `onstate[]/isprepare[]/VoteList/Mem`(方位映射后显示态) | `GameUI` 顶部变量 | `ui` 各控制器局部态 |
|
||
| 平台-本地持久化 | 开关/roomlist/playerid/machineId 等 | `Utl` storage key | `core/storage`(key 按 `GameId+AgentId` 拼,保持兼容) |
|
||
| **子游戏-对局态** | 手牌/出牌历史/轮次/分数/结算 | `Game_Modify`/`gameCombat` | 子游戏自身命名空间 + `serialize()/restore(deskinfo)` |
|
||
|
||
**边界判据(三条,移植时逐条守住)**:
|
||
1. **路由判据**:`route ∈ {platform,agent,room}` 归平台层,其余归子游戏(§4.1)。
|
||
2. **对局态透传不解析**:服务器在 `player_login` 回包下发 `deskinfo` 对局快照,`Desk.login` **原样**交给 `Game_Modify.Reconnect(deskinfo)`(`07_Desk.js:419-426`),平台层**不持有、不解析**对局态。Cocos 里是 `IGameModule.onReconnect(deskinfo)`,`RoomStore` 只透传快照、不拆解。
|
||
3. **同一玩家单一来源**:消除 `C_Player` 与 `Desk.PlayerList[seat]` 双镜像(§3.1)。
|
||
|
||
---
|
||
|
||
## 6. 核心流程(逻辑流程一致性基准)
|
||
|
||
以下五条流程是「逻辑流程一致」的验证基准,Cocos 侧必须**按同一次序、同一门控条件**复刻(实现手段可不同,流程与时序必须一致)。
|
||
|
||
### 6.1 启动流程(页面加载 → 首屏登录)
|
||
|
||
旧:资源加载(`onloadurl` 逐张计数到 100)→ `gamestart` → `Logic.AppStart`(定 netType/isGameHall、`registerFunction`、`setChannelId→setGameServer→setAgentId→getVersionState`、`new C_Player`)→ `get_config`(HTTP 取 `player_server_tcp/game_server_tcp/urlserver`)→ `getConfig_Succ`(写 `GameData.Server/AgentId`、`GameInit`)→ `firstConnect` 建 WS。
|
||
|
||
**首屏门控四条件**(全齐才进登录页,`GameUI.JumpWxAuth()`):
|
||
1. `LoadCount==100`(资源)
|
||
2. `firstConnect_Succ`(WS onopen)
|
||
3. `getJSONState`(配置就绪)
|
||
4. `Timesup`(加载计时器 `Game_Config.Max.showtime` 到点)
|
||
|
||
> 门控四条件的**时序语义必须保留**(缺一不进登录页),但实现手段升级:资源计数交给 Cocos 加载系统,计时器用 `scheduleOnce`,四条件合成一个「就绪信号」而非各自散落置位。
|
||
|
||
### 6.2 登录 / 进大厅 / 进房间
|
||
|
||
`Net.Send_login`(组包 agentid/openid/nickname/…/machineid)→ `Net.player_login` → `Desk.login`,按 `roomcode` 分支:
|
||
- **无 `roomcode`** → `Game_Modify.closeGameScene()` + `GameUI.JumpMenuScene()`(大厅)+ 按 `Logic.JudgeShow()` 弹公告。
|
||
- **有 `roomcode`** → `Logic.updateMainSceneData(roomtype)`(=`Game_Modify.onCreateDesk` + `Desk.Create`)→ `GameUI.MainScene(true)` → 按 `deskinfo` 有无走 `Game_Modify.Reconnect(deskinfo)` 或 `ReconnectNoMakewar()`。
|
||
|
||
### 6.3 断线重连(`isbattle==1` → `Reconnect(deskinfo)`)
|
||
|
||
- **断线检测**:`game_websocket.onclose` → 置 `netWorkSate=false`;非首次连接 `NetType=1` + `TryConnect()` + `OpenDisConnect()`。
|
||
- **重连后**:`onopen` → 若 `isLogin` 重发 `Send_login`。
|
||
- **触发点**(`07_Desk.js:419-426`):登录回包带 `deskinfo` 时 → `Game_Modify.Reconnect(deskinfo)`;否则 `ReconnectNoMakewar()`。子游戏必须能**反序列化同一结构**(与 `docs/protocol/` 的 `deskinfo` 快照对齐,B 已强调)。
|
||
- **旁路**:`self_join_room`(`07_Desk.js:649`)带 `deskinfo` → `Desk.stage=1` + `Game_Modify.DeskInfo(deskinfo)`(他人未开战牌桌数据)。
|
||
|
||
### 6.4 对局流程(`Desk` 状态机 + 子游戏协作)
|
||
|
||
开战 / 准备 / 对局收发包 / 解散投票 / 离桌 / 结算投降,均以 `Desk` 状态机为骨架、`Game_Modify` 为协作方:
|
||
|
||
| 流程 | 平台层(`Desk`/`C_Player`) | 子游戏(`Game_Modify`,Cocos `IGameModule`) |
|
||
|---|---|---|
|
||
| 开战 | `self/other_makewar` → `stage=1`、`ChangeExit(0)`、`HideStartScene()` | `StartWar(_msg)` 建对局 |
|
||
| 准备 | `player_prepare` → 改座位 `isprepare` + `SetIsprepare` | `onReady` |
|
||
| 对局中 | route 非 platform/agent/room 的包**完全不介入** | `_ReceiveData`(`onReceive(rpc,data)`) |
|
||
| 解散投票 | `state=1` + `AgreeList` 累积 + `OpenApply` | `Free(deskfree)`(`free_room` 时) |
|
||
| 离桌 | `stage==1` → `breakRoom()`;其余 `playerLeaveRoom` 等 | `breakRoom/playerLeaveRoom/playerOffline/changeSeat` |
|
||
| 结算/投降 | `get_player_grade1/2`→`gameCombat`;`beanroom_surrender` | `onSurrender` |
|
||
|
||
### 6.5 界面切换(**不是 `set_level`**)
|
||
|
||
> 重要澄清(全仓 grep 实证):`set_level`/`set_level_up` 是**引擎层函数**,平台层**从未直接调用**。平台层的「界面切换」机制是**精灵级显隐 + 场景哨兵**:
|
||
|
||
- `set_self(spid, 37, vsb)`(cpid=37 可见性)+ `set_group(groupid, 37, vsb)` 整组显隐。
|
||
- 界面骨架:`GameUI.invisible()`(全隐藏)→ 各界面只点亮自己的 group(登录 `set_group(2,37,1)`、大厅 `set_group(3,37,1)`、房间 `set_group(21,37,1)`、各弹窗各自 group)。
|
||
- **场景哨兵**:`get_self(149,37)` = 「是否在房间主界面」、`get_self(4,37)` = 「大厅」标志,被 `Utl.isMainScene`/`Logic.checkRoom` 读。
|
||
|
||
Cocos 等价:`set_self(spid,37,vsb)` → `node.active`(B §3 cpid=37);「界面」→ 独立的**场景 / 预制根节点**;「场景哨兵」→ `AppStore` 里显式的 `currentScene` 状态(而不是反查某个精灵的可见性)。**不要**去找 `set_level` 的对应物。
|
||
|
||
---
|
||
|
||
## 7. 平台层 gameabc API 依赖清单(19 个,分域)
|
||
|
||
全平台层 `00_Surface` 实际调用 **19 个引擎 API,共 2305 处**,其中 `set_self`/`get_self`/`set_group` 三项占 88.6%(2042 处),且集中在 `11_GameUI.js`。按域分列;**B 已覆盖的引用 B,本文只补 B 未覆盖的映射方向**。
|
||
|
||
| 域 | API(次数) | Cocos 对应方向 |
|
||
|---|---|---|
|
||
| 属性读写 | `set_self`(1525)、`get_self`(373)、`set_group`(144) | 属性号对照见 **B §3**;`set_group(groupid,37,vsb)` 整组显隐 → 该 group 父节点的 `active`(A §2.1 已并入父节点) |
|
||
| 裁剪/记录 | `set_clip`(21) | 设置裁剪区域(滚动列表/进度条)→ `cc.Mask` / `ScrollView` 视口裁剪 |
|
||
| 记录 | `set_rec`(4)、`get_rec`(2) | 见 **B §5.6**(文字表 → `Label`,不建全局可变文字表) |
|
||
| 窗口变量 | `set_windows`(1) | ⚠️ 待逆向(`12_Logic.js:523 set_windows(2,"var","1977")`,仅 1 处,落地前看用途) |
|
||
| 渲染绘制 | `ifast_mydrawbmp`(19)、`ifast_mydrawtext`(2) | 见 **B §5.1/§5.2** |
|
||
| 精灵绘制 | `ifast_mydrawsprite`(—) | 见 **B §5.3** |
|
||
| 批量加载 | `ifast_loadsprite`(1) | 批量预加载精灵 → Cocos `Resources.loadDir` / 图集预载(引擎自动,通常无需) |
|
||
| 实例/资源 | `ifast_addtospritefromspritecopy`(77)、`ifast_dllpritefromspritecopy`(69) | 见 **B §5.5**(列表 → `Layout`/`ScrollView`/`NodePool`) |
|
||
| 命中/检测 | `ifast_check_add`(12)、`ifast_checkimg`(1) | 按坐标检测精灵 → Cocos 节点事件系统天然覆盖;`checkimg` 图片已加载检查 → 资源系统 |
|
||
| 对象查找 | `ifast_getobj`(4) | 按 id 取引擎对象 → `node.getComponent` / `manifest.json`(A §1.3)定位 |
|
||
| 工具/数学 | `ifast_random`(14)、`ifast_abs`(14) | 纯 JS:`Math.random()`/`Math.abs()`,**无引擎依赖** |
|
||
| 引擎单例 | `gameabc_face`(14)、`gameabc_Voice`(8) | `gameabc_face`(取 div/canvas ctx)→ 场景根/Canvas 持有;`gameabc_Voice`(语音列表)→ 音频资源清单 + `AudioSource` |
|
||
|
||
**网络域(独立,见 `native-bridge-contract` 技能)**:平台层网络**不走**引擎的 `ifast_ws/tcp/ajax/http`(0 次调用),而是自有 `00_minhttp.js` 的 `min_tcp`(原生 `new WebSocket`)+ `min_http`(原生 `XMLHttpRequest`),收发经 `Net.ws_tcp.send(JSON.stringify(msg))`。Cocos 用 `WebSocket` 封装 + 协议信封逐字节对齐。
|
||
|
||
**任务提及但平台层实际未使用(避免白做迁移)**:
|
||
|
||
| 未使用 API | 实测 |
|
||
|---|---|
|
||
| `ifast_ws`/`ifast_tcp_*`/`ifast_ajax`/`ifast_http`/`ifast_split` | 0 次(平台层改用自有 `min_tcp`/`min_http`) |
|
||
| `get_selfdiv`/`set_selfdiv` | 0 次 |
|
||
| `set_level`/`set_level_up`/`openurl`/`showmessage` | 0 次 |
|
||
| `gameabc_Object`/`gameabc_Image`/`gameabc_Layer`/`gameabc_GroupList`/`gameabc_GameTxt` | 0 次(仅 `gameabc_face`、`gameabc_Voice` 被用) |
|
||
| `up_imgurl` | 平台层自有 `Func.up_imgurl`(`05_Func.js:1710`),非引擎 API |
|
||
|
||
---
|
||
|
||
## 8. 逻辑流程一致性检查点(验证基准)
|
||
|
||
迁移完成后,以下检查点逐一核验(作为「逻辑流程一致」的验收单):
|
||
|
||
- [ ] **信封**:`{app:"youle", route, rpc, data}` 结构与 `docs/protocol/` 逐字节对齐;`route` 三值 `platform/agent/room` 判定正确。
|
||
- [ ] **收包分界**:`route ∈ {platform,agent,room}` → 平台层;其余 → `IGameModule.onReceive`;平台层不拦对局包。
|
||
- [ ] **发包路径**:`netType==0` WebSocket / `netType==1` HTTP 兜底两条都在;`player_login` 的 `putMsg="playerLogin"` 特判保留。
|
||
- [ ] **启动门控四条件**:资源/WS onopen/配置/加载计时器,缺一不进登录页。
|
||
- [ ] **登录分支**:`roomcode` 有无 → 大厅 or 房间;`deskinfo` 有无 → `onReconnect` or `ReconnectNoMakewar`。
|
||
- [ ] **断线重连**:onclose → 重连 → 重发登录 → `deskinfo` 反序列化恢复对局(子游戏 `restore`)。
|
||
- [ ] **状态归属**:`RoomStore`/`PlayerStore`/`AppStore` 三态机职责唯一;`C_Player` 与 `PlayerList[seat]` 无双镜像。
|
||
- [ ] **对局态透传**:平台层不解析 `deskinfo`,原样交 `IGameModule`。
|
||
- [ ] **界面切换**:用 `node.active` + `AppStore.currentScene`,不搬 `set_level`。
|
||
- [ ] **原生接口**:`window.settings` 同步取值 + WVJB 异步桥,接口名/数据格式/URL 构造与旧逐字一致(见 `native-bridge-contract`)。
|
||
|
||
---
|
||
|
||
## 9. 落地约定 / 红线 / 待验证
|
||
|
||
### 9.1 落地约定
|
||
|
||
1. **模块名遵循框架 spec §3**:旧文件 → framework 层的映射(§3 表)是唯一落点,不得另起命名。
|
||
2. **Store 响应式驱动 UI**:`RoomStore`/`PlayerStore`/`AppStore` 状态变 → UI 自动刷新,**消灭** `Desk`/`C_Player` 里那批 `GameUI.*` 手工回调。
|
||
3. **路由/信封/deskinfo 只认 `docs/protocol/`**:任何网络层疑问先读协议文档,不臆测(CLAUDE.md 第一准则)。
|
||
4. **遇到 ❓/⚠️ API**(如 `set_windows`)回到 `gameabc.min.js` 对应处补齐再回填,**禁止臆测**(第二准则)。
|
||
|
||
### 9.2 红线
|
||
|
||
- 不手写 `.scene`/`.prefab`/`.meta`(CLAUDE.md)——本规范落地产物仍走 MCP。
|
||
- 不复刻引擎机制(主循环/双缓冲/帧内命中/对象注册表)——交给 Cocos 运行时。
|
||
- 不改变协议信封、route 判定、`deskinfo` 透传边界(第一准则)。
|
||
|
||
### 9.3 待验证(落地前)
|
||
|
||
| # | 待验证 | 方法 |
|
||
|---|---|---|
|
||
| 1 | `set_windows(2,"var","1977")` 的语义(仅 1 处,`12_Logic.js:523`) | 看该调用上下文,判定是否需迁移或可直接丢弃 |
|
||
| 2 | `Utl` storage key(`GameId+AgentId` 拼接)在新工程是否要保持原 key 以兼容旧缓存 | 与后端/运营确认是否需沿用旧 key |
|
||
| 3 | 首屏门控四条件里「加载计时器 `showtime`」的精确时长与超时行为 | 读 `Game_Config.Max.showtime` 定义值 |
|
||
| 4 | `C_Player`/`Desk.PlayerList[seat]` 双镜像在哪些方法里被读写,确保 `PlayerStore` 单一来源无遗漏 | grep `SetDeskInfo`/`getDeskInfo`/`PlayerList[` 全调用点 |
|