docs(phys L.2d): slice 1 + 1.5 shipped handoff + 3rd plan-of-record reframe
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) <noreply@anthropic.com>
This commit is contained in:
parent
8bacef0598
commit
34b7f1faa1
2 changed files with 283 additions and 22 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
251
docs/research/2026-05-13-l2d-slice1-shipped-handoff.md
Normal file
251
docs/research/2026-05-13-l2d-slice1-shipped-handoff.md
Normal file
|
|
@ -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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue