77 lines
2.9 KiB
C#
77 lines
2.9 KiB
C#
using System;
|
|
using System.Buffers;
|
|
using System.Reflection;
|
|
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<DataPacketHeader>();
|
|
|
|
public DataPacketHeader Header { get; set; }
|
|
public dynamic Data { get; set; }
|
|
|
|
// Helper classes
|
|
public static byte[] Serialize<T>( T Object ) {
|
|
|
|
// Use an expandable buffer writer from the system stack
|
|
var writer = new ArrayBufferWriter<byte>(256);
|
|
|
|
// Advance the writer past the 3-byte 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 3-byte 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<byte> 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<byte> 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 );
|
|
|
|
}
|
|
|
|
}
|
|
} |