refactor(runtime): own combat and magic intent

Move attack build/repeat state, combat-mode policy, authoritative auto-target transitions, and spell-cast intent beneath RuntimeActionState. Keep App as the input, world-query, DAT-policy, transport, and presentation adapter while preserving retail request and busy ordering. Add direct/graphical parity, reset, failure, and instance-isolation coverage.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-26 11:56:40 +02:00
parent 81b31857c6
commit 20df9d155d
49 changed files with 1949 additions and 634 deletions

View file

@ -373,10 +373,15 @@ public sealed class GameWindow :
private readonly DeferredRenderFrameDiagnosticsSource _uiFrameDiagnostics = new();
private readonly AcDream.App.Combat.CombatAttackOperationsSlot
_combatAttackOperations = new();
private readonly AcDream.App.Combat.RuntimeCombatTargetOperationsSlot
_combatTargetOperations = new();
private readonly AcDream.App.Combat.RuntimeCombatModeOperationsSlot
_combatModeOperations = new();
private readonly AcDream.App.Spells.RuntimeSpellCastOperationsSlot
_spellCastOperations = new();
private readonly AcDream.App.Combat.CombatFeedbackSlot
_combatFeedback = new();
private AcDream.App.Combat.CombatAttackController? _combatAttackController;
private AcDream.App.Combat.CombatTargetController? _combatTargetController;
private RuntimeCombatAttackState? _combatAttackController;
private AcDream.App.UI.ItemInteractionController? _itemInteractionController;
private AcDream.App.World.ExternalContainerLifecycleController? _externalContainerLifecycle;
private AcDream.App.Spells.MagicRuntime? _magicRuntime;
@ -561,8 +566,14 @@ public sealed class GameWindow :
{
_options = options ?? throw new System.ArgumentNullException(nameof(options));
_runtimeInventory = new RuntimeInventoryState(_runtimeEntityObjects);
_runtimeActions = new RuntimeActionState(_runtimeInventory.Transactions);
_runtimeCharacter = new RuntimeCharacterState();
_runtimeActions = new RuntimeActionState(
_runtimeInventory.Transactions,
_runtimeCharacter.Spellbook,
_combatAttackOperations,
_combatTargetOperations,
_combatModeOperations,
_spellCastOperations);
var alphaScratchBudgets =
AcDream.App.Rendering.Residency.AlphaScratchBudgetProfile.Create(
_options.ResidencyBudgets.AlphaScratchBytes);
@ -905,7 +916,6 @@ public sealed class GameWindow :
{
ArgumentNullException.ThrowIfNull(result);
if (_combatAttackController is not null
|| _combatTargetController is not null
|| _externalContainerLifecycle is not null
|| _itemInteractionController is not null
|| _interactionUiLateBindings is not null
@ -921,10 +931,10 @@ public sealed class GameWindow :
}
_combatAttackController = result.CombatAttack;
_combatTargetController = result.CombatTarget;
_externalContainerLifecycle = result.ExternalContainerLifecycle;
_itemInteractionController = result.ItemInteraction;
_interactionUiLateBindings = result.LateBindings;
_magicRuntime = result.Magic;
if (result.RetainedUi is { } retained)
{
_uiHost = retained.Host;
@ -932,7 +942,6 @@ public sealed class GameWindow :
_vitalsVm ??= retained.Vitals;
_retailChatVm = retained.Chat;
_characterSheetProvider = retained.CharacterSheet;
_magicRuntime = retained.Magic;
_frameScreenshots = retained.Screenshots;
}
}
@ -1256,6 +1265,8 @@ public sealed class GameWindow :
_runtimeSettings,
_runtimeActions,
_combatAttackOperations,
_combatTargetOperations,
_spellCastOperations,
_runtimeInventory,
contentEffectsAudio.MagicCatalog,
_runtimeCharacter,
@ -1358,6 +1369,7 @@ public sealed class GameWindow :
_worldSceneDebugState,
_runtimeDiagnosticCommands,
_liveCombatModeCommands,
_combatModeOperations,
_hostQuiescence,
_physicsEngine,
_physicsDataCache,
@ -1564,8 +1576,7 @@ public sealed class GameWindow :
new LiveShutdownRoots(
_cameraPointerInput,
_retailUiLease,
_combatTargetController,
_combatAttackController,
_magicRuntime,
_itemInteractionController,
_externalContainerLifecycle,
_streamer,

View file

@ -10,6 +10,7 @@ using AcDream.App.Rendering.Scene;
using AcDream.App.Rendering.Vfx;
using AcDream.App.Rendering.Wb;
using AcDream.App.Settings;
using AcDream.App.Spells;
using AcDream.App.Streaming;
using AcDream.App.UI;
using AcDream.App.World;
@ -76,8 +77,7 @@ internal sealed record FrameShutdownRoots(
internal sealed record LiveShutdownRoots(
CameraPointerInputController? CameraPointer,
RetailUiRuntimeLease RetailUi,
CombatTargetController? CombatTarget,
CombatAttackController? CombatAttack,
MagicRuntime? Magic,
ItemInteractionController? ItemInteraction,
ExternalContainerLifecycleController? ExternalContainers,
LandblockStreamer? Streamer,
@ -377,8 +377,7 @@ internal static class GameWindowShutdownManifest
Hard("interaction/UI late bindings", () => frame.InteractionBindings?.Dispose()),
Hard("mouse capture", () => live.CameraPointer?.ReleaseMouseLookAfterSessionRetirement()),
Hard("retail UI", () => DisposeRetailUi(live.RetailUi)),
Hard("combat target", () => live.CombatTarget?.Dispose()),
Hard("combat attack", () => live.CombatAttack?.Dispose()),
Hard("magic runtime", () => live.Magic?.Dispose()),
Hard("item interaction", () => live.ItemInteraction?.Dispose()),
Hard("external containers", () => live.ExternalContainers?.Dispose()),
Hard("streamer", () => live.Streamer?.Dispose()),
@ -393,12 +392,12 @@ internal static class GameWindowShutdownManifest
]),
new ResourceShutdownStage("runtime entity/object stream",
[
Hard(
"runtime character state",
live.Character.Dispose),
Hard(
"runtime action state",
live.Actions.Dispose),
Hard(
"runtime character state",
live.Character.Dispose),
Hard(
"runtime inventory state",
live.Inventory.Dispose),