acdream/tests/AcDream.Core.Net.Tests/Messages/PickupEventTests.cs
Erik f7636a9e78 fix(B.5): handle PickupEvent 0xF74A so picked-up items despawn locally
ACE sends GameMessagePickupEvent (opcode 0xF74A) instead of
GameMessageDeleteObject (0xF747) for items removed via player pickup
(Player_Tracking.RemoveTrackedObject with fromPickup=true).

Without this handler, BuildPickUp succeeded server-side (item moved
into the player's container, retail observers saw it disappear), but
our local client kept rendering it on the ground because the despawn
message went to the unhandled-opcode bucket.

PickupEvent's wire body adds an objectPositionSequence field on top
of DeleteObject's layout, so the parser is its own type. The
downstream view-removal semantics are identical to DeleteObject, so
the dispatcher routes both opcodes into the same EntityDeleted event
via a small adapter.
2026-05-14 16:13:16 +02:00

41 lines
1.2 KiB
C#

using System.Buffers.Binary;
using AcDream.Core.Net.Messages;
using Xunit;
namespace AcDream.Core.Net.Tests.Messages;
public sealed class PickupEventTests
{
[Fact]
public void RejectsWrongOpcode()
{
Span<byte> body = stackalloc byte[12];
BinaryPrimitives.WriteUInt32LittleEndian(body, 0xDEADBEEFu);
Assert.Null(PickupEvent.TryParse(body));
}
[Fact]
public void RejectsTruncated()
{
Assert.Null(PickupEvent.TryParse(ReadOnlySpan<byte>.Empty));
Assert.Null(PickupEvent.TryParse(new byte[11]));
}
[Fact]
public void ParsesGuidAndSequences()
{
Span<byte> body = stackalloc byte[12];
BinaryPrimitives.WriteUInt32LittleEndian(body, PickupEvent.Opcode);
BinaryPrimitives.WriteUInt32LittleEndian(body.Slice(4), 0x80000727u);
BinaryPrimitives.WriteUInt16LittleEndian(body.Slice(8), 0x1234);
BinaryPrimitives.WriteUInt16LittleEndian(body.Slice(10), 0x5678);
var parsed = PickupEvent.TryParse(body);
Assert.NotNull(parsed);
Assert.Equal(0x80000727u, parsed!.Value.Guid);
Assert.Equal((ushort)0x1234, parsed.Value.InstanceSequence);
Assert.Equal((ushort)0x5678, parsed.Value.PositionSequence);
}
}