Files
TankIC/sockets/probe_chassis.js
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

251 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// probe_chassis.js (v1) —— 十字军 / 悬浮底盘「旋转 + 移动」控制链路探针(网络转储版)
//
// 数据流向:探针 → POST /__probe__?f=chassis → serve.js 追加写 3DTank/names/probe_chassis.log
// 分析时直接读文件(离线 grep),不刷控制台。
//
// 采什么(对应 module_87072 里的四段链路):
// ① 组件清单定位:Cyt(输入组件,持 j14k_1)/ Zmt(悬浮物理,持 r14f_1·q14f_1)
// / Eyt(上行桥,持 k14l_1=serverInterface)/ Iyt(注入通道,持 t14l_1)
// ② Hook Cyt.wak —— 本地输入合成结果 j14k_1(forward / right / turnLeft) 三轴
// ③ Hook Zmt.wak —— 悬浮物理每帧:r14f_1 / q14f_1 三轴(变化即记)
// ④ Hook serverInterface.s14j —— 悬浮控制上行真实参数(时间 + 三轴)★核心
// ⑤ Hook serverInterface.p14n —— 履带控制上行(对照,确认量纲差异)
// ⑥ 扫描 inputSettingsService.ua2() 的前进/侧移刻度(ja3_1) 与转向刻度(ka3_1)
//
// 用法:加载器会自动引入;进战场后推杆走几下 / 转个圈 / 侧移一下,日志即落盘。
// 手动全量:__probeChassis__('dump') 停止:__probeChassis__(false)
(function () {
'use strict';
var ENDPOINT = '/__probe__?f=chassis';
var T0 = window.performance && performance.now ? performance.now() : Date.now();
var Now = function () {
return +(((window.performance && performance.now) ? performance.now() : Date.now()) - T0).toFixed(1);
};
var Src = function (o) { try { return String(o).replace(/\s+/g, ' '); } catch (e) { return '?'; } };
var Ctor = function (o) { try { return Src(o.constructor).slice(0, 90); } catch (e) { return '?'; } };
var Num = function (v) {
if (v === null) return 'null';
if (v === undefined) return 'undef';
if (typeof v === 'number') return Math.round(v * 1000) / 1000;
if (typeof v === 'boolean') return v;
if (typeof v === 'string') return v.slice(0, 24);
if (typeof v === 'object') { try { return 'obj:' + Src(v.constructor).slice(9, 24); } catch (e) { return 'obj'; } }
return String(v).slice(0, 24);
};
// ---- 转储队列 ----
var Buf = [];
var Fallback = false;
var flush = function () {
if (!Buf.length) return;
var text = Buf.join('\n') + '\n';
Buf = [];
if (Fallback) { console.log('[probe-chassis] ' + text); return; }
try {
fetch(ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'text/plain;charset=utf-8' }, body: text })
.then(function (R) { if (!R.ok) throw new Error('HTTP ' + R.status); })
.catch(function (E) {
Fallback = true;
console.warn('[probe-chassis] POST 失败,回落控制台: ' + (E && E.message));
Buf.push(text.trim());
flush();
});
} catch (e) { Fallback = true; }
};
var LOG = function () {
var s = '[+' + Now() + 'ms] ' + [].slice.call(arguments).map(function (a) {
return typeof a === 'string' ? a : JSON.stringify(a);
}).join(' ');
Buf.push(s);
if (Buf.length >= 40) flush();
};
// ---- 状态 ----
var Tank = null, Cyt = null, Zmt = null, Eyt = null, Iyt = null, InputS = null, SI = null, Mount = null, Turret = null;
var LastSeen = {};
var Once = function (key, val) {
var s = JSON.stringify(val);
if (LastSeen[key] === s) return false;
LastSeen[key] = s;
return true;
};
// Qmt 三轴:k149_1=前进 l149_1=侧移 m149_1=转向
var Axes = function (o) {
if (!o) return null;
return { fwd: Num(o.k149_1), right: Num(o.l149_1), turn: Num(o.m149_1) };
};
var Shallow = function (o) {
var d = {};
try {
Object.keys(o).forEach(function (k) {
var v = o[k];
if (typeof v === 'number' || typeof v === 'boolean' || typeof v === 'string' || v === null) d[k] = Num(v);
else if (v && typeof v.length === 'number' && (v instanceof Array || typeof v.slice === 'function'))
d[k] = 'arr[' + v.length + ']=' + [].slice.call(v, 0, 16).map(Num).join('/');
});
} catch (e) {}
return d;
};
// ---- 定位(可重试;坦克会随进战场/重建而变化)----
var CompMapOf = function (t) {
if (!t) return null;
if (t.oyt_1 && t.oyt_1.c2a_1) return t.oyt_1.c2a_1; // 新版组件表
if (t.pyt_1 && t.pyt_1.s2a_1) return t.pyt_1.s2a_1; // 旧版组件表
return null;
};
var Locate = function () {
var Gm = window.__gameMode__;
if (!Gm) return false;
var Best = -1, Found = null;
[Gm.y100_1, Gm.x100_1, Gm.fzr_1, Gm.ezr_1].forEach(function (t) {
var m = CompMapOf(t);
if (!m) return;
var n = 0;
try {
if (typeof m.forEach === 'function' && !(m instanceof Array)) m.forEach(function () { n++; });
else n = Object.keys(m).length;
} catch (e) {}
if (n > Best) { Best = n; Found = t; }
});
if (!Found) return false;
var Entries = [];
(function () {
var m = CompMapOf(Found);
if (typeof m.forEach === 'function' && !(m instanceof Array)) m.forEach(function (v, k) { Entries.push([k, v]); });
else Object.keys(m).forEach(function (k) { Entries.push([k, m[k]]); });
})();
var c = null, z = null, e = null, iy = null, isv = null, mt = null, tu = null;
Entries.forEach(function (en) {
var v = en[1];
if (!v) return;
if (!c && 'j14k_1' in v && 'n14k_1' in v) c = v; // 输入组件
if (!z && 'r14f_1' in v && 'q14f_1' in v && 's14f_1' in v) z = v; // 悬浮物理
if (!e && 'k14l_1' in v && 'l14l_1' in v) e = v; // 上行桥
if (!iy && 't14l_1' in v && 'r14l_1' in v && 'u14l_1' in v) iy = v; // 注入通道
if (!isv && typeof v.ua2 === 'function') isv = v; // inputSettingsService
if (!mt && 'azi_1' in v && 'dzi_1' in v && 'ezi_1' in v && 'mzi_1' in v) mt = v; // weaponMount(炮塔朝向矩阵)
if (!tu && 'tzp_1' in v && 'pzp_1' in v && 'rzp_1' in v && 'lzp_1' in v) tu = v; // oxt(炮塔控制器)
});
// 只在有实质变化时更新(避免坦克重建后仍指向旧对象)
if (Found !== Tank) { Tank = Found; LOG('玩家坦克组件数=' + Best + ' ctor=' + Ctor(Tank)); }
Cyt = c; Zmt = z; Eyt = e; Iyt = iy; InputS = isv;
Mount = mt; Turret = tu;
return !!(Cyt || Zmt);
};
var Dump = function () {
LOG('===== 底盘组件定位 =====');
LOG('Cyt ' + (Cyt ? Ctor(Cyt) + ' ▸ ' + Object.keys(Cyt).join(',') : 'null'));
LOG('Zmt ' + (Zmt ? Ctor(Zmt) + ' ▸ ' + Object.keys(Zmt).join(',') : 'null'));
LOG('Eyt ' + (Eyt ? Ctor(Eyt) + ' ▸ ' + Object.keys(Eyt).join(',') : 'null'));
LOG('Iyt ' + (Iyt ? Ctor(Iyt) + ' ▸ ' + Object.keys(Iyt).join(',') : 'null'));
LOG('Mount ' + (Mount ? Ctor(Mount) + ' ▸ ' + Object.keys(Mount).join(',') : 'null'));
LOG('Turret ' + (Turret ? Ctor(Turret) + ' ▸ ' + Object.keys(Turret).join(',') : 'null'));
if (Cyt) LOG('Cyt.j14k_1 ctor=' + Ctor(Cyt.j14k_1) + ' 三轴=' + JSON.stringify(Axes(Cyt.j14k_1)));
if (Zmt) LOG('Zmt.r14f_1 三轴=' + JSON.stringify(Axes(Zmt.r14f_1)) + ' q14f_1 三轴=' + JSON.stringify(Axes(Zmt.q14f_1)));
if (InputS) {
LOG('inputSettings ctor=' + Ctor(InputS));
try { LOG('ua2()=' + JSON.stringify(Shallow(InputS.ua2()))); } catch (err) { LOG('ua2() 读取失败 ' + err.message); }
} else {
LOG('inputSettingsService 未在坦克组件表里找到(可能在场景服务层)');
}
LOG('===== 定位结束 =====');
};
// ---- Hook(实例自有属性覆盖原型方法,去重记录)----
var Report = function (tag, self, args) {
if (tag === 'CYTAWAK') {
var a = Axes(self.j14k_1);
if (Once('cyt', a)) LOG('Cyt.wak j14k_1=' + JSON.stringify(a) +
' k14k_1=' + Num(self.k14k_1) + ' l14k_1=' + Num(self.l14k_1) + ' m14k_1=' + Num(self.m14k_1));
} else if (tag === 'ZMTAWAK') {
var b = Axes(self.r14f_1);
if (Once('zmt', b)) LOG('Zmt.wak r14f_1=' + JSON.stringify(b) +
' q14f_1=' + JSON.stringify(Axes(self.q14f_1)));
} else if (tag === 'S14J') {
LOG('s14j 悬浮上行 t=' + Num(args[0]) + ' ctrl=' + JSON.stringify(Axes(args[1])));
} else if (tag === 'P14N') {
var c = args[1];
LOG('p14n 履带上行 t=' + Num(args[0]) + ' fwd=' + Num(c && c.m14b_1) +
' turn=' + Num(c && c.n14b_1) + ' revTurn=' + Num(c && c.o14b_1));
} else if (tag === 'OXTWAK') {
// 炮塔控制器每帧:azi_1=目标角,mode=输入模式,rzp_1=输入,lzp_1=当前转速
var z = Num(self.azi_1);
if (Once('oxt', z + '|' + Num(self.pzp_1 && self.pzp_1.k3_1))) {
LOG('oxt.wak azi_1=' + z + ' mode=' + Num(self.pzp_1 && self.pzp_1.k3_1) +
' rzp_1=' + Num(self.rzp_1) + ' lzp_1=' + Num(self.lzp_1) + ' jzp_1=' + Num(self.jzp_1));
}
} else if (tag === 'QYR') {
// 炮塔矩阵每帧插值:azi_1=目标角,dzi_1=显示角,czi_1=弹簧补偿,args[0]=渲染插值系数
var R2 = function (x) { return typeof x === 'number' ? Math.round(x * 100) / 100 : Num(x); };
var Key = R2(self.azi_1) + '|' + R2(self.dzi_1) + '|' + R2(self.czi_1) + '|' + R2(args[0]);
if (Once('qyr', Key)) {
LOG('qyr t=' + R2(args[0]) + ' azi_1=' + R2(self.azi_1) + ' dzi_1=' + R2(self.dzi_1) + ' czi_1=' + R2(self.czi_1));
}
}
};
var Wrap = function (obj, name, tag) {
if (!obj || typeof obj[name] !== 'function' || obj['__hk_' + name]) return false;
var Orig = obj[name];
obj[name] = function () {
var R = Orig.apply(this, arguments);
try { Report(tag, this, arguments); } catch (e) {}
return R;
};
obj['__hk_' + name] = true;
return true;
};
window.addEventListener('beforeunload', flush);
LOG('===== probe_chassis v1 启动 location=' + location.href + ' =====');
// ---- 主循环:定位 → 挂 Hook → 采样 ----
var Hooked = false, Tries = 0;
var R = function () {
Tries++;
if (!Hooked) {
if (Locate()) {
Dump();
var Hit = [];
if (Wrap(Cyt, 'wak', 'CYTAWAK')) Hit.push('Cyt.wak');
if (Wrap(Zmt, 'wak', 'ZMTAWAK')) Hit.push('Zmt.wak');
if (Wrap(Turret, 'wak', 'OXTWAK')) Hit.push('oxt.wak(炮塔控制器)');
if (Wrap(Mount, 'qyr', 'QYR')) Hit.push('weaponMount.qyr(炮塔矩阵)');
Hooked = true;
LOG('已挂 Hook: ' + (Hit.join(' | ') || '(无)'));
} else if (Tries % 15 === 0) {
LOG('等待玩家坦克 / 底盘组件… 第 ' + Tries + ' 次');
}
} else {
Locate(); // 坦克重建后刷新引用
}
// serverInterface(Eyt.k14l_1)通常在进战场后才赋值,延后补挂
if (!SI && Eyt && Eyt.k14l_1) {
SI = Eyt.k14l_1;
var Hit2 = [];
if (Wrap(SI, 's14j', 'S14J')) Hit2.push('serverInterface.s14j(悬浮)');
if (Wrap(SI, 'p14n', 'P14N')) Hit2.push('serverInterface.p14n(履带)');
LOG('已挂 Hook: ' + (Hit2.join(' | ') || '(无)'));
}
// 兜底采样
if (Cyt && Once('cyt-sample', Axes(Cyt.j14k_1))) LOG('SAMPLE Cyt.j14k_1=' + JSON.stringify(Axes(Cyt.j14k_1)));
if (Zmt && Once('zmt-sample', Axes(Zmt.r14f_1))) LOG('SAMPLE Zmt.r14f_1=' + JSON.stringify(Axes(Zmt.r14f_1)));
flush();
if (Tries > 900) { clearInterval(Timer); LOG('探针自动停止(已运行 900 拍)'); }
};
var Timer = setInterval(R, 200);
R();
window.__probeChassis__ = function (a) {
if (a === false) { clearInterval(Timer); flush(); return 'stopped'; }
if (a === 'flush') { flush(); return 'flushed'; }
if (a === 'dump') { Locate(); Dump(); flush(); return 'dumped'; }
return 'running';
};
console.log('[probe-chassis] 已启动:网络转储 → ' + ENDPOINT + '(落盘 3DTank/names/probe_chassis.log)。停:__probeChassis__(false)');
})();