From 34b7f1faa1fb3f81276f639fca745b2cb95d0276 Mon Sep 17 00:00:00 2001 From: Erik Date: Tue, 12 May 2026 19:46:45 +0200 Subject: [PATCH] docs(phys L.2d): slice 1 + 1.5 shipped handoff + 3rd plan-of-record reframe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L.2d as scoped is essentially closed at the Holtburg site. The slice-1.5 trace settled the question: the "I can't walk through doorways" symptom is a closed Door entity (Setup 0x020019FF named "Door") at the building threshold, not a building-BSP-collision issue. Building BSP is healthy. The two prior framings turned out wrong: - L.2a handoff (2026-05-12): "per-cell walkability missing" — based on hit attribution pointing at the building, missed the Door cylinder also colliding per tick. - L.2d slice 1 spec (2026-05-13 morning): "BSP shape fidelity, three hypotheses X/Y/Z" — ruled out by the trace once the probe labeling bug was fixed in slice 1.5. Handoff doc captures full evidence, side findings (building double- registration latent bug, missing PhysicsState in entity-source log), and a candidates list for the next-session ordering discussion. Plan-of-record L.2d sub-direction paragraph updated to match: "watch- and-wait" mode, no more slices until a new shape-fidelity bug is observed at a different site. Door-state handling becomes its own sub-phase, scope deferred to project-ordering discussion. Co-Authored-By: Claude Opus 4.7 (1M context) --- ...26-04-29-movement-collision-conformance.md | 54 ++-- .../2026-05-13-l2d-slice1-shipped-handoff.md | 251 ++++++++++++++++++ 2 files changed, 283 insertions(+), 22 deletions(-) create mode 100644 docs/research/2026-05-13-l2d-slice1-shipped-handoff.md diff --git a/docs/plans/2026-04-29-movement-collision-conformance.md b/docs/plans/2026-04-29-movement-collision-conformance.md index d77901d..7db0325 100644 --- a/docs/plans/2026-04-29-movement-collision-conformance.md +++ b/docs/plans/2026-04-29-movement-collision-conformance.md @@ -169,30 +169,40 @@ fallback. - Audit `Setup.Radius` and cylinder fallback behavior against retail before relying on them for conformance. -Current sub-direction (revised 2026-05-13 in slice 1 design spec): -The "I can't walk through doorways" symptom at Holtburg is **NOT a door- -state-toggle issue** — the `[resolve]` probe captured 140 hit=yes lines -at the doorway with `obj=0xA9B47900` (126 hits), one specific BSP shadow -entry. The 2026-05-12 handoff initially proposed porting `CBuildingObj` + -**per-cell walkability** as the fix, but reading -[ACE BuildingObj.cs:39-52](../../references/ACE/Source/ACE.Server/Physics/Common/BuildingObj.cs) -and named-retail -[acclient_2013_pseudo_c.txt:701260](../research/named-retail/acclient_2013_pseudo_c.txt) -shows that's **not how retail solves doorways**. `find_building_collisions` -is just one BSP test on `PartArray.Parts[0]`. The doorway gap lives -inside that part's physics BSP itself. Per-cell walkability -(`CCellStruct::point_in_cell`, `sphere_intersects_cell`, -`box_intersects_cell`, `CObjCell::find_cell_list`) is how the resolver -selects **which cells** to iterate, not how it decides whether a wall -has a hole — that work belongs to **L.2e**, not L.2d. +Current sub-direction (revised 2026-05-13 evening after slice 1 + 1.5 +shipped and Holtburg-doorway capture analyzed — third reframe): +L.2d as scoped ("shape fidelity: Sphere / CylSphere / Building Objects") +is **essentially closed at the Holtburg site that motivated this phase**. +Building BSP collision works correctly — the slice-1.5 probe captured +real triangles in plausible world positions for `gfxObj=0x01000A2B` with +`bspR=13.99m`. The 121 wall hits the L.2a probe attributed to +`obj=0xA9B47900` were **side effects of the player already being pushed +back by a separate Door cylinder entity** at the same doorway threshold. -L.2d slice 1 is therefore a **read-only BSP-hit diagnostic** that -captures full collision evidence per `[resolve]` `hit=yes` line. -Distinguishes three hypotheses (wrong BSP loaded / over-registered -parts / BSPQuery flaw) from a single Holtburg-doorway capture; slice -2 is the right-sized fix scoped from slice 1's evidence. Design spec: +The actual blocker is a server-spawned **Door** entity — Setup +`0x020019FF` named `"Door"` — that ACE places at each Holtburg-town +building threshold (five doors total observed across `0xA9B40029`, +`0xA9B40154`, `0xA9B40155`). It registers as a Cylinder shadow entry +via the server-spawn path; its Cylinder collision blocks the player +walking into the doorway. That's **door-state handling**, a different +class of problem from L.2d's shape-fidelity scope — it touches network +(`CreateObject` PhysicsState bits), interaction (Use action on door +entity), animation (door open/close), and collision-state-toggle. + +Recommend: **leave L.2d in "watch-and-wait" mode** with slice 1's probe +infrastructure in place. No more L.2d slices until a NEW shape-fidelity +bug is observed at a different site (dungeon walls, stairs, roofs) with +the probe-armed client. The door-state work becomes its own sub-phase +(probably nested under B.4 interaction or filed as a new L.2 sub-phase +like L.2g) scoped separately. + +Full slice 1 + 1.5 handoff: +[docs/research/2026-05-13-l2d-slice1-shipped-handoff.md](../research/2026-05-13-l2d-slice1-shipped-handoff.md). +Design spec (now mostly historical, framing was wrong but probe +infrastructure shipped from it): [docs/superpowers/specs/2026-05-13-l2d-cbuildingobj-collision-design.md](../superpowers/specs/2026-05-13-l2d-cbuildingobj-collision-design.md). -Handoff: [docs/research/2026-05-12-l2a-shipped-l2d-handoff.md](../research/2026-05-12-l2a-shipped-l2d-handoff.md). +Predecessor L.2a handoff: +[docs/research/2026-05-12-l2a-shipped-l2d-handoff.md](../research/2026-05-12-l2a-shipped-l2d-handoff.md). ### L.2e - Cell Ownership: Outdoor Seams, CELLARRAY, cell_bsp diff --git a/docs/research/2026-05-13-l2d-slice1-shipped-handoff.md b/docs/research/2026-05-13-l2d-slice1-shipped-handoff.md new file mode 100644 index 0000000..d6e2363 --- /dev/null +++ b/docs/research/2026-05-13-l2d-slice1-shipped-handoff.md @@ -0,0 +1,251 @@ +# L.2d slice 1 + 1.5 shipped — handoff + +**Date:** 2026-05-13 evening, immediately after slice 1.5 + Holtburg verification. +**Branch:** `claude/sharp-chatelet-023dda` (ready to merge to main). +**Predecessor:** [2026-05-12-l2a-shipped-l2d-handoff.md](2026-05-12-l2a-shipped-l2d-handoff.md). + +--- + +## TL;DR + +The "I can't walk through Holtburg doorways" symptom is **a closed Door +entity blocking the threshold**, not a building-collision-mesh bug. +Building BSP collision is healthy. The L.2a handoff's framing +("per-cell walkability missing") was wrong, the L.2d-slice-1 spec's +reframe ("BSP shape fidelity, three hypotheses X/Y/Z") was also +wrong, and the actual answer fell out of one capture once the probe +labeling was fixed (slice 1.5). **L.2d as scoped is essentially +closed.** The remaining work is door-state handling — a different +sub-phase entirely. + +--- + +## What shipped on this branch + +| Commit | What | +|---|---| +| [`92cd723`](.) | `docs(phys L.2d): design spec for slice 1 BSP-hit diagnostic + L.2d reframe` | +| [`66dc23e`](.) | `feat(phys L.2d slice 1): BSP-hit diagnostic probe + plan-of-record correction` | +| [`8bacef0`](.) | `fix(phys L.2d slice 1.5): probe captures hit poly under StepSphereUp recursion` | + +What slice 1 + 1.5 give the next agent: + +- **`ACDREAM_PROBE_BUILDING=1`** env var + DebugPanel checkbox: one + multi-line `[resolve-bldg]` entry per attributed BSP shadow-entry hit + (partIdx, hasPhys, bspR vs vAabbR, world-space entOrigin_lb, actual + hit polygon vertices in both local and world coords). Reliable + under `StepSphereUp` recursion after the slice 1.5 fix. +- **`[entity-source]`** one-time log line per `ShadowObjects.Register` + call, gated on the same flag. Makes `entityId=0xA9B479` in a + probe line greppable to its WorldEntity source. +- **`PhysicsDiagnostics.LastBspHitPoly`** — diagnostic side-channel + for any future "what poly did BSPQuery hit" question. +- **The two synthetic tests** in + [PhysicsDiagnosticsTests.cs](../../tests/AcDream.Core.Tests/Physics/PhysicsDiagnosticsTests.cs) + pin the side-channel API contract. + +--- + +## What the trace actually showed + +After slice 1.5, walking acdream into a Holtburg town doorway +captured 242 real BSP hit polys + 122 cylinder n/a. **Definitive +finding:** + +``` +live: spawn guid=0x7A9B4015 name="Door" setup=0x020019FF + pos=(132.6,17.1,94.1)@0xA9B40029 itemType=0x00000080 +[entity-source] id=0x000F4244 entityId=0x000F4244 src=0x020019FF + gfxObj=0x020019FF lb=0xA9B40029 type=Cylinder note=server-spawn-root +``` + +The blocker is a **Door entity** — Setup `0x020019FF` named `"Door"` — +server-spawned by ACE at the threshold of each Holtburg town building. +**Five Doors** appear across Holtburg (landblock cells `0xA9B40029`, +`0xA9B40154`, `0xA9B40155`); same Setup DID reused. ItemType +`0x00000080` = Misc category in AC's ItemType flags. + +Each Door's Cylinder collision blocks the player. The building BSP +*also* fires (the L.2a evidence the original handoff pointed at), but +the BSP hits were the player **already pushed back by the Door +cylinder** then grazing the doorframe — they look like wall collision +but are a side effect of the Door cylinder push. Slice 1.5's per-tick +multi-entity probe revealed this by showing `nObj=3` on every hit +resolve: one Door + two sphere checks against the building BSP. + +The L.2a slice 2 handoff's expectation that doors would be in the +`0xCC0Cxxxx` range was wrong; **doors are in `0x000Fxxxx`** (server- +spawn-root range) because they're hydrated through the live +`CreateObject` stream like NPCs, not the static landblock pipeline. + +--- + +## What this means for L.2d + +L.2d as originally scoped ("Shape Fidelity: Sphere / CylSphere / +Building Objects") is essentially **closed at this site**: + +- Building BSP is loaded, parsed, queried correctly. `bspR=13.99m` for + GfxObj `0x01000A2B`, real triangles in real positions. +- `Setup.CylSpheres` for Door (`0x020019FF`) is also loaded correctly + — the cylinder is firing the cylinder collision path with sensible + world-space radius. +- No actual shape-fidelity bug observed at this test site. + +The remaining work is **door state handling**, which is a different +class of problem entirely — it touches network (CreateObject +PhysicsState bits), interaction (Use action on door entity), animation +(door open/close animation state), and collision-state-toggle +(ETHEREAL during open animation). That doesn't fit under L.2d's +shape-fidelity umbrella. + +**Recommend reframing L.2d as "watch-and-wait":** keep the probes for +future shape-fidelity work at other sites (dungeon walls, stairs, +roofs), but don't plan more slices until a NEW shape-fidelity bug is +observed with the probe-armed client. + +--- + +## Side findings (latent bugs to file, not block this slice) + +### 1. Building double-registration + +The trace shows the same WorldEntity registered TWICE in +ShadowObjectRegistry: + +``` +[entity-source] id=0xA9B47900 entityId=0xC0A9B479 ... type=BSP note=partIdx=0 hasPhys=true +[entity-source] id=0xC0A9B479 entityId=0xC0A9B479 ... type=Cylinder note=mesh-aabb-fallback +``` + +[GameWindow.cs:5625](../../src/AcDream.App/Rendering/GameWindow.cs:5625) +gates the mesh-AABB-fallback on `entityBsp == 0`, but the BSP +registration at [line 5530](../../src/AcDream.App/Rendering/GameWindow.cs:5530) +DOES increment `entityBsp`. So the fallback shouldn't fire when BSP +parts exist. Either `entityBsp` isn't being checked in the right +scope, or there's a second mesh-AABB-fallback site that doesn't gate +on `entityBsp`. Worth a short investigation + one-line fix. + +Filing as ISSUE candidate. Doesn't break anything observable yet +(cylinder is too far from player to fire at this Holtburg site), but +will cause confusion in any future "why does entity X have two +ShadowEntries" trace. + +### 2. PhysicsState / EntityCollisionFlags not in entity-source log + +The slice 1 `[entity-source]` log captures `id, entityId, src, +gfxObj, lb, type, note, hasPhys` but **not** `state` (PhysicsState +bits) or `flags` (EntityCollisionFlags). For any future +ethereal-handling / IGNORE_COLLISIONS work — including the door +state handling above — these would be required. + +Tiny slice 1.6 if the next agent needs them: add `state=0x{...:X8} +flags={...}` to the format string. ~5 LOC, gated on the same +ProbeBuilding flag. + +--- + +## What the next session probably should NOT do + +- **Re-investigate Holtburg doorways with the same setup.** The + evidence is conclusive; we're not going to find new information by + re-running the probe at the same site. +- **Port `CBuildingObj` or per-cell walkability infrastructure.** + That was based on the original (wrong) hypothesis. ACE's + `find_building_collisions` is six lines and doesn't use per-cell + walkability; our equivalent is already in place implicitly. +- **Start L.2d slice 2 as scoped in the design spec.** Hypotheses X / + Y / Z don't apply — the trace ruled them all out. Update or close + the spec. + +--- + +## What the next session COULD do (in rough preference order) + +These are NOT prescribed; they're candidates for the project-level +ordering discussion the user wants to have. + +1. **Door state handling sub-phase.** New phase (call it L.2g or + nest under B.4). Touches: Use action → server door toggle, + PhysicsState ETHEREAL bit honor, door open/close animation, + collision-shape suppression during open animation. Probably + 2-3 commits. + +2. **Fix the building double-registration latent bug** (side + finding #1). One-liner, no real impact today but cleaner trace + later. + +3. **Capture slice 1.6** (state + flags in entity-source log) if + any future ethereal-related work is on the immediate horizon. + Otherwise defer. + +4. **Move to a different L.2 sub-phase entirely** — L.2e + (cell ownership / `find_cell_list` / outdoor seam updates) or + L.2f (real-DAT + retail-observer conformance). Both are scoped + in [the L.2 plan-of-record](../plans/2026-04-29-movement-collision-conformance.md). + +5. **Triage the 8 pre-existing test failures** that have shadowed + the last few sessions. Some are in physics modules that L.2d + slice 2 (if it ever happens) would touch — fixing them first + gives a cleaner baseline. + +6. **Pick from CLAUDE.md's "Next phase candidates"** list — non-L.2 + work like Phase C visual fidelity, N.6 slice 2, or perf tiers + 2/3. The session-level "I don't know what to do" feeling is + often easier to resolve by **shipping something in a different + area** for a session. + +--- + +## Reproducibility + +Same recipe as L.2a + L.2d slice 1: + +```powershell +$env:ACDREAM_DAT_DIR = "$env:USERPROFILE\Documents\Asheron's Call" +$env:ACDREAM_LIVE = "1" +$env:ACDREAM_TEST_HOST = "127.0.0.1" +$env:ACDREAM_TEST_PORT = "9000" +$env:ACDREAM_TEST_USER = "testaccount" +$env:ACDREAM_TEST_PASS = "testpassword" +$env:ACDREAM_DEVTOOLS = "1" +$env:ACDREAM_PROBE_CELL = "1" +$env:ACDREAM_PROBE_RESOLVE = "1" +$env:ACDREAM_PROBE_BUILDING = "1" +dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | + Tee-Object -FilePath "launch-l2d.log" +``` + +Walk acdream toward any Holtburg building threshold. Hit `Ctrl+F2` to +toggle collision wireframes — you'll see the Door cylinder right at +the threshold. The `name="Door"` line appears in the log at startup +during the `CreateObject` stream replay. + +--- + +## Open questions / unresolved + +- **What `PhysicsState` bits is ACE sending for the Door entity?** + Not captured in current logs. Slice 1.6 would answer this. +- **Are these doors *supposed* to be open by default in retail?** + If yes, ACE config issue. If no, retail clients see the same + blocker and players had to open them manually. +- **What does ACE's door-state state machine look like?** Probably + documented in `references/ACE/Source/ACE.Server/Entity/Door.cs` + or similar. + +These are doors-and-ACE-side questions; defer to the door-state +sub-phase when (if) it gets scoped. + +--- + +## Worktree state at handoff + +- All three slice 1 / 1.5 commits ready to merge to main. +- WorldBuilder submodule initialized + 6 directory junctions in place + for the gitignored peer reference dirs (created during slice 1 + prep). Worktree builds clean. +- Three test artifacts (`launch-l2d-slice1.log`, `launch-l2d-slice1b.log`, + `launch-l2d-slice1c.log`) are in working tree but **not committed** — + they're large and ephemeral. Delete or preserve at the merge + author's discretion.