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:
parent
d2bb5af453
commit
5acc3f01cf
23 changed files with 2635 additions and 168 deletions
|
|
@ -301,6 +301,97 @@ public class ToolbarControllerTests
|
|||
Assert.Equal(new[] { (item, player, 0) }, puts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InventoryButton_unownedGroundDropUsesDirectAttemptWithoutDestinationProjection()
|
||||
{
|
||||
const uint player = 0x5000u;
|
||||
const uint item = 0x70005001u;
|
||||
var (layout, _, _) = FakeToolbar();
|
||||
var repo = new ClientObjectTable();
|
||||
repo.AddOrUpdate(new ClientObject { ObjectId = item, Name = "Loot", Type = ItemType.Misc });
|
||||
var placements = new List<(uint Item, uint Container, int Placement)>();
|
||||
var directPuts = new List<(uint Item, uint Container, int Placement)>();
|
||||
using var interaction = new ItemInteractionController(
|
||||
repo,
|
||||
playerGuid: () => player,
|
||||
sendUse: null,
|
||||
sendUseWithTarget: null,
|
||||
sendWield: null,
|
||||
sendDrop: null,
|
||||
placeInBackpack: (i, c, p) => placements.Add((i, c, p)));
|
||||
ToolbarController.Bind(
|
||||
layout,
|
||||
repo,
|
||||
() => Array.Empty<ShortcutEntry>(),
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
useItem: static _ => { },
|
||||
itemInteraction: interaction,
|
||||
playerGuid: () => player,
|
||||
sendPutItemInContainer: (i, c, p) => directPuts.Add((i, c, p)));
|
||||
var button = (UiButton)layout.FindElement(InventoryButtonId)!;
|
||||
var payload = new ItemDragPayload(item, ItemDragSource.Ground, 0, new UiItemSlot());
|
||||
|
||||
Assert.True(button.OnEvent(new UiEvent(0u, button, UiEventType.DragEnter, Payload: payload)));
|
||||
Assert.True(button.OnEvent(new UiEvent(0u, button, UiEventType.DropReleased, Payload: payload)));
|
||||
|
||||
Assert.Empty(placements);
|
||||
Assert.Equal(new[] { (item, player, 0) }, directPuts);
|
||||
Assert.False(interaction.TryGetPendingBackpackPlacement(item, out _));
|
||||
Assert.True(interaction.TryGetPendingInventoryRequest(out var request));
|
||||
Assert.Equal(item, request.ItemId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InventoryButton_ownedDropPublishesDestinationAndGloballyRejectsSecondRequest()
|
||||
{
|
||||
const uint player = 0x5000u;
|
||||
const uint first = 0x70005002u;
|
||||
const uint second = 0x70005003u;
|
||||
var (layout, _, _) = FakeToolbar();
|
||||
var repo = new ClientObjectTable();
|
||||
const uint pack = 0x5004u;
|
||||
repo.AddOrUpdate(new ClientObject { ObjectId = player, Name = "Player", Type = ItemType.Creature });
|
||||
repo.AddOrUpdate(new ClientObject { ObjectId = pack, Name = "Pack", Type = ItemType.Container });
|
||||
repo.MoveItem(pack, player, 0);
|
||||
repo.AddOrUpdate(new ClientObject { ObjectId = first, Name = "First Loot", Type = ItemType.Misc });
|
||||
repo.AddOrUpdate(new ClientObject { ObjectId = second, Name = "Second Loot", Type = ItemType.Misc });
|
||||
repo.MoveItem(first, pack, 0);
|
||||
repo.MoveItem(second, pack, 1);
|
||||
var puts = new List<(uint Item, uint Container, int Placement)>();
|
||||
var messages = new List<string>();
|
||||
using var interaction = new ItemInteractionController(
|
||||
repo,
|
||||
playerGuid: () => player,
|
||||
sendUse: null,
|
||||
sendUseWithTarget: null,
|
||||
sendWield: null,
|
||||
sendDrop: null,
|
||||
systemMessage: messages.Add);
|
||||
ToolbarController.Bind(
|
||||
layout,
|
||||
repo,
|
||||
() => Array.Empty<ShortcutEntry>(),
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
useItem: static _ => { },
|
||||
itemInteraction: interaction,
|
||||
playerGuid: () => player,
|
||||
sendPutItemInContainer: (i, c, p) => puts.Add((i, c, p)));
|
||||
var button = (UiButton)layout.FindElement(InventoryButtonId)!;
|
||||
|
||||
foreach (uint item in new[] { first, second })
|
||||
{
|
||||
var payload = new ItemDragPayload(item, ItemDragSource.Inventory, 0, new UiItemSlot());
|
||||
button.OnEvent(new UiEvent(0u, button, UiEventType.DragEnter, Payload: payload));
|
||||
button.OnEvent(new UiEvent(0u, button, UiEventType.DropReleased, Payload: payload));
|
||||
}
|
||||
|
||||
Assert.Equal(new[] { (first, player, 0) }, puts);
|
||||
Assert.True(interaction.TryGetPendingBackpackPlacement(first, out _));
|
||||
Assert.True(interaction.TryGetPendingInventoryRequest(out var request));
|
||||
Assert.Equal(first, request.ItemId);
|
||||
Assert.Equal(new[] { ItemInteractionController.InventoryRequestBusyMessage }, messages);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InventoryButton_shortcutAliasDrop_staysNeutralAndDoesNotMovePhysicalItem()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue