using AcDream.App.Streaming;
using AcDream.Core.Physics;
using AcDream.Core.World;
using AcDream.Runtime.World;
using DatReaderWriter.DBObjs;
namespace AcDream.App.Tests.Streaming;
///
/// #280 end-to-end: the derived reveal window, the tiered render predicate,
/// the terrain-residency gate, the destination reservation, and the loosened
/// Runtime shape invariant, wired together with the REAL
/// , , and
/// rather than fakes.
///
///
/// This is the test that fails if any single piece is missing: raising the
/// radius without the tier-aware predicate hangs forever (T2), and loosening
/// neither the Runtime invariant nor the predicate makes
/// AcknowledgeDestinationReadiness fail
/// invalid-readiness-shape (T1).
///
///
public sealed class WorldRevealDerivedWindowIntegrationTests
{
private const int CenterX = 0x40;
private const int CenterY = 0x40;
private const uint DestinationCell = (uint)CenterX << 24
| (uint)CenterY << 16
| 0x0021u;
[Theory]
[InlineData(1, 2)]
[InlineData(2, 4)]
public void OutdoorReveal_HoldsUntilTheWholeDerivedWindowIsPublished(
int nearRadius,
int farRadius)
{
var world = new GpuWorldState();
var physics = new PhysicsEngine();
var transit = new RuntimeWorldTransitState();
var streaming = new RecordingReservations();
StreamingController controller = CreateController(
world,
nearRadius,
farRadius);
WorldRevealCoordinator coordinator = CreateCoordinator(
transit,
controller,
physics,
streaming);
long generation = coordinator.BeginLogin(DestinationCell);
// The reservation opens on the same square the gate measures.
Assert.Equal(
(generation, DestinationCell, farRadius),
Assert.Single(streaming.Begins));
// Publish the Near window only. Pre-#280 this was the entire gate; it
// must no longer be enough.
for (int radius = 0; radius <= nearRadius; radius++)
PublishRing(world, physics, radius, LandblockStreamTier.Near);
Assert.False(coordinator.Evaluate(DestinationCell).IsReady);
// Fill the outer rings with Far-tier terrain publication, one ring at
// a time, so the hold is proven to track the outer boundary and not
// just the first missing member.
for (int radius = nearRadius + 1; radius < farRadius; radius++)
{
PublishRing(world, physics, radius, LandblockStreamTier.Far);
Assert.False(coordinator.Evaluate(DestinationCell).IsReady);
}
PublishRing(world, physics, farRadius, LandblockStreamTier.Far);
WorldRevealReadinessSnapshot ready =
coordinator.Evaluate(DestinationCell);
Assert.True(ready.IsReady);
Assert.Equal(farRadius, ready.RequiredRenderRadius);
Assert.Equal(nearRadius, ready.RequiredNearRadius);
// The loosened Runtime shape invariant accepted the derived radius.
Assert.Equal(0, transit.Snapshot.InvariantFailureCount);
Assert.True(transit.Snapshot.IsReady);
}
///
/// P7/ยง9-8: login and portal share the barrier, so first login gets the
/// same widened gate. Asserted through the production readiness predicate
/// the login auto-entry context calls.
///
[Fact]
public void LoginReveal_UsesTheSameWidenedGateAsPortalArrival()
{
const int nearRadius = 1;
const int farRadius = 3;
var world = new GpuWorldState();
var physics = new PhysicsEngine();
var transit = new RuntimeWorldTransitState();
StreamingController controller = CreateController(
world,
nearRadius,
farRadius);
WorldRevealCoordinator coordinator = CreateCoordinator(
transit,
controller,
physics,
streaming: null);
coordinator.BeginLogin(DestinationCell);
for (int radius = 0; radius < farRadius; radius++)
{
PublishRing(
world,
physics,
radius,
radius <= nearRadius
? LandblockStreamTier.Near
: LandblockStreamTier.Far);
}
Assert.False(coordinator.Evaluate(DestinationCell).IsReady);
PublishRing(world, physics, farRadius, LandblockStreamTier.Far);
Assert.True(coordinator.Evaluate(DestinationCell).IsReady);
Assert.Equal(0, transit.Snapshot.InvariantFailureCount);
}
///
/// Indoor destinations keep retail's EnvCell arm: no landscape ring at
/// all, regardless of how wide the streaming window is.
///
[Fact]
public void IndoorReveal_IgnoresTheStreamingWindowEntirely()
{
const uint indoorCell = (uint)CenterX << 24
| (uint)CenterY << 16
| 0x0100u;
var world = new GpuWorldState();
var physics = new PhysicsEngine();
var transit = new RuntimeWorldTransitState();
StreamingController controller = CreateController(world, 2, 6);
WorldRevealCoordinator coordinator = CreateCoordinator(
transit,
controller,
physics,
streaming: null);
coordinator.BeginLogin(indoorCell);
Assert.False(coordinator.Evaluate(indoorCell).IsReady);
// Only the destination's own landblock, at Near tier.
PublishRing(world, physics, 0, LandblockStreamTier.Near);
WorldRevealReadinessSnapshot snapshot = coordinator.Evaluate(indoorCell);
Assert.True(snapshot.IsRenderNeighborhoodReady);
Assert.Equal(0, snapshot.RequiredRenderRadius);
Assert.Equal(0, transit.Snapshot.InvariantFailureCount);
}
private sealed class RecordingReservations : IWorldRevealStreamingScheduler
{
public List<(long Generation, uint Cell, int Radius)> Begins { get; } = [];
public List Ends { get; } = [];
public void BeginDestinationReservation(
long revealGeneration,
uint destinationCell,
int requiredRenderRadius) =>
Begins.Add((revealGeneration, destinationCell, requiredRenderRadius));
public void EndDestinationReservation(long revealGeneration) =>
Ends.Add(revealGeneration);
}
private static WorldRevealCoordinator CreateCoordinator(
RuntimeWorldTransitState transit,
StreamingController controller,
PhysicsEngine physics,
IWorldRevealStreamingScheduler? streaming) =>
new(
transit,
() => new StreamingRevealWindow(
controller.NearRadius,
controller.FarRadius),
controller.IsRenderNeighborhoodResident,
physics.IsSpawnCellReady,
physics.IsNeighborhoodTerrainResident,
() => true,
(_, _) => { },
() => { },
_ => false,
streaming: streaming);
private static StreamingController CreateController(
GpuWorldState state,
int nearRadius,
int farRadius) =>
new(
(_, _, _) => { },
(_, _) => { },
_ => Array.Empty(),
(_, _) => { },
state,
nearRadius: nearRadius,
farRadius: farRadius);
private static void PublishRing(
GpuWorldState world,
PhysicsEngine physics,
int radius,
LandblockStreamTier tier)
{
for (int dx = -radius; dx <= radius; dx++)
for (int dy = -radius; dy <= radius; dy++)
{
if (Math.Abs(dx) != radius && Math.Abs(dy) != radius)
continue;
uint id = ((uint)(CenterX + dx) << 24)
| ((uint)(CenterY + dy) << 16)
| 0xFFFFu;
world.AddLandblock(
new LoadedLandblock(id, new LandBlock(), Array.Empty()),
tier: tier);
// The Far tier publishes terrain COLLISION as well as terrain
// render (LandblockPhysicsPublisher, reached for
// PublicationKind.Far), which is what makes the outer arm of the
// reveal gate satisfiable on the collision side too.
physics.AddLandblock(
id,
new TerrainSurface(new byte[81], new float[256]),
Array.Empty(),
Array.Empty(),
worldOffsetX: 0f,
worldOffsetY: 0f);
}
}
}