From 01910e3fabdca97eb717c3aadfadb9f665fe68b8 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 21 Jun 2026 18:55:14 +0200 Subject: [PATCH] =?UTF-8?q?fix(net):=20D.2b-B=20B-Wire=20=E2=80=94=20Parse?= =?UTF-8?q?PutObjInContainer=20reads=20containerType=20(4th=20field)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0x0022 InventoryPutObjInContainer carries 4 u32s per ACE GameEventItemServerSaysContainId.cs: itemGuid, containerGuid, placement, containerType. The parser was reading only 3 (12 bytes) and silently dropping containerType. Fixed the record struct to add ContainerType and raised the length guard to 16. GameEventWiring caller uses only .ItemGuid/.ContainerGuid/.Placement — adding a positional field is source-compatible. 1 new test in GameEventsInventoryTests. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/AcDream.Core.Net/Messages/GameEvents.cs | 13 +++++++++---- .../Messages/GameEventsInventoryTests.cs | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/AcDream.Core.Net/Messages/GameEvents.cs b/src/AcDream.Core.Net/Messages/GameEvents.cs index bd28a283..edb98809 100644 --- a/src/AcDream.Core.Net/Messages/GameEvents.cs +++ b/src/AcDream.Core.Net/Messages/GameEvents.cs @@ -343,19 +343,24 @@ public static class GameEvents BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(8))); } - /// 0x0022 InventoryPutObjInContainer: server puts item into container slot. + /// 0x0022 InventoryPutObjInContainer: server puts item into container slot. + /// 4 fields (ACE GameEventItemServerSaysContainId.cs): itemGuid, containerGuid, + /// placement, containerType. ContainerType (0=item,1=container,2=foci) confirmed + /// vs holtburger events.rs fixture (slot=3 type=1). public readonly record struct InventoryPutObjInContainer( uint ItemGuid, uint ContainerGuid, - uint Placement); + uint Placement, + uint ContainerType); public static InventoryPutObjInContainer? ParsePutObjInContainer(ReadOnlySpan payload) { - if (payload.Length < 12) return null; + if (payload.Length < 16) return null; return new InventoryPutObjInContainer( BinaryPrimitives.ReadUInt32LittleEndian(payload), BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(4)), - BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(8))); + BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(8)), + BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(12))); } /// 0x0196 ViewContents: full contents list of a container you opened. diff --git a/tests/AcDream.Core.Net.Tests/Messages/GameEventsInventoryTests.cs b/tests/AcDream.Core.Net.Tests/Messages/GameEventsInventoryTests.cs index 5a49b53a..c77f646b 100644 --- a/tests/AcDream.Core.Net.Tests/Messages/GameEventsInventoryTests.cs +++ b/tests/AcDream.Core.Net.Tests/Messages/GameEventsInventoryTests.cs @@ -42,4 +42,21 @@ public sealed class GameEventsInventoryTests [Fact] public void ParseViewContents_truncated_returnsNull() => Assert.Null(GameEvents.ParseViewContents(new byte[4])); + + [Fact] + public void ParsePutObjInContainer_readsAllFourFields() + { + var b = new byte[16]; + BinaryPrimitives.WriteUInt32LittleEndian(b.AsSpan(0), 0x50000A01u); // itemGuid + BinaryPrimitives.WriteUInt32LittleEndian(b.AsSpan(4), 0x500000C9u); // containerGuid + BinaryPrimitives.WriteUInt32LittleEndian(b.AsSpan(8), 3u); // placement + BinaryPrimitives.WriteUInt32LittleEndian(b.AsSpan(12), 1u); // containerType + + var p = GameEvents.ParsePutObjInContainer(b); + Assert.NotNull(p); + Assert.Equal(0x50000A01u, p!.Value.ItemGuid); + Assert.Equal(0x500000C9u, p.Value.ContainerGuid); + Assert.Equal(3u, p.Value.Placement); + Assert.Equal(1u, p.Value.ContainerType); + } }