using System.Reflection; using AcDream.App.Rendering; using AcDream.App.Update; using AcDream.App.World; namespace AcDream.App.Tests.World; public sealed class UpdateFrameOrchestratorTests { [Fact] public void Tick_PreservesTheCompleteAcceptedPhaseGraph() { var calls = new List(); UpdateFrameOrchestrator frame = Create(calls); frame.Tick(new UpdateFrameInput(1.0 / 60.0)); Assert.Equal( [ "teardown", "clock", "streaming", "input", "objects", "network", "commands", "ordinary-reconcile", "liveness", "teleport", "auto-entry", "camera", ], calls); } [Fact] public void ConditionalReconciles_RemainAtTheirOwningEdges() { // The outer ownership oracle is complemented by the production // teleport and camera tests that pin both conditional reconcile edges. var calls = new List(); UpdateFrameOrchestrator frame = Create( calls, teleportPlace: true, inboundCreatedPlayer: true); frame.Tick(new UpdateFrameInput(1.0 / 60.0)); Assert.Equal( [ "teardown", "clock", "streaming", "input", "objects", "network", "commands", "ordinary-reconcile", "liveness", "teleport-place", "teleport-reconcile", "teleport-reveal", "auto-entry", "inbound-player-projection", "inbound-player-reconcile", "camera", ], calls); } [Theory] [InlineData(double.NaN)] [InlineData(double.NegativeInfinity)] [InlineData(double.PositiveInfinity)] [InlineData(-1.0)] [InlineData(0.0)] [InlineData(double.MaxValue)] public void InvalidSimulationDelta_BecomesZeroWithoutSuppressingOuterPhases( double hostDelta) { var calls = new List(); var observed = new FrameObservations(); UpdateFrameOrchestrator frame = Create(calls, observed: observed); frame.Tick(new UpdateFrameInput(hostDelta)); Assert.Equal( [ "teardown", "clock", "streaming", "input", "objects", "network", "commands", "ordinary-reconcile", "liveness", "teleport", "auto-entry", "camera", ], calls); Assert.Equal([0.0], observed.PublishedTimes); Assert.Equal([0.0], observed.Input.Select(value => value.SimulationDeltaSeconds)); Assert.Equal([0f], observed.LiveDeltas); Assert.Equal([0f], observed.TeleportDeltas); Assert.Equal([0.0], observed.Camera.Select(value => value.SimulationDeltaSeconds)); Assert.All( observed.Input.Concat(observed.Camera), timing => Assert.Equal(0.0, timing.ScriptTime)); } [Fact] public void Clock_AdvancesOnceAndPublishesTheSameTimeToEveryConsumer() { var calls = new List(); var observed = new FrameObservations(); UpdateFrameOrchestrator frame = Create(calls, observed: observed); frame.Tick(new UpdateFrameInput(0.25)); frame.Tick(new UpdateFrameInput(double.NaN)); frame.Tick(new UpdateFrameInput(0.5)); Assert.Equal([0.25, 0.25, 0.75], observed.PublishedTimes); Assert.Equal( [0.25, 0.25, 0.75], observed.Input.Select(value => value.ScriptTime)); Assert.Equal( [0.25, 0.25, 0.75], observed.Camera.Select(value => value.ScriptTime)); Assert.Equal([0.25f, 0f, 0.5f], observed.LiveDeltas); Assert.Equal([0.25f, 0f, 0.5f], observed.TeleportDeltas); Assert.Equal( [0.25, 0.0, 0.5], observed.Input.Select(value => value.SimulationDeltaSeconds)); Assert.Equal( [0.25, 0.0, 0.5], observed.Camera.Select(value => value.SimulationDeltaSeconds)); } [Fact] public void Clock_RejectsFiniteDeltaAboveTheSinglePrecisionConsumerRange() { double tooLarge = (double)float.MaxValue * 2.0; Assert.True(double.IsFinite(tooLarge)); Assert.Equal(0.0, UpdateFrameClock.NormalizeDeltaSeconds(tooLarge)); } [Fact] public void AggregateTeardownFailure_IsReportedAndRetriedNextFrame() { var calls = new List(); var teardown = new RecordingTeardown(calls) { Failure = new AggregateException(new InvalidOperationException("transient")), }; var failures = new RecordingFailureSink(); UpdateFrameOrchestrator frame = Create( calls, teardown: teardown, failureSink: failures); frame.Tick(new UpdateFrameInput(0.1)); teardown.Failure = null; frame.Tick(new UpdateFrameInput(0.1)); Assert.Equal(2, teardown.Attempts); Assert.Single(failures.Errors); string[] oneFrame = [ "teardown", "clock", "streaming", "input", "objects", "network", "commands", "ordinary-reconcile", "liveness", "teleport", "auto-entry", "camera", ]; Assert.Equal(oneFrame.Concat(oneFrame), calls); } [Fact] public void NonAggregateTeardownFailure_PropagatesBeforeTimeOrLaterPhases() { var calls = new List(); var teardown = new RecordingTeardown(calls) { Failure = new InvalidOperationException("fatal"), }; UpdateFrameOrchestrator frame = Create(calls, teardown: teardown); InvalidOperationException error = Assert.Throws( () => frame.Tick(new UpdateFrameInput(0.1))); Assert.Equal("fatal", error.Message); Assert.Equal(["teardown"], calls); } [Fact] public void OrchestrationTypes_UseOnlyTheExplicitTypedOwnerGraph() { Type[] expectedFieldTypes = [ typeof(IUpdateFrameTeardownPhase), typeof(IUpdateFrameFailureSink), typeof(UpdateFrameClock), typeof(IUpdateFrameScriptClockPublisher), typeof(IStreamingFramePhase), typeof(IGameplayInputFramePhase), typeof(IRetailLiveFramePhase), typeof(ILiveEntityLivenessFramePhase), typeof(ILocalPlayerTeleportFramePhase), typeof(IPlayerModeAutoEntryFramePhase), typeof(ICameraFramePhase), ]; FieldInfo[] fields = typeof(UpdateFrameOrchestrator).GetFields( BindingFlags.Instance | BindingFlags.NonPublic); Assert.Equal( expectedFieldTypes.OrderBy(type => type.FullName), fields.Select(field => field.FieldType).OrderBy(type => type.FullName)); Assert.All(fields, field => { Assert.NotEqual(typeof(GameWindow), field.FieldType); Assert.False(typeof(Delegate).IsAssignableFrom(field.FieldType)); }); Type[] phaseInterfaces = expectedFieldTypes.Where(type => type.IsInterface).ToArray(); Assert.DoesNotContain( phaseInterfaces, phaseInterface => phaseInterface.IsAssignableFrom(typeof(GameWindow))); Type[] productionPhaseOwners = typeof(GameWindow).Assembly.GetTypes() .Where(type => !type.IsAbstract && !type.IsInterface) .Where(type => phaseInterfaces.Any(contract => contract.IsAssignableFrom(type))) .ToArray(); foreach (Type owner in productionPhaseOwners) { FieldInfo[] ownerFields = owner.GetFields( BindingFlags.Instance | BindingFlags.NonPublic); Assert.DoesNotContain(ownerFields, field => field.FieldType == typeof(GameWindow)); Assert.DoesNotContain( ownerFields, field => typeof(Delegate).IsAssignableFrom(field.FieldType)); } Assert.DoesNotContain( typeof(GameWindow).GetFields(BindingFlags.Instance | BindingFlags.NonPublic), field => field.Name == "_physicsScriptGameTime"); } [Fact] public void PhysicsScriptClockConsumers_RetainTheTypedSourceNotGameWindowClosures() { Type[] consumers = [ typeof(DatLiveEntityProjectionMaterializer), typeof(AcDream.App.Physics.LiveEntityNetworkUpdateController), ]; foreach (Type consumer in consumers) { FieldInfo clock = Assert.Single( consumer.GetFields(BindingFlags.Instance | BindingFlags.NonPublic), field => field.Name == "_gameTime"); Assert.Equal(typeof(IPhysicsScriptTimeSource), clock.FieldType); Assert.DoesNotContain( consumer.GetFields(BindingFlags.Instance | BindingFlags.NonPublic), field => field.FieldType == typeof(GameWindow)); } Assert.False(typeof(IPhysicsScriptTimeSource).IsAssignableFrom(typeof(GameWindow))); } [Fact] public void ProductionFrame_PublishesPhysicsScriptTimeExactlyOnce() { string root = FindRepoRoot(); string source = File.ReadAllText(Path.Combine( root, "src", "AcDream.App", "Rendering", "GameWindow.cs")); string adapters = File.ReadAllText(Path.Combine( root, "src", "AcDream.App", "Update", "UpdateFrameRuntimeAdapters.cs")); Assert.Equal(0, CountOccurrences(source, "PublishTime(")); Assert.Equal(1, CountOccurrences(adapters, "_runner.PublishTime(")); Assert.Contains("new AcDream.App.Update.PhysicsScriptClockPublisher(", source, StringComparison.Ordinal); } [Fact] public void ExtractedLiveObjectSource_PinsRetailAndRegisteredAdaptationOrder() { string source = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Update", "LiveObjectFrameController.cs")); AssertAppearsInOrder( source, "_localPlayerFrame.AdvanceBeforeNetwork", "_selectionInteractions?.DrainOutbound", "_animations.Tick", "_staticAnimations.Tick", "_animationPresenter.Present", "_equippedChildren.Tick", "_staticAnimations.ProcessHooks", "_effects.Tick"); AssertAppearsInOrder( source, "_translucencyFades.AdvanceAll", "_animationHooks.Drain", "_entityEffects.RefreshLiveOwnerPoses", "_particleSink.RefreshAttachedEmitters", "_lights.Refresh", "_particleVisibility.Apply", "_particles.Tick", "_scripts.Tick"); AssertAppearsInOrder( source, "public void Reconcile()", "_entityEffects.RefreshLiveOwnerPoses", "_equippedChildren.Tick", "_particleSink.RefreshAttachedEmitters", "_lights.Refresh"); Assert.Equal(1, CountOccurrences(source, "_staticAnimations.Tick(")); Assert.Equal(1, CountOccurrences(source, "_staticAnimations.ProcessHooks(")); Assert.Equal(1, CountOccurrences(source, "_effects.Tick(")); Assert.Equal(1, CountOccurrences(source, "_particles.Tick(")); Assert.Equal(1, CountOccurrences(source, "_scripts.Tick(")); } [Fact] public void GameWindow_ComposesTheLiveFrameOwnersWithoutOwningTheirBodies() { string source = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Rendering", "GameWindow.cs")); string livePresentation = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Composition", "LivePresentationComposition.cs")); string sessionPlayer = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Composition", "SessionPlayerComposition.cs")); Assert.Contains("new LiveObjectFrameController(", sessionPlayer); Assert.Contains("new LiveSpatialPresentationReconciler(", sessionPlayer); Assert.Contains("new AcDream.App.World.RetailLiveFrameCoordinator(", source); Assert.DoesNotContain("AdvanceLiveObjectRuntime", source, StringComparison.Ordinal); Assert.DoesNotContain("ReconcileLiveObjectSpatialPresentation", source, StringComparison.Ordinal); Assert.DoesNotContain("ILiveAnimationPresentationContext", source, StringComparison.Ordinal); } [Fact] public void GameWindow_DelegatesTheCompleteStreamingFrameBody() { string source = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Rendering", "GameWindow.cs")); string sessionPlayer = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Composition", "SessionPlayerComposition.cs")); Assert.Contains("new StreamingFrameController(", sessionPlayer); Assert.DoesNotContain("_streamingFrame", source, StringComparison.Ordinal); Assert.Equal(1, CountOccurrences( source, "_frameGraphs.Tick(")); Assert.DoesNotContain("_streamingController.Tick(observerCx", source, StringComparison.Ordinal); Assert.DoesNotContain("DungeonStreamingGate.Compute", source, StringComparison.Ordinal); Assert.DoesNotContain("DrainRescued()", source, StringComparison.Ordinal); } [Fact] public void GameWindow_DelegatesTheCompleteGameplayInputFrameBody() { string source = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Rendering", "GameWindow.cs")); string sessionPlayer = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Composition", "SessionPlayerComposition.cs")); Assert.Contains("new GameplayInputFrameController(", sessionPlayer); Assert.DoesNotContain("_gameplayInputFrame!.Tick", source, StringComparison.Ordinal); Assert.DoesNotContain("_inputDispatcher?.Tick()", source, StringComparison.Ordinal); Assert.DoesNotContain("TryTakeRawSample", source, StringComparison.Ordinal); Assert.DoesNotContain("_combatAttackController?.Tick()", source, StringComparison.Ordinal); Assert.DoesNotContain("CaptureMovementInput", source, StringComparison.Ordinal); Assert.DoesNotContain("EndMouseLookAndRestoreCursor", source, StringComparison.Ordinal); Assert.DoesNotContain("HideCursorForMouseLook", source, StringComparison.Ordinal); Assert.DoesNotContain("RestoreCursorAfterMouseLook", source, StringComparison.Ordinal); Assert.DoesNotContain("CanStartLiveCombatAttack", source, StringComparison.Ordinal); Assert.DoesNotContain("SendLiveCombatAttack", source, StringComparison.Ordinal); Assert.DoesNotContain("PreparePlayerForAttackRequest", source, StringComparison.Ordinal); Assert.DoesNotContain("DumpMovementTruthOutbound", source, StringComparison.Ordinal); Assert.DoesNotContain("DumpMovementTruthServerEcho", source, StringComparison.Ordinal); Assert.DoesNotContain("wantCaptureMouse: ()", source, StringComparison.Ordinal); Assert.DoesNotContain( "_gameplayInputFrame?.EndMouseLook", source, StringComparison.Ordinal); string pointerSource = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Input", "CameraPointerInputController.cs")); Assert.Contains("_gameplayFrame?.EndMouseLook();", pointerSource, StringComparison.Ordinal); string teleportSource = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Streaming", "LocalPlayerTeleportController.cs")); AssertAppearsInOrder( teleportSource, "_transit.CanBegin(teleportSequence)", "_input.EndMouseLook();", "_transit.QueueStart(teleportSequence)"); string playerModeSource = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Input", "PlayerModeController.cs")); Assert.Contains("_input.EndMouseLook();", playerModeSource, StringComparison.Ordinal); AssertAppearsInOrder( source, "private void OnFocusChanged(bool focused)", "_cameraPointerInput?.HandleFocusChanged(focused);"); } [Fact] public void GameWindow_DelegatesTheCompleteLocalTeleportLifetime() { string root = FindRepoRoot(); string source = File.ReadAllText(Path.Combine( root, "src", "AcDream.App", "Rendering", "GameWindow.cs")); string networkSource = File.ReadAllText(Path.Combine( root, "src", "AcDream.App", "Physics", "LiveEntityNetworkUpdateController.cs")); string sessionPlayer = File.ReadAllText(Path.Combine( root, "src", "AcDream.App", "Composition", "SessionPlayerComposition.cs")); Assert.Contains( "new LocalPlayerTeleportController(", sessionPlayer, StringComparison.Ordinal); Assert.DoesNotContain("_localPlayerTeleport!.Tick", source, StringComparison.Ordinal); Assert.DoesNotContain("_teleportTransit", source, StringComparison.Ordinal); Assert.DoesNotContain("_teleportAnim", source, StringComparison.Ordinal); Assert.DoesNotContain("_teleportViewPlane", source, StringComparison.Ordinal); Assert.DoesNotContain("_pendingTeleport", source, StringComparison.Ordinal); Assert.DoesNotContain("AimTeleportDestination", source, StringComparison.Ordinal); Assert.DoesNotContain("ResetTeleportTransitState", source, StringComparison.Ordinal); Assert.DoesNotContain("PlaceTeleportArrival", source, StringComparison.Ordinal); Assert.DoesNotContain("TryActivatePendingTeleportPresentation", source, StringComparison.Ordinal); Assert.DoesNotContain("Action", networkSource, StringComparison.Ordinal); Assert.Contains("ILocalPlayerTeleportNetworkSink", networkSource, StringComparison.Ordinal); AssertAppearsInOrder( source, "new AcDream.App.Update.LiveEntityLivenessFramePhase(", "sessionPlayer.LocalTeleport,", "new AcDream.App.Update.PlayerModeAutoEntryFramePhase(", "cameraFrame);"); } [Fact] public void GameplayInputOwnersUseTypedSeamsWithoutGameWindowBackReferences() { Type[] owners = [ typeof(AcDream.App.Input.GameplayInputFrameController), typeof(AcDream.App.Input.DispatcherMovementInputSource), typeof(AcDream.App.Input.MouseLookController), ]; foreach (Type owner in owners) { FieldInfo[] fields = owner.GetFields( BindingFlags.Instance | BindingFlags.NonPublic); Assert.DoesNotContain(fields, field => field.FieldType == typeof(GameWindow)); Assert.DoesNotContain( fields, field => typeof(Delegate).IsAssignableFrom(field.FieldType)); } Assert.DoesNotContain( typeof(AcDream.App.Input.MouseLookController).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => field.FieldType == typeof(Silk.NET.Input.IMouse)); FieldInfo combatOperations = Assert.Single( typeof(AcDream.App.Combat.CombatAttackController).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => field.Name == "_operations"); Assert.Equal( typeof(AcDream.App.Combat.ICombatAttackOperations), combatOperations.FieldType); Assert.DoesNotContain( typeof(AcDream.App.Combat.LiveCombatAttackOperations).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => typeof(Delegate).IsAssignableFrom(field.FieldType)); FieldInfo combatTargets = Assert.Single( typeof(AcDream.App.Combat.LiveCombatAttackOperations).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => field.Name == "_targets"); Assert.Equal( typeof(AcDream.App.Combat.ICombatAttackTargetSource), combatTargets.FieldType); Assert.DoesNotContain( typeof(AcDream.App.Combat.CombatAttackTargetSource).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => typeof(Delegate).IsAssignableFrom(field.FieldType)); Assert.DoesNotContain( typeof(AcDream.App.Combat.CombatAttackTargetSource).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => field.FieldType == typeof(AcDream.App.Interaction.SelectionInteractionController)); FieldInfo outboundDiagnostics = Assert.Single( typeof(AcDream.App.Input.LocalPlayerOutboundController).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => field.Name == "_diagnostic"); Assert.Equal( typeof(AcDream.App.Input.IMovementTruthDiagnosticSink), outboundDiagnostics.FieldType); Assert.DoesNotContain( typeof(AcDream.App.Input.MovementTruthDiagnosticController).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => typeof(Delegate).IsAssignableFrom(field.FieldType)); FieldInfo approachCompletions = Assert.Single( typeof(AcDream.App.Input.PlayerModeController).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => field.Name == "_approachCompletions"); Assert.Equal( typeof(AcDream.App.Interaction.IPlayerApproachCompletionLifetimeOwner), approachCompletions.FieldType); Assert.DoesNotContain( typeof(AcDream.App.Input.PlayerModeController).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => field.FieldType == typeof(AcDream.App.Interaction.SelectionInteractionController)); Assert.DoesNotContain( typeof(AcDream.App.Interaction.PlayerApproachCompletionState).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => typeof(Delegate).IsAssignableFrom(field.FieldType)); string playerModeSource = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Input", "PlayerModeController.cs")); AssertAppearsInOrder( playerModeSource, "controller.PreparePositionForCommit(", "_camera.EnterChaseMode(legacyCamera, retailCamera);", "EntityPhysicsHost.SelectStableHostWithoutRebind(", "_shadow.SyncPose(", "EntityPhysicsHost.InstallOrRebind(", "playerEntity.SetPosition(initial.Position);", "controller.CommitPreparedPosition();", "_controllerSlot.Controller = controller;", "_mode.IsPlayerMode = true;"); Assert.Contains("_shadow.Restore(playerEntity, priorShadow);", playerModeSource, StringComparison.Ordinal); Assert.Contains("_camera.RestoreState(priorCamera);", playerModeSource, StringComparison.Ordinal); string mouseLookSource = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Input", "MouseLookController.cs")); AssertAppearsInOrder( mouseLookSource, "controller?.StopMouseDrift", "retail.FilterMouseDelta", "_state.ApplyDelta"); string localPlayerSource = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Input", "RetailLocalPlayerFrameController.cs")); Assert.DoesNotContain("Func", localPlayerSource, StringComparison.Ordinal); Assert.Contains("IMovementInputSource", localPlayerSource, StringComparison.Ordinal); } [Fact] public void CameraAndLocalPlayerFrameOwnersUseTypedSeamsWithoutWindowCallbacks() { Type[] owners = [ typeof(AcDream.App.Rendering.CameraFrameController), typeof(AcDream.App.Input.RetailLocalPlayerFrameController), typeof(AcDream.App.Input.LocalPlayerProjectionController), typeof(AcDream.App.Input.LiveLocalPlayerFrameRuntime), typeof(AcDream.App.Input.LiveLocalPlayerProjectionRuntime), typeof(AcDream.App.Combat.CombatCameraTargetSource), ]; foreach (Type owner in owners) { FieldInfo[] fields = owner.GetFields( BindingFlags.Instance | BindingFlags.NonPublic); Assert.DoesNotContain(fields, field => field.FieldType == typeof(GameWindow)); Assert.DoesNotContain( fields, field => typeof(Delegate).IsAssignableFrom(field.FieldType)); } string root = FindRepoRoot(); string source = File.ReadAllText(Path.Combine( root, "src", "AcDream.App", "Rendering", "GameWindow.cs")); Assert.Equal(1, CountOccurrences( source, "_frameGraphs.Tick(")); Assert.DoesNotContain("CanAdvanceLocalPlayer", source, StringComparison.Ordinal); Assert.DoesNotContain("GetCombatCameraTargetPoint()", source, StringComparison.Ordinal); Assert.DoesNotContain("_cameraController.Fly.Update(", source, StringComparison.Ordinal); Assert.DoesNotContain("_localPlayerFrame.TryGetPresentationAfterNetwork", source, StringComparison.Ordinal); Assert.DoesNotContain("_cameraFrame", source, StringComparison.Ordinal); string cameraSource = File.ReadAllText(Path.Combine( root, "src", "AcDream.App", "Rendering", "CameraFrameController.cs")); AssertAppearsInOrder( cameraSource, "_localFrame.TryGetPresentationAfterNetwork", "_spatialReconciler.Reconcile();", "legacy.Update(", "retail?.Update("); } [Fact] public void GameWindow_OnUpdateOwnsOnlyProfilingAndOneOrchestratorTick() { string source = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Rendering", "GameWindow.cs")); Assert.Equal(1, CountOccurrences( source, "_frameGraphs.Tick(")); Assert.DoesNotContain("_updateFrameClock.Advance(", source, StringComparison.Ordinal); Assert.DoesNotContain("_liveFrameCoordinator", source, StringComparison.Ordinal); Assert.DoesNotContain("_liveEntityLiveness?.Tick", source, StringComparison.Ordinal); Assert.DoesNotContain("_playerModeAutoEntry?.TryEnter", source, StringComparison.Ordinal); AssertAppearsInOrder( source, "private void OnUpdate(double dt)", "_frameProfiler.BeginStage(", "_frameGraphs.Tick(", "private void OnRender(double deltaSeconds)"); } [Fact] public void ProductionFrameAdaptersRetainTypedOwnersWithoutWindowCallbacks() { Type[] adapters = [ typeof(LiveEntityTeardownFramePhase), typeof(ConsoleUpdateFrameFailureSink), typeof(PhysicsScriptClockPublisher), typeof(LiveEntityLivenessFramePhase), typeof(PlayerModeAutoEntryFramePhase), ]; foreach (Type adapter in adapters) { FieldInfo[] fields = adapter.GetFields( BindingFlags.Instance | BindingFlags.NonPublic); Assert.DoesNotContain(fields, field => field.FieldType == typeof(GameWindow)); Assert.DoesNotContain( fields, field => typeof(Delegate).IsAssignableFrom(field.FieldType)); } FieldInfo clock = Assert.Single( typeof(LiveEntityLivenessFramePhase).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => field.Name == "_clock"); Assert.Equal(typeof(IClientMonotonicTimeSource), clock.FieldType); FieldInfo teardownRuntime = Assert.Single( typeof(LiveEntityTeardownFramePhase).GetFields( BindingFlags.Instance | BindingFlags.NonPublic)); Assert.Equal(typeof(LiveEntityRuntime), teardownRuntime.FieldType); Type[] typedProductionOwners = [ typeof(LiveEntityLivenessController), typeof(AcDream.App.Input.LivePlayerModeAutoEntryContext), typeof(LiveSessionLocalPhysicsTimestampPublisher), typeof(AcDream.App.Physics.LiveEntityNetworkUpdateController), typeof(AcDream.App.Rendering.LiveEntityPartArrayLifecycle), typeof(AcDream.App.Physics.RemoteShadowPlacementSynchronizer), typeof(AcDream.App.Physics.RemoteTeleportPlacementPresentation), typeof(AcDream.App.Net.LiveEntitySessionController), ]; foreach (Type owner in typedProductionOwners) { FieldInfo[] fields = owner.GetFields( BindingFlags.Instance | BindingFlags.NonPublic); Assert.DoesNotContain(fields, field => field.FieldType == typeof(GameWindow)); Assert.DoesNotContain( fields, field => typeof(Delegate).IsAssignableFrom(field.FieldType)); } FieldInfo originIdentity = Assert.Single( typeof(LiveEntityWorldOriginCoordinator).GetFields( BindingFlags.Instance | BindingFlags.NonPublic), field => field.Name == "_identity"); Assert.Equal( typeof(AcDream.App.Input.ILocalPlayerIdentitySource), originIdentity.FieldType); string source = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Rendering", "GameWindow.cs")); string livePresentation = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Composition", "LivePresentationComposition.cs")); string sessionRuntime = File.ReadAllText(Path.Combine( FindRepoRoot(), "src", "AcDream.App", "Net", "LiveSessionRuntimeFactory.cs")); Assert.DoesNotContain("PublishLocalPhysicsTimestamps", source, StringComparison.Ordinal); Assert.DoesNotContain("LoginWorldReady", source, StringComparison.Ordinal); Assert.DoesNotContain("candidate => _liveEntityHydration.OnPrune", source, StringComparison.Ordinal); Assert.DoesNotContain("CreateLiveEntitySessionSink", source, StringComparison.Ordinal); Assert.DoesNotContain("private System.Numerics.Vector3 CellLocalForSeed", source, StringComparison.Ordinal); Assert.DoesNotContain("OnPlayScriptReceived", source, StringComparison.Ordinal); Assert.Contains("d.WorldOrigin.GetCenter", livePresentation, StringComparison.Ordinal); Assert.Contains("d.WorldOrigin.CellLocalForSeed", livePresentation, StringComparison.Ordinal); Assert.DoesNotContain("CreateLiveSessionEventRouter", source, StringComparison.Ordinal); Assert.Contains("_world.EntitySession.CreateSink()", sessionRuntime, StringComparison.Ordinal); Assert.DoesNotContain("GameWindow", sessionRuntime, StringComparison.Ordinal); } private static UpdateFrameOrchestrator Create( List calls, RecordingTeardown? teardown = null, RecordingFailureSink? failureSink = null, FrameObservations? observed = null, bool teleportPlace = false, bool inboundCreatedPlayer = false) { teardown ??= new RecordingTeardown(calls); failureSink ??= new RecordingFailureSink(); return new UpdateFrameOrchestrator( teardown, failureSink, new UpdateFrameClock(), new RecordingClockPublisher(calls, observed), new RecordingStreaming(calls), new RecordingInput(calls, observed), new RecordingLiveFrame(calls, observed), new RecordingLiveness(calls), new RecordingTeleport(calls, observed, teleportPlace), new RecordingAutoEntry(calls), new RecordingCamera(calls, observed, inboundCreatedPlayer)); } private sealed class RecordingTeardown(List calls) : IUpdateFrameTeardownPhase { public Exception? Failure { get; set; } public int Attempts { get; private set; } public void RetryPendingTeardowns() { calls.Add("teardown"); Attempts++; if (Failure is not null) throw Failure; } } private sealed class RecordingFailureSink : IUpdateFrameFailureSink { public List Errors { get; } = []; public void ReportTeardownFailure(AggregateException error) => Errors.Add(error); } private sealed class RecordingClockPublisher( List calls, FrameObservations? observed) : IUpdateFrameScriptClockPublisher { public void PublishTime(double scriptTime) { calls.Add("clock"); observed?.PublishedTimes.Add(scriptTime); } } private sealed class RecordingStreaming(List calls) : IStreamingFramePhase { public void Tick() => calls.Add("streaming"); } private sealed class RecordingInput( List calls, FrameObservations? observed) : IGameplayInputFramePhase { public void Tick(UpdateFrameTiming timing) { calls.Add("input"); observed?.Input.Add(timing); } } private sealed class RecordingLiveFrame( List calls, FrameObservations? observed) : IRetailLiveFramePhase { public void Tick(float deltaSeconds) { observed?.LiveDeltas.Add(deltaSeconds); calls.Add("objects"); calls.Add("network"); calls.Add("commands"); calls.Add("ordinary-reconcile"); } } private sealed class RecordingLiveness(List calls) : ILiveEntityLivenessFramePhase { public void Tick() => calls.Add("liveness"); } private sealed class RecordingTeleport( List calls, FrameObservations? observed, bool place) : ILocalPlayerTeleportFramePhase { public void Tick(float deltaSeconds) { observed?.TeleportDeltas.Add(deltaSeconds); if (!place) { calls.Add("teleport"); return; } calls.Add("teleport-place"); calls.Add("teleport-reconcile"); calls.Add("teleport-reveal"); } } private sealed class RecordingAutoEntry(List calls) : IPlayerModeAutoEntryFramePhase { public void TryEnter() => calls.Add("auto-entry"); } private sealed class RecordingCamera( List calls, FrameObservations? observed, bool inboundCreatedPlayer) : ICameraFramePhase { public void Tick(UpdateFrameTiming timing) { if (inboundCreatedPlayer) { calls.Add("inbound-player-projection"); calls.Add("inbound-player-reconcile"); } calls.Add("camera"); observed?.Camera.Add(timing); } } private sealed class FrameObservations { public List PublishedTimes { get; } = []; public List Input { get; } = []; public List LiveDeltas { get; } = []; public List TeleportDeltas { get; } = []; public List Camera { get; } = []; } private static string FindRepoRoot() { DirectoryInfo? directory = new(AppContext.BaseDirectory); while (directory is not null) { if (File.Exists(Path.Combine(directory.FullName, "AcDream.slnx"))) return directory.FullName; directory = directory.Parent; } throw new DirectoryNotFoundException("Could not find AcDream.slnx."); } private static void AssertAppearsInOrder(string source, params string[] markers) { int previous = -1; foreach (string marker in markers) { int current = source.IndexOf(marker, previous + 1, StringComparison.Ordinal); Assert.True(current >= 0, $"Missing source marker: {marker}"); Assert.True(current > previous, $"Out-of-order source marker: {marker}"); previous = current; } } private static int CountOccurrences(string source, string marker) => source.Split(marker, StringSplitOptions.None).Length - 1; }