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

@ -1,4 +1,3 @@
using AcDream.App.Combat;
using AcDream.App.Input;
using AcDream.App.Interaction;
using AcDream.App.Net;
@ -43,8 +42,7 @@ internal sealed class CurrentGameRuntimeAdapter
WorldRevealCoordinator worldReveal,
IGameRuntimeClock clock,
SelectionInteractionController selection,
GameplayInputFrameController gameplayInput,
ILiveCombatModeCommand combat)
GameplayInputFrameController gameplayInput)
{
_view = new CurrentGameRuntimeViewAdapter(
session,
@ -75,7 +73,6 @@ internal sealed class CurrentGameRuntimeAdapter
actions,
selection,
gameplayInput,
combat,
_events);
}
@ -95,6 +92,7 @@ internal sealed class CurrentGameRuntimeAdapter
public IRuntimeSessionCommands Session => _commands;
public IRuntimeSelectionCommands Selection => _commands;
public IRuntimeCombatCommands Combat => _commands;
public IRuntimeMagicCommands Magic => _commands;
public IRuntimeMovementCommands MovementCommands => _commands;
IRuntimeMovementCommands IGameRuntimeCommands.Movement => _commands;
public IRuntimeChatCommands ChatCommands => _commands;

View file

@ -1,4 +1,3 @@
using AcDream.App.Combat;
using AcDream.App.Input;
using AcDream.App.Interaction;
using AcDream.App.Net;
@ -19,6 +18,7 @@ internal sealed class CurrentGameRuntimeCommandAdapter
: IRuntimeSessionCommands,
IRuntimeSelectionCommands,
IRuntimeCombatCommands,
IRuntimeMagicCommands,
IRuntimeMovementCommands,
IRuntimeChatCommands,
IRuntimePortalCommands,
@ -36,7 +36,6 @@ internal sealed class CurrentGameRuntimeCommandAdapter
private readonly RuntimeActionState _actions;
private readonly SelectionInteractionController _selection;
private readonly GameplayInputFrameController _gameplayInput;
private readonly ILiveCombatModeCommand _combat;
private readonly ICurrentGameRuntimeEventSink _events;
public CurrentGameRuntimeCommandAdapter(
@ -49,7 +48,6 @@ internal sealed class CurrentGameRuntimeCommandAdapter
RuntimeActionState actions,
SelectionInteractionController selection,
GameplayInputFrameController gameplayInput,
ILiveCombatModeCommand combat,
ICurrentGameRuntimeEventSink events)
{
_session = session ?? throw new ArgumentNullException(nameof(session));
@ -63,7 +61,6 @@ internal sealed class CurrentGameRuntimeCommandAdapter
_selection = selection ?? throw new ArgumentNullException(nameof(selection));
_gameplayInput = gameplayInput
?? throw new ArgumentNullException(nameof(gameplayInput));
_combat = combat ?? throw new ArgumentNullException(nameof(combat));
_events = events ?? throw new ArgumentNullException(nameof(events));
}
@ -178,8 +175,16 @@ internal sealed class CurrentGameRuntimeCommandAdapter
RuntimeCommandStatus status;
if (command == RuntimeCombatCommand.ToggleMode)
{
_combat.Toggle();
status = RuntimeCommandStatus.Accepted;
RuntimeCombatModeRequestResult result =
_actions.CombatMode.Toggle();
status = result.Status switch
{
RuntimeCombatModeRequestStatus.Sent =>
RuntimeCommandStatus.Accepted,
RuntimeCombatModeRequestStatus.Inactive =>
RuntimeCommandStatus.Inactive,
_ => RuntimeCommandStatus.Rejected,
};
}
else
{
@ -190,6 +195,49 @@ internal sealed class CurrentGameRuntimeCommandAdapter
return Result(status);
}
public RuntimeCommandResult ExecuteAttack(
RuntimeGenerationToken expectedGeneration,
in RuntimeCombatAttackInput command)
{
RuntimeCommandStatus gate = Validate(
expectedGeneration,
requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
RuntimeCommandStatus status = _actions.CombatAttack.HandleCommand(
command)
? RuntimeCommandStatus.Accepted
: RuntimeCommandStatus.Unsupported;
_events.EmitCommand(
RuntimeCommandDomain.Combat,
operation: 0x100 + (int)command.Command,
status);
return Result(status);
}
public RuntimeCommandResult Execute(
RuntimeGenerationToken expectedGeneration,
in RuntimeMagicCommand command)
{
RuntimeCommandStatus gate = Validate(
expectedGeneration,
requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
CastRequestResult cast = _actions.SpellCast.Cast(command.SpellId);
RuntimeCommandStatus status = cast == CastRequestResult.Sent
? RuntimeCommandStatus.Accepted
: RuntimeCommandStatus.Rejected;
_events.EmitCommand(
RuntimeCommandDomain.Magic,
operation: (int)cast,
status,
command.SpellId);
return Result(status, command.SpellId);
}
public RuntimeCommandResult Execute(
RuntimeGenerationToken expectedGeneration,
RuntimeMovementCommand command)