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
63
src/AcDream.App/Combat/RuntimeCombatTargetOperationsSlot.cs
Normal file
63
src/AcDream.App/Combat/RuntimeCombatTargetOperationsSlot.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
using AcDream.Runtime.Gameplay;
|
||||
|
||||
namespace AcDream.App.Combat;
|
||||
|
||||
/// <summary>
|
||||
/// Early Runtime construction seam for the App-owned closest-hostile query.
|
||||
/// The slot owns no target identity or selection state.
|
||||
/// </summary>
|
||||
internal sealed class RuntimeCombatTargetOperationsSlot
|
||||
: IRuntimeCombatTargetOperations
|
||||
{
|
||||
private IRuntimeCombatTargetOperations? _owner;
|
||||
|
||||
public IDisposable BindOwned(IRuntimeCombatTargetOperations owner)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(owner);
|
||||
if (_owner is not null)
|
||||
throw new InvalidOperationException(
|
||||
"Runtime combat-target operations are already bound.");
|
||||
_owner = owner;
|
||||
return new Binding(this, owner);
|
||||
}
|
||||
|
||||
private void Unbind(IRuntimeCombatTargetOperations expected)
|
||||
{
|
||||
if (ReferenceEquals(_owner, expected))
|
||||
_owner = null;
|
||||
}
|
||||
|
||||
public bool AutoTarget => _owner?.AutoTarget == true;
|
||||
public uint? SelectClosestTarget() => _owner?.SelectClosestTarget();
|
||||
|
||||
private sealed class Binding : IDisposable
|
||||
{
|
||||
private RuntimeCombatTargetOperationsSlot? _slot;
|
||||
private readonly IRuntimeCombatTargetOperations _expected;
|
||||
|
||||
public Binding(
|
||||
RuntimeCombatTargetOperationsSlot slot,
|
||||
IRuntimeCombatTargetOperations expected)
|
||||
{
|
||||
_slot = slot;
|
||||
_expected = expected;
|
||||
}
|
||||
|
||||
public void Dispose() =>
|
||||
Interlocked.Exchange(ref _slot, null)?.Unbind(_expected);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class LiveCombatTargetOperations(
|
||||
Func<bool> autoTarget,
|
||||
Func<uint?> selectClosestTarget)
|
||||
: IRuntimeCombatTargetOperations
|
||||
{
|
||||
private readonly Func<bool> _autoTarget = autoTarget
|
||||
?? throw new ArgumentNullException(nameof(autoTarget));
|
||||
private readonly Func<uint?> _selectClosestTarget = selectClosestTarget
|
||||
?? throw new ArgumentNullException(nameof(selectClosestTarget));
|
||||
|
||||
public bool AutoTarget => _autoTarget();
|
||||
public uint? SelectClosestTarget() => _selectClosestTarget();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue