acdream/src/AcDream.App/Combat/RuntimeCombatTargetOperationsSlot.cs
Erik 20df9d155d 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>
2026-07-26 11:56:40 +02:00

63 lines
2 KiB
C#

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();
}