feat(physics): add differential flat BSP traversal

Port every current containment, overlap, walkable, and six-path moving-collision query to immutable integer-indexed assets behind a graph-authoritative referee. Exact synthetic, installed-DAT, complete-resolver, and zero-allocation gates prove bit-identical behavior before connected dual publication.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-25 15:47:58 +02:00
parent 9cd42417a8
commit f7ff9f4eea
13 changed files with 3907 additions and 46 deletions

View file

@ -159,15 +159,19 @@ public static class CellTransit
// neighbour cell whether the sphere intersects its CellBSP.
// The portal-plane side test is only the unloaded-cell load hint.
var otherCell = cache.GetCellStruct(otherId);
if (otherCell?.CellBSP?.Root is not null)
if (otherCell is not null &&
CollisionTraversal.HasCellContainment(cache, otherCell))
{
for (int i = 0; i < sphereCount; i++)
{
var sphere = worldSpheres[i];
var otherLocalCenter = Vector3.Transform(
sphere.Origin, otherCell.InverseWorldTransform);
bool hit = BSPQuery.SphereIntersectsCellBsp(
otherCell.CellBSP.Root, otherLocalCenter, sphere.Radius);
bool hit = CollisionTraversal.SphereIntersectsCell(
cache,
otherCell,
otherLocalCenter,
sphere.Radius);
if (hit)
{
candidates.Add(otherId);
@ -372,7 +376,8 @@ public static class CellTransit
continue;
var otherCell = cache.GetCellStruct(portal.OtherCellId);
if (otherCell?.CellBSP?.Root is null)
if (otherCell is null ||
!CollisionTraversal.HasCellContainment(cache, otherCell))
{
if (PhysicsDiagnostics.ProbeIndoorBspEnabled)
{
@ -398,8 +403,11 @@ public static class CellTransit
{
var sphere = worldSpheres[i];
var localCenter = Vector3.Transform(sphere.Origin, otherCell.InverseWorldTransform);
inside = BSPQuery.SphereIntersectsCellBsp(
otherCell.CellBSP.Root, localCenter, sphere.Radius);
inside = CollisionTraversal.SphereIntersectsCell(
cache,
otherCell,
localCenter,
sphere.Radius);
if (PhysicsDiagnostics.ProbeIndoorBspEnabled)
{
@ -599,19 +607,25 @@ public static class CellTransit
if (start is null) return 0u;
// this->point_in_cell(point) → return this (:311402-311405)
if (PointInCell(start, worldPoint)) return startCellId;
if (PointInCell(cache, start, worldPoint)) return startCellId;
if (useStabList)
{
// arg3 != 0 → iterate stab_list, GetVisible + point_in_cell (:311444-311465)
foreach (uint id in start.VisibleCellIds)
if (PointInCell(cache.GetCellStruct(id), worldPoint)) return id;
if (PointInCell(cache, cache.GetCellStruct(id), worldPoint)) return id;
}
else
{
// arg3 == 0 → iterate direct portals, GetOtherCell + point_in_cell (:311411-311434)
foreach (var portal in start.Portals)
if (PointInCell(cache.GetCellStruct(portal.OtherCellId), worldPoint)) return portal.OtherCellId;
if (PointInCell(
cache,
cache.GetCellStruct(portal.OtherCellId),
worldPoint))
{
return portal.OtherCellId;
}
}
return 0u;
@ -623,11 +637,19 @@ public static class CellTransit
/// A cell with no hydrated <see cref="CellPhysics.CellBSP"/> returns false (see
/// <see cref="FindVisibleChildCell"/>'s adaptation note).
/// </summary>
private static bool PointInCell(CellPhysics? cell, Vector3 worldPoint)
private static bool PointInCell(
PhysicsDataCache cache,
CellPhysics? cell,
Vector3 worldPoint)
{
if (cell?.CellBSP?.Root is null) return false;
if (cell is null ||
!CollisionTraversal.HasCellContainment(cache, cell))
{
return false;
}
var local = Vector3.Transform(worldPoint, cell.InverseWorldTransform);
return BSPQuery.PointInsideCellBsp(cell.CellBSP.Root, local);
return CollisionTraversal.PointInsideCell(cache, cell, local);
}
/// <summary>
@ -901,9 +923,14 @@ public static class CellTransit
{
// Interior candidate — point_in_cell via the cell BSP (vtable[0x84]).
var cand = cache.GetCellStruct(candId);
if (cand?.CellBSP?.Root is null) continue;
if (cand is null ||
!CollisionTraversal.HasCellContainment(cache, cand))
{
continue;
}
var local = Vector3.Transform(worldSphereCenter, cand.InverseWorldTransform);
if (BSPQuery.PointInsideCellBsp(cand.CellBSP.Root, local))
if (CollisionTraversal.PointInsideCell(cache, cand, local))
return candId; // interior-wins, stop (pseudo_c:308819)
}
else if (outdoorResult == 0u && containingOutdoorId != 0u && outdoorPickAllowed)
@ -950,10 +977,15 @@ public static class CellTransit
if (currentLow >= 0x0100u)
{
var cur = cache.GetCellStruct(currentCellId);
if (cur?.CellBSP?.Root is not null)
if (cur is not null &&
CollisionTraversal.HasCellContainment(cache, cur))
{
var curLocal = Vector3.Transform(worldSphereCenter, cur.InverseWorldTransform);
if (!BSPQuery.SphereIntersectsCellBsp(cur.CellBSP.Root, curLocal, sphereRadius))
if (!CollisionTraversal.SphereIntersectsCell(
cache,
cur,
curLocal,
sphereRadius))
{
uint recovered = FindVisibleChildCell(
cache, currentCellId, worldSphereCenter, useStabList: true);