From e8a20f26c75bace7a1ebd42cea1f725647cac4f7 Mon Sep 17 00:00:00 2001 From: Erik Date: Thu, 14 May 2026 15:01:24 +0200 Subject: [PATCH] =?UTF-8?q?feat(B.5):=20InteractRequests.BuildPickUp=20?= =?UTF-8?q?=E2=80=94=20PutItemInContainer=200x0019?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TDD: failing test first (CS0117 on BuildPickUp + PutItemInContainerOpcode), then implementation. Wire layout matches ACE GameActionPutItemInContainer: 0xF7B1 envelope + seq + 0x0019 opcode + itemGuid + containerGuid + placement (24 bytes). For F-key ground-pickup, caller passes player's server guid as containerGuid; Task 2 (GameWindow wiring) will handle that dispatch. Co-Authored-By: Claude Sonnet 4.6 --- .../Messages/InteractRequests.cs | 33 +++++++++++++++++++ .../Messages/InteractRequestsTests.cs | 24 ++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/AcDream.Core.Net/Messages/InteractRequests.cs b/src/AcDream.Core.Net/Messages/InteractRequests.cs index d9cfe7b..68b3b1e 100644 --- a/src/AcDream.Core.Net/Messages/InteractRequests.cs +++ b/src/AcDream.Core.Net/Messages/InteractRequests.cs @@ -29,6 +29,7 @@ public static class InteractRequests public const uint UseOpcode = 0x0036u; public const uint UseWithTargetOpcode = 0x0035u; public const uint TeleToLifestoneOpcode = 0x0063u; + public const uint PutItemInContainerOpcode = 0x0019u; /// /// Use an object: click a door, loot a corpse, talk to an NPC, @@ -73,4 +74,36 @@ public static class InteractRequests BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(8), TeleToLifestoneOpcode); return body; } + + /// + /// Pick up a ground item or move an item between containers. The + /// server places the item in at + /// the given slot (pass 0 to let the + /// server choose). For F-key ground-pickup, pass the player's own + /// server guid as . + /// + /// + /// Wire layout (ACE GameActionPutItemInContainer.Handle): + /// + /// u32 0xF7B1 + /// u32 gameActionSequence + /// u32 0x0019 // PutItemInContainer + /// u32 itemGuid // server guid of the item + /// u32 containerGuid // destination container (player or bag) + /// i32 placement // 0 = server picks slot + /// + /// + /// + public static byte[] BuildPickUp( + uint gameActionSequence, uint itemGuid, uint containerGuid, int placement) + { + byte[] body = new byte[24]; + BinaryPrimitives.WriteUInt32LittleEndian(body, GameActionEnvelope); + BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(4), gameActionSequence); + BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(8), PutItemInContainerOpcode); + BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(12), itemGuid); + BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(16), containerGuid); + BinaryPrimitives.WriteInt32LittleEndian (body.AsSpan(20), placement); + return body; + } } diff --git a/tests/AcDream.Core.Net.Tests/Messages/InteractRequestsTests.cs b/tests/AcDream.Core.Net.Tests/Messages/InteractRequestsTests.cs index 5e99b5d..f251cf4 100644 --- a/tests/AcDream.Core.Net.Tests/Messages/InteractRequestsTests.cs +++ b/tests/AcDream.Core.Net.Tests/Messages/InteractRequestsTests.cs @@ -42,4 +42,28 @@ public sealed class InteractRequestsTests Assert.Equal(InteractRequests.TeleToLifestoneOpcode, BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(8))); } + + [Fact] + public void BuildPickUp_WritesOpcode0x0019AndPayload() + { + byte[] body = InteractRequests.BuildPickUp( + gameActionSequence: 5, + itemGuid: 0xABCDu, + containerGuid: 0x5000000Au, + placement: 0); + + Assert.Equal(24, body.Length); + Assert.Equal(InteractRequests.GameActionEnvelope, + BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(0))); + Assert.Equal(5u, + BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(4))); + Assert.Equal(InteractRequests.PutItemInContainerOpcode, + BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(8))); + Assert.Equal(0xABCDu, + BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(12))); + Assert.Equal(0x5000000Au, + BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(16))); + Assert.Equal(0, + BinaryPrimitives.ReadInt32LittleEndian(body.AsSpan(20))); + } }