docs: 修正还原计划,确认 net 模块已实现数据包解析

This commit is contained in:
TermiNexus committed 2026-10-27 02:08:01 +08:00
1 parent faf109a6a3
commit a46bba2435
2 files changed
+195 -77

No files matched your search

+86 -77
View File
@@ -236,113 +236,118 @@
---
## 5. 官方 Socket 链路反编译
## 5. 官方 Socket 链路
### 5.1 先纠正一个事实
### 5.1 先纠正:数据包解析已经实现
官方客户端**没有 Socket.IO**。在 `3DTank/src` 与 `main.6469b966.js` 中搜索 `socket.io` / `engine.io` / `io.connect` 均为 0 命中。
不是“从零反编译”。KT 工程已经有一套完整的官方包解析:
官方用的是**原生 WebSocket + 自定义二进制协议**:
- `TankiOffline/net/src/jsMain/kotlin/Net/Generated/`:
- `DownlinkRegistry`:**681** 个 methodId → codec
- `UplinkRegistry`:**361** 个 methodId → codec
- `ModelRegistry`:**363** 个 modelId → codec
- 14 个 codec 模块:85183 / 47243 / 85196 / 31908 / 16100 / 10283 / 25377 / 54199 / 37504 / 88693 / 89803 / 85667 / 67222 / 99527
- 另有 24635 / 1510 / 29554 / 45686 / 61860 / 71105 / 85745 / 87072
- `Net/Protocol/`:
- `Entry`:Hash Request / Hash Response / EnterSpace / OpenSpace
- `SpaceFrame`:帧体 → 记录
- `StreamDecoder`:明文/探测/解密三阶段、XOR key
- `Containers`:Lt / Pt / Zt / Alias
- `TankStateCodec`
- `Net/Wire/ModelCodec`
- `App/Session/`:
- `SpaceSession`:Feed → DecodedRecord
- `SessionRouter`:DecodedRecord → DownlinkActions → Redux Store
- `UplinkEncoder`:动作 → 上行帧
- `SessionCheck` / `StateCheck` / `AutoTest`:自检与真实中继测试
- `App/State/`:
- 89/89 reducer 切片
- `DownlinkActions` / `DownlinkModelActions`
- `RootState` / `RootWiring`
- `3DTank/src/module_61860.js:992`:`new WebSocket(this.t7u_1)`
- `this.t7u_1 = t + "://" + n + ":" + i + "/"`(protocol / host / port)
- `binaryType = "arraybuffer"`
- 连接后走 `Ee(t)` 协议对象、`p7u_1` / `q7u_1` 编解码、`r7u_1` 命令分发
所以“官方所有的数据包解析”这件事,KT 工程已经做了大部分,不需要重新读 14 个 codec 模块。
所以计划是反编译**官方 WebSocket 链路**;如果另有 Socket.IO 入口(例如网页活动页),需要单独给出 URL,我再补一条支线。
### 5.2 真正缺的是“链路前半段”
### 5.2 链路分层
现在的 `LobbyClient` 是:
```text
启动
└─ 配置 / 区域
├─ config.xml(c{server}.3dtank.com/config.xml)
├─ status.js(3dtank.com/s/status.js)
└─ balancer(balancer.*.tankionline.com/balancer)
└─ BalancerStatus / BalancerNode / BalancerNodeEndpoint
└─ 选节点 host:port
└─ WebSocket(protocol://host:port/)
├─ 登录 / 鉴权
├─ Hash Request / Hash Response
├─ Open Space / EnterSpace
├─ LoadDependencies
└─ Space 二进制帧
├─ 解帧 / 解密
├─ 命令 id + 字段
└─ SessionRouter → RootState
登录表单 → LobbyClient.Login → Connect(中继 URL) → Hash Request → ...
```
### 5.3 反编译步骤
它缺的是官方链路的前半段:
#### S1 配置 / Balancer
1. **config / status / balancer**:官方节点发现
2. **auth**:账号密码 → token/cookie
3. **官方 WebSocket 建连**:protocol/host/port、header、子协议
4. **覆盖率**:真实官方会话下 `SessionRouter.Unmapped` / `Failed` 是否归零
5. **golden 帧校验**:现有 codec 是否 byte-for-byte 对得上
1. 读 `module_13431`:区域、`config.xml`、`status.js`、balancer URL 规则。
2. 读 `module_61860` 的 `BalancerStatus` / `BalancerNode` / `BalancerNodeEndpoint` 字段。
3. 抓一次官方启动请求:config、status、balancer。
4. 产出 `docs/BalancerProtocol.md`:URL 规则、字段、选节点算法。
### 5.3 链路分层(已有 / 待补)
#### S2 登录 / 鉴权
| 层 | 状态 | 位置 |
|---|---|---|
| config / status / balancer | 待补 | `module_13431` / `module_61860` |
| auth / 登录 | 待补 | `module_82347` Entrance / `module_61860` |
| WebSocket 建连 | 待补 | `module_61860:992` `Ie` |
| Hash / OpenSpace / EnterSpace | 已有 | `Net/Protocol/Entry.kt` |
| 帧解码 / XOR | 已有 | `Net/Protocol/StreamDecoder.kt` |
| 记录解码 | 已有 | `Net/Protocol/SpaceFrame.kt` + `Registry.kt` |
| 容器 Lt/Pt/Zt/Alias | 已有 | `Net/Protocol/Containers.kt` |
| 记录 → 动作 | 已有 | `App/Session/SessionRouter.kt` |
| 动作 → 上行 | 已有 | `App/Session/UplinkEncoder.kt` |
| 状态 | 已有 | `App/State/` |
1. 读 `module_82347` 的 `EntranceComponentStyle` + `xxn` / `Tzn` / `gKt` / `sWt`。
2. 找登录请求:HTTP/WS、方法、路径、body、header、cookie、token。
3. 抓包:登录成功/失败、验证码、记住我、社交登录。
4. 产出 `docs/AuthProtocol.md`:请求/响应、错误码、token 生命周期。
### 5.4 待补工作
#### S3 WebSocket 建连
#### S1 config / balancer
1. 读 `module_61860` `Ie`:URL、子协议、header、binaryType。
2. 读 `Ee(t)`:protocol 对象、版本、握手字段。
3. 读 `p7u_1` / `q7u_1`:帧格式、长度、压缩、加密。
4. 产出 `docs/SocketProtocol.md`:建连、帧格式、心跳、重连。
1. 读 `module_13431` 的 URL 规则、区域、config.xml、status.js、balancer。
2. 读 `module_61860` 的 `BalancerStatus` / `BalancerNode` / `BalancerNodeEndpoint`。
3. 抓官方启动请求。
4. 在 Kotlin 实现 `BalancerClient`,输出 `docs/BalancerProtocol.md`。
#### S4 Lobby 握手
#### S2 auth
1. `Hash Request` / `Hash Response`:字段、digest、加密标志。
2. `Open Space`:spaceId、节点、token。
3. `EnterSpace`:digest、spaceId。
4. `LoadDependencies`:zt 载荷、依赖列表。
5. 与现有 `LobbyClient` 逐字段对照,删掉中继特化代码。
1. 读 `module_82347` Entrance 的登录请求。
2. 抓登录成功/失败、token/cookie。
3. 在 `LobbyClient.Login` 里替换 `Connect(中继)` 为官方 auth + 官方 WS。
4. 输出 `docs/AuthProtocol.md`。
#### S5 Space 协议
#### S3 官方 WebSocket
1. 读 14 个 codec 模块:85183 / 47243 / 85196 / 31908 / 16100 / 10283 / 25377 / 54199 / 37504 / 88693 / 89803 / 85667 / 67222 / 99527。
2. 命令 id + 字段序号 + 默认值逐项入表。
3. 用 `wss_server.js` 抓 golden 帧,做 encode/decode 对比。
4. 产出 `docs/SpaceProtocol.md` + `names/codec_fields.json`。
1. 读 `module_61860` `Ie`:URL、header、子协议、binaryType。
2. 用官方 URL 替换 `LobbyClient.Connect`。
3. 保留现有 `Entry` / `SpaceSession` / `SessionRouter`。
4. 输出 `docs/SocketProtocol.md`。
#### S6 状态映射
#### S4 覆盖率审计
1. 读 `module_10032`(Redux 核心)、`module_18334`(DI)、`module_61860`(对象模型)。
2. 命令 → 记录 → RootState 槽位逐项对照。
3. 产出 `docs/StateMap.md` 更新。
1. 用官方会话跑 `SessionRouter`,收集 `UnmappedIds` / `FailedIds`。
2. 对照 `Registry.kt` / `DownlinkActions`,逐项补齐。
3. 目标:`Unmapped = 0`、`Failed = 0`(或只剩明确不需要的 UI-only 记录)。
4. 输出 `docs/NetCoverage.md`。
### 5.4 工具链
#### S5 golden 帧
| 工具 | 用途 |
|---|---|
| `3DTank/tools/serve.js` | 本地静态 + 反向代理 + config 改写 |
| `3DTank/tools/wss_server.js` | 中继 + 抓包 + 实时解密 |
| `3DTank/tools/analyze_packets.js` | 抓包分析 |
| `3DTank/tools/prefetch_assets.js` | 资源预拉 |
| `3DTank/tools/headless_probe.js` | 页面探针 / CSS / 截图 |
| `3DTank/tools/server/` | 协议服务端骨架(codec/dispatch/session/space/world) |
| Chrome DevTools Protocol | 网络抓包、HAR、WS frames |
| mitmproxy / Fiddler | TLS 抓包(如需要) |
1. 用 `wss_server.js` / CDP 抓官方帧。
2. 对每个 methodId 做 encode/decode 对比。
3. 差异写入 `docs/NetCoverage.md`。
### 5.5 验收
1. 不经过 `9091` 中继,直接连官方节点。
1. 不经过 `9091` 中继,直连官方节点。
2. 登录成功,拿到 Lobby 状态。
3. 进入 Space,收到 `LoadDependencies` 并完成依赖加载。
4. 抓包 golden 帧回放,编解码 byte-for-byte 一致。
5. 同一账号下,客户端 RootState 与官方客户端一致(至少用户、货币、车库、任务、聊天)。
4. `SessionRouter.Unmapped = 0`、`Failed = 0`。
5. golden 帧 byte-for-byte 一致。
### 5.6 风险
- TLS/证书、区域限制、登录验证码。
- 官方协议版本更新(codec 字段漂移)。
- token/加密密钥的获取方式。
- 反作弊/风控(只做本地复现,不绕过官方限制)。
- TLS/证书、区域限制、验证码。
- token/加密密钥获取。
- 官方协议版本更新导致 codec 漂移。
- 反作弊/风控(只做本地复现,不绕过限制)。
---
@@ -381,10 +386,14 @@
- 补 `EntranceComponentStyle` 的社交登录、找回密码、错误 tooltip。
- 补 `gKt` 输入组件的 `visualState` / `error` / 图标。
- 补 `sWt` 共享按钮的完整样式。
2. 同时开 **S1/S2 链路取证**:
2. 同时做 **Net 覆盖率审计**(不是重写 codec):
- 用现有 `net` 模块 + `SessionRouter` 跑真实/中继会话。
- 收集 `UnmappedIds` / `FailedIds`,逐项补齐 `Registry.kt` / `DownlinkActions`。
- 产出 `NetCoverage.md`。
3. 同时开 **S1/S2 链路取证**:
- 用 CDP 抓官方 config/status/balancer/login。
- 产出 `BalancerProtocol.md` / `AuthProtocol.md`。
3. 把 `UiTranslationStatus.md` 改成“只有 100% 才写已完成”,其余全部列“进行中”。
4. 把 `UiTranslationStatus.md` 改成“只有 100% 才写已完成”,其余全部列“进行中”。
---
+109
View File
@@ -0,0 +1,109 @@
# Net Coverage
> 目的:证明 KT 工程已经实现官方数据包解析,并明确“还缺什么”。
> 结论:**解析层基本完成**;缺的是官方链路前半段(config/balancer/auth/WS)和真实会话覆盖率审计。
## 1. 已实现
### 1.1 生成物(`TankiOffline/net/src/jsMain/kotlin/Net/Generated/`)
| 文件 | 内容 | 数量 |
|---|---|---|
| `Registry.kt` → `DownlinkRegistry.ByMethodId` | methodId → downlink codec | **681** |
| `Registry.kt` → `UplinkRegistry.ByMethodId` | methodId → uplink codec | **361** |
| `Registry.kt` → `ModelRegistry.ByModelId` | modelId → model codec | **363** |
| `Metadata.kt` | 模型名 / method 名 / 字段元数据 | — |
生成的 codec 模块:
```text
Downlink: 10283 1510 25377 29554 31908 37504 47243 54199 85183 85196 85667 88693 89803
Models: 01510 10283 16100 24635 25377 31908 37504 45686 47243 54199 61860 67222
71105 85183 85196 85667 85745 87072 88693 89803 99527
Uplink: 10283 25377 37504 47243 54199 85183 85196 85667 89803
```
覆盖原版 14 个 codec 模块:85183 / 47243 / 85196 / 31908 / 16100 / 10283 / 25377 / 54199 / 37504 / 88693 / 89803 / 85667 / 67222 / 99527。
### 1.2 协议层(`Net/Protocol/`)
| 文件 | 作用 |
|---|---|
| `Entry.kt` | Hash Request / Hash Response / EnterSpace / OpenSpace / BuildObjectDataRequest |
| `SpaceFrame.kt` | 帧体 → 记录;处理 nullmap / alias |
| `StreamDecoder.kt` | 明文 / 探测 / 解密三阶段;XOR key |
| `Containers.kt` | Lt / Pt / Zt / Alias 容器 |
| `TankStateCodec.kt` | 坦克状态 |
| `Wire/ModelCodec.kt` | 模型编解码接口 |
### 1.3 会话层(`App/Session/`)
| 文件 | 作用 |
|---|---|
| `SpaceSession.kt` | WebSocket 字节 → `DecodedRecord` |
| `SessionRouter.kt` | `DecodedRecord` → `DownlinkActions` / `DownlinkModelActions` → Redux |
| `UplinkEncoder.kt` | 动作 → 上行帧 |
| `SessionCheck.kt` | 会话自检 |
| `StateCheck.kt` | Redux 状态自检 |
| `AutoTest.kt` | 真实中继一次性测试 |
### 1.4 状态层(`App/State/`)
- 89/89 reducer 切片(见 `KtRebuild_Plan.md`)。
- `RootState.kt` / `RootWiring.kt`。
- `DownlinkActions.kt` / `DownlinkModelActions.kt`。
- `ActionCatalog.kt` / `ActionSamples.kt`。
## 2. 还没实现
### 2.1 链路前半段
| 层 | 状态 | 依据 |
|---|---|---|
| config.xml / status.js | 未实现 | `module_13431` |
| balancer | 未实现 | `module_13431` / `module_61860` |
| auth(账号密码 → token/cookie) | 未实现 | `module_82347` Entrance / `module_61860` |
| 官方 WebSocket 建连 | 未实现 | `module_61860:992` `Ie` |
| 直连官方节点 | 未实现 | 当前 `LobbyClient` 走 `9091` 中继 |
### 2.2 覆盖率审计
`SessionRouter` 已有计数器:
```kotlin
var Unmapped: Int
var Failed: Int
val UnmappedIds: MutableMap<Long, Int>
val UnmappedModels: MutableMap<String, Int>
val FailedIds: MutableMap<Long, Int>
val FailedReasons: MutableMap<String, Int>
```
目标:
- `Unmapped = 0`
- `Failed = 0`
- `UnmappedModels` 为空
需要跑一次真实官方会话,收集并补齐。
### 2.3 golden 帧
现有 codec 是否 byte-for-byte 对得上,需要:
1. 用 `wss_server.js` / CDP 抓官方帧。
2. 对每个 methodId 做 encode/decode 对比。
3. 差异写入本文件。
## 3. 结论
- **数据包解析:已实现**(681 downlink / 361 uplink / 363 model / 14 codec 模块 / Entry / SpaceFrame / StreamDecoder / Containers / SessionRouter / 89 reducer)。
- **官方链路:未实现**(config / balancer / auth / 官方 WS)。
- **覆盖率:未审计**(`Unmapped` / `Failed` 未归零验证)。
- **golden 帧:未校验**。
下一步不是重写 codec,而是:
1. 补 config / balancer / auth / 官方 WS。
2. 跑真实会话,驱动 `Unmapped` / `Failed` 归零。
3. golden 帧 byte diff。