From 2deb53995363da3d26cae868ee2621ed2a64716d Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 25 May 2026 10:45:41 +0200 Subject: [PATCH] docs(handoff): add second door-bug symptom (over-penetration before block) --- ...5-25-door-bug-cdb-retail-trace-findings.md | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/docs/research/2026-05-25-door-bug-cdb-retail-trace-findings.md b/docs/research/2026-05-25-door-bug-cdb-retail-trace-findings.md index 36c2c4d..fb3f548 100644 --- a/docs/research/2026-05-25-door-bug-cdb-retail-trace-findings.md +++ b/docs/research/2026-05-25-door-bug-cdb-retail-trace-findings.md @@ -69,6 +69,37 @@ traversal. Once that's in place, the existing Path 5 changes + TransitionalInsert NegPolyHit dispatch should fire correctly and produce the block. +## Second symptom flagged by user (2026-05-25 evening) + +User flagged: "we get run a bit into the door as well when it blocks. +That is not retail behavior." + +Over-penetration before block = our BSP detects collision AFTER the +sphere has already moved into the surface (static overlap detection) +vs retail's swept-sphere collision (predicts the t-value of first +contact along the motion path and stops the sphere at the surface). + +This is the SAME ROOT MECHANISM as the squeeze-through: +sphere_intersects_poly in retail does swept collision with the +motion vector (var_44 = sphere_center - prev_center). Our +`SphereIntersectsPolyInternal` takes a `movement` parameter but the +internal poly-test logic may not actually use it for swept detection. + +Verifying: read SphereIntersectsPolyInternal and check whether it +uses the `movement` vector for swept-sphere-vs-poly intersection +testing (computes the t-value where sphere first contacts the poly +along motion), or just does static overlap (sphere center +/- radius +overlaps poly plane). Retail does swept (the `var_44` in +sphere_intersects_poly is the motion delta). + +Single fix needed in next session: SphereIntersectsPolyInternal needs to: +1. Implement swept-sphere-vs-poly detection (use the motion vector) +2. Record the closest-considered polygon for near-miss handling + +Both feed into the existing Path 5 + TransitionalInsert dispatch +(committed today). Once that single function does its job correctly, +both symptoms close at once. + ## What the cdb trace proved | Symbol | v1 hits | v2 hits | v3 hits | @@ -115,14 +146,26 @@ side-effect; our equivalent only sets it on full hits. Current phase: A6.P4 door bug — implement near-miss polygon recording in SphereIntersectsPolyInternal. + TWO SYMPTOMS to fix simultaneously (same root cause): + (a) Off-center inside-out: sphere walks (or squeezes) past door + (b) When blocked: sphere visibly penetrates the door before stopping + + Both = static overlap detection without near-miss recording. + Retail uses swept-sphere-vs-poly intersection (uses motion vector + to compute t-value of first contact, stops sphere at surface) + AND records the closest near-miss polygon during BSP traversal. + First move: read SphereIntersectsPolyInternal in - src/AcDream.Core/Physics/BSPQuery.cs (the function used at the - Path 5 entry). Identify where polygons are tested during BSP - traversal. Add a "closestPoly" output param that's set to ANY - polygon considered during traversal (not just hit polygons). + src/AcDream.Core/Physics/BSPQuery.cs. Check whether the `movement` + param is actually used for swept-sphere-vs-poly testing. If not + (just static overlap), that's symptom (b). Add swept detection + and a "closestPoly" output param set on ANY polygon considered + during traversal (not just hits). That closes symptom (a) too. + Then the Path 5 branch `if (hitPoly0 is not null)` will fire on near-miss cases, NegPolyHitDispatch will set NegPolyHit, and the - TransitionalInsert dispatch (already landed) will block the sphere. + TransitionalInsert dispatch (already landed) will block the sphere + at the surface (swept-detected t-value), not after penetration. Retail oracle: BSPTREE::find_collisions + sphere_intersects_poly vtable call at acclient_2013_pseudo_c.txt:0053a630-0053a6fb.