diff --git a/src/AcDream.Core/Physics/PhysicsEngine.cs b/src/AcDream.Core/Physics/PhysicsEngine.cs index 108b9234..05354644 100644 --- a/src/AcDream.Core/Physics/PhysicsEngine.cs +++ b/src/AcDream.Core/Physics/PhysicsEngine.cs @@ -31,6 +31,15 @@ public sealed class PhysicsEngine /// Number of registered landblocks (diagnostic). public int LandblockCount => _landblocks.Count; + /// + /// Returns true iff a landblock with this id has been registered via + /// . Because registers + /// terrain + collision cells + portals atomically, ContainsKey implies the + /// collision mesh is present and resolvable. + /// + public bool IsLandblockLoaded(uint landblockId) => + _landblocks.ContainsKey(landblockId); + /// /// Cell-based spatial index for static object collision. /// Populated during landblock streaming; queried by the Transition system. diff --git a/tests/AcDream.Core.Tests/Physics/PhysicsEngineIsLandblockLoadedTests.cs b/tests/AcDream.Core.Tests/Physics/PhysicsEngineIsLandblockLoadedTests.cs new file mode 100644 index 00000000..727eeccf --- /dev/null +++ b/tests/AcDream.Core.Tests/Physics/PhysicsEngineIsLandblockLoadedTests.cs @@ -0,0 +1,57 @@ +using AcDream.Core.Physics; +using Xunit; + +namespace AcDream.Core.Tests.Physics; + +public class PhysicsEngineIsLandblockLoadedTests +{ + private static TerrainSurface MakeFlatTerrain() + { + var heights = new byte[81]; + Array.Fill(heights, (byte)50); + var heightTable = new float[256]; + for (int i = 0; i < 256; i++) heightTable[i] = i * 1f; + return new TerrainSurface(heights, heightTable); + } + + [Fact] + public void IsLandblockLoaded_AbsentId_ReturnsFalse() + { + var engine = new PhysicsEngine(); + Assert.False(engine.IsLandblockLoaded(0xA9B4FFFFu)); + } + + [Fact] + public void IsLandblockLoaded_AddedId_ReturnsTrue() + { + var engine = new PhysicsEngine(); + engine.AddLandblock(0xA9B4FFFFu, MakeFlatTerrain(), + Array.Empty(), Array.Empty(), + worldOffsetX: 0f, worldOffsetY: 0f); + + Assert.True(engine.IsLandblockLoaded(0xA9B4FFFFu)); + } + + [Fact] + public void IsLandblockLoaded_AnotherIdAbsent_ReturnsFalse() + { + var engine = new PhysicsEngine(); + engine.AddLandblock(0xA9B4FFFFu, MakeFlatTerrain(), + Array.Empty(), Array.Empty(), + worldOffsetX: 0f, worldOffsetY: 0f); + + Assert.False(engine.IsLandblockLoaded(0xDEADBEEFu)); + } + + [Fact] + public void IsLandblockLoaded_AfterRemove_ReturnsFalse() + { + var engine = new PhysicsEngine(); + engine.AddLandblock(0xA9B4FFFFu, MakeFlatTerrain(), + Array.Empty(), Array.Empty(), + worldOffsetX: 0f, worldOffsetY: 0f); + engine.RemoveLandblock(0xA9B4FFFFu); + + Assert.False(engine.IsLandblockLoaded(0xA9B4FFFFu)); + } +}