docs(kt): 新增 Kotlin 重构计划(工具清单/阶段/验收)
按 dir.file 的 40/21/65 分类修正范围:仅 40 个游戏本体模块需要复刻;补充现有工具用法、S0-S6 阶段、可启动 JS 验收标准、换版漂移处理与风险回退。
This commit is contained in:
1 parent
66a74df6e3
commit
8bbdb40364
1 file changed
+261
@@ -0,0 +1,261 @@
|
||||
# 3DTank Kotlin 重构计划(KtRebuild Plan)
|
||||
|
||||
> **目标**:用 Kotlin 复刻游戏本体,最终产出**职责等价、可启动**的 JS 客户端。
|
||||
> **基线**:`main.7cfa4058.js`(10,080,299 字节)/ `client_version = e98d02161a563e043eabb96c6e4db5fedcf165e7`
|
||||
> **文档定位**:计划表 —— 有哪些工具、怎么用、按什么顺序做、怎么验收。
|
||||
|
||||
---
|
||||
|
||||
## 0. 先纠正三个前提
|
||||
|
||||
1. **`dir.file` 不是当前版本的职责表。**
|
||||
它是旧版 126 模块的职责划分;当前版本的模块 id、字节数、内部字段都有漂移。
|
||||
但**职责划分大体一致**,仍可作为"要做哪些子系统"的规划依据;正式开工前必须用当前包重建一份职责表(见 S0)。
|
||||
|
||||
2. **`e98d0216` 不是文件名。**
|
||||
`e98d0216…` 是 `client_version`(git release hash,写死在 `module_61860.js`):
|
||||
```js
|
||||
i.g3("client_version", "e98d02161a563e043eabb96c6e4db5fedcf165e7");
|
||||
```
|
||||
而 `main.7cfa4058.js` 的 `7cfa4058` 是 webpack **contenthash**。两者无对应关系,不能互相推导文件名。
|
||||
|
||||
3. **真正要复刻的只有 40 个模块。**
|
||||
`dir.file` 的分类计数:**游戏本体 40 / Kotlin 生态库 21 / 第三方库 65**(另有 index.json、resources.json)。
|
||||
后 86 个是已知开源依赖,直接引上游即可,不需要反编译重写。
|
||||
|
||||
---
|
||||
|
||||
## 1. 验收标准("可启动 JS"的定义)
|
||||
|
||||
| 级别 | 判定 | 手段 |
|
||||
|---|---|---|
|
||||
| **L1 可加载** | 126 模块 + 资源全部注册成功,无 404 / 无语法错误 | `tools/test_loader.js` 全绿 |
|
||||
| **L2 可进战局** | `serve.js` 起站 → 登录 → 车库 → 进战斗 → 控制台无未捕获异常 | 人工 + 控制台 |
|
||||
| **L3 行为等价** | 同场景关键状态(位置/血量/状态机/事件序列)与原包对比一致 | 双跑 golden trace |
|
||||
| **L4 工具兼容** | HORNET 全部开关可用(雷达/透视/后视镜/穿坦克/拒绝击退…) | `build_bundle.py` 产物实测 |
|
||||
|
||||
> L1/L2 是最低门槛;L3 才是"职责等价"的真正证据。
|
||||
|
||||
---
|
||||
|
||||
## 2. 模块分层(依据 `dir.file`)
|
||||
|
||||
| 分类 | 数量 | 处理方式 | 是否重写 |
|
||||
|---|---|---|---|
|
||||
| 游戏本体 | 40 | 反混淆 → Kotlin 复刻 | ✅ |
|
||||
| Kotlin 生态库 | 21 | 换官方依赖(stdlib / serialization / coroutines / atomicfu / kvbuffer…) | ❌ |
|
||||
| 第三方库 | 65 | 换 npm 依赖(React 18.3.1 / Redux / Sentry 5.30.0 / qrcode / Underscore 1.13.6 / Emotion / fflate…) | ❌ |
|
||||
| 资源/索引 | 2 | index.json、resources.json 原样托管 | ❌ |
|
||||
|
||||
**游戏本体的体积分布(决定推进顺序)**:
|
||||
|
||||
| 模块 | 大小 | 职责 | 阶段 |
|
||||
|---|---|---|---|
|
||||
| 82347 | 5.50 MB | 大厅/车库/商店/部落/结算 UI | S6(最后) |
|
||||
| 87072 | 3.78 MB | 战斗系统:底盘物理、模式、物品池、特效、空投、地图渲染 | S5 |
|
||||
| 10032 | 1.54 MB | 核心 Redux 状态 | S3 |
|
||||
| 85183 | 1.18 MB | 全量协议 Codec 注册 | S2 |
|
||||
| 92980 | 0.83 MB | WebGL 渲染核心 | S4 |
|
||||
| 其余 35 个 | < 5 MB | 协议/工具/音频/输入/资源/ECS/物理… | S2–S5 |
|
||||
|
||||
前 5 个约占 12.8 MB,是工作量的绝对主体。
|
||||
|
||||
---
|
||||
|
||||
## 3. 工具清单与用法
|
||||
|
||||
### 3.1 基线与拆分
|
||||
|
||||
| 工具 | 作用 | 用法 |
|
||||
|---|---|---|
|
||||
| `tools/split.js` | 把 `main.<hash>.js` 切成 126 个模块 + `resources.json`,并注入 bundle 加载 | `node tools/split.js [bundle] [输出目录] --clean`(不传参自动取根目录最新 `main.*.js`) |
|
||||
| `3DTank/tools/extract.js` | bundle → prettier 美化源码(`3DTank/src/`) | `cd 3DTank/tools && node extract.js [bundle] [输出目录]` |
|
||||
| `tools/pack_unpacked.js` | 把 `unpacked/` 打成 `unpacked.pack.json`(一次请求加载全部模块) | `node tools/pack_unpacked.js` |
|
||||
| `tools/test_loader.js` | 模拟浏览器加载流程,验证切割产物完整 | `node tools/test_loader.js` |
|
||||
|
||||
### 3.2 命名还原
|
||||
|
||||
| 工具 | 作用 | 用法 |
|
||||
|---|---|---|
|
||||
| `3DTank/tools/mine_evidence.js` | 从源码挖命名证据(组件名/类名/枚举/闭包原名/导出表/字符串) | `cd 3DTank/tools && node mine_evidence.js` |
|
||||
| `3DTank/tools/apply_names.js` | 把证据回填成 `src_named/`(三道校验) | `node apply_names.js --aliases` |
|
||||
| `tools/map_symbols.js` | 新旧 bundle 符号映射(K 元块锚点 + 投票) | `node tools/map_symbols.js <旧unpacked> <新bundle> all tools/symbol_map.json` |
|
||||
| `tools/apply_symbol_map.js` | 按映射批量改名(五道安全规则 + 双向校验) | 见文件头注释;默认读 `3DTank/tmp_symbol_map.json` |
|
||||
| `3DTank/names/module-graph.json` | 模块依赖图(`DependsOn` / `Exports` / `Anchors` / `Kind`) | 数据文件,作为 Kotlin 模块切分依据 |
|
||||
|
||||
### 3.3 字段抽象(当前版本适配的主入口)
|
||||
|
||||
| 工具 | 作用 | 用法 |
|
||||
|---|---|---|
|
||||
| `tools/hornet_schema.js` | 匿名字段 → 语义字段总表(88 项)+ 导出键表 | 控制台 `__hornetSchema__.SelfCheck()` 一次列出失配项 |
|
||||
| `build_bundle.py` | 把 `tools/hornet_*.js` 拼成 `3dtank_bundle.js` 并同步到 `unpacked/` | `python build_bundle.py` |
|
||||
|
||||
换版本时**只改 schema**,工具代码不动;这是本计划里"漂移成本最低"的一环。
|
||||
|
||||
### 3.4 本地运行与协议取证
|
||||
|
||||
| 工具 | 作用 | 用法 |
|
||||
|---|---|---|
|
||||
| `3DTank/tools/serve.js` | 本地静态服务器 + 反向代理(resources / config / balancer)+ 中继 config 改写 | `node serve.js --port 8080 [--relay-port 9091] [--verbose]` |
|
||||
| `3DTank/tools/wss_server.js` | 本地游戏通信服务器(中继 + 抓包 + 实时解密) | `node wss_server.js --port 9091 --upstream wss://c1.3dtank.com:9090/` |
|
||||
| `3DTank/tools/analyze_packets.js` | 抓包产物分析 | 见文件头 |
|
||||
| `3DTank/tools/prefetch_assets.js` | 按 `resources.json` 预拉资源到本地镜像 | `node prefetch_assets.js` |
|
||||
| `3DTank/tools/server/` | 协议服务端骨架(codec / dispatch / session / space / world…) | 供 S3 协议层对照 |
|
||||
|
||||
### 3.5 HORNET 探针(现成的行为断言)
|
||||
|
||||
`tools/hornet_lib.js` / `hornet_radar.js` / `hornet_3d_wireframe.js` / `hornet_noclip.js` / `hornet_noknockback.js` 等,
|
||||
直接读引擎状态(位置、血量、队伍、物理形状)。S5 之后可用它们做"新包是否语义一致"的活体探针。
|
||||
|
||||
---
|
||||
|
||||
## 4. 阶段计划
|
||||
|
||||
### S0 基线重建(必须先做)
|
||||
- **目标**:产出**当前版本**的职责表与依赖图,替换 `dir.file` 的旧数据。
|
||||
- **做法**:
|
||||
1. `node tools/split.js --clean`
|
||||
2. `node 3DTank/tools/extract.js ../main.7cfa4058.js ../src`
|
||||
3. `node mine_evidence.js`(更新 `evidence.json`)
|
||||
4. 以 `module-graph.json` 的 `DependsOn/Exports/Anchors/Kind` 重新分类 126 模块
|
||||
- **输出**:`3DTank/names/module-graph.json` + 新版职责表(按当前模块 id)
|
||||
- **验收**:`node tools/test_loader.js` 全绿;分类计数与旧表基本一致(40/21/65 量级)
|
||||
|
||||
### S1 依赖还原(86 个库)
|
||||
- **目标**:把库模块映射为上游依赖,产出 `deps.lock`。
|
||||
- **做法**:用 `Anchors`(版本字符串、API 名)反推包名与版本;导出表对照 API 面。
|
||||
- **已知**:React/React-DOM 18.3.1、Sentry 5.30.0、Underscore 1.13.6。
|
||||
- **待挖**:Kotlin 编译器版本、kotlinx-coroutines / serialization / atomicfu 版本、kotlin-wrappers、Emotion。
|
||||
- **验收**:每个库模块都能指到"包名 + 版本 + 用到的导出符号"。
|
||||
|
||||
### S2 协议层(14 个 codec 模块)
|
||||
- 模块:85183 / 47243 / 85196 / 31908 / 16100 / 10283 / 25377 / 54199 / 37504 / 88693 / 89803 / 85667 / 67222 / 99527
|
||||
- **目标**:Kotlin 数据类 + `@Serializable`,按 **命令 id + 字段序号** 对齐。
|
||||
- **验证**:用 `wss_server.js` 抓到的帧做 golden 编解码对比(现有 `names/*_table.json`、`codec_fields.json` 可直接用)。
|
||||
- **注意**:字段顺序/默认值错一位整包不可用,必须逐帧验。
|
||||
|
||||
### S3 状态与胶水
|
||||
- 模块:10032(Redux 核心)、18334(DI 装配)、61860(连接与对象模型)、13431(启动)、52943(工具库)、26482(SW 注册)
|
||||
- **目标**:新工程能完成"启动 → 连接 → 进入大厅"。
|
||||
- **验收**:L2 的一半(登录 + 大厅)。
|
||||
|
||||
### S4 引擎核心
|
||||
- 模块:32088(3D 数学)、92980(渲染)、61378(ECS)、55088(物理)、36659 + 71105(资源)、36734(音频)、3569(输入)
|
||||
- **目标**:场景可渲染、物理可步进。
|
||||
- **做法**:先纯函数层(矩阵/几何/物理步进),再渲染管线;用同输入同输出做单元比对。
|
||||
- **验收**:车库 3D 预览可显示;进战斗不崩。
|
||||
|
||||
### S5 战斗系统(87072,3.78 MB)
|
||||
- 按子系统拆文件:底盘/悬挂、物理、战斗模式、物品池、空投、特效、地图渲染。
|
||||
- **验收**:L2 完整(可进战斗并驾驶/开火),HORNET 探针读数与原包一致。
|
||||
|
||||
### S6 UI(82347 5.5 MB + 21300 HUD)
|
||||
- **建议最后做**,或长期保留原 JS 模块(Kotlin 与 JS 模块可混跑)。
|
||||
- **验收**:各界面可打开、无报错;不追求像素级一致。
|
||||
|
||||
---
|
||||
|
||||
## 5. 目录规划(拟)
|
||||
|
||||
```
|
||||
KT/
|
||||
settings.gradle.kts
|
||||
build.gradle.kts
|
||||
app/ # 入口(对应 13431)
|
||||
core/ # 数学 32088、工具 52943
|
||||
ecs/ # 61378
|
||||
physics/ # 55088
|
||||
render/ # 92980
|
||||
resource/ # 36659、71105
|
||||
net/ # 61860 + codec/*(S2 全部模块)
|
||||
state/ # 10032、18334
|
||||
battle/ # 87072(内部再按子系统分文件)
|
||||
ui/ # 82347、21300(可延后)
|
||||
deps/ # React/Redux/Sentry 的 external 声明
|
||||
web/ # index.html、resources.json、静态资源
|
||||
```
|
||||
|
||||
约定:
|
||||
- 一个 webpack 模块 ≈ 一个 Kotlin 文件(巨型模块按类拆);
|
||||
- 对外属性名保持不变(跨模块共享),类名可改;
|
||||
- 浏览器 API 全部 `external`(WebGL2 / WebSocket / PointerLock / WebAudio / Storage / Worker)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 依赖与版本
|
||||
|
||||
| 依赖 | 模块 | 版本 | 状态 |
|
||||
|---|---|---|---|
|
||||
| kotlin-stdlib-js | 37036 | 待挖 | — |
|
||||
| kotlinx-serialization-core / json | 9539 / 61430 | 待挖 | — |
|
||||
| kotlinx-coroutines | 89613 | 待挖 | — |
|
||||
| atomicfu | 71426 | 待挖 | — |
|
||||
| kvbuffer | 72834 | 待挖 | — |
|
||||
| React / React-DOM | 78931 / 45555 | 18.3.1 | ✅ |
|
||||
| Sentry Browser SDK | 30285 | 5.30.0 | ✅ |
|
||||
| Underscore | 94965 | 1.13.6 | ✅ |
|
||||
| Redux(Kotlin 侧) | 10849 | 自研封装 | 需评估 |
|
||||
| qrcode 系列 | 59411 等 | 待挖 | — |
|
||||
| Emotion / inline-style-prefixer | 14766 / 77249 等 | 待挖 | — |
|
||||
| fflate | 29518 | 待挖 | — |
|
||||
|
||||
---
|
||||
|
||||
## 7. 换版与漂移处理
|
||||
|
||||
1. 抓新 `main.<hash>.js` → `node tools/split.js --clean`
|
||||
2. `node tools/map_symbols.js <旧unpacked> <新bundle> all tools/symbol_map.json`
|
||||
3. `__hornetSchema__.SelfCheck()` 列出语义字段失配 → **只改 `hornet_schema.js`**
|
||||
4. 人工核对三类:
|
||||
- `$_.xx` 导出键(队伍 `vd/dl`、碰撞世界 `55088.$_.h` 等)
|
||||
- 工具 hook 的类内部方法(`o37` / `o3c` / `n3c` / `f3t` / `q9q` / `kz7`)
|
||||
- 渲染管线字段语义(`d75_1` / `w39_1` / `b74_1` …)
|
||||
5. `python build_bundle.py` → 实测工具
|
||||
|
||||
---
|
||||
|
||||
## 8. 产出"可启动 JS"的端到端流程
|
||||
|
||||
```bash
|
||||
# 1) 基线
|
||||
node tools/split.js --clean
|
||||
node 3DTank/tools/extract.js ../main.7cfa4058.js ../src
|
||||
cd 3DTank/tools && node mine_evidence.js && cd ..
|
||||
|
||||
# 2) Kotlin 编译(工程建好后)
|
||||
./gradlew :app:build # 产物:build/dist/js/productionExecutable/
|
||||
|
||||
# 3) 产物接入(二选一)
|
||||
# A. 用 Kotlin 产物直接替换 main.<hash>.js(需自建 webpack runtime)
|
||||
# B. 保留现有 loader,把 Kotlin 产物作为新模块注册进 __modules__
|
||||
node tools/pack_unpacked.js
|
||||
|
||||
# 4) 验收
|
||||
node tools/test_loader.js # L1
|
||||
node 3DTank/tools/serve.js --port 8080 # L2:浏览器进站
|
||||
node 3DTank/tools/wss_server.js --port 9091 --upstream wss://c1.3dtank.com:9090/ # L3:抓包对比
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 风险与回退
|
||||
|
||||
| 风险 | 影响 | 应对 |
|
||||
|---|---|---|
|
||||
| 协议字段序号错位 | 整包不可用 | S2 逐帧 golden 对比;先只做只读命令 |
|
||||
| Kotlin 版本差异 | 输出与原包不同 | 不追求字节一致,只追求语义等价(双跑) |
|
||||
| 巨型模块拆分失控 | 进度不可控 | 87072/82347 按子系统拆文件,先骨架后逻辑 |
|
||||
| 渲染管线语义不明 | 画面异常 | 保留原 92980 模块,先替换非渲染层 |
|
||||
| UI 体量过大 | 拖慢整体 | S6 延后,允许长期混跑原 JS 模块 |
|
||||
| 换版漂移 | 工具失效 | schema + `SelfCheck()` 作为唯一适配面 |
|
||||
|
||||
**回退策略**:每个阶段都保留"原模块可用"的开关;Kotlin 模块按模块 id 替换,出问题单模块回退,不影响整包。
|
||||
|
||||
---
|
||||
|
||||
## 10. 待确认
|
||||
|
||||
1. `32088`(标注"Alternativa3D,Kotlin 编写")是自研移植还是开源库?决定 S4 是"引入"还是"重写"。
|
||||
2. `10032` / `10849`(Redux)是否必须保持 Kotlin 实现,还是可以换成原生 Redux?
|
||||
3. S6 UI 是否允许永久保留原 JS 模块(推荐允许)。
|
||||
4. 是否要求最终产物能**替代** `main.<hash>.js`,还是只要"能启动 + 职责等价"即可。
|
||||
Reference in new issue
Block a user