using System.Buffers.Binary; namespace AcDream.Core.Net.Messages; /// /// Inbound PickupEvent GameMessage (opcode 0xF74A). /// /// /// ACE emits this from Player_Tracking.RemoveTrackedObject(wo, fromPickup: true) /// when a player picks up a world item — distinguishes the despawn /// from a generic 0xF747 DeleteObject (timeout / death / /// out-of-LOS). Downstream effect on the client view is the same /// (remove the entity from the world), so /// routes both opcodes to the same EntityDeleted event. /// /// /// /// Wire layout (ACE GameMessagePickupEvent.cs): /// /// u32 0xF74A /// u32 guid /// u16 objectInstanceSequence /// u16 objectPositionSequence /// /// /// public static class PickupEvent { public const uint Opcode = 0xF74Au; public readonly record struct Parsed( uint Guid, ushort InstanceSequence, ushort PositionSequence); public static Parsed? TryParse(ReadOnlySpan body) { if (body.Length < 12) return null; uint opcode = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(0, 4)); if (opcode != Opcode) return null; uint guid = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(4, 4)); ushort instanceSequence = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(8, 2)); ushort positionSequence = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(10, 2)); return new Parsed(guid, instanceSequence, positionSequence); } }