fix(render): Phase A8 — stamp BuildingId on already-loaded cells too
First visual-gate launch showed 8,737 [vis] lines (player at Holtburg cottage cell 0xA9B40143, inside=True really=True) but ZERO [buildings] / [envcells] / [stencil] / [draworder] probe emissions. Root cause: same as the original RR7.1 saga — BuildingLoader.Build was passed only the per-frame drainedCells dict, missing cells loaded on PRIOR frames. Those cells stayed with BuildingId=null, the strict cameraInsideBuilding gate returned false, the indoor branch never fired. Fix: in ApplyLoadedTerrainLocked, merge drainedCells with the cells already registered in _cellVisibility for the same landblock prefix before passing to BuildingLoader. The richer dict ensures the stamping loop in BuildingLoader.Build covers EVERY cell in this landblock. Added IReadOnlyList<LoadedCell> GetCellsForLandblock(uint lbId) on CellVisibility — minimal API expose; existing _cellsByLandblock dict was already the right shape (lbId = upper 16 bits). Build green. Tests unchanged. Next: relaunch the client. With the fix, [buildings] probe should fire with camBldgs=[0x1,...] when the player is inside a Holtburg cottage, [envcells] should report cells>=1 tris>=1 per indoor frame, and the indoor branch should be exercising the WB-faithful Steps 1-5 pipeline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8532c84f57
commit
0fc6003c2a
2 changed files with 45 additions and 8 deletions
|
|
@ -208,6 +208,23 @@ public sealed class CellVisibility
|
|||
_cellLookup[cell.CellId] = cell;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Phase A8 (2026-05-28): enumerates the loaded cells that belong to a
|
||||
/// landblock prefix. Used by <c>GameWindow.ApplyLoadedTerrainLocked</c> when
|
||||
/// building the per-landblock <c>BuildingRegistry</c> — the per-frame
|
||||
/// <c>drainedCells</c> dict misses cells loaded on prior frames, so the
|
||||
/// stamping loop in <see cref="Wb.BuildingLoader.Build"/> needs access to
|
||||
/// every cell currently in the landblock to ensure <c>BuildingId</c> is set.
|
||||
/// </summary>
|
||||
/// <param name="lbId">Upper 16 bits of the landblock key (e.g. <c>0xA9B4</c>
|
||||
/// for landblock <c>0xA9B40000</c>). NOT the full 32-bit landblock id.</param>
|
||||
public IReadOnlyList<LoadedCell> GetCellsForLandblock(uint lbId)
|
||||
{
|
||||
return _cellsByLandblock.TryGetValue(lbId, out var list)
|
||||
? list
|
||||
: System.Array.Empty<LoadedCell>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all cells belonging to <paramref name="lbId"/> (upper 16 bits of
|
||||
/// the landblock key, e.g. 0xA9B4 for landblock 0xA9B40000). Called when a
|
||||
|
|
|
|||
|
|
@ -5878,18 +5878,38 @@ public sealed class GameWindow : IDisposable
|
|||
_physicsEngine.AddLandblock(lb.LandblockId, terrainSurface, cellSurfaces,
|
||||
portalPlanes, origin.X, origin.Y);
|
||||
|
||||
// Phase A8 (2026-05-26): build per-landblock BuildingRegistry from
|
||||
// LandBlockInfo.Buildings, stamping LoadedCell.BuildingId for each cell
|
||||
// in a building's cell set. Uses the already-drained drainedCells dict
|
||||
// (LoadedCells registered this frame) so stamping and registry build
|
||||
// happen in the same render-thread pass — no extra dat reads required.
|
||||
// Cells without a building stay at BuildingId == null (outdoor surface
|
||||
// cells; dungeon cells not enumerated in LandBlockInfo.Buildings).
|
||||
// Phase A8 (2026-05-26 / fix 2026-05-28): build per-landblock
|
||||
// BuildingRegistry from LandBlockInfo.Buildings, stamping
|
||||
// LoadedCell.BuildingId for each cell in a building's cell set.
|
||||
//
|
||||
// FIX 2026-05-28: previously passed `drainedCells` only — that's the
|
||||
// dict of cells drained THIS frame. Cells loaded on prior frames
|
||||
// were missed, leaving their BuildingId null and the
|
||||
// `cameraInsideBuilding` gate FALSE even when the player was inside
|
||||
// a tagged cottage. (First visual-gate launch showed 8737 [vis]
|
||||
// lines with inside=True really=True but ZERO [buildings] probe
|
||||
// emissions — same root cause as the RR7.1 / RR7.2 saga.) The fix:
|
||||
// merge `drainedCells` with every cell currently registered with
|
||||
// _cellVisibility for this landblock prefix. BuildingLoader's BFS
|
||||
// + stamping pass then sees the complete cell set.
|
||||
//
|
||||
// Cells without a building stay at BuildingId == null (outdoor
|
||||
// surface cells; dungeon cells not enumerated in LandBlockInfo.Buildings).
|
||||
if (lbInfo is not null)
|
||||
{
|
||||
// Merge: previously-loaded cells + freshly-drained cells.
|
||||
// drainedCells wins on key collision (it has the same instance
|
||||
// anyway — both dicts reference the same LoadedCell objects).
|
||||
var lbStampCells = new System.Collections.Generic.Dictionary<uint, LoadedCell>(drainedCells);
|
||||
uint lbPrefix = (lb.LandblockId >> 16) & 0xFFFFu;
|
||||
foreach (var c in _cellVisibility.GetCellsForLandblock(lbPrefix))
|
||||
{
|
||||
if (!lbStampCells.ContainsKey(c.CellId))
|
||||
lbStampCells[c.CellId] = c;
|
||||
}
|
||||
_buildingRegistries[lb.LandblockId] =
|
||||
AcDream.App.Rendering.Wb.BuildingLoader.Build(
|
||||
lbInfo, lb.LandblockId, drainedCells);
|
||||
lbInfo, lb.LandblockId, lbStampCells);
|
||||
}
|
||||
|
||||
// Phase A8: finalize EnvCellRenderer's per-landblock instance store.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue