fix #131 (root cause 4, structurally forced): look-in cells draw their DYNAMICS - the town portal is a server object in the hall's porch cell

The headless replay of the captured indoor frame proved the look-in flood ADMITS the porch 0x017A (Diagnostic_LookInFlood_AdmitsHallPorchFromCottage: 14 cells). So the portal (a SERVER object - the teleport proves it - with ParentCellId 0xA9B4017A) routes to partition.Dynamics and draws NOWHERE under an interior root: dynamics-last viewcone-culls it (the main cone has no look-in cells) and post-seal it would z-fail beyond the root's door plane (the #118 lesson). This is AP-33's own recorded deferral - 'look-in DYNAMICS are not drawn' - the deferred case was the most-stared-at object in town. Outdoors the merge path puts the porch in the main cone -> drawn -> 'appears when I walk out'.

Fix: DrawBuildingLookIns pass 2 draws look-in-cell dynamics with the statics (whole, AP-33 over-include) and their emitters ride the same DrawCellParticles call. No double-draw: dynamics-last keeps culling them; DrawDynamicsParticles only sees its cone survivors. #124 CLOSED by user gate same session. AP-33 row updated. Suites: App 261+1skip / Core 1439+2skip / UI 420 / Net 294 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-12 20:52:34 +02:00
parent 47f32cd45c
commit d208002bf8
4 changed files with 89 additions and 27 deletions

View file

@ -4304,7 +4304,7 @@ of which draw list the building's shell left.
## #124 — Looking out through an opening: far buildings with openings show missing/transparent back walls
**Status:** FIX SHIPPED — awaiting user visual gate
**Status:** CLOSED (user-gated 2026-06-12 evening: "124, that one is solved")
**Severity:** MEDIUM
**Filed:** 2026-06-11 (re-gate; pre-existing — "still have that issue";
user 2026-06-12: "especially visible when I look out through a door
@ -4637,22 +4637,27 @@ terrain, outdoor static meshes (the look-in punches need their depth, the
dynamics' meshes + ALL attached scene particles + weather + the
unattached pass. (This FIXED #132 indoors but not the portal.)
**ROOT CAUSE (fix 3 — the real one, pinned by the teleport capture):**
walking into the portal flipped `pCell` to **0xA9B4017A — the hall's
porch EnvCell**. The portal's swirl emitter is owned by a STATIC inside
ANOTHER BUILDING'S CELL, not an outdoor entity at all. Outdoors the
hall's cells merge into the main frame and the per-cell object pass
runs `DrawCellParticles` → swirl visible. Under an interior root the
#124 look-in sub-pass drew the far cells' shells + statics but had NO
cell-particles call — retail's nested DrawCells draws objects WITH
their emitters (`DrawObjCellForDummies`). Every earlier suspect
(unattached pass, owner-cone verdicts, alpha ordering) was real-but-
adjacent; the cone math was correct all along (the 0xC0A9B462 flips
were a porch torch, geometrically defensible).
**ROOT CAUSE (fix 4 — structurally forced; fixes 13 were
real-but-adjacent):** the teleport capture flipped `pCell` to
**0xA9B4017A — the hall's porch EnvCell** (the portal is a SERVER
object standing inside a look-in cell), and the headless replay of the
captured indoor frame proved the look-in flood ADMITS 0x017A (14 cells
incl. the porch — `Issue131SetupProbeTests.Diagnostic_LookInFlood_*`).
The partition routes server objects to the dynamics-last pass, where
(a) the viewcone has NO entries for look-in cells → culled, and (b)
even un-culled they would z-fail post-seal beyond the root's door plane
(the #118 lesson). This is exactly AP-33's recorded "look-in DYNAMICS
are not drawn (deferred)" — the deferred case was the town portal.
Outdoors the merge path puts the porch in the main cone → drawn →
"appears when I walk out."
**Fix 3:** `DrawBuildingLookIns` pass 2 invokes `DrawCellParticles` per
look-in cell with its static bucket (same callback as the main per-cell
pass; no-clip slice when the cell has no slot).
**Fix 4:** look-in-cell DYNAMICS draw inside `DrawBuildingLookIns`
pass 2 (with the statics, whole — AP-33's over-include), and their
emitters ride the same `DrawCellParticles` call (fix 3). Retail
equivalent: the nested DrawCells draws the cell's objects
(`DrawObjCellForDummies` pc:432878+). No double-draw: dynamics-last
keeps culling them (cell absent from the main cone);
DrawDynamicsParticles only sees dynamics-last cone survivors.
**Gate:** stand inside, look out the doorway at the town portal — the
swirl renders through the door.

View file

@ -128,7 +128,7 @@ accepted-divergence entries (#96, #49, #50).
| AP-30 | AutonomousPosition diff cadence compares with epsilons (1 mm pos, 1e-4 normal, 1 mm dist); retail's `Frame::is_equal` is an exact float compare | `src/AcDream.App/Input/PlayerMovementController.cs:1541` | Sub-millimeter epsilon is well below any movement worth suppressing; comparisons are against last-SENT state so drift accumulates past the epsilon | Sub-epsilon drift suppresses an AP send retail would have made — negligible today; a consumer expecting retail's exact send-on-any-change cadence sees fewer packets | `Frame::is_equal` pc:700263 |
| AP-31 | Scenery placement drift + the 0xA9B1 road-edge tree — WB-upstream divergences from retail, ACCEPTED (**#49/#50**, 2026-05-11) | `src/AcDream.Core/World/SceneryGenerator.cs` (via `WbSceneryAdapter`) | Piecemeal patching against WB upstream is net-negative (the `e279c46` road-check attempt over-suppressed scenery elsewhere, reverted `677a726`); visible impact = a handful of trees a few meters off | The same WB-upstream class could hide a *larger* placement divergence elsewhere; revisit only via a coherent ACME-style per-vertex filter port | `CLandBlock::get_land_scenes`; ACME GameScene.cs:1074 per-vertex road filter |
| AP-32 | Cell shells DRAW +0.02 m above the dat EnvCell origin (`ShellDrawLiftZ`, z-fight vs coplanar terrain); retail draws at the origin verbatim. Split invariant: PHYSICS + visibility graph UNLIFTED (f35cb8b, **#119**-residual), every DRAW-space consumer of portal/cell geometry LIFTED (OutsideView color gate via `Build(drawLiftZ)`, seal/punch fans — **#130**) | `src/AcDream.App/Rendering/GameWindow.cs:5604` (const at `PortalVisibilityBuilder.ShellDrawLiftZ`) | Shell floors coplanar with terrain z-fight in our z-buffered frame; the 2 cm lift is the documented stand-in | A new draw-space consumer of portal/cell polygons that forgets the lift re-opens a 2 cm seam at horizontal aperture edges (the #130 top-edge strip, ~7 px at 2.4 m); a visibility consumer that picks up the LIFTED transform re-opens the #119-residual horizontal-portal side-cull | retail draws cell geometry at the dat EnvCell origin (no lift) |
| AP-33 | Interior-root look-in statics (**#124** sub-pass) draw WHOLE — no per-part viewcone check; retail viewconeCheck's each part vs the installed view. Look-in DYNAMICS are not drawn at all (deferred; retail draws objects per overlapped cell in the landscape stage) | `src/AcDream.App/Rendering/RetailPViewRenderer.cs` (`DrawBuildingLookIns`) | The main viewcone has no entries for look-in cells; over-include is the safe direction (z-correct, repainted outside apertures by the root's shells); look-in cell counts are small (~1-3 cells) | Statics: a few wasted draws only. Dynamics: an NPC inside a far building seen through two openings is invisible where retail shows it | `viewconeCheck` 0x0054c250; nested `DrawCells` objects pc:432878 |
| AP-33 | Interior-root look-in cells (**#124** sub-pass) draw their statics + DYNAMICS + emitters WHOLE — no per-part/per-object viewcone check; retail viewconeCheck's each vs the installed view (the **#131** portal closure: a server object in a look-in cell drew nowhere — dynamics-last culls cells absent from the main cone, and post-seal it z-fails anyway) | `src/AcDream.App/Rendering/RetailPViewRenderer.cs` (`DrawBuildingLookIns`) | The main viewcone has no entries for look-in cells; over-include is the safe direction (z-correct, repainted outside apertures by the root's shells); look-in cell counts are small (~1-3 cells) | A few wasted draws on content outside the doorway region (repainted); no under-draw direction remains | `viewconeCheck` 0x0054c250; nested `DrawCells` objects pc:432878 |
| AP-34 | Landscape-stage alpha deferral is a TWO-PHASE slice split (statics-early / dynamics+particles+weather-late around the **#124** look-ins) + outdoor-root attached scene emitters moved to the post-frame pass, not retail's single deferred alpha flush. Residual: building exteriors' / outside-stage dynamics' own translucent MESH batches still draw within their stage draw call (before later stage content) | `src/AcDream.App/Rendering/RetailPViewRenderer.cs` (`DrawLandscapeThroughOutsideView` late loop) + `GameWindow` post-frame Scene pass | The MDI dispatcher draws translucency inside each Draw call; a faithful FlushAlphaList port needs a global deferred alpha list across all landscape draws — the split covers the user-visible cases (#131 portal swirl, #132 candle flame indoors + outdoors) | Translucent landscape content drawn early and screen-overlapped by content drawn later in the stage gets overpainted (no depth self-protection) — the portal-swirl/candle-flame class re-appears in the residual configurations | `D3DPolyRender::FlushAlphaList` (DrawCells pc:432722) |
---