Phase B's WorldPicker change added cellOccluder to both Pick overloads,
but the integration test suite only covered the legacy ray-sphere
overload. The production code path (GameWindow.PickAndStoreSelection)
uses the screen-rect overload, and its clip.W depth-conversion math
had no direct test. Adds two integration tests mirroring the existing
ray-sphere variants:
- Pick_ScreenRect_EntityBehindWall_OccludedByCellBsp — entity dead-
ahead, wall between, with cellOccluder → null.
- Pick_ScreenRect_NoWall_HitsEntity — same scene, null occluder → hit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
WorldPicker.Pick previously had no occlusion test — any entity along
the click ray within maxDistance was a candidate, including ones
behind walls. Adds the CellBspRayOccluder static helper that
Möller-Trumbore-tests the click ray against every polygon in every
currently-cached EnvCell BSP, returning the nearest wall-hit `t`.
Both Pick overloads gate candidate selection by that wall-t (legacy
ray-sphere via world-space `t`, screen-rect via camera-space clip.W
depth — matching ScreenProjection.TryProjectSphereToScreenRect's
convention).
PhysicsDataCache exposes a new CellStructIds snapshot accessor so the
caller can iterate without needing the private cache dictionary.
CellPhysics.BSP/PhysicsPolygons/Vertices relaxed from required to
nullable so test fixtures can construct a CellPhysics from Resolved
alone without a real DAT BSP object. GameWindow snapshots the loaded
cell physics on each Pick call and passes the occluder callback.
Closes#86.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>