diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 64e04419..a4cd549b 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -46,56 +46,45 @@ Copy this block when adding a new issue: --- -## #185 — LOCAL player jams half-way up outdoor stairs (house on stilts); a jump clears it +## #185 — [DONE 2026-07-08 · `07c5b832`] LOCAL player jams half-way up outdoor stairs (house on stilts); a jump clears it -**Status:** OPEN (investigated, root cause characterised — NOT yet fixed; a fix touches the frozen collision internals → brainstorm gate first) -**Severity:** MEDIUM -**Filed:** 2026-07-08 -**Component:** physics / collision (building/stair BSP + step-up vs slide classification) +**Status:** DONE (live gate PASSED — "OK works"). Root cause was NOT the collision response. +**Severity:** MEDIUM · **Filed:** 2026-07-08 · **Component:** physics / collision-registration (landblock shadow objects) -**Description:** Running the LOCAL player up the outside stairs of a house-on-stilts, you hit -an invisible block **half-way up** that you cannot walk through — you shuffle sideways but -never advance. **Jumping clears it** and you continue up normally. Pre-existing (observed -before the #184 work); unrelated to the remote de-overlap thread. Building object -`0xf6822103`, landblock `0xf682`, jam at world ≈ (132, 77.8, 61.4), cell `0xF682002C`. +**Description:** Running up the outside stairs of a house-on-stilts you hit an invisible wall +"in the middle of the stairs" (steps look unbroken) — you shuffle sideways, never advance; a +jump clears it. Landblock `0xf682`, jam ≈ world (132, 77.9, 61.5), cell `0xF682002C`. -**Root cause / status (from `ACDREAM_CAPTURE_RESOLVE` at the jam):** The staircase is a -fairly uniform ~0.4 m-rise / **38.7°** flight of tilted tread faces (`n=(0,-0.62,0.78)`), -which is under the ~49° walkable cutoff, so the player *glides* straight up it (long -no-collision stretches; the wireframe shows discrete stacked step faces). At **one junction -(~Z 61.4)** there is an anomalous **~52° face** (`collisionNormal=(0,0.78,0.62)`, constant -across every stuck frame → a real stable face, NOT the #137 synthetic-negated-run-direction -normal). 52° is just past the walkable cutoff, so the sweep treats it as a **wall**: it -**flattens that normal to a pure-horizontal `(0,1,0)` sliding normal** (Z zeroed) and slides -the player sideways in X, pinning Y+Z — instead of recognising it as a normal ~0.4 m **step** -and stepping the player up onto the next tread. The jump clears it because the jump's +Z -velocity is not in the horizontal `(0,1,0)` slide plane. The staircase continues climbable -above the jam (more 38.7° treads → a flat porch at Z 63.6) — so it is ONE localised spot, -not a general stair failure. Classic **#137 / building-collision-mesh junction-anomaly family** -(TS-4 sliding-normal-provenance), stair edition. +**Root cause (REAL — a uint32 overflow in the shadow-registry part-id, `07c5b832`):** +`GameWindow.cs` registered each landblock BSP part with a synthetic id `entity.Id * 256u + +partIndex`. That `<< 8` **overflows uint32** for class-prefixed landblock ids +(`0x40`/`0x80`/`0xC0`…) and drops the prefix byte, so different-class entities sharing the low +24 bits **collide on one shadow part-id**; `Register`'s deregister-then-insert silently +overwrites one entity's collision (`0xF6822100 ← {0x40F68221, 0xC0F68221}` — 23 such collisions +in landblock `0xF682` alone). Three mid-staircase steps therefore **rendered but had NO +collision**; the player floats into the hole and the (retail-faithful) `PrecipiceSlide` wedge +fires at the walkable edge = the "invisible wall." **The wedge was a symptom, not the cause.** +The two earlier theories in this session — the handoff's "convex-tread-edge synthetic normal" +and design-v1's "grounding-retention at a coplanar seam" — were both SUPERSEDED by the live +`[entity-source]`/`[bsp-test]` capture (#3) that mapped the collision hole + the 23 id +collisions. -**RESOLVED (artifact, not geometry) — `ACDREAM_PROBE_BUILDING=1` hit-poly capture:** at the -jam, ALL 156 building collisions are ONE polygon — a real, walkable **38.7° tread quad** -(`gfxObj=0x01000AC5`, `obj=0xF6822103`, `partIdx=3`, local plane `(-0.625,0,0.781)`; world -verts X 131.25–132.75, Y 77.00–77.50, Z 60.62–61.01). **There is NO riser / wall polygon in -the collision mesh at all.** The 52° "wall" normal from the resolve capture (`(0,0.78,0.62)`) -is that tread normal **rotated exactly 90°** (perpendicular; dot ≈ 0) — it does not exist in -the dat. So the block is a **synthetic sliding normal fabricated by our collision RESPONSE**, -not real geometry and not a step-height/budget issue: the foot sphere straddles a convex tread -edge (near a building-part seam — `partIdx=3`, neighbouring `gfxObj=0x01000ACA` present), hits -the lower tread poly, and the slide/validate chain invents a perpendicular normal, flattens it -to horizontal `(0,1,0)`, and slides the player sideways. **Confirmed #137 / TS-4 -sliding-normal-provenance family** (phantom wall at a convex edge/seam), stair edition. Fix -lives in that family (where the perpendicular normal is fabricated / how a convex walkable -tread edge is handled) — touches the frozen collision internals → brainstorm gate first. +**Fix (Option A, retail-faithful):** register each multi-part landblock entity via +`ShadowObjectRegistry.RegisterMultiPart` under its **unique 32-bit `entity.Id`** (retail +`CPhysicsObj::add_shadows_to_cells` → `CPartArray::AddPartsShadow` — one object, a part array; +no synthetic per-part id). New builder `ShadowShapeBuilder.FromLandblockBspParts`. Setup +cyl/sphere path unchanged (runs only when `entityBsp==0`, retail BSP-xor-cyl). Despawn is +landblock-scoped so the id change is safe. Does NOT touch the frozen collision internals. -**Files:** `src/AcDream.Core/Physics/TransitionTypes.cs` (step-up / slide classification, the -sliding-normal horizontalisation); building-collision mesh generation (BSP faces for -landblock stabs). Capture apparatus: `ACDREAM_CAPTURE_RESOLVE`. +**Files:** `src/AcDream.Core/Physics/ShadowShapeBuilder.cs` (`FromLandblockBspParts`), +`src/AcDream.App/Rendering/GameWindow.cs` (~7898 registration block). +**Tests:** `ShadowRegistrationOverflowTests` (overflow arithmetic; old scheme drops one; +`RegisterMultiPart` keeps both; builder), `Issue185OutdoorStairsSeamReplayTests` (dat-free +clean-climb pin). Core 2629 / App 741 green. Design: `docs/superpowers/specs/2026-07-08-185-outdoor-stairs-fix-design.md` (v2). -**Acceptance:** the LOCAL player walks up the full outdoor staircase of the house-on-stilts -without jumping; no sideways-slide pin at the ~Z 61.4 junction; regression pass on other -stairs/ramps (indoor + outdoor) — no new phantom blocks. +**Fallout note:** shared registration path → this was silently dropping collision on OTHER +landblock objects too (23 id collisions in one landblock); likely fixed a class of +"walked-through-a-thing-that's-clearly-there" bugs, not just these stairs. ---