From 0b449968a74b3f958111018ed295cd37bb2d4a55 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 22 May 2026 12:17:47 +0200 Subject: [PATCH] =?UTF-8?q?diag(phys):=20A6.P3=20slice=204=20=E2=80=94=20a?= =?UTF-8?q?dd=20[poly-dump]=20probe=20for=20#98=20investigation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a polygon-geometry dump probe that fires alongside [push-back] whenever AdjustSphereToPlane lands a push-back. Gated by ACDREAM_PROBE_POLY_DUMP=1. Output format: [poly-dump] cell=0xA9B40147 polyId=0x0042 numPts=4 sides=Single n=(0.000,-0.719,0.695) d=-0.1007 verts=[(x1,y1,z1),(x2,y2,z2),(x3,y3,z3),(x4,y4,z4)] Purpose: investigate #98 (cellar-up stuck at top step). The push-back trace shows the player hitting a sloped surface n=(0,-0.719,0.695) at the cellar stair top. Two possibilities: 1. The polygon really IS sloped 44° in the dat (genuine geometry). 2. Our dat-read produces wrong vertices → wrong normal → wrong plane. The dump lets us: - Identify which dat polygon was hit (cell + poly ID) - Compare our extracted vertices against WorldBuilder's straight-from- dat read for the same poly - Or spawn the cell in ACViewer to visually verify the geometry Changes: - Added `ushort Id` property to ResolvedPolygon (defaults to 0 for test fixtures that don't care; production code in PhysicsDataCache.cs + BSPQuery.cs sets it from the dictionary key). - Added ProbePolyDumpEnabled + LogPolyDump in PhysicsDiagnostics. - Wired the dump into AdjustSphereToPlane's apply-branch (after the existing push-back log; same gating pattern). Test suite: 1148 pass + 8 pre-existing fail (baseline maintained). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/AcDream.Core/Physics/BSPQuery.cs | 9 ++++ src/AcDream.Core/Physics/PhysicsDataCache.cs | 10 +++++ .../Physics/PhysicsDiagnostics.cs | 45 +++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/src/AcDream.Core/Physics/BSPQuery.cs b/src/AcDream.Core/Physics/BSPQuery.cs index bdff8f4..4e045aa 100644 --- a/src/AcDream.Core/Physics/BSPQuery.cs +++ b/src/AcDream.Core/Physics/BSPQuery.cs @@ -394,6 +394,14 @@ public static class BSPQuery applied: true); } + if (PhysicsDiagnostics.ProbePolyDumpEnabled) + { + // A6.P3 slice 4 (2026-05-22): dump the polygon geometry to + // cross-reference against WorldBuilder's straight-from-dat + // read. CellId taken from path.CheckCellId. + PhysicsDiagnostics.LogPolyDump(path.CheckCellId, poly); + } + return true; } @@ -2212,6 +2220,7 @@ public static class BSPQuery Plane = new Plane(normal, planeD), NumPoints = n, SidesType = poly.SidesType, + Id = id, }; } return resolved; diff --git a/src/AcDream.Core/Physics/PhysicsDataCache.cs b/src/AcDream.Core/Physics/PhysicsDataCache.cs index 934b3a1..9bcda0b 100644 --- a/src/AcDream.Core/Physics/PhysicsDataCache.cs +++ b/src/AcDream.Core/Physics/PhysicsDataCache.cs @@ -289,6 +289,7 @@ public sealed class PhysicsDataCache Plane = new Plane(normal, d), NumPoints = numVerts, SidesType = poly.SidesType, + Id = id, }; } return resolved; @@ -383,6 +384,15 @@ public sealed class ResolvedPolygon public required Plane Plane { get; init; } public required int NumPoints { get; init; } public required CullMode SidesType { get; init; } + /// + /// Polygon index within its parent (cell or GfxObj). Used by the + /// `ACDREAM_PROBE_POLY_DUMP` probe (A6.P3 slice 4 investigation, + /// 2026-05-22) to identify which dat polygon a push-back hit so we + /// can compare our extracted vertices/plane against WorldBuilder's + /// straight-from-dat read. Defaults to 0 for test fixtures that + /// don't care about polygon identity. + /// + public ushort Id { get; init; } } /// Cached physics data for a single GfxObj part. diff --git a/src/AcDream.Core/Physics/PhysicsDiagnostics.cs b/src/AcDream.Core/Physics/PhysicsDiagnostics.cs index 5942a19..731eb05 100644 --- a/src/AcDream.Core/Physics/PhysicsDiagnostics.cs +++ b/src/AcDream.Core/Physics/PhysicsDiagnostics.cs @@ -304,6 +304,51 @@ public static class PhysicsDiagnostics public static bool ProbePushBackEnabled { get; set; } = Environment.GetEnvironmentVariable("ACDREAM_PROBE_PUSH_BACK") == "1"; + /// + /// A6.P3 slice 4 investigation (2026-05-22) — dumps the polygon's + /// vertices + plane + sidesType + cell id whenever a push-back fires. + /// Lets us compare our extracted polygon (from our cache) against + /// WorldBuilder's straight-from-dat read for the same poly index, to + /// falsify the "is our dat-read producing wrong polygon geometry?" + /// hypothesis for issue #98 (cellar-up stuck at top step). + /// + /// + /// Initial state from ACDREAM_PROBE_POLY_DUMP=1. + /// Heavy output (one dump per AdjustSphereToPlane call); use briefly + /// to capture a specific scenario, then turn off. + /// + /// + public static bool ProbePolyDumpEnabled { get; set; } = + Environment.GetEnvironmentVariable("ACDREAM_PROBE_POLY_DUMP") == "1"; + + /// + /// Emit one [poly-dump] line with the full polygon geometry: + /// cell id, polygon index, num vertices, sides flag, plane normal+D, + /// and all vertex coordinates. Used in conjunction with the push-back + /// probe to identify which dat polygon a push-back hit so we can + /// cross-reference against WorldBuilder's straight-from-dat read. + /// + /// Caller MUST guard with if (!ProbePolyDumpEnabled) return;. + /// + public static void LogPolyDump(uint cellId, ResolvedPolygon poly) + { + var ci = System.Globalization.CultureInfo.InvariantCulture; + var sb = new System.Text.StringBuilder(256); + sb.AppendFormat(ci, + "[poly-dump] cell=0x{0:X8} polyId=0x{1:X4} numPts={2} sides={3} " + + "n=({4:F6},{5:F6},{6:F6}) d={7:F6} verts=[", + cellId, poly.Id, poly.NumPoints, poly.SidesType, + poly.Plane.Normal.X, poly.Plane.Normal.Y, poly.Plane.Normal.Z, poly.Plane.D); + for (int i = 0; i < poly.Vertices.Length; i++) + { + if (i > 0) sb.Append(','); + sb.AppendFormat(ci, "({0:F6},{1:F6},{2:F6})", + poly.Vertices[i].X, poly.Vertices[i].Y, poly.Vertices[i].Z); + } + sb.Append(']'); + Console.WriteLine(sb.ToString()); + } + /// /// A6.P1 emission helper for the AdjustSphereToPlane site. /// One line per call: input sphere center, plane geometry, push-back