Appearance
RPC / 网络抓包面板 — 设计原则
状态:MVP 已实现(L0 + L1 只读)。
目标:在 Copilot 内增加 sproto 系通用化 + 多协议 Provider 插件 的网络/RPC 调试能力,不绑死单个 demo 项目,且 不影响现有引擎检测与常驻性能。
HTTP 联调(GET/POST、JSON/XML、接口管理)可外置 CrapApi 等工具;本面板聚焦 游戏内 WebSocket / 二进制 RPC(如 sproto) 的抓包、解码、(可选)重放与 mock。
1. 架构分层(不绑 demo)
| 层级 | 能力 | 通用程度 |
|---|---|---|
| L0 | WebSocket 帧抓包(hex/base64、时间、方向) | 任意 WS 游戏 |
| L1 | sproto 解码(tag/session → 协议名 + JSON) | 页面存在 sproto 运行时 + 协议字典,或用户导入 schema |
| L2 | RPC 重放 / mock 回包 | 需 ProtocolProvider 适配发送/响应入口 |
| HTTP | 独立 Provider 或 DevTools Network | 非 sproto 主链路 |
禁止写死 demo 的 SocketForGame、C2sProtocol 类名;demo 仅作第一个 ProjectPreset 验证。
ProtocolProvider 插件接口(概念)
text
detect() → 是否适用(轻量,仅存在性探测)
decodeSend(bytes) → { tag, name, session, body }
decodeRecv(bytes) → { ... }
replay(entry) → 可选
mock(entry, rsp) → 可选,须单独开关 + 风险警示Provider 按需加载:detect 命中 sproto 才加载 SprotoProvider;未命中可回落 L0。
2. 不影响检测 — 铁律
与 EngineManager.check() / haveEngine() 完全解耦:
| 规则 | 说明 |
|---|---|
| 不进引擎探针 | RPC 模块不得放入 packages/engine/ 的引擎注册或 EngineManager.check() 逻辑 |
| 不篡改引擎全局 | 禁止覆盖 window.Laya / egret / cc / WebSocket 构造函数;仅 wrap 原型方法并保留原实现 |
| 独立 detect | ProtocolProvider.detect() 与引擎检测是两条链路;不得「有 sproto ⇒ 有引擎」 |
| 命名空间 | Hook 状态、缓冲、配置放在 $h5GameCopilot* 下,避免与其他检视扩展冲突 |
| 注入时机 | 优先在 引擎 init 之后 或 面板显式开启录制 时 install hook,避免干扰引擎加载顺序 |
回归必测(改动 RPC 相关代码时):
- Laya / Egret / Cocos 页:
gameInfo引擎名正确、场景树能出 stage - 未开 RPC 面板时:行为与改前一致
- MV3 重载:关 F12 → 重载扩展 → 刷新游戏页 → 再开 DevTools
3. 可控性能 — 铁律
对齐 性能优化.md:默认零 Hook,按需启用,热路径极简。
3.1 生命周期(Lazy)
| 状态 | 行为 |
|---|---|
| 未开 DevTools / RPC 面板关闭 / 录制 off | 不 install WS Hook(或 passthrough,零拷贝路径) |
| RPC 面板打开且用户开启录制 | install hook |
| 面板关闭或录制 off | uninstall 或恢复原生 send/onmessage |
触发可参考:devPanelStateChange(true) + RpcCapture 面板 onShown(与 ai-lazy.js、注入日志 P0 按需轮询同一思路)。
3.2 热路径(MAIN world)
在 WebSocket.send / onmessage 回调内 仅允许:
- 时间戳、方向、长度
- 拷贝 bytes 入 环形缓冲区(上限如 500 条,超出丢最旧)
禁止在 WS 回调内:sproto 全量解码、JSON.stringify、逐条 postMessage / Port 推送。
3.3 冷路径(DevPanel / inspector)
- 解码:
requestIdleCallback或面板侧批量处理 - IPC:批量 flush(如 200ms 一批),避免每条 RPC 一次 Port
- UI:虚拟列表或分页;勿一次渲染万条 DOM
3.4 限流与黑名单
- 高频 tag(心跳、移动同步等)可折叠、采样或用户配置黑名单
- 单条 payload 过大时只存 hex 摘要 + 截断预览
3.5 包体积
- Provider 与解码器可拆
rpc-capture.js懒加载(类似ai-lazy.js),不增大首屏devpanel.js关键路径
3.6 禁止项
- 不得为 RPC 增加常驻 700ms 全 frame
eval轮询(见CodePanel.pollPageConsoleP0 策略) - 不得全局永久重写
console.log把 RPC 灌进运行日志;独立通道,用户可选导出
4. 与其他功能域的边界
| 功能域 | 要求 |
|---|---|
| 注入 / 运行日志 | RPC 抓包不走 userCodeConsoleHook 默认通道 |
| AI 附带上下文 | 默认不带 RPC 历史;仅「选中一条发给 AI」 |
| 暂停 / 下一帧 | Mock/重放须标注可能与服务端状态不一致 |
| 共存 | 与 Charles、其他 WS Hook 扩展:链式调用原方法,禁止独占 WebSocket.prototype |
| Mock / 重放 | 独立开关,UI 标注 【⚠️ 风险警示】;与「只读抓包」分离 |
5. 建议通信链路(实现时)
text
DevPanel(RpcCapturePanel)
↔ Chrome Port(DevPanel{tabId})
content.js(隔离世界)
↔ CustomEvent($h5GameCopilotChannel)
inspector.js(MAIN world)
↔ RpcCaptureBridge(WS Hook + 环形缓冲 + Provider 调度)不得在 DevPanel 上下文直接读 window 上的游戏协议对象;解码在 MAIN world 或 inspectedWindow.eval 与现有检视链路一致。
6. MVP 建议顺序
L0 + L1 只读:Lazy Hook + 缓冲 + sproto 自动 detect + 列表面板✅(顶栏「RPC抓包」、RpcCapturePanel、rpcCapture/*)L0 明文增强:WS 帧内自动识别✅[...]/{...},首字段作 cmd;可选开发者protocolMapL0 二进制包头:通用✅[size:u16][msgType:u16][action?]…;hg 内置通道名;Body 为结构化摘要- 单条详情、导出、发给 AI
- 单条重放(Provider 适配)
- Mock 回包(独立模式)
- HTTP Provider 或文档引导使用 CrapApi(避免与 CrapApi 全量重复)
双路径解码(勿混用破坏)
| 路径 | 条件 | 能力 |
|---|---|---|
| sproto Tap | 页面有 window.Sproto 且可 patch SendData/HandlerType | 协议名 cs_/sc_ + JSON Body(自研/demo) |
| WS + 明文 | 无完整 sproto | 抓原始帧;自动剥离包头后的 JSON/数组;列表 cmd:数字 |
| WS + 二进制包头 | 明文解不出,且前 4 字节 size≈帧长 | msgType + 可选 action;protocolMap / hg 内置通道名;Body 为 {size,msgType,msgName,action,payloadHex} |
| 用户字段表 | 可选 | decodeSchemas:按 u8/u16/u32/u64/string… 把 payload 解成 fields;键 7027:8 / 7027 / * |
| 开发者协议表 | 可选 | protocolMap = { 7027: "MsgML", "7027:8": "MsgML_Act8" } |
用户补全 Body(非 sproto)
游戏页 Console(MAIN world,与 inspector 同页):
js
window.__h5GameCopilotRpc = window.__h5GameCopilotRpc || {};
window.__h5GameCopilotRpc.protocolMap = {
'7027': 'MsgML',
'7027:8': 'MsgML_Act8'
};
window.__h5GameCopilotRpc.decodeSchemas = {
'7027:8': [
{ name: 'id', type: 'u64' },
{ name: 'flag', type: 'u64' },
{ name: 'tail', type: 'restHex' }
]
};对照 MsgXxx.create / process 里 pushUint64 / popUint8 顺序写表;仅对新录制的包生效。也可在 RPC 面板点 「挂表扩展」 粘贴同一 JSON(DevPanel 经 Port 写入游戏页)。也可用 __h5GameCopilotRpcCapture.setDecodeSchemas(...)。
已实现文件(MVP)
| 路径 | 职责 |
|---|---|
packages/inspect/src/inspector/rpcCapture/ | MAIN world Hook、sproto / 明文 / 二进制包头解码、Bridge |
rawTextDecode.ts | WS 明文 [...]/{...} + 开发者 protocolMap |
binaryHeaderDecode.ts | 通用长度+消息号包头;hg 通道内置表 |
userBinarySchema.ts | 用户 decodeSchemas 字段解码 |
packages/inspect/src/devpanel/RpcCapturePanel.ts | DevPanel 列表 / 详情 UI |
packages/inspect/src/common/MessageTypes.ts | rpcCapture* 消息 |
scripts/assemble-copilot.js | #rpcCaptureView + #btnRpcCapture |
7. 相关文档
AGENTS.md— Agent 规约(RPC 改动须遵守本节原则)性能优化.md— 常驻开销与 P0/P1/P2 减负策略.cursor/rules/change-impact-regression.mdc— 功能域 RPC抓包 回归地图cursor.md— 路线图「RPC / 网络抓包」待办