- 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' 开启)
251 lines
12 KiB
JavaScript
251 lines
12 KiB
JavaScript
// 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)');
|
||
})();
|