From 892019bc9a804695e9fccf32679b2aee486aa2f2 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 22 May 2026 10:19:48 +0200 Subject: [PATCH] =?UTF-8?q?fix(phys):=20A6.P3=20slice=202=20=E2=80=94=20re?= =?UTF-8?q?move=20L622=20per-tick=20CP=20seed=20(issue=20#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes issue #96 (per-tick PhysicsEngine.ResolveWithTransition CP seed contributing 99.3% of post-slice-1 CP writes). Matches retail's CTransition::init at acclient_2013_pseudo_c.txt:271954 which explicitly clears contact_plane_valid = 0 at transition start. Cross-tick CP retention now flows entirely via retail-faithful mechanisms: - Mechanism A: BSPQuery.FindCollisions Path-6 land write - Mechanism B: Transition.ValidateTransition LKCP restore (slice 1) - Body persist at transition end (already existed) Cost (deliberate): AdjustOffset on sub-step 1 of each tick takes the 'no contact plane' path. Slope-snap loss is imperceptible (sub-steps are small, sub-steps 2+ pick up CP normally). Likely closes issue #97 (phantom collisions + fall-through) as side-effect — hypothesis was stale-CP slope-snap from body.ContactPlane of a previous cell. To be verified post-commit via re-capture + user happy-test. Verification this commit: - Test suite: 1148 pass + 8 pre-existing fail (baseline maintained) - scen3 re-capture pending (separate commit) Co-Authored-By: Claude Opus 4.7 (1M context) --- src/AcDream.Core/Physics/PhysicsEngine.cs | 55 ++++++++++++----------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/AcDream.Core/Physics/PhysicsEngine.cs b/src/AcDream.Core/Physics/PhysicsEngine.cs index d23a000..f225b4d 100644 --- a/src/AcDream.Core/Physics/PhysicsEngine.cs +++ b/src/AcDream.Core/Physics/PhysicsEngine.cs @@ -597,33 +597,36 @@ public sealed class PhysicsEngine if (isOnGround) transition.ObjectInfo.State |= ObjectInfoState.Contact | ObjectInfoState.OnWalkable; - // K-fix7 (2026-04-26): only seed the contact plane when the body - // is actually grounded. Pre-seeding while AIRBORNE caused - // AdjustOffset's "Have a contact plane / Moving away from plane" - // branch to fire on every jump step — which calls - // Plane::snap_to_plane on the offset and ZEROES the Z component, - // killing all upward jump motion (the body's Z velocity stayed - // ~9 m/s but Position.Z never advanced because every step's - // offset got snapped flat). Retail's CTransition::init at - // 0x509dd0 (named-retail line 271954) explicitly clears - // contact_plane_valid = 0 at the start of every transition - // resolve, then ValidateWalkable re-establishes it during the - // sweep when the sphere bottom is within EPSILON of the terrain - // plane — so for grounded motion the plane is set fresh every - // resolve, and for airborne motion no plane interferes. + // A6.P3 slice 2 (2026-05-22) — DO NOT seed ContactPlane at + // transition start. Retail's CTransition::init at 0x509dd0 + // (acclient_2013_pseudo_c.txt:271954) explicitly clears + // contact_plane_valid = 0 — retail does NOT seed. Cross-tick + // CP retention flows via: + // - Mechanism A: BSPQuery.FindCollisions Path-6 land write + // (writes ContactPlane during the sub-step loop when the + // sphere ground-contacts a floor poly) + // - Mechanism B: Transition.ValidateTransition LKCP restore + // (slice 1 commit 5aba071; restores ContactPlane from + // LastKnownContactPlane post-sub-step when sphere close to + // LKCP) + // - Body persist below: at transition end, body.ContactPlane + // gets set from ci.ContactPlane OR ci.LastKnownContactPlane + // so the NEXT tick's body state is preserved. // - // We KEEP the seeding when isOnGround for slope-walking - // continuity (the original concern that motivated the seed) — - // walking up a hill needs the previous step's slope to project - // movement properly. Airborne / jumping must start with no - // plane so AdjustOffset preserves Z. - if (isOnGround && body is not null && body.ContactPlaneValid) - { - transition.CollisionInfo.SetContactPlane( - body.ContactPlane, - body.ContactPlaneCellId, - body.ContactPlaneIsWater); - } + // Cost: AdjustOffset on sub-step 1 of each tick has no CP and + // takes the "no contact plane" path (TransitionTypes.cs:2329-2334) + // — slide-projects only, no slope-snap. Sub-steps 2+ pick up CP + // from Mechanism A / B as normal. Imperceptible in practice. + // + // Removing this seed closes issue #96 (per-tick CP-write blowup; + // 99.3% of post-slice-1 CP writes came from the seed) and is + // hypothesized to close issue #97 (phantom collisions + + // fall-through; suspected stale-CP slope-snap was the cause). + // + // Previous K-fix7 seed (2026-04-26 to slice-1 ship) deliberately + // diverged from retail for "slope-walking continuity" but the + // tradeoff (per-tick CP writes, stale-CP slope-snap) was not + // worth it. // Retail CPhysicsObj::get_object_info also seeds SlidingNormal when // transient_state has bit 2 set. This matters for one-step/frame hits: