feat(net): D.2b-B B-Wire — register ViewContents + InventoryPutObjectIn3D/SaveFailed/CloseGroundContainer

Register four previously-unwired GameEvent handlers after InventoryPutObjInContainer:

- ViewContents (0x0196): iterates ParseViewContents entries and calls
  items.RecordMembership(entry.Guid, containerId) for each — so the
  object table is correct before the container-open UI mounts.
- InventoryPutObjectIn3D (0x019A): calls items.MoveItem(guid, 0u) to
  unparent a dropped item from its container (it's now a ground object).
- InventoryServerSaveFailed (0x00A0): parse + log; rollback behavior
  deferred to B-Drag (acdream has no speculative moves yet).
- CloseGroundContainer (0x0052): parse + log; no table change needed
  (the container-open view is UI-only).

Two dispatcher tests cover ViewContents membership and Put3D unparenting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-21 19:01:53 +02:00
parent d97d84d7ca
commit 3a9c188233
2 changed files with 75 additions and 0 deletions

View file

@ -249,6 +249,46 @@ public static class GameEventWiring
if (p is not null) items.MoveItem(p.Value.ItemGuid, p.Value.ContainerGuid,
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.
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);
});
// B-Wire: InventoryPutObjectIn3D (0x019A) — server confirms an item dropped
// to the world. Unparent it from its container (it's now a ground object) so
// the inventory grid drops the cell; the object itself survives.
dispatcher.Register(GameEventType.InventoryPutObjectIn3D, e =>
{
var guid = GameEvents.ParsePutObjectIn3D(e.Payload.Span);
if (guid is not null) items.MoveItem(guid.Value, newContainerId: 0u);
});
// B-Wire: InventoryServerSaveFailed (0x00A0) — rollback of a speculative move.
// acdream does not do speculative moves yet (read-only inventory); parse + log
// so the wire is correct. B-Drag wires the rollback behavior. (Divergence note.)
dispatcher.Register(GameEventType.InventoryServerSaveFailed, e =>
{
var p = GameEvents.ParseInventoryServerSaveFailed(e.Payload.Span);
if (p is not null)
Console.WriteLine($"[B-Wire] InventoryServerSaveFailed guid=0x{p.Value.ItemGuid:X8} err=0x{p.Value.WeenieError:X}");
});
// B-Wire: CloseGroundContainer (0x0052) — server closed a ground-container
// view. No table change (the view is UI-only, wired in container-open); log.
dispatcher.Register(GameEventType.CloseGroundContainer, e =>
{
var guid = GameEvents.ParseCloseGroundContainer(e.Payload.Span);
if (guid is not null)
Console.WriteLine($"[B-Wire] CloseGroundContainer guid=0x{guid.Value:X8}");
});
dispatcher.Register(GameEventType.IdentifyObjectResponse, e =>
{
var p = AppraiseInfoParser.TryParse(e.Payload.Span);