TermiNexus
|
86b9322a9f
|
fix(wireframe): 按新版字段修复模型采集与敌我判定
|
2026-10-18 19:10:22 +08:00 |
|
TermiNexus
|
4d8cbd81d6
|
chore(sw): 本地镜像禁用 Service Worker(自注销旧注册 + 置空游戏 SW 注册模块)
|
2026-10-18 19:00:52 +08:00 |
|
TermiNexus
|
a34cae5474
|
fix(tools): 按新旧差异修复位置与相机链路(雷达/透视恢复绘制)
|
2026-10-17 16:50:54 +08:00 |
|
TermiNexus
|
9506648877
|
fix(lib): 位置探测增加矩阵式兜底([12],[13],[14] 平移分量)
- 旧版位置来自物理组件的世界变换矩阵(K$ 实例,非普通向量),新版字段平移后无法靠名字命中
- 兜底 2:遍历组件找长度 >=15 的矩阵对象,取 [12]/[13]/[14] 作为平移(引擎惯用布局)
|
2026-10-17 16:29:06 +08:00 |
|
TermiNexus
|
67b2ff4a80
|
fix(lib): 坦克位置改为多级字段探测(修复雷达/透视为空)
- 根因:物理组件的位置向量字段每构建都平移,本次 pz7_1→gzh_1→rzf_1 的映射全都指错(gzh_1 是 TerminatorCC、rzf_1 是 RicochetSfxData)
- GetTankPosition 改为多级探测:先试一组成员字段(xzq_1/uzq_1/azr_1/bzr_1/dzr_1/izr_1/jzr_1…),再兜底遍历组件找带 f20_1/g20_1/h20_1 的 O\$ 向量
- 透视的坦克绘制与金箱位置都改用 GetTankPosition
|
2026-10-17 16:19:54 +08:00 |
|
TermiNexus
|
1cc1afdb08
|
fix(hook): GameMode hook 目标改为新版导出键(jc/ic),修复所有工具静默失效
- 根因:新版导出键语义漂移 —— \$.ac 变成两字段数据类 \、\ \$.zb 变成 ydt,不再是「取 gmt 实例 / ght 类」
- 新版对应关系:\ \$.jc = dct(scene) 取 ght 实例;\ \$.ic = wct 即 ght 类;\ \$.kc = gct(scene) 取 GameMode 实体
- hook 目标改为 \ \$.jc,并继续 hook wct.prototype 全方法作为兜底
- 重新生成 hornet_bundle.js 并同步 unpacked
|
2026-10-17 15:57:40 +08:00 |
|
TermiNexus
|
56a1356cce
|
fix(tools): 补全新版符号替换(修复透视/雷达仍不可用)
- 双向校验误判:q100_1 / r11l / jyw / t101_1 在新版同名但含义不同(普通数值 / 别的方法),被当作未变而跳过
- 强制替换:q100_1 到 m10b_1(坦克管理)、r11l 到 j11y(坦克列表)、jyw 到 lz4(取实体)、t101_1 到 p10c_1
- 覆盖 hook_gamemode.js(文件名不匹配 hornet_ 被漏掉)
- 物理组件字段 gzh_1 改为 rzf_1(新版 gzh_1 已是 TerminatorCC 字段,非物理)
- 移除已不存在的 xyu(GameMode),改用 gm.lz4()(等价:取 GameMode 实体)
- 重新生成 hornet_bundle.js(10 模块 / 249229 字节)并同步 unpacked
|
2026-10-17 15:49:50 +08:00 |
|
TermiNexus
|
dcf5dfce5c
|
fix(tools): 工具链符号对齐新版 bundle(修复 HORNET 功能大面积失效)
- 根因:新版 main.7cfa4058 重拆后游戏符号整体平移,工具里写死的字段名(pyt_1/q100_1/r11l/oyz/jyw/cyw_1/dyw_1…)全部对不上 → 找不到组件/相机/场景
- 新增 tools/apply_symbol_map.js:按 map_symbols 映射批量替换,4 道安全规则:① 长名或含下划线 ② 排除 JS 关键字/内置名黑名单 ③ 游戏符号命名特征(含数字或 _数字 结尾) ④ 双向校验(旧名在新 bundle 仍存在→视为未变跳过;新名不存在→映射错误丢弃)
- 单遍替换,避免链式污染(映射表新旧同名复用时会被二次替换)
- 应用到 12 个 hornet_*.js 共 231 处(跳过 25764 个未变符号)
- 重新生成 hornet_bundle.js(10 模块 / 249263 字节)并同步 unpacked
|
2026-10-16 14:55:39 +08:00 |
|
TermiNexus
|
469f913619
|
fix(page): 修复 index.html 主文件引用失配(新主文件没被加载,自动刷新拦截等全部失效)
- 根因:index.html 写死 main.9f4e7a89.js,重拆后主文件改名 main.7cfa4058.js → 请求旧名 404,新主文件里的 HORNET 注入 / 自动刷新拦截 / F5 兜底压根没加载
- 3DTank/web/index.html:引用改为 main.7cfa4058.js
- tools/serve.js:Resolve 增加兜底 —— 请求 main.<hash>.js 但文件不存在时,回退到目录里最新的 main.<hash>.js(以后换 bundle 无需再改 HTML)
- tools/split.js:拆分完成后自动改写 index.html 的主文件引用(防复发)
|
2026-10-16 14:23:02 +08:00 |
|
TermiNexus
|
fd0dffe31b
|
feat(bundle): 迁移到新版 main.7cfa4058.js(重做拆分 + 移植 7 处针对性修改)
- 拆分:tools/split.js 重切新版(1347 模块 / 126 代码模块),主文件 main.7cfa4058.js,语法验证通过
- 修复 split.js 内自动刷新拦截的 \\n 转义:它在模板字符串里,必须写 \\\\n,否则生成的主文件字符串断行、语法报错
- 符号映射:map_symbols.js 对齐旧→新(qyr→ryz、w187→c18o、z4t→jtn、vgt→rkt、Bmt→Ezt、Qjt→Fjt、txt→Gjt、k15b→s15n、azi_1→vzr_1…)
- 移植 7 处针对性修改:炮塔摆头不回弹(vSt.ryz)、摆头不过冲(case 0)、精准跟手(case 1/2)、悬浮底盘 raw 两级(Ezt.n36 + Zmt 实际速度)、电磁炮蓄力时长(jtn.c18o)
- 重新打包 unpacked.pack.json(127 文件 / 版本 96833eb2b0cf8909)
|
2026-10-16 14:20:15 +08:00 |
|
TermiNexus
|
cbeb78baba
|
feat(page): 自动刷新拦截改为默认开启(便于查看 err toast)
- 原来默认关闭(需 localStorage.hornetBlockReload=1),游戏一遇到致命错误/断线就 location.reload() 刷页,err toast 一闪即没
- 现改为默认开启:localStorage.hornetBlockReload='0' 才关闭;F5 仍然放行一次
- 同步源文件 tools/split.js 与产物 main.9f4e7a89.js
- 注意:拦截期间游戏无法靠刷页重连,只能反复内部重连(临时排查用)
|
2026-10-16 14:14:51 +08:00 |
|
TermiNexus
|
6dbe6c6b24
|
fix(hover): 悬浮底盘 raw 速度补上第二级平滑器(Zmt.wak 的 m14f_1)
- 上一版只改了 Bmt.l36(目标速度那一级),实际速度还在 Zmt.wak 里经 m14f_1.x142 逐帧追赶,所以摆动依旧
- 速度链是两级串联:Bmt.y12d_1(目标速度)→ Zmt.m14f_1(实际速度),现两级都按 raw 直接锁目标
- 回退:window.__hornetHoverRaw__ = false
|
2026-10-15 18:51:41 +08:00 |
|
TermiNexus
|
f8502a0726
|
feat(hover): 悬浮底盘改为 raw 速度(参考炮塔做法,消除无端摆动)
- 位置:module_87072 的 Bmt.l36(悬浮底盘每帧速度推进)
- 原逻辑:y12d_1/z12d_1 两个 vgt 平滑器按加速度 u143_1/v143_1 逐帧逼近目标 → 惯性来回摆
- 改为:直接 na0(w143_1) 把当前值锁成目标值(等同炮塔 qyr 的 i = this.azi_1)
- 回退开关:window.__hornetHoverRaw__ = false
|
2026-10-15 18:20:35 +08:00 |
|
TermiNexus
|
ab4c31311c
|
fix(relay): 上游握手不再发送 Referer(对齐浏览器真实握手)
- 依据:官方 Copy-as-cURL 的握手头里没有 Referer —— 浏览器发起的 WebSocket 握手本身不带它
- 实测:用原版头直连 wss://c1.3dtank.com:9090/ 可保持连接(8s 超时退出);而中继因多带 Referer 被上游 code=1000 关闭(短命连接)
- 仅删 Referer;Origin 仍强制覆盖为 https://3dtank.com(本机 origin 会被上游拒)
|
2026-10-15 16:27:34 +08:00 |
|
TermiNexus
|
1b487fbdd6
|
revert(relay): 回退「按首帧分流上游」(假设已被原始 bundle 证伪)
- 依据:官方 main.9f4e7a89.js 中 config-template = https://c{server}.3dtank.com/config.xml,server 号由 balancer(/s/status.js)决定,与连接类型无关
- 本机镜像走 else 分支:config-template = http://<本机>/config.xml(无 {server} 占位符),根本不参与分服
- 恢复「连上立即建上游」以保持与上游 TLS 建连并行;保留 --upstream-alt 参数与 FirstCmdId 记录备用
|
2026-10-15 16:19:35 +08:00 |
|
TermiNexus
|
941dde0913
|
fix(relay): 按首帧分流上游 —— Hash Request 走 c2(大厅),EnterSpace 走 c1(二次进空间)
- 取证:短命连接是「复用首个会话哈希、跳过 Hash Request 直接 EnterSpace」,被服务器 code=1000 关闭(约 1.2 秒);完整握手的连接可稳定存活(2 分半)
- wss_server:上游改为「首帧到达后再建」——StreamDecoder 记录 FirstCmdId,首帧 ID=3 走备用上游、其余走主上游;首帧仍走 Pending 原序补发
- 新增 --upstream-alt / -UpstreamAlt(默认 wss://c1.3dtank.com:9090/)
|
2026-10-15 16:16:16 +08:00 |
|
TermiNexus
|
529868b194
|
feat(wireframe): 3D 透视里给人机坦克标「人机」文字
- hornet_3d_wireframe:坦克绘制后在其上方投影并写「人机」(先描黑边再填黄字,任何背景下可读)
- 复用 lib.ScanBots / IsBot,节流约每 0.3 秒扫描一次;雷达的方块标记保留
|
2026-10-15 15:47:52 +08:00 |
|
TermiNexus
|
2b64211173
|
feat(radar): 人机识别标记(同队装备分数相同且 < 8000)
- hornet_lib:新增 GetGearScore(BattleGearScoreCC.score → 组件 cjf_1)、ScanBots(按队伍分组,同分且低于阈值判为人机)、GetBotSet/IsBot
- hornet_radar:约每 0.3 秒扫一次;人机画「灰方块 + 黄框」,真人仍「实心圆 + 白边」;顶部统计加 Bot 计数
- 重新生成 hornet_bundle.js 并同步到 unpacked
|
2026-10-15 15:27:34 +08:00 |
|
TermiNexus
|
92b5ca6e9b
|
refactor(panel): 移除左上角常驻 HUD(「3DTank 控制台」小窗)
- tools/hornet_panel.js:HUD 不再挂载到页面(等于不显示),原样式与 appendChild 一并去掉
- 保留 hud 对象与 UpdateHud 循环:循环里还负责 TryAutoEnable()(按保存状态自动开启工具)
- 重新生成 hornet_bundle.js 并同步到 unpacked
|
2026-10-15 15:15:28 +08:00 |
|
TermiNexus
|
cca13974de
|
fix(relay): 上游对齐官方 —— config 回源与中继上游改为 c2
- serve.js:新增 --config-upstream(默认 https://c2.3dtank.com),/config.xml 回源与改写底稿都改用它
- wss_server.js / Start-LocalAndRelay.ps1:上游默认 c1 改为 c2,可用 -Upstream / --upstream 切回
- 依据:客户端 JS 无 c1/c2 硬编码(连谁完全由 config 决定);实测 c1/c2 各自提供指向自己的 config,官方客户端实际连 c2
|
2026-10-15 14:09:25 +08:00 |
|
TermiNexus
|
9bce46a86e
|
fix(loader): 断线重连死循环 —— location.reload 拦截改为默认关闭
- 游戏断线时靠 location.reload() 刷页重连;此前为看 err toast 接管了 reload,会把刷页吃掉
- 后果:游戏只能反复内部重连 + 反复拉 config.xml(表现为一直重连 c1 / 反复访问 xml,且只在断线时触发,故呈概率性)
- 现默认关闭;需保留页面看 err toast 时用 localStorage.hornetBlockReload='1' 临时开启
|
2026-10-15 13:47:35 +08:00 |
|
TermiNexus
|
86aa8bd9bd
|
feat(turret): 炮塔精准跟手加死区消抖(滤掉悬浮底盘的 micro-motion)
- module_87072 oxt.wak case 1/2:目标角变化小于死区(默认 0.5 度)时不搬动炮塔
- 死区可实时调:window.__hornetTurretDeadZone__ = 弧度值
|
2026-10-15 13:35:39 +08:00 |
|
TermiNexus
|
d4c5a89703
|
feat(turret): 炮塔摆头精准跟手(默认开启)+ 探针默认关闭
- module_87072 oxt.wak:case 1/2 直接锁到目标角,去掉速度追赶导致的追过头再回摆
- module_87072 weaponMount.qyr:去掉渲染层二次插值(dzi_1=azi_1、izi_1=gzi_1)
- 回退开关:window.__hornetTurretPrecise__ = 'off' / false
- probe_chassis.js:新增 oxt.wak / weaponMount.qyr 采样链路,用于定位过冲
- main.9f4e7a89.js:探针改为默认关闭(localStorage.hornetProbe='1' 开启)
|
2026-10-15 13:34:25 +08:00 |
|
TermiNexus
|
512c718d38
|
feat(hornet): 十字军底盘控制探针 + 中继 config.xml 动态改写
- 新增 sockets/probe_chassis.js:采样 Cyt.j14k_1 / Zmt.r14f_1 三轴并 hook Cyt.wak / Zmt.wak,转储到 names/probe_chassis.log
- serve.js:新增 /probe_chassis.js 路由与 /__probe__?f= 落盘选择;新增 --relay-port 动态改写 config.xml 指向本机中继(不落盘、不依赖 local/config.xml)
- main.9f4e7a89.js:探针块改为自动加载 railgun + chassis 两个探针
- Start-LocalAndRelay.ps1:-WithRelay 改传 --relay-port,修复「前端未走中继」的根因
|
2026-10-13 17:14:22 +08:00 |
|
TermiNexus
|
12e547f32f
|
docs(3DTank): 电磁炮锁定蓄力改造的计划与进度(机制/门槛/改动/待办/教训)
含:z4t 三条上行(amr/o1ag/tnl)、三个时长(w1al/w187/x187)、FSM(TWt/vWt)结构、实测门槛(1.5s 最低满伤)、已落地改动与 commit 列表、离线解码流水线命令、关键行号速查。
同批提交 decode_space_frames.js 的 --side s2c/c2s 选项(MD 里的解码命令依赖它)。
|
2026-10-12 11:20:34 +08:00 |
|
TermiNexus
|
651e29f8b2
|
feat: 探针改整帧 hex 记录 + 新增 probe_log_to_bins.js 接现有解码流水线
- sockets/probe_railgun.js: SEND 记录整帧字节(流密码跨消息连续,截断/丢帧会导致后续解密全错)
- 3DTank/tools/probe_log_to_bins.js: 把日志里的 c2s 帧还原成 <out>/<label>/session_001/c2s_*.bin,供 decrypt_frames.js → dump_plain.js → decode_space_frames.js 复用
|
2026-10-12 11:11:57 +08:00 |
|
TermiNexus
|
d4c8a843e2
|
feat(panel): 电磁炮锁定时长固定默认 1.5s(面板默认开启覆盖)
面板回填逻辑改为「未显式关闭即开启」,默认值 1.5s(实测满伤的最小值);取消勾选仍可回退原版 3~5s。z4t.w187 的 HORNET-TAG 同步。
|
2026-10-12 11:08:01 +08:00 |
|
TermiNexus
|
db8a92a2f7
|
feat(panel): Alt+T 面板新增「电磁炮设置」——锁定/蓄力时长可实时调
启用时长覆盖(checkbox) + 锁定/蓄力(s) 滑块 0.1~5.0/步进0.05,拖动立即写入 window.__hornetLockSec__ 并持久化到 localStorage(hornet_lock_on/hornet_lock_sec)。实测门槛:1.5s/2.0s 满伤,1.0s/0.1s 无伤害。
|
2026-10-12 11:01:36 +08:00 |
|
TermiNexus
|
1af3b3a7a3
|
feat(mirror): 电磁炮锁定时长支持运行时覆盖(window.__hornetLockSec__)
z4t.w187() 优先读 window.__hornetLockSec__(正数则用它),否则回退 gaussParams.njs_1;便于面板实时调值,不必重打包刷新。
|
2026-10-12 11:01:34 +08:00 |
|
TermiNexus
|
2d2a2c9f61
|
chore(mirror): 电磁炮锁定时长试 0.1s(极端对照,用于离线解码对比)
z4t.w187() 返回 LR(0.1);已知 1.5s/2.0s 满伤、1.0s 掉伤。HORNET-TAG 同步 0.1s。
|
2026-10-12 10:57:50 +08:00 |
|
TermiNexus
|
8e13aac99f
|
feat(mirror): 电磁炮锁定时长 2.0s → 1.5s(二分探门槛)
z4t.w187() 返回 LR(1.5);2.0s 已实测满伤、1.0s 掉伤,门槛在 1.0~2.0s 之间。HORNET-TAG 同步为 1.5s。
|
2026-10-12 10:41:49 +08:00 |
|
TermiNexus
|
e154c1ab14
|
fix(sockets): 探针 WS 字节读取兼容 DataView(此前 hex 恒为空)
游戏实际发的是 DataView(有 byteLength、无 slice),走 buffer+byteOffset 取视图;此前 new Uint8Array(dataView,0,24) 得到长度 0 视图,导致 SEND 行 hex 恒空。
|
2026-10-12 10:35:39 +08:00 |
|
TermiNexus
|
712d24e059
|
fix(mirror): 徽标抗 DOM 裁剪 + 探针块加自证日志
- 徽标每 2s 自检补回(游戏初始化重排 DOM 时会被删掉)
- 打印「版本徽标已注入」「探针块已执行(hornetProbe=…)」两条日志,便于区分是加载器没生效还是探针 fetch 404
|
2026-10-12 10:31:34 +08:00 |
|
TermiNexus
|
dfdd69b375
|
feat(mirror): 探针自动加载并转储(/probe_railgun.js 路由 + 加载器引入)
- tools/serve.js: 新增 /probe_railgun.js 路由,读 sockets/probe_railgun.js
- main.9f4e7a89.js: 等 __gameMode__ 就绪后自动 fetch+eval 探针(localStorage.hornetProbe='0' 可关闭),数据走 POST /__probe__ 落盘 3DTank/names/probe_railgun.log,省去每次手粘控制台
|
2026-10-12 10:23:07 +08:00 |
|
TermiNexus
|
09f8769585
|
feat(mirror): 电磁炮锁定时长 3~5s → 2.0s(z4t.w187,实测满伤)
z4t.w187() 返回 LR(2),不再取 gaussParams.njs_1;冷却 w1al()/x187() 未动(服务端按冷却裁决)。附 HORNET-TAG 供版本徽标显示。
|
2026-10-12 10:21:04 +08:00 |
|
TermiNexus
|
bb3d76117a
|
feat(mirror): 右下角版本徽标(包版本 + 从模块源码读出的 HORNET-TAG)
加载器记录 __hornetPackVersion__ 并渲染固定徽标;TAG 用正则从 __modules__[87072] 源码读取,避免手写常量与真实包不一致。
|
2026-10-12 10:21:03 +08:00 |
|
TermiNexus
|
b63435d401
|
fix(sockets): probe_railgun.js WS 上行改异步读 Blob(此前 hex 恒为空)
游戏 send 的是 Blob,slice 后 new Uint8Array(Blob) 长度为 0,导致 SEND 行 hex 全空;改为 blob.arrayBuffer() 异步读前 24 字节。
|
2026-10-12 10:21:02 +08:00 |
|
TermiNexus
|
2b95e5de28
|
chore(3DTank): 新增页面内探针的网络转储通道(/__probe__ + probe_railgun.js)
- tools/serve.js: POST /__probe__ 追加写 3DTank/names/probe_railgun.log
- sockets/probe_railgun.js: 电磁炮/武器链路现场探针(组件清单 + 采样 + WS 上行帧),fetch 批量转储,POST 不通自动回落控制台
|
2026-10-12 10:13:32 +08:00 |
|
TermiNexus
|
0c55021479
|
fix(origin): Origin 修正为 https://3dtank.com 并回退误改的 c2 上游
- 中继/代理 origin 由 https://3dtank.com/play/ 改为 https://3dtank.com(Origin 规范只到源、不带路径);referer 保持完整地址 https://3dtank.com/play/
- 上游与 /config.xml 回源回退到 c1.3dtank.com:9090:战斗必须连 c1,改 c2 会让前端战斗连 c2 而无法使用
- wss_server.js 新增「上游握手头」诊断日志,区分「浏览器→中继」与「中继→上游」两段
- README 同步
|
2026-10-12 00:19:04 +08:00 |
|
TermiNexus
|
dd2c6c4c16
|
change(origin): Origin/Referer 改为 https://3dtank.com/play/(中继上游强制覆盖 + 镜像回源)
- wss_server.js:上游握手头的 origin/referer 不再透传前端值(前端带的是本机 http://localhost:8080),改为强制覆盖为 https://3dtank.com/play/;其余请求头仍整包透传
- serve.js:代理回源(/resources、/config.xml)的 origin/referer 同步改为 https://3dtank.com/play/
|
2026-10-11 22:21:14 +08:00 |
|
TermiNexus
|
ae4d4ee055
|
fix(mirror): ws 抓包开关改为 serve.js --ws-hook(不碰 URL),避免 hash 破坏游戏路由
- 实测:URL 里任何 hash(包括 #hook/#nohook)都会让游戏进不去战场(游戏用 location.hash 做路由/状态),所以弃用 hash 开关
- serve.js --ws-hook:服务 HTML 时注入 /ws_hook.js;Start-LocalAndRelay.ps1 加 -Hook 开关;ws_hook.js 支持 localStorage.hornetWsHook=0 临时关闭
- index.html(本地)移除静态 ws_hook 引入
|
2026-10-11 21:43:12 +08:00 |
|
TermiNexus
|
d6758b14e1
|
fix(mirror): ws 抓包降到最小入侵(只包 send + on* 访问器,热路径只拷贝不编码)
- 不再包装 addEventListener(会破坏 removeEventListener 的按引用移除);游戏只用 onopen/onclose/onmessage
- 逐帧 base64 推迟到 __ws_save__(),去掉战斗入口的收发延迟
|
2026-10-11 21:31:16 +08:00 |
|
TermiNexus
|
240892c9b5
|
fix(mirror): ws 抓包改为原型级 hook(不动 window.WebSocket 构造函数),避免被游戏察觉
- 实测替换构造函数会让 WebSocket.toString() 不再是 native code → 进不去战场;改为只包 WebSocket.prototype 的 send / addEventListener / onmessage|onopen|onclose 访问器
- window.WebSocket 的名字/长度/toString/instanceof/静态常量全部保持原生
|
2026-10-11 20:54:38 +08:00 |
|
TermiNexus
|
c021d5c164
|
fix(mirror): ws 抓包 ToBase64 分块降到 8192,远离 apply 实参上限
- String.fromCharCode.apply 会把参数数组整包展开成实参,块过大必爆栈(V8 上限约 6.5 万);原 32768 虽安全但偏高,降到 8192
|
2026-10-11 20:49:41 +08:00 |
|
TermiNexus
|
245e27e192
|
chore(mirror): ws 抓包未启用时也定义 __ws_save__,调用时提示加 #hook
|
2026-10-11 20:43:14 +08:00 |
|
TermiNexus
|
f3cd1aae67
|
feat(mirror): 恢复 /ws_hook.js(页面内旁听抓包,无需 SW,URL 加 #hook 才启用)
- 抓包不再依赖 Service Worker:浏览器仍直连服务器,不改传输、不改模块加载,服务端看不出差别
- index.html(本地,未入库)重新引入 ws_hook;SW 保持移除状态
|
2026-10-11 20:32:31 +08:00 |
|
TermiNexus
|
6d229abfb2
|
change(mirror): 撤掉 /ws_hook.js 路由与 index.html 引入,恢复默认无 hook
- serve.js 删除 /ws_hook.js 路由,该路径回落 404(sockets/ws_hook.js 文件保留在仓库,需要时再加回路由)
- index.html(本地,未入库)去掉 ws_hook 的 script 引入
|
2026-10-11 20:17:38 +08:00 |
|
TermiNexus
|
d33e7b0eba
|
change(mirror): 从模板中移除 Service Worker 注册(排查断联用)
- tools/split.js 模板与已部署 main 同步删除 SW 注册块;hornet_sw.js 本体与 serve.js 的 /hornet_sw.js 路由保留
- index.html(本地,未入库)加一次性注销,清掉已装的 SW(需再刷一次生效)
|
2026-10-11 20:16:07 +08:00 |
|
TermiNexus
|
ba56ab9d7c
|
change(mirror): 页面内 ws 抓包改为默认关闭(URL 加 #hook 才启用)
- 之前默认一直挂 window.WebSocket;为避免干扰排查(先排除 SW/hook 因素),改为显式 #hook 才抓;#nohook 仍可强制关
|
2026-10-11 20:14:40 +08:00 |
|
TermiNexus
|
562835c284
|
fix(mirror): Service Worker 默认关闭(URL 加 #sw 才启用),排查 SW 是否导致断联
- main 加载器与 split.js 模板同步:默认注销已注册的 SW(单包缓存接管),#sw 显式启用,#nosw 仍可强制关闭
- 注意:注销在下次导航生效,需刷新两次
|
2026-10-11 20:11:02 +08:00 |
|
TermiNexus
|
418298e2ec
|
feat(mirror): 页面内 window.WebSocket 抓包(/ws_hook.js),用于与中继转存逐帧对比
- sockets/ws_hook.js:hook window.WebSocket,按收发顺序记录 {d,t,n,b(base64)};__ws_save__() 存到 3DTank/names/,离开页面自动 sendBeacon;#nohook 关闭
- serve.js:根路径提供 /ws_hook.js(no-cache)
- web/index.html:在主脚本之前引入,确保先于游戏创建 WebSocket
|
2026-10-11 20:04:23 +08:00 |
|
TermiNexus
|
bd35ca1c12
|
chore(relay): 会话起始打印浏览器握手头(cookie/protocol/extensions/referer)用于诊断
|
2026-10-11 19:59:52 +08:00 |
|
TermiNexus
|
8c7f87b58f
|
fix(relay): 上游握手整包透传客户端请求头并镜像子协议,对齐浏览器直连
- 除 Host/Connection/Upgrade/Sec-WebSocket-* 外,客户端握手头全部原样带上(Cookie / Origin / User-Agent / Referer / Accept-Language / Sec-Fetch-* 等)
- Sec-WebSocket-Protocol 改走 ws 的 protocols 选项,由 ws 负责协商校验
|
2026-10-11 19:54:22 +08:00 |
|
TermiNexus
|
5dd5560090
|
fix(relay): 透传客户端真实握手头(Origin/UA/Referer),消除与浏览器直连的唯一差异;镜像加 #nosw 旁路
- 上游改按 Req.headers 的 origin/user-agent/referer 透传(缺省才回退常量),避免上游按 Origin 返回与本地构建不匹配的响应(客户端握手失败自行 close=1005)
- main 加载器与 split.js 模板同步:hash 含 #nosw 时注销已注册的 Service Worker,便于排查镜像页接管问题
|
2026-10-11 19:47:19 +08:00 |
|
TermiNexus
|
ad2b069659
|
fix(relay): 转发回退到速度优化前的可用实现(原样直发 + 竞态帧暂存补发),仅保留异步有序落盘
- 移除会话级 socket 反压暂停/看门狗/重连重试:该改动会让握手帧在内核缓冲里卡住,表现为前端反复新建 wss、进不去战场
- 恢复:客户端帧原样直发;上游未就绪时暂存 Pending,open 后按原序补发;上游关闭即关客户端
- 保留:落盘走单条有序异步写队列(默认开启),崩溃可见性兜底
|
2026-10-11 19:39:50 +08:00 |
|
TermiNexus
|
4005213226
|
feat(tools): 新版本工具链移植 + 本地镜像单包加载,中继改为原样直发与异步有序落盘
- hornet 工具链:无 ght 启动;透视冻结节点拖拽跟随、金箱标记、性能优化;雷达死亡红叉;鼠标稳定器;窗口布局持久化
- 本地镜像:切割与单包加载(pack_unpacked.js)+ SW 单包缓存 + F5 兜底刷新;入口更新为 main.9f4e7a89.js
- 中继 wss_server.js:转发改 socket 反压的原样直发(零等待零缓存);落盘改单条有序异步队列(默认开启);新增反压看门狗(默认 60s)
|
2026-10-11 19:35:54 +08:00 |
|
TermiNexus
|
2224ddc3f6
|
feat: M14 搬运官方车库 UI(官方应用壳 + DOM 运行时等价实现 + 车库主屏)
按用户要求改为「搬运式复刻」:版式与样式全部取自官方反编译代码 module_82347.js,逐条标注 file:line,不自行排版。壳:client/src/jsMain/resources/index.html 复刻 3DTank/web/index.html(6 个 @font-face = Rubik-*.woff / MPLUS1p-*.ttf、#preloader、#root.wrapper、#app-root、#modal-root、.bgClipText),有意差异(https 重定向脚本/analytics/isRussia 检测/manifest/favicon/官方 main.6469b966.js)已在报告标注,改为加载 TankIcClient.js。运行时 Ui/Official/UiDom.kt:等价实现 FD(parent,tag,styleFn)/iq(styleObj)->类名(注入 style[data-emotion])/WD/ip2/lp1/fp2 与单位值函数(E$=%, G$=px, O$=em, zj=rgba, rnr=em/16, cnr=rem/16, Ms 的 0 去单位),并注入官方 Emotion Global 表(module_82347.js:105411-105424 的 btr:html/body/.wrapper/portrait 媒体查询)——.wrapper 的 position:absolute;height:100% 不在 index.html 里,是车库 height:100% 成立的前提。车库主屏 Ui/Official/OfficialGarage.kt:按官方实例化路径(module_82347.js:161904-162084 的 gPn -> :166813-166828 的 hGn -> _Ln/PWn/PGn/_Wn)搬节点层级与样式函数,含 GarageCommonStyle/GarageMainScreenStyle/MountedItemsStyle 的片段;设备块按官方 PGn.tan 的 case 13 语义合并为一类一块(6 块而非 33 块)。两处纠正我任务书里的错误假设(均有证据):w$ 不是单位换算而是 Kotlin 的 Any?.toString()(w$ = Co.$_$.je -> module_37036.js:1165 Br()),单位由调用点拼字符串;fq/jq/Y$ 不是样式注册表而是 Kotlin/JS 的类/对象/伴生对象元数据注册(module_37036.js:1249/1257/1266)。浏览器实测(经由 AssetRelay 8130):官方壳与车库主屏渲染、#preloader 已移除、13 条 emotion 类规则注入、字体 BaseFontRegular/Medium 与 Fallback 全 loaded、33/33 图片加载成功、真实中文名(火焰炮/炸弹/橄榄绿/神谕者/十字军/防护×28)、布局尺寸非零(host 1311x986、positionContent 1311x826@0,64、blockParameters 1119x591@96,64、mounted 368x2186)。逐步修掉两个真问题:#app-root 缺官方 PresetContainer(position:absolute;height:100%)导致下游 height:100% 退化成 auto 而塌成 0 高;以及设备块数按官方 case 13 语义合并。回归:CompareContainerDecode 5 帧/26950/0、selftest 1108/9/90、semantic --demo 全部断言通过、compileKotlinJs/jsBrowserProductionWebpack/jsBrowserDistribution 成功。未完成(待搬,附官方出处):_Ln 3D 预览、PWn TankParametersStyle 全部片段、_Wn SuppliesComponentStyle、vGn 块内 improvementArrow/commonBlockForTurretsHulls/resistanceContainer/iconNotificator/SkinsIcon;未实现:sp1 状态选择器、Global 表的 li/a(部分)/input::placeholder;物品单件图标因数据里缺 TankInfoCC(5543162332469864498) 而退化为 defaultDevice.svg(数据缺失,非算法问题)。
|
2026-09-18 17:01:35 +08:00 |
|
TermiNexus
|
6c36c5e98d
|
feat: M13a 导出官方「型号枚举→图标」表 + 素材中继 + 物品名称/类别中文可展示
A 图标表:从 module_36659.js:5135 的 eA.upf(底盘)与 module_57128.js:840 的 Dn.duk(炮塔)解出 case→形参→实参→i(模块id)→resources.json 的映射(严格走 case→形参名→形参声明行→实参行,不假设 case 号等于实参位置,因为该模块实参表约 1000 项而工厂形参只有 714 个、多出的被丢弃)。自验:用同文件 :907 的 Dn.euk 抗性表 21 case 全命中且本地镜像均存在(去重 20 个文件)。规模:底盘 416 case(未解 1)、炮塔 20、抗性 21、7 格道具 7。B 物品信息:名称来自服务端模型 3935107155251354407(DescriptionModelCC)的 name 字段,类别中文用 lobby.garage.<枚举名>(ARMOR=底盘/WEAPON=炮塔/PAINT=迷彩/DRONE=辅助无人机…),15 件仓库物品名称 9/9、类别中文 9/9 命中;但图标 0/9 —— 承载底盘/炮塔型号的 TankInfoCC(5543162332469864498)在全部 68 个 s2c 帧与模板里 0 次出现,属数据缺失而非算法问题,已如实标注。C 素材中继 client/tools/AssetRelay.mjs(8130):/ 服务客户端产物、/play/static/** 映射 3DTank/web/play/static 本地镜像、正确 MIME 与宽 CORS、防目录穿越(%2e%2e 返回 400)。回归:CompareContainerDecode 5 帧/26950/0、selftest 1108/9/90、semantic --demo 全部断言通过、Kotlin/JS 构建 SUCCESSFUL。
|
2026-09-18 15:56:00 +08:00 |
|
TermiNexus
|
17083ceff4
|
feat: M12 车库会话推满 39 帧 + 客户端可进其它空间解码(含 3 种未解上行语义)
A 会话推满:新增驱动策略 PumpDerive(每拍从 ClientState 推上行)——ls.xbl←pt 负数对象 id、ba.lcr←pt 挂载位标记、M_.hcn←devicesLoaded 记录头、Qh.ycw←mountedItems、G.q1wd←AutoResponder 对每条 zt 回 X;队列空而会话未满就 RefillPump 再补一轮;收尾判据=进空间满 12s 且连续 7s 无新下行。结果:39/39 帧全部收到并与服务端 session_002/log.txt 逐条对照 39/39 命中,重放卡住 0,全部 Bad=false(含 28 条 ka 查库应答帧)。诚实口径:触发上行的类型与靶 100% 由已收到下行推出,但「下一步该发哪条」不可从语义推出(回放器只认会话顺序里最靠前的待触发帧),必须靠派生行流轮询补发——已在报告与代码里标注。未解上行语义(file:line 证据):M_.hcn 4795202316771985007 = RequestItem3DPart(靶=空间 id,负载=对象 id,module_85196.js:6760 组帧 / module_18334.js:5767 触发);Qh.ycw 4428603232159847900 = GameObject 级选中/请求(靶=对象 id,空负载,module_85196.js:7290,对应 action sU module_10032.js:6064 无 toString 故人类名未确认);ha.gcq 8060894096836849355 = GarageUpgradeItem(靶=空间 id,负载 itemId+i32 1+期望价+货币 enum,module_85196.js:6879 / module_10032.js:30492 的 GarageUpgradeItemAction)。B 其它空间:新增 SpaceDumpDriver(TANKIC_SPACES=... 控制,默认不影响既有自检),实测 5 个空间全部进得去解得开、Bad 全 false:Entrance 3帧/3记录、Chat 1帧/2记录、Shop 3帧/11记录(zt 150批1731项 + pt 764对象)、Unknown 2帧/11记录、Queue 3帧/5记录。回归:CompareContainerDecode 26950/0、selftest 1108/9/90、semantic.js --demo 全部断言通过、三构建 exit 0。
|
2026-09-18 14:42:31 +08:00 |
|
TermiNexus
|
3065d23413
|
feat: M10 挂载位设备可装备(dh.hcu → Mounted.DeviceId → 重启后回显)
上行口径(源码链推出,抓包无样本):dh.hcu = 3804107380183105968,靶 = 挂载位对象 id,负载 = 设备对象 id(i64);证据见 Uplink.kt 的 DH_HCU 头注(module_85196.js:7134-7173 的 dh.hcu、module_10032.js:7692 的 TF 动作、module_18334.js:5926-5927 的 dispatch)。客户端:Uplink.BuildDeviceInsert + ClientState.MarkDeviceMounted(本地乐观)+ GarageSession.EquipDevice;Main.kt 挂载位面板每个可用设备一个「装备 <设备id>」按钮(已装备者置灰);GarageDriver 支持 TANKIC_DEVICE_EQUIP=<槽位id>:<设备id> 自检与 PrintDeviceMountDump。服务端见 2299b09。验收(9092 干净重启):帧 255848→255856B(+8B = i64 正好)、客户端解码 29 条记录 Bad=false;服务端日志「回显覆盖:devicesLoaded 的 mountedDevice 由模板…改为库中…」;MySQL SELECT 槽位 920009631046 DeviceId=920005132727;客户端 dump「槽位 920009631046 设备 23 个 当前装备:920005132727」。换装备:改为 920005770334 后库里只剩后者;重复同值 → 服务端「值未变,幂等跳过」。UI:浏览器点「装备」后该槽位行显示新设备。回归:CompareContainerDecode 5 帧/一致叶子 26950/不一致 0;selftest 逐字节一致 1108/不一致 9/解码中断 90;semantic.js --demo 全部断言通过;三构建全绿。
|
2026-09-18 14:19:04 +08:00 |
|
TermiNexus
|
2299b0996b
|
fix(server): 组帧漏写帧级 nullmap 位,opt 字段改值会产出错位帧(M10 回显的真因)
space.js 的 BuildInitFrames 自己逐条调 Container.Write / Semantic.EncodeRecord 出负载,再把模板的 NullmapHex 原样带上。但帧级 nullmap 是所有记录共用的一串位(每条记录 1 个形态位 + 每个 opt 字段 1 个空/非空位,按编码顺序排),只有 semantic.EncodeFrameBody 持位游标(容器与字段两条路径都会推进 Ctx)。于是「把 opt<T> 由空改成有值」时负载多出 T 的字节数而 nullmap 位仍是 1(=空),解码侧按位读到空、把那多出来的字节当成下一条记录头 —— 实测 devicesLoaded 的 mountedDevice 由 null 改成设备 id 时帧 255848B→255856B 且 Bad(29 条记录只解出 7 条)。M7 覆盖 mountedItems 时没暴露,是因为 list<T> 改长度不占 nullmap 位(长度编在负载里)。改法:BuildInitFrames 把记录按模板形态原样交给 Semantic.EncodeFrameBody(容器 → Layout+Value、字段 → Fields、解不动 → Hex、旧模板的现成 Payload 仍透传),由它按编码顺序重建 nullmap 位;没传 semantic 实例时保留旧路径。验证:字节中性 —— names/ 下全部模板(init+session,61 帧)改动前后逐字节相同 61/61;修复有效 —— 把 s2c_0004 槽位 920009631046 的 mountedDevice 由 null 改为设备 id 后,帧 +8B、解码 29 条记录 Bad=false、nullmap 长度不变且恰好 1 个字节变化、其余 27 个槽位 0 处变化;回归 —— semantic.js --demo 全部断言通过(含「space.js 组帧 == 参考字节」那条)、selftest 逐字节一致 1108/不一致 9/解码中断 90、CompareContainerDecode 5 帧/26950/0。
|
2026-09-18 13:38:28 +08:00 |
|
TermiNexus
|
356647937e
|
feat: M9 枚举线形序数 enum#N 解析成成员名(category 显示 ARMOR/WEAPON/PAINT…)
数据:evidence.json 的 byModule.<模块>.enums = { 枚举短名: [{field, member, value}] },全局 348 类 / 2633 成员。查表键定为 (字段所属模块, 枚举短名, 序数):同模块内短名天然唯一;跨模块同名 11 个短名 / 9 个同名异义,键含模块号即可隔离。全表 102 条 enum<X> 引用的定义模块均由字段的 TypeCodec 唯一确定(无冲突、未解 0),导出后落盘 77 类 / 1343 成员(33879 字符,整表增量 33894)。两层分离(本任务核心约束):协议层原始值仍是 enum#N,一字不改,因此 CompareContainerDecode.mjs 的逐字段对照口径不变;EnumNames 只在 UI/日志/dump 里翻译,查不到返回 null 并由调用方标「未解」,不猜。category 实测(15 件仓库物品全部解出):ARMOR#1 / WEAPON#0 / PAINT#2 / BAZOOKA#13 / DRONE#8 / INVENTORY#3 / INVISIBLE#9,真实 5 件挂载物品类别互不相同 —— M8 结论不变。UI 与日志显示「成员名(enum#N)」。顺带修正 GarageDriver 接线:上一轮把 URL 硬编码成 9092 且日志 label 写死 store-02,改为环境变量 TANKIC_WS_URL(默认 9091)与 TANKIC_LOG_LABEL(默认 store-03),否则「配对表 ⇔ 服务端日志」会找错目录。验收:CompareContainerDecode 5 帧 / 一致叶子 26950 / 不一致 0(硬门槛);server selftest 逐字节一致 1108 / 不一致 9 / 解码中断 90;三构建全绿;浏览器实测 15/15 类别显示成员名。未解:枚举成员名未覆盖 list<enum<X>>/opt<enum<X>> 的元素级。
|
2026-09-18 12:59:45 +08:00 |
|
TermiNexus
|
4277e0ae08
|
feat: M8 查明物品类别来源并实现同类互斥(切武器时旧件自动卸下)
类别来源(完整链):挂载 reducer IB.yr9 用物品的 qr3_1 查类别表;qr3_1 = oB 构造第 4 参 = n.yr6_1.ici_1;yr6_1 来自 pt 里 model 类 Ij 那一项 = modelId 6117306895090150422(module_85196::Lo,字段名就叫 category)。交叉验证:真实 5 件 mountedItems 的类别 {enum#1,enum#0,enum#13,enum#2,enum#8} 互不相同 → 规则成立;并确认 M7 留下的第 6 件 920009631018 与 920009631039 同为 enum#1(都是底盘),正是 M7 缺口的体现。排查并排除:不是本地静态表;GarageSelectItem 的 Yy/Xy/ek/Wy 是另一套枚举(模型 ox/2114179554921095892 的 pr3_1),与挂载互斥无关。实现:schema 加 Items.Category + 索引;新增可重跑的 backfill_category.js(从 ObjectModels 回填,支持 --dry),992 件全部回填;store.SetMounted 改为「先卸同类、再置新件」且幂等,日志打印「同时卸下 N 件同类」;客户端 ClientState.MarkMounted 同步互斥(与 IB.yr9 同顺序),UI 每行显示类别。验收:连装两件 enum#1 → 库中只剩后者(日志「同时卸下 1 件同类」);浏览器 a11y 快照前后对比正确;回归 selftest 1108/9/90、CompareContainerDecode 5 帧 0 不一致、三构建全绿。未解:enum#N 只是线形序数,枚举成员名未解出,库里一律存原始令牌 enum#N。
|
2026-09-18 12:26:01 +08:00 |
|
TermiNexus
|
ab1a905d28
|
feat: M7 点装备即落库,重启服务端后仍回显(闭合「能切换但没持久化」)
客户端:Uplink 加 M_.fcn 构造(6 条抓包样本逐字节相同)、仓库每行加「装备」按钮、Equip() 入队 + 本地乐观标记(对齐真实客户端的 jU reducer)。服务端:store.js 加 LoadMountedFlags/SetMounted(UPDATE ... WHERE Mounted<>1,幂等)/OverrideMountedRecord;session.js 加可选 RecordOverride 钩子;index.js 进车库时刷新快照、收 M_.fcn 落库。回显只在库与模板有差异时覆盖并打日志(装备前帧仍与抓包逐字节一致 775441B;装备后 775449B,+8B = 多一个 i64)。验收:浏览器点装备 → 服务端落盘 c2s_0064.bin 与抓包 c2s_0141.bin 逐字节相同;MySQL Items.Mounted=1 共 6 行;重启 9092 后启动日志显示 Items.Mounted=1 共 6 件、重进车库 UI 6 个装备按钮置灰与库一致。回归:selftest 1108/9/90、CompareContainerDecode 5 帧 0 不一致、三构建全绿。未实现并如实记录:类别互斥(物品类别来源未解出,不硬猜)、挂载位设备 mountedDevice 未处理。
|
2026-09-18 12:01:30 +08:00 |
|
TermiNexus
|
8964ea28cd
|
feat(client): M6 车库最小界面(浏览器只读),实测显示 15/28/515/992
browser 分支改为单页界面:连接区(URL 可改)→ 仓库物品(15 件,标注已挂载/未挂载) / 挂载位(28 槽位 + 515 设备,当前装备全 null) / 市场(992 件,只渲染前 20) / 日志区(最近 50 条,人类可读名)。状态更新用「状态容器 + 手动重渲染根节点」(未用 hooks)——全页只有一份全局会话状态。新增 GarageSession.kt(浏览器侧驱动,复用 AutoResponder 与 ClientState 的靶推导);M5 GarageDriver 的 node-only 逻辑(读抓包/日志/NodeRequire)没有拖进浏览器路径。验收:三构建成功(注意 dev 与 prod 系列要分开跑,否则 Gradle 报隐式依赖);浏览器实测已进空间 100073070、面板显示 15/28/515/992、日志含 G.q1wd/LoadObjectsData/ls.xbl/ba.lcr/devicesLoaded;服务端 session_069 佐证浏览器的上行被逐条收到;浏览器 Origin(http://127.0.0.1:8123) 被接受——服务端只记录不校验 Origin(index.js:484-489),当前无需改动。
|
2026-09-18 11:50:19 +08:00 |
|
TermiNexus
|
c0360810b7
|
feat(client): 协议层 M5 —— 车库因果闭环成立,ClientState 语义状态可 dump
闭环证据(自检 session_063,与服务端日志逐条对照):客户端 48 条上行换来服务端 5 条重放帧(s2c_0000..0004,按整帧字节数逐一匹配)+ 28 条 ba.lcr 的查库定向应答(与服务端 28 行「查库应答」吻合)。靶 id 从客户端语义状态推导、不是照抄抓包:G.q1wd 靶=空间 id;ls.xbl 靶=pt 里 ObjectId 为负的对象(与抓包 5/5 命中);ba.lcr 靶=pt 里带语义标记 modelId 2494628067134376039(自指 + modificationCount=7)与 7391892068905080676(devicesAvailable=true)的对象(与抓包 28/28 命中),且从 s2c_0001 推导出的 28 个挂载位与后到的 s2c_0004 里 28 条 devicesLoaded 记录头 ObjectId 28/28 一致(独立预测成功)。ClientState:itemsOnDepot 15 / itemsOnMarket 992 / mountedItems 5 / 挂载位 28 / 设备 515 / mountedDevice 全 null,全部与期望一致。修复自身缺陷:原先用「最新一帧 pt」推导 URL 会被 s2c_0004 的无标记版本覆盖导致靶集从 28 掉到 0,改为按帧各存对象→模型快照并扫描所有 pt 帧。无跳帧(仅 3 行正常的「重放等待」);三构建全绿;浏览器目标不回归。
|
2026-09-18 11:37:32 +08:00 |
|
TermiNexus
|
78ce1bacea
|
feat(client): 协议层 M4 —— 上行帧构造与自动应答,形成问答闭环
新增 Uplink.kt:c2s 空间帧构造 [nullmap][靶 objectId i64][methodId i64][负载];ba.lcr(19B)/ls.xbl(19B)/G.q1wd(23B) 的构造结果与抓包逐字节相同(4 条帧全字节比对通过)。新增 AutoResponder.kt:收 LoadDependencies(zt) 自动回 G.q1wd(X),X 原样回传;防重放用「(X, 来源帧序号) 只回一次」而非「X 只回一次」——X 是回调号会被复用(3DTank/tools/server/schema.sql 头注 8),按 X 去重会吞掉合法应答;另加单连接 64 次上限兜底。Connection 加 SendBaLcr/SendLsXbl/SendGQ1wd 手动触发与 LastObjectsDataObjectIds()。口径修正:G.q1wd 的靶是「客户端进入的空间 id」,不是 s2c 记录头上的 objectId(证据:s2c_0000 记录 objectId=390801,而同会话 c2s_0001 靶=100045260)。端到端(服务端 session_055 佐证):客户端自动发出的 c2s_0002.bin 23B 与服务端落盘逐字节一致;注:100045260 的 _loadObjectsData 是模板第 2 帧(进空间即排期 +455ms),不是本次 G.q1wd 因果换来的,且查库定向应答默认 Scope.GQ1wd=false,服务端记为 Disabled/G.q1wd=1,故因果闭环需在有会话回放的 100073070 验证。
|
2026-09-18 11:13:33 +08:00 |
|
TermiNexus
|
2a0296d0bb
|
feat(client): 协议层 M3 —— 压缩帧解压两端统一走 fflate.unzlibSync
真实抓包里的关键帧是 zlib 压缩的(space-100045260/s2c_0000.bin 整帧 915B → 解压后帧体 1799B;space-100073070/s2c_0004.bin 整帧 41590B → 解压后 255844B),M2 只在 Node 侧用 zlib 解、浏览器目标直接抛错。改为两端同一份纯 JS 实现 fflate 0.8.3,DecodeFrame 保持同步签名。关键修正:fflate 的 inflateSync 是「无包装 DEFLATE」,喂 zlib 流会报 unexpected EOF,zlib 包装要用 unzlibSync —— 官方客户端也正是用它(3DTank/src/module_24635.js:20 g = n.unzlibSync,来自 module_29518.js:1172),与我们同路。验收:Node 侧两个压缩帧的解压结果与 link.js 的 zlib.inflateSync SHA256 完全相同,且解压后完整解出记录(1 条 zt / 1 条 pt + 28 条 fields),M2 对照脚本仍 5 帧、一致叶子 26950 / 不一致 0;浏览器侧页面加载即自动跑自检、console 全项通过(已实际用浏览器打开确认);三个构建任务全绿;production 产物 524579 → 564689 字节(+40110,fflate 的 CJS 入口无法 tree-shake,后续可换 ESM 瘦身)。
|
2026-09-18 10:31:37 +08:00 |
|
TermiNexus
|
830d6408b8
|
feat(client): 协议层 M2 —— 容器三布局 lt/pt/zt 落定,多记录帧不再丢记录
客户端实现三种容器布局的读,与 JS 实现(3DTank/tools/server/container.js)逐字段对照:5/5 帧、一致叶子 26950 / 不一致 0,两份规范 JSON SHA256 完全相同(各 795139 B)。覆盖 space-100073070/s2c_0004.bin 的 pt(7210 项,含 515 个 Id=0 字面量与 6695 个模型展开) 与其后 28 条 fields 记录——M1 会把这 28 条全丢掉。协议表由 codec_fields.json 的 1143497 B 裁到 ProtocolTables.json 的 124270 B(削 89.1%),做法:只留解码必需属性 + 闭包裁剪(根=所有带 ModelId 的 codec ∪ 命令/容器方法,沿 TypeCodec 与模型真名取闭包,保留 559/643 个 codec),闭包外如实报「无 codec」。计划外但必需:space-100045260 的 s2c_0000/s2c_0004 是 zlib 压缩帧,M1 直接抛错,现用 Node zlib 解压(browser 侧仍显式抛错);并新增正式产物 client/tools/CompareContainerDecode.mjs。
|
2026-09-18 10:11:10 +08:00 |
|
TermiNexus
|
2deb628bf6
|
feat(client): 协议层 M1 —— 入口层握手 + 空间帧记录级解码 + Node 自检
在 client/ 里实现 3DTank 协议层(Kotlin/JS),并给同一工程加 nodejs() 目标做无头自检。自检跑通:Hash Request(571B) → Hash Response(启用链路加密=0)→ Auth/EnterSpace(100045260) → Open Space → 3 条初始化帧(LoadDependencies/zt、LoadObjectsData/pt、gn)→ 保活 ping。字节级核对:Hash Request 与真实抓包 server-logs/store-02/session_040/c2s_0000.bin 逐字节相同;EnterSpace 与 packets/plain/space-100045260/c2s_0000.bin 逐字节相同。M1 明确不做:容器三布局定界、短命令形态、压缩帧解压(遇到即报错,不静默)。协议表由 client/tools/ExportProtocolTables.mjs 从 3DTank/names/ 生成(下行 31 / 上行 7);本机拉不到 Kotlin 插件自带的 yarn,改用系统 npm,故 kotlin-js-store 由 yarn.lock 换成 package-lock.json。
|
2026-09-18 09:51:00 +08:00 |
|
TermiNexus
|
61b57a3d11
|
docs(3dtank): 架构逆向:模块依赖图、6 条运行链路、TOState↔reducer 映射
names/module-graph.json:126 模块的 Kind/职责/依赖/导出/锚点,533 条依赖边,入口 13431(出度 46,依赖链深 17 层)。docs/ArchitectureModules.md:依赖图摘要 + 40 个游戏模块逐条 + 依赖分层(由数据生成)。docs/ArchitectureRuntime.md:启动引导/网络层/Redux/UI 系统/资源与渲染/空间与对象模型 6 条链路,64 条关键函数([证据] 77 / [推断] 15)。names/tostate-map.json + docs/StateMap.md:TOState 实为 89 字段(非估计的 60),89/89 由「toString 字段→槽位」与「根 reducer v8 的实参顺序→ntb 形参→w8 字段顺序」两条独立链路交叉验证,唯一未映射的是只读的 launchParams。
|
2026-09-18 09:30:30 +08:00 |
|
TermiNexus
|
4eff6bb315
|
chore(3dtank): 模块职责表规范化并修正两处误标
dir.file 改写为规范表格(126 模块 + 2 个资源文件),补「分类」「需反混淆」两列;分类计数与 module-graph.json 的 Stats.ByKind 逐项对齐(游戏本体 40 / Kotlin生态库 21 / 第三方库 65)。修正两处被标反的职责:module_96480 实为 inline-style-prefixer 的 transition 前缀插件(原标 Underscore.js 1.13.6);module_94965 实为 Underscore.js 1.13.6(原标 ReactHTML 标签构建器),分类随之由 Kotlin生态库 改为 第三方库。
|
2026-09-18 09:30:29 +08:00 |
|
TermiNexus
|
5644692c97
|
feat(client): Kotlin/JS + React 客户端脚手架(对齐游戏技术栈)
游戏本体是 Kotlin/JS + kotlin-react + kotlinx.serialization + coroutines,逆向客户端要用同一套栈重写,所以脚手架与它对齐:Kotlin 2.1.21 / kotlin-wrappers 2025.5.11-19.1.0(React 19.1.0)/ kotlinx-serialization-json 1.8.1 / kotlinx-coroutines-core 1.10.2 / kotlinx-html-js 0.12.0;Gradle 8.10.2 走腾讯镜像(services.gradle.org 与 raw.githubusercontent.com 本机不可达)。构建已验证:BUILD SUCCESSFUL,产物 build/dist/js/productionExecutable/TankIcClient.js(261KB)。注:kotlin-wrappers 自 2025 年起只发 React 19.x 的 wrapper,故 React 锁 19.1.0,与游戏的 18.3.1 不同。
|
2026-09-18 09:30:22 +08:00 |
|
TermiNexus
|
812d3702a5
|
chore(3dtank): 清理工作区可重建产物,360MB -> 199MB
删除的都是能重新生成的:cache/(124MB,serve.js 代理缓存)、src_named/(18MB,apply_names.js 重建)、旧 server-logs(19MB,保留当前在用的 store-02)、tools/symbol_map.json(8.9MB,map_symbols.js 重建)、names 下的报告产物(flow.json / commands.json / commands_decrypted.json / decoded_frames.txt,各自工具可重跑)、运行产物 missing.txt / sendlog.json,以及根目录杂项 1 / curlcmd / i.html。
保留:packets/(真实抓包证据,不可再生)、src/(权威解包)、web/(跑本地客户端要用)、names/ 协议表(工具输入,注意 model_table.json 是 probe_containers.js 的输入,没删)。
|
2026-09-17 20:05:12 +08:00 |
|
TermiNexus
|
b6f2cb71ee
|
feat(3dtank): 协议逆向工程与自研服务器入库(工具链 + 协议表 + 空间回放 + MySQL)
工具链(3DTank/tools/):extract(模块提取)、mine_evidence/apply_names(命名证据与别名回填)、extract_codec_fields(字段表 + 全库槽位类型 + PrimClassWire/ResourceClasses)、mine_downlink(下行字段表)、extract_space_init/rebase_space_init/audit_space_init(空间模板与记录切分审计)、extract_space_session(把真实会话切成按上行触发的回放模板)、pair_flow(请求→应答配对)、probe_containers、ingest/decrypt_frames(抓包入库与解密)、serve/fetch_assets(本地站点镜像)、import_db(抓包对象仓库导入 MySQL)。
服务器(3DTank/tools/server/):link/entry/codec/container/dispatch/world/space/semantic(协议层与 lt/pt/zt 三个容器布局)、session(会话回放,顺序推进)、db + schema.sql(MySQL 连接层与对象仓库表结构)、store/responder(查库组帧与定向应答;接管范围默认只开 ba.lcr)。
同时修 pair_flow 的时间轴偏移:timeline_c2s 与 timeline_s2c 的 0 点相差 144~4453ms,改前配对整体偏约 2 秒(实测 space-100073070 偏 2084ms),改后 22.4% 的触发者被纠正。
src/、src_named/、packets/、3DTank/local/(含数据库口令)不进库,可用上述工具重新生成。
|
2026-09-17 20:00:41 +08:00 |
|
TermiNexus
|
90c377ad79
|
feat(3dtank): 本地镜像与 hornet 工具链迁到新版 bundle main.6469b966.js
旧 main.b7114b43.js 已被新构建替换(10,011,039 字节 / 1335 模块),本地镜像整体重切到新版并清掉旧产物;hornet 工具链按 tools/map_symbols.js 生成的新旧符号映射改名后重新打包(3dtank_bundle.js 与 unpacked/hornet_bundle.js 同步)。tools/symbol_map.json(8.9MB 映射产物)与切割解包目录不进库,可用 map_symbols.js / split.js 重新生成。
|
2026-09-17 19:59:40 +08:00 |
|
TermiNexus
|
fd32881c3d
|
chore(3dtank): 补 .gitignore,隔离依赖/凭据/抓包/反编译产物
无 .gitignore 时 3DTank/local/db.json(含 MySQL 明文口令)、node_modules、web/(70MB 资源)、packets/、src/ 都会被 git add 扫进来。
|
2026-09-17 19:59:19 +08:00 |
|
TermiNexus
|
de3dbbc097
|
fix(3dtank): dump_plain 静默丢帧:明文尾部被巧合密钥当成加密段
- Solve 只按第一个可用 Start 提前返回,实测 mine-01/session_001 的 59 条 c2s 全是明文整帧,
却被巧合的 K=31 判成「加密段只切出 1 帧」,只 dump 出 13 条(还多出一个解不开的假帧)
- 加两条护栏:① 剩余消息自身都是完整帧时不再尝试解密;② 多个候选取 Start 最大的那个
- 加覆盖度自检:解出的帧没覆盖到每条 WS 消息就在 summary 里显式报 ⚠
重跑 mine-01 入库:回放库 7 个目录 → 18 个,帧数 13621 全量为整帧、
33 个压缩帧全部解压成功(原先 session_001 的假帧已消失)
|
2026-09-16 17:35:55 +08:00 |
|
TermiNexus
|
8d2aa5566d
|
feat(3dtank): 解出容器「模式表」头部并约束内层扫描
- ContainerSchema:容器负载头部 = [i32 a][i32 b][i64 objId][i32 N][N × i64 modelId],
这 N 个 modelId 就是容器里出现的模型(登录批次/聊天批次/商店各自对得上)
- InnerScan 支持模式表:只认表里的模型且按表内顺序出现,内层「吃满边界」60% → 70%,假命中基本清掉
- 容器负载打印模式表模型名;README/注释补已核实结论与未闭合环节
|
2026-09-16 16:38:24 +08:00 |
|
TermiNexus
|
2e5e8bd7b0
|
feat(3dtank): 协议工具链入库:上行命令接入 fake server + 字段表/WireClasses
- wss_server:识别 c2s 空间命令([nullmap][objectId i64][methodId i64][负载])并逐字段解码
- 应答签名改用 S:<methodId>(pair_flow.js 同步),fake 模式能按具体上行命令触发对应下行回放
- extract_codec_fields:新增「协议核心类 → 线上基础类型」挖掘(WireClasses,xr/R → i64)
- lib_space_codec:按模型真名/核心类换算兜底(ji → i64、xr → i64),抽成上下行共享库
- decode_space_frames:记录容器(_t/lt)已核实结构与未闭合环节
- README:补「协议逆向与离线模拟」章节(帧格式/字段编码/命令表/fake 回放/容器现状)
实测:297 条上行记录 100% 完整解出;fake 模式按 G.q1wd、ls.xbl 等命令精确触发应答
|
2026-09-16 16:30:38 +08:00 |
|
TermiNexus
|
f1c9d903fa
|
Test Version
|
2026-07-28 01:16:15 +08:00 |
|