From 3e006d372a77903db11afdecc007d257e6f58464 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 14 Jun 2026 14:21:41 +0200 Subject: [PATCH] =?UTF-8?q?fix(G.3):=20register=20connector=20cells=20in?= =?UTF-8?q?=20the=20PHYSICS=20graph=20too=20=E2=80=94=20viewer-cell=20tran?= =?UTF-8?q?sit=20(#133)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- src/AcDream.App/Rendering/GameWindow.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 5a6e2868..3eb7d8aa 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -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); } } }