fix(physics): restore retail cell availability semantics
This commit is contained in:
parent
d3c0d9ec0e
commit
7716c2ee89
14 changed files with 393 additions and 62 deletions
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using DatReaderWriter.Enums;
|
||||
|
|
@ -74,6 +75,64 @@ public class BuildShadowCellSetTests
|
|||
};
|
||||
}
|
||||
|
||||
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(
|
||||
Matrix4x4 worldTransform)
|
||||
{
|
||||
Matrix4x4.Invert(worldTransform, out var inv);
|
||||
var portalPlane = new Plane(new Vector3(1f, 0f, 0f), -2.5f);
|
||||
return new CellPhysics
|
||||
{
|
||||
WorldTransform = worldTransform,
|
||||
InverseWorldTransform = inv,
|
||||
Resolved = new Dictionary<ushort, ResolvedPolygon>(),
|
||||
CellBSP = new CellBSPTree { Root = null },
|
||||
FlatContainmentBsp = new FlatCellContainmentBsp(
|
||||
-1,
|
||||
ImmutableArray<FlatCellBspNode>.Empty),
|
||||
PortalPolygons = new Dictionary<ushort, ResolvedPolygon>
|
||||
{
|
||||
[10] = new ResolvedPolygon
|
||||
{
|
||||
Vertices =
|
||||
[
|
||||
new Vector3(2.5f, -2.5f, 0f),
|
||||
new Vector3(2.5f, 2.5f, 0f),
|
||||
new Vector3(2.5f, 2.5f, 5f),
|
||||
new Vector3(2.5f, -2.5f, 5f),
|
||||
],
|
||||
Plane = portalPlane,
|
||||
NumPoints = 4,
|
||||
SidesType = CullMode.None,
|
||||
},
|
||||
},
|
||||
Portals =
|
||||
[
|
||||
new PortalInfo(otherCellId: 0xFFFF, polygonId: 10, flags: 0),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
private static void RegisterFlatTerrain(PhysicsDataCache cache)
|
||||
=> cache.CellGraph.RegisterTerrain(
|
||||
0xA9B40000u,
|
||||
new TerrainSurface(new byte[81], new float[256]),
|
||||
Vector3.Zero);
|
||||
|
||||
// ── Seeds ──────────────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
|
|
@ -129,6 +188,42 @@ public class BuildShadowCellSetTests
|
|||
Assert.Equal(new[] { IndoorSeed }, set);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void IndoorSeed_RefloodsAfterNullRootPayloadHydrates(
|
||||
bool useFlat)
|
||||
{
|
||||
var cache = new PhysicsDataCache
|
||||
{
|
||||
CollisionTraversalMode = useFlat
|
||||
? CollisionTraversalMode.Flat
|
||||
: CollisionTraversalMode.Graph,
|
||||
};
|
||||
Sphere[] sphere = One(new Vector3(2.4f, 0f, 2.5f), 0.5f);
|
||||
|
||||
IReadOnlyList<uint> unavailable = CellTransit.BuildShadowCellSet(
|
||||
cache,
|
||||
IndoorSeed,
|
||||
sphere,
|
||||
1,
|
||||
isStatic: false);
|
||||
Assert.Equal(new[] { IndoorSeed }, unavailable);
|
||||
|
||||
cache.RegisterCellStructForTest(
|
||||
IndoorSeed,
|
||||
MakeNullRootCellWithExteriorPortal(Matrix4x4.Identity));
|
||||
IReadOnlyList<uint> hydrated = CellTransit.BuildShadowCellSet(
|
||||
cache,
|
||||
IndoorSeed,
|
||||
sphere,
|
||||
1,
|
||||
isStatic: false);
|
||||
|
||||
Assert.Contains(IndoorSeed, hydrated);
|
||||
Assert.Contains(hydrated, id => (id & 0xFFFFu) < 0x0100u);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OutdoorSeed_FloodsOverlappedLandcells_BlockCrossingMath()
|
||||
{
|
||||
|
|
@ -155,6 +250,7 @@ public class BuildShadowCellSetTests
|
|||
// vestibule's shadow_object_list at registration via
|
||||
// CLandCell::find_transit_cells → ... → check_building_transit.
|
||||
var cache = new PhysicsDataCache();
|
||||
RegisterFlatTerrain(cache);
|
||||
cache.RegisterCellStructForTest(NeighborCell, MakeLeafCell(Matrix4x4.Identity));
|
||||
|
||||
var sphere = One(new Vector3(12f, 12f, 0f), 0.5f);
|
||||
|
|
@ -188,6 +284,7 @@ public class BuildShadowCellSetTests
|
|||
// other_portal_id = -1 (wire 0xFFFF) never admits its interior cell
|
||||
// (CEnvCell::check_building_transit, 0x0052c5dc).
|
||||
var cache = new PhysicsDataCache();
|
||||
RegisterFlatTerrain(cache);
|
||||
cache.RegisterCellStructForTest(NeighborCell, MakeLeafCell(Matrix4x4.Identity));
|
||||
|
||||
var sphere = One(new Vector3(12f, 12f, 0f), 0.5f);
|
||||
|
|
@ -211,6 +308,63 @@ public class BuildShadowCellSetTests
|
|||
Assert.DoesNotContain(NeighborCell, set);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void UnavailableOutdoorSeed_AddsOutsideButSkipsTransit_UntilTerrainHydrates(
|
||||
bool useFlat)
|
||||
{
|
||||
var cache = new PhysicsDataCache
|
||||
{
|
||||
CollisionTraversalMode = useFlat
|
||||
? CollisionTraversalMode.Flat
|
||||
: CollisionTraversalMode.Graph,
|
||||
};
|
||||
cache.RegisterCellStructForTest(
|
||||
NeighborCell,
|
||||
MakeNullRootCell(Matrix4x4.Identity));
|
||||
|
||||
var sphere = One(new Vector3(12f, 12f, 0f), 0.5f);
|
||||
IReadOnlyList<uint> seeded = CellTransit.BuildShadowCellSet(
|
||||
cache,
|
||||
0xA9B40001u,
|
||||
sphere,
|
||||
1,
|
||||
isStatic: false);
|
||||
uint landcell = seeded[0];
|
||||
cache.RegisterBuildingForTest(landcell, new BuildingPhysics
|
||||
{
|
||||
WorldTransform = Matrix4x4.Identity,
|
||||
InverseWorldTransform = Matrix4x4.Identity,
|
||||
Portals =
|
||||
[
|
||||
new BldPortalInfo(NeighborCell, otherPortalId: 0, flags: 0),
|
||||
],
|
||||
});
|
||||
|
||||
IReadOnlyList<uint> unavailable = CellTransit.BuildShadowCellSet(
|
||||
cache,
|
||||
0xA9B40001u,
|
||||
sphere,
|
||||
1,
|
||||
isStatic: false);
|
||||
|
||||
Assert.NotEmpty(unavailable);
|
||||
Assert.All(unavailable, id => Assert.True((id & 0xFFFFu) < 0x0100u));
|
||||
Assert.DoesNotContain(NeighborCell, unavailable);
|
||||
|
||||
RegisterFlatTerrain(cache);
|
||||
IReadOnlyList<uint> hydrated = CellTransit.BuildShadowCellSet(
|
||||
cache,
|
||||
0xA9B40001u,
|
||||
sphere,
|
||||
1,
|
||||
isStatic: false);
|
||||
|
||||
Assert.Contains(landcell, hydrated);
|
||||
Assert.Contains(NeighborCell, hydrated);
|
||||
}
|
||||
|
||||
// ── Exterior straddle from an indoor seed ──────────────────────────
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue