feat(ignore): 栅栏诊断输出重叠物体信息(形状 + 邻近场景节点名)

保持原有几何判定(仅陡峭静态三角形);DebugFence(true) 后,本车与任意非坦克形状配对时按签名去重打印 cat/type/法线/位置/7m 内场景节点名,用于确认栅栏对应哪个物体;schema 补 Body.State/PositionVec。
This commit is contained in:
TermiNexus committed 2026-10-21 00:25:16 +08:00
1 parent 8244e2097a
commit 2e4f97ac4c
4 files changed
+255 -33

No files matched your search

@@ -304,6 +304,8 @@
'Shape.Vertex1': 'v9x_1', // 三角形顶点 1
'Shape.Vertex2': 'w9x_1', // 三角形顶点 2
'Body.Owner': 'x9i_1', // 刚体 → 拥有者(坦克物理组件 ejt)
'Body.State': 'f9j_1', // 刚体当前物理态
'Body.PositionVec': 's9j_1', // 刚体位置向量(f9j_1.s9j_1)
// ---- 碰撞世界(module_55088 的 ki)----
'CollisionWorld.ShouldCollide': 'q9q()', // 唯一配对过滤:mask + 形状类型 → 生成接触
@@ -6670,16 +6672,82 @@
return !IsTankShape(Shape);
}
// 「栅栏类」= 静态几何里除地面/缓坡以外的部分:
// · 非三角形静态体(盒/柱等碰撞代理)→ 视为障碍
// · 三角形且法线接近水平(墙/栅栏/悬崖立面)→ 视为障碍
// 「栅栏类」= 静态几何中法线接近水平(墙/栅栏/悬崖立面)的三角形
// 保持原方案:只按几何判定,不做任何物体白名单
function IsFenceLike(Shape) {
if (!IsStaticShape(Shape)) return false;
if (!IsTriangle(Shape)) return true;
return IsSteepTriangle(Shape);
}
// ===== 诊断(控制台 __hornetFenceDebug__ = true 开启)=====
// ===== 诊断:识别「正在和什么物体重叠」=====
// 碰撞形状本身没有名字(地图三角形是合并的三角汤),所以用两级信息:
// ① 形状自身:category / mask / type / 法线
// ② 形状位置附近(默认 7m)场景树里的节点名(如 fence_s / wall_new_3w)
var FSceneRoot = Fld('Scene.RootNode', 'fyx_1');
var FNodeName = Fld('Node.Name', 'g35_1');
var FNodeMatrix = Fld('Node.Matrix', 'p35_1');
var FNodeChildren = Fld('Node.Children', 'r35_1');
var FBodyState = Fld('Body.State', 'f9j_1');
var FBodyPosVec = Fld('Body.PositionVec', 's9j_1');
function ShapePoint(Shape) {
if (!Shape) return null;
if (IsTriangle(Shape)) {
var A = Shape[FV0], B = Shape[FV1], C = Shape[FV2];
if (A && B && C) {
return {
x: (A.f20_1 + B.f20_1 + C.f20_1) / 3,
y: (A.g20_1 + B.g20_1 + C.g20_1) / 3,
z: (A.h20_1 + B.h20_1 + C.h20_1) / 3
};
}
return null;
}
// 非三角形:取所在刚体的世界位置
var Body = Shape[FShapeBody];
var State = Body && Body[FBodyState];
var P = State && State[FBodyPosVec];
if (P && typeof P.f20_1 === 'number') return { x: P.f20_1, y: P.g20_1, z: P.h20_1 };
return null;
}
function FindNearNodeNames(Point, Radius) {
if (!Point) return [];
var Gm = window.__gameMode__;
if (!Gm) return [];
var Scene = null;
try { Scene = Gm.lz4()[Fld('Camera.SceneRef', 'jz1_1')]; } catch (e) { return []; }
var Root = Scene && Scene[FSceneRoot];
if (!Root) return [];
var Names = [];
var Seen = typeof Set !== 'undefined' ? new Set() : null;
var Visited = 0;
var R = Radius || 700;
var R2 = R * R;
(function Walk(Node, Depth) {
if (!Node || Depth > 12 || Visited > 4000) return;
if (Seen) { if (Seen.has(Node)) return; Seen.add(Node); }
Visited++;
var M = Node[FNodeMatrix];
if (M && typeof M.length === 'number' && M.length >= 16 && typeof M[12] === 'number') {
var Dx = M[12] - Point.x, Dy = M[13] - Point.y, Dz = M[14] - Point.z;
if (Dx * Dx + Dy * Dy + Dz * Dz <= R2) {
var Nm = Node[FNodeName];
if (Nm && Names.indexOf(Nm) < 0 && Names.length < 8) Names.push(Nm);
}
}
var Children = Node[FNodeChildren];
if (Children && typeof Children.e1 === 'function') {
var N = Children.e1();
for (var i = 0; i < N; i++) {
try { Walk(Children.g1(i), Depth + 1); } catch (e) {}
}
}
})(Root, 0);
return Names;
}
// 每个「未跳过」的静态形状只打印一次(按签名去重)
var FenceSampleKeys = {};
function RecordFenceSample(Shape) {
if (window.__hornetFenceDebug__ !== true) return;
@@ -6690,8 +6758,14 @@
var Key = Cat + '/' + Type + '/' + (Nz === null ? '-' : Nz.toFixed(2));
if (FenceSampleKeys[Key]) return;
FenceSampleKeys[Key] = 1;
console.log('[忽略][栅栏样本] cat=' + Cat + ' type=' + Type + ' 三角=' + Tri +
' nz=' + (Nz === null ? '-' : Nz.toFixed(2)) + ' 跳过=' + IsFenceLike(Shape));
var Pt = ShapePoint(Shape);
var Near = FindNearNodeNames(Pt, 700);
console.log('[忽略][重叠物体] cat=' + Cat + ' type=' + Type + ' 三角=' + Tri +
' nz=' + (Nz === null ? '-' : Nz.toFixed(2)) +
' 位置=' + (Pt ? ('(' + Pt.x.toFixed(0) + ',' + Pt.y.toFixed(0) + ',' + Pt.z.toFixed(0) + ')') : '-') +
' 近邻节点=[' + Near.join(', ') + ']' +
' 当前判定=' + (IsFenceLike(Shape) ? '忽略' : '保留'));
}
// ===== 判定:这一对形状要不要跳过 =====
@@ -6728,9 +6802,9 @@
Stat.skippedFence++;
return true;
}
// 诊断:本车与静态形状配对但没跳过 → 记录样本,便于定位分类/法线
if (TankA && OwnerOf(ShapeA) === Local && IsStaticShape(ShapeB)) RecordFenceSample(ShapeB);
if (TankB && OwnerOf(ShapeB) === Local && IsStaticShape(ShapeA)) RecordFenceSample(ShapeA);
// 诊断:本车与任意非坦克形状配对但没跳过 → 记录样本(含被挡住的栅栏)
if (TankA && OwnerOf(ShapeA) === Local && !TankB) RecordFenceSample(ShapeB);
if (TankB && OwnerOf(ShapeB) === Local && !TankA) RecordFenceSample(ShapeA);
}
return false;
@@ -6850,7 +6924,7 @@
DebugFence: function (On) {
window.__hornetFenceDebug__ = On !== false;
FenceSampleKeys = {};
console.log('[忽略] 栅栏诊断 = ' + (window.__hornetFenceDebug__ ? '开(撞墙后看 [忽略][栅栏样本])' : '关'));
console.log('[忽略] 栅栏诊断 = ' + (window.__hornetFenceDebug__ ? '开(撞栅栏后看 [忽略][重叠物体])' : '关'));
},
GetStat: function () {
return {
+85 -11
View File
@@ -304,6 +304,8 @@
'Shape.Vertex1': 'v9x_1', // 三角形顶点 1
'Shape.Vertex2': 'w9x_1', // 三角形顶点 2
'Body.Owner': 'x9i_1', // 刚体 → 拥有者(坦克物理组件 ejt)
'Body.State': 'f9j_1', // 刚体当前物理态
'Body.PositionVec': 's9j_1', // 刚体位置向量(f9j_1.s9j_1)
// ---- 碰撞世界(module_55088 的 ki)----
'CollisionWorld.ShouldCollide': 'q9q()', // 唯一配对过滤:mask + 形状类型 → 生成接触
@@ -6670,16 +6672,82 @@
return !IsTankShape(Shape);
}
// 「栅栏类」= 静态几何里除地面/缓坡以外的部分:
// · 非三角形静态体(盒/柱等碰撞代理)→ 视为障碍
// · 三角形且法线接近水平(墙/栅栏/悬崖立面)→ 视为障碍
// 「栅栏类」= 静态几何中法线接近水平(墙/栅栏/悬崖立面)的三角形
// 保持原方案:只按几何判定,不做任何物体白名单
function IsFenceLike(Shape) {
if (!IsStaticShape(Shape)) return false;
if (!IsTriangle(Shape)) return true;
return IsSteepTriangle(Shape);
}
// ===== 诊断(控制台 __hornetFenceDebug__ = true 开启)=====
// ===== 诊断:识别「正在和什么物体重叠」=====
// 碰撞形状本身没有名字(地图三角形是合并的三角汤),所以用两级信息:
// ① 形状自身:category / mask / type / 法线
// ② 形状位置附近(默认 7m)场景树里的节点名(如 fence_s / wall_new_3w)
var FSceneRoot = Fld('Scene.RootNode', 'fyx_1');
var FNodeName = Fld('Node.Name', 'g35_1');
var FNodeMatrix = Fld('Node.Matrix', 'p35_1');
var FNodeChildren = Fld('Node.Children', 'r35_1');
var FBodyState = Fld('Body.State', 'f9j_1');
var FBodyPosVec = Fld('Body.PositionVec', 's9j_1');
function ShapePoint(Shape) {
if (!Shape) return null;
if (IsTriangle(Shape)) {
var A = Shape[FV0], B = Shape[FV1], C = Shape[FV2];
if (A && B && C) {
return {
x: (A.f20_1 + B.f20_1 + C.f20_1) / 3,
y: (A.g20_1 + B.g20_1 + C.g20_1) / 3,
z: (A.h20_1 + B.h20_1 + C.h20_1) / 3
};
}
return null;
}
// 非三角形:取所在刚体的世界位置
var Body = Shape[FShapeBody];
var State = Body && Body[FBodyState];
var P = State && State[FBodyPosVec];
if (P && typeof P.f20_1 === 'number') return { x: P.f20_1, y: P.g20_1, z: P.h20_1 };
return null;
}
function FindNearNodeNames(Point, Radius) {
if (!Point) return [];
var Gm = window.__gameMode__;
if (!Gm) return [];
var Scene = null;
try { Scene = Gm.lz4()[Fld('Camera.SceneRef', 'jz1_1')]; } catch (e) { return []; }
var Root = Scene && Scene[FSceneRoot];
if (!Root) return [];
var Names = [];
var Seen = typeof Set !== 'undefined' ? new Set() : null;
var Visited = 0;
var R = Radius || 700;
var R2 = R * R;
(function Walk(Node, Depth) {
if (!Node || Depth > 12 || Visited > 4000) return;
if (Seen) { if (Seen.has(Node)) return; Seen.add(Node); }
Visited++;
var M = Node[FNodeMatrix];
if (M && typeof M.length === 'number' && M.length >= 16 && typeof M[12] === 'number') {
var Dx = M[12] - Point.x, Dy = M[13] - Point.y, Dz = M[14] - Point.z;
if (Dx * Dx + Dy * Dy + Dz * Dz <= R2) {
var Nm = Node[FNodeName];
if (Nm && Names.indexOf(Nm) < 0 && Names.length < 8) Names.push(Nm);
}
}
var Children = Node[FNodeChildren];
if (Children && typeof Children.e1 === 'function') {
var N = Children.e1();
for (var i = 0; i < N; i++) {
try { Walk(Children.g1(i), Depth + 1); } catch (e) {}
}
}
})(Root, 0);
return Names;
}
// 每个「未跳过」的静态形状只打印一次(按签名去重)
var FenceSampleKeys = {};
function RecordFenceSample(Shape) {
if (window.__hornetFenceDebug__ !== true) return;
@@ -6690,8 +6758,14 @@
var Key = Cat + '/' + Type + '/' + (Nz === null ? '-' : Nz.toFixed(2));
if (FenceSampleKeys[Key]) return;
FenceSampleKeys[Key] = 1;
console.log('[忽略][栅栏样本] cat=' + Cat + ' type=' + Type + ' 三角=' + Tri +
' nz=' + (Nz === null ? '-' : Nz.toFixed(2)) + ' 跳过=' + IsFenceLike(Shape));
var Pt = ShapePoint(Shape);
var Near = FindNearNodeNames(Pt, 700);
console.log('[忽略][重叠物体] cat=' + Cat + ' type=' + Type + ' 三角=' + Tri +
' nz=' + (Nz === null ? '-' : Nz.toFixed(2)) +
' 位置=' + (Pt ? ('(' + Pt.x.toFixed(0) + ',' + Pt.y.toFixed(0) + ',' + Pt.z.toFixed(0) + ')') : '-') +
' 近邻节点=[' + Near.join(', ') + ']' +
' 当前判定=' + (IsFenceLike(Shape) ? '忽略' : '保留'));
}
// ===== 判定:这一对形状要不要跳过 =====
@@ -6728,9 +6802,9 @@
Stat.skippedFence++;
return true;
}
// 诊断:本车与静态形状配对但没跳过 → 记录样本,便于定位分类/法线
if (TankA && OwnerOf(ShapeA) === Local && IsStaticShape(ShapeB)) RecordFenceSample(ShapeB);
if (TankB && OwnerOf(ShapeB) === Local && IsStaticShape(ShapeA)) RecordFenceSample(ShapeA);
// 诊断:本车与任意非坦克形状配对但没跳过 → 记录样本(含被挡住的栅栏)
if (TankA && OwnerOf(ShapeA) === Local && !TankB) RecordFenceSample(ShapeB);
if (TankB && OwnerOf(ShapeB) === Local && !TankA) RecordFenceSample(ShapeA);
}
return false;
@@ -6850,7 +6924,7 @@
DebugFence: function (On) {
window.__hornetFenceDebug__ = On !== false;
FenceSampleKeys = {};
console.log('[忽略] 栅栏诊断 = ' + (window.__hornetFenceDebug__ ? '开(撞墙后看 [忽略][栅栏样本])' : '关'));
console.log('[忽略] 栅栏诊断 = ' + (window.__hornetFenceDebug__ ? '开(撞栅栏后看 [忽略][重叠物体])' : '关'));
},
GetStat: function () {
return {
+83 -11
View File
@@ -148,16 +148,82 @@
return !IsTankShape(Shape);
}
// 「栅栏类」= 静态几何里除地面/缓坡以外的部分:
// · 非三角形静态体(盒/柱等碰撞代理)→ 视为障碍
// · 三角形且法线接近水平(墙/栅栏/悬崖立面)→ 视为障碍
// 「栅栏类」= 静态几何中法线接近水平(墙/栅栏/悬崖立面)的三角形
// 保持原方案:只按几何判定,不做任何物体白名单
function IsFenceLike(Shape) {
if (!IsStaticShape(Shape)) return false;
if (!IsTriangle(Shape)) return true;
return IsSteepTriangle(Shape);
}
// ===== 诊断(控制台 __hornetFenceDebug__ = true 开启)=====
// ===== 诊断:识别「正在和什么物体重叠」=====
// 碰撞形状本身没有名字(地图三角形是合并的三角汤),所以用两级信息:
// ① 形状自身:category / mask / type / 法线
// ② 形状位置附近(默认 7m)场景树里的节点名(如 fence_s / wall_new_3w)
var FSceneRoot = Fld('Scene.RootNode', 'fyx_1');
var FNodeName = Fld('Node.Name', 'g35_1');
var FNodeMatrix = Fld('Node.Matrix', 'p35_1');
var FNodeChildren = Fld('Node.Children', 'r35_1');
var FBodyState = Fld('Body.State', 'f9j_1');
var FBodyPosVec = Fld('Body.PositionVec', 's9j_1');
function ShapePoint(Shape) {
if (!Shape) return null;
if (IsTriangle(Shape)) {
var A = Shape[FV0], B = Shape[FV1], C = Shape[FV2];
if (A && B && C) {
return {
x: (A.f20_1 + B.f20_1 + C.f20_1) / 3,
y: (A.g20_1 + B.g20_1 + C.g20_1) / 3,
z: (A.h20_1 + B.h20_1 + C.h20_1) / 3
};
}
return null;
}
// 非三角形:取所在刚体的世界位置
var Body = Shape[FShapeBody];
var State = Body && Body[FBodyState];
var P = State && State[FBodyPosVec];
if (P && typeof P.f20_1 === 'number') return { x: P.f20_1, y: P.g20_1, z: P.h20_1 };
return null;
}
function FindNearNodeNames(Point, Radius) {
if (!Point) return [];
var Gm = window.__gameMode__;
if (!Gm) return [];
var Scene = null;
try { Scene = Gm.lz4()[Fld('Camera.SceneRef', 'jz1_1')]; } catch (e) { return []; }
var Root = Scene && Scene[FSceneRoot];
if (!Root) return [];
var Names = [];
var Seen = typeof Set !== 'undefined' ? new Set() : null;
var Visited = 0;
var R = Radius || 700;
var R2 = R * R;
(function Walk(Node, Depth) {
if (!Node || Depth > 12 || Visited > 4000) return;
if (Seen) { if (Seen.has(Node)) return; Seen.add(Node); }
Visited++;
var M = Node[FNodeMatrix];
if (M && typeof M.length === 'number' && M.length >= 16 && typeof M[12] === 'number') {
var Dx = M[12] - Point.x, Dy = M[13] - Point.y, Dz = M[14] - Point.z;
if (Dx * Dx + Dy * Dy + Dz * Dz <= R2) {
var Nm = Node[FNodeName];
if (Nm && Names.indexOf(Nm) < 0 && Names.length < 8) Names.push(Nm);
}
}
var Children = Node[FNodeChildren];
if (Children && typeof Children.e1 === 'function') {
var N = Children.e1();
for (var i = 0; i < N; i++) {
try { Walk(Children.g1(i), Depth + 1); } catch (e) {}
}
}
})(Root, 0);
return Names;
}
// 每个「未跳过」的静态形状只打印一次(按签名去重)
var FenceSampleKeys = {};
function RecordFenceSample(Shape) {
if (window.__hornetFenceDebug__ !== true) return;
@@ -168,8 +234,14 @@
var Key = Cat + '/' + Type + '/' + (Nz === null ? '-' : Nz.toFixed(2));
if (FenceSampleKeys[Key]) return;
FenceSampleKeys[Key] = 1;
console.log('[忽略][栅栏样本] cat=' + Cat + ' type=' + Type + ' 三角=' + Tri +
' nz=' + (Nz === null ? '-' : Nz.toFixed(2)) + ' 跳过=' + IsFenceLike(Shape));
var Pt = ShapePoint(Shape);
var Near = FindNearNodeNames(Pt, 700);
console.log('[忽略][重叠物体] cat=' + Cat + ' type=' + Type + ' 三角=' + Tri +
' nz=' + (Nz === null ? '-' : Nz.toFixed(2)) +
' 位置=' + (Pt ? ('(' + Pt.x.toFixed(0) + ',' + Pt.y.toFixed(0) + ',' + Pt.z.toFixed(0) + ')') : '-') +
' 近邻节点=[' + Near.join(', ') + ']' +
' 当前判定=' + (IsFenceLike(Shape) ? '忽略' : '保留'));
}
// ===== 判定:这一对形状要不要跳过 =====
@@ -206,9 +278,9 @@
Stat.skippedFence++;
return true;
}
// 诊断:本车与静态形状配对但没跳过 → 记录样本,便于定位分类/法线
if (TankA && OwnerOf(ShapeA) === Local && IsStaticShape(ShapeB)) RecordFenceSample(ShapeB);
if (TankB && OwnerOf(ShapeB) === Local && IsStaticShape(ShapeA)) RecordFenceSample(ShapeA);
// 诊断:本车与任意非坦克形状配对但没跳过 → 记录样本(含被挡住的栅栏)
if (TankA && OwnerOf(ShapeA) === Local && !TankB) RecordFenceSample(ShapeB);
if (TankB && OwnerOf(ShapeB) === Local && !TankA) RecordFenceSample(ShapeA);
}
return false;
@@ -328,7 +400,7 @@
DebugFence: function (On) {
window.__hornetFenceDebug__ = On !== false;
FenceSampleKeys = {};
console.log('[忽略] 栅栏诊断 = ' + (window.__hornetFenceDebug__ ? '开(撞墙后看 [忽略][栅栏样本])' : '关'));
console.log('[忽略] 栅栏诊断 = ' + (window.__hornetFenceDebug__ ? '开(撞栅栏后看 [忽略][重叠物体])' : '关'));
},
GetStat: function () {
return {
+2
View File
@@ -80,6 +80,8 @@
'Shape.Vertex1': 'v9x_1', // 三角形顶点 1
'Shape.Vertex2': 'w9x_1', // 三角形顶点 2
'Body.Owner': 'x9i_1', // 刚体 → 拥有者(坦克物理组件 ejt)
'Body.State': 'f9j_1', // 刚体当前物理态
'Body.PositionVec': 's9j_1', // 刚体位置向量(f9j_1.s9j_1)
// ---- 碰撞世界(module_55088 的 ki)----
'CollisionWorld.ShouldCollide': 'q9q()', // 唯一配对过滤:mask + 形状类型 → 生成接触