fix(physics): preserve retail step-down probe state
This commit is contained in:
parent
1fd5da67b4
commit
acec33eca8
5 changed files with 249 additions and 36 deletions
|
|
@ -5234,29 +5234,12 @@ public sealed class Transition
|
|||
// overlapping solid geometry, for both ordinary contact
|
||||
// maintenance and StepUp.
|
||||
//
|
||||
// A6.P3 slice 4 (2026-05-22) — reset WalkInterp to 1.0 before
|
||||
// the placement_insert. The prior TransitionalInsert(5) probe
|
||||
// above may have consumed WalkInterp down to 0 (e.g. on a
|
||||
// step-up onto a sloped ramp — AdjustSphereToPlane lifted the
|
||||
// sphere by step_down_amt and ate all the interp). With
|
||||
// WalkInterp=0, subsequent AdjustSphereToPlane calls' `interp
|
||||
// >= path.WalkInterp` check fires immediately (0 >= 0) and
|
||||
// rejects any push-back — so any geometric overlap that needs
|
||||
// push-out resolution returns false → placement fails → step-up
|
||||
// returns failure → step_up_slide loop → player stuck.
|
||||
//
|
||||
// Retail's CTransition::step_down (acclient_2013_pseudo_c.txt:272952)
|
||||
// resets walk_interp = 1 at function entry. The placement_insert
|
||||
// (line 272989-272990) runs after that initial reset; we believe
|
||||
// placement-insert mode doesn't consume walk_interp the same way
|
||||
// because it's a "can we fit here" check, not a movement sweep.
|
||||
//
|
||||
// This fix is the cellar-up target (issue #98). May also help
|
||||
// other "step-up onto sloped surface" scenarios.
|
||||
// Retail resets walk_interp once at step_down entry. The final
|
||||
// placement consumes the exact value left by the support and
|
||||
// check-walkable probes; there is no second reset here.
|
||||
var savedInsert = sp.InsertType;
|
||||
float winterpBeforePlacement = sp.WalkInterp;
|
||||
sp.InsertType = InsertType.Placement;
|
||||
sp.WalkInterp = 1.0f;
|
||||
|
||||
var placeState = TransitionalInsert(1, engine);
|
||||
|
||||
|
|
@ -5453,12 +5436,9 @@ public sealed class Transition
|
|||
/// TransitionalInsert before re-testing as Placement.
|
||||
///
|
||||
/// <para>
|
||||
/// Returns true if a walkable surface was found within reach (i.e. the
|
||||
/// sphere can land here). Returns false if:
|
||||
/// - ObjectInfo.OnWalkable is NOT set (always walkable by convention).
|
||||
/// - CheckWalkables() already confirmed a walkable (skip the probe).
|
||||
/// - The downward probe returned OK (meaning: no walkable was found
|
||||
/// within reach, so we CANNOT land → transitState == OK → return false).
|
||||
/// Returns true when no support check is required or when a walkable
|
||||
/// surface is found within reach. Returns false when the downward probe
|
||||
/// returns OK (no walkable collision was found).
|
||||
/// </para>
|
||||
///
|
||||
/// ACE: Transition.CheckWalkable (Transition.cs:206-235).
|
||||
|
|
@ -5478,7 +5458,13 @@ public sealed class Transition
|
|||
if (sp.CheckWalkables())
|
||||
return true;
|
||||
|
||||
sp.SaveCheckPos();
|
||||
// Retail CTransition::check_walkable (0x0050AFF0) uses stack locals
|
||||
// for this nested probe. Preserve SPHEREPATH's outer backup pair for
|
||||
// edge_slide if the support check fails.
|
||||
Vector3 savedCheckPos = sp.CheckPos;
|
||||
uint savedCheckCellId = sp.CheckCellId;
|
||||
Vector3 savedBackupCheckPos = sp.BackupCheckPos;
|
||||
uint savedBackupCheckCellId = sp.BackupCheckCellId;
|
||||
|
||||
float stepHeight = oi.StepDownHeight;
|
||||
var globSphere = sp.GlobalSphere[0];
|
||||
|
|
@ -5496,7 +5482,9 @@ public sealed class Transition
|
|||
var transitState = TransitionalInsert(1, engine);
|
||||
|
||||
sp.CheckWalkable = false;
|
||||
sp.RestoreCheckPos();
|
||||
sp.SetCheckPos(savedCheckPos, savedCheckCellId);
|
||||
sp.BackupCheckPos = savedBackupCheckPos;
|
||||
sp.BackupCheckCellId = savedBackupCheckCellId;
|
||||
|
||||
// ACE returns (transitState != OK) — i.e. true when we DID find a
|
||||
// walkable (collision probe returned Adjusted/Collided).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue