using AcDream.Core.Physics;
namespace AcDream.Core.Tests.Physics;
///
/// #280 (D6/P8). is
/// the collision half of the reveal gate and runs once per frame for the whole
/// duration of a hold. Before #280 that hold measured a 3x3 neighbourhood; it
/// now measures the streaming Far window (12 at the shipped High preset =
/// 625 members). Rebuilding a landblock-prefix HashSet per call would
/// allocate on every frame of every hold, against Slice I1's 0 B standard.
///
public sealed class NeighborhoodTerrainResidencyTests
{
private const int FarRadius = 12;
[Fact]
public void WarmedNeighborhoodQuery_AtTheFarRadius_AllocatesNothing()
{
PhysicsEngine engine = EngineWithWindow(0x80, 0x80, FarRadius);
uint center = Canonical(0x80, 0x80);
// Warm the JIT, the scratch set's buckets/entries arrays, and the
// dictionary enumerator before measuring.
for (int i = 0; i < 64; i++)
Assert.True(engine.IsNeighborhoodTerrainResident(center, FarRadius));
long before = GC.GetAllocatedBytesForCurrentThread();
for (int i = 0; i < 1_000; i++)
Assert.True(engine.IsNeighborhoodTerrainResident(center, FarRadius));
long allocated = GC.GetAllocatedBytesForCurrentThread() - before;
Assert.True(
allocated == 0,
$"1,000 radius-{FarRadius} residency queries allocated "
+ $"{allocated:N0} bytes");
}
[Fact]
public void NeighborhoodQuery_StillRejectsAMissingOuterRingMember()
{
PhysicsEngine engine = EngineWithWindow(0x80, 0x80, FarRadius);
uint center = Canonical(0x80, 0x80);
Assert.True(engine.IsNeighborhoodTerrainResident(center, FarRadius));
engine.RemoveLandblock(Canonical(0x80 + FarRadius, 0x80));
Assert.False(engine.IsNeighborhoodTerrainResident(center, FarRadius));
Assert.True(engine.IsNeighborhoodTerrainResident(center, FarRadius - 1));
}
///
/// The gate has always compared on the high 16 bits, so a landblock
/// registered under a cell-resolved id satisfies the same ring member as
/// one registered under the canonical sentinel. D6 replaced the per-call
/// set construction, not that masking rule.
///
[Fact]
public void NeighborhoodQuery_KeepsPrefixMaskedMembership()
{
var engine = new PhysicsEngine();
AddTerrain(engine, (0x40u << 24) | (0x40u << 16) | 0x0021u);
Assert.True(
engine.IsNeighborhoodTerrainResident(Canonical(0x40, 0x40), 0));
Assert.False(
engine.IsNeighborhoodTerrainResident(Canonical(0x41, 0x40), 0));
}
private static PhysicsEngine EngineWithWindow(int cx, int cy, int radius)
{
var engine = new PhysicsEngine();
for (int dx = -radius; dx <= radius; dx++)
for (int dy = -radius; dy <= radius; dy++)
AddTerrain(engine, Canonical(cx + dx, cy + dy));
return engine;
}
private static uint Canonical(int x, int y) =>
((uint)x << 24) | ((uint)y << 16) | 0xFFFFu;
private static void AddTerrain(PhysicsEngine engine, uint landblockId)
{
var heights = new byte[81];
var heightTable = new float[256];
engine.AddLandblock(
landblockId,
new TerrainSurface(heights, heightTable),
Array.Empty(),
Array.Empty(),
worldOffsetX: 0f,
worldOffsetY: 0f);
}
}