using System; using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using MessagePack; using Mistox.Attributes; namespace Mistox { [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DataPacketHeader { public ushort Type { get; set; } public ushort DataLength { get; set; } } public class DataPacket { // The length of the packet header in bytes public static int HeaderLength => Unsafe.SizeOf(); // Helper classes public static byte[] Serialize( T Object ) { // Use an expandable buffer writer from the system stack var writer = new ArrayBufferWriter(256); // Advance the writer past the header slot so MessagePack doesn't overwrite it writer.Advance(HeaderLength); // Serialize the payload DIRECTLY into the final buffer memory MessagePackSerializer.Serialize(writer, Object); // Build our header struct on the stack DataPacketHeader header = new DataPacketHeader { Type = NetworkPacketDictionary.PacketIDTable[typeof(T)], DataLength = (ushort)(writer.WrittenCount - HeaderLength) }; // Map the struct directly onto the reservation we left at the front writer.WrittenMemory.Slice(0, HeaderLength); MemoryMarshal.Write(writer.GetSpan(HeaderLength).Slice(0, HeaderLength), in header); // 7. Extract the finished byte array. // Note: In a production socket pipeline, you would pass writer.WrittenMemory directly // to the socket instead of converting it to an array here! return writer.WrittenSpan.ToArray(); } public static object? Deserialize( DataPacketHeader Header, ReadOnlyMemory Data ) { // Get the type from the tag if (!NetworkPacketDictionary.PacketLookupTable.TryGetValue(Header.Type, out Type? resolvedType)) { throw new Exception($"Unknown packet type ID: {Header.Type}"); } // Ensure the packet we received actually has the payload bytes it claims to have if ( Header.DataLength < Data.Length ) { throw new Exception("Malformed packet: Payload size mismatch."); } // Make sure the data is exactly the size requested ReadOnlyMemory payloadSlice = Data.Slice(0, Header.DataLength); // Create the low-level reader struct directly over the memory slice var reader = new MessagePackReader(payloadSlice); // Extract the object return MessagePackSerializer.Deserialize( resolvedType, ref reader, MessagePackSerializerOptions.Standard ); } } }