feat(core): Stage 3 T3.3 — CellGraph.FindVisibleChildCell (retail find_visible_child_cell)

Port CEnvCell::find_visible_child_cell @ 0x0052dc50 (pseudo_c:311397): walk
rootId's StabList + the root itself, return the first EnvCell whose
PointInCell is true for worldPoint. Used to resolve the camera cell in
3rd-person from the physics cell graph rather than a fresh AABB reclassification.
Root is always the player cell (preserves U.4c flap fix). Returns null when
no stab-list cell or root itself contains the query point.

Confirmed (T3.3 Step 1): no production call site uses FindCameraCell for the
camera projection — the only AABB camera resolver is now deleted (T3.1).
FindVisibleChildCell is wired implicitly via Stage 4 (camera-outside-door scenario);
no GameWindow call site needed in Stage 3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-02 15:37:10 +02:00
parent 352086042e
commit 38a52a7dac

View file

@ -55,4 +55,24 @@ public sealed class CellGraph
/// reserved for the OtherCellPtr neighbor cache (Stage 3); the lookup keys only on the portal.
/// </summary>
public ObjCell? Neighbor(ObjCell cell, in CellPortal portal) => GetVisible(portal.OtherCellId);
/// <summary>
/// Retail CEnvCell::find_visible_child_cell @ 0x0052dc50 (pseudo_c:311397).
/// Walk <paramref name="rootId"/>'s StabList + the root itself, return the first
/// EnvCell whose <see cref="ObjCell.PointInCell"/> is true for
/// <paramref name="worldPoint"/>. Used to resolve the camera cell in 3rd-person
/// from the physics cell graph rather than an independent AABB reclassification —
/// the root is the player cell, never a camera-eye AABB scan.
/// Returns null when no cell in the root's stab list (or the root itself) contains
/// the query point (caller falls back to the player cell as projection root).
/// </summary>
public EnvCell? FindVisibleChildCell(uint rootId, Vector3 worldPoint)
{
if (!_envCells.TryGetValue(rootId, out var root)) return null;
if (root.PointInCell(worldPoint)) return root;
foreach (var stabId in root.StabList)
if (_envCells.TryGetValue(stabId, out var stab) && stab.PointInCell(worldPoint))
return stab;
return null;
}
}