docs(G.3): file #134 (ramp slide) + #135 (login FPS); record #133 grey+FPS fixes

Wrap-up bookkeeping for the dungeon work this session:

- #135 — login FPS ramp (~10 fps -> high over ~30 s): the streaming
  collapse only fires once CurrCell resolves to a sealed cell, so the
  first-frame bootstrap loads ~24 neighbour ocean-grid dungeons (+ ~19k
  entities each) then unloads them. Residual of the dungeon collapse;
  clean fix = pre-collapse at login when the spawn cell is a sealed
  dungeon cell.
- #134 — ramp slide-response feel ("lags downward" instead of gliding
  along the slope). SURFACED (not caused) by 3e006d3 caching the ramp
  connector cell in the physics graph; the slope-walk/edge-slide is now
  exercised. Port the retail slide-response; no band-aid.
- #133 — progress note: dungeon FPS FIXED (streaming collapse to the
  single dungeon landblock, 14-30 -> ~1000+ fps) + grey barrier FIXED
  (register portals-only connector cells for BOTH visibility and the
  physics graph even when they build 0 sub-meshes; d90c538 + 3e006d3).
  A7 per-vertex lighting bake (LightBake Core 3b93f91) is the remaining
  "lighting off" work; revised diagnosis (intensity=100 is the real dat
  value; the divergence is no-static-light-burnin, not a mis-read).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-14 14:33:07 +02:00
parent 3b93f91ebe
commit a100bc37a7

View file

@ -46,6 +46,61 @@ Copy this block when adding a new issue:
---
## #135 — ~30 s low-FPS ramp at login (≈10 fps → high) before streaming settles
**Status:** OPEN
**Severity:** LOW (startup-only; self-corrects)
**Filed:** 2026-06-14
**Component:** streaming — first-frame bootstrap vs the dungeon collapse
**Description:** On login into a dungeon, FPS starts ~10 and climbs over ~30 s before
settling (then 1000+ fps). User: "we still have about 30ish seconds before FPS is ramped
up; when logging in I get like 10 then it slowly increases."
**Root cause / status:** The #133 streaming collapse (`5686050`/`d9e7dd6`/`7d8da99`) only
engages once CurrCell resolves to a sealed cell (the snap, a few s in). Before that the
first Tick bootstraps the full 25×25 window, so ~24 neighbour ocean-grid dungeons (+ their
~19k entities) load, then unload when the collapse fires. The collapse-at-snap change moved
the trigger from finalize-time (~30 s) toward snap-time but the bootstrap churn remains.
Clean fix = pre-collapse at login when the spawn cell is a sealed dungeon cell so the full
window never enqueues (touches the sensitive login spawn path — do carefully; no band-aid).
**Files:** `GameWindow.cs:6885` (streaming Tick gate); `StreamingController.cs` (collapse);
login recenter `OnLiveEntitySpawnedLocked` ~2470.
**Acceptance:** Login into a dungeon reaches steady-state FPS within ~12 s (no full-window
neighbour load/unload churn).
---
## #134 — Player "lags downward" instead of gliding along a dungeon ramp edge
**Status:** OPEN
**Severity:** LOW-MEDIUM (movement feel; not a hard traversal block)
**Filed:** 2026-06-14
**Component:** physics — slope-walk / edge-slide response
**Description:** Running up or down against a dungeon ramp's edge, the player "sort of lags
downwards" instead of gliding/sliding ALONG the ramp surface (up when running up, down when
running down). Reported in the 0x0007 Town Network dungeon ramp after #133.
**Root cause / status:** Surfaced (not caused) by the #133 connector-cell physics
registration (`3e006d3`): the ramp connector cell's collision is now fully resident in the
physics graph, so the slope-walk / edge-slide response on it is exercised for the first time.
"Lag down" suggests the slide velocity is projected toward gravity rather than along the
contact plane (the slope tangent). Likely the retail edge-slide / slope-slide response is
incomplete — see #32 (retail edge-slide/cliff-slide/precipice-slide incomplete) and the
AP-6 / TS-1 / TS-4 slide rows in the divergence register. NO band-aid — port the retail
slide-response.
**Files:** `src/AcDream.Core/Physics/` (slide-response in TransitionTypes / BSPQuery); ramp
cell 0x0007014D + neighbours.
**Acceptance:** Running up a walkable ramp climbs it smoothly; running into the edge slides
along the slope (up/down per input direction), matching retail feel.
---
## #133 — Teleport into a dungeon snaps the player BEFORE the dungeon landblock streams in → lands at the old landblock's frame (ocean), not the dungeon
**Status:** OPEN — promoted to **Phase G.3** (Dungeon streaming + portal
@ -97,6 +152,37 @@ transition` spam), and the render budget is sane — **WB-DIAG instances ~39,000
(meshMissing=0)** vs the 9.1M pre-Bug-A blowup (#95, now RESOLVED as a Bug-A symptom).
User-confirmed: "no errors from ACE this time."
**✅ DUNGEON FPS FIXED + GREY BARRIER FIXED (2026-06-14, user-confirmed).** Two
separate causes, both resolved:
- **FPS (was 1430, now ~1000+):** AC dungeons sit adjacent in the "ocean" landblock
grid, so the 25×25 (farRadius=12) streaming window pulled ~129 neighbour dungeons +
their ~19k particle emitters / entities each frame. Fix = **collapse streaming to the
player's single dungeon landblock** when CurrCell is a sealed EnvCell (`!SeenOutside`),
with landblock-level hysteresis to stop collapse↔expand thrash. Confirmed against ACE
(`landblock.IsDungeon → return adjacents` with no neighbours): dungeons have no neighbour
landblocks, so collapsing to the one block is retail-faithful. Commits `5686050` (collapse)
+ `d9e7dd6` (hysteresis) + `2561918` (pin to CurrCell's landblock, not the position-derived
one — the negative cell-local-Y made `floor(pp.Y/192)` land one block off and unload the
REAL dungeon). Divergence register: AP-36.
- **GREY BARRIER (the "barrier above the ramp" / cellar-mouth grey):** portals-only
connector cells (ramp mouths, stair landings, cellar throats) build **0 drawable
sub-meshes**, and BOTH cell-registration gates (`BuildLoadedCell` → visibility
`_cellVisibility`, and `CacheCellStruct` → the physics cell graph) were gated on
`cellSubMeshes.Count > 0`. So a connector cell never registered → the portal flood
hit a **lookup-miss** at its opening (the un-flooded opening shows the clear/grey
colour) AND the camera eye-sweep couldn't transit through it. Fix = register EVERY
cell with a valid cellStruct for visibility + physics; only the *drawing* registration
stays gated on having sub-meshes. Commits `d90c538` (visibility) + `3e006d3` (physics
graph). The physics-graph half EXPOSED the ramp slide-response feel (now **#134**).
Three render-MATH theories (portal_side centroid, on-screen clip, near-eye projection)
were instrumented and REFUTED before the real lookup-miss cause was found — apparatus
discipline held. Render-pipeline digest updated.
Residual (filed separately): login FPS ramp **#135**; ramp slide-response **#134**; the
A7 per-vertex lighting bake (below) is the remaining "lighting off" work.
**✅ A7 dungeon lighting — selection fix LANDED + objectively verified (`a80061b`).** The
"lighting off" report was NOT missing torches — the `ACDREAM_PROBE_LIGHT` diagnostic
(`d6fb788`) showed the dungeon correctly gets retail's flat 0.2 indoor ambient + sun zeroed
@ -112,21 +198,27 @@ light it). Core lighting suite green. Then `Range = Falloff × 1.5` (retail `ran
retail-faithful (`SmartBox::SetWorldAmbientLight(0.2f)`); the 0.30 was a red herring
(`CreatureMode` paperdoll renderer, not world cells).
**⚠️ REAL remaining cause — GENERAL light over-saturation (NOT dungeon-specific; belongs to
the #79 indoor-lighting umbrella).** Screenshot + `[light-detail]` probe (`9e809bc`): torches
read **`intensity=100`** (+ garbage `cone`). Our shader does `Diffuse = color × intensity`
`color × 100` → every lit surface blows out to white = the hard "spotlight" disks. Retail's
`config_hardware_light` (0x0059adc) uses the SAME math (`Diffuse = (color/255) × intensity`)
and is NOT blown out → **retail's intensity is ~1.0; we are mis-reading the dat
`LightInfo.Intensity`** (likely a DatReaderWriter field/type bug — its source is a compiled
NuGet, not vendored, so unconfirmed). Over-saturates EVERY light (houses + outdoors + dungeons —
matches the user's "same issue everywhere; retail is uniform"). **DO NOT ad-hoc `÷100`
(forbidden workaround, risks the frozen outdoor/building lighting).** Proper fix = pin the
dat-format (raw-byte inspect a `LightInfo` / get the DatReaderWriter source) → correct the
intensity read → fixes the general spotty lighting everywhere. GENERAL engine-lighting work,
beyond G.3 dungeon scope. Separately: dungeon FPS 1430 (WB-DIAG ~22K draws/frame — heavy
cell-geometry draw count / poor instancing — a general rendering-perf task; the 8-light
selection also added a per-frame 2227-light sort that should become a partial-select).
**⚠️ REAL remaining cause — REVISED 2026-06-14 (the earlier "mis-read intensity" theory is
REFUTED).** `intensity=100` is the **REAL dat value** (raw-byte verified `00 00 C8 42` = 100.0f;
DatReaderWriter 2.1.7 parses it correctly; the garbage `cone` is MSVC `CD CD CD CD`
uninitialized fill Turbine baked into the dat — point lights never read it). **DO NOT `÷100`.**
The actual divergence is the **[HIGH] `no-static-light-burnin`**: retail bakes ALL of a cell's
reaching static lights **PER-VERTEX once** (`D3DPolyRender::SetStaticLightingVertexColors`
0x0059cfe0 → `calc_point_light` 0x0059c8b0, Gouraud-interpolated → uniform, never blown out via
the per-channel min-to-colour clamp), while we light **per-PIXEL with only the 8 nearest-to-
CAMERA lights** → bright pools near torches, dark between, and a crescent that slides as the
camera re-ranks the 8-slot list. Diagnosed via a 5-agent investigation + a clean Ghidra
decompile (the BN pseudo-C is x87-mangled). **LANDED:** the per-pixel `(1-dist/falloff_eff)`
shader ramp (`007e287`, necessary but NOT sufficient — it can't fix the per-vertex-vs-per-pixel
structure) + the GL-free `LightBake` Core (`3b93f91`: the verbatim `calc_point_light` port +
7 conformance tests). **REMAINING — the A7 integration:** add a per-vertex linear-RGB colour
attribute to the cell mesh + a bake driver keyed on `envCellId` (NOT the dedup `cellGeomId`
adjacent rooms share a geom but not their torches) + consume it in `mesh_modern.frag` for cell
draws; bound the bake's light set to the player dungeon (#133's FPS collapse already does this).
Belongs to the #79/#93 indoor-lighting umbrella; outdoor static objects + building shells still
use the per-pixel-8 path (the same spottiness — separate follow-up). **NOTE — dungeon FPS is
FIXED** (was 1430 from streaming ~129 neighbour ocean-grid dungeons; now ~1000+ fps after the
#133 streaming collapse + the allocation-free 8-light partial-select, `5872bcf`/`5686050`).
**Severity:** HIGH (any far/dungeon teleport is unusable)
**Filed:** 2026-06-13 (M1.5 dungeon-demo gate attempt — meeting-hall portal)
**Component:** physics/streaming — teleport-arrival snap vs async landblock hydration