using System.Collections.Immutable; using System.Numerics; using AcDream.App.Rendering; using AcDream.App.Rendering.Wb; using AcDream.App.Streaming; using AcDream.App.World; using AcDream.Core.Terrain; using AcDream.Core.World; using DatReaderWriter.DBObjs; using Xunit; namespace AcDream.App.Tests.Streaming; public sealed class LandblockPresentationPipelineTests { [Fact] public void ControllerRejectsPresentationPipelineFromForeignWorldState() { var controllerState = new GpuWorldState(); var foreignState = new GpuWorldState(); var foreignPipeline = new LandblockPresentationPipeline( static (_, _) => { }, foreignState); Assert.Throws(() => new StreamingController( enqueueLoad: static (_, _, _) => { }, enqueueUnload: static (_, _) => { }, drainCompletions: static _ => Array.Empty(), controllerState, nearRadius: 0, farRadius: 0, presentationPipeline: foreignPipeline)); } [Fact] public void LegacyPipelineRejectsRetirementCoordinatorFromForeignWorldState() { var pipelineState = new GpuWorldState(); var foreignCoordinator = new LandblockRetirementCoordinator( new GpuWorldState(), static _ => { }); Assert.Throws(() => new LandblockPresentationPipeline( static (_, _) => { }, pipelineState, retirementCoordinator: foreignCoordinator)); } [Fact] public void PublicPresentationConstructorsExposeOnlyConcreteOwnerGraph() { string[] legacyNames = [ "applyTerrain", "removeTerrain", "demoteNearLayer", "onLandblockLoaded", "ensureEnvCellMeshes", "retirementCoordinator", ]; System.Reflection.ConstructorInfo controller = Assert.Single( typeof(StreamingController).GetConstructors()); Assert.Contains( controller.GetParameters(), parameter => parameter.Name == "presentationPipeline"); string[] names = controller.GetParameters() .Select(parameter => parameter.Name!) .ToArray(); Assert.DoesNotContain(names, legacyNames.Contains); System.Reflection.ConstructorInfo pipeline = Assert.Single( typeof(LandblockPresentationPipeline).GetConstructors()); Type[] pipelineParameterTypes = pipeline.GetParameters() .Select(parameter => parameter.ParameterType) .ToArray(); Assert.Contains(typeof(LandblockRenderPublisher), pipelineParameterTypes); Assert.Contains(typeof(LandblockPhysicsPublisher), pipelineParameterTypes); Assert.Contains(typeof(LandblockStaticPresentationPublisher), pipelineParameterTypes); Assert.DoesNotContain( pipeline.GetParameters(), parameter => parameter.Name == "publishBeforeSpatialCommit"); string[] coordinatorOnlyMethods = [ "BeginOriginRecenter", "IsOriginRecenterRetirementComplete", "TryCommitOriginRecenter", "TryCancelOriginRecenter", ]; foreach (string methodName in coordinatorOnlyMethods) { Assert.Null(typeof(StreamingController).GetMethod(methodName)); Assert.NotNull(typeof(StreamingController).GetMethod( methodName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)); } } [Fact] public void OriginRecenter_BlocksOriginAndBootstrapUntilEveryOldOwnerConverges() { const uint centerId = 0x1919FFFFu; const uint neighborId = 0x191AFFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( centerId, new LandBlock(), Array.Empty())); state.AddLandblock(new LoadedLandblock( neighborId, new LandBlock(), Array.Empty())); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x19, 0x19)); var enqueued = new List(); bool failNeighbor = true; int neighborAttempts = 0; var controller = new StreamingController( enqueueLoad: (id, _) => enqueued.Add(id), enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, removeTerrain: id => { if (id != neighborId) return; neighborAttempts++; if (failNeighbor) throw new InvalidOperationException("injected non-center failure"); }); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x22, 0x23, isSealedDungeon: false)); Assert.Equal((0x19, 0x19), (origin.CenterX, origin.CenterY)); Assert.False(state.IsLoaded(centerId)); Assert.False(state.IsLoaded(neighborId)); Assert.Equal(1, controller.PendingRetirementCount); Assert.Equal(2, controller.LastFullWindowRetirementLandblockCount); controller.Tick(0x19, 0x19); Assert.Empty(enqueued); Assert.True(neighborAttempts >= 2); failNeighbor = false; Assert.True(recenter.Advance()); Assert.Equal((0x22, 0x23), (origin.CenterX, origin.CenterY)); Assert.Equal(0, controller.PendingRetirementCount); controller.Tick(0x22, 0x23); Assert.Equal([0x2223FFFFu], enqueued); } [Fact] public void OriginRecenter_PreparationFailureBeforeDetachRetainsOldOriginAndResidents() { const uint landblockId = 0x3030FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( landblockId, new LandBlock(), Array.Empty())); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x30, 0x30)); bool failClear = true; int clearAttempts = 0; var controller = new StreamingController( enqueueLoad: static (_, _) => { }, enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, clearPendingLoads: () => { clearAttempts++; if (failClear) throw new InvalidOperationException("injected clear failure"); }); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x40, 0x41, isSealedDungeon: false)); Assert.Equal((0x30, 0x30), (origin.CenterX, origin.CenterY)); Assert.True(state.IsLoaded(landblockId)); Assert.Equal(0, controller.PendingRetirementCount); failClear = false; Assert.True(recenter.Advance()); Assert.Equal(2, clearAttempts); Assert.False(state.IsLoaded(landblockId)); Assert.Equal((0x40, 0x41), (origin.CenterX, origin.CenterY)); } [Fact] public void OriginRecenter_ObserverFailureHalfwayRetainsBarrierUntilSnapshotFinishes() { const uint firstId = 0x4242FFFFu; const uint secondId = 0x4243FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( firstId, new LandBlock(), Array.Empty())); state.AddLandblock(new LoadedLandblock( secondId, new LandBlock(), [Entity(2, serverGuid: 0x70000042u)])); int observerCalls = 0; state.LiveProjectionVisibilityChanged += (_, _) => { observerCalls++; throw new InvalidOperationException("injected observer failure"); }; var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x42, 0x42)); var removed = new List(); var controller = new StreamingController( enqueueLoad: static (_, _) => { }, enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, removeTerrain: id => removed.Add(id)); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x43, 0x44, isSealedDungeon: false)); Assert.Equal((0x42, 0x42), (origin.CenterX, origin.CenterY)); Assert.False(state.IsLoaded(firstId)); Assert.False(state.IsLoaded(secondId)); Assert.Equal(1, observerCalls); Assert.True(recenter.Advance()); Assert.Equal((0x43, 0x44), (origin.CenterX, origin.CenterY)); Assert.Equal([firstId, secondId], removed); } [Fact] public void OriginRecenter_RetryPreservesLiveIdentityAndDoesNotRescueReusedGuid() { const uint oldId = 0x4545FFFFu; const uint destinationId = 0x4646FFFFu; const uint playerGuid = 0x50000045u; const uint remoteGuid = 0x70000045u; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( oldId, new LandBlock(), Array.Empty())); WorldEntity player = Entity(10, playerGuid); WorldEntity remote = Entity(11, remoteGuid); state.MarkPersistent(playerGuid); state.PlaceLiveEntityProjection(oldId, player); state.PlaceLiveEntityProjection(oldId, remote); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x45, 0x45)); bool failRetirement = true; var controller = new StreamingController( enqueueLoad: static (_, _) => { }, enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, removeTerrain: _ => { if (failRetirement) throw new InvalidOperationException("injected live-owner retry"); }); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x46, 0x46, isSealedDungeon: false)); Assert.Same(player, Assert.Single(state.DrainRescued())); Assert.Equal(1, state.PendingLiveEntityCount); Assert.Empty(state.Entities); failRetirement = false; Assert.True(recenter.Advance()); Assert.Empty(state.DrainRescued()); state.AddLandblock(new LoadedLandblock( destinationId, new LandBlock(), Array.Empty())); state.RebucketLiveEntity(player, destinationId); Assert.Same(player, Assert.Single(state.Entities)); state.AddLandblock(new LoadedLandblock( oldId, new LandBlock(), Array.Empty())); Assert.Contains(state.Entities, entity => ReferenceEquals(entity, remote)); state.ForgetLiveEntity(playerGuid); WorldEntity replacement = Entity(12, playerGuid); state.MarkPersistent(playerGuid); state.PlaceLiveEntityProjection(destinationId, replacement); state.RemoveLandblock(destinationId); Assert.Same(replacement, Assert.Single(state.DrainRescued())); Assert.DoesNotContain(state.Entities, entity => ReferenceEquals(entity, player)); } [Fact] public void OriginRecenter_ResetWithoutReplacementConvergesAtCurrentOrigin() { const uint landblockId = 0x5050FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( landblockId, new LandBlock(), Array.Empty())); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x50, 0x50)); bool failRetirement = true; var controller = new StreamingController( enqueueLoad: static (_, _) => { }, enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, removeTerrain: _ => { if (failRetirement) throw new InvalidOperationException("injected retirement failure"); }); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x60, 0x60, isSealedDungeon: false)); recenter.Reset(); Assert.True(recenter.IsPending); failRetirement = false; Assert.True(recenter.Advance()); Assert.False(recenter.IsPending); Assert.Equal((0x50, 0x50), (origin.CenterX, origin.CenterY)); controller.Tick(0x50, 0x50); } [Fact] public void OriginRecenter_ResetBackToSealedSourceKeepsRadiusZeroMode() { const uint sourceId = 0x5252FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( sourceId, new LandBlock(), Array.Empty())); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x52, 0x52)); var enqueued = new List<(uint Id, LandblockStreamJobKind Kind)>(); bool failRetirement = true; var controller = new StreamingController( enqueueLoad: (id, kind) => enqueued.Add((id, kind)), enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 2, farRadius: 4, removeTerrain: _ => { if (failRetirement) throw new InvalidOperationException("injected retirement failure"); }); controller.PreCollapseToDungeon(0x52, 0x52); enqueued.Clear(); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x60, 0x60, isSealedDungeon: false)); recenter.Reset(); failRetirement = false; Assert.True(recenter.Advance()); Assert.Equal((0x52, 0x52), (origin.CenterX, origin.CenterY)); Assert.Equal([(sourceId, LandblockStreamJobKind.LoadNear)], enqueued); controller.Tick(0x52, 0x52, insideDungeon: true); Assert.Single(enqueued); } [Fact] public void OriginRecenter_SessionResetConvergesWithoutBootstrappingEndingWorld() { const uint sourceId = 0x5353FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( sourceId, new LandBlock(), Array.Empty())); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x53, 0x53)); var enqueued = new List(); bool failRetirement = true; var controller = new StreamingController( enqueueLoad: (id, _) => enqueued.Add(id), enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, removeTerrain: _ => { if (failRetirement) throw new InvalidOperationException("injected session reset failure"); }); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x54, 0x54, isSealedDungeon: true)); recenter.Reset(sessionEnding: true); failRetirement = false; Assert.True(recenter.Advance()); Assert.Empty(enqueued); Assert.Equal((0x53, 0x53), (origin.CenterX, origin.CenterY)); controller.Tick(0x53, 0x53); Assert.Equal([sourceId], enqueued); } [Fact] public void OriginRecenter_SessionResetCannotOverwriteNextSessionOrigin() { const uint sourceId = 0x5353FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( sourceId, new LandBlock(), Array.Empty())); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x53, 0x53)); bool failRetirement = true; var controller = new StreamingController( enqueueLoad: static (_, _) => { }, enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, removeTerrain: _ => { if (failRetirement) throw new InvalidOperationException("injected session reset failure"); }); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x54, 0x54, isSealedDungeon: true)); recenter.Reset(sessionEnding: true); origin.Reset(); Assert.True(origin.TryInitialize(0x61, 0x62)); failRetirement = false; Assert.True(recenter.Advance()); Assert.Equal((0x61, 0x62), (origin.CenterX, origin.CenterY)); } [Fact] public void OriginRecenter_CommittedPendingClearFailureDoesNotReplayClear() { var state = new GpuWorldState(); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x10, 0x10)); int clearAttempts = 0; var controller = new StreamingController( enqueueLoad: static (_, _) => { }, enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, clearPendingLoads: () => { clearAttempts++; throw new StreamingMutationException( "injected committed clear failure", mutationCommitted: true); }); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x11, 0x11, isSealedDungeon: false)); Assert.True(recenter.Advance()); Assert.Equal(1, clearAttempts); Assert.Equal((0x11, 0x11), (origin.CenterX, origin.CenterY)); } [Fact] public void OriginRecenter_ReentrantClearAndRetirementDoNotRecurseOrSkipResidents() { const uint firstId = 0x7070FFFFu; const uint secondId = 0x7071FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( firstId, new LandBlock(), Array.Empty())); state.AddLandblock(new LoadedLandblock( secondId, new LandBlock(), Array.Empty())); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x70, 0x70)); StreamingController? controller = null; int clearCalls = 0; var removed = new List(); controller = new StreamingController( enqueueLoad: static (_, _) => { }, enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, clearPendingLoads: () => { clearCalls++; Assert.False(controller!.IsOriginRecenterRetirementComplete()); }, removeTerrain: id => { removed.Add(id); if (id == firstId) Assert.False(controller!.IsOriginRecenterRetirementComplete()); }); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.True(recenter.Begin(0x71, 0x71, isSealedDungeon: false)); Assert.Equal(1, clearCalls); Assert.Equal([firstId, secondId], removed); Assert.False(state.IsLoaded(firstId)); Assert.False(state.IsLoaded(secondId)); } [Fact] public void OriginRecenter_DefersRadiusChangeUntilDestinationCommit() { const uint oldId = 0x7272FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( oldId, new LandBlock(), Array.Empty())); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x72, 0x72)); var enqueued = new List(); bool failRetirement = true; var controller = new StreamingController( enqueueLoad: (id, _) => enqueued.Add(id), enqueueUnload: static _ => { }, drainCompletions: static _ => Array.Empty(), applyTerrain: static (_, _) => { }, state, nearRadius: 0, farRadius: 0, removeTerrain: _ => { if (failRetirement) throw new InvalidOperationException("injected radius barrier failure"); }); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x73, 0x73, isSealedDungeon: false)); controller.ReconfigureRadii(nearRadius: 1, farRadius: 2); controller.Tick(0x72, 0x72); Assert.Equal(0, controller.NearRadius); Assert.Equal(0, controller.FarRadius); Assert.Empty(enqueued); failRetirement = false; Assert.True(recenter.Advance()); controller.Tick(0x73, 0x73); Assert.Equal(1, controller.NearRadius); Assert.Equal(2, controller.FarRadius); Assert.Equal(25, enqueued.Count); } [Fact] public void OriginRecenter_SealedDungeonPinsRadiusZeroBeforeCenterCompletion() { const uint oldId = 0x2020FFFFu; const uint dungeonId = 0x3030FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( oldId, new LandBlock(), Array.Empty())); var origin = new LiveWorldOriginState(); Assert.True(origin.TryInitialize(0x20, 0x20)); var outbox = new Queue(); var enqueued = new List<(uint Id, LandblockStreamJobKind Kind)>(); bool failDungeonEnqueue = true; int enqueueAttempts = 0; int publications = 0; var controller = new StreamingController( enqueueLoad: (id, kind) => { enqueueAttempts++; if (failDungeonEnqueue) throw new InvalidOperationException("injected dungeon enqueue failure"); enqueued.Add((id, kind)); }, enqueueUnload: static _ => { }, drainCompletions: max => Drain(outbox, max), applyTerrain: (_, _) => publications++, state, nearRadius: 2, farRadius: 4); var recenter = new StreamingOriginRecenterCoordinator(controller, origin); Assert.False(recenter.Begin(0x30, 0x30, isSealedDungeon: true)); Assert.True(recenter.IsPending); controller.Tick(0x30, 0x30, insideDungeon: true); Assert.Empty(enqueued); failDungeonEnqueue = false; Assert.True(recenter.Advance()); Assert.Equal(2, enqueueAttempts); Assert.Equal([(dungeonId, LandblockStreamJobKind.LoadNear)], enqueued); outbox.Enqueue(new LandblockStreamResult.Loaded( dungeonId, LandblockStreamTier.Near, new LoadedLandblock( dungeonId, new LandBlock(), Array.Empty()), EmptyMesh(), generation: 1)); controller.Tick(0x30, 0x30, insideDungeon: true); Assert.Equal(1, publications); Assert.True(state.IsNearTier(dungeonId)); } [Fact] public void Loaded_PreservesPresentationSpatialPinReplayAndLiveRecoveryOrder() { const uint landblockId = 0x2020FFFFu; var calls = new List(); var meshes = new RecordingMeshAdapter(calls); var state = new GpuWorldState(new LandblockSpawnAdapter(meshes)); LandblockBuild build = BuildWithShell(landblockId); var pipeline = new LandblockPresentationPipeline( publishBeforeSpatialCommit: (accepted, _) => { Assert.Same(build, accepted); Assert.False(state.IsLoaded(landblockId)); calls.Add("presentation"); }, state, onLandblockLoaded: id => { Assert.Equal(landblockId, id); Assert.True(state.IsLoaded(id)); calls.Add("live-recovery"); }, ensureEnvCellMeshes: envCells => { Assert.Same(build.EnvCells, envCells); Assert.True(state.IsLoaded(landblockId)); calls.Add("mesh-replay-after-pin"); }); pipeline.PublishLoaded(new LandblockStreamResult.Loaded( landblockId, LandblockStreamTier.Near, build, EmptyMesh())); Assert.Equal( ["presentation", "pin", "mesh-replay-after-pin", "live-recovery"], calls); Assert.True(state.IsNearTier(landblockId)); } [Fact] public void Promoted_ExistingFar_MergesNearLayerBeforeReplayAndRecovery() { const uint landblockId = 0x3030FFFFu; var calls = new List(); var meshes = new RecordingMeshAdapter(calls); var state = new GpuWorldState(new LandblockSpawnAdapter(meshes)); state.AddLandblock( new LoadedLandblock( landblockId, new LandBlock(), Array.Empty(), PhysicsDatBundle.Empty), tier: LandblockStreamTier.Far); LandblockBuild build = BuildWithShell(landblockId, Entity(7)); var pipeline = new LandblockPresentationPipeline( publishBeforeSpatialCommit: (_, _) => calls.Add("presentation"), state, onLandblockLoaded: _ => { Assert.True(state.IsNearTier(landblockId)); Assert.Contains(state.Entities, entity => entity.Id == 7); calls.Add("live-recovery"); }, ensureEnvCellMeshes: _ => { Assert.True(state.IsNearTier(landblockId)); Assert.Contains(state.Entities, entity => entity.Id == 7); calls.Add("mesh-replay-after-pin"); }); pipeline.PublishPromoted(new LandblockStreamResult.Promoted( landblockId, build, EmptyMesh()), mergeIntoExistingLandblock: true); Assert.Equal( ["presentation", "pin", "mesh-replay-after-pin", "live-recovery"], calls); } [Fact] public void PublishAsFar_StripsNearPayloadAndSkipsEnvCellReplay() { const uint landblockId = 0x4040FFFFu; var state = new GpuWorldState(); var origin = new LandblockBuildOrigin(0x40, 0x41); LandblockBuild source = BuildWithShell(landblockId, Entity(9)) with { Origin = origin, }; LandblockBuild? published = null; int replayCount = 0; int recoveryCount = 0; var pipeline = new LandblockPresentationPipeline( publishBeforeSpatialCommit: (build, _) => published = build, state, onLandblockLoaded: _ => recoveryCount++, ensureEnvCellMeshes: _ => replayCount++); var accepted = new LandblockStreamResult.Loaded( landblockId, LandblockStreamTier.Near, source, EmptyMesh()); pipeline.PublishAsFar(accepted, source, accepted.MeshData); Assert.NotNull(published); Assert.Empty(published.Landblock.Entities); Assert.Same(PhysicsDatBundle.Empty, published.Landblock.PhysicsDats); Assert.Null(published.EnvCells); Assert.Equal(origin, published.Origin); Assert.True(state.IsLoaded(landblockId)); Assert.False(state.IsNearTier(landblockId)); Assert.Equal(0, replayCount); Assert.Equal(1, recoveryCount); } [Fact] public void EnvCellReplayFailure_ResumesSuffixWithoutReplayingCommittedPrefix() { const uint landblockId = 0x5151FFFFu; var calls = new List(); var state = new GpuWorldState(new LandblockSpawnAdapter( new RecordingMeshAdapter(calls))); bool failReplayOnce = true; var pipeline = new LandblockPresentationPipeline( publishBeforeSpatialCommit: (_, _) => calls.Add("presentation"), state, onLandblockLoaded: _ => calls.Add("live-recovery"), ensureEnvCellMeshes: _ => { calls.Add("mesh-replay"); if (failReplayOnce) { failReplayOnce = false; throw new InvalidOperationException("injected replay failure"); } }); LandblockBuild build = BuildWithShell(landblockId); var result = new LandblockStreamResult.Loaded( landblockId, LandblockStreamTier.Near, build, EmptyMesh()); Assert.Throws(() => pipeline.PublishLoaded(result)); Assert.True(state.IsNearTier(landblockId)); Assert.True(pipeline.HasPendingPublication(result)); pipeline.PublishLoaded(result); Assert.Equal( ["presentation", "pin", "mesh-replay", "mesh-replay", "live-recovery"], calls); Assert.False(pipeline.HasPendingPublication(result)); } [Fact] public void PromotionReplayFailure_RetainsOriginalSelfContainedModeAcrossRetry() { const uint landblockId = 0x5252FFFFu; var calls = new List(); var state = new GpuWorldState(new LandblockSpawnAdapter( new RecordingMeshAdapter(calls))); bool failReplayOnce = true; var pipeline = new LandblockPresentationPipeline( publishBeforeSpatialCommit: (_, _) => calls.Add("presentation"), state, onLandblockLoaded: _ => calls.Add("live-recovery"), ensureEnvCellMeshes: _ => { calls.Add("mesh-replay"); if (failReplayOnce) { failReplayOnce = false; throw new InvalidOperationException("injected replay failure"); } }); LandblockBuild build = BuildWithShell(landblockId, Entity(17)); var result = new LandblockStreamResult.Promoted( landblockId, build, EmptyMesh()); Assert.Throws(() => pipeline.PublishPromoted( result, mergeIntoExistingLandblock: false)); Assert.True(state.IsNearTier(landblockId)); // Current residency changed after the first attempt. The transaction // must retain the original self-contained publication command rather // than switching policy mid-retry. pipeline.PublishPromoted(result, mergeIntoExistingLandblock: true); Assert.Equal( ["presentation", "pin", "mesh-replay", "mesh-replay", "live-recovery"], calls); Assert.Single(state.Entities, entity => entity.Id == 17); } [Fact] public void SpatialPinFailure_ControllerRetriesExactCompletionWithoutReplayingPresentation() { const uint landblockId = 0x6060FFFFu; var meshes = new FailFirstPreparedPinAdapter(); var state = new GpuWorldState(new LandblockSpawnAdapter(meshes)); var outbox = new Queue(); LandblockBuild build = BuildWithShell(landblockId); outbox.Enqueue(new LandblockStreamResult.Loaded( landblockId, LandblockStreamTier.Near, build, EmptyMesh())); int presentationCalls = 0; int replayCalls = 0; int liveRecoveryCalls = 0; var controller = new StreamingController( enqueueLoad: (_, _) => { }, enqueueUnload: _ => { }, drainCompletions: max => Drain(outbox, max), applyTerrain: (_, _) => presentationCalls++, state, nearRadius: 0, farRadius: 0, onLandblockLoaded: _ => liveRecoveryCalls++, ensureEnvCellMeshes: _ => replayCalls++); Assert.Throws(() => controller.Tick(0x60, 0x60)); Assert.True(state.IsNearTier(landblockId)); Assert.Equal(1, presentationCalls); Assert.Equal(0, replayCalls); Assert.Equal(0, liveRecoveryCalls); controller.Tick(0x60, 0x60); Assert.Equal(1, presentationCalls); Assert.Equal(2, meshes.PinAttempts); Assert.Equal(1, replayCalls); Assert.Equal(1, liveRecoveryCalls); } [Fact] public void PromotionPinFailure_RetriesActivationWithoutAppendingEntitiesAgain() { const uint landblockId = 0x6161FFFFu; var meshes = new FailFirstPreparedPinAdapter(); var state = new GpuWorldState(new LandblockSpawnAdapter(meshes)); state.AddLandblock( new LoadedLandblock( landblockId, new LandBlock(), Array.Empty()), tier: LandblockStreamTier.Far); int presentationCalls = 0; var pipeline = new LandblockPresentationPipeline( publishBeforeSpatialCommit: (_, _) => presentationCalls++, state); WorldEntity promotedEntity = Entity(31); LandblockBuild build = BuildWithShell(landblockId, promotedEntity); var result = new LandblockStreamResult.Promoted( landblockId, build, EmptyMesh()); Assert.Throws(() => pipeline.PublishPromoted( result, mergeIntoExistingLandblock: true)); Assert.Single(state.Entities, entity => ReferenceEquals(entity, promotedEntity)); pipeline.PublishPromoted(result, mergeIntoExistingLandblock: true); Assert.Equal(1, presentationCalls); Assert.Equal(2, meshes.PinAttempts); Assert.Single(state.Entities, entity => ReferenceEquals(entity, promotedEntity)); Assert.False(pipeline.HasPendingPublication(result)); } [Fact] public void LoadedPinFailure_RetryPreservesPendingLiveProjectionMergedAtSpatialCommit() { const uint landblockId = 0x6262FFFFu; var meshes = new FailFirstPreparedPinAdapter(); var state = new GpuWorldState(new LandblockSpawnAdapter(meshes)); var pendingLive = new WorldEntity { Id = 77, ServerGuid = 0x80000077u, SourceGfxObjOrSetupId = 0x01000077u, Position = Vector3.Zero, Rotation = Quaternion.Identity, MeshRefs = [new MeshRef(0x01000077u, Matrix4x4.Identity)], }; state.PlaceLiveEntityProjection(0x62620100u, pendingLive); LandblockBuild build = BuildWithShell(landblockId, Entity(32)); var result = new LandblockStreamResult.Loaded( landblockId, LandblockStreamTier.Near, build, EmptyMesh()); var pipeline = new LandblockPresentationPipeline( static (_, _) => { }, state); Assert.Throws(() => pipeline.PublishLoaded(result)); Assert.Contains(state.Entities, entity => ReferenceEquals(entity, pendingLive)); Assert.Equal(0, state.PendingLiveEntityCount); pipeline.PublishLoaded(result); Assert.Contains(state.Entities, entity => ReferenceEquals(entity, pendingLive)); Assert.Single(state.Entities, entity => ReferenceEquals(entity, pendingLive)); Assert.Equal(0, state.PendingLiveEntityCount); Assert.Equal(2, meshes.PinAttempts); } [Fact] public void PriorityFailure_PreservesFailingResultAndUntouchedDrainedSuffix() { const uint priorityId = 0x7070FFFFu; const uint laterId = 0x7071FFFFu; const uint unloadId = 0x1010FFFFu; var meshes = new FailFirstPreparedPinAdapter(); var state = new GpuWorldState(new LandblockSpawnAdapter(meshes)); state.AddLandblock(new LoadedLandblock( unloadId, new LandBlock(), Array.Empty())); var outbox = new Queue( [ new LandblockStreamResult.Loaded( priorityId, LandblockStreamTier.Near, BuildWithShell(priorityId), EmptyMesh()), new LandblockStreamResult.Loaded( laterId, LandblockStreamTier.Near, BuildWithShell(laterId), EmptyMesh()), new LandblockStreamResult.Unloaded(unloadId), ]); var calls = new List(); var controller = new StreamingController( enqueueLoad: (_, _) => { }, enqueueUnload: _ => { }, drainCompletions: max => Drain(outbox, max), applyTerrain: (build, _) => calls.Add($"publish:{build.LandblockId:X8}"), state, nearRadius: 0, farRadius: 2, removeTerrain: id => calls.Add($"unload:{id:X8}")); controller.PriorityLandblockId = priorityId; Assert.Throws(() => controller.Tick(0x70, 0x70)); Assert.Empty(outbox); Assert.False(state.IsLoaded(laterId)); Assert.True(state.IsLoaded(unloadId)); controller.PriorityLandblockId = 0; controller.Tick(0x70, 0x70); Assert.True(state.IsLoaded(priorityId)); Assert.True(state.IsLoaded(laterId)); Assert.False(state.IsLoaded(unloadId)); Assert.Equal( [ $"publish:{priorityId:X8}", $"publish:{laterId:X8}", $"unload:{unloadId:X8}", ], calls); } [Fact] public void HardRecenter_ConvergesPendingSpatialPublicationBeforeRetiringIt() { const uint landblockId = 0x8080FFFFu; var meshes = new FailFirstPreparedPinAdapter(); var state = new GpuWorldState(new LandblockSpawnAdapter(meshes)); var outbox = new Queue(); var result = new LandblockStreamResult.Loaded( landblockId, LandblockStreamTier.Near, BuildWithShell(landblockId), EmptyMesh()); outbox.Enqueue(result); int presentationCalls = 0; int replayCalls = 0; int recoveryCalls = 0; var controller = new StreamingController( enqueueLoad: (_, _) => { }, enqueueUnload: _ => { }, drainCompletions: max => Drain(outbox, max), applyTerrain: (_, _) => presentationCalls++, state, nearRadius: 0, farRadius: 0, onLandblockLoaded: _ => recoveryCalls++, ensureEnvCellMeshes: _ => replayCalls++); Assert.Throws(() => controller.Tick(0x80, 0x80)); Assert.True(state.IsNearTier(landblockId)); controller.ForceReloadWindow(); Assert.False(state.IsLoaded(landblockId)); Assert.Equal(1, presentationCalls); Assert.Equal(1, replayCalls); Assert.Equal(1, recoveryCalls); Assert.Equal(2, meshes.PinAttempts); } [Fact] public void DesiredNearToFarChurn_ResumesOriginalPublicationThenDemotes() { const uint landblockId = 0x9090FFFFu; var calls = new List(); var state = new GpuWorldState(new LandblockSpawnAdapter( new RecordingMeshAdapter(calls))); var outbox = new Queue(); var result = new LandblockStreamResult.Loaded( landblockId, LandblockStreamTier.Near, BuildWithShell(landblockId, Entity(23)), EmptyMesh()); outbox.Enqueue(result); bool failReplayOnce = true; var controller = new StreamingController( enqueueLoad: (_, _) => { }, enqueueUnload: _ => { }, drainCompletions: max => Drain(outbox, max), applyTerrain: (_, _) => calls.Add("presentation"), state, nearRadius: 0, farRadius: 2, demoteNearLayer: _ => calls.Add("demote"), ensureEnvCellMeshes: _ => { calls.Add("mesh-replay"); if (failReplayOnce) { failReplayOnce = false; throw new InvalidOperationException("injected replay failure"); } }); Assert.Throws(() => controller.Tick(0x90, 0x90)); Assert.True(state.IsNearTier(landblockId)); controller.Tick(0x90, 0x93); Assert.True(state.IsLoaded(landblockId)); Assert.False(state.IsNearTier(landblockId)); Assert.DoesNotContain(state.Entities, entity => entity.Id == 23); Assert.Equal(1, calls.Count(call => call == "presentation")); Assert.Equal(2, calls.Count(call => call == "mesh-replay")); Assert.Contains("demote", calls); } [Fact] public void CoarsePresentationFailure_IsFailFastAndNotRetainedForAutomaticReplay() { const uint landblockId = 0xA0A0FFFFu; var state = new GpuWorldState(); int presentationCalls = 0; var pipeline = new LandblockPresentationPipeline( publishBeforeSpatialCommit: (_, _) => { presentationCalls++; throw new StreamingMutationException( "injected committed coarse failure", mutationCommitted: true); }, state); var result = new LandblockStreamResult.Loaded( landblockId, LandblockStreamTier.Near, BuildWithShell(landblockId), EmptyMesh()); Assert.Throws(() => pipeline.PublishLoaded(result)); Assert.Equal(1, presentationCalls); Assert.False(pipeline.HasPendingPublication(result)); Assert.Equal(0, pipeline.PendingPublicationCount); Assert.False(state.IsLoaded(landblockId)); } [Fact] public void DeferredCommittedPresentationFailure_DropsOnlyFailedResultAndPreservesTail() { const uint failedId = 0xB0B0FFFFu; const uint tailId = 0xB0B1FFFFu; var outbox = new Queue( [ new LandblockStreamResult.Loaded( failedId, LandblockStreamTier.Near, new LandblockBuild(new LoadedLandblock( failedId, new LandBlock(), Array.Empty())), EmptyMesh()), new LandblockStreamResult.Loaded( tailId, LandblockStreamTier.Near, new LandblockBuild(new LoadedLandblock( tailId, new LandBlock(), Array.Empty())), EmptyMesh()), ]); int failedCalls = 0; int tailCalls = 0; var state = new GpuWorldState(); var controller = new StreamingController( enqueueLoad: (_, _) => { }, enqueueUnload: _ => { }, drainCompletions: max => Drain(outbox, max), applyTerrain: (build, _) => { if (build.LandblockId == failedId) { failedCalls++; throw new StreamingMutationException( "injected committed presentation failure", mutationCommitted: true); } tailCalls++; }, state, nearRadius: 0, farRadius: 2); Assert.Throws(() => controller.Tick(0xB0, 0xB0)); Assert.Equal(1, failedCalls); Assert.Equal(0, tailCalls); Assert.Equal(1, controller.DeferredApplyBacklog); controller.Tick(0xB0, 0xB0); Assert.Equal(1, failedCalls); Assert.Equal(1, tailCalls); Assert.False(state.IsLoaded(failedId)); Assert.True(state.IsLoaded(tailId)); Assert.Equal(0, controller.DeferredApplyBacklog); } [Fact] public void RetirementFacade_DetachesFirstAndReportsPendingLedger() { const uint landblockId = 0x5050FFFFu; var state = new GpuWorldState(); state.AddLandblock(new LoadedLandblock( landblockId, new LandBlock(), Array.Empty())); bool failOnce = true; var retirements = new LandblockRetirementCoordinator( state, ticket => { ticket.RunOnce( LandblockRetirementStage.EntityLighting, () => { if (failOnce) { failOnce = false; throw new InvalidOperationException("injected failure"); } }); }, _ => LandblockRetirementStage.EntityLighting); var pipeline = new LandblockPresentationPipeline( static (_, _) => { }, state, retirementCoordinator: retirements); pipeline.BeginFullRetirement(landblockId); Assert.False(state.IsLoaded(landblockId)); Assert.True(pipeline.IsRetirementPending(landblockId)); Assert.Equal(1, pipeline.PendingRetirementCount); pipeline.AdvanceRetirements(); Assert.False(pipeline.IsRetirementPending(landblockId)); Assert.Equal(0, pipeline.PendingRetirementCount); } [Fact] public void Pipeline_DoesNotOwnStreamingPolicyOrLiveIdentityMaps() { string[] forbiddenFragments = [ "generation", "desiredtier", "streamingregion", "serverguid", "liveentity", ]; string[] fields = typeof(LandblockPresentationPipeline) .GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) .Select(field => $"{field.Name}:{field.FieldType.FullName}") .ToArray(); foreach (string field in fields) foreach (string forbidden in forbiddenFragments) Assert.DoesNotContain(forbidden, field, StringComparison.OrdinalIgnoreCase); } private static LandblockBuild BuildWithShell( uint landblockId, params WorldEntity[] entities) { uint cellId = (landblockId & 0xFFFF0000u) | 0x0100u; var shell = new EnvCellShellPlacement( cellId, 0x2_0000_0001UL, 0x0D000001u, 1, ImmutableArray.Empty, Vector3.Zero, Quaternion.Identity, Matrix4x4.Identity, new WbBoundingBox(Vector3.Zero, Vector3.One), new WbBoundingBox(Vector3.Zero, Vector3.One)); var envCells = new EnvCellLandblockBuild( landblockId, Array.Empty(), [shell]); return new LandblockBuild( new LoadedLandblock( landblockId, new LandBlock(), entities, PhysicsDatBundle.Empty), envCells); } private static WorldEntity Entity(uint id, uint serverGuid = 0) => new() { Id = id, ServerGuid = serverGuid, SourceGfxObjOrSetupId = 0x01000000u + id, Position = Vector3.Zero, Rotation = Quaternion.Identity, MeshRefs = Array.Empty(), }; private static LandblockMeshData EmptyMesh() => new( Array.Empty(), Array.Empty()); private static IReadOnlyList Drain( Queue queue, int max) { var drained = new List(max); while (drained.Count < max && queue.TryDequeue(out LandblockStreamResult? result)) drained.Add(result); return drained; } private sealed class RecordingMeshAdapter(List calls) : IWbMeshAdapter { public void IncrementRefCount(ulong id) { } public void PinPreparedRenderData(ulong id) => calls.Add("pin"); public void DecrementRefCount(ulong id) { } } private sealed class FailFirstPreparedPinAdapter : IWbMeshAdapter { public int PinAttempts { get; private set; } public void IncrementRefCount(ulong id) { } public void PinPreparedRenderData(ulong id) { PinAttempts++; if (PinAttempts == 1) throw new InvalidOperationException("injected pin failure"); } public void DecrementRefCount(ulong id) { } } }