refactor(update): cut over the frame orchestrator
Reduce GameWindow.OnUpdate to one typed orchestration call and remove transitive window callbacks from teardown, liveness, teleport placement, live presentation, auto-entry, and entity packet routing. Preserve the frozen retail object/network order while making the production owner graph explicit and testable.
This commit is contained in:
parent
947c61d2d7
commit
e91f310279
18 changed files with 864 additions and 348 deletions
|
|
@ -36,9 +36,8 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
[Fact]
|
||||
public void ConditionalReconciles_RemainAtTheirOwningEdges()
|
||||
{
|
||||
// Checkpoint A freezes only the outer ownership contract. Checkpoints
|
||||
// E and F must replace these probes with production teleport/camera
|
||||
// owner tests before the conditional edges can be claimed guarded.
|
||||
// The outer ownership oracle is complemented by the production
|
||||
// teleport and camera tests that pin both conditional reconcile edges.
|
||||
var calls = new List<string>();
|
||||
UpdateFrameOrchestrator frame = Create(
|
||||
calls,
|
||||
|
|
@ -228,19 +227,6 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
FieldInfo[] ownerFields = owner.GetFields(
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
Assert.DoesNotContain(ownerFields, field => field.FieldType == typeof(GameWindow));
|
||||
if (owner == typeof(AcDream.App.Input.RetailLocalPlayerFrameController))
|
||||
{
|
||||
// Checkpoint D replaced input capture with its typed owner.
|
||||
// Checkpoint F still owns the remaining player presentation
|
||||
// callback composition. No other phase owner may add one.
|
||||
Assert.Contains(
|
||||
ownerFields,
|
||||
field => typeof(Delegate).IsAssignableFrom(field.FieldType));
|
||||
Assert.DoesNotContain(
|
||||
ownerFields,
|
||||
field => field.FieldType == typeof(Func<AcDream.App.Input.MovementInput>));
|
||||
continue;
|
||||
}
|
||||
Assert.DoesNotContain(
|
||||
ownerFields,
|
||||
field => typeof(Delegate).IsAssignableFrom(field.FieldType));
|
||||
|
|
@ -277,14 +263,24 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
[Fact]
|
||||
public void ProductionFrame_PublishesPhysicsScriptTimeExactlyOnce()
|
||||
{
|
||||
string root = FindRepoRoot();
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
root,
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Rendering",
|
||||
"GameWindow.cs"));
|
||||
string adapters = File.ReadAllText(Path.Combine(
|
||||
root,
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Update",
|
||||
"UpdateFrameRuntimeAdapters.cs"));
|
||||
|
||||
Assert.Equal(1, source.Split("PublishTime(", StringSplitOptions.None).Length - 1);
|
||||
Assert.Equal(0, CountOccurrences(source, "PublishTime("));
|
||||
Assert.Equal(1, CountOccurrences(adapters, "_runner.PublishTime("));
|
||||
Assert.Contains("new AcDream.App.Update.PhysicsScriptClockPublisher(", source,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -363,12 +359,10 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
"GameWindow.cs"));
|
||||
|
||||
Assert.Contains("new AcDream.App.Streaming.StreamingFrameController(", source);
|
||||
Assert.Equal(1, CountOccurrences(source, "_streamingFrame.Tick();"));
|
||||
AssertAppearsInOrder(
|
||||
Assert.DoesNotContain("_streamingFrame", source, StringComparison.Ordinal);
|
||||
Assert.Equal(1, CountOccurrences(
|
||||
source,
|
||||
"_streamingFrame.Tick();",
|
||||
"_gameplayInputFrame!.Tick(frameTiming);",
|
||||
"_liveFrameCoordinator.Tick(frameDelta);");
|
||||
"_updateFrameOrchestrator.Tick("));
|
||||
Assert.DoesNotContain("_streamingController.Tick(observerCx", source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("DungeonStreamingGate.Compute", source,
|
||||
|
|
@ -387,7 +381,8 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
"GameWindow.cs"));
|
||||
|
||||
Assert.Contains("new AcDream.App.Input.GameplayInputFrameController(", source);
|
||||
Assert.Equal(1, CountOccurrences(source, "_gameplayInputFrame!.Tick(frameTiming);"));
|
||||
Assert.DoesNotContain("_gameplayInputFrame!.Tick", source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_inputDispatcher?.Tick()", source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("TryTakeRawSample", source,
|
||||
|
|
@ -468,9 +463,8 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
"new AcDream.App.Streaming.LocalPlayerTeleportController(",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Equal(1, CountOccurrences(
|
||||
source,
|
||||
"_localPlayerTeleport!.Tick(frameDelta);"));
|
||||
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);
|
||||
|
|
@ -486,9 +480,10 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
StringComparison.Ordinal);
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"_liveEntityLiveness?.Tick(ClientTimerNow());",
|
||||
"_localPlayerTeleport!.Tick(frameDelta);",
|
||||
"_playerModeAutoEntry?.TryEnter();");
|
||||
"new AcDream.App.Update.LiveEntityLivenessFramePhase(",
|
||||
"_localPlayerTeleport,",
|
||||
"new AcDream.App.Update.PlayerModeAutoEntryFramePhase(",
|
||||
"cameraFrame);");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -649,7 +644,9 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
"AcDream.App",
|
||||
"Rendering",
|
||||
"GameWindow.cs"));
|
||||
Assert.Equal(1, CountOccurrences(source, "_cameraFrame.Tick(frameTiming);"));
|
||||
Assert.Equal(1, CountOccurrences(
|
||||
source,
|
||||
"_updateFrameOrchestrator.Tick("));
|
||||
Assert.DoesNotContain("CanAdvanceLocalPlayer", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("GetCombatCameraTargetPoint()", source,
|
||||
StringComparison.Ordinal);
|
||||
|
|
@ -657,11 +654,7 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_localPlayerFrame.TryGetPresentationAfterNetwork", source,
|
||||
StringComparison.Ordinal);
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"_localPlayerTeleport!.Tick(frameDelta);",
|
||||
"_playerModeAutoEntry?.TryEnter();",
|
||||
"_cameraFrame.Tick(frameTiming);");
|
||||
Assert.DoesNotContain("_cameraFrame", source, StringComparison.Ordinal);
|
||||
|
||||
string cameraSource = File.ReadAllText(Path.Combine(
|
||||
root,
|
||||
|
|
@ -677,6 +670,123 @@ public sealed class UpdateFrameOrchestratorTests
|
|||
"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,
|
||||
"_updateFrameOrchestrator.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(",
|
||||
"_updateFrameOrchestrator.Tick(",
|
||||
"private void OnCameraModeChanged");
|
||||
}
|
||||
|
||||
[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"));
|
||||
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("_liveWorldOrigin.GetCenter", source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("_liveWorldOrigin.CellLocalForSeed", source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("_liveEntitySessionEvents.CreateSink()", source,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static UpdateFrameOrchestrator Create(
|
||||
List<string> calls,
|
||||
RecordingTeardown? teardown = null,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue