fix(G.3): register connector cells in the PHYSICS graph too — viewer-cell transit (#133)

After registering portals-only connector cells for VISIBILITY (d90c538), an
angle-dependent residual grey remained when the camera crossed a ramp: the
camera-collision sweep (SmartBox::update_viewer -> sphere_path.curr_cell, pc:92870)
could not transit INTO the connector cell because it had no physics cell to sweep
into — CacheCellStruct was still gated on drawable sub-meshes. So the viewer cell
stalled one cell behind the eye (confirmed live: [flap-sweep] transited every cached
neighbour but NEVER the un-cached connector 0x014D, viewerCell stuck at 0x00070103
while the eye sat 1.32 m past the connector's portal plane), and the side test
correctly culled the on-screen connector portal -> grey.

Fix: move CacheCellStruct out of the `cellSubMeshes.Count > 0` gate, next to
BuildLoadedCell — cache EVERY cell with a valid cellStruct for physics too. Retail
keeps the whole landblock cell array resident for the sweep; a portals-only
connector has an empty collision BSP but its portals drive the transit. User-gated:
"I see no grey background any longer."

Build green; 12 flood-gate tests + 677 physics/cell/transit tests green (no collision
or membership regression). TEMP render probes still retained (strip after).

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

View file

@ -5696,6 +5696,20 @@ public sealed class GameWindow : IDisposable
// lift shifted horizontal portal planes 2 cm, side-culling deck/stair cells).
BuildLoadedCell(envCellId, envCell, cellStruct, physicsCellOrigin, physicsCellTransform);
// PHYSICS cell graph: cache EVERY cell with a valid cellStruct, regardless of
// drawable sub-meshes. The camera-collision sweep (SmartBox::update_viewer →
// sphere_path.curr_cell, pc:92870) and the player cell-transit must be able to
// TRANSIT THROUGH a portals-only connector — otherwise the viewer/curr cell can
// never reach it and lags one cell behind the eye (#133 residual: the camera sat
// 1.32 m past the ramp portal's plane while the viewer cell stalled in
// 0x00070103 — the sweep transited every cached neighbour but NEVER the
// un-cached connector 0x014D — so the side test culled the on-screen connector
// portal and the grey clear showed through). Retail keeps the whole landblock
// cell array resident for the sweep; a portals-only connector has an empty
// collision BSP but its portals drive the transit. CacheCellStruct reads the
// cellStruct directly, not the render sub-meshes.
_physicsDataCache.CacheCellStruct(envCellId, envCell, cellStruct, physicsCellTransform);
var cellSubMeshes = AcDream.Core.Meshing.CellMesh.Build(envCell, cellStruct, _dats);
if (cellSubMeshes.Count > 0)
{
@ -5713,10 +5727,6 @@ public sealed class GameWindow : IDisposable
cellWorldPosition: cellOrigin,
cellRotation: envCell.Position.Orientation,
staticObjects: System.Array.Empty<(uint, System.Numerics.Vector3, System.Numerics.Quaternion, bool, System.Numerics.Matrix4x4)>());
// Cache CellStruct physics BSP for indoor collision (UNCHANGED — gated
// on drawable cells; a portals-only connector has no collision surface).
_physicsDataCache.CacheCellStruct(envCellId, envCell, cellStruct, physicsCellTransform);
}
}
}