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