test(phys): A6.P3 #98 — harness diagnostic + initial Z lift experiment
Adds two diagnostic-only tests: - Harness_DiagnosticDump_FirstTenTicks: prints trajectory + resolve probe lines for the seeded-body path - Harness_DiagnosticDump_NoBodySeed: same but with body=null, isolating whether the CP seed contributes to the airborne-at-tick-1 issue Also adjusts InitialSphereWorld to lift the sphere by 0.05m above cellar floor (sphere bottom at Z=91.00, not Z=90.95). The lift should give the engine a clean step-down on tick 1 instead of an exact-boundary contact. Experimental finding: NEITHER the no-body-seed path NOR the 0.05m lift changes the airborne-at-tick-1 behavior. With sphere center at world Z=91.48 (0.05m + radius above cellar floor at 90.95): - Tick 1: in=(141.5, 9.5, 91.48), out=(141.5, 9.5, 91.48) — Y move rejected. hit=yes n=(0,0,1) walkable=False. - Tick 2+: Y advances by 0.1/tick, Z stays put, onGround stays False. The hit normal (0,0,1) at tick 1 means the engine treats the cellar floor polygon as a NON-WALKABLE collision target when the sphere is seeded grounded above it. The walkability classifier returns False even though Normal.Z=1.0 > FloorZ=0.6642. This is a real engine bug worth investigating in a future session — independent of the cellar-up freeze. The synthetic ramp polygon registered via RegisterStairRampGfxObj is NOT reached because the sphere is now airborne and floats over the cellar floor without contacting the ramp. Next session pickup options: 1. Debug the airborne-at-tick-1 issue (likely in TransitionTypes FindEnvCollisions indoor BSP path — why does a flat (0,0,1) hit return walkable=False?). Once fixed, the harness should reproduce cellar-up freeze. 2. Pivot to a different M1.5 issue with cleaner reproduction. 3. Use the harness mechanics elsewhere — the synthetic-GfxObj + ShadowEntry pattern is reusable for any indoor-static-collision test (corpse pickup boundaries, door swings, etc.). Test baseline: 1167 + 5 (harness) = 1172 + 8 pre-existing failures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3d2d10b331
commit
227a77522a
1 changed files with 68 additions and 5 deletions
|
|
@ -96,14 +96,23 @@ public class CellarUpTrajectoryReplayTests
|
||||||
private const float StepDownHeight = 0.04f;
|
private const float StepDownHeight = 0.04f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sphere center starts above cellar floor by exactly the radius
|
/// Sphere center starts slightly ABOVE its resting position on the
|
||||||
/// (bottom resting on floor). Y=9.5 is ~0.75 m before the ramp foot
|
/// cellar floor (offset by an additional 0.05 m above sphere-bottom-
|
||||||
/// at Y=8.75 (live-capture ramp plane equation:
|
/// on-floor) to avoid the BSP query's floating-point boundary at
|
||||||
/// <c>0.719·y + 0.695·z = 69.5035</c> → y=8.75 at z=90.95).
|
/// exact contact. With sphere center at exactly Z=floor+radius, the
|
||||||
|
/// engine reports hit=yes (back-face contact) and the body goes
|
||||||
|
/// airborne; with a 0.05 m lift, step-down on tick 1 should snap
|
||||||
|
/// the sphere cleanly to the floor.
|
||||||
|
///
|
||||||
|
/// <para>
|
||||||
|
/// Y=9.5 is ~0.75 m before the ramp foot at Y=8.75 (live-capture
|
||||||
|
/// ramp plane: <c>0.719·y + 0.695·z = 69.5035</c> → y=8.75 at z=90.95).
|
||||||
/// X=141.5 matches the live capture's X.
|
/// X=141.5 matches the live capture's X.
|
||||||
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
private const float InitialZLift = 0.05f;
|
||||||
private static readonly Vector3 InitialSphereWorld =
|
private static readonly Vector3 InitialSphereWorld =
|
||||||
new(141.5f, 9.5f, CellarFloorZ + SphereRadius);
|
new(141.5f, 9.5f, CellarFloorZ + SphereRadius + InitialZLift);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Per-tick forward offset (−Y direction toward the ramp).
|
/// Per-tick forward offset (−Y direction toward the ramp).
|
||||||
|
|
@ -168,6 +177,60 @@ public class CellarUpTrajectoryReplayTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Experiment: drive without a PhysicsBody (no CP seeding, no
|
||||||
|
/// cross-tick state). Tests whether the airborne-at-tick-1 issue
|
||||||
|
/// is caused by the seeded CP creating a false collision against
|
||||||
|
/// the cellar floor.
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public void Harness_DiagnosticDump_NoBodySeed()
|
||||||
|
{
|
||||||
|
PhysicsDiagnostics.ProbeResolveEnabled = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var (engine, _) = BuildEngineWithCellarFixtures();
|
||||||
|
|
||||||
|
uint cellId = CellarId;
|
||||||
|
bool isOnGround = true;
|
||||||
|
Vector3 pos = InitialSphereWorld;
|
||||||
|
|
||||||
|
var trajectory = new List<TrajectoryPoint>
|
||||||
|
{
|
||||||
|
new(0, pos, cellId, isOnGround, false),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int tick = 1; tick <= 10; tick++)
|
||||||
|
{
|
||||||
|
Vector3 target = pos + PerTickOffset;
|
||||||
|
var result = engine.ResolveWithTransition(
|
||||||
|
pos, target, cellId,
|
||||||
|
SphereRadius, SphereHeight,
|
||||||
|
StepUpHeight, StepDownHeight,
|
||||||
|
isOnGround,
|
||||||
|
body: null, // ← no body, no CP seed
|
||||||
|
moverFlags: ObjectInfoState.IsPlayer | ObjectInfoState.EdgeSlide,
|
||||||
|
movingEntityId: 0);
|
||||||
|
|
||||||
|
pos = result.Position;
|
||||||
|
cellId = result.CellId;
|
||||||
|
isOnGround = result.IsOnGround;
|
||||||
|
trajectory.Add(new(tick, pos, cellId, isOnGround, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = "No-body trajectory (10 ticks):\n " +
|
||||||
|
string.Join("\n ", trajectory.Select(p =>
|
||||||
|
$"tick={p.Tick} pos=({p.Position.X:F4},{p.Position.Y:F4},{p.Position.Z:F4}) " +
|
||||||
|
$"onGround={p.IsOnGround}"));
|
||||||
|
|
||||||
|
Assert.True(true, msg);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
PhysicsDiagnostics.ProbeResolveEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Documents finding #2: at the initial grounded position, the
|
/// Documents finding #2: at the initial grounded position, the
|
||||||
/// engine reports the cellar floor as a non-walkable collision
|
/// engine reports the cellar floor as a non-walkable collision
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue