fix(physics): validate retail cell containment roots
This commit is contained in:
parent
7716c2ee89
commit
3e0f3b6206
23 changed files with 429 additions and 197 deletions
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using DatReaderWriter.Enums;
|
||||
|
|
@ -63,6 +62,7 @@ public class BuildShadowCellSetTests
|
|||
private static CellPhysics MakeLeafCell(Matrix4x4 worldTransform)
|
||||
{
|
||||
Matrix4x4.Invert(worldTransform, out var inv);
|
||||
var root = new CellBSPNode { Type = BSPNodeType.Leaf };
|
||||
return new CellPhysics
|
||||
{
|
||||
WorldTransform = worldTransform,
|
||||
|
|
@ -70,40 +70,25 @@ public class BuildShadowCellSetTests
|
|||
Resolved = new Dictionary<ushort, ResolvedPolygon>(),
|
||||
CellBSP = new CellBSPTree
|
||||
{
|
||||
Root = new CellBSPNode { Type = BSPNodeType.Leaf },
|
||||
Root = root,
|
||||
},
|
||||
FlatContainmentBsp = FlatCollisionAssetBuilder.FlattenCellContainmentBsp(root),
|
||||
};
|
||||
}
|
||||
|
||||
private static CellPhysics MakeNullRootCell(Matrix4x4 worldTransform)
|
||||
{
|
||||
Matrix4x4.Invert(worldTransform, out var inv);
|
||||
return new CellPhysics
|
||||
{
|
||||
WorldTransform = worldTransform,
|
||||
InverseWorldTransform = inv,
|
||||
Resolved = new Dictionary<ushort, ResolvedPolygon>(),
|
||||
CellBSP = new CellBSPTree { Root = null },
|
||||
FlatContainmentBsp = new FlatCellContainmentBsp(
|
||||
-1,
|
||||
ImmutableArray<FlatCellBspNode>.Empty),
|
||||
};
|
||||
}
|
||||
|
||||
private static CellPhysics MakeNullRootCellWithExteriorPortal(
|
||||
private static CellPhysics MakeValidCellWithExteriorPortal(
|
||||
Matrix4x4 worldTransform)
|
||||
{
|
||||
Matrix4x4.Invert(worldTransform, out var inv);
|
||||
var portalPlane = new Plane(new Vector3(1f, 0f, 0f), -2.5f);
|
||||
var root = new CellBSPNode { Type = BSPNodeType.Leaf };
|
||||
return new CellPhysics
|
||||
{
|
||||
WorldTransform = worldTransform,
|
||||
InverseWorldTransform = inv,
|
||||
Resolved = new Dictionary<ushort, ResolvedPolygon>(),
|
||||
CellBSP = new CellBSPTree { Root = null },
|
||||
FlatContainmentBsp = new FlatCellContainmentBsp(
|
||||
-1,
|
||||
ImmutableArray<FlatCellBspNode>.Empty),
|
||||
CellBSP = new CellBSPTree { Root = root },
|
||||
FlatContainmentBsp = FlatCollisionAssetBuilder.FlattenCellContainmentBsp(root),
|
||||
PortalPolygons = new Dictionary<ushort, ResolvedPolygon>
|
||||
{
|
||||
[10] = new ResolvedPolygon
|
||||
|
|
@ -191,7 +176,7 @@ public class BuildShadowCellSetTests
|
|||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void IndoorSeed_RefloodsAfterNullRootPayloadHydrates(
|
||||
public void IndoorSeed_RefloodsAfterValidPayloadHydrates(
|
||||
bool useFlat)
|
||||
{
|
||||
var cache = new PhysicsDataCache
|
||||
|
|
@ -212,7 +197,7 @@ public class BuildShadowCellSetTests
|
|||
|
||||
cache.RegisterCellStructForTest(
|
||||
IndoorSeed,
|
||||
MakeNullRootCellWithExteriorPortal(Matrix4x4.Identity));
|
||||
MakeValidCellWithExteriorPortal(Matrix4x4.Identity));
|
||||
IReadOnlyList<uint> hydrated = CellTransit.BuildShadowCellSet(
|
||||
cache,
|
||||
IndoorSeed,
|
||||
|
|
@ -322,7 +307,7 @@ public class BuildShadowCellSetTests
|
|||
};
|
||||
cache.RegisterCellStructForTest(
|
||||
NeighborCell,
|
||||
MakeNullRootCell(Matrix4x4.Identity));
|
||||
MakeLeafCell(Matrix4x4.Identity));
|
||||
|
||||
var sphere = One(new Vector3(12f, 12f, 0f), 0.5f);
|
||||
IReadOnlyList<uint> seeded = CellTransit.BuildShadowCellSet(
|
||||
|
|
@ -365,6 +350,65 @@ public class BuildShadowCellSetTests
|
|||
Assert.Contains(NeighborCell, hydrated);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void LoadedSeed_AbsentAdjacentLandcell_SkipsStaleBuildingUntilAdjacentHydrates(
|
||||
bool useFlat)
|
||||
{
|
||||
const uint seedCell = 0xA9B4_0031u;
|
||||
const uint adjacentCell = 0xA9B3_0038u;
|
||||
const uint interiorCell = 0xA9B3_0100u;
|
||||
var cache = new PhysicsDataCache
|
||||
{
|
||||
CollisionTraversalMode = useFlat
|
||||
? CollisionTraversalMode.Flat
|
||||
: CollisionTraversalMode.Graph,
|
||||
};
|
||||
cache.CellGraph.RegisterTerrain(
|
||||
0xA9B4_0000u,
|
||||
new TerrainSurface(new byte[81], new float[256]),
|
||||
Vector3.Zero);
|
||||
cache.RegisterCellStructForTest(
|
||||
interiorCell,
|
||||
MakeLeafCell(Matrix4x4.Identity));
|
||||
cache.RegisterBuildingForTest(adjacentCell, new BuildingPhysics
|
||||
{
|
||||
WorldTransform = Matrix4x4.Identity,
|
||||
InverseWorldTransform = Matrix4x4.Identity,
|
||||
Portals =
|
||||
[
|
||||
new BldPortalInfo(interiorCell, otherPortalId: 0, flags: 0),
|
||||
],
|
||||
});
|
||||
Sphere[] sphere = One(new Vector3(150f, 0.2f, 0f), 0.5f);
|
||||
|
||||
IReadOnlyList<uint> unavailable = CellTransit.BuildShadowCellSet(
|
||||
cache,
|
||||
seedCell,
|
||||
sphere,
|
||||
1,
|
||||
isStatic: false);
|
||||
|
||||
Assert.Contains(seedCell, unavailable);
|
||||
Assert.Contains(adjacentCell, unavailable);
|
||||
Assert.DoesNotContain(interiorCell, unavailable);
|
||||
|
||||
cache.CellGraph.RegisterTerrain(
|
||||
0xA9B3_0000u,
|
||||
new TerrainSurface(new byte[81], new float[256]),
|
||||
new Vector3(0f, -192f, 0f));
|
||||
IReadOnlyList<uint> hydrated = CellTransit.BuildShadowCellSet(
|
||||
cache,
|
||||
seedCell,
|
||||
sphere,
|
||||
1,
|
||||
isStatic: false);
|
||||
|
||||
Assert.Contains(adjacentCell, hydrated);
|
||||
Assert.Contains(interiorCell, hydrated);
|
||||
}
|
||||
|
||||
// ── Exterior straddle from an indoor seed ──────────────────────────
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue