diff --git a/src/AcDream.Core.Net/GameEventWiring.cs b/src/AcDream.Core.Net/GameEventWiring.cs index 0413611d..6676f0a1 100644 --- a/src/AcDream.Core.Net/GameEventWiring.cs +++ b/src/AcDream.Core.Net/GameEventWiring.cs @@ -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); diff --git a/tests/AcDream.Core.Net.Tests/GameEventWiringTests.cs b/tests/AcDream.Core.Net.Tests/GameEventWiringTests.cs index ca0a54db..96ae5a54 100644 --- a/tests/AcDream.Core.Net.Tests/GameEventWiringTests.cs +++ b/tests/AcDream.Core.Net.Tests/GameEventWiringTests.cs @@ -535,4 +535,39 @@ public sealed class GameEventWiringTests Assert.Equal(1500, player!.Properties.Ints[5]); } + [Fact] + public void WireAll_ViewContents_RecordsMembershipInClientObjectTable() + { + var (d, items, _, _, _) = MakeAll(); + + // containerGuid 0xC9 + 2 entries + byte[] payload = new byte[8 + 2 * 8]; + BinaryPrimitives.WriteUInt32LittleEndian(payload.AsSpan(0), 0x500000C9u); + BinaryPrimitives.WriteUInt32LittleEndian(payload.AsSpan(4), 2u); + BinaryPrimitives.WriteUInt32LittleEndian(payload.AsSpan(8), 0x50000A01u); + BinaryPrimitives.WriteUInt32LittleEndian(payload.AsSpan(12), 0u); + BinaryPrimitives.WriteUInt32LittleEndian(payload.AsSpan(16), 0x50000A02u); + BinaryPrimitives.WriteUInt32LittleEndian(payload.AsSpan(20), 1u); + + var env = GameEventEnvelope.TryParse(WrapEnvelope(GameEventType.ViewContents, payload)); + d.Dispatch(env!.Value); + + Assert.Equal(0x500000C9u, items.Get(0x50000A01u)!.ContainerId); + Assert.Equal(0x500000C9u, items.Get(0x50000A02u)!.ContainerId); + } + + [Fact] + public void WireAll_InventoryPutObjectIn3D_UnparentsFromContainer() + { + var (d, items, _, _, _) = MakeAll(); + items.RecordMembership(0x50000A01u, containerId: 0x500000C9u); + + byte[] payload = new byte[4]; + BinaryPrimitives.WriteUInt32LittleEndian(payload, 0x50000A01u); + var env = GameEventEnvelope.TryParse(WrapEnvelope(GameEventType.InventoryPutObjectIn3D, payload)); + d.Dispatch(env!.Value); + + Assert.Equal(0u, items.Get(0x50000A01u)!.ContainerId); + } + }