Snowflake/RPG.Services.Gateserver/Network/NetPacket.cs

68 lines
2.3 KiB
C#

using System.Buffers.Binary;
namespace RPG.Services.Gateserver.Network;
internal class NetPacket
{
public const int Overhead = 16;
private const uint HeadMagic = 0x01234567;
private const uint TailMagic = 0x89ABCDEF;
public ushort CmdType { get; }
public ReadOnlyMemory<byte> Head { get; }
public ReadOnlyMemory<byte> Body { get; }
public int Size => Overhead + Head.Length + Body.Length;
public NetPacket(ushort cmdType, ReadOnlyMemory<byte> head, ReadOnlyMemory<byte> body)
{
CmdType = cmdType;
Head = head;
Body = body;
}
public static DeserializationResult TryDeserialize(ReadOnlyMemory<byte> buffer, out NetPacket? packet, out int bytesRead)
{
packet = null;
bytesRead = 0;
if (buffer.Length < Overhead) return DeserializationResult.BufferExceeded;
ReadOnlySpan<byte> span = buffer.Span;
if (BinaryPrimitives.ReadUInt32BigEndian(span[..4]) != HeadMagic) return DeserializationResult.Corrupted;
ushort cmdType = BinaryPrimitives.ReadUInt16BigEndian(span[4..6]);
int headSize = BinaryPrimitives.ReadUInt16BigEndian(span[6..8]);
int bodySize = BinaryPrimitives.ReadInt32BigEndian(span[8..12]);
if (buffer.Length < Overhead + headSize + bodySize) return DeserializationResult.BufferExceeded;
if (BinaryPrimitives.ReadUInt32BigEndian(span[(12 + headSize + bodySize)..]) != TailMagic) return DeserializationResult.Corrupted;
packet = new(cmdType, buffer.Slice(12, headSize), buffer.Slice(12 + headSize, bodySize));
bytesRead = Overhead + headSize + bodySize;
return DeserializationResult.Success;
}
public void Serialize(Memory<byte> buffer)
{
Span<byte> span = buffer.Span;
BinaryPrimitives.WriteUInt32BigEndian(span[..4], HeadMagic);
BinaryPrimitives.WriteUInt16BigEndian(span[4..6], CmdType);
BinaryPrimitives.WriteUInt16BigEndian(span[6..8], (ushort)Head.Length);
BinaryPrimitives.WriteInt32BigEndian(span[8..12], Body.Length);
Head.CopyTo(buffer[12..]);
Body.CopyTo(buffer[(12 + Head.Length)..]);
BinaryPrimitives.WriteUInt32BigEndian(span[(12 + Head.Length + Body.Length)..], TailMagic);
}
public enum DeserializationResult
{
Success,
BufferExceeded,
Corrupted
}
}