refactor(ui): D.2b-B — Populate uses GetContents only (drop test-driven fallback)
The implementer added a full-scan fallback in Populate() to accommodate a test that seeded items via AddOrUpdate (which deliberately does NOT touch the container index — only Ingest/MoveItem do). That was a production workaround for a faulty test, and inconsistent (it only triggered when the index was wholly empty). Root-fix: Populate reads GetContents(player) only — the index IS retail's per-container item list. The test now seeds via the faithful indexed path (AddOrUpdate + MoveItem → Reindex) through a SeedContained helper. 530 App tests green.
This commit is contained in:
parent
89c640a54d
commit
383e8b7b55
2 changed files with 22 additions and 31 deletions
|
|
@ -121,38 +121,19 @@ public sealed class InventoryController
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Retail gm*UI display refresh: partition the player's direct contents into loose
|
/// <summary>Retail gm*UI display refresh: partition the player's direct contents into loose
|
||||||
/// items (the "Contents of Backpack" grid) and side bags (the pack-selector list).
|
/// items (the "Contents of Backpack" grid) and side bags (the pack-selector list). The
|
||||||
/// Uses the container index when available (items ingested via Ingest/MoveItem) or
|
/// container index (<see cref="ClientObjectTable.GetContents"/>) IS retail's per-container
|
||||||
/// falls back to a full scan — both paths are correct for the two production flows.</summary>
|
/// item list — items enter it via the CreateObject (Ingest) / server-move (MoveItem) flows
|
||||||
|
/// that call Reindex, slot-sorted.</summary>
|
||||||
public void Populate()
|
public void Populate()
|
||||||
{
|
{
|
||||||
uint p = _playerGuid();
|
uint p = _playerGuid();
|
||||||
|
var contents = _objects.GetContents(p);
|
||||||
// GetContents returns indexed + slot-sorted items (the production path via Ingest).
|
|
||||||
// For AddOrUpdate-seeded items (tests + initial populate before indexing), we fall
|
|
||||||
// back to scanning all objects with ContainerId == p, sorted by slot.
|
|
||||||
var indexed = _objects.GetContents(p);
|
|
||||||
IEnumerable<uint> guids;
|
|
||||||
if (indexed.Count > 0)
|
|
||||||
{
|
|
||||||
guids = indexed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var direct = new List<(int slot, uint id)>();
|
|
||||||
foreach (var o in _objects.Objects)
|
|
||||||
if (o.ContainerId == p)
|
|
||||||
direct.Add((o.ContainerSlot, o.ObjectId));
|
|
||||||
direct.Sort((a, b) => a.slot.CompareTo(b.slot));
|
|
||||||
var ids = new List<uint>(direct.Count);
|
|
||||||
foreach (var (_, id) in direct) ids.Add(id);
|
|
||||||
guids = ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
_contentsGrid?.Flush();
|
_contentsGrid?.Flush();
|
||||||
_containerList?.Flush();
|
_containerList?.Flush();
|
||||||
|
|
||||||
foreach (var guid in guids)
|
foreach (var guid in contents)
|
||||||
{
|
{
|
||||||
var item = _objects.Get(guid);
|
var item = _objects.Get(guid);
|
||||||
if (item is null) continue;
|
if (item is null) continue;
|
||||||
|
|
|
||||||
|
|
@ -54,17 +54,27 @@ public class InventoryControllerTests
|
||||||
iconIds: (_, _, _, _, _) => 0u, // no real GL upload in tests
|
iconIds: (_, _, _, _, _) => 0u, // no real GL upload in tests
|
||||||
strength: () => strength, datFont: null);
|
strength: () => strength, datFont: null);
|
||||||
|
|
||||||
|
// Place an object in a container at a slot via the faithful production path:
|
||||||
|
// AddOrUpdate registers it, MoveItem sets ContainerId+ContainerSlot and calls Reindex
|
||||||
|
// (the same machinery server-driven moves use), so GetContents returns it slot-ordered.
|
||||||
|
private static void SeedContained(ClientObjectTable t, uint guid, uint container, int slot,
|
||||||
|
int burden = 0, ItemType type = ItemType.None)
|
||||||
|
{
|
||||||
|
t.AddOrUpdate(new ClientObject { ObjectId = guid, Burden = burden, Type = type });
|
||||||
|
t.MoveItem(guid, container, slot);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Populate_fills_contents_grid_with_loose_items_only()
|
public void Populate_fills_contents_grid_with_loose_items_only()
|
||||||
{
|
{
|
||||||
var (layout, grid, containers, _, _, _, _, _) = BuildLayout();
|
var (layout, grid, containers, _, _, _, _, _) = BuildLayout();
|
||||||
var objects = new ClientObjectTable();
|
var objects = new ClientObjectTable();
|
||||||
objects.AddOrUpdate(new ClientObject { ObjectId = 0xA, ContainerId = Player,
|
// Seed via the indexed path: AddOrUpdate registers the object, MoveItem places it in
|
||||||
ContainerSlot = 0, Burden = 10 }); // loose
|
// the container at a slot (the faithful "server moved item into container" flow that
|
||||||
objects.AddOrUpdate(new ClientObject { ObjectId = 0xB, ContainerId = Player,
|
// calls Reindex). GetContents — retail's per-container list — then returns them ordered.
|
||||||
ContainerSlot = 1, Burden = 20 }); // loose
|
SeedContained(objects, 0xA, Player, slot: 0, burden: 10); // loose
|
||||||
objects.AddOrUpdate(new ClientObject { ObjectId = 0xC, ContainerId = Player,
|
SeedContained(objects, 0xB, Player, slot: 1, burden: 20); // loose
|
||||||
ContainerSlot = 2, Type = ItemType.Container }); // side bag
|
SeedContained(objects, 0xC, Player, slot: 2, type: ItemType.Container); // side bag
|
||||||
|
|
||||||
Bind(layout, objects);
|
Bind(layout, objects);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue