feat(D.2b): InventoryController drag-drop handler (optimistic move + green-arrow/red-circle)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4aebf444d9
commit
81d9b3b37a
2 changed files with 165 additions and 8 deletions
|
|
@ -51,12 +51,14 @@ public class InventoryControllerTests
|
|||
}
|
||||
|
||||
private static InventoryController Bind(ImportedLayout layout, ClientObjectTable objects,
|
||||
int? strength = 100, List<uint>? uses = null, List<uint>? closes = null)
|
||||
int? strength = 100, List<uint>? uses = null, List<uint>? closes = null,
|
||||
List<(uint item, uint container, int placement)>? puts = null)
|
||||
=> InventoryController.Bind(layout, objects, () => Player,
|
||||
iconIds: (_, _, _, _, _) => 0u, // no real GL upload in tests
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
strength: () => strength, datFont: null,
|
||||
sendUse: uses is null ? null : g => uses.Add(g),
|
||||
sendNoLongerViewing: closes is null ? null : g => closes.Add(g));
|
||||
sendNoLongerViewing: closes is null ? null : g => closes.Add(g),
|
||||
sendPutItemInContainer: puts is null ? null : (i, c, p) => puts.Add((i, c, p)));
|
||||
|
||||
// Seed a side bag (a container) in the player's pack, plus optionally its own contents.
|
||||
private static void SeedBag(ClientObjectTable t, uint bag, int slot, int itemsCapacity = 24)
|
||||
|
|
@ -403,6 +405,85 @@ public class InventoryControllerTests
|
|||
Assert.Equal(-1f, grid.GetItem(0)!.CapacityFill); // hidden — not a container
|
||||
}
|
||||
|
||||
private static ItemDragPayload Payload(uint obj) => new(obj, ItemDragSource.Inventory, 0, new UiItemSlot());
|
||||
|
||||
[Fact]
|
||||
public void Drop_onOccupiedGridCell_insertsBefore_andMovesLocally()
|
||||
{
|
||||
var (layout, grid, _, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedContained(objects, 0xA, Player, slot: 0);
|
||||
SeedContained(objects, 0xB, Player, slot: 1);
|
||||
var puts = new List<(uint, uint, int)>();
|
||||
var ctrl = Bind(layout, objects, puts: puts);
|
||||
|
||||
// Drag a fresh item 0xFFFF from elsewhere; drop on the grid cell holding 0xB (slot 1).
|
||||
objects.AddOrUpdate(new ClientObject { ObjectId = 0xFFFFu });
|
||||
var bCell = grid.GetItem(1)!; // ItemId == 0xB, SlotIndex 1
|
||||
((IItemListDragHandler)ctrl).HandleDropRelease(grid, bCell, Payload(0xFFFFu));
|
||||
|
||||
Assert.Contains((0xFFFFu, Player, 1), puts); // insert-before slot 1, into the open container
|
||||
Assert.Equal(Player, objects.Get(0xFFFFu)!.ContainerId); // moved locally (instant)
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Drop_onEmptyGridCell_appendsToFirstEmpty()
|
||||
{
|
||||
var (layout, grid, _, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedContained(objects, 0xA, Player, slot: 0); // 1 loose item → first empty = slot 1
|
||||
var puts = new List<(uint, uint, int)>();
|
||||
var ctrl = Bind(layout, objects, puts: puts);
|
||||
|
||||
objects.AddOrUpdate(new ClientObject { ObjectId = 0xFFFFu });
|
||||
var emptyCell = grid.GetItem(5)!; // an empty padded cell (ItemId 0)
|
||||
((IItemListDragHandler)ctrl).HandleDropRelease(grid, emptyCell, Payload(0xFFFFu));
|
||||
|
||||
Assert.Contains((0xFFFFu, Player, 1), puts); // placement = occupied count (1) = first empty
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Drop_onSideBagCell_movesIntoThatBag()
|
||||
{
|
||||
var (layout, _, containers, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedBag(objects, 0xC, slot: 0, itemsCapacity: 24);
|
||||
var puts = new List<(uint, uint, int)>();
|
||||
var ctrl = Bind(layout, objects, puts: puts);
|
||||
|
||||
objects.AddOrUpdate(new ClientObject { ObjectId = 0xFFFFu });
|
||||
var bagCell = containers.GetItem(0)!; // ItemId == 0xC (the bag)
|
||||
((IItemListDragHandler)ctrl).HandleDropRelease(containers, bagCell, Payload(0xFFFFu));
|
||||
|
||||
Assert.Contains((0xFFFFu, 0xCu, 0), puts); // into the bag, append (placement 0)
|
||||
Assert.Equal(0xCu, objects.Get(0xFFFFu)!.ContainerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnDragOver_fullSideBag_rejects_butGridAccepts()
|
||||
{
|
||||
var (layout, grid, containers, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedBag(objects, 0xC, slot: 0, itemsCapacity: 1); // capacity 1...
|
||||
SeedContained(objects, 0xB0, 0xC, slot: 0); // ...and already full
|
||||
objects.AddOrUpdate(new ClientObject { ObjectId = 0xFFFFu });
|
||||
var ctrl = (IItemListDragHandler)Bind(layout, objects);
|
||||
|
||||
Assert.False(ctrl.OnDragOver(containers, containers.GetItem(0)!, Payload(0xFFFFu))); // full bag → red
|
||||
Assert.True(ctrl.OnDragOver(grid, grid.GetItem(0)!, Payload(0xFFFFu))); // grid → green
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnDragLift_isNoOp_itemStaysUntilServerConfirms()
|
||||
{
|
||||
var (layout, grid, _, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedContained(objects, 0xA, Player, slot: 0);
|
||||
var ctrl = (IItemListDragHandler)Bind(layout, objects);
|
||||
((IItemListDragHandler)ctrl).OnDragLift(grid, grid.GetItem(0)!, Payload(0xAu));
|
||||
Assert.Equal(Player, objects.Get(0xAu)!.ContainerId); // NOT removed on lift (unlike the toolbar)
|
||||
}
|
||||
|
||||
// Reads the text of the UiText caption child attached by the controller.
|
||||
private static string CaptionText(UiElement host)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue