feat(D.2b): ViewContents wiring is a full REPLACE (consumes the GameEventWiring TODO)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-22 14:28:08 +02:00
parent 48bf752cf1
commit ad9d2651c1
2 changed files with 37 additions and 9 deletions

View file

@ -250,19 +250,18 @@ public static class GameEventWiring
newSlot: (int)p.Value.Placement);
});
// B-Wire: ViewContents (0x0196) — the server's full contents list for a
// container you opened. Record membership for each entry so the table is
// correct before the container-open UI mounts the second item list.
// TODO(container-open): ViewContents is the AUTHORITATIVE full snapshot. When the
// container-open phase consumes it, treat it as a full REPLACE (flush the container's
// prior membership first), not the additive merge below — otherwise items removed
// server-side since the last open would linger.
// ViewContents (0x0196) — the server's AUTHORITATIVE full contents list for a container you
// opened (Use 0x0036). Treat it as a full REPLACE: flush the container's prior membership and
// record the new entries in order (ContainerSlot = index — ACE writes entries
// OrderBy(PlacementPosition) with no slot field). The container-open UI (InventoryController)
// repaints the grid off the resulting ObjectAdded/Moved events. Retail: ClientUISystem::OnViewContents.
dispatcher.Register(GameEventType.ViewContents, e =>
{
var p = GameEvents.ParseViewContents(e.Payload.Span);
if (p is null) return;
foreach (var entry in p.Value.Items)
items.RecordMembership(entry.Guid, containerId: p.Value.ContainerGuid);
var guids = new uint[p.Value.Items.Count];
for (int i = 0; i < guids.Length; i++) guids[i] = p.Value.Items[i].Guid;
items.ReplaceContents(p.Value.ContainerGuid, guids);
});
// B-Wire: InventoryPutObjectIn3D (0x019A) — server confirms an item dropped