# Handoff — indoor lighting DONE; NEXT: #145 portal re-use, then #144 dungeon dimness **Date:** 2026-06-20 **Branch:** `claude/thirsty-goldberg-51bb9b` — **committed, NOT merged to main, NOT pushed** (user's call) **Milestone:** M1.5 "Indoor world feels right" --- ## What shipped this session (on the branch, not pushed) The entire indoor-lighting saga. **#142 + #143 CLOSED, user-confirmed.** | Commit | What | |---|---| | `ef5049f` | #142 per-instance sun gate (indoor objects skip the sun, per-draw like retail) | | `0d8b827` | **THE root-cause fix** — EnvCellRenderer landblock-key bug + viewer light + weenie fixture lights | | `57c2ab7` | #143 dynamic-light D3D `1/d` attenuation (portal + viewer spread softly) | | `653e7f3` | docs: close #142/#143, file #144 | | (this) | docs: file #145 + this handoff | **One-line story:** interiors were dark NOT because of the sun/ambient (those were already retail-faithful — the 0.2-flat/sky split == `CellManager::ChangePosition` 0x004559B0). The real bug was a landblock-key lookup in `EnvCellRenderer.GetCellLightSet`: it keyed `_landblocks` by `cellId & 0xFFFF0000` (0xXXYY**0000**) instead of the streaming key 0xXXYY**FFFF**, so the lookup missed for EVERY cell → `SelectForObject` never ran → every interior wall got ZERO point lights, always. Fix: `(cellId & 0xFFFF0000) | 0xFFFF`. Found by a `[cell-light]` probe (inBounds=False selected=0 → True selected=3-4) after 3+ speculative fixes. Retail mechanisms ported alongside it (all faithful, decomp-cited): - **Viewer light** — `SmartBox::set_viewer` 0x00452c40: white fill pinned to the player every frame; `1/d` att, range 15. `LightManager.UpdateViewerLight`. - **Weenie fixture lights** (AP-44) — server-object `Setup.Lights` registered on spawn (`OnLiveEntitySpawnedLocked`); the meeting-hall portal's magenta light rides this → #143 lit "for free." - **Dynamic vs static attenuation** — `config_hardware_light` 0x0059ad30: dynamic = `1/d` + range×1.5; static = `1/d³` + range×1.3. Per-light `IsDynamic` flag packed into `GlobalLight.coneAngleEtc.y`. Register: AP-43 (#142 sun gate), AP-44 (weenie lights), AP-47 (acdream's always-lit interiors vs retail's 40-light pop-in — INTENTIONAL). Full lighting detail: memory `reference_retail_ambient_values.md` (2026-06-20 resolution note). **Suites:** Core 1505 / App 476 green. --- ## NEXT SESSION — in this order ### 1. FIRST — #145: portals only work once per session (HIGH) User wants: **run into a portal, run out, re-enter — repeatedly.** Currently only the FIRST teleport works; the second portal use does nothing. - **Machinery:** `WorldSession.cs:999` (0xF751 PlayerTeleport) → `PlayerMovementController` `PlayerState.PortalSpace` (`:75`/`:840`) → `TeleportArrivalController` (`Phase` Idle/Holding; the placement delegate flips PortalSpace back to InWorld) → `GameWindow.cs:4903/5332/5362` (PortalSpace observer + arrival placement) → streaming collapse↔expand (#133/#135 machinery). - **First step (don't guess):** instrument a SECOND teleport and find WHERE it stalls — does the 2nd 0xF751 arrive? does PortalSpace toggle back to InWorld? does `TeleportArrivalController.Tick` place via `PlaceTeleportArrival`? does the streaming window re-expand? One probe across those four points pins it. - **Likely overlaps #138** (teleport OUT of a dungeon loads the outdoor world incompletely) — may be the same root or a sibling; check together. ### 2. THEN — #144: dungeon interiors still too dim vs retail (MEDIUM) Dungeons improved (torch cells light up now — the landblock-key fix + viewer fill), but torch-sparse stretches + overall brightness still trail retail (user: "better but not good enough"). - **Approach:** side-by-side **cdb capture of retail's dungeon** — `world_lights` active set + `world_lights.ambient_color` + the viewer-light intensity at the SAME spot — vs acdream's `[light]`/`[light-detail]` there. Do NOT guess. - **Candidates:** per-vertex Gouraud bake under-lights low-poly dungeon walls (AP-35 residual); the sealed-dungeon flat 0.2 ambient too dark; retail leans harder on the viewer light / carries more dynamics. --- ## Launch / probes `testaccount2` / `testpassword2` (character Horan, spawns near Holtburg; reaches the 0x0007 Town Network dungeon). Canonical launch + `ACDREAM_PROBE_LIGHT=1` + `ACDREAM_PROBE_CELL=1` → `[light]` / `[light-detail]` / `[cell-transit]`. The `[cell-light]` per-cell probe was STRIPPED (the bug it found is fixed) — re-add a per-cell light probe in `EnvCellRenderer.GetCellLightSet` if #144 needs it. ## Pointers - memory `reference_retail_ambient_values.md` — lighting resolution + the cdb toolchain. - `docs/architecture/retail-divergence-register.md` — AP-43 / AP-44 / AP-47. - `docs/ISSUES.md` — #144, #145, #138 (related), #137 (dungeon collision). - cdb toolchain: CLAUDE.md "Retail debugger toolchain" (binary matches `refs/acclient.pdb`).