fix(interaction): close selection lifecycle review gaps

Bind queued actions and pending inventory requests to exact live incarnations, separate optimistic placement from authoritative responses, and serialize retail-style inventory ownership across UI surfaces.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-21 09:01:02 +02:00
parent d2bb5af453
commit 5acc3f01cf
23 changed files with 2635 additions and 168 deletions

View file

@ -13081,12 +13081,7 @@ public sealed class GameWindow : IDisposable
private void OnUiDragReleasedOutside(object payload, int x, int y)
{
if (payload is AcDream.App.UI.ItemDragPayload itemPayload)
{
uint target = PickWorldGuidAt(x, y, includeSelf: true) ?? 0u;
if (target != 0u)
BeginSelectionLightingPulse(target);
_itemInteractionController?.PlaceIn3D(itemPayload, target);
}
_selectionInteractions?.PlaceDraggedItem(itemPayload, x, y);
}
// L.0 follow-up: persisted-settings cache populated by
@ -13746,15 +13741,8 @@ public sealed class GameWindow : IDisposable
return _worldSelectionQuery?.GetCombatCameraTargetPoint(selected);
}
// ============================================================
// Phase B.4b — outbound Use handler. Wires three input actions
// (LMB click select, LMB-double-click select+use, R hotkey
// use-selected) through WorldPicker into InteractRequests.BuildUse.
// The inbound reply (SetState 0xF74B) lands via L.2g slice 1.
// ============================================================
/// <summary>
/// Shared world pick at the current cursor. The renderer supplies the
/// Item-target-mode world pick at the current cursor. The renderer supplies the
/// exact visible CPhysicsPart equivalents and RetailWorldPicker performs
/// retail's drawing-sphere broadphase followed by flat visual-polygon
/// intersection. <paramref name="includeSelf"/> allows item target-use to
@ -13764,13 +13752,6 @@ public sealed class GameWindow : IDisposable
=> _selectionInteractions?.PickAtCursor(includeSelf)
?? _worldSelectionQuery?.PickAtCursor(includeSelf);
private uint? PickWorldGuidAt(float mouseX, float mouseY, bool includeSelf)
=> _selectionInteractions?.PickAt(mouseX, mouseY, includeSelf)
?? _worldSelectionQuery?.PickAt(mouseX, mouseY, includeSelf);
private void BeginSelectionLightingPulse(uint serverGuid)
=> _worldSelectionQuery?.BeginLightingPulse(serverGuid);
// Contained/toolbar activation is not a world-selection interaction: it
// sends directly without speculative TurnToObject/MoveToObject.
private void UseItemByGuid(uint guid)
@ -13818,33 +13799,6 @@ public sealed class GameWindow : IDisposable
private AcDream.App.UI.Layout.VividTargetInfo? ResolveVividTargetInfo(uint guid)
=> _worldSelectionQuery?.ResolveVividTargetInfo(guid);
/// <summary>
/// 2026-05-16 — retail-faithful port of
/// <c>SmartBox::GetObjectBoundingBox</c> (decomp <c>0x00452e20</c>)
/// using <c>CPhysicsObj::GetSelectionSphere</c> (<c>0x0050ea40</c>)
/// → <c>CPartArray::GetSelectionSphere</c> (<c>0x00518b80</c>).
///
/// <para>
/// Retail's VividTargetIndicator does NOT use a per-mesh AABB —
/// it uses the Setup's <c>selection_sphere</c> field (a single
/// sphere encompassing the entire entity, baked at Setup-creation
/// time). The sphere is scaled by the part-array scale
/// (component-wise on center, Z-scale on radius — retail's exact
/// formula at <c>0x00518ba60x00518be3</c>) and rotated by entity
/// orientation. The screen indicator rect is the projection of
/// the camera-aligned BBox of this sphere — i.e. a screen circle
/// of radius <c>worldRadius * focalLength / depth</c>.
/// </para>
///
/// <para>
/// Result: the indicator rect MATCHES the Setup's intended
/// "selectable extent" — which is typically larger than the mesh
/// AABB by design (Setups bake a slightly oversized selection
/// sphere so far targets still get pickable indicators). That's
/// why our previous mesh-AABB indicator was smaller than retail's.
/// </para>
/// </summary>
private void TogglePlayerMode()
{
// Phase B.2 guard: only active when a live session is in-world.
@ -14084,7 +14038,11 @@ public sealed class GameWindow : IDisposable
Console.WriteLine($"[autowalk-end] reason=complete err={err}");
if (err == AcDream.Core.Physics.WeenieError.None)
OnAutoWalkArrivedSendDeferredAction();
else
_selectionInteractions?.OnMoveToCancelled(err);
};
playerMoveTo.MoveToCancelled = err =>
_selectionInteractions?.OnMoveToCancelled(err);
// R5-V3 (#171, retires TS-39 — player side): bind the sticky
// seams to the player host's PositionManager (same trio as the