fix(physics): validate retail cell containment roots

This commit is contained in:
Erik 2026-07-31 14:48:26 +02:00
parent 7716c2ee89
commit 3e0f3b6206
23 changed files with 429 additions and 197 deletions

View file

@ -18,7 +18,10 @@
using System.Collections.Generic;
using System.Numerics;
using AcDream.Core.World.Cells;
using DatReaderWriter.Enums;
using Xunit;
using CellBSPNode = DatReaderWriter.Types.CellBSPNode;
using CellBSPTree = DatReaderWriter.Types.CellBSPTree;
namespace AcDream.Core.Tests.Rendering;
@ -29,8 +32,8 @@ public class CellGraphRootTests
// ------------------------------------------------------------------
/// <summary>
/// Synthetic EnvCell with an identity transform and axis-aligned bounds so
/// PointInCell returns true for points inside [min, max].
/// Synthetic EnvCell with an authored six-plane containment BSP for
/// [min,max] and one portal so retail CEnvCell::point_in_cell is eligible.
/// seenOutside = false → sealed dungeon; true → building interior/exterior.
/// </summary>
private static EnvCell MakeEnvCell(uint id, Vector3 min, Vector3 max, bool seenOutside = false)
@ -39,10 +42,10 @@ public class CellGraphRootTests
Matrix4x4.Identity,
Matrix4x4.Identity,
min, max,
portals: new List<CellPortal>(),
portals: new List<CellPortal> { new(0xFFFFu, 0, 0, 0) },
stabList: new List<uint>(),
seenOutside: seenOutside,
containmentBsp: null);
containmentBsp: new CellBSPTree { Root = BoundsBsp(min, max) });
/// <summary>
/// EnvCell with an explicit stab list (used by FindVisibleChildCell tests).
@ -54,10 +57,30 @@ public class CellGraphRootTests
Matrix4x4.Identity,
Matrix4x4.Identity,
min, max,
portals: new List<CellPortal>(),
portals: new List<CellPortal> { new(0xFFFFu, 0, 0, 0) },
stabList: stabList,
seenOutside: seenOutside,
containmentBsp: null);
containmentBsp: new CellBSPTree { Root = BoundsBsp(min, max) });
private static CellBSPNode BoundsBsp(Vector3 min, Vector3 max)
{
var leaf = new CellBSPNode { Type = BSPNodeType.Leaf };
CellBSPNode Add(Plane plane, CellBSPNode positive) => new()
{
Type = BSPNodeType.BPIn,
SplittingPlane = plane,
PosNode = positive,
};
CellBSPNode root = leaf;
root = Add(new Plane(-Vector3.UnitZ, max.Z), root);
root = Add(new Plane(Vector3.UnitZ, -min.Z), root);
root = Add(new Plane(-Vector3.UnitY, max.Y), root);
root = Add(new Plane(Vector3.UnitY, -min.Y), root);
root = Add(new Plane(-Vector3.UnitX, max.X), root);
root = Add(new Plane(Vector3.UnitX, -min.X), root);
return root;
}
// ------------------------------------------------------------------
// Predicate helpers — mirror the formulas in GameWindow.OnRender (Stage 3)