fix(physics): Task 3 follow-up — obstruction_ethereal consume for Cylinder+Sphere shapes
Retail oracle greps confirmed: - CSphere::intersects_sphere @ 0x00537ae4 (pc:321692): the ethereal branch is `void __thiscall` — all paths return void (no COLLIDED). The function performs a proximity check only; no blocking result is produced. - CCylSphere::intersects_sphere @ 0x0053b4a0 (pc:324573): same void-return pattern — ethereal branch calls collides_with_sphere (check only, no slide), all returns are void = passable. Change: added `if (sp.ObstructionEthereal) return TransitionState.OK` at the top of SphereCollision and CylinderCollision in TransitionTypes.cs, mirroring the void-return semantics of both retail functions. The existing per-object clear at pc:276989 (line 2837) still fires after the early OK return. Before this fix: an ethereal-alone NPC/ghost with a Cylinder or Sphere shadow shape would BLOCK the player (regression introduced when Task 3 made ETHEREAL- alone fall through ShouldSkip instead of instant-skipping). After: all three shape types — BSP (via BSPQuery Path 1), Sphere, and Cylinder — correctly pass through when obstruction_ethereal is set. Tests: added 4 tests to ObstructionEtherealTests.cs verifying: - Ethereal Cylinder → passable (sweep passes through, no CollisionNormalValid) - Ethereal Sphere → passable (same) - Non-ethereal Cylinder → still blocks (regression guard) - Non-ethereal Sphere → still blocks (regression guard) Full Core suite: 1584 pass, 0 fail, 2 skip (pre-existing dat skips). Pseudocode doc updated with confirmed cyl/sphere ethereal contracts and the complete set/clear/consume flow summary. Retail refs: - CSphere::intersects_sphere @ 0x00537ae4 / acclient_2013_pseudo_c.txt:321692 - CCylSphere::intersects_sphere @ 0x0053b4a0 / acclient_2013_pseudo_c.txt:324573 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3361a8d776
commit
dc1e927080
3 changed files with 298 additions and 20 deletions
|
|
@ -2986,6 +2986,15 @@ public sealed class Transition
|
|||
/// </summary>
|
||||
private TransitionState SphereCollision(ShadowEntry obj, SpherePath sp)
|
||||
{
|
||||
// Consume site 1 — CSphere::intersects_sphere @ 0x00537ae4 (pc:321692).
|
||||
// When obstruction_ethereal is set (target is ETHEREAL-alone, state & 0x4),
|
||||
// the retail function is void and all paths in the ethereal branch return
|
||||
// without producing a COLLIDED/Slid result — the player is fully passable.
|
||||
// We mirror this by returning OK immediately, skipping all blocking paths.
|
||||
// Retail ref: acclient_2013_pseudo_c.txt:321692.
|
||||
if (sp.ObstructionEthereal)
|
||||
return TransitionState.OK;
|
||||
|
||||
var ci = CollisionInfo;
|
||||
Vector3 sphereCurrPos = sp.GlobalCurrCenter[0].Origin;
|
||||
Vector3 sphereCheckPos = sp.GlobalSphere[0].Origin;
|
||||
|
|
@ -3090,6 +3099,15 @@ public sealed class Transition
|
|||
/// </summary>
|
||||
private TransitionState CylinderCollision(ShadowEntry obj, SpherePath sp, PhysicsEngine engine)
|
||||
{
|
||||
// Consume site 2 — CCylSphere::intersects_sphere @ 0x0053b4a0 (pc:324573).
|
||||
// When obstruction_ethereal is set (target is ETHEREAL-alone, state & 0x4),
|
||||
// the retail function is void and all paths in the ethereal branch return
|
||||
// without producing a COLLIDED/Slid result — the player is fully passable.
|
||||
// We mirror this by returning OK immediately, skipping all blocking paths.
|
||||
// Retail ref: acclient_2013_pseudo_c.txt:324573.
|
||||
if (sp.ObstructionEthereal)
|
||||
return TransitionState.OK;
|
||||
|
||||
var ci = CollisionInfo;
|
||||
var oi = ObjectInfo;
|
||||
Vector3 sphereCurrPos = sp.GlobalCurrCenter[0].Origin;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue