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>
251 lines
10 KiB
Markdown
251 lines
10 KiB
Markdown
# 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.
|