fix(phys): A6.P3 #98 — gate ContactPlane assignment by Normal.Z (Shape 1)
Adds PhysicsGlobals.ContactPlaneFlatThreshold = 0.99f and uses it at both BSPQuery.AdjustSphereToPlane call sites that previously set CP unconditionally on any walkable polygon found by FindWalkableInternal. Backed by the retail cdb capture in cellar_up_capture_1: across 161 set_contact_plane writes during 5 seconds of cellar-up climbing, EVERY write lands on a flat (Normal.Z = 1.0) plane — cellar floor at world Z=90.95 or cottage floor at world Z=94. The cellar ramp (Normal.Z = 0.695, walkable per FloorZ but sloped ~46 degrees) is never set as CP in retail. Acdream's prior behavior of setting CP=ramp caused two cascading issues at the top of the ramp: 1. AdjustOffset's slope-projection produced +Z gain per call (correct in isolation) but inflated step-up's responsibility to "find the next walkable below the lifted check position". 2. step-up's downward step-down probe found no walkable within 0.6m below the proposed check (cottage floor at Z=94 is ABOVE, not below), so step-down rejected, sphere rolled back. Infinite freeze at world Z ~= 92.80. With CP only set on flat polygons, sloped surfaces drive collision detection and walkable-poly tracking (via path.SetWalkable) but don't override the resting CP. The sphere should now climb the ramp via step-up over the ramp polygon, with CP staying on the flat cellar floor until the sphere reaches the flat cottage floor. Tests: 1167 + 8 baseline maintained. No regression. The Issue98 replay tests still pass — they document the failing-frame geometry (sphere world Z=92.01 below cottage floor), which doesn't change; the fix prevents the sphere from getting STUCK at that altitude in the first place. Live visual verification required next. If the live test shows new failure modes (sphere stuck somewhere else, doesn't climb at all, climbs but slides off, etc), the threshold (0.99) or the gating approach itself may need refining. This is the conservative empirical version of Shape 1; the named- decomp research did not conclusively prove the exact retail gate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8daf7e7e4d
commit
0cb4c59681
2 changed files with 31 additions and 2 deletions
|
|
@ -1230,7 +1230,17 @@ public static class BSPQuery
|
|||
var worldNormal = TransformNormal(polyHit.Plane.Normal, localToWorld);
|
||||
var worldVertices = TransformVertices(polyHit.Vertices, localToWorld, scale, worldOrigin);
|
||||
var worldPlane = BuildWorldPlane(worldNormal, worldVertices);
|
||||
collisions.SetContactPlane(worldPlane, path.CheckCellId, false);
|
||||
|
||||
// A6.P3 #98 (2026-05-23): gate ContactPlane assignment by Normal.Z.
|
||||
// Retail's cdb capture shows CP is only ever set to flat polygons
|
||||
// (Normal.Z = 1.0); the cellar ramp (Normal.Z = 0.695) is never CP.
|
||||
// Setting CP=ramp made AdjustOffset slope-project forward motion
|
||||
// and caused the sphere to wedge at the ramp top when step-up's
|
||||
// downward probe couldn't find cottage floor (which is ABOVE).
|
||||
// Polygons that fail this gate still drive collision detection
|
||||
// and walkable-polygon tracking — they just don't become CP.
|
||||
if (worldNormal.Z >= PhysicsGlobals.ContactPlaneFlatThreshold)
|
||||
collisions.SetContactPlane(worldPlane, path.CheckCellId, false);
|
||||
|
||||
path.SetWalkable(worldPlane, worldVertices, Vector3.UnitZ);
|
||||
|
||||
|
|
@ -1770,7 +1780,14 @@ public static class BSPQuery
|
|||
var worldNormal = TransformNormal(hitPoly.Plane.Normal, localToWorld);
|
||||
var worldVertices = TransformVertices(hitPoly.Vertices, localToWorld, scale, worldOrigin);
|
||||
var worldPlane = BuildWorldPlane(worldNormal, worldVertices);
|
||||
collisions.SetContactPlane(worldPlane, path.CheckCellId, false);
|
||||
|
||||
// A6.P3 #98 (2026-05-23): same Normal.Z gate as
|
||||
// AdjustSphereToPlane above — only flat polygons become CP.
|
||||
// Sloped walkable polygons (cellar ramp etc.) drive collision
|
||||
// and walkable tracking but don't override the resting CP.
|
||||
if (worldNormal.Z >= PhysicsGlobals.ContactPlaneFlatThreshold)
|
||||
collisions.SetContactPlane(worldPlane, path.CheckCellId, false);
|
||||
|
||||
path.SetWalkable(worldPlane, worldVertices, Vector3.UnitZ);
|
||||
|
||||
if (PhysicsDiagnostics.ProbeBuildingEnabled || PhysicsDiagnostics.ProbeIndoorBspEnabled)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue