fix(runtime): restore interaction completion ownership

Preserve prepublication local motion completion, require the PartArray enter-world lifecycle port, and balance deferred Use busy ownership across dispatch and cancellation. Reconcile the completed GameWindow connected gates and add regression coverage.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-23 05:51:51 +02:00
parent 5c955c36ec
commit f9736ece6c
26 changed files with 675 additions and 68 deletions

View file

@ -38,6 +38,7 @@ internal sealed class SelectionInteractionController
uint DestinationContainerId,
int Placement,
ulong PendingPlacementToken,
ItemUseRequestReservation? UseReservation,
PlayerApproachToken ApproachToken);
public SelectionInteractionController(
@ -197,16 +198,23 @@ internal sealed class SelectionInteractionController
}
public void SendUse(uint serverGuid)
=> RequestUse(serverGuid, reservation: null);
public void RequestUse(
uint serverGuid,
ItemUseRequestReservation? reservation)
{
CancelPendingApproach();
if (!_transport.IsInWorld)
{
_toast?.Invoke("Not in world");
reservation?.CancelBeforeDispatch();
return;
}
if (!_query.IsUseable(serverGuid)
|| !_query.TryGetApproach(serverGuid, out InteractionApproach approach))
{
reservation?.CancelBeforeDispatch();
return;
}
@ -219,18 +227,28 @@ internal sealed class SelectionInteractionController
DestinationContainerId: 0u,
Placement: 0,
PendingPlacementToken: 0u,
UseReservation: reservation,
ApproachToken: default);
bool started = _movement.BeginApproach(
approach,
token => _pendingPostArrival = pending with { ApproachToken = token });
if (!started && _pendingPostArrival?.ServerGuid == pending.ServerGuid)
CancelPendingApproach();
else if (!started)
reservation?.CancelBeforeDispatch();
return;
}
_movement.BeginApproach(approach);
if (_transport.TrySendUse(serverGuid, out uint sequence))
{
reservation?.MarkDispatched();
Console.WriteLine($"[B.4b] use guid=0x{serverGuid:X8} seq={sequence}");
}
else
{
reservation?.CancelBeforeDispatch();
}
}
public void SendPickup(uint itemGuid, uint destinationContainerId, int placement)
@ -272,6 +290,7 @@ internal sealed class SelectionInteractionController
destinationContainerId,
placement,
pendingPlacementToken,
UseReservation: null,
ApproachToken: default);
bool started = _movement.BeginApproach(
approach,
@ -327,6 +346,8 @@ internal sealed class SelectionInteractionController
CancelPickupPresentation(
pending.ServerGuid,
pending.PendingPlacementToken);
else
pending.UseReservation?.CancelBeforeDispatch();
return;
}
@ -357,7 +378,10 @@ internal sealed class SelectionInteractionController
}
else
{
_transport.TrySendUse(pending.ServerGuid, out _);
if (_transport.TrySendUse(pending.ServerGuid, out _))
pending.UseReservation?.MarkDispatched();
else
pending.UseReservation?.CancelBeforeDispatch();
}
}
@ -484,6 +508,8 @@ internal sealed class SelectionInteractionController
CancelPickupPresentation(
pending.ServerGuid,
pending.PendingPlacementToken);
else
pending.UseReservation?.CancelBeforeDispatch();
}
private void CancelPickupPresentation(uint itemGuid, ulong token = 0u)