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
This commit is contained in:
TermiNexus committed 2026-10-16 14:55:39 +08:00
1 parent 469f913619
commit dcf5dfce5c
12 files changed
+638 -538

No files matched your search

@@ -250,9 +250,9 @@
// 遍历 entity.wyj_1.r2a_1(Map<组件标识, 组件列表>),value 是列表类(s_),g1(0) 获取实际组件
// 注意:用 !== undefined 检查字段存在性,避免 falsy 值(0/""/null/false)漏判
function FindComponentByField(entity, fieldName) {
if (!entity || !entity.pyt_1 || !entity.pyt_1.s2a_1) return null;
if (!entity || !entity.qz1_1 || !entity.qz1_1.s2a_1) return null;
var result = null;
entity.pyt_1.s2a_1.forEach(function(valueList, key) {
entity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (result) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
@@ -262,7 +262,7 @@
return result;
}
// ===== 获取坦克位置(G$t 物理组件的 pz7_1 = O$向量) =====
// ===== 获取坦克位置(G$t 物理组件的 rzf_1 = O$向量) =====
// 返回 {x, y, z},x/y 水平面,z 高度
function GetTankPosition(tank) {
var physicsComp = FindComponentByField(tank, 'gzh_1');
@@ -280,21 +280,21 @@
// 状态枚举:0=DEAD, 1=DEAD_PHANTOM, 2=SEMI_ACTIVE, 3=ACTIVE, 4=DISABLED
// Yjt 特征:有 azs_1(状态机)和 vzr_1(状态枚举)字段
function GetTankState(tank) {
if (!tank || !tank.pyt_1 || !tank.pyt_1.s2a_1) return -1;
if (!tank || !tank.qz1_1 || !tank.qz1_1.s2a_1) return -1;
var tankComp = null;
tank.pyt_1.s2a_1.forEach(function(valueList, key) {
tank.qz1_1.s2a_1.forEach(function(valueList, key) {
if (tankComp) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && comp.t101_1 && comp.o101_1 !== undefined) tankComp = comp;
if (comp && comp.t101_1 && comp.k10c_1 !== undefined) tankComp = comp;
} catch(e) {}
});
if (tankComp && tankComp.o101_1) return tankComp.o101_1.k3_1;
if (tankComp && tankComp.k10c_1) return tankComp.k10c_1.k3_1;
return -1;
}
// 可见/战斗中的坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)
// 依据:引擎用 tankComponent.y147()(= SEMI_ACTIVE || ACTIVE)决定该坦克节点是否渲染,
// 依据:引擎用 tankComponent.s14j()(= SEMI_ACTIVE || ACTIVE)决定该坦克节点是否渲染,
// 只认 ACTIVE 会漏掉半活跃状态(出生/过渡)的坦克
function IsTankAlive(tank) {
var s = GetTankState(tank);
@@ -304,20 +304,20 @@
// ===== 获取坦克名称(yot 用户信息组件) =====
// s120_1 = userName, u120_1 = clanTag(可为null), t120_1 = userRank
function GetTankName(tank) {
var userComp = FindComponentByField(tank, 'k12a_1');
var userComp = FindComponentByField(tank, 'c12n_1');
if (!userComp) return null;
var name = userComp.k12a_1 || '';
var clanTag = userComp.m12a_1 || '';
var name = userComp.c12n_1 || '';
var clanTag = userComp.e12n_1 || '';
return clanTag ? (clanTag + ' ' + name) : name;
}
// ===== 获取坦克血量(Vkt 血量组件) =====
// f122_1 = 最大血量(max), g122_1 = 当前血量(current, 死亡时=0)
function GetTankHealth(tank) {
var healthComp = FindComponentByField(tank, 'y12b_1');
var healthComp = FindComponentByField(tank, 'q12o_1');
if (!healthComp) return null;
var max = healthComp.x12b_1 || 0;
var cur = healthComp.y12b_1 || 0;
var max = healthComp.p12o_1 || 0;
var cur = healthComp.q12o_1 || 0;
if (max <= 0) return null;
return { current: cur, max: max, percent: cur / max };
}
@@ -370,9 +370,9 @@
// checkPosition: 是否检查位置有效性(默认true;测试脚本传false以在死亡状态控制)
function GetPlayerTank(gm, checkPosition) {
if (checkPosition === undefined) checkPosition = true;
var t = gm.x100_1;
var t = gm.t10b_1;
if (t && (!checkPosition || GetTankPosition(t))) return t;
t = gm.y100_1;
t = gm.u10b_1;
if (t && (!checkPosition || GetTankPosition(t))) return t;
try {
var tl = gm.q100_1.r11l();
@@ -397,10 +397,10 @@
} catch(e) {}
}
try {
if (gm && gm.z100_1 && ZCt) {
if (gm && gm.v10b_1 && ZCt) {
var team = ZCt(tank);
if (team && gm.z100_1) {
return team.equals(gm.z100_1) && m2Fn ? m2Fn(team, gm.z100_1) : team.equals(gm.z100_1);
if (team && gm.v10b_1) {
return team.equals(gm.v10b_1) && m2Fn ? m2Fn(team, gm.v10b_1) : team.equals(gm.v10b_1);
}
}
} catch(e) {}
@@ -410,13 +410,13 @@
// ===== 获取相机信息($r/gq 相机组件) =====
// 遍历 GameMode entity 和所有坦克 entity 查找活跃相机组件
// 策略1:查找 $r/gq 相机组件(有 kym_1 位置 和 lym_1 方向)
// 策略2:查找 k7 相机控制器(有 qz9_1 和 gz9_1),从 gz9_1 获取相机组件
// 策略2:查找 k7 相机控制器(有 qz9_1 和 jzh_1),从 jzh_1 获取相机组件
// 返回 {yaw, pitch, fov, pos:{x,y,z}}
// 注意:lym_1.h20_1 是 roll(绕Z),lym_1.f20_1 是 pitch(绕X)
function GetCameraInfo(gm) {
var entities = [];
try {
var gameScene = gm.jyw().iyt_1;
var gameScene = gm.jyw().jz1_1;
var gmEntity = gameScene.xyu("GameMode");
if (gmEntity) entities.push(gmEntity);
} catch(e) {}
@@ -431,9 +431,9 @@
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (!entity || !entity.pyt_1 || !entity.pyt_1.s2a_1) continue;
if (!entity || !entity.qz1_1 || !entity.qz1_1.s2a_1) continue;
var found = null;
entity.pyt_1.s2a_1.forEach(function(valueList, key) {
entity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (found) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
@@ -478,13 +478,13 @@
function GetUMtComponent(gm) {
try {
var gmEntity = gm.jyw();
if (!gmEntity || !gmEntity.pyt_1 || !gmEntity.pyt_1.s2a_1) return null;
if (!gmEntity || !gmEntity.qz1_1 || !gmEntity.qz1_1.s2a_1) return null;
var uMt = null;
gmEntity.pyt_1.s2a_1.forEach(function(valueList, key) {
gmEntity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (uMt) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && typeof comp.m179 === 'function') uMt = comp;
if (comp && typeof comp.a17p === 'function') uMt = comp;
} catch(e) {}
});
return uMt;
@@ -514,24 +514,24 @@
y178_1: MkVec(0, 0, 0),
z178_1: MkVec(0, 0, 0),
a179_1: maxDist,
c179_1: null,
q17o_1: null,
b179_1: null,
d179: function(t, n, i, r, e) {
r17o: function(t, n, i, r, e) {
this.y178_1.k26(t);
this.z178_1.k26(n);
this.a179_1 = i;
this.c179_1 = r;
this.q17o_1 = r;
this.b179_1 = e;
},
d3: function() { this.b179_1 = null; }
};
var filter = {
o1co_1: { h1: function() { return false; }, d3: function() {} },
l1da_1: { h1: function() { return false; }, d3: function() {} },
w179: function() { return true; },
d3: function() { this.o1co_1.d3(); },
p1co: function() {}
d3: function() { this.l1da_1.d3(); },
m1da: function() {}
};
var hit = uMt.m179(startVec, dirVec, maxDist, result, filter);
var hit = uMt.a17p(startVec, dirVec, maxDist, result, filter);
return (hit && result.a179_1 < maxDist) ? result.a179_1 : -1;
} catch(e) {
return -1;
@@ -750,7 +750,7 @@
// ===== 获取坦克方向(Kkt 组件的 dzc_1) =====
function getTankDirection(tank) {
var hullComp = FindComponentByField(tank, 'vzl_1');
var hullComp = FindComponentByField(tank, 'qzv_1');
if (hullComp && hullComp.wzl_1) {
return {
x: hullComp.wzl_1.f20_1,
@@ -764,13 +764,13 @@
// ===== 获取相机方向(gq/$r 组件的 lym_1.h20_1 = 偏航角) =====
// 相机组件可能在 GameMode entity、玩家坦克或任何坦克上
// 策略1:查找 $r/gq 相机组件(有 kym_1 和 lym_1 字段)
// 策略2:查找 k7 相机控制器(有 qz9_1 和 gz9_1 字段),从 gz9_1 获取相机组件
// 策略2:查找 k7 相机控制器(有 qz9_1 和 jzh_1 字段),从 jzh_1 获取相机组件
function getCameraHeading() {
var entities = [];
// 1. GameMode entity
try {
var gameScene = gm.jyw().iyt_1;
var gameScene = gm.jyw().jz1_1;
var gmEntity = gameScene.xyu("GameMode");
if (gmEntity) entities.push(gmEntity);
} catch(e) {}
@@ -788,10 +788,10 @@
// 在每个 entity 上查找相机组件
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (!entity || !entity.pyt_1 || !entity.pyt_1.s2a_1) continue;
if (!entity || !entity.qz1_1 || !entity.qz1_1.s2a_1) continue;
var found = null;
entity.pyt_1.s2a_1.forEach(function(valueList, key) {
entity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (found) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
@@ -807,7 +807,7 @@
}
}
// 策略2:查找 k7 相机控制器(有 qz9_1 和 gz9_1 字段)
// 策略2:查找 k7 相机控制器(有 qz9_1 和 jzh_1 字段)
if (comp.jzj_1 && comp.zzi_1) {
var camComp = comp.zzi_1;
if (camComp && camComp.cyw_1 && camComp.dyw_1 &&
@@ -861,12 +861,12 @@
if (UMtComponent) return UMtComponent;
try {
var gmEntity = gm.jyw();
if (!gmEntity || !gmEntity.pyt_1 || !gmEntity.pyt_1.s2a_1) return null;
gmEntity.pyt_1.s2a_1.forEach(function(valueList, key) {
if (!gmEntity || !gmEntity.qz1_1 || !gmEntity.qz1_1.s2a_1) return null;
gmEntity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (UMtComponent) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && typeof comp.m179 === 'function') UMtComponent = comp;
if (comp && typeof comp.a17p === 'function') UMtComponent = comp;
} catch(e) {}
});
if (UMtComponent) console.log('[雷达] uMt 碰撞检测器已获取');
@@ -889,19 +889,19 @@
var dirVec = MkVec(dirX, dirY, dirZ);
var result = {
y178_1: MkVec(0,0,0), z178_1: MkVec(0,0,0),
a179_1: maxDist, c179_1: null, b179_1: null,
d179: function(t, n, i, r, e) {
a179_1: maxDist, q17o_1: null, b179_1: null,
r17o: function(t, n, i, r, e) {
this.y178_1.k26(t); this.z178_1.k26(n);
this.a179_1 = i; this.c179_1 = r; this.b179_1 = e;
this.a179_1 = i; this.q17o_1 = r; this.b179_1 = e;
},
d3: function() { this.b179_1 = null; }
};
var filter = {
o1co_1: { h1: function() { return false; }, d3: function() {} },
l1da_1: { h1: function() { return false; }, d3: function() {} },
w179: function() { return true; },
d3: function() {}, p1co: function() {}
d3: function() {}, m1da: function() {}
};
var hit = uMt.m179(startVec, dirVec, maxDist, result, filter);
var hit = uMt.a17p(startVec, dirVec, maxDist, result, filter);
return (hit && result.a179_1 < maxDist) ? result.a179_1 : -1;
} catch(e) {
return -1;
@@ -1460,7 +1460,7 @@
ctx.textAlign = 'left';
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ' Bot:' + botCount + ')', 5, 12);
if (radar.playerFound) {
ctx.fillText('Player: ' + (playerTank ? playerTank.hyt_1 : '?'), 5, 24);
ctx.fillText('Player: ' + (playerTank ? playerTank.iz1_1 : '?'), 5, 24);
} else {
ctx.fillText('Player: NOT FOUND', 5, 24);
}
@@ -1695,12 +1695,12 @@
}
// ===== 获取 KMt / TDt 渲染组件 =====
// 新 build:车身皮肤组件字段是 w14w_1(kDt(t)=t.w14w_1,缺失报 "skin";RDt.v16b 里赋值)
// 旧 build:u14l_1 / t14l_1 / p14l_1(新版 t14l_1 已改成悬停车体状态 Qmt,务必别再当皮肤用)
// 新 build:车身皮肤组件字段是 w14w_1(kDt(t)=t.w14w_1,缺失报 "skin";RDt.j16r 里赋值)
// 旧 build:w14x_1 / t14l_1 / p14l_1(新版 t14l_1 已改成悬停车体状态 Qmt,务必别再当皮肤用)
function GetKMtComponent(entity) {
var comp = FindComponentByField(entity, 'w14w_1');
if (comp) return comp;
comp = FindComponentByField(entity, 'u14l_1');
comp = FindComponentByField(entity, 'w14x_1');
if (comp) return comp;
comp = FindComponentByField(entity, 't14l_1');
if (comp) return comp;
@@ -1708,13 +1708,13 @@
return comp;
}
// 取车身皮肤对象(含 s17b_1 部件表),跨版本兼容;stats 用于诊断来源
// 取车身皮肤对象(含 g17r_1 部件表),跨版本兼容;stats 用于诊断来源
function GetHullSkin(tank, stats) {
var comp = GetKMtComponent(tank);
if (!comp) { if (stats) stats.hullSource = '无组件'; return null; }
if (comp.w14w_1 && comp.w14w_1.s17b_1) { if (stats) stats.hullSource = 'w14w_1'; return comp.w14w_1; } // 新 build
if (comp.t14l_1 && comp.t14l_1.s17b_1) { if (stats) stats.hullSource = 't14l_1'; return comp.t14l_1; } // 旧 build
if (comp.p14l_1 && comp.p14l_1.s17b_1) { if (stats) stats.hullSource = 'p14l_1'; return comp.p14l_1; } // 旧 build
if (comp.w14w_1 && comp.w14w_1.g17r_1) { if (stats) stats.hullSource = 'w14w_1'; return comp.w14w_1; } // 新 build
if (comp.t14l_1 && comp.t14l_1.g17r_1) { if (stats) stats.hullSource = 't14l_1'; return comp.t14l_1; } // 旧 build
if (comp.p14l_1 && comp.p14l_1.g17r_1) { if (stats) stats.hullSource = 'p14l_1'; return comp.p14l_1; } // 旧 build
if (stats) stats.hullSource = '有组件但无皮肤';
return null;
}
@@ -1728,14 +1728,14 @@
// ===== 从GPU读取顶点位置数据(缓冲区[0]) =====
function ReadVertexPositionsFromTp(tp) {
if (!tp || !tp.t4w_1) return null;
var tl = tp.t4w_1.g1(0);
if (!tp || !tp.x4w_1) return null;
var tl = tp.x4w_1.g1(0);
if (!tl || !tl.d3x_1) return null;
var vq = tl.d3x_1;
var bs = vq.s3h_1;
if (!bs || !bs.b74_1) return null;
var gl = bs.b74_1;
var webglBuf = vq.r3x_1 && vq.r3x_1.z73_1;
var webglBuf = vq.v3x_1 && vq.v3x_1.z73_1;
if (!webglBuf) return null;
gl.bindBuffer(gl.ARRAY_BUFFER, webglBuf);
var bufSize = gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE);
@@ -1753,12 +1753,12 @@
var allIndices = [];
for (var m = 0; m < meshCount; m++) {
var il = tp.y4w_1.g1(m);
if (!il || !il.q3p_1) continue;
var fq = il.q3p_1;
if (!il || !il.u3p_1) continue;
var fq = il.u3p_1;
var bs = fq.s3h_1;
if (!bs || !bs.b74_1) continue;
var gl = bs.b74_1;
var webglBuf = fq.j3x_1 && fq.j3x_1.z73_1;
var webglBuf = fq.n3x_1 && fq.n3x_1.z73_1;
if (!webglBuf) continue;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webglBuf);
var bufSize = gl.getBufferParameter(gl.ELEMENT_ARRAY_BUFFER, gl.BUFFER_SIZE);
@@ -1815,25 +1815,25 @@
function CollectMeshNodes(bpNode, nodes, depth, group, stats) {
if (!bpNode || depth > 5) return;
if (stats) stats.seen++;
var name = bpNode.e35_1 || '';
if (bpNode.t3m_1) {
var name = bpNode.g35_1 || '';
if (bpNode.v3m_1) {
if (stats) stats.hasMesh++;
var gpuData = GetGpuData(bpNode.t3m_1);
var gpuData = GetGpuData(bpNode.v3m_1);
if (gpuData) {
if (stats) stats.gpuOk++;
nodes.push({
name: name, node: bpNode, tp: bpNode.t3m_1,
name: name, node: bpNode, tp: bpNode.v3m_1,
positions: gpuData.positions, indices: gpuData.indices, stride: gpuData.stride, group: group
});
} else if (stats) stats.gpuFail++;
}
if (bpNode.q4x_1 && typeof bpNode.q4x_1.e1 === 'function') {
if (bpNode.u4x_1 && typeof bpNode.u4x_1.e1 === 'function') {
try {
var lodCount = bpNode.q4x_1.e1();
var lodCount = bpNode.u4x_1.e1();
for (var lod = 0; lod < lodCount && lod < 1; lod++) {
var lodLevel = bpNode.q4x_1.g1(lod);
var lodLevel = bpNode.u4x_1.g1(lod);
if (!lodLevel) continue;
var lodTp = lodLevel.t3m_1 || lodLevel.v3m_1;
var lodTp = lodLevel.v3m_1 || lodLevel.v3m_1;
if (!lodTp) continue;
var lodGpuData = GetGpuData(lodTp);
if (lodGpuData) {
@@ -1863,14 +1863,14 @@
var skin = GetHullSkin(tank, stats);
if (skin) {
try {
var partCount = skin.s17b_1.e1();
var partCount = skin.g17r_1.e1();
if (stats) stats.hullParts = partCount;
for (var p = 0; p < partCount; p++) {
var part = skin.s17b_1.g1(p);
if (!part || !part.v17b_1) continue;
var nodeCount = part.v17b_1.e1();
var part = skin.g17r_1.g1(p);
if (!part || !part.j17r_1) continue;
var nodeCount = part.j17r_1.e1();
for (var n = 0; n < nodeCount; n++) {
var bpNode = part.v17b_1.g1(n);
var bpNode = part.j17r_1.g1(n);
if (!bpNode) continue;
CollectMeshNodes(bpNode, nodes, 0, 'hull', stats ? stats.hull : null);
}
@@ -2437,7 +2437,7 @@
var physicsComp = FindComponentByField(tank, 'gzh_1');
if (!physicsComp || !physicsComp.gzh_1) continue;
var tankState = GetTankState(tank);
// 可见坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)(引擎 y147() 判定),0/1/4 才跳过
// 可见坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)(引擎 s14j() 判定),0/1/4 才跳过
if (tankState !== 2 && tankState !== 3) continue;
var pos = {
@@ -2449,7 +2449,7 @@
// 本帧该坦克是否在移动(供「残留节点」检测:坦克在动而节点矩阵不动 = 旧位置遗留)
// 用位移的指数滑动平均,而不是「单帧位移 > 10 单位」——后者对慢速移动几乎永远为假,
// 会让残留检测形同虚设(残留漏掉的根因就在这里)
var tankId = tank.hyt_1;
var tankId = tank.iz1_1;
var prevPos = TankPrevPos.get(tankId);
var tankMove = 0;
if (prevPos) {
@@ -2467,7 +2467,7 @@
if (distance > 50000) continue;
var friendly = IsFriendly(tank, playerTank);
var tankName = GetTankName(tank) || ('ID:' + tank.hyt_1);
var tankName = GetTankName(tank) || ('ID:' + tank.iz1_1);
// 根据 HighlightMode 判断是否渲染该坦克
if (!ShouldRender(tankName)) continue;
// 颜色按队伍:友方=蓝,敌方=红
@@ -2736,11 +2736,11 @@
var initError = null;
try {
scene = gm.jyw().iyt_1;
scene = gm.jyw().jz1_1;
console.log('[后视] 场景对象:', scene);
// hC 渲染器实例(jr.lye_1)
var renderer = scene.fyo_1;
var renderer = scene.gyw_1;
console.log('[后视] 渲染器:', renderer);
// Ff 绘制器实例(hC.r74_1)
@@ -2748,11 +2748,11 @@
console.log('[后视] Ff绘制器:', ff);
// 场景根节点(jr.kyf_1)
rootNode = scene.eyp_1;
rootNode = scene.fyx_1;
console.log('[后视] 根节点:', rootNode);
// 主相机 Ha 实例(jr.nyf_1)
mainCamera = scene.hyp_1;
mainCamera = scene.iyx_1;
console.log('[后视] 主相机:', mainCamera);
// 游戏 gl context(Ff.p39_1.p73_1 = BS.p73_1)
@@ -2764,11 +2764,11 @@
}
// 探测相机字段
console.log('[后视] 相机s35_1:', mainCamera.s35_1);
console.log('[后视] 相机u35_1:', mainCamera.u35_1);
console.log('[后视] 相机r35_1:', mainCamera.r35_1);
console.log('[后视] 相机b37_1:', mainCamera.b37_1);
if (!mainCamera.s35_1 || !mainCamera.r35_1) {
if (!mainCamera.u35_1 || !mainCamera.r35_1) {
throw new Error('相机字段缺失');
}
@@ -2964,14 +2964,14 @@
var camPosZ = playerPos.z + Config.cameraHeight;
// ===== 保存主相机参数 =====
var savedPitch = mainCamera.s35_1.f20_1;
var savedYaw = mainCamera.s35_1.g20_1;
var savedRoll = mainCamera.s35_1.h20_1;
var savedPitch = mainCamera.u35_1.f20_1;
var savedYaw = mainCamera.u35_1.g20_1;
var savedRoll = mainCamera.u35_1.h20_1;
var savedX = mainCamera.r35_1.f20_1;
var savedY = mainCamera.r35_1.g20_1;
var savedZ = mainCamera.r35_1.h20_1;
var savedL36 = mainCamera.s36_1;
var savedM36 = mainCamera.t36_1;
var savedL36 = mainCamera.u36_1;
var savedM36 = mainCamera.v36_1;
var savedS36 = mainCamera.z36_1;
var savedQ36 = mainCamera.x36_1;
var savedR36 = mainCamera.y36_1;
@@ -2985,14 +2985,14 @@
// g=π 使水平方向反向(朝后看),h=yaw+π 保持水平视角正确
// f=-pitch 使垂直方向与主视一致(低头看后方地形)
// up 朝下 → FBO 画面颠倒 → GL readback Y 翻转修正
mainCamera.s35_1.f20_1 = rearPitch;
mainCamera.s35_1.g20_1 = Math.PI;
mainCamera.s35_1.h20_1 = camInfo.yaw + Math.PI;
mainCamera.u35_1.f20_1 = rearPitch;
mainCamera.u35_1.g20_1 = Math.PI;
mainCamera.u35_1.h20_1 = camInfo.yaw + Math.PI;
mainCamera.r35_1.f20_1 = camPosX;
mainCamera.r35_1.g20_1 = camPosY;
mainCamera.r35_1.h20_1 = camPosZ;
mainCamera.s36_1 = rw;
mainCamera.t36_1 = rh;
mainCamera.u36_1 = rw;
mainCamera.v36_1 = rh;
mainCamera.z36_1 = Config.fov;
mainCamera.x36_1 = Config.near;
mainCamera.y36_1 = Config.far;
@@ -3004,14 +3004,14 @@
var rearViewMatrix = new Float32Array(mainCamera.b37_1);
// ===== 保存并禁用阴影/后处理(避免它们切换 FBO 覆盖 rearFbo)=====
// p38_1.x3n_1 控制 z39_1(阴影),y3n_1 控制 c3a_1/d3a_1(后处理),z3n_1 控制 f3a_1
// p38_1.b3o_1 控制 z39_1(阴影),c3o_1 控制 c3a_1/d3a_1(后处理),z3n_1 控制 f3a_1
// 禁用后 y3s 只执行主场景渲染 z3k,跳过所有 FBO 切换的 pass
var savedX3n = ff.w38_1.e3o_1;
var savedY3n = ff.w38_1.f3o_1;
var savedZ3n = ff.w38_1.g3o_1;
ff.w38_1.e3o_1 = false;
ff.w38_1.f3o_1 = false;
ff.w38_1.g3o_1 = false;
var savedX3n = ff.y38_1.e3o_1;
var savedY3n = ff.y38_1.f3o_1;
var savedZ3n = ff.y38_1.k3o_1;
ff.y38_1.e3o_1 = false;
ff.y38_1.f3o_1 = false;
ff.y38_1.k3o_1 = false;
// ===== 禁用 UI 渲染层(防止技能条等 UI 混入后视 FBO)=====
// 保存 UI 层队列,替换为空假对象,y3s 后恢复
@@ -3085,9 +3085,9 @@
// ===== 恢复阴影/后处理(异常时也要恢复)=====
try {
if (typeof savedX3n !== 'undefined') {
ff.w38_1.e3o_1 = savedX3n;
ff.w38_1.f3o_1 = savedY3n;
ff.w38_1.g3o_1 = savedZ3n;
ff.y38_1.e3o_1 = savedX3n;
ff.y38_1.f3o_1 = savedY3n;
ff.y38_1.k3o_1 = savedZ3n;
}
} catch(e) {
console.error('[后视] 恢复阴影/后处理失败:', e.message);
@@ -3107,14 +3107,14 @@
// ===== 恢复主相机参数 =====
try {
mainCamera.s35_1.f20_1 = savedPitch;
mainCamera.s35_1.g20_1 = savedYaw;
mainCamera.s35_1.h20_1 = savedRoll;
mainCamera.u35_1.f20_1 = savedPitch;
mainCamera.u35_1.g20_1 = savedYaw;
mainCamera.u35_1.h20_1 = savedRoll;
mainCamera.r35_1.f20_1 = savedX;
mainCamera.r35_1.g20_1 = savedY;
mainCamera.r35_1.h20_1 = savedZ;
mainCamera.s36_1 = savedL36;
mainCamera.t36_1 = savedM36;
mainCamera.u36_1 = savedL36;
mainCamera.v36_1 = savedM36;
mainCamera.z36_1 = savedS36;
mainCamera.x36_1 = savedQ36;
mainCamera.y36_1 = savedR36;
@@ -3466,12 +3466,12 @@
if (UMtComponent) return UMtComponent;
try {
var gmEntity = gm.jyw();
if (!gmEntity || !gmEntity.pyt_1 || !gmEntity.pyt_1.s2a_1) return null;
gmEntity.pyt_1.s2a_1.forEach(function(valueList, key) {
if (!gmEntity || !gmEntity.qz1_1 || !gmEntity.qz1_1.s2a_1) return null;
gmEntity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (UMtComponent) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && typeof comp.m179 === 'function') UMtComponent = comp;
if (comp && typeof comp.a17p === 'function') UMtComponent = comp;
} catch(e) {}
});
if (UMtComponent) console.log('[瞄准] uMt 碰撞检测器已获取');
@@ -3516,26 +3516,26 @@
y178_1: MkVec(0,0,0),
z178_1: MkVec(0,0,0),
a179_1: maxDist,
c179_1: null,
q17o_1: null,
b179_1: null,
d179: function(t, n, i, r, e) {
r17o: function(t, n, i, r, e) {
this.y178_1.k26(t);
this.z178_1.k26(n);
this.a179_1 = i;
this.c179_1 = r;
this.q17o_1 = r;
this.b179_1 = e;
},
d3: function() { this.b179_1 = null; }
};
var filter = {
o1co_1: { h1: function() { return false; }, d3: function() {} },
l1da_1: { h1: function() { return false; }, d3: function() {} },
w179: function() { return true; },
d3: function() { this.o1co_1.d3(); },
p1co: function() {}
d3: function() { this.l1da_1.d3(); },
m1da: function() {}
};
var hit = uMt.m179(startVec, dirVec, maxDist, result, filter);
var hit = uMt.a17p(startVec, dirVec, maxDist, result, filter);
blocked = !!hit && result.a179_1 < (maxDist - 50);
RaycastFailCount = 0;
} catch(e) {
@@ -3648,19 +3648,19 @@
if (aimInfo.angle >= aimThreshold) continue;
// 墙体阻隔判断
var blocked = IsLineOfSightBlocked(pos, playerPos, tank.hyt_1, frameCount);
var blocked = IsLineOfSightBlocked(pos, playerPos, tank.iz1_1, frameCount);
if (blocked) continue;
// 记录威胁
var proj = Project3D(pos, camInfo.pos, camInfo.yaw, camInfo.pitch, camInfo.fov, screenW, screenH);
var tankName = GetTankName(tank) || ('ID:' + tank.hyt_1);
var tankName = GetTankName(tank) || ('ID:' + tank.iz1_1);
threats.push({
pos: pos,
distance: aimInfo.distance,
angle: aimInfo.angle,
turretDir: aimInfo.turretDir,
screenProj: proj,
tankId: tank.hyt_1,
tankId: tank.iz1_1,
tankName: tankName
});
}
@@ -4019,14 +4019,14 @@
var initError = null;
try {
scene = gm.jyw().iyt_1;
mainCamera = scene.hyp_1;
ff = scene.fyo_1.d75_1;
if (!mainCamera || !mainCamera.s35_1 || !mainCamera.r35_1 || !mainCamera.o37) {
scene = gm.jyw().jz1_1;
mainCamera = scene.iyx_1;
ff = scene.gyw_1.d75_1;
if (!mainCamera || !mainCamera.u35_1 || !mainCamera.r35_1 || !mainCamera.o37) {
throw new Error('相机字段缺失');
}
console.log('[自由视角] 主相机:', mainCamera.constructor.name,
'l35=(' + mainCamera.s35_1.f20_1.toFixed(2) + ',' + mainCamera.s35_1.g20_1.toFixed(2) + ',' + mainCamera.s35_1.h20_1.toFixed(2) + ')',
'l35=(' + mainCamera.u35_1.f20_1.toFixed(2) + ',' + mainCamera.u35_1.g20_1.toFixed(2) + ',' + mainCamera.u35_1.h20_1.toFixed(2) + ')',
'k35=(' + mainCamera.r35_1.f20_1.toFixed(0) + ',' + mainCamera.r35_1.g20_1.toFixed(0) + ',' + mainCamera.r35_1.h20_1.toFixed(0) + ')');
} catch(e) {
initError = e;
@@ -4053,9 +4053,9 @@
var origH37 = mainCamera.o37;
function applyFreeLookParams() {
mainCamera.s35_1.f20_1 = freePitch; // pitch (f)
mainCamera.s35_1.g20_1 = freeRoll; // roll (g) 保持初始值
mainCamera.s35_1.h20_1 = freeYaw; // yaw (h) 鼠标左右控制
mainCamera.u35_1.f20_1 = freePitch; // pitch (f)
mainCamera.u35_1.g20_1 = freeRoll; // roll (g) 保持初始值
mainCamera.u35_1.h20_1 = freeYaw; // yaw (h) 鼠标左右控制
mainCamera.r35_1.f20_1 = freePosX;
mainCamera.r35_1.g20_1 = freePosY;
mainCamera.r35_1.h20_1 = freePosZ;
@@ -4092,9 +4092,9 @@
function enableFreeLook() {
// 从当前相机参数初始化(平滑过渡)
// l35_1: f=pitch, g=roll, h=yaw
freePitch = mainCamera.s35_1.f20_1;
freeRoll = mainCamera.s35_1.g20_1; // roll 保持初始值
freeYaw = mainCamera.s35_1.h20_1; // yaw 鼠标控制
freePitch = mainCamera.u35_1.f20_1;
freeRoll = mainCamera.u35_1.g20_1; // roll 保持初始值
freeYaw = mainCamera.u35_1.h20_1; // yaw 鼠标控制
freePosX = mainCamera.r35_1.f20_1;
freePosY = mainCamera.r35_1.g20_1;
freePosZ = mainCamera.r35_1.h20_1;
@@ -4380,21 +4380,21 @@
// 皮肤字段:新 build 是 w14w_1;旧 build 是 t14l_1(新版 t14l_1 已改成悬停车体状态 Qmt)
var hullComp = FindComponentByField(tank, 'w14w_1') ||
FindComponentByField(tank, 't14l_1') ||
FindComponentByField(tank, 'u14l_1') ||
FindComponentByField(tank, 'w14x_1') ||
FindComponentByField(tank, 'p14l_1');
if (!hullComp) return null;
var skin = (hullComp.w14w_1 && hullComp.w14w_1.s17b_1) ? hullComp.w14w_1 :
(hullComp.t14l_1 && hullComp.t14l_1.s17b_1) ? hullComp.t14l_1 :
(hullComp.p14l_1 && hullComp.p14l_1.s17b_1) ? hullComp.p14l_1 : null;
var skin = (hullComp.w14w_1 && hullComp.w14w_1.g17r_1) ? hullComp.w14w_1 :
(hullComp.t14l_1 && hullComp.t14l_1.g17r_1) ? hullComp.t14l_1 :
(hullComp.p14l_1 && hullComp.p14l_1.g17r_1) ? hullComp.p14l_1 : null;
if (!skin) return null;
try {
var partCount = skin.s17b_1.e1();
var partCount = skin.g17r_1.e1();
for (var p = 0; p < partCount; p++) {
var part = skin.s17b_1.g1(p);
if (!part || !part.v17b_1) continue;
var nodeCount = part.v17b_1.e1();
var part = skin.g17r_1.g1(p);
if (!part || !part.j17r_1) continue;
var nodeCount = part.j17r_1.e1();
for (var n = 0; n < nodeCount; n++) {
var bpNode = part.v17b_1.g1(n);
var bpNode = part.j17r_1.g1(n);
if (!bpNode || !bpNode.n35_1) continue;
// 不按 g35_1 过滤:它是引擎的细节/淡出权重(0~1),不是幽灵标志,
// 过滤会漏掉低细节节点、导致取不到朝向
@@ -4428,10 +4428,10 @@
var scene = null, ff = null, rootNode = null, mainCamera = null, gl = null;
var initError = null;
try {
scene = gm.jyw().iyt_1;
ff = scene.fyo_1.d75_1;
rootNode = scene.eyp_1;
mainCamera = scene.hyp_1;
scene = gm.jyw().jz1_1;
ff = scene.gyw_1.d75_1;
rootNode = scene.fyx_1;
mainCamera = scene.iyx_1;
gl = ff.w39_1.b74_1;
if (!ff || !rootNode || !mainCamera || !gl) throw new Error('关键字段缺失');
} catch(e) {
@@ -5002,37 +5002,37 @@
try {
// 保存主相机参数
var sPitch = mainCamera.s35_1.f20_1;
var sRoll = mainCamera.s35_1.g20_1;
var sYaw = mainCamera.s35_1.h20_1;
var sPitch = mainCamera.u35_1.f20_1;
var sRoll = mainCamera.u35_1.g20_1;
var sYaw = mainCamera.u35_1.h20_1;
var sX = mainCamera.r35_1.f20_1;
var sY = mainCamera.r35_1.g20_1;
var sZ = mainCamera.r35_1.h20_1;
var sL36 = mainCamera.s36_1, sM36 = mainCamera.t36_1;
var sL36 = mainCamera.u36_1, sM36 = mainCamera.v36_1;
var sS36 = mainCamera.z36_1, sQ36 = mainCamera.x36_1, sR36 = mainCamera.y36_1;
// 设置俯瞰相机参数
// pitch=-π/2 朝下看,roll=0 不翻转,yaw=0 北朝上
mainCamera.s35_1.f20_1 = -Math.PI / 2;
mainCamera.s35_1.g20_1 = 0;
mainCamera.s35_1.h20_1 = 0;
mainCamera.u35_1.f20_1 = -Math.PI / 2;
mainCamera.u35_1.g20_1 = 0;
mainCamera.u35_1.h20_1 = 0;
mainCamera.r35_1.f20_1 = viewCenterX;
mainCamera.r35_1.g20_1 = viewCenterY;
mainCamera.r35_1.h20_1 = camHeight;
mainCamera.s36_1 = FBO_W;
mainCamera.t36_1 = FBO_H;
mainCamera.u36_1 = FBO_W;
mainCamera.v36_1 = FBO_H;
mainCamera.z36_1 = Config.fov;
mainCamera.x36_1 = Config.near;
mainCamera.y36_1 = Config.far;
mainCamera.o37();
// 禁用阴影/后处理
var savedX3n = ff.w38_1.e3o_1;
var savedY3n = ff.w38_1.f3o_1;
var savedZ3n = ff.w38_1.g3o_1;
ff.w38_1.e3o_1 = false;
ff.w38_1.f3o_1 = false;
ff.w38_1.g3o_1 = false;
var savedX3n = ff.y38_1.e3o_1;
var savedY3n = ff.y38_1.f3o_1;
var savedZ3n = ff.y38_1.k3o_1;
ff.y38_1.e3o_1 = false;
ff.y38_1.f3o_1 = false;
ff.y38_1.k3o_1 = false;
// 禁用 UI 层
var savedUiQueues = {};
@@ -5085,21 +5085,21 @@
origBindFramebuffer(gl.FRAMEBUFFER, mainFbo);
// 恢复渲染状态
ff.w38_1.e3o_1 = savedX3n;
ff.w38_1.f3o_1 = savedY3n;
ff.w38_1.g3o_1 = savedZ3n;
ff.y38_1.e3o_1 = savedX3n;
ff.y38_1.f3o_1 = savedY3n;
ff.y38_1.k3o_1 = savedZ3n;
for (var ui2 = 0; ui2 < uiLayerIndices.length; ui2++) {
ff.e39_1[uiLayerIndices[ui2]] = savedUiQueues[uiLayerIndices[ui2]];
}
// 恢复主相机
mainCamera.s35_1.f20_1 = sPitch;
mainCamera.s35_1.g20_1 = sRoll;
mainCamera.s35_1.h20_1 = sYaw;
mainCamera.u35_1.f20_1 = sPitch;
mainCamera.u35_1.g20_1 = sRoll;
mainCamera.u35_1.h20_1 = sYaw;
mainCamera.r35_1.f20_1 = sX;
mainCamera.r35_1.g20_1 = sY;
mainCamera.r35_1.h20_1 = sZ;
mainCamera.s36_1 = sL36; mainCamera.t36_1 = sM36;
mainCamera.u36_1 = sL36; mainCamera.v36_1 = sM36;
mainCamera.z36_1 = sS36; mainCamera.x36_1 = sQ36; mainCamera.y36_1 = sR36;
mainCamera.o37();
@@ -5981,7 +5981,7 @@
});
// ===== 电磁炮(RAILGUN / z4t)设置 =====
// 锁定/蓄力时长实时覆盖 window.__hornetLockSec__(游戏内 z4t.w187() 优先读它),
// 锁定/蓄力时长实时覆盖 window.__hornetLockSec__(游戏内 z4t.c18o() 优先读它),
// 拖动滑块**立即生效**,不需要重打包或刷新页面。
// 实测门槛:1.5s / 2.0s / 原版3~5s = 满伤;1.0s / 0.1s = 无伤害 ⇒ 门槛在 1.0~1.5s。
var rgSec = MakeSettingsSection('电磁炮设置');
+169 -169
View File
@@ -250,9 +250,9 @@
// 遍历 entity.wyj_1.r2a_1(Map<组件标识, 组件列表>),value 是列表类(s_),g1(0) 获取实际组件
// 注意:用 !== undefined 检查字段存在性,避免 falsy 值(0/""/null/false)漏判
function FindComponentByField(entity, fieldName) {
if (!entity || !entity.pyt_1 || !entity.pyt_1.s2a_1) return null;
if (!entity || !entity.qz1_1 || !entity.qz1_1.s2a_1) return null;
var result = null;
entity.pyt_1.s2a_1.forEach(function(valueList, key) {
entity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (result) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
@@ -262,7 +262,7 @@
return result;
}
// ===== 获取坦克位置(G$t 物理组件的 pz7_1 = O$向量) =====
// ===== 获取坦克位置(G$t 物理组件的 rzf_1 = O$向量) =====
// 返回 {x, y, z},x/y 水平面,z 高度
function GetTankPosition(tank) {
var physicsComp = FindComponentByField(tank, 'gzh_1');
@@ -280,21 +280,21 @@
// 状态枚举:0=DEAD, 1=DEAD_PHANTOM, 2=SEMI_ACTIVE, 3=ACTIVE, 4=DISABLED
// Yjt 特征:有 azs_1(状态机)和 vzr_1(状态枚举)字段
function GetTankState(tank) {
if (!tank || !tank.pyt_1 || !tank.pyt_1.s2a_1) return -1;
if (!tank || !tank.qz1_1 || !tank.qz1_1.s2a_1) return -1;
var tankComp = null;
tank.pyt_1.s2a_1.forEach(function(valueList, key) {
tank.qz1_1.s2a_1.forEach(function(valueList, key) {
if (tankComp) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && comp.t101_1 && comp.o101_1 !== undefined) tankComp = comp;
if (comp && comp.t101_1 && comp.k10c_1 !== undefined) tankComp = comp;
} catch(e) {}
});
if (tankComp && tankComp.o101_1) return tankComp.o101_1.k3_1;
if (tankComp && tankComp.k10c_1) return tankComp.k10c_1.k3_1;
return -1;
}
// 可见/战斗中的坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)
// 依据:引擎用 tankComponent.y147()(= SEMI_ACTIVE || ACTIVE)决定该坦克节点是否渲染,
// 依据:引擎用 tankComponent.s14j()(= SEMI_ACTIVE || ACTIVE)决定该坦克节点是否渲染,
// 只认 ACTIVE 会漏掉半活跃状态(出生/过渡)的坦克
function IsTankAlive(tank) {
var s = GetTankState(tank);
@@ -304,20 +304,20 @@
// ===== 获取坦克名称(yot 用户信息组件) =====
// s120_1 = userName, u120_1 = clanTag(可为null), t120_1 = userRank
function GetTankName(tank) {
var userComp = FindComponentByField(tank, 'k12a_1');
var userComp = FindComponentByField(tank, 'c12n_1');
if (!userComp) return null;
var name = userComp.k12a_1 || '';
var clanTag = userComp.m12a_1 || '';
var name = userComp.c12n_1 || '';
var clanTag = userComp.e12n_1 || '';
return clanTag ? (clanTag + ' ' + name) : name;
}
// ===== 获取坦克血量(Vkt 血量组件) =====
// f122_1 = 最大血量(max), g122_1 = 当前血量(current, 死亡时=0)
function GetTankHealth(tank) {
var healthComp = FindComponentByField(tank, 'y12b_1');
var healthComp = FindComponentByField(tank, 'q12o_1');
if (!healthComp) return null;
var max = healthComp.x12b_1 || 0;
var cur = healthComp.y12b_1 || 0;
var max = healthComp.p12o_1 || 0;
var cur = healthComp.q12o_1 || 0;
if (max <= 0) return null;
return { current: cur, max: max, percent: cur / max };
}
@@ -370,9 +370,9 @@
// checkPosition: 是否检查位置有效性(默认true;测试脚本传false以在死亡状态控制)
function GetPlayerTank(gm, checkPosition) {
if (checkPosition === undefined) checkPosition = true;
var t = gm.x100_1;
var t = gm.t10b_1;
if (t && (!checkPosition || GetTankPosition(t))) return t;
t = gm.y100_1;
t = gm.u10b_1;
if (t && (!checkPosition || GetTankPosition(t))) return t;
try {
var tl = gm.q100_1.r11l();
@@ -397,10 +397,10 @@
} catch(e) {}
}
try {
if (gm && gm.z100_1 && ZCt) {
if (gm && gm.v10b_1 && ZCt) {
var team = ZCt(tank);
if (team && gm.z100_1) {
return team.equals(gm.z100_1) && m2Fn ? m2Fn(team, gm.z100_1) : team.equals(gm.z100_1);
if (team && gm.v10b_1) {
return team.equals(gm.v10b_1) && m2Fn ? m2Fn(team, gm.v10b_1) : team.equals(gm.v10b_1);
}
}
} catch(e) {}
@@ -410,13 +410,13 @@
// ===== 获取相机信息($r/gq 相机组件) =====
// 遍历 GameMode entity 和所有坦克 entity 查找活跃相机组件
// 策略1:查找 $r/gq 相机组件(有 kym_1 位置 和 lym_1 方向)
// 策略2:查找 k7 相机控制器(有 qz9_1 和 gz9_1),从 gz9_1 获取相机组件
// 策略2:查找 k7 相机控制器(有 qz9_1 和 jzh_1),从 jzh_1 获取相机组件
// 返回 {yaw, pitch, fov, pos:{x,y,z}}
// 注意:lym_1.h20_1 是 roll(绕Z),lym_1.f20_1 是 pitch(绕X)
function GetCameraInfo(gm) {
var entities = [];
try {
var gameScene = gm.jyw().iyt_1;
var gameScene = gm.jyw().jz1_1;
var gmEntity = gameScene.xyu("GameMode");
if (gmEntity) entities.push(gmEntity);
} catch(e) {}
@@ -431,9 +431,9 @@
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (!entity || !entity.pyt_1 || !entity.pyt_1.s2a_1) continue;
if (!entity || !entity.qz1_1 || !entity.qz1_1.s2a_1) continue;
var found = null;
entity.pyt_1.s2a_1.forEach(function(valueList, key) {
entity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (found) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
@@ -478,13 +478,13 @@
function GetUMtComponent(gm) {
try {
var gmEntity = gm.jyw();
if (!gmEntity || !gmEntity.pyt_1 || !gmEntity.pyt_1.s2a_1) return null;
if (!gmEntity || !gmEntity.qz1_1 || !gmEntity.qz1_1.s2a_1) return null;
var uMt = null;
gmEntity.pyt_1.s2a_1.forEach(function(valueList, key) {
gmEntity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (uMt) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && typeof comp.m179 === 'function') uMt = comp;
if (comp && typeof comp.a17p === 'function') uMt = comp;
} catch(e) {}
});
return uMt;
@@ -514,24 +514,24 @@
y178_1: MkVec(0, 0, 0),
z178_1: MkVec(0, 0, 0),
a179_1: maxDist,
c179_1: null,
q17o_1: null,
b179_1: null,
d179: function(t, n, i, r, e) {
r17o: function(t, n, i, r, e) {
this.y178_1.k26(t);
this.z178_1.k26(n);
this.a179_1 = i;
this.c179_1 = r;
this.q17o_1 = r;
this.b179_1 = e;
},
d3: function() { this.b179_1 = null; }
};
var filter = {
o1co_1: { h1: function() { return false; }, d3: function() {} },
l1da_1: { h1: function() { return false; }, d3: function() {} },
w179: function() { return true; },
d3: function() { this.o1co_1.d3(); },
p1co: function() {}
d3: function() { this.l1da_1.d3(); },
m1da: function() {}
};
var hit = uMt.m179(startVec, dirVec, maxDist, result, filter);
var hit = uMt.a17p(startVec, dirVec, maxDist, result, filter);
return (hit && result.a179_1 < maxDist) ? result.a179_1 : -1;
} catch(e) {
return -1;
@@ -750,7 +750,7 @@
// ===== 获取坦克方向(Kkt 组件的 dzc_1) =====
function getTankDirection(tank) {
var hullComp = FindComponentByField(tank, 'vzl_1');
var hullComp = FindComponentByField(tank, 'qzv_1');
if (hullComp && hullComp.wzl_1) {
return {
x: hullComp.wzl_1.f20_1,
@@ -764,13 +764,13 @@
// ===== 获取相机方向(gq/$r 组件的 lym_1.h20_1 = 偏航角) =====
// 相机组件可能在 GameMode entity、玩家坦克或任何坦克上
// 策略1:查找 $r/gq 相机组件(有 kym_1 和 lym_1 字段)
// 策略2:查找 k7 相机控制器(有 qz9_1 和 gz9_1 字段),从 gz9_1 获取相机组件
// 策略2:查找 k7 相机控制器(有 qz9_1 和 jzh_1 字段),从 jzh_1 获取相机组件
function getCameraHeading() {
var entities = [];
// 1. GameMode entity
try {
var gameScene = gm.jyw().iyt_1;
var gameScene = gm.jyw().jz1_1;
var gmEntity = gameScene.xyu("GameMode");
if (gmEntity) entities.push(gmEntity);
} catch(e) {}
@@ -788,10 +788,10 @@
// 在每个 entity 上查找相机组件
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (!entity || !entity.pyt_1 || !entity.pyt_1.s2a_1) continue;
if (!entity || !entity.qz1_1 || !entity.qz1_1.s2a_1) continue;
var found = null;
entity.pyt_1.s2a_1.forEach(function(valueList, key) {
entity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (found) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
@@ -807,7 +807,7 @@
}
}
// 策略2:查找 k7 相机控制器(有 qz9_1 和 gz9_1 字段)
// 策略2:查找 k7 相机控制器(有 qz9_1 和 jzh_1 字段)
if (comp.jzj_1 && comp.zzi_1) {
var camComp = comp.zzi_1;
if (camComp && camComp.cyw_1 && camComp.dyw_1 &&
@@ -861,12 +861,12 @@
if (UMtComponent) return UMtComponent;
try {
var gmEntity = gm.jyw();
if (!gmEntity || !gmEntity.pyt_1 || !gmEntity.pyt_1.s2a_1) return null;
gmEntity.pyt_1.s2a_1.forEach(function(valueList, key) {
if (!gmEntity || !gmEntity.qz1_1 || !gmEntity.qz1_1.s2a_1) return null;
gmEntity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (UMtComponent) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && typeof comp.m179 === 'function') UMtComponent = comp;
if (comp && typeof comp.a17p === 'function') UMtComponent = comp;
} catch(e) {}
});
if (UMtComponent) console.log('[雷达] uMt 碰撞检测器已获取');
@@ -889,19 +889,19 @@
var dirVec = MkVec(dirX, dirY, dirZ);
var result = {
y178_1: MkVec(0,0,0), z178_1: MkVec(0,0,0),
a179_1: maxDist, c179_1: null, b179_1: null,
d179: function(t, n, i, r, e) {
a179_1: maxDist, q17o_1: null, b179_1: null,
r17o: function(t, n, i, r, e) {
this.y178_1.k26(t); this.z178_1.k26(n);
this.a179_1 = i; this.c179_1 = r; this.b179_1 = e;
this.a179_1 = i; this.q17o_1 = r; this.b179_1 = e;
},
d3: function() { this.b179_1 = null; }
};
var filter = {
o1co_1: { h1: function() { return false; }, d3: function() {} },
l1da_1: { h1: function() { return false; }, d3: function() {} },
w179: function() { return true; },
d3: function() {}, p1co: function() {}
d3: function() {}, m1da: function() {}
};
var hit = uMt.m179(startVec, dirVec, maxDist, result, filter);
var hit = uMt.a17p(startVec, dirVec, maxDist, result, filter);
return (hit && result.a179_1 < maxDist) ? result.a179_1 : -1;
} catch(e) {
return -1;
@@ -1460,7 +1460,7 @@
ctx.textAlign = 'left';
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ' Bot:' + botCount + ')', 5, 12);
if (radar.playerFound) {
ctx.fillText('Player: ' + (playerTank ? playerTank.hyt_1 : '?'), 5, 24);
ctx.fillText('Player: ' + (playerTank ? playerTank.iz1_1 : '?'), 5, 24);
} else {
ctx.fillText('Player: NOT FOUND', 5, 24);
}
@@ -1695,12 +1695,12 @@
}
// ===== 获取 KMt / TDt 渲染组件 =====
// 新 build:车身皮肤组件字段是 w14w_1(kDt(t)=t.w14w_1,缺失报 "skin";RDt.v16b 里赋值)
// 旧 build:u14l_1 / t14l_1 / p14l_1(新版 t14l_1 已改成悬停车体状态 Qmt,务必别再当皮肤用)
// 新 build:车身皮肤组件字段是 w14w_1(kDt(t)=t.w14w_1,缺失报 "skin";RDt.j16r 里赋值)
// 旧 build:w14x_1 / t14l_1 / p14l_1(新版 t14l_1 已改成悬停车体状态 Qmt,务必别再当皮肤用)
function GetKMtComponent(entity) {
var comp = FindComponentByField(entity, 'w14w_1');
if (comp) return comp;
comp = FindComponentByField(entity, 'u14l_1');
comp = FindComponentByField(entity, 'w14x_1');
if (comp) return comp;
comp = FindComponentByField(entity, 't14l_1');
if (comp) return comp;
@@ -1708,13 +1708,13 @@
return comp;
}
// 取车身皮肤对象(含 s17b_1 部件表),跨版本兼容;stats 用于诊断来源
// 取车身皮肤对象(含 g17r_1 部件表),跨版本兼容;stats 用于诊断来源
function GetHullSkin(tank, stats) {
var comp = GetKMtComponent(tank);
if (!comp) { if (stats) stats.hullSource = '无组件'; return null; }
if (comp.w14w_1 && comp.w14w_1.s17b_1) { if (stats) stats.hullSource = 'w14w_1'; return comp.w14w_1; } // 新 build
if (comp.t14l_1 && comp.t14l_1.s17b_1) { if (stats) stats.hullSource = 't14l_1'; return comp.t14l_1; } // 旧 build
if (comp.p14l_1 && comp.p14l_1.s17b_1) { if (stats) stats.hullSource = 'p14l_1'; return comp.p14l_1; } // 旧 build
if (comp.w14w_1 && comp.w14w_1.g17r_1) { if (stats) stats.hullSource = 'w14w_1'; return comp.w14w_1; } // 新 build
if (comp.t14l_1 && comp.t14l_1.g17r_1) { if (stats) stats.hullSource = 't14l_1'; return comp.t14l_1; } // 旧 build
if (comp.p14l_1 && comp.p14l_1.g17r_1) { if (stats) stats.hullSource = 'p14l_1'; return comp.p14l_1; } // 旧 build
if (stats) stats.hullSource = '有组件但无皮肤';
return null;
}
@@ -1728,14 +1728,14 @@
// ===== 从GPU读取顶点位置数据(缓冲区[0]) =====
function ReadVertexPositionsFromTp(tp) {
if (!tp || !tp.t4w_1) return null;
var tl = tp.t4w_1.g1(0);
if (!tp || !tp.x4w_1) return null;
var tl = tp.x4w_1.g1(0);
if (!tl || !tl.d3x_1) return null;
var vq = tl.d3x_1;
var bs = vq.s3h_1;
if (!bs || !bs.b74_1) return null;
var gl = bs.b74_1;
var webglBuf = vq.r3x_1 && vq.r3x_1.z73_1;
var webglBuf = vq.v3x_1 && vq.v3x_1.z73_1;
if (!webglBuf) return null;
gl.bindBuffer(gl.ARRAY_BUFFER, webglBuf);
var bufSize = gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE);
@@ -1753,12 +1753,12 @@
var allIndices = [];
for (var m = 0; m < meshCount; m++) {
var il = tp.y4w_1.g1(m);
if (!il || !il.q3p_1) continue;
var fq = il.q3p_1;
if (!il || !il.u3p_1) continue;
var fq = il.u3p_1;
var bs = fq.s3h_1;
if (!bs || !bs.b74_1) continue;
var gl = bs.b74_1;
var webglBuf = fq.j3x_1 && fq.j3x_1.z73_1;
var webglBuf = fq.n3x_1 && fq.n3x_1.z73_1;
if (!webglBuf) continue;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webglBuf);
var bufSize = gl.getBufferParameter(gl.ELEMENT_ARRAY_BUFFER, gl.BUFFER_SIZE);
@@ -1815,25 +1815,25 @@
function CollectMeshNodes(bpNode, nodes, depth, group, stats) {
if (!bpNode || depth > 5) return;
if (stats) stats.seen++;
var name = bpNode.e35_1 || '';
if (bpNode.t3m_1) {
var name = bpNode.g35_1 || '';
if (bpNode.v3m_1) {
if (stats) stats.hasMesh++;
var gpuData = GetGpuData(bpNode.t3m_1);
var gpuData = GetGpuData(bpNode.v3m_1);
if (gpuData) {
if (stats) stats.gpuOk++;
nodes.push({
name: name, node: bpNode, tp: bpNode.t3m_1,
name: name, node: bpNode, tp: bpNode.v3m_1,
positions: gpuData.positions, indices: gpuData.indices, stride: gpuData.stride, group: group
});
} else if (stats) stats.gpuFail++;
}
if (bpNode.q4x_1 && typeof bpNode.q4x_1.e1 === 'function') {
if (bpNode.u4x_1 && typeof bpNode.u4x_1.e1 === 'function') {
try {
var lodCount = bpNode.q4x_1.e1();
var lodCount = bpNode.u4x_1.e1();
for (var lod = 0; lod < lodCount && lod < 1; lod++) {
var lodLevel = bpNode.q4x_1.g1(lod);
var lodLevel = bpNode.u4x_1.g1(lod);
if (!lodLevel) continue;
var lodTp = lodLevel.t3m_1 || lodLevel.v3m_1;
var lodTp = lodLevel.v3m_1 || lodLevel.v3m_1;
if (!lodTp) continue;
var lodGpuData = GetGpuData(lodTp);
if (lodGpuData) {
@@ -1863,14 +1863,14 @@
var skin = GetHullSkin(tank, stats);
if (skin) {
try {
var partCount = skin.s17b_1.e1();
var partCount = skin.g17r_1.e1();
if (stats) stats.hullParts = partCount;
for (var p = 0; p < partCount; p++) {
var part = skin.s17b_1.g1(p);
if (!part || !part.v17b_1) continue;
var nodeCount = part.v17b_1.e1();
var part = skin.g17r_1.g1(p);
if (!part || !part.j17r_1) continue;
var nodeCount = part.j17r_1.e1();
for (var n = 0; n < nodeCount; n++) {
var bpNode = part.v17b_1.g1(n);
var bpNode = part.j17r_1.g1(n);
if (!bpNode) continue;
CollectMeshNodes(bpNode, nodes, 0, 'hull', stats ? stats.hull : null);
}
@@ -2437,7 +2437,7 @@
var physicsComp = FindComponentByField(tank, 'gzh_1');
if (!physicsComp || !physicsComp.gzh_1) continue;
var tankState = GetTankState(tank);
// 可见坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)(引擎 y147() 判定),0/1/4 才跳过
// 可见坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)(引擎 s14j() 判定),0/1/4 才跳过
if (tankState !== 2 && tankState !== 3) continue;
var pos = {
@@ -2449,7 +2449,7 @@
// 本帧该坦克是否在移动(供「残留节点」检测:坦克在动而节点矩阵不动 = 旧位置遗留)
// 用位移的指数滑动平均,而不是「单帧位移 > 10 单位」——后者对慢速移动几乎永远为假,
// 会让残留检测形同虚设(残留漏掉的根因就在这里)
var tankId = tank.hyt_1;
var tankId = tank.iz1_1;
var prevPos = TankPrevPos.get(tankId);
var tankMove = 0;
if (prevPos) {
@@ -2467,7 +2467,7 @@
if (distance > 50000) continue;
var friendly = IsFriendly(tank, playerTank);
var tankName = GetTankName(tank) || ('ID:' + tank.hyt_1);
var tankName = GetTankName(tank) || ('ID:' + tank.iz1_1);
// 根据 HighlightMode 判断是否渲染该坦克
if (!ShouldRender(tankName)) continue;
// 颜色按队伍:友方=蓝,敌方=红
@@ -2736,11 +2736,11 @@
var initError = null;
try {
scene = gm.jyw().iyt_1;
scene = gm.jyw().jz1_1;
console.log('[后视] 场景对象:', scene);
// hC 渲染器实例(jr.lye_1)
var renderer = scene.fyo_1;
var renderer = scene.gyw_1;
console.log('[后视] 渲染器:', renderer);
// Ff 绘制器实例(hC.r74_1)
@@ -2748,11 +2748,11 @@
console.log('[后视] Ff绘制器:', ff);
// 场景根节点(jr.kyf_1)
rootNode = scene.eyp_1;
rootNode = scene.fyx_1;
console.log('[后视] 根节点:', rootNode);
// 主相机 Ha 实例(jr.nyf_1)
mainCamera = scene.hyp_1;
mainCamera = scene.iyx_1;
console.log('[后视] 主相机:', mainCamera);
// 游戏 gl context(Ff.p39_1.p73_1 = BS.p73_1)
@@ -2764,11 +2764,11 @@
}
// 探测相机字段
console.log('[后视] 相机s35_1:', mainCamera.s35_1);
console.log('[后视] 相机u35_1:', mainCamera.u35_1);
console.log('[后视] 相机r35_1:', mainCamera.r35_1);
console.log('[后视] 相机b37_1:', mainCamera.b37_1);
if (!mainCamera.s35_1 || !mainCamera.r35_1) {
if (!mainCamera.u35_1 || !mainCamera.r35_1) {
throw new Error('相机字段缺失');
}
@@ -2964,14 +2964,14 @@
var camPosZ = playerPos.z + Config.cameraHeight;
// ===== 保存主相机参数 =====
var savedPitch = mainCamera.s35_1.f20_1;
var savedYaw = mainCamera.s35_1.g20_1;
var savedRoll = mainCamera.s35_1.h20_1;
var savedPitch = mainCamera.u35_1.f20_1;
var savedYaw = mainCamera.u35_1.g20_1;
var savedRoll = mainCamera.u35_1.h20_1;
var savedX = mainCamera.r35_1.f20_1;
var savedY = mainCamera.r35_1.g20_1;
var savedZ = mainCamera.r35_1.h20_1;
var savedL36 = mainCamera.s36_1;
var savedM36 = mainCamera.t36_1;
var savedL36 = mainCamera.u36_1;
var savedM36 = mainCamera.v36_1;
var savedS36 = mainCamera.z36_1;
var savedQ36 = mainCamera.x36_1;
var savedR36 = mainCamera.y36_1;
@@ -2985,14 +2985,14 @@
// g=π 使水平方向反向(朝后看),h=yaw+π 保持水平视角正确
// f=-pitch 使垂直方向与主视一致(低头看后方地形)
// up 朝下 → FBO 画面颠倒 → GL readback Y 翻转修正
mainCamera.s35_1.f20_1 = rearPitch;
mainCamera.s35_1.g20_1 = Math.PI;
mainCamera.s35_1.h20_1 = camInfo.yaw + Math.PI;
mainCamera.u35_1.f20_1 = rearPitch;
mainCamera.u35_1.g20_1 = Math.PI;
mainCamera.u35_1.h20_1 = camInfo.yaw + Math.PI;
mainCamera.r35_1.f20_1 = camPosX;
mainCamera.r35_1.g20_1 = camPosY;
mainCamera.r35_1.h20_1 = camPosZ;
mainCamera.s36_1 = rw;
mainCamera.t36_1 = rh;
mainCamera.u36_1 = rw;
mainCamera.v36_1 = rh;
mainCamera.z36_1 = Config.fov;
mainCamera.x36_1 = Config.near;
mainCamera.y36_1 = Config.far;
@@ -3004,14 +3004,14 @@
var rearViewMatrix = new Float32Array(mainCamera.b37_1);
// ===== 保存并禁用阴影/后处理(避免它们切换 FBO 覆盖 rearFbo)=====
// p38_1.x3n_1 控制 z39_1(阴影),y3n_1 控制 c3a_1/d3a_1(后处理),z3n_1 控制 f3a_1
// p38_1.b3o_1 控制 z39_1(阴影),c3o_1 控制 c3a_1/d3a_1(后处理),z3n_1 控制 f3a_1
// 禁用后 y3s 只执行主场景渲染 z3k,跳过所有 FBO 切换的 pass
var savedX3n = ff.w38_1.e3o_1;
var savedY3n = ff.w38_1.f3o_1;
var savedZ3n = ff.w38_1.g3o_1;
ff.w38_1.e3o_1 = false;
ff.w38_1.f3o_1 = false;
ff.w38_1.g3o_1 = false;
var savedX3n = ff.y38_1.e3o_1;
var savedY3n = ff.y38_1.f3o_1;
var savedZ3n = ff.y38_1.k3o_1;
ff.y38_1.e3o_1 = false;
ff.y38_1.f3o_1 = false;
ff.y38_1.k3o_1 = false;
// ===== 禁用 UI 渲染层(防止技能条等 UI 混入后视 FBO)=====
// 保存 UI 层队列,替换为空假对象,y3s 后恢复
@@ -3085,9 +3085,9 @@
// ===== 恢复阴影/后处理(异常时也要恢复)=====
try {
if (typeof savedX3n !== 'undefined') {
ff.w38_1.e3o_1 = savedX3n;
ff.w38_1.f3o_1 = savedY3n;
ff.w38_1.g3o_1 = savedZ3n;
ff.y38_1.e3o_1 = savedX3n;
ff.y38_1.f3o_1 = savedY3n;
ff.y38_1.k3o_1 = savedZ3n;
}
} catch(e) {
console.error('[后视] 恢复阴影/后处理失败:', e.message);
@@ -3107,14 +3107,14 @@
// ===== 恢复主相机参数 =====
try {
mainCamera.s35_1.f20_1 = savedPitch;
mainCamera.s35_1.g20_1 = savedYaw;
mainCamera.s35_1.h20_1 = savedRoll;
mainCamera.u35_1.f20_1 = savedPitch;
mainCamera.u35_1.g20_1 = savedYaw;
mainCamera.u35_1.h20_1 = savedRoll;
mainCamera.r35_1.f20_1 = savedX;
mainCamera.r35_1.g20_1 = savedY;
mainCamera.r35_1.h20_1 = savedZ;
mainCamera.s36_1 = savedL36;
mainCamera.t36_1 = savedM36;
mainCamera.u36_1 = savedL36;
mainCamera.v36_1 = savedM36;
mainCamera.z36_1 = savedS36;
mainCamera.x36_1 = savedQ36;
mainCamera.y36_1 = savedR36;
@@ -3466,12 +3466,12 @@
if (UMtComponent) return UMtComponent;
try {
var gmEntity = gm.jyw();
if (!gmEntity || !gmEntity.pyt_1 || !gmEntity.pyt_1.s2a_1) return null;
gmEntity.pyt_1.s2a_1.forEach(function(valueList, key) {
if (!gmEntity || !gmEntity.qz1_1 || !gmEntity.qz1_1.s2a_1) return null;
gmEntity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (UMtComponent) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && typeof comp.m179 === 'function') UMtComponent = comp;
if (comp && typeof comp.a17p === 'function') UMtComponent = comp;
} catch(e) {}
});
if (UMtComponent) console.log('[瞄准] uMt 碰撞检测器已获取');
@@ -3516,26 +3516,26 @@
y178_1: MkVec(0,0,0),
z178_1: MkVec(0,0,0),
a179_1: maxDist,
c179_1: null,
q17o_1: null,
b179_1: null,
d179: function(t, n, i, r, e) {
r17o: function(t, n, i, r, e) {
this.y178_1.k26(t);
this.z178_1.k26(n);
this.a179_1 = i;
this.c179_1 = r;
this.q17o_1 = r;
this.b179_1 = e;
},
d3: function() { this.b179_1 = null; }
};
var filter = {
o1co_1: { h1: function() { return false; }, d3: function() {} },
l1da_1: { h1: function() { return false; }, d3: function() {} },
w179: function() { return true; },
d3: function() { this.o1co_1.d3(); },
p1co: function() {}
d3: function() { this.l1da_1.d3(); },
m1da: function() {}
};
var hit = uMt.m179(startVec, dirVec, maxDist, result, filter);
var hit = uMt.a17p(startVec, dirVec, maxDist, result, filter);
blocked = !!hit && result.a179_1 < (maxDist - 50);
RaycastFailCount = 0;
} catch(e) {
@@ -3648,19 +3648,19 @@
if (aimInfo.angle >= aimThreshold) continue;
// 墙体阻隔判断
var blocked = IsLineOfSightBlocked(pos, playerPos, tank.hyt_1, frameCount);
var blocked = IsLineOfSightBlocked(pos, playerPos, tank.iz1_1, frameCount);
if (blocked) continue;
// 记录威胁
var proj = Project3D(pos, camInfo.pos, camInfo.yaw, camInfo.pitch, camInfo.fov, screenW, screenH);
var tankName = GetTankName(tank) || ('ID:' + tank.hyt_1);
var tankName = GetTankName(tank) || ('ID:' + tank.iz1_1);
threats.push({
pos: pos,
distance: aimInfo.distance,
angle: aimInfo.angle,
turretDir: aimInfo.turretDir,
screenProj: proj,
tankId: tank.hyt_1,
tankId: tank.iz1_1,
tankName: tankName
});
}
@@ -4019,14 +4019,14 @@
var initError = null;
try {
scene = gm.jyw().iyt_1;
mainCamera = scene.hyp_1;
ff = scene.fyo_1.d75_1;
if (!mainCamera || !mainCamera.s35_1 || !mainCamera.r35_1 || !mainCamera.o37) {
scene = gm.jyw().jz1_1;
mainCamera = scene.iyx_1;
ff = scene.gyw_1.d75_1;
if (!mainCamera || !mainCamera.u35_1 || !mainCamera.r35_1 || !mainCamera.o37) {
throw new Error('相机字段缺失');
}
console.log('[自由视角] 主相机:', mainCamera.constructor.name,
'l35=(' + mainCamera.s35_1.f20_1.toFixed(2) + ',' + mainCamera.s35_1.g20_1.toFixed(2) + ',' + mainCamera.s35_1.h20_1.toFixed(2) + ')',
'l35=(' + mainCamera.u35_1.f20_1.toFixed(2) + ',' + mainCamera.u35_1.g20_1.toFixed(2) + ',' + mainCamera.u35_1.h20_1.toFixed(2) + ')',
'k35=(' + mainCamera.r35_1.f20_1.toFixed(0) + ',' + mainCamera.r35_1.g20_1.toFixed(0) + ',' + mainCamera.r35_1.h20_1.toFixed(0) + ')');
} catch(e) {
initError = e;
@@ -4053,9 +4053,9 @@
var origH37 = mainCamera.o37;
function applyFreeLookParams() {
mainCamera.s35_1.f20_1 = freePitch; // pitch (f)
mainCamera.s35_1.g20_1 = freeRoll; // roll (g) 保持初始值
mainCamera.s35_1.h20_1 = freeYaw; // yaw (h) 鼠标左右控制
mainCamera.u35_1.f20_1 = freePitch; // pitch (f)
mainCamera.u35_1.g20_1 = freeRoll; // roll (g) 保持初始值
mainCamera.u35_1.h20_1 = freeYaw; // yaw (h) 鼠标左右控制
mainCamera.r35_1.f20_1 = freePosX;
mainCamera.r35_1.g20_1 = freePosY;
mainCamera.r35_1.h20_1 = freePosZ;
@@ -4092,9 +4092,9 @@
function enableFreeLook() {
// 从当前相机参数初始化(平滑过渡)
// l35_1: f=pitch, g=roll, h=yaw
freePitch = mainCamera.s35_1.f20_1;
freeRoll = mainCamera.s35_1.g20_1; // roll 保持初始值
freeYaw = mainCamera.s35_1.h20_1; // yaw 鼠标控制
freePitch = mainCamera.u35_1.f20_1;
freeRoll = mainCamera.u35_1.g20_1; // roll 保持初始值
freeYaw = mainCamera.u35_1.h20_1; // yaw 鼠标控制
freePosX = mainCamera.r35_1.f20_1;
freePosY = mainCamera.r35_1.g20_1;
freePosZ = mainCamera.r35_1.h20_1;
@@ -4380,21 +4380,21 @@
// 皮肤字段:新 build 是 w14w_1;旧 build 是 t14l_1(新版 t14l_1 已改成悬停车体状态 Qmt)
var hullComp = FindComponentByField(tank, 'w14w_1') ||
FindComponentByField(tank, 't14l_1') ||
FindComponentByField(tank, 'u14l_1') ||
FindComponentByField(tank, 'w14x_1') ||
FindComponentByField(tank, 'p14l_1');
if (!hullComp) return null;
var skin = (hullComp.w14w_1 && hullComp.w14w_1.s17b_1) ? hullComp.w14w_1 :
(hullComp.t14l_1 && hullComp.t14l_1.s17b_1) ? hullComp.t14l_1 :
(hullComp.p14l_1 && hullComp.p14l_1.s17b_1) ? hullComp.p14l_1 : null;
var skin = (hullComp.w14w_1 && hullComp.w14w_1.g17r_1) ? hullComp.w14w_1 :
(hullComp.t14l_1 && hullComp.t14l_1.g17r_1) ? hullComp.t14l_1 :
(hullComp.p14l_1 && hullComp.p14l_1.g17r_1) ? hullComp.p14l_1 : null;
if (!skin) return null;
try {
var partCount = skin.s17b_1.e1();
var partCount = skin.g17r_1.e1();
for (var p = 0; p < partCount; p++) {
var part = skin.s17b_1.g1(p);
if (!part || !part.v17b_1) continue;
var nodeCount = part.v17b_1.e1();
var part = skin.g17r_1.g1(p);
if (!part || !part.j17r_1) continue;
var nodeCount = part.j17r_1.e1();
for (var n = 0; n < nodeCount; n++) {
var bpNode = part.v17b_1.g1(n);
var bpNode = part.j17r_1.g1(n);
if (!bpNode || !bpNode.n35_1) continue;
// 不按 g35_1 过滤:它是引擎的细节/淡出权重(0~1),不是幽灵标志,
// 过滤会漏掉低细节节点、导致取不到朝向
@@ -4428,10 +4428,10 @@
var scene = null, ff = null, rootNode = null, mainCamera = null, gl = null;
var initError = null;
try {
scene = gm.jyw().iyt_1;
ff = scene.fyo_1.d75_1;
rootNode = scene.eyp_1;
mainCamera = scene.hyp_1;
scene = gm.jyw().jz1_1;
ff = scene.gyw_1.d75_1;
rootNode = scene.fyx_1;
mainCamera = scene.iyx_1;
gl = ff.w39_1.b74_1;
if (!ff || !rootNode || !mainCamera || !gl) throw new Error('关键字段缺失');
} catch(e) {
@@ -5002,37 +5002,37 @@
try {
// 保存主相机参数
var sPitch = mainCamera.s35_1.f20_1;
var sRoll = mainCamera.s35_1.g20_1;
var sYaw = mainCamera.s35_1.h20_1;
var sPitch = mainCamera.u35_1.f20_1;
var sRoll = mainCamera.u35_1.g20_1;
var sYaw = mainCamera.u35_1.h20_1;
var sX = mainCamera.r35_1.f20_1;
var sY = mainCamera.r35_1.g20_1;
var sZ = mainCamera.r35_1.h20_1;
var sL36 = mainCamera.s36_1, sM36 = mainCamera.t36_1;
var sL36 = mainCamera.u36_1, sM36 = mainCamera.v36_1;
var sS36 = mainCamera.z36_1, sQ36 = mainCamera.x36_1, sR36 = mainCamera.y36_1;
// 设置俯瞰相机参数
// pitch=-π/2 朝下看,roll=0 不翻转,yaw=0 北朝上
mainCamera.s35_1.f20_1 = -Math.PI / 2;
mainCamera.s35_1.g20_1 = 0;
mainCamera.s35_1.h20_1 = 0;
mainCamera.u35_1.f20_1 = -Math.PI / 2;
mainCamera.u35_1.g20_1 = 0;
mainCamera.u35_1.h20_1 = 0;
mainCamera.r35_1.f20_1 = viewCenterX;
mainCamera.r35_1.g20_1 = viewCenterY;
mainCamera.r35_1.h20_1 = camHeight;
mainCamera.s36_1 = FBO_W;
mainCamera.t36_1 = FBO_H;
mainCamera.u36_1 = FBO_W;
mainCamera.v36_1 = FBO_H;
mainCamera.z36_1 = Config.fov;
mainCamera.x36_1 = Config.near;
mainCamera.y36_1 = Config.far;
mainCamera.o37();
// 禁用阴影/后处理
var savedX3n = ff.w38_1.e3o_1;
var savedY3n = ff.w38_1.f3o_1;
var savedZ3n = ff.w38_1.g3o_1;
ff.w38_1.e3o_1 = false;
ff.w38_1.f3o_1 = false;
ff.w38_1.g3o_1 = false;
var savedX3n = ff.y38_1.e3o_1;
var savedY3n = ff.y38_1.f3o_1;
var savedZ3n = ff.y38_1.k3o_1;
ff.y38_1.e3o_1 = false;
ff.y38_1.f3o_1 = false;
ff.y38_1.k3o_1 = false;
// 禁用 UI 层
var savedUiQueues = {};
@@ -5085,21 +5085,21 @@
origBindFramebuffer(gl.FRAMEBUFFER, mainFbo);
// 恢复渲染状态
ff.w38_1.e3o_1 = savedX3n;
ff.w38_1.f3o_1 = savedY3n;
ff.w38_1.g3o_1 = savedZ3n;
ff.y38_1.e3o_1 = savedX3n;
ff.y38_1.f3o_1 = savedY3n;
ff.y38_1.k3o_1 = savedZ3n;
for (var ui2 = 0; ui2 < uiLayerIndices.length; ui2++) {
ff.e39_1[uiLayerIndices[ui2]] = savedUiQueues[uiLayerIndices[ui2]];
}
// 恢复主相机
mainCamera.s35_1.f20_1 = sPitch;
mainCamera.s35_1.g20_1 = sRoll;
mainCamera.s35_1.h20_1 = sYaw;
mainCamera.u35_1.f20_1 = sPitch;
mainCamera.u35_1.g20_1 = sRoll;
mainCamera.u35_1.h20_1 = sYaw;
mainCamera.r35_1.f20_1 = sX;
mainCamera.r35_1.g20_1 = sY;
mainCamera.r35_1.h20_1 = sZ;
mainCamera.s36_1 = sL36; mainCamera.t36_1 = sM36;
mainCamera.u36_1 = sL36; mainCamera.v36_1 = sM36;
mainCamera.z36_1 = sS36; mainCamera.x36_1 = sQ36; mainCamera.y36_1 = sR36;
mainCamera.o37();
@@ -5981,7 +5981,7 @@
});
// ===== 电磁炮(RAILGUN / z4t)设置 =====
// 锁定/蓄力时长实时覆盖 window.__hornetLockSec__(游戏内 z4t.w187() 优先读它),
// 锁定/蓄力时长实时覆盖 window.__hornetLockSec__(游戏内 z4t.c18o() 优先读它),
// 拖动滑块**立即生效**,不需要重打包或刷新页面。
// 实测门槛:1.5s / 2.0s / 原版3~5s = 满伤;1.0s / 0.1s = 无伤害 ⇒ 门槛在 1.0~1.5s。
var rgSec = MakeSettingsSection('电磁炮设置');
+100
View File
@@ -0,0 +1,100 @@
// 临时脚本:按 tmp_symbol_map.json 的映射,批量替换 tools/hornet_*.js 里的符号名
// 用法:node tools/tmp_apply_symbol_map.js
// 安全规则(上一版全量替换误伤了 function/return/window/length 等 JS 关键字与内置名):
// ① 旧名必须是"长名或含下划线"(>=4 字符 或 含 '_')—— 游戏符号基本都长这样;
// ② 旧名/新名都不能落在 JS 关键字/内置名黑名单里;
// ③ 只替换独立标识符(带词边界)。
const fs = require('fs');
const path = require('path');
const MapPath = path.resolve(__dirname, '..', '3DTank', 'tmp_symbol_map.json');
const Map = (require(MapPath)._merged) || {};
// JS 关键字 + 内置名 + 常见通用词:绝不能参与替换
const BLACK = new Set([
'function', 'return', 'var', 'let', 'const', 'null', 'undefined', 'true', 'false', 'this',
'typeof', 'instanceof', 'new', 'delete', 'void', 'in', 'of', 'if', 'else', 'for', 'while',
'do', 'switch', 'case', 'break', 'continue', 'throw', 'try', 'catch', 'finally', 'class',
'extends', 'super', 'yield', 'await', 'async', 'default', 'export', 'import',
'window', 'document', 'console', 'Math', 'Object', 'Array', 'String', 'Number', 'Boolean',
'JSON', 'Date', 'Error', 'Promise', 'Map', 'Set', 'Symbol', 'Proxy', 'Reflect',
'length', 'name', 'value', 'text', 'call', 'apply', 'bind', 'prototype', 'constructor',
'toString', 'valueOf', 'equals', 'hashCode', 'push', 'pop', 'slice', 'splice', 'indexOf',
'forEach', 'filter', 'reduce', 'join', 'split', 'replace', 'match', 'test', 'keys', 'values',
'entries', 'has', 'get', 'set', 'add', 'clear', 'size', 'run', 'self', 'globalThis',
'requestAnimationFrame', 'setTimeout', 'setInterval', 'parseInt', 'parseFloat', 'isNaN',
'NaN', 'Infinity', 'arguments', 'prototype_', 'undefined_',
]);
// ===== 双向校验用的"新 bundle 符号表" =====
// 背景:map_symbols 的投票在"通用字段名"上会算错(例如把未变的 f20_1 投成 w9p_1)。
// 这里直接拿新 bundle 原文做事实校验:
// ① 旧名在新 bundle 里**仍然存在** → 说明它根本没变,跳过(保守,避免误改);
// ② 新名在新 bundle 里**不存在** → 说明这条映射是错的,丢弃。
const BUNDLE_PATH = path.resolve(__dirname, '..', 'main.7cfa4058.js');
const BUNDLE = fs.existsSync(BUNDLE_PATH) ? fs.readFileSync(BUNDLE_PATH, 'utf8') : '';
const CountCache = {};
function CountInBundle(Name) {
if (!BUNDLE) return 1; // 拿不到 bundle 就不做校验(退回旧行为)
if (CountCache[Name] !== undefined) return CountCache[Name];
const Re = new RegExp('(?<![A-Za-z0-9_$])' + Name.replace(/\$/g, '\\$') + '(?![A-Za-z0-9_$])', 'g');
const M = BUNDLE.match(Re);
CountCache[Name] = M ? M.length : 0;
return CountCache[Name];
}
// 收集要替换的条目
const Entries = [];
const Skipped = { keeps: [], bad: [] };
for (const K of Object.keys(Map)) {
const V = Map[K];
if (typeof V !== 'string' || !V || V === K) continue;
if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(K)) continue;
if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(V)) continue;
if (BLACK.has(K) || BLACK.has(V)) continue;
if (K.length < 4 && K.indexOf('_') < 0) continue; // 规则①:长名或含下划线
// 规则④:游戏符号的命名特征 —— 必须含数字,或以 _数字 结尾(如 pyt_1 / q100_1 / r11l / cyw_1)。
// 这样能排除工具自身的普通英文单词变量(placeholder / mode / length 之类)。
if (!/[0-9]/.test(K) && !/_[0-9]+$/.test(K)) continue;
// 规则⑤/⑥:双向校验
if (CountInBundle(K) > 0) { Skipped.keeps.push(K); continue; }
if (CountInBundle(V) === 0) { Skipped.bad.push(K + '→' + V); continue; }
Entries.push([K, V]);
}
if (Skipped.keeps.length) console.log('跳过(旧名在新版仍存在,视为未变) ' + Skipped.keeps.length + ' 个: ' + Skipped.keeps.slice(0, 20).join(' ') + (Skipped.keeps.length > 20 ? ' …' : ''));
if (Skipped.bad.length) console.log('丢弃(新名在新版不存在,映射有误) ' + Skipped.bad.length + ' 条: ' + Skipped.bad.slice(0, 20).join(' ') + (Skipped.bad.length > 20 ? ' …' : ''));
// 长符号优先,避免短符号先吃掉长符号的一部分
Entries.sort((A, B) => B[0].length - A[0].length);
const Dir = path.resolve(__dirname);
const Files = fs.readdirSync(Dir).filter((F) => /^hornet_.*\.js$/.test(F));
// 单遍替换:一个正则同时匹配所有旧名,回调里查映射。
// 这样能避免"上一轮的替换结果又被下一轮规则二次替换"(映射表里新旧符号可能同名复用,会造成链式污染)。
const Alt = new RegExp(
'(?<![A-Za-z0-9_$])(' + Entries.map((E) => E[0].replace(/\$/g, '\\$')).join('|') + ')(?![A-Za-z0-9_$])',
'g'
);
let HitsOf = {}; // 注意:别用 new Map()——本文件里 Map 已被映射表变量占用
let TotalHits = 0;
for (const F of Files) {
const P = path.join(Dir, F);
const Before = fs.readFileSync(P, 'utf8');
HitsOf = {};
const S = Before.replace(Alt, (M) => {
const V = Map[M];
if (!V || V === M) return M;
HitsOf[M + '→' + V] = (HitsOf[M + '→' + V] || 0) + 1;
return V;
});
if (S !== Before) {
fs.writeFileSync(P, S, 'utf8');
let Hits = 0;
Object.keys(HitsOf).forEach((K) => (Hits += HitsOf[K]));
TotalHits += Hits;
const Detail = Object.keys(HitsOf).map((K) => K + '(' + HitsOf[K] + ')');
console.log(F + ':' + Hits + ' 处 ' + Detail.slice(0, 12).join(' ') + (Detail.length > 12 ? ' …共' + Detail.length + '种' : ''));
}
}
console.log('— 合计 ' + TotalHits + ' 处替换 —');
+29 -29
View File
@@ -178,12 +178,12 @@
}
// ===== 获取 KMt / TDt 渲染组件 =====
// 新 build:车身皮肤组件字段是 w14w_1(kDt(t)=t.w14w_1,缺失报 "skin";RDt.v16b 里赋值)
// 旧 build:u14l_1 / t14l_1 / p14l_1(新版 t14l_1 已改成悬停车体状态 Qmt,务必别再当皮肤用)
// 新 build:车身皮肤组件字段是 w14w_1(kDt(t)=t.w14w_1,缺失报 "skin";RDt.j16r 里赋值)
// 旧 build:w14x_1 / t14l_1 / p14l_1(新版 t14l_1 已改成悬停车体状态 Qmt,务必别再当皮肤用)
function GetKMtComponent(entity) {
var comp = FindComponentByField(entity, 'w14w_1');
if (comp) return comp;
comp = FindComponentByField(entity, 'u14l_1');
comp = FindComponentByField(entity, 'w14x_1');
if (comp) return comp;
comp = FindComponentByField(entity, 't14l_1');
if (comp) return comp;
@@ -191,13 +191,13 @@
return comp;
}
// 取车身皮肤对象(含 s17b_1 部件表),跨版本兼容;stats 用于诊断来源
// 取车身皮肤对象(含 g17r_1 部件表),跨版本兼容;stats 用于诊断来源
function GetHullSkin(tank, stats) {
var comp = GetKMtComponent(tank);
if (!comp) { if (stats) stats.hullSource = '无组件'; return null; }
if (comp.w14w_1 && comp.w14w_1.s17b_1) { if (stats) stats.hullSource = 'w14w_1'; return comp.w14w_1; } // 新 build
if (comp.t14l_1 && comp.t14l_1.s17b_1) { if (stats) stats.hullSource = 't14l_1'; return comp.t14l_1; } // 旧 build
if (comp.p14l_1 && comp.p14l_1.s17b_1) { if (stats) stats.hullSource = 'p14l_1'; return comp.p14l_1; } // 旧 build
if (comp.w14w_1 && comp.w14w_1.g17r_1) { if (stats) stats.hullSource = 'w14w_1'; return comp.w14w_1; } // 新 build
if (comp.t14l_1 && comp.t14l_1.g17r_1) { if (stats) stats.hullSource = 't14l_1'; return comp.t14l_1; } // 旧 build
if (comp.p14l_1 && comp.p14l_1.g17r_1) { if (stats) stats.hullSource = 'p14l_1'; return comp.p14l_1; } // 旧 build
if (stats) stats.hullSource = '有组件但无皮肤';
return null;
}
@@ -211,14 +211,14 @@
// ===== 从GPU读取顶点位置数据(缓冲区[0]) =====
function ReadVertexPositionsFromTp(tp) {
if (!tp || !tp.t4w_1) return null;
var tl = tp.t4w_1.g1(0);
if (!tp || !tp.x4w_1) return null;
var tl = tp.x4w_1.g1(0);
if (!tl || !tl.d3x_1) return null;
var vq = tl.d3x_1;
var bs = vq.s3h_1;
if (!bs || !bs.b74_1) return null;
var gl = bs.b74_1;
var webglBuf = vq.r3x_1 && vq.r3x_1.z73_1;
var webglBuf = vq.v3x_1 && vq.v3x_1.z73_1;
if (!webglBuf) return null;
gl.bindBuffer(gl.ARRAY_BUFFER, webglBuf);
var bufSize = gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE);
@@ -236,12 +236,12 @@
var allIndices = [];
for (var m = 0; m < meshCount; m++) {
var il = tp.y4w_1.g1(m);
if (!il || !il.q3p_1) continue;
var fq = il.q3p_1;
if (!il || !il.u3p_1) continue;
var fq = il.u3p_1;
var bs = fq.s3h_1;
if (!bs || !bs.b74_1) continue;
var gl = bs.b74_1;
var webglBuf = fq.j3x_1 && fq.j3x_1.z73_1;
var webglBuf = fq.n3x_1 && fq.n3x_1.z73_1;
if (!webglBuf) continue;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webglBuf);
var bufSize = gl.getBufferParameter(gl.ELEMENT_ARRAY_BUFFER, gl.BUFFER_SIZE);
@@ -298,25 +298,25 @@
function CollectMeshNodes(bpNode, nodes, depth, group, stats) {
if (!bpNode || depth > 5) return;
if (stats) stats.seen++;
var name = bpNode.e35_1 || '';
if (bpNode.t3m_1) {
var name = bpNode.g35_1 || '';
if (bpNode.v3m_1) {
if (stats) stats.hasMesh++;
var gpuData = GetGpuData(bpNode.t3m_1);
var gpuData = GetGpuData(bpNode.v3m_1);
if (gpuData) {
if (stats) stats.gpuOk++;
nodes.push({
name: name, node: bpNode, tp: bpNode.t3m_1,
name: name, node: bpNode, tp: bpNode.v3m_1,
positions: gpuData.positions, indices: gpuData.indices, stride: gpuData.stride, group: group
});
} else if (stats) stats.gpuFail++;
}
if (bpNode.q4x_1 && typeof bpNode.q4x_1.e1 === 'function') {
if (bpNode.u4x_1 && typeof bpNode.u4x_1.e1 === 'function') {
try {
var lodCount = bpNode.q4x_1.e1();
var lodCount = bpNode.u4x_1.e1();
for (var lod = 0; lod < lodCount && lod < 1; lod++) {
var lodLevel = bpNode.q4x_1.g1(lod);
var lodLevel = bpNode.u4x_1.g1(lod);
if (!lodLevel) continue;
var lodTp = lodLevel.t3m_1 || lodLevel.v3m_1;
var lodTp = lodLevel.v3m_1 || lodLevel.v3m_1;
if (!lodTp) continue;
var lodGpuData = GetGpuData(lodTp);
if (lodGpuData) {
@@ -346,14 +346,14 @@
var skin = GetHullSkin(tank, stats);
if (skin) {
try {
var partCount = skin.s17b_1.e1();
var partCount = skin.g17r_1.e1();
if (stats) stats.hullParts = partCount;
for (var p = 0; p < partCount; p++) {
var part = skin.s17b_1.g1(p);
if (!part || !part.v17b_1) continue;
var nodeCount = part.v17b_1.e1();
var part = skin.g17r_1.g1(p);
if (!part || !part.j17r_1) continue;
var nodeCount = part.j17r_1.e1();
for (var n = 0; n < nodeCount; n++) {
var bpNode = part.v17b_1.g1(n);
var bpNode = part.j17r_1.g1(n);
if (!bpNode) continue;
CollectMeshNodes(bpNode, nodes, 0, 'hull', stats ? stats.hull : null);
}
@@ -920,7 +920,7 @@
var physicsComp = FindComponentByField(tank, 'gzh_1');
if (!physicsComp || !physicsComp.gzh_1) continue;
var tankState = GetTankState(tank);
// 可见坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)(引擎 y147() 判定),0/1/4 才跳过
// 可见坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)(引擎 s14j() 判定),0/1/4 才跳过
if (tankState !== 2 && tankState !== 3) continue;
var pos = {
@@ -932,7 +932,7 @@
// 本帧该坦克是否在移动(供「残留节点」检测:坦克在动而节点矩阵不动 = 旧位置遗留)
// 用位移的指数滑动平均,而不是「单帧位移 > 10 单位」——后者对慢速移动几乎永远为假,
// 会让残留检测形同虚设(残留漏掉的根因就在这里)
var tankId = tank.hyt_1;
var tankId = tank.iz1_1;
var prevPos = TankPrevPos.get(tankId);
var tankMove = 0;
if (prevPos) {
@@ -950,7 +950,7 @@
if (distance > 50000) continue;
var friendly = IsFriendly(tank, playerTank);
var tankName = GetTankName(tank) || ('ID:' + tank.hyt_1);
var tankName = GetTankName(tank) || ('ID:' + tank.iz1_1);
// 根据 HighlightMode 判断是否渲染该坦克
if (!ShouldRender(tankName)) continue;
// 颜色按队伍:友方=蓝,敌方=红
+13 -13
View File
@@ -128,12 +128,12 @@
if (UMtComponent) return UMtComponent;
try {
var gmEntity = gm.jyw();
if (!gmEntity || !gmEntity.pyt_1 || !gmEntity.pyt_1.s2a_1) return null;
gmEntity.pyt_1.s2a_1.forEach(function(valueList, key) {
if (!gmEntity || !gmEntity.qz1_1 || !gmEntity.qz1_1.s2a_1) return null;
gmEntity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (UMtComponent) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && typeof comp.m179 === 'function') UMtComponent = comp;
if (comp && typeof comp.a17p === 'function') UMtComponent = comp;
} catch(e) {}
});
if (UMtComponent) console.log('[瞄准] uMt 碰撞检测器已获取');
@@ -178,26 +178,26 @@
y178_1: MkVec(0,0,0),
z178_1: MkVec(0,0,0),
a179_1: maxDist,
c179_1: null,
q17o_1: null,
b179_1: null,
d179: function(t, n, i, r, e) {
r17o: function(t, n, i, r, e) {
this.y178_1.k26(t);
this.z178_1.k26(n);
this.a179_1 = i;
this.c179_1 = r;
this.q17o_1 = r;
this.b179_1 = e;
},
d3: function() { this.b179_1 = null; }
};
var filter = {
o1co_1: { h1: function() { return false; }, d3: function() {} },
l1da_1: { h1: function() { return false; }, d3: function() {} },
w179: function() { return true; },
d3: function() { this.o1co_1.d3(); },
p1co: function() {}
d3: function() { this.l1da_1.d3(); },
m1da: function() {}
};
var hit = uMt.m179(startVec, dirVec, maxDist, result, filter);
var hit = uMt.a17p(startVec, dirVec, maxDist, result, filter);
blocked = !!hit && result.a179_1 < (maxDist - 50);
RaycastFailCount = 0;
} catch(e) {
@@ -310,19 +310,19 @@
if (aimInfo.angle >= aimThreshold) continue;
// 墙体阻隔判断
var blocked = IsLineOfSightBlocked(pos, playerPos, tank.hyt_1, frameCount);
var blocked = IsLineOfSightBlocked(pos, playerPos, tank.iz1_1, frameCount);
if (blocked) continue;
// 记录威胁
var proj = Project3D(pos, camInfo.pos, camInfo.yaw, camInfo.pitch, camInfo.fov, screenW, screenH);
var tankName = GetTankName(tank) || ('ID:' + tank.hyt_1);
var tankName = GetTankName(tank) || ('ID:' + tank.iz1_1);
threats.push({
pos: pos,
distance: aimInfo.distance,
angle: aimInfo.angle,
turretDir: aimInfo.turretDir,
screenProj: proj,
tankId: tank.hyt_1,
tankId: tank.iz1_1,
tankName: tankName
});
}
+11 -11
View File
@@ -33,14 +33,14 @@
var initError = null;
try {
scene = gm.jyw().iyt_1;
mainCamera = scene.hyp_1;
ff = scene.fyo_1.d75_1;
if (!mainCamera || !mainCamera.s35_1 || !mainCamera.r35_1 || !mainCamera.o37) {
scene = gm.jyw().jz1_1;
mainCamera = scene.iyx_1;
ff = scene.gyw_1.d75_1;
if (!mainCamera || !mainCamera.u35_1 || !mainCamera.r35_1 || !mainCamera.o37) {
throw new Error('相机字段缺失');
}
console.log('[自由视角] 主相机:', mainCamera.constructor.name,
'l35=(' + mainCamera.s35_1.f20_1.toFixed(2) + ',' + mainCamera.s35_1.g20_1.toFixed(2) + ',' + mainCamera.s35_1.h20_1.toFixed(2) + ')',
'l35=(' + mainCamera.u35_1.f20_1.toFixed(2) + ',' + mainCamera.u35_1.g20_1.toFixed(2) + ',' + mainCamera.u35_1.h20_1.toFixed(2) + ')',
'k35=(' + mainCamera.r35_1.f20_1.toFixed(0) + ',' + mainCamera.r35_1.g20_1.toFixed(0) + ',' + mainCamera.r35_1.h20_1.toFixed(0) + ')');
} catch(e) {
initError = e;
@@ -67,9 +67,9 @@
var origH37 = mainCamera.o37;
function applyFreeLookParams() {
mainCamera.s35_1.f20_1 = freePitch; // pitch (f)
mainCamera.s35_1.g20_1 = freeRoll; // roll (g) 保持初始值
mainCamera.s35_1.h20_1 = freeYaw; // yaw (h) 鼠标左右控制
mainCamera.u35_1.f20_1 = freePitch; // pitch (f)
mainCamera.u35_1.g20_1 = freeRoll; // roll (g) 保持初始值
mainCamera.u35_1.h20_1 = freeYaw; // yaw (h) 鼠标左右控制
mainCamera.r35_1.f20_1 = freePosX;
mainCamera.r35_1.g20_1 = freePosY;
mainCamera.r35_1.h20_1 = freePosZ;
@@ -106,9 +106,9 @@
function enableFreeLook() {
// 从当前相机参数初始化(平滑过渡)
// l35_1: f=pitch, g=roll, h=yaw
freePitch = mainCamera.s35_1.f20_1;
freeRoll = mainCamera.s35_1.g20_1; // roll 保持初始值
freeYaw = mainCamera.s35_1.h20_1; // yaw 鼠标控制
freePitch = mainCamera.u35_1.f20_1;
freeRoll = mainCamera.u35_1.g20_1; // roll 保持初始值
freeYaw = mainCamera.u35_1.h20_1; // yaw 鼠标控制
freePosX = mainCamera.r35_1.f20_1;
freePosY = mainCamera.r35_1.g20_1;
freePosZ = mainCamera.r35_1.h20_1;
+33 -33
View File
@@ -35,9 +35,9 @@
// 遍历 entity.wyj_1.r2a_1(Map<组件标识, 组件列表>),value 是列表类(s_),g1(0) 获取实际组件
// 注意:用 !== undefined 检查字段存在性,避免 falsy 值(0/""/null/false)漏判
function FindComponentByField(entity, fieldName) {
if (!entity || !entity.pyt_1 || !entity.pyt_1.s2a_1) return null;
if (!entity || !entity.qz1_1 || !entity.qz1_1.s2a_1) return null;
var result = null;
entity.pyt_1.s2a_1.forEach(function(valueList, key) {
entity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (result) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
@@ -47,7 +47,7 @@
return result;
}
// ===== 获取坦克位置(G$t 物理组件的 pz7_1 = O$向量) =====
// ===== 获取坦克位置(G$t 物理组件的 rzf_1 = O$向量) =====
// 返回 {x, y, z},x/y 水平面,z 高度
function GetTankPosition(tank) {
var physicsComp = FindComponentByField(tank, 'gzh_1');
@@ -65,21 +65,21 @@
// 状态枚举:0=DEAD, 1=DEAD_PHANTOM, 2=SEMI_ACTIVE, 3=ACTIVE, 4=DISABLED
// Yjt 特征:有 azs_1(状态机)和 vzr_1(状态枚举)字段
function GetTankState(tank) {
if (!tank || !tank.pyt_1 || !tank.pyt_1.s2a_1) return -1;
if (!tank || !tank.qz1_1 || !tank.qz1_1.s2a_1) return -1;
var tankComp = null;
tank.pyt_1.s2a_1.forEach(function(valueList, key) {
tank.qz1_1.s2a_1.forEach(function(valueList, key) {
if (tankComp) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && comp.t101_1 && comp.o101_1 !== undefined) tankComp = comp;
if (comp && comp.t101_1 && comp.k10c_1 !== undefined) tankComp = comp;
} catch(e) {}
});
if (tankComp && tankComp.o101_1) return tankComp.o101_1.k3_1;
if (tankComp && tankComp.k10c_1) return tankComp.k10c_1.k3_1;
return -1;
}
// 可见/战斗中的坦克 = ACTIVE(3) 或 SEMI_ACTIVE(2)
// 依据:引擎用 tankComponent.y147()(= SEMI_ACTIVE || ACTIVE)决定该坦克节点是否渲染,
// 依据:引擎用 tankComponent.s14j()(= SEMI_ACTIVE || ACTIVE)决定该坦克节点是否渲染,
// 只认 ACTIVE 会漏掉半活跃状态(出生/过渡)的坦克
function IsTankAlive(tank) {
var s = GetTankState(tank);
@@ -89,20 +89,20 @@
// ===== 获取坦克名称(yot 用户信息组件) =====
// s120_1 = userName, u120_1 = clanTag(可为null), t120_1 = userRank
function GetTankName(tank) {
var userComp = FindComponentByField(tank, 'k12a_1');
var userComp = FindComponentByField(tank, 'c12n_1');
if (!userComp) return null;
var name = userComp.k12a_1 || '';
var clanTag = userComp.m12a_1 || '';
var name = userComp.c12n_1 || '';
var clanTag = userComp.e12n_1 || '';
return clanTag ? (clanTag + ' ' + name) : name;
}
// ===== 获取坦克血量(Vkt 血量组件) =====
// f122_1 = 最大血量(max), g122_1 = 当前血量(current, 死亡时=0)
function GetTankHealth(tank) {
var healthComp = FindComponentByField(tank, 'y12b_1');
var healthComp = FindComponentByField(tank, 'q12o_1');
if (!healthComp) return null;
var max = healthComp.x12b_1 || 0;
var cur = healthComp.y12b_1 || 0;
var max = healthComp.p12o_1 || 0;
var cur = healthComp.q12o_1 || 0;
if (max <= 0) return null;
return { current: cur, max: max, percent: cur / max };
}
@@ -155,9 +155,9 @@
// checkPosition: 是否检查位置有效性(默认true;测试脚本传false以在死亡状态控制)
function GetPlayerTank(gm, checkPosition) {
if (checkPosition === undefined) checkPosition = true;
var t = gm.x100_1;
var t = gm.t10b_1;
if (t && (!checkPosition || GetTankPosition(t))) return t;
t = gm.y100_1;
t = gm.u10b_1;
if (t && (!checkPosition || GetTankPosition(t))) return t;
try {
var tl = gm.q100_1.r11l();
@@ -182,10 +182,10 @@
} catch(e) {}
}
try {
if (gm && gm.z100_1 && ZCt) {
if (gm && gm.v10b_1 && ZCt) {
var team = ZCt(tank);
if (team && gm.z100_1) {
return team.equals(gm.z100_1) && m2Fn ? m2Fn(team, gm.z100_1) : team.equals(gm.z100_1);
if (team && gm.v10b_1) {
return team.equals(gm.v10b_1) && m2Fn ? m2Fn(team, gm.v10b_1) : team.equals(gm.v10b_1);
}
}
} catch(e) {}
@@ -195,13 +195,13 @@
// ===== 获取相机信息($r/gq 相机组件) =====
// 遍历 GameMode entity 和所有坦克 entity 查找活跃相机组件
// 策略1:查找 $r/gq 相机组件(有 kym_1 位置 和 lym_1 方向)
// 策略2:查找 k7 相机控制器(有 qz9_1 和 gz9_1),从 gz9_1 获取相机组件
// 策略2:查找 k7 相机控制器(有 qz9_1 和 jzh_1),从 jzh_1 获取相机组件
// 返回 {yaw, pitch, fov, pos:{x,y,z}}
// 注意:lym_1.h20_1 是 roll(绕Z),lym_1.f20_1 是 pitch(绕X)
function GetCameraInfo(gm) {
var entities = [];
try {
var gameScene = gm.jyw().iyt_1;
var gameScene = gm.jyw().jz1_1;
var gmEntity = gameScene.xyu("GameMode");
if (gmEntity) entities.push(gmEntity);
} catch(e) {}
@@ -216,9 +216,9 @@
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (!entity || !entity.pyt_1 || !entity.pyt_1.s2a_1) continue;
if (!entity || !entity.qz1_1 || !entity.qz1_1.s2a_1) continue;
var found = null;
entity.pyt_1.s2a_1.forEach(function(valueList, key) {
entity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (found) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
@@ -263,13 +263,13 @@
function GetUMtComponent(gm) {
try {
var gmEntity = gm.jyw();
if (!gmEntity || !gmEntity.pyt_1 || !gmEntity.pyt_1.s2a_1) return null;
if (!gmEntity || !gmEntity.qz1_1 || !gmEntity.qz1_1.s2a_1) return null;
var uMt = null;
gmEntity.pyt_1.s2a_1.forEach(function(valueList, key) {
gmEntity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (uMt) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && typeof comp.m179 === 'function') uMt = comp;
if (comp && typeof comp.a17p === 'function') uMt = comp;
} catch(e) {}
});
return uMt;
@@ -299,24 +299,24 @@
y178_1: MkVec(0, 0, 0),
z178_1: MkVec(0, 0, 0),
a179_1: maxDist,
c179_1: null,
q17o_1: null,
b179_1: null,
d179: function(t, n, i, r, e) {
r17o: function(t, n, i, r, e) {
this.y178_1.k26(t);
this.z178_1.k26(n);
this.a179_1 = i;
this.c179_1 = r;
this.q17o_1 = r;
this.b179_1 = e;
},
d3: function() { this.b179_1 = null; }
};
var filter = {
o1co_1: { h1: function() { return false; }, d3: function() {} },
l1da_1: { h1: function() { return false; }, d3: function() {} },
w179: function() { return true; },
d3: function() { this.o1co_1.d3(); },
p1co: function() {}
d3: function() { this.l1da_1.d3(); },
m1da: function() {}
};
var hit = uMt.m179(startVec, dirVec, maxDist, result, filter);
var hit = uMt.a17p(startVec, dirVec, maxDist, result, filter);
return (hit && result.a179_1 < maxDist) ? result.a179_1 : -1;
} catch(e) {
return -1;
+1 -1
View File
@@ -538,7 +538,7 @@
});
// ===== 电磁炮(RAILGUN / z4t)设置 =====
// 锁定/蓄力时长实时覆盖 window.__hornetLockSec__(游戏内 z4t.w187() 优先读它),
// 锁定/蓄力时长实时覆盖 window.__hornetLockSec__(游戏内 z4t.c18o() 优先读它),
// 拖动滑块**立即生效**,不需要重打包或刷新页面。
// 实测门槛:1.5s / 2.0s / 原版3~5s = 满伤;1.0s / 0.1s = 无伤害 ⇒ 门槛在 1.0~1.5s。
var rgSec = MakeSettingsSection('电磁炮设置');
+16 -16
View File
@@ -36,7 +36,7 @@
// ===== 获取坦克方向(Kkt 组件的 dzc_1) =====
function getTankDirection(tank) {
var hullComp = FindComponentByField(tank, 'vzl_1');
var hullComp = FindComponentByField(tank, 'qzv_1');
if (hullComp && hullComp.wzl_1) {
return {
x: hullComp.wzl_1.f20_1,
@@ -50,13 +50,13 @@
// ===== 获取相机方向(gq/$r 组件的 lym_1.h20_1 = 偏航角) =====
// 相机组件可能在 GameMode entity、玩家坦克或任何坦克上
// 策略1:查找 $r/gq 相机组件(有 kym_1 和 lym_1 字段)
// 策略2:查找 k7 相机控制器(有 qz9_1 和 gz9_1 字段),从 gz9_1 获取相机组件
// 策略2:查找 k7 相机控制器(有 qz9_1 和 jzh_1 字段),从 jzh_1 获取相机组件
function getCameraHeading() {
var entities = [];
// 1. GameMode entity
try {
var gameScene = gm.jyw().iyt_1;
var gameScene = gm.jyw().jz1_1;
var gmEntity = gameScene.xyu("GameMode");
if (gmEntity) entities.push(gmEntity);
} catch(e) {}
@@ -74,10 +74,10 @@
// 在每个 entity 上查找相机组件
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (!entity || !entity.pyt_1 || !entity.pyt_1.s2a_1) continue;
if (!entity || !entity.qz1_1 || !entity.qz1_1.s2a_1) continue;
var found = null;
entity.pyt_1.s2a_1.forEach(function(valueList, key) {
entity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (found) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
@@ -93,7 +93,7 @@
}
}
// 策略2:查找 k7 相机控制器(有 qz9_1 和 gz9_1 字段)
// 策略2:查找 k7 相机控制器(有 qz9_1 和 jzh_1 字段)
if (comp.jzj_1 && comp.zzi_1) {
var camComp = comp.zzi_1;
if (camComp && camComp.cyw_1 && camComp.dyw_1 &&
@@ -147,12 +147,12 @@
if (UMtComponent) return UMtComponent;
try {
var gmEntity = gm.jyw();
if (!gmEntity || !gmEntity.pyt_1 || !gmEntity.pyt_1.s2a_1) return null;
gmEntity.pyt_1.s2a_1.forEach(function(valueList, key) {
if (!gmEntity || !gmEntity.qz1_1 || !gmEntity.qz1_1.s2a_1) return null;
gmEntity.qz1_1.s2a_1.forEach(function(valueList, key) {
if (UMtComponent) return;
try {
var comp = (valueList && typeof valueList.g1 === 'function') ? valueList.g1(0) : valueList;
if (comp && typeof comp.m179 === 'function') UMtComponent = comp;
if (comp && typeof comp.a17p === 'function') UMtComponent = comp;
} catch(e) {}
});
if (UMtComponent) console.log('[雷达] uMt 碰撞检测器已获取');
@@ -175,19 +175,19 @@
var dirVec = MkVec(dirX, dirY, dirZ);
var result = {
y178_1: MkVec(0,0,0), z178_1: MkVec(0,0,0),
a179_1: maxDist, c179_1: null, b179_1: null,
d179: function(t, n, i, r, e) {
a179_1: maxDist, q17o_1: null, b179_1: null,
r17o: function(t, n, i, r, e) {
this.y178_1.k26(t); this.z178_1.k26(n);
this.a179_1 = i; this.c179_1 = r; this.b179_1 = e;
this.a179_1 = i; this.q17o_1 = r; this.b179_1 = e;
},
d3: function() { this.b179_1 = null; }
};
var filter = {
o1co_1: { h1: function() { return false; }, d3: function() {} },
l1da_1: { h1: function() { return false; }, d3: function() {} },
w179: function() { return true; },
d3: function() {}, p1co: function() {}
d3: function() {}, m1da: function() {}
};
var hit = uMt.m179(startVec, dirVec, maxDist, result, filter);
var hit = uMt.a17p(startVec, dirVec, maxDist, result, filter);
return (hit && result.a179_1 < maxDist) ? result.a179_1 : -1;
} catch(e) {
return -1;
@@ -746,7 +746,7 @@
ctx.textAlign = 'left';
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ' Bot:' + botCount + ')', 5, 12);
if (radar.playerFound) {
ctx.fillText('Player: ' + (playerTank ? playerTank.hyt_1 : '?'), 5, 24);
ctx.fillText('Player: ' + (playerTank ? playerTank.iz1_1 : '?'), 5, 24);
} else {
ctx.fillText('Player: NOT FOUND', 5, 24);
}
+31 -31
View File
@@ -81,11 +81,11 @@
var initError = null;
try {
scene = gm.jyw().iyt_1;
scene = gm.jyw().jz1_1;
console.log('[后视] 场景对象:', scene);
// hC 渲染器实例(jr.lye_1)
var renderer = scene.fyo_1;
var renderer = scene.gyw_1;
console.log('[后视] 渲染器:', renderer);
// Ff 绘制器实例(hC.r74_1)
@@ -93,11 +93,11 @@
console.log('[后视] Ff绘制器:', ff);
// 场景根节点(jr.kyf_1)
rootNode = scene.eyp_1;
rootNode = scene.fyx_1;
console.log('[后视] 根节点:', rootNode);
// 主相机 Ha 实例(jr.nyf_1)
mainCamera = scene.hyp_1;
mainCamera = scene.iyx_1;
console.log('[后视] 主相机:', mainCamera);
// 游戏 gl context(Ff.p39_1.p73_1 = BS.p73_1)
@@ -109,11 +109,11 @@
}
// 探测相机字段
console.log('[后视] 相机s35_1:', mainCamera.s35_1);
console.log('[后视] 相机u35_1:', mainCamera.u35_1);
console.log('[后视] 相机r35_1:', mainCamera.r35_1);
console.log('[后视] 相机b37_1:', mainCamera.b37_1);
if (!mainCamera.s35_1 || !mainCamera.r35_1) {
if (!mainCamera.u35_1 || !mainCamera.r35_1) {
throw new Error('相机字段缺失');
}
@@ -309,14 +309,14 @@
var camPosZ = playerPos.z + Config.cameraHeight;
// ===== 保存主相机参数 =====
var savedPitch = mainCamera.s35_1.f20_1;
var savedYaw = mainCamera.s35_1.g20_1;
var savedRoll = mainCamera.s35_1.h20_1;
var savedPitch = mainCamera.u35_1.f20_1;
var savedYaw = mainCamera.u35_1.g20_1;
var savedRoll = mainCamera.u35_1.h20_1;
var savedX = mainCamera.r35_1.f20_1;
var savedY = mainCamera.r35_1.g20_1;
var savedZ = mainCamera.r35_1.h20_1;
var savedL36 = mainCamera.s36_1;
var savedM36 = mainCamera.t36_1;
var savedL36 = mainCamera.u36_1;
var savedM36 = mainCamera.v36_1;
var savedS36 = mainCamera.z36_1;
var savedQ36 = mainCamera.x36_1;
var savedR36 = mainCamera.y36_1;
@@ -330,14 +330,14 @@
// g=π 使水平方向反向(朝后看),h=yaw+π 保持水平视角正确
// f=-pitch 使垂直方向与主视一致(低头看后方地形)
// up 朝下 → FBO 画面颠倒 → GL readback Y 翻转修正
mainCamera.s35_1.f20_1 = rearPitch;
mainCamera.s35_1.g20_1 = Math.PI;
mainCamera.s35_1.h20_1 = camInfo.yaw + Math.PI;
mainCamera.u35_1.f20_1 = rearPitch;
mainCamera.u35_1.g20_1 = Math.PI;
mainCamera.u35_1.h20_1 = camInfo.yaw + Math.PI;
mainCamera.r35_1.f20_1 = camPosX;
mainCamera.r35_1.g20_1 = camPosY;
mainCamera.r35_1.h20_1 = camPosZ;
mainCamera.s36_1 = rw;
mainCamera.t36_1 = rh;
mainCamera.u36_1 = rw;
mainCamera.v36_1 = rh;
mainCamera.z36_1 = Config.fov;
mainCamera.x36_1 = Config.near;
mainCamera.y36_1 = Config.far;
@@ -349,14 +349,14 @@
var rearViewMatrix = new Float32Array(mainCamera.b37_1);
// ===== 保存并禁用阴影/后处理(避免它们切换 FBO 覆盖 rearFbo)=====
// p38_1.x3n_1 控制 z39_1(阴影),y3n_1 控制 c3a_1/d3a_1(后处理),z3n_1 控制 f3a_1
// p38_1.b3o_1 控制 z39_1(阴影),c3o_1 控制 c3a_1/d3a_1(后处理),z3n_1 控制 f3a_1
// 禁用后 y3s 只执行主场景渲染 z3k,跳过所有 FBO 切换的 pass
var savedX3n = ff.w38_1.e3o_1;
var savedY3n = ff.w38_1.f3o_1;
var savedZ3n = ff.w38_1.g3o_1;
ff.w38_1.e3o_1 = false;
ff.w38_1.f3o_1 = false;
ff.w38_1.g3o_1 = false;
var savedX3n = ff.y38_1.e3o_1;
var savedY3n = ff.y38_1.f3o_1;
var savedZ3n = ff.y38_1.k3o_1;
ff.y38_1.e3o_1 = false;
ff.y38_1.f3o_1 = false;
ff.y38_1.k3o_1 = false;
// ===== 禁用 UI 渲染层(防止技能条等 UI 混入后视 FBO)=====
// 保存 UI 层队列,替换为空假对象,y3s 后恢复
@@ -430,9 +430,9 @@
// ===== 恢复阴影/后处理(异常时也要恢复)=====
try {
if (typeof savedX3n !== 'undefined') {
ff.w38_1.e3o_1 = savedX3n;
ff.w38_1.f3o_1 = savedY3n;
ff.w38_1.g3o_1 = savedZ3n;
ff.y38_1.e3o_1 = savedX3n;
ff.y38_1.f3o_1 = savedY3n;
ff.y38_1.k3o_1 = savedZ3n;
}
} catch(e) {
console.error('[后视] 恢复阴影/后处理失败:', e.message);
@@ -452,14 +452,14 @@
// ===== 恢复主相机参数 =====
try {
mainCamera.s35_1.f20_1 = savedPitch;
mainCamera.s35_1.g20_1 = savedYaw;
mainCamera.s35_1.h20_1 = savedRoll;
mainCamera.u35_1.f20_1 = savedPitch;
mainCamera.u35_1.g20_1 = savedYaw;
mainCamera.u35_1.h20_1 = savedRoll;
mainCamera.r35_1.f20_1 = savedX;
mainCamera.r35_1.g20_1 = savedY;
mainCamera.r35_1.h20_1 = savedZ;
mainCamera.s36_1 = savedL36;
mainCamera.t36_1 = savedM36;
mainCamera.u36_1 = savedL36;
mainCamera.v36_1 = savedM36;
mainCamera.z36_1 = savedS36;
mainCamera.x36_1 = savedQ36;
mainCamera.y36_1 = savedR36;
+31 -31
View File
@@ -2,10 +2,10 @@
// 功能:通过修改 Dyt.j14b_1(履带控制状态 Uyt)触发 KC 回调 → ryp(Ds) → kyt 发送网络包
// 原理:
// 1. Dyt 构造函数中 KC 回调(z14a_1)注册到 gameScene 每帧更新
// 2. KC 回调检测 j14b_1.equals(i14b_1) === false 时:
// a) 复制 j14b_1 → i14b_1(l14a)
// 2. KC 回调检测 j14b_1.equals(d14n_1) === false 时:
// a) 复制 j14b_1 → d14n_1(l14a)
// b) 触发 ryp(Ds)(_yt 事件全局单例)
// 3. kyt 监听 _yt 事件 → 调用 w14b_1.b14c(time, j14b_1) 发送网络包
// 3. kyt 监听 _yt 事件 → 调用 r14n_1.b14c(time, j14b_1) 发送网络包
// 4. 这是游戏自然移动路径,网络包格式/时机完全正常,不触发服务器检测
// 控制:W/S 前进/后退,A/D 左转/右转,松开停止
// 在浏览器控制台运行(需先运行 hook_gamemode.js + hornet_lib.js)
@@ -47,9 +47,9 @@
// ===== 获取玩家坦克 =====
function GetPlayerTank() {
var t = gm.y100_1;
var t = gm.u10b_1;
if (t) return t;
t = gm.x100_1;
t = gm.t10b_1;
if (t) return t;
try {
var tl = gm.q100_1.r11l();
@@ -77,9 +77,9 @@
console.log(' n14m_1 (在战斗中):', dyt.n14m_1);
try {
console.log(' v14m_1:', dyt.v14m_1.toString());
console.log(' i14b_1:', dyt.i14b_1.toString());
console.log(' d14n_1:', dyt.d14n_1.toString());
} catch(e) {
console.log(' v14m_1/i14b_1 toString 失败:', e.message);
console.log(' v14m_1/d14n_1 toString 失败:', e.message);
}
// 检查 KC(z14a_1)的方法
@@ -92,36 +92,36 @@
}
// ===== 获取 maxSpeed 和 maxTurn =====
// 尝试从 f14b_1(speedCharacteristics/dgt 组件)获取
// 尝试从 a14n_1(speedCharacteristics/dgt 组件)获取
try {
var sc = dyt.r14m_1;
var sc = dyt.q14y_1;
if (sc) {
if (typeof sc.na9 === 'function') {
maxSpeed = sc.na9();
console.log(' 从 r14m_1.na9() 获取 maxSpeed:', maxSpeed);
console.log(' 从 q14y_1.na9() 获取 maxSpeed:', maxSpeed);
} else if (sc.f14c_1 !== undefined) {
maxSpeed = sc.f14c_1;
console.log(' 从 r14m_1.f14c_1 获取 maxSpeed:', maxSpeed);
console.log(' 从 q14y_1.f14c_1 获取 maxSpeed:', maxSpeed);
}
if (sc.j14c_1 !== undefined) {
maxTurn = sc.j14c_1;
console.log(' 从 r14m_1.j14c_1 获取 maxTurn:', maxTurn);
console.log(' 从 q14y_1.j14c_1 获取 maxTurn:', maxTurn);
}
}
} catch(e) {
console.warn('[测试] 获取速度参数失败:', e.message);
}
// 尝试从其他组件获取(a149_1 字段存储 na9() 的值)
// 尝试从其他组件获取(u14k_1 字段存储 na9() 的值)
if (maxSpeed === 100) {
try {
playerTank.pyt_1.s2a_1.forEach(function(valueList) {
playerTank.qz1_1.s2a_1.forEach(function(valueList) {
if (maxSpeed !== 100) return;
try {
var comp = valueList && typeof valueList.g1 === 'function' ? valueList.g1(0) : valueList;
if (comp && comp.m14k_1 !== undefined && typeof comp.m14k_1 === 'number' && comp.m14k_1 > 0) {
maxSpeed = comp.m14k_1;
console.log(' 从组件 m14k_1 获取 maxSpeed:', maxSpeed);
if (comp && comp.p14w_1 !== undefined && typeof comp.p14w_1 === 'number' && comp.p14w_1 > 0) {
maxSpeed = comp.p14w_1;
console.log(' 从组件 p14w_1 获取 maxSpeed:', maxSpeed);
}
} catch(e) {}
});
@@ -171,25 +171,25 @@
var newS140 = forward * maxSpeed;
var newT140 = turn * maxTurn;
// 只在值变化时设置(KC 回调检测 j14b_1 ≠ i14b_1 才触发 ryp(Ds))
// 只在值变化时设置(KC 回调检测 j14b_1 ≠ d14n_1 才触发 ryp(Ds))
if (newS140 !== lastS140 || newT140 !== lastT140) {
try {
dyt.v14m_1.m14b_1 = newS140;
dyt.v14m_1.n14b_1 = newT140;
// u140_1 (reverseBackTurn) 不修改
// k14c_1 (reverseBackTurn) 不修改
lastS140 = newS140;
lastT140 = newT140;
console.log('[移动] m14b_1=' + newS140 + ' n14b_1=' + newT140 +
' (v14m_1 ≠ i14b_1 → KC 回调将触发 iyz(Ds) → kyt 发送网络包)');
' (v14m_1 ≠ d14n_1 → KC 回调将触发 iyz(Ds) → kyt 发送网络包)');
} catch(e) {
console.error('[测试] 设置 v14m_1 失败:', e.message);
}
}
}, 50);
// ===== KC 回调验证:修改 j14b_1 后检查 i14b_1 是否更新 =====
// KC 回调会复制 j14b_1 → i14b_1(i14b_1.l14a(j14b_1))
// 如果 i14b_1 更新了,说明 KC 回调每帧调用,方案有效
// ===== KC 回调验证:修改 j14b_1 后检查 d14n_1 是否更新 =====
// KC 回调会复制 j14b_1 → d14n_1(d14n_1.l14a(j14b_1))
// 如果 d14n_1 更新了,说明 KC 回调每帧调用,方案有效
kcVerified = false;
var verifyCount = 0;
verifyInterval = setInterval(function() {
@@ -199,23 +199,23 @@
clearInterval(verifyInterval);
verifyInterval = null;
if (!kcVerified) {
console.warn('[验证] 3秒内未检测到 KC 回调工作(i14b_1 未跟随 v14m_1 更新)');
console.warn('[验证] 3秒内未检测到 KC 回调工作(d14n_1 未跟随 v14m_1 更新)');
console.warn('[验证] 可能原因:1) KC 回调不每帧调用 2) n14m_1=false 3) l14m_1 未注册');
console.warn('[验证] 请尝试在游戏中移动(点击地面寻路),观察 i14b_1 是否变化');
console.warn('[验证] 请尝试在游戏中移动(点击地面寻路),观察 d14n_1 是否变化');
}
return;
}
// 如果 j14b_1 ≠ i14b_1,说明 KC 回调还没复制(可能 KC 不每帧调用)
// 如果 j14b_1 == i14b_1,说明 KC 回调已复制(KC 工作正常)
// 如果 j14b_1 ≠ d14n_1,说明 KC 回调还没复制(可能 KC 不每帧调用)
// 如果 j14b_1 == d14n_1,说明 KC 回调已复制(KC 工作正常)
try {
if (dyt.v14m_1.m14b_1 === dyt.i14b_1.m14b_1 &&
dyt.v14m_1.n14b_1 === dyt.i14b_1.n14b_1) {
if (dyt.v14m_1.m14b_1 === dyt.d14n_1.m14b_1 &&
dyt.v14m_1.n14b_1 === dyt.d14n_1.n14b_1) {
if (lastS140 !== 0 || lastT140 !== 0) {
// j14b_1 有非零值且 i14b_1 已同步
// j14b_1 有非零值且 d14n_1 已同步
kcVerified = true;
clearInterval(verifyInterval);
verifyInterval = null;
console.log('[验证] KC 回调工作正常!i14b_1 已跟随 v14m_1 更新');
console.log('[验证] KC 回调工作正常!d14n_1 已跟随 v14m_1 更新');
console.log('[验证] iyz(Ds) 应已触发,kyt 应已发送网络包');
}
}
+35 -35
View File
@@ -39,21 +39,21 @@
// 皮肤字段:新 build 是 w14w_1;旧 build 是 t14l_1(新版 t14l_1 已改成悬停车体状态 Qmt)
var hullComp = FindComponentByField(tank, 'w14w_1') ||
FindComponentByField(tank, 't14l_1') ||
FindComponentByField(tank, 'u14l_1') ||
FindComponentByField(tank, 'w14x_1') ||
FindComponentByField(tank, 'p14l_1');
if (!hullComp) return null;
var skin = (hullComp.w14w_1 && hullComp.w14w_1.s17b_1) ? hullComp.w14w_1 :
(hullComp.t14l_1 && hullComp.t14l_1.s17b_1) ? hullComp.t14l_1 :
(hullComp.p14l_1 && hullComp.p14l_1.s17b_1) ? hullComp.p14l_1 : null;
var skin = (hullComp.w14w_1 && hullComp.w14w_1.g17r_1) ? hullComp.w14w_1 :
(hullComp.t14l_1 && hullComp.t14l_1.g17r_1) ? hullComp.t14l_1 :
(hullComp.p14l_1 && hullComp.p14l_1.g17r_1) ? hullComp.p14l_1 : null;
if (!skin) return null;
try {
var partCount = skin.s17b_1.e1();
var partCount = skin.g17r_1.e1();
for (var p = 0; p < partCount; p++) {
var part = skin.s17b_1.g1(p);
if (!part || !part.v17b_1) continue;
var nodeCount = part.v17b_1.e1();
var part = skin.g17r_1.g1(p);
if (!part || !part.j17r_1) continue;
var nodeCount = part.j17r_1.e1();
for (var n = 0; n < nodeCount; n++) {
var bpNode = part.v17b_1.g1(n);
var bpNode = part.j17r_1.g1(n);
if (!bpNode || !bpNode.n35_1) continue;
// 不按 g35_1 过滤:它是引擎的细节/淡出权重(0~1),不是幽灵标志,
// 过滤会漏掉低细节节点、导致取不到朝向
@@ -87,10 +87,10 @@
var scene = null, ff = null, rootNode = null, mainCamera = null, gl = null;
var initError = null;
try {
scene = gm.jyw().iyt_1;
ff = scene.fyo_1.d75_1;
rootNode = scene.eyp_1;
mainCamera = scene.hyp_1;
scene = gm.jyw().jz1_1;
ff = scene.gyw_1.d75_1;
rootNode = scene.fyx_1;
mainCamera = scene.iyx_1;
gl = ff.w39_1.b74_1;
if (!ff || !rootNode || !mainCamera || !gl) throw new Error('关键字段缺失');
} catch(e) {
@@ -661,37 +661,37 @@
try {
// 保存主相机参数
var sPitch = mainCamera.s35_1.f20_1;
var sRoll = mainCamera.s35_1.g20_1;
var sYaw = mainCamera.s35_1.h20_1;
var sPitch = mainCamera.u35_1.f20_1;
var sRoll = mainCamera.u35_1.g20_1;
var sYaw = mainCamera.u35_1.h20_1;
var sX = mainCamera.r35_1.f20_1;
var sY = mainCamera.r35_1.g20_1;
var sZ = mainCamera.r35_1.h20_1;
var sL36 = mainCamera.s36_1, sM36 = mainCamera.t36_1;
var sL36 = mainCamera.u36_1, sM36 = mainCamera.v36_1;
var sS36 = mainCamera.z36_1, sQ36 = mainCamera.x36_1, sR36 = mainCamera.y36_1;
// 设置俯瞰相机参数
// pitch=-π/2 朝下看,roll=0 不翻转,yaw=0 北朝上
mainCamera.s35_1.f20_1 = -Math.PI / 2;
mainCamera.s35_1.g20_1 = 0;
mainCamera.s35_1.h20_1 = 0;
mainCamera.u35_1.f20_1 = -Math.PI / 2;
mainCamera.u35_1.g20_1 = 0;
mainCamera.u35_1.h20_1 = 0;
mainCamera.r35_1.f20_1 = viewCenterX;
mainCamera.r35_1.g20_1 = viewCenterY;
mainCamera.r35_1.h20_1 = camHeight;
mainCamera.s36_1 = FBO_W;
mainCamera.t36_1 = FBO_H;
mainCamera.u36_1 = FBO_W;
mainCamera.v36_1 = FBO_H;
mainCamera.z36_1 = Config.fov;
mainCamera.x36_1 = Config.near;
mainCamera.y36_1 = Config.far;
mainCamera.o37();
// 禁用阴影/后处理
var savedX3n = ff.w38_1.e3o_1;
var savedY3n = ff.w38_1.f3o_1;
var savedZ3n = ff.w38_1.g3o_1;
ff.w38_1.e3o_1 = false;
ff.w38_1.f3o_1 = false;
ff.w38_1.g3o_1 = false;
var savedX3n = ff.y38_1.e3o_1;
var savedY3n = ff.y38_1.f3o_1;
var savedZ3n = ff.y38_1.k3o_1;
ff.y38_1.e3o_1 = false;
ff.y38_1.f3o_1 = false;
ff.y38_1.k3o_1 = false;
// 禁用 UI 层
var savedUiQueues = {};
@@ -744,21 +744,21 @@
origBindFramebuffer(gl.FRAMEBUFFER, mainFbo);
// 恢复渲染状态
ff.w38_1.e3o_1 = savedX3n;
ff.w38_1.f3o_1 = savedY3n;
ff.w38_1.g3o_1 = savedZ3n;
ff.y38_1.e3o_1 = savedX3n;
ff.y38_1.f3o_1 = savedY3n;
ff.y38_1.k3o_1 = savedZ3n;
for (var ui2 = 0; ui2 < uiLayerIndices.length; ui2++) {
ff.e39_1[uiLayerIndices[ui2]] = savedUiQueues[uiLayerIndices[ui2]];
}
// 恢复主相机
mainCamera.s35_1.f20_1 = sPitch;
mainCamera.s35_1.g20_1 = sRoll;
mainCamera.s35_1.h20_1 = sYaw;
mainCamera.u35_1.f20_1 = sPitch;
mainCamera.u35_1.g20_1 = sRoll;
mainCamera.u35_1.h20_1 = sYaw;
mainCamera.r35_1.f20_1 = sX;
mainCamera.r35_1.g20_1 = sY;
mainCamera.r35_1.h20_1 = sZ;
mainCamera.s36_1 = sL36; mainCamera.t36_1 = sM36;
mainCamera.u36_1 = sL36; mainCamera.v36_1 = sM36;
mainCamera.z36_1 = sS36; mainCamera.x36_1 = sQ36; mainCamera.y36_1 = sR36;
mainCamera.o37();