fix(items): preserve wand stance and corpse use order
Keep active-combat AutoWield intent through ACE's pre-wield transition and queued trailing peace notice, while allowing explicit combat input to supersede it. Queue one-shot item interactions until the frame's movement edge has been serialized, so a movement release cannot cancel ACE's server-side corpse approach callback. Release build succeeds and all 5,890 runnable tests pass with five intentional skips. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
0392c6d721
commit
e6dd8bf6fa
10 changed files with 303 additions and 22 deletions
41
src/AcDream.App/Input/OutboundInteractionQueue.cs
Normal file
41
src/AcDream.App/Input/OutboundInteractionQueue.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
namespace AcDream.App.Input;
|
||||
|
||||
/// <summary>
|
||||
/// Orders input-originated item interactions after the local player's movement
|
||||
/// edge has been serialized for the same frame, but before inbound network
|
||||
/// dispatch.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Silk input callbacks arrive before the retail object phase. A movement-key
|
||||
/// release and a later Use press can therefore be observed in one frame even
|
||||
/// though the movement controller has not yet emitted the release packet.
|
||||
/// Draining here preserves that event order on the wire: the release is sent
|
||||
/// first, then the one-shot interaction. ACE otherwise interprets the later
|
||||
/// MoveToState as cancellation of the Use-created MoveTo chain.
|
||||
/// </remarks>
|
||||
public sealed class OutboundInteractionQueue
|
||||
{
|
||||
private readonly Queue<Action> _pending = new();
|
||||
|
||||
public int Count => _pending.Count;
|
||||
|
||||
public void Enqueue(Action action)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(action);
|
||||
_pending.Enqueue(action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drain only the actions present at the frame boundary. An action that
|
||||
/// enqueues another action leaves it for the next frame instead of making
|
||||
/// the current dispatch recursively unbounded.
|
||||
/// </summary>
|
||||
public void Drain()
|
||||
{
|
||||
int count = _pending.Count;
|
||||
while (count-- > 0)
|
||||
_pending.Dequeue().Invoke();
|
||||
}
|
||||
|
||||
public void Clear() => _pending.Clear();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue