fix(physics): restore retail path-6 collision response
This commit is contained in:
parent
acec33eca8
commit
75b6f6b6c9
8 changed files with 523 additions and 223 deletions
|
|
@ -2213,59 +2213,10 @@ public static class BSPQuery
|
|||
}
|
||||
|
||||
var worldNormal0 = L2W(hitPoly0!.Plane.Normal);
|
||||
|
||||
// L.4 slide-tangent for steep airborne hits (2026-04-30).
|
||||
//
|
||||
// For polygons too steep to walk on (worldNormal.Z < FloorZ),
|
||||
// skip the SetCollide → Path-4 → ContactPlane landing chain.
|
||||
// That chain commits the body to the steep surface, leading
|
||||
// to the "stuck in falling animation on the roof" bug — once
|
||||
// grounded with a steep ContactPlane, our step_up_slide /
|
||||
// cliff_slide / edge_slide chain can't produce smooth
|
||||
// descent and the body wedges or "falls a bit at a time"
|
||||
// when bumped.
|
||||
//
|
||||
// Instead: project the move along the steep face (remove
|
||||
// the into-wall displacement), set CollisionNormal +
|
||||
// SlidingNormal, return Slid. Same shape as Path 5's
|
||||
// step-up fallback (line 1545-1547) and CylinderCollision
|
||||
// (TransitionTypes.cs:1518-1522). Position is updated in-
|
||||
// place; on the next resolver iteration the sphere is
|
||||
// outside the poly, FindCollisions returns OK, and
|
||||
// ValidateTransition commits the new position. Body stays
|
||||
// airborne, falling animation continues, and gravity's
|
||||
// tangent component drifts the body downhill until it
|
||||
// slides off the slope's edge.
|
||||
//
|
||||
// This is a deliberate deviation from retail (retail uses
|
||||
// SetCollide unconditionally and lets find_walkable +
|
||||
// step_up_slide produce the slide). Validated against
|
||||
// retail debugger trace 2026-04-30: retail body did not
|
||||
// wedge; our retail-faithful port DID wedge because we're
|
||||
// missing implementation details of the step_up_slide /
|
||||
// cliff_slide chain on grounded-steep movement. The
|
||||
// slide-tangent here produces user-acceptable behavior
|
||||
// (slides off naturally) while the deeper chain port is
|
||||
// researched. Filed as L.5+ followup for retail-strict.
|
||||
if (worldNormal0.Z < PhysicsGlobals.FloorZ)
|
||||
{
|
||||
Vector3 currWorld = path.GlobalCurrCenter[0].Origin;
|
||||
Vector3 endWorld = path.GlobalSphere[0].Origin;
|
||||
Vector3 gDelta = endWorld - currWorld;
|
||||
float diff = Vector3.Dot(worldNormal0, gDelta);
|
||||
if (diff < 0f)
|
||||
path.AddOffsetToCheckPos(-worldNormal0 * diff);
|
||||
|
||||
collisions.SetCollisionNormal(worldNormal0);
|
||||
collisions.SetSlidingNormal(worldNormal0);
|
||||
// L.2d slice 1 (2026-05-13): diagnostic side-channel.
|
||||
if (PhysicsDiagnostics.ProbeBuildingEnabled || PhysicsDiagnostics.ProbeIndoorBspEnabled)
|
||||
PhysicsDiagnostics.LastBspHitPoly = hitPoly0;
|
||||
return TransitionState.Slid;
|
||||
}
|
||||
|
||||
// ─── SetCollide response (shallow / walkable) ───────────
|
||||
// Per retail (acclient_2013_pseudo_c.txt:323783-323821).
|
||||
// Retail Path 6 always defers a primary/foot-sphere hit to
|
||||
// the outer Collide handler, regardless of polygon steepness.
|
||||
// The BSP layer neither projects a tangent nor writes the
|
||||
// persistent sliding normal (0x0053A7B3-0x0053A7DC).
|
||||
path.SetCollide(worldNormal0);
|
||||
path.WalkableAllowance = PhysicsGlobals.LandingZ;
|
||||
// L.2d slice 1 (2026-05-13): diagnostic side-channel.
|
||||
|
|
|
|||
|
|
@ -2036,23 +2036,6 @@ internal static class FlatBspQuery
|
|||
|
||||
Vector3 worldNormal0 = LocalToWorld(
|
||||
tree.PolygonTable.Polygons[defaultHitPolygonIndex0].Plane.Normal);
|
||||
if (worldNormal0.Z < PhysicsGlobals.FloorZ)
|
||||
{
|
||||
Vector3 currentWorld =
|
||||
path.GlobalCurrCenter[0].Origin;
|
||||
Vector3 endWorld =
|
||||
path.GlobalSphere[0].Origin;
|
||||
Vector3 globalDelta = endWorld - currentWorld;
|
||||
float difference = Vector3.Dot(worldNormal0, globalDelta);
|
||||
if (difference < 0f)
|
||||
path.AddOffsetToCheckPos(-worldNormal0 * difference);
|
||||
|
||||
collisions.SetCollisionNormal(worldNormal0);
|
||||
collisions.SetSlidingNormal(worldNormal0);
|
||||
RecordDiagnosticHit(tree, defaultHitPolygonIndex0);
|
||||
return TransitionState.Slid;
|
||||
}
|
||||
|
||||
path.SetCollide(worldNormal0);
|
||||
path.WalkableAllowance = PhysicsGlobals.LandingZ;
|
||||
RecordDiagnosticHit(tree, defaultHitPolygonIndex0);
|
||||
|
|
@ -2075,28 +2058,9 @@ internal static class FlatBspQuery
|
|||
{
|
||||
Vector3 worldNormal1 = LocalToWorld(
|
||||
tree.PolygonTable.Polygons[defaultHitPolygonIndex1].Plane.Normal);
|
||||
if (worldNormal1.Z < PhysicsGlobals.FloorZ)
|
||||
{
|
||||
Vector3 currentWorld =
|
||||
path.GlobalCurrCenter[0].Origin;
|
||||
Vector3 endWorld =
|
||||
path.GlobalSphere[0].Origin;
|
||||
Vector3 globalDelta = endWorld - currentWorld;
|
||||
float difference =
|
||||
Vector3.Dot(worldNormal1, globalDelta);
|
||||
if (difference < 0f)
|
||||
path.AddOffsetToCheckPos(-worldNormal1 * difference);
|
||||
|
||||
collisions.SetCollisionNormal(worldNormal1);
|
||||
collisions.SetSlidingNormal(worldNormal1);
|
||||
RecordDiagnosticHit(tree, defaultHitPolygonIndex1);
|
||||
return TransitionState.Slid;
|
||||
}
|
||||
|
||||
path.SetCollide(worldNormal1);
|
||||
path.WalkableAllowance = PhysicsGlobals.LandingZ;
|
||||
collisions.SetCollisionNormal(worldNormal1);
|
||||
RecordDiagnosticHit(tree, defaultHitPolygonIndex1);
|
||||
return TransitionState.Adjusted;
|
||||
return TransitionState.Collided;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue