docs(spec): expand probe design with concrete line formats + code sites

User feedback: "add the probes you need. Better info, better code."
Original spec had a single ACDREAM_PROBE_INDOOR=1 with vague "log
lookup results" guidance. Replaced with five individually-toggleable
probes, each with:

- Specific env var name + DebugPanel checkbox name.
- Concrete log-line format.
- Exact code site to instrument.
- The hypothesis it disambiguates.

Probe set:
- ACDREAM_PROBE_INDOOR_WALK   — dispatcher entity walk per cell
- ACDREAM_PROBE_INDOOR_LOOKUP — render-data lookup hit/miss + SetupParts
- ACDREAM_PROBE_INDOOR_UPLOAD — WB upload result (requested + completed)
- ACDREAM_PROBE_INDOOR_XFORM  — composed world transform for cell geom
- ACDREAM_PROBE_INDOOR_CULL   — visibility/frustum filter decisions

Plus ACDREAM_PROBE_INDOOR_ALL master toggle.

Implementation outline added: new RenderingDiagnostics static class
(mirrors L.2a's PhysicsDiagnostics pattern), DebugPanel subsection,
edits to WbDrawDispatcher + WbMeshAdapter.

Acceptance criteria refreshed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-19 11:07:54 +02:00
parent f6e9c58932
commit e798cb7898

View file

@ -98,23 +98,74 @@ Six untested hypotheses, in rough order of probability:
## 3. Solution
**Phase 1: Diagnostics.** Add a runtime-toggleable `ACDREAM_PROBE_INDOOR=1`
env-var (mirrored as a DebugPanel checkbox) that prints one line per frame
with:
### Phase 1 — Diagnostics (this phase's work)
- Number of cell entities walked by the dispatcher.
- Per-cell-entity: `TryGetRenderData(envCellId)` hit/miss.
- On hit: `renderData.IsSetup`, `renderData.SetupParts.Count`.
- For each SetupPart: `TryGetRenderData(partGfxObjId)` hit/miss.
- The composed world matrix for the cell-geometry part (so we can see
where the floor actually ends up in world space).
- Whether the entity was culled by `visibleCellIds` (and why).
Five probes, each individually toggleable via env-var + DebugPanel
checkbox. The probes live in a new
`AcDream.Core.Rendering.RenderingDiagnostics` static class (mirroring
the `AcDream.Core.Physics.PhysicsDiagnostics` pattern shipped in L.2a)
so they're discoverable from one place and survive across the
Core / App seam.
Run the client, walk into Holtburg Inn, capture probe output. The log
tells us exactly which step in the chain is breaking.
Each probe is **rate-limited**: by default, one line per (envCellId,
frame-modulo-30) — i.e., once per second per cell at 30 Hz — to avoid
log spam. When `ACDREAM_PROBE_INDOOR_VERBOSE=1` is also set, the
rate-limit drops and every frame logs.
**Phase 2: Fix the specific break.** Once the probe identifies the
failure point, implement the surgical fix. Likely shapes per hypothesis:
| Env var (and DebugPanel mirror) | Probe | Code location | Line format |
|---|---|---|---|
| `ACDREAM_PROBE_INDOOR_WALK` | Cell-entity dispatcher walk | `WbDrawDispatcher.WalkVisibleEntities` (rate-limited per cellId) | `[indoor-walk] cellEnt=0xID pos=(x,y,z) parentCell=0xID landblockVisible=B aabbVisible=B cellInVis=B drawn=B` |
| `ACDREAM_PROBE_INDOOR_LOOKUP` | Render-data lookup for cell entities | `WbDrawDispatcher.DrawAccumulated` per cell entity | `[indoor-lookup] cellId=0xID hit=B isSetup=B partCount=N hasEnvCellGeom=B partsHit=N partsMiss=N` |
| `ACDREAM_PROBE_INDOOR_UPLOAD` | WB upload result for envCellId | `WbMeshAdapter.IncrementRefCount` (on first call per id) + a callback hooked into `_meshManager.Tick()` for completion | `[indoor-upload] cellId=0xID requested=true completed=B partsCount=N cellGeomVerts=N error="..."` |
| `ACDREAM_PROBE_INDOOR_XFORM` | Composed world transform for cell-geometry SetupPart | `WbDrawDispatcher` inside the `IsSetup` branch at line 607-621, for partGfxObjId matching `(envCellId | 0x1_00000000UL)` | `[indoor-xform] cellId=0xID cellOrigin=(x,y,z) entityWorld=(...) partTransform=(...) composed=(x,y,z y-axis,z-axis) detExpected≈1 detActual=F` |
| `ACDREAM_PROBE_INDOOR_CULL` | Visibility / cull decision per cell entity | `WbDrawDispatcher.WalkVisibleEntities` (the two filter sites at lines 304-305 and 317-319) | `[indoor-cull] cellEnt=0xID reason="visibleCellIds-miss" or "frustum" or "served" details="..."` |
The five probes can be enabled independently or together. The user's
common case is `ACDREAM_PROBE_INDOOR_ALL=1` which sets all five at
once.
#### Implementation outline
1. **New file** `src/AcDream.Core/Rendering/RenderingDiagnostics.cs`
five static `bool` properties, each backed by an env-var read at
startup, each runtime-settable from the DebugPanel.
2. **DebugPanel section** — new "Indoor rendering diagnostics" block
in the existing DebugPanel "Diagnostics" group, with one checkbox
per probe + a master "all" toggle.
3. **WbDrawDispatcher edits** — instrument the walk and the IsSetup
draw branch. The walk probe needs to know whether the entity passed
the cell-visibility filter; the cull probe needs the same data.
Cleanest: emit BOTH lines in one place when either probe is on.
4. **WbMeshAdapter edits**`IncrementRefCount` logs an `[indoor-upload]
requested=true` line when the id is recognized as an EnvCell
(high-bit check `(id & 0xFFFF) >= 0x0100`). On Tick(), when a
completion drains for an envCellId, log the result line with the
actual ObjectMeshData/ObjectRenderData fields.
5. **No GameWindow changes** beyond passing the diagnostics class
into the dispatcher (if not already accessible).
#### Capture procedure
1. Build with the probe instrumentation. `dotnet build` green.
2. Launch with `ACDREAM_PROBE_INDOOR_ALL=1`. Walk to Holtburg Inn,
stand at the doorway, then step inside, then walk around the room.
3. Stop the client, grep `launch.log` for `[indoor-*]` lines.
4. The captured log identifies WHICH hypothesis matches:
- **H1 (null upload)**`[indoor-upload] completed=false`
- **H2 (empty batches)**`[indoor-upload] cellGeomVerts=0`
- **H3 (cull bug)**`[indoor-cull] reason="visibleCellIds-miss"`
- **H4 (double-spawn)**`[indoor-lookup] partCount` includes
static-object IDs that ALSO appear in `landblock.Entities`
- **H5 (transform double-apply)**`[indoor-xform] composed`
world position lands at `2 × cellOrigin` instead of `cellOrigin`
- **H6 (MeshRefs structure)** → ruled out; probe data would still
surface it as `hit=true isSetup=true partCount=N` followed by
all `partsHit=0`
### Phase 2 — Fix the specific break (next phase)
Once the probe identifies the failure point, implement the surgical
fix. Likely shapes per hypothesis:
| Hypothesis | Fix shape |
|---|---|
@ -170,16 +221,28 @@ bug), tests verify visibility BFS for indoor entities.
**Phase 1 (this phase):**
- [ ] `ACDREAM_PROBE_INDOOR=1` env var + DebugPanel mirror.
- [ ] One log line per frame, per cell entity, showing render-data lookup
results, SetupParts traversal, and composed transforms.
- [ ] `AcDream.Core.Rendering.RenderingDiagnostics` static class created
with five `bool` properties + master `IndoorAll` toggle, each backed
by an env-var read at startup and runtime-settable.
- [ ] DebugPanel "Diagnostics" group has a new "Indoor rendering"
subsection with six checkboxes (five probes + master).
- [ ] `WbDrawDispatcher` emits `[indoor-walk]`, `[indoor-lookup]`,
`[indoor-xform]`, `[indoor-cull]` lines when the respective probe
is on. Rate-limited to ~1/sec per cell unless verbose mode active.
- [ ] `WbMeshAdapter` emits `[indoor-upload]` lines for EnvCell IDs:
one `requested` line on first `IncrementRefCount`, one `completed`
line when WB's Tick drains the result (success or failure).
- [ ] `dotnet build` clean. `dotnet test` clean (the diagnostics-only
change should not affect any test).
- [ ] Probe captured at Holtburg Inn confirms which hypothesis matches.
- [ ] Phase 2 design (amended spec or new spec) documents the surgical fix.
Capture procedure documented in §3 above.
- [ ] Phase 2 design (amended spec or new spec) documents the surgical
fix matched to the identified hypothesis.
**Phase 2 (next phase, driven by Phase 1 output):**
- [ ] `dotnet build` clean, `dotnet test` clean.
- [ ] Visual verification: walking into Holtburg Inn renders interior floor +
walls correctly.
- [ ] Visual verification: walking into Holtburg Inn renders interior
floor + walls correctly.
- [ ] Roadmap updated.
- [ ] Probe left in place for future regressions but defaulted off.
- [ ] Probes left in place for future regressions but defaulted off.