refactor(input): own gameplay action routing

Move the sole semantic action-priority graph, combat and diagnostic commands, and retained-root item-drop lifetime behind focused typed owners. Preserve retail toggle behavior, explicit auto-wield cancellation, shutdown quiescence, and symmetric callback cleanup.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-22 12:43:05 +02:00
parent 8b8afeefa3
commit 4eae9b4f5a
25 changed files with 2608 additions and 418 deletions

View file

@ -62,7 +62,6 @@ public sealed class GameWindowSlice8BoundaryTests
"_inputDispatcher.Attach();",
"_movementInput.Bind(_inputDispatcher);",
"_cameraInput.Bind(_inputDispatcher);",
"_inputDispatcher.Fired += OnInputAction;",
"_cameraController = new CameraController(orbit, fly);",
"_cameraPointerInput = AcDream.App.Input.CameraPointerInputController.Create(",
"_cameraPointerInput.AttachRaw();",
@ -73,9 +72,17 @@ public sealed class GameWindowSlice8BoundaryTests
"_uiHost.WireKeyboard(kb)",
"_retailUiRuntime = AcDream.App.UI.RetailUiRuntime.Mount(",
"_liveEntities = new AcDream.App.World.LiveEntityRuntime(",
"_selectionInteractions ??= new AcDream.App.Interaction.SelectionInteractionController(",
"_retainedUiGameplayBinding =",
"AcDream.App.Input.RetainedUiGameplayBinding.Create(",
"_retainedUiGameplayBinding.Attach();",
"_renderFrameOrchestrator =",
"_updateFrameOrchestrator = new AcDream.App.Update.UpdateFrameOrchestrator(",
"_liveSessionHost = CreateLiveSessionHost();",
"_liveCombatModeCommands.Bind(combatCommand);",
"_runtimeDiagnosticCommands.Bind(runtimeDiagnostics);",
"_gameplayInputActions = AcDream.App.Input.GameplayInputActionRouter.Create(",
"_gameplayInputActions.Attach();",
"_liveSessionHost.Start(_options)");
Assert.Equal(1, CountOccurrences(body, "_liveSessionHost.Start(_options)"));
Assert.Contains("if (firstKb is not null)", body, StringComparison.Ordinal);
@ -128,33 +135,53 @@ public sealed class GameWindowSlice8BoundaryTests
Assert.DoesNotContain("private void RefreshSkyForCurrentDay()", source, StringComparison.Ordinal);
Assert.DoesNotContain("private void OnEnvironChanged(", source, StringComparison.Ordinal);
string cycleTime = MethodBody(
"private void CycleTimeOfDay()",
"private void CycleWeather()");
Assert.DoesNotContain("private void CycleTimeOfDay()", source, StringComparison.Ordinal);
Assert.DoesNotContain("private void CycleWeather()", source, StringComparison.Ordinal);
AssertAppearsInOrder(
cycleTime,
"_worldEnvironment.CycleTimeOfDay();",
"_debugVm?.AddToast(message);");
load,
"_debugVm.CycleTimeOfDay =",
"_runtimeDiagnosticCommands.CycleTimeOfDay;",
"new AcDream.App.Diagnostics.RuntimeDiagnosticCommandController(",
"_runtimeDiagnosticCommands.Bind(runtimeDiagnostics);");
}
[Fact]
public void InputAction_PreservesRetailAcceptedPriority()
public void InputAction_IsOneTypedOwnerHandoff()
{
string body = MethodBody(
"private void OnInputAction(",
"private void ToggleLiveCombatMode()");
string source = GameWindowSource();
string load = MethodBody(
"private void OnLoad()",
"private AcDream.App.Net.LiveSessionHost");
string shutdown = MethodBody(
"private ResourceShutdownTransaction CreateShutdownTransaction()",
"private void OnFocusChanged(bool focused)");
Assert.DoesNotContain("private void OnInputAction(", source, StringComparison.Ordinal);
Assert.DoesNotContain("private void SetInputCombatScope(", source, StringComparison.Ordinal);
Assert.DoesNotContain("private void ToggleLiveCombatMode()", source, StringComparison.Ordinal);
Assert.DoesNotContain("private void OnUiDragReleasedOutside(", source, StringComparison.Ordinal);
Assert.DoesNotContain("DragReleasedOutsideUi +=", source, StringComparison.Ordinal);
Assert.Equal(1, CountOccurrences(
load,
"AcDream.App.Input.GameplayInputActionRouter.Create("));
Assert.Equal(1, CountOccurrences(load, "_gameplayInputActions.Attach();"));
Assert.Equal(1, CountOccurrences(
load,
"AcDream.App.Input.RetainedUiGameplayBinding.Create("));
Assert.Equal(1, CountOccurrences(
load,
"_retainedUiGameplayBinding.Attach();"));
AssertAppearsInOrder(
body,
"HandlePointerAction(action, activation)",
"action == AcDream.UI.Abstractions.Input.InputAction.ScrollUp",
"HandleScrollAction(action);",
"HandleCombatAction(action, activation)",
"activation != AcDream.UI.Abstractions.Input.ActivationType.Press",
"_retailUiRuntime?.HandleInputAction(action)",
"_selectionInteractions?.HandleInputAction(action)",
"HandlePressedMovementAction(action)",
"switch (action)");
shutdown,
"_liveCombatModeCommands.Deactivate",
"_runtimeDiagnosticCommands.Deactivate",
"_retainedUiGameplayBinding?.Deactivate()",
"_gameplayInputActions?.Deactivate()",
"new ResourceShutdownStage(\"session lifetime\"",
"binding.Dispose();",
"_retainedUiGameplayBinding = null;",
"actions.Dispose();",
"_gameplayInputActions = null;");
}
[Fact]
@ -265,10 +292,16 @@ public sealed class GameWindowSlice8BoundaryTests
"_windowCallbacks = null;");
AssertAppearsInOrder(
manifest,
"new(\"combat command slot\", _liveCombatModeCommands.Deactivate)",
"new(\"diagnostic command slot\", _runtimeDiagnosticCommands.Deactivate)",
"new(\"retained gameplay\", () => _retainedUiGameplayBinding?.Deactivate())",
"new(\"gameplay actions\", () => _gameplayInputActions?.Deactivate())",
"new(\"camera pointer\", () => _cameraPointerInput?.Deactivate())",
"new ResourceShutdownStage(\"session lifetime\"",
"controller.Dispose();",
"new ResourceShutdownStage(\"input callback detach\"",
"binding.Dispose();",
"actions.Dispose();",
"pointer.Dispose();",
"new ResourceShutdownStage(\"session dependents\"",
"pointer.ReleaseMouseLookAfterSessionRetirement();",