From 580a456032c23d833d67f63c582cc101f33014fb Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 21 Oct 2026 00:32:24 +0800 Subject: [PATCH] =?UTF-8?q?fix(ignore):=20=E6=A0=85=E6=A0=8F=E5=88=A4?= =?UTF-8?q?=E5=AE=9A=E5=8A=A0=E5=85=A5=E9=AB=98=E5=BA=A6=E9=97=A8=E6=A7=9B?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=E6=8A=8A=E5=9C=B0=E9=9D=A2=E4=B8=80?= =?UTF-8?q?=E8=B5=B7=E5=BF=BD=E7=95=A5=E5=AF=BC=E8=87=B4=E6=8E=89=E5=87=BA?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上一版 skippedFence 达 4.6 万,说明地面三角也被忽略。现规则:静态形状最高点必须高于本地坦克中心 1m 才可能是栅栏;三角形再要求 |法线z|<0.6。新增 byType 统计(cat/type → 忽略次数)便于确认命中对象。 --- .../play/static/js/unpacked/hornet_bundle.js | 50 ++++++++++++++++--- 3dtank_bundle.js | 50 ++++++++++++++++--- tools/hornet_noclip.js | 50 ++++++++++++++++--- 3 files changed, 126 insertions(+), 24 deletions(-) diff --git a/3dtank.com/play/static/js/unpacked/hornet_bundle.js b/3dtank.com/play/static/js/unpacked/hornet_bundle.js index 54ae4d7..a923702 100644 --- a/3dtank.com/play/static/js/unpacked/hornet_bundle.js +++ b/3dtank.com/play/static/js/unpacked/hornet_bundle.js @@ -6587,6 +6587,7 @@ ignoreFence: false, skippedTank: 0, skippedFence: 0, + byType: {}, // cat/type → 被忽略次数(诊断) patched: false }; @@ -6672,13 +6673,41 @@ return !IsTankShape(Shape); } - // 「栅栏类」= 静态几何里除地面/缓坡以外的部分: - // · 三角形:法线接近水平(墙/栅栏/悬崖立面)→ 忽略;法线朝上(地面/缓坡)→ 保留 - // · 非三角形静态碰撞代理(盒/柱等):地图里这类基本都不是可站立地面 → 忽略 + var FPhysicsPosition = Fld('Physics.Position', 'bzr_1'); // 本地坦克世界位置 + + // 「栅栏类」= 静态几何中「明显高于车体中心」的那部分: + // · 三角形:|法线 z| < 0.6(立面)且最高点高于车体中心 1m → 墙/栅栏 + // · 非三角形(盒/柱等代理):中心高于车体中心 1m → 障碍 + // · 地面/缓坡(最高点不高于车体中心)→ 一律保留,避免掉出地图 + function LocalTankZ() { + var Phys = GetLocalPhysics(); + var P = Phys && Phys[FPhysicsPosition]; + return (P && typeof P.h20_1 === 'number') ? P.h20_1 : null; + } + + function ShapeMaxZ(Shape) { + if (IsTriangle(Shape)) { + var A = Shape[FV0], B = Shape[FV1], C = Shape[FV2]; + if (!A || !B || !C) return null; + var Max = Math.max(A.h20_1, B.h20_1, C.h20_1); + return isFinite(Max) ? Max : null; + } + var Body = Shape[FShapeBody]; + var State = Body && Body[FBodyState]; + var P = State && State[FBodyPosVec]; + return (P && typeof P.h20_1 === 'number') ? P.h20_1 : null; + } + function IsFenceLike(Shape) { if (!IsStaticShape(Shape)) return false; - if (!IsTriangle(Shape)) return true; - return IsSteepTriangle(Shape); + var TankZ = LocalTankZ(); + if (TankZ === null) return false; + var MaxZ = ShapeMaxZ(Shape); + if (MaxZ === null) return false; + if (MaxZ < TankZ + 100) return false; // 不高于车体中心 1m → 地面/缓坡/低矮物 + if (!IsTriangle(Shape)) return true; // 高于车体中心的盒/柱代理 → 障碍 + var Nz = TriangleNormalZ(Shape); + return Nz !== null && Math.abs(Nz) < 0.6; // 立面才算墙/栅栏 } // ===== 诊断:识别「正在和什么物体重叠」===== @@ -6799,9 +6828,13 @@ // ② 忽略栅栏(静态障碍;地面/缓坡保留) if (Stat.ignoreFence && Local) { - if ((TankA && OwnerOf(ShapeA) === Local && IsFenceLike(ShapeB)) || - (TankB && OwnerOf(ShapeB) === Local && IsFenceLike(ShapeA))) { + var FenceShape = null; + if (TankA && OwnerOf(ShapeA) === Local) FenceShape = ShapeB; + else if (TankB && OwnerOf(ShapeB) === Local) FenceShape = ShapeA; + if (FenceShape && IsFenceLike(FenceShape)) { Stat.skippedFence++; + var Key = FenceShape[FShapeCategory] + '/' + FenceShape[FShapeType]; + Stat.byType[Key] = (Stat.byType[Key] || 0) + 1; return true; } // 诊断:本车与任意非坦克形状配对但没跳过 → 记录样本(含被挡住的栅栏) @@ -6931,7 +6964,8 @@ GetStat: function () { return { running: Stat.running, mode: Stat.mode, ignoreFence: Stat.ignoreFence, - skippedTank: Stat.skippedTank, skippedFence: Stat.skippedFence, patched: Stat.patched + skippedTank: Stat.skippedTank, skippedFence: Stat.skippedFence, + byType: Stat.byType, patched: Stat.patched }; } }; diff --git a/3dtank_bundle.js b/3dtank_bundle.js index 54ae4d7..a923702 100644 --- a/3dtank_bundle.js +++ b/3dtank_bundle.js @@ -6587,6 +6587,7 @@ ignoreFence: false, skippedTank: 0, skippedFence: 0, + byType: {}, // cat/type → 被忽略次数(诊断) patched: false }; @@ -6672,13 +6673,41 @@ return !IsTankShape(Shape); } - // 「栅栏类」= 静态几何里除地面/缓坡以外的部分: - // · 三角形:法线接近水平(墙/栅栏/悬崖立面)→ 忽略;法线朝上(地面/缓坡)→ 保留 - // · 非三角形静态碰撞代理(盒/柱等):地图里这类基本都不是可站立地面 → 忽略 + var FPhysicsPosition = Fld('Physics.Position', 'bzr_1'); // 本地坦克世界位置 + + // 「栅栏类」= 静态几何中「明显高于车体中心」的那部分: + // · 三角形:|法线 z| < 0.6(立面)且最高点高于车体中心 1m → 墙/栅栏 + // · 非三角形(盒/柱等代理):中心高于车体中心 1m → 障碍 + // · 地面/缓坡(最高点不高于车体中心)→ 一律保留,避免掉出地图 + function LocalTankZ() { + var Phys = GetLocalPhysics(); + var P = Phys && Phys[FPhysicsPosition]; + return (P && typeof P.h20_1 === 'number') ? P.h20_1 : null; + } + + function ShapeMaxZ(Shape) { + if (IsTriangle(Shape)) { + var A = Shape[FV0], B = Shape[FV1], C = Shape[FV2]; + if (!A || !B || !C) return null; + var Max = Math.max(A.h20_1, B.h20_1, C.h20_1); + return isFinite(Max) ? Max : null; + } + var Body = Shape[FShapeBody]; + var State = Body && Body[FBodyState]; + var P = State && State[FBodyPosVec]; + return (P && typeof P.h20_1 === 'number') ? P.h20_1 : null; + } + function IsFenceLike(Shape) { if (!IsStaticShape(Shape)) return false; - if (!IsTriangle(Shape)) return true; - return IsSteepTriangle(Shape); + var TankZ = LocalTankZ(); + if (TankZ === null) return false; + var MaxZ = ShapeMaxZ(Shape); + if (MaxZ === null) return false; + if (MaxZ < TankZ + 100) return false; // 不高于车体中心 1m → 地面/缓坡/低矮物 + if (!IsTriangle(Shape)) return true; // 高于车体中心的盒/柱代理 → 障碍 + var Nz = TriangleNormalZ(Shape); + return Nz !== null && Math.abs(Nz) < 0.6; // 立面才算墙/栅栏 } // ===== 诊断:识别「正在和什么物体重叠」===== @@ -6799,9 +6828,13 @@ // ② 忽略栅栏(静态障碍;地面/缓坡保留) if (Stat.ignoreFence && Local) { - if ((TankA && OwnerOf(ShapeA) === Local && IsFenceLike(ShapeB)) || - (TankB && OwnerOf(ShapeB) === Local && IsFenceLike(ShapeA))) { + var FenceShape = null; + if (TankA && OwnerOf(ShapeA) === Local) FenceShape = ShapeB; + else if (TankB && OwnerOf(ShapeB) === Local) FenceShape = ShapeA; + if (FenceShape && IsFenceLike(FenceShape)) { Stat.skippedFence++; + var Key = FenceShape[FShapeCategory] + '/' + FenceShape[FShapeType]; + Stat.byType[Key] = (Stat.byType[Key] || 0) + 1; return true; } // 诊断:本车与任意非坦克形状配对但没跳过 → 记录样本(含被挡住的栅栏) @@ -6931,7 +6964,8 @@ GetStat: function () { return { running: Stat.running, mode: Stat.mode, ignoreFence: Stat.ignoreFence, - skippedTank: Stat.skippedTank, skippedFence: Stat.skippedFence, patched: Stat.patched + skippedTank: Stat.skippedTank, skippedFence: Stat.skippedFence, + byType: Stat.byType, patched: Stat.patched }; } }; diff --git a/tools/hornet_noclip.js b/tools/hornet_noclip.js index 529f876..39f36ae 100644 --- a/tools/hornet_noclip.js +++ b/tools/hornet_noclip.js @@ -63,6 +63,7 @@ ignoreFence: false, skippedTank: 0, skippedFence: 0, + byType: {}, // cat/type → 被忽略次数(诊断) patched: false }; @@ -148,13 +149,41 @@ return !IsTankShape(Shape); } - // 「栅栏类」= 静态几何里除地面/缓坡以外的部分: - // · 三角形:法线接近水平(墙/栅栏/悬崖立面)→ 忽略;法线朝上(地面/缓坡)→ 保留 - // · 非三角形静态碰撞代理(盒/柱等):地图里这类基本都不是可站立地面 → 忽略 + var FPhysicsPosition = Fld('Physics.Position', 'bzr_1'); // 本地坦克世界位置 + + // 「栅栏类」= 静态几何中「明显高于车体中心」的那部分: + // · 三角形:|法线 z| < 0.6(立面)且最高点高于车体中心 1m → 墙/栅栏 + // · 非三角形(盒/柱等代理):中心高于车体中心 1m → 障碍 + // · 地面/缓坡(最高点不高于车体中心)→ 一律保留,避免掉出地图 + function LocalTankZ() { + var Phys = GetLocalPhysics(); + var P = Phys && Phys[FPhysicsPosition]; + return (P && typeof P.h20_1 === 'number') ? P.h20_1 : null; + } + + function ShapeMaxZ(Shape) { + if (IsTriangle(Shape)) { + var A = Shape[FV0], B = Shape[FV1], C = Shape[FV2]; + if (!A || !B || !C) return null; + var Max = Math.max(A.h20_1, B.h20_1, C.h20_1); + return isFinite(Max) ? Max : null; + } + var Body = Shape[FShapeBody]; + var State = Body && Body[FBodyState]; + var P = State && State[FBodyPosVec]; + return (P && typeof P.h20_1 === 'number') ? P.h20_1 : null; + } + function IsFenceLike(Shape) { if (!IsStaticShape(Shape)) return false; - if (!IsTriangle(Shape)) return true; - return IsSteepTriangle(Shape); + var TankZ = LocalTankZ(); + if (TankZ === null) return false; + var MaxZ = ShapeMaxZ(Shape); + if (MaxZ === null) return false; + if (MaxZ < TankZ + 100) return false; // 不高于车体中心 1m → 地面/缓坡/低矮物 + if (!IsTriangle(Shape)) return true; // 高于车体中心的盒/柱代理 → 障碍 + var Nz = TriangleNormalZ(Shape); + return Nz !== null && Math.abs(Nz) < 0.6; // 立面才算墙/栅栏 } // ===== 诊断:识别「正在和什么物体重叠」===== @@ -275,9 +304,13 @@ // ② 忽略栅栏(静态障碍;地面/缓坡保留) if (Stat.ignoreFence && Local) { - if ((TankA && OwnerOf(ShapeA) === Local && IsFenceLike(ShapeB)) || - (TankB && OwnerOf(ShapeB) === Local && IsFenceLike(ShapeA))) { + var FenceShape = null; + if (TankA && OwnerOf(ShapeA) === Local) FenceShape = ShapeB; + else if (TankB && OwnerOf(ShapeB) === Local) FenceShape = ShapeA; + if (FenceShape && IsFenceLike(FenceShape)) { Stat.skippedFence++; + var Key = FenceShape[FShapeCategory] + '/' + FenceShape[FShapeType]; + Stat.byType[Key] = (Stat.byType[Key] || 0) + 1; return true; } // 诊断:本车与任意非坦克形状配对但没跳过 → 记录样本(含被挡住的栅栏) @@ -407,7 +440,8 @@ GetStat: function () { return { running: Stat.running, mode: Stat.mode, ignoreFence: Stat.ignoreFence, - skippedTank: Stat.skippedTank, skippedFence: Stat.skippedFence, patched: Stat.patched + skippedTank: Stat.skippedTank, skippedFence: Stat.skippedFence, + byType: Stat.byType, patched: Stat.patched }; } };