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:
parent
81b31857c6
commit
20df9d155d
49 changed files with 1949 additions and 634 deletions
|
|
@ -1,6 +1,7 @@
|
|||
using AcDream.Core.Combat;
|
||||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Selection;
|
||||
using AcDream.Core.Spells;
|
||||
|
||||
namespace AcDream.Runtime.Gameplay;
|
||||
|
||||
|
|
@ -8,6 +9,9 @@ public readonly record struct RuntimeActionOwnershipSnapshot(
|
|||
bool IsDisposed,
|
||||
bool InternalSubscriptionsAttached,
|
||||
bool InteractionTransactionsDisposed,
|
||||
bool CombatAttackDisposed,
|
||||
bool CombatTargetDisposed,
|
||||
bool SpellCastReset,
|
||||
uint SelectedObjectId,
|
||||
uint PreviousObjectId,
|
||||
uint PreviousValidObjectId,
|
||||
|
|
@ -23,6 +27,9 @@ public readonly record struct RuntimeActionOwnershipSnapshot(
|
|||
IsDisposed
|
||||
&& !InternalSubscriptionsAttached
|
||||
&& InteractionTransactionsDisposed
|
||||
&& CombatAttackDisposed
|
||||
&& CombatTargetDisposed
|
||||
&& SpellCastReset
|
||||
&& SelectedObjectId == 0u
|
||||
&& PreviousObjectId == 0u
|
||||
&& PreviousValidObjectId == 0u
|
||||
|
|
@ -33,9 +40,9 @@ public readonly record struct RuntimeActionOwnershipSnapshot(
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Canonical presentation-independent owner for selection, combat
|
||||
/// notifications/mode, and temporary interaction target mode. Graphical and
|
||||
/// no-window hosts borrow these exact instances.
|
||||
/// Canonical presentation-independent owner for selection, interaction
|
||||
/// transactions, combat mode/attack/target intent, and spell-cast intent.
|
||||
/// Graphical and no-window hosts borrow these exact instances.
|
||||
/// </summary>
|
||||
public sealed class RuntimeActionState : IDisposable
|
||||
{
|
||||
|
|
@ -44,21 +51,52 @@ public sealed class RuntimeActionState : IDisposable
|
|||
private long _selectionRevision;
|
||||
private long _combatRevision;
|
||||
private long _interactionRevision;
|
||||
private long _combatIntentRevision;
|
||||
private long _magicIntentRevision;
|
||||
|
||||
public RuntimeActionState(InventoryTransactionState inventoryTransactions)
|
||||
public RuntimeActionState(
|
||||
InventoryTransactionState inventoryTransactions,
|
||||
Spellbook spellbook,
|
||||
IRuntimeCombatAttackOperations combatAttackOperations,
|
||||
IRuntimeCombatTargetOperations combatTargetOperations,
|
||||
IRuntimeCombatModeOperations combatModeOperations,
|
||||
IRuntimeSpellCastOperations spellCastOperations,
|
||||
Func<double>? now = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(inventoryTransactions);
|
||||
ArgumentNullException.ThrowIfNull(spellbook);
|
||||
ArgumentNullException.ThrowIfNull(combatAttackOperations);
|
||||
ArgumentNullException.ThrowIfNull(combatTargetOperations);
|
||||
ArgumentNullException.ThrowIfNull(combatModeOperations);
|
||||
ArgumentNullException.ThrowIfNull(spellCastOperations);
|
||||
Selection = new SelectionState();
|
||||
Combat = new CombatState();
|
||||
Interaction = new InteractionState();
|
||||
Transactions = new RuntimeInteractionTransactionState(
|
||||
inventoryTransactions);
|
||||
CombatAttack = new RuntimeCombatAttackState(
|
||||
Combat,
|
||||
combatAttackOperations,
|
||||
now);
|
||||
CombatTarget = new RuntimeCombatTargetState(
|
||||
Combat,
|
||||
Selection,
|
||||
combatTargetOperations);
|
||||
CombatMode = new RuntimeCombatModeState(
|
||||
Combat,
|
||||
combatModeOperations);
|
||||
SpellCast = new RuntimeSpellCastState(
|
||||
spellbook,
|
||||
Selection,
|
||||
spellCastOperations);
|
||||
View = new ActionView(this);
|
||||
|
||||
Selection.Changed += OnSelectionChanged;
|
||||
Combat.CombatModeChanged += OnCombatModeChanged;
|
||||
Combat.HealthChanged += OnHealthChanged;
|
||||
Interaction.Changed += OnInteractionChanged;
|
||||
CombatAttack.StateChanged += OnCombatAttackChanged;
|
||||
SpellCast.StateChanged += OnSpellCastChanged;
|
||||
_internalSubscriptionsAttached = true;
|
||||
}
|
||||
|
||||
|
|
@ -66,6 +104,10 @@ public sealed class RuntimeActionState : IDisposable
|
|||
public CombatState Combat { get; }
|
||||
public InteractionState Interaction { get; }
|
||||
public RuntimeInteractionTransactionState Transactions { get; }
|
||||
public RuntimeCombatAttackState CombatAttack { get; }
|
||||
public RuntimeCombatTargetState CombatTarget { get; }
|
||||
public RuntimeCombatModeState CombatMode { get; }
|
||||
public RuntimeSpellCastState SpellCast { get; }
|
||||
public IRuntimeActionView View { get; }
|
||||
public bool IsDisposed => _disposed;
|
||||
|
||||
|
|
@ -73,6 +115,10 @@ public sealed class RuntimeActionState : IDisposable
|
|||
_disposed,
|
||||
_internalSubscriptionsAttached,
|
||||
Transactions.IsDisposed,
|
||||
CombatAttack.IsDisposed,
|
||||
CombatTarget.IsDisposed,
|
||||
SpellCast.LastRequestedSpellId is null
|
||||
&& SpellCast.LastRequestedTargetId is null,
|
||||
Selection.SelectedObjectId ?? 0u,
|
||||
Selection.PreviousObjectId ?? 0u,
|
||||
Selection.PreviousValidObjectId ?? 0u,
|
||||
|
|
@ -95,6 +141,8 @@ public sealed class RuntimeActionState : IDisposable
|
|||
List<Exception>? failures = null;
|
||||
Try(Transactions.ResetSession, ref failures);
|
||||
Try(Interaction.ResetSession, ref failures);
|
||||
Try(SpellCast.Reset, ref failures);
|
||||
Try(CombatAttack.ResetSession, ref failures);
|
||||
Try(() => Selection.Reset(), ref failures);
|
||||
Try(Combat.Clear, ref failures);
|
||||
if (failures is not null)
|
||||
|
|
@ -115,6 +163,8 @@ public sealed class RuntimeActionState : IDisposable
|
|||
{
|
||||
Try(Transactions.Dispose, ref failures);
|
||||
Try(Interaction.ResetSession, ref failures);
|
||||
Try(SpellCast.Reset, ref failures);
|
||||
Try(CombatAttack.ResetSession, ref failures);
|
||||
Try(() => Selection.Reset(), ref failures);
|
||||
Try(Combat.Clear, ref failures);
|
||||
}
|
||||
|
|
@ -124,6 +174,10 @@ public sealed class RuntimeActionState : IDisposable
|
|||
Combat.CombatModeChanged -= OnCombatModeChanged;
|
||||
Combat.HealthChanged -= OnHealthChanged;
|
||||
Interaction.Changed -= OnInteractionChanged;
|
||||
CombatAttack.StateChanged -= OnCombatAttackChanged;
|
||||
SpellCast.StateChanged -= OnSpellCastChanged;
|
||||
Try(CombatAttack.Dispose, ref failures);
|
||||
Try(CombatTarget.Dispose, ref failures);
|
||||
_internalSubscriptionsAttached = false;
|
||||
_disposed = true;
|
||||
}
|
||||
|
|
@ -148,6 +202,12 @@ public sealed class RuntimeActionState : IDisposable
|
|||
private void OnInteractionChanged(InteractionModeTransition _) =>
|
||||
Interlocked.Increment(ref _interactionRevision);
|
||||
|
||||
private void OnCombatAttackChanged() =>
|
||||
Interlocked.Increment(ref _combatIntentRevision);
|
||||
|
||||
private void OnSpellCastChanged() =>
|
||||
Interlocked.Increment(ref _magicIntentRevision);
|
||||
|
||||
private static void Try(Action action, ref List<Exception>? failures)
|
||||
{
|
||||
try
|
||||
|
|
@ -174,7 +234,19 @@ public sealed class RuntimeActionState : IDisposable
|
|||
Interlocked.Read(ref owner._interactionRevision),
|
||||
owner.Interaction.Current.Kind,
|
||||
owner.Interaction.Current.SourceObjectId,
|
||||
owner.Transactions.CaptureOwnership());
|
||||
owner.Transactions.CaptureOwnership(),
|
||||
new RuntimeCombatAttackSnapshot(
|
||||
Interlocked.Read(ref owner._combatIntentRevision),
|
||||
owner.CombatAttack.RequestedHeight,
|
||||
owner.CombatAttack.DesiredPower,
|
||||
owner.CombatAttack.PowerBarLevel,
|
||||
owner.CombatAttack.BuildInProgress,
|
||||
owner.CombatAttack.AttackRequestInProgress,
|
||||
owner.CombatAttack.RequestedAttackPower),
|
||||
new RuntimeSpellCastSnapshot(
|
||||
Interlocked.Read(ref owner._magicIntentRevision),
|
||||
owner.SpellCast.LastRequestedSpellId ?? 0u,
|
||||
owner.SpellCast.LastRequestedTargetId ?? 0u));
|
||||
|
||||
public bool TryGetHealth(uint objectId, out float healthPercent)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue