probe(physics): ACDREAM_PROBE_SUPPORT + ACDREAM_WIRE_MESH — separate #337's three candidates
The user is wedged at the top of Neftet rock plateaus, jumps sink into the mesh, and a corpse falls straight through. ACDREAM_PROBE_REACH already ruled out its own domain: blocked=0, every candidate tested-ok. Three candidates remain — terrain support, a collision mesh not where its visual is, or the transition wedging on an unobstructed path. ACDREAM_PROBE_RESOLVE alone cannot separate them. It prints a three-value contact-plane token, no plane normal, no plane height, no terrain sample and no plane provenance, so all three produce the same line. Two additions: [support] — one line per resolve for EVERY body, not just the player. A corpse is a plain physics body with no player-specific logic, so its fall-through is the cheapest available control on "movement code vs geometry data", and it is invisible to any player-filtered probe. The line samples the outdoor terrain INDEPENDENTLY at the body's own out-XY and prints the contact plane's own height at that same XY. Two heights at one point make support=terrain / object / none a measurement rather than an inference, and cpSrc= names the site that asserted the plane so provenance and classification cross-check. [geom] — once per GfxObj that comes near a mover: the object's physics-BSP vertex cloud against its visual mesh AABB in the same local frame, through the same prepared accessors the resolver queries. verdict=coincident REFUTES the working hypothesis for that object outright; no-physics-bsp / empty-physics-bsp / displaced / extent-mismatch each name a specific data defect. Built to refute, not to confirm — two diagnoses on this defect's lineage have already been refuted by measurement. ACDREAM_WIRE_MESH upgrades the existing F2 overlay, which drew a broadphase proxy cylinder for BSP objects and so could not answer the question at all, to the real physics-BSP polygon edges (cyan) beside the visual mesh box (magenta) and the terrain surface (yellow). Own class per code-structure rule 1. The provenance latch lives on PhysicsDiagnostics, not on CollisionInfo. Two fields there first — the obvious home — broke the flat/graph differential referee and the scratch-reset poison test, both of which compare CollisionInfo member-for-member. Teaching either to skip a member is a one-line green fix that puts a permanent hole in a referee whose whole job is comparing everything. Captured as feedback_probe_state_off_compared_types. Seven tests cover the support classifier's boundaries: a wrong classifier does not fail to answer, it answers confidently wrong. Gates: Release build 0 errors; complete suite 11,225 passed / 4 skipped / 0 failed from a cleaned tree — baseline 11,218/4/0 plus exactly the seven new tests, skips unchanged. Issue #337 filed with the symptom set, what is ruled out, and a table of what each possible output means. All of this is TEMPORARY and recorded for stripping with the physics-probe family. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
13fcf38138
commit
49a7e90652
9 changed files with 1376 additions and 1 deletions
|
|
@ -64,6 +64,10 @@ internal sealed class WorldSceneDiagnosticsController : IWorldSceneDiagnostics
|
|||
private readonly DebugVmRenderFactsPublisher _debugVm;
|
||||
private readonly bool _debugVmConsumerActive;
|
||||
private int _debugDrawLogCount;
|
||||
// #337 (TEMPORARY): built on first use so the ordinary overlay path and
|
||||
// every headless/no-window host pay nothing for it.
|
||||
private CollisionMeshWireframe? _meshWireframe;
|
||||
private CollisionMeshWireframeStats _lastMeshStats = new(-1, -1, -1, -1, false);
|
||||
|
||||
public WorldSceneDiagnosticsController(
|
||||
WorldRenderDiagnostics diagnostics,
|
||||
|
|
@ -215,6 +219,18 @@ internal sealed class WorldSceneDiagnosticsController : IWorldSceneDiagnostics
|
|||
if (!_state.CollisionWireframesVisible || _lines is null)
|
||||
return;
|
||||
|
||||
// #337 (2026-08-06 — TEMPORARY): ACDREAM_WIRE_MESH=1 replaces the
|
||||
// broadphase-proxy overlay below with the objects' real physics-BSP
|
||||
// polygon edges beside their visual mesh boxes and the terrain surface
|
||||
// — see CollisionMeshWireframe for why the proxy cannot answer the
|
||||
// question this mode exists for. Default off; F2 keeps its old
|
||||
// behaviour otherwise.
|
||||
if (RenderingDiagnostics.CollisionMeshWireframeEnabled)
|
||||
{
|
||||
DrawCollisionMesh(in camera);
|
||||
return;
|
||||
}
|
||||
|
||||
_lines.Begin();
|
||||
int drawn = 0;
|
||||
foreach (ShadowEntry shadow in _physics.ShadowObjects.AllEntriesForDebug())
|
||||
|
|
@ -255,6 +271,50 @@ internal sealed class WorldSceneDiagnosticsController : IWorldSceneDiagnostics
|
|||
_lines.Flush(camera.Camera.View, camera.Projection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #337 (2026-08-06 — TEMPORARY, strip with the probe family). Centres on
|
||||
/// the player when there is one, else on the camera, so the fly-camera
|
||||
/// mode can inspect geometry too.
|
||||
/// </summary>
|
||||
private void DrawCollisionMesh(in WorldCameraFrame camera)
|
||||
{
|
||||
Vector3 centre = _mode.IsPlayerMode && _player.Controller is { } controller
|
||||
? controller.Position
|
||||
: camera.Position;
|
||||
|
||||
_meshWireframe ??= new CollisionMeshWireframe(_physics);
|
||||
|
||||
_lines!.Begin();
|
||||
CollisionMeshWireframeStats stats = _meshWireframe.Draw(_lines, centre);
|
||||
|
||||
if (_mode.IsPlayerMode && _player.Controller is { } player)
|
||||
{
|
||||
_lines.AddCylinder(
|
||||
player.Position,
|
||||
DebugVmRenderFactsPublisher.PlayerCollisionRadius,
|
||||
1.8f,
|
||||
new Vector3(1f, 0f, 0f));
|
||||
}
|
||||
|
||||
_lines.Flush(camera.Camera.View, camera.Projection);
|
||||
|
||||
// A capped frame is showing PARTIAL geometry, which would otherwise be
|
||||
// indistinguishable from an object that has none — exactly the
|
||||
// misreading this overlay exists to prevent. Say so, throttled, rather
|
||||
// than letting the picture lie.
|
||||
if (stats != _lastMeshStats)
|
||||
{
|
||||
_lastMeshStats = stats;
|
||||
Console.WriteLine(string.Format(
|
||||
System.Globalization.CultureInfo.InvariantCulture,
|
||||
"[wire-mesh] centre=({0:F2},{1:F2},{2:F2}) objects={3} polys={4} " +
|
||||
"noPhysicsGeometry={5} lines={6} capped={7}",
|
||||
centre.X, centre.Y, centre.Z,
|
||||
stats.ObjectsConsidered, stats.PolygonsDrawn,
|
||||
stats.ObjectsWithoutPhysicsGeometry, stats.LinesDrawn, stats.Capped));
|
||||
}
|
||||
}
|
||||
|
||||
private void LogNearbyCollisionObjects(Vector3 playerPosition, int drawn)
|
||||
{
|
||||
if (_debugDrawLogCount >= 5)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue