fix(physics): L.2.3h — skip Placement in step-down contact-recovery branch
Live-test bug: player getting "super stuck" near walls without touching them. Diagnostic showed 0 step-up calls, so the issue wasn't in DoStepUp. Root cause: my subagent's L.2.1 commit added a Placement validation inside DoStepDown to prevent step-up-through-walls. That check is right for DoStepUp's call (the original use case). But DoStepDown is ALSO called from TransitionalInsert's contact-recovery branch when the per- sub-step contact plane is briefly lost (e.g., right after a wall-slide nudges the sphere slightly upward). For that "maintain contact during normal movement" use, the Placement check is over-strict. Wall-slide can leave the sphere with sub-EPSILON overlap of the wall's BSP solid; SphereIntersectsSolid returns Collided inside Placement; DoStepDown returns false; my L.2.3e then escalates that to TransitionState.Collided in the outer loop; ValidateTransition reverts the position to CurPos every frame. Result: player stuck near the wall without ever touching it. Fix: add a `bool runPlacement = true` parameter to DoStepDown. - DoStepUp passes the default (Placement runs — protects step-up). - TransitionalInsert's contact-recovery branch passes false (Placement skipped — accepts whatever walkable surface is found within reach). This preserves L.2.3e's edge-block (genuine edges return Collided because no walkable is found, not because Placement rejected) while unbreaking normal-walking-near-walls. ACE Transition.cs:731-741 runs Placement unconditionally, but ACE's pre-step-down state machine is cleaner — acdream's residual wall-slide artifacts make Placement misfire here. Test count 825/825 still pass. Build clean. Live verification needed: walk near a wall, should no longer get stuck. Walk off a tall (>1.5m) balcony, should still edge-block. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
eed8e8ccaa
commit
4cbfe0a5f8
1 changed files with 29 additions and 4 deletions
|
|
@ -630,9 +630,17 @@ public sealed class Transition
|
|||
|
||||
float radsum = sp.GlobalSphere[0].Radius * 2f;
|
||||
|
||||
// L.2.3h (2026-04-29): pass runPlacement=false. This
|
||||
// branch's job is to maintain ground contact during normal
|
||||
// movement (e.g., walking over small bumps or near walls).
|
||||
// The Placement check inside DoStepDown is too strict for
|
||||
// this use — minor wall overlap from a prior wall-slide
|
||||
// would fail Placement and trigger the L.2.3e edge-block,
|
||||
// leaving the player stuck near walls. DoStepUp still runs
|
||||
// Placement for the step-UP-through-walls protection.
|
||||
if (radsum >= stepDownHeight)
|
||||
{
|
||||
if (DoStepDown(stepDownHeight, zVal, engine))
|
||||
if (DoStepDown(stepDownHeight, zVal, engine, runPlacement: false))
|
||||
{
|
||||
sp.WalkableValid = false;
|
||||
return TransitionState.OK;
|
||||
|
|
@ -641,8 +649,8 @@ public sealed class Transition
|
|||
else
|
||||
{
|
||||
stepDownHeight *= 0.5f;
|
||||
if (DoStepDown(stepDownHeight, zVal, engine)
|
||||
|| DoStepDown(stepDownHeight, zVal, engine))
|
||||
if (DoStepDown(stepDownHeight, zVal, engine, runPlacement: false)
|
||||
|| DoStepDown(stepDownHeight, zVal, engine, runPlacement: false))
|
||||
{
|
||||
sp.WalkableValid = false;
|
||||
return TransitionState.OK;
|
||||
|
|
@ -1314,7 +1322,8 @@ public sealed class Transition
|
|||
/// Ported from pseudocode section 5 (StepDown).
|
||||
/// ACE: Transition.StepDown(float stepDownHeight, float zVal).
|
||||
/// </summary>
|
||||
private bool DoStepDown(float stepDownHeight, float walkableZ, PhysicsEngine engine)
|
||||
private bool DoStepDown(float stepDownHeight, float walkableZ, PhysicsEngine engine,
|
||||
bool runPlacement = true)
|
||||
{
|
||||
var sp = SpherePath;
|
||||
|
||||
|
|
@ -1348,6 +1357,22 @@ public sealed class Transition
|
|||
&& CollisionInfo.ContactPlaneValid
|
||||
&& CollisionInfo.ContactPlane.Normal.Z >= walkableZ)
|
||||
{
|
||||
// L.2.3h (2026-04-29): Placement validation is for the
|
||||
// DoStepUp use case (prevents climbing through walls by
|
||||
// stepping up onto ground beyond a tall wall). For the
|
||||
// "maintain contact during normal movement" use case (called
|
||||
// from TransitionalInsert's contact-recovery branch), the
|
||||
// Placement check is over-strict — slight wall overlap from
|
||||
// a prior wall-slide makes Placement reject, then the caller
|
||||
// returns Collided (L.2.3e) and the player gets stuck near
|
||||
// walls without ever touching them.
|
||||
//
|
||||
// ACE Transition.cs:731-741 runs Placement here unconditionally,
|
||||
// but ACE's pre-step-down state is cleaner — we have residual
|
||||
// wall-slide artifacts that make Placement misfire.
|
||||
if (!runPlacement)
|
||||
return true;
|
||||
|
||||
// Placement validation: can we actually stand here?
|
||||
var savedInsert = sp.InsertType;
|
||||
sp.InsertType = InsertType.Placement;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue