Untested conversion to variable size packets

This commit is contained in:
Sanae 2022-03-10 23:59:02 -06:00
parent 713e5f4cce
commit 8c5cd0ced2
16 changed files with 132 additions and 99 deletions

View File

@ -1,6 +1,7 @@
using System.Buffers;
using System.Collections.Concurrent;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using Shared;
using Shared.Packet;
using Shared.Packet.Packets;
@ -36,25 +37,26 @@ public class Client : IDisposable {
public event PacketTransformerDel? PacketTransformer;
public async Task Send<T>(T packet, Client? sender = null) where T : struct, IPacket {
IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize);
IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.RentZero(Constants.HeaderSize + packet.Size);
packet = (T) (PacketTransformer?.Invoke(sender, packet) ?? packet);
PacketHeader header = new PacketHeader {
Id = sender?.Id ?? Guid.Empty,
Type = Constants.PacketMap[typeof(T)].Type
Type = Constants.PacketMap[typeof(T)].Type,
PacketSize = packet.Size
};
Server.FillPacket(header, packet, memory.Memory);
await Send(memory.Memory[..Constants.MaxPacketSize], sender);
await Send(memory.Memory[..], sender);
memory.Dispose();
}
public async Task Send(ReadOnlyMemory<byte> data, Client? sender) {
if (!Connected) {
Server.Logger.Info($"Didn't send {(PacketType) data.Span[16]} to {Id} because they weren't connected yet");
Server.Logger.Info($"Didn't send {MemoryMarshal.Read<PacketType>(data.Span[16..])} to {Id} because they weren't connected yet");
return;
}
// Server.Logger.Info($"Sending {(PacketType) data.Span[16]} to {Id} from {other?.Id.ToString() ?? "server"}");
await Socket!.SendAsync(data[..Constants.MaxPacketSize], SocketFlags.None);
int packetSize = MemoryMarshal.Read<short>(data.Span[18..]);
await Socket!.SendAsync(data[..(Constants.HeaderSize + packetSize)], SocketFlags.None);
}
public static bool operator ==(Client? left, Client? right) {

View File

@ -78,11 +78,11 @@ public class Server {
}
public async Task Broadcast<T>(T packet, Client sender) where T : struct, IPacket {
IMemoryOwner<byte> memory = memoryPool.RentZero(Constants.MaxPacketSize);
IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.RentZero(Constants.HeaderSize + packet.Size);
PacketHeader header = new PacketHeader {
Id = sender?.Id ?? Guid.Empty,
Type = Constants.PacketMap[typeof(T)].Type
Type = Constants.PacketMap[typeof(T)].Type,
PacketSize = packet.Size
};
FillPacket(header, packet, memory.Memory);
await Broadcast(memory, sender);
@ -118,11 +118,12 @@ public class Server {
bool first = true;
try {
while (true) {
memory = memoryPool.Rent(Constants.MaxPacketSize);
{
int readOffset = 0;
while (readOffset < Constants.MaxPacketSize) {
int size = await socket.ReceiveAsync(memory.Memory[readOffset..Constants.MaxPacketSize], SocketFlags.None);
memory = memoryPool.Rent(Constants.HeaderSize);
async Task Read(Memory<byte> readMem, int readOffset = 0, int readSize = -1) {
if (readSize == -1) readSize = Constants.HeaderSize;
while (readOffset < readSize) {
int size = await socket.ReceiveAsync(readMem[readOffset..readSize], SocketFlags.None);
if (size == 0) {
// treat it as a disconnect and exit
Logger.Info($"Socket {socket.RemoteEndPoint} disconnected.");
@ -132,11 +133,17 @@ public class Server {
readOffset += size;
}
if (readOffset < Constants.MaxPacketSize) break;
}
PacketHeader header = GetHeader(memory.Memory.Span[..Constants.MaxPacketSize]);
await Read(memory.Memory[..Constants.HeaderSize]);
PacketHeader header = GetHeader(memory.Memory.Span[..Constants.HeaderSize]);
{
IMemoryOwner<byte> memTemp = memory;
memory = memoryPool.Rent(Constants.HeaderSize + header.Size);
memTemp.Memory.CopyTo(memory.Memory);
memTemp.Dispose();
}
await Read(memory.Memory[Constants.HeaderSize..(Constants.HeaderSize + header.Size)]);
// connection initialization
if (first) {
@ -144,7 +151,7 @@ public class Server {
if (header.Type != PacketType.Connect) throw new Exception($"First packet was not init, instead it was {header.Type}");
ConnectPacket connect = new ConnectPacket();
connect.Deserialize(memory.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]);
connect.Deserialize(memory.Memory.Span[Constants.HeaderSize..(Constants.HeaderSize + header.PacketSize)]);
lock (Clients) {
client.Name = connect.ClientName;
bool firstConn = false;
@ -188,10 +195,11 @@ public class Server {
List<Client> otherConnectedPlayers = Clients.FindAll(c => c.Id != header.Id && c.Connected && c.Socket != null);
await Parallel.ForEachAsync(otherConnectedPlayers, async (other, _) => {
IMemoryOwner<byte> tempBuffer = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize);
IMemoryOwner<byte> tempBuffer = MemoryPool<byte>.Shared.RentZero(Constants.HeaderSize + (other.CurrentCostume.HasValue ? Math.Max(connect.Size, other.CurrentCostume.Value.Size) : connect.Size));
PacketHeader connectHeader = new PacketHeader {
Id = other.Id,
Type = PacketType.Connect
Type = PacketType.Connect,
PacketSize = connect.Size
};
MemoryMarshal.Write(tempBuffer.Memory.Span, ref connectHeader);
ConnectPacket connectPacket = new ConnectPacket {
@ -199,12 +207,13 @@ public class Server {
ClientName = other.Name
};
connectPacket.Serialize(tempBuffer.Memory.Span[Constants.HeaderSize..]);
await client.Send(tempBuffer.Memory, null);
await client.Send(tempBuffer.Memory[..(Constants.HeaderSize + connect.Size)], null);
if (other.CurrentCostume.HasValue) {
connectHeader.Type = PacketType.Costume;
connectHeader.PacketSize = other.CurrentCostume.Value.Size;
MemoryMarshal.Write(tempBuffer.Memory.Span, ref connectHeader);
other.CurrentCostume.Value.Serialize(tempBuffer.Memory.Span[Constants.HeaderSize..]);
await client.Send(tempBuffer.Memory, null);
other.CurrentCostume.Value.Serialize(tempBuffer.Memory.Span[Constants.HeaderSize..(Constants.HeaderSize + connectHeader.PacketSize)]);
await client.Send(tempBuffer.Memory[..(Constants.HeaderSize + connectHeader.PacketSize)], null);
}
tempBuffer.Dispose();
@ -219,14 +228,14 @@ public class Server {
CostumePacket costumePacket = new CostumePacket {
BodyName = ""
};
costumePacket.Deserialize(memory.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]);
costumePacket.Deserialize(memory.Memory.Span[Constants.HeaderSize..(Constants.HeaderSize + costumePacket.Size)]);
client.CurrentCostume = costumePacket;
}
try {
// if (header.Type is not PacketType.Cap and not PacketType.Player) client.Logger.Warn($"lol {header.Type}");
IPacket packet = (IPacket) Activator.CreateInstance(Constants.PacketIdMap[header.Type])!;
packet.Deserialize(memory.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]);
packet.Deserialize(memory.Memory.Span[Constants.HeaderSize..(Constants.HeaderSize + packet.Size)]);
if (PacketHandler?.Invoke(client, packet) is false) {
memory.Dispose();
continue;

View File

@ -6,7 +6,6 @@ using Shared.Packet.Packets;
namespace Shared;
public static class Constants {
public const int MaxPacketSize = 256;
public const int MaxClients = 8;
public const int CostumeNameSize = 0x20;
@ -23,5 +22,4 @@ public static class Constants {
.ToDictionary(type => type.GetCustomAttribute<PacketAttribute>()!.Type, type => type);
public static int HeaderSize { get; } = Marshal.SizeOf<PacketHeader>();
public static int PacketDataSize { get; } = MaxPacketSize - HeaderSize;
}

View File

@ -8,6 +8,9 @@ public struct PacketHeader : IPacket {
// public int Length;
public Guid Id;
public PacketType Type;
public short PacketSize;
public short Size => 20;
public void Serialize(Span<byte> data) {
// MemoryMarshal.Write(data, ref Length);
@ -18,5 +21,6 @@ public struct PacketHeader : IPacket {
public void Deserialize(Span<byte> data) {
Id = MemoryMarshal.Read<Guid>(data);
Type = MemoryMarshal.Read<PacketType>(data[16..]);
Type = MemoryMarshal.Read<PacketType>(data[16..]);
}
}

View File

@ -1,6 +1,6 @@
namespace Shared.Packet;
public enum PacketType {
public enum PacketType : short {
Unknown,
Player,
Cap,

View File

@ -11,6 +11,8 @@ public struct CapPacket : IPacket {
public Quaternion Rotation;
public string CapAnim;
public short Size => 0x4C;
public void Serialize(Span<byte> data) {
MemoryMarshal.Write(data, ref Position);
MemoryMarshal.Write(data[12..], ref Position);

View File

@ -10,6 +10,7 @@ public struct CapturePacket : IPacket {
public bool IsCaptured;
public short Size => Constants.CostumeNameSize + 1;
public void Serialize(Span<byte> data) {
Encoding.UTF8.GetBytes(ModelName).CopyTo(data[..Constants.CostumeNameSize]);
MemoryMarshal.Write(data[Constants.CostumeNameSize..], ref IsCaptured);
@ -19,4 +20,5 @@ public struct CapturePacket : IPacket {
ModelName = Encoding.UTF8.GetString(data[..Constants.CostumeNameSize]).TrimNullTerm();
IsCaptured = MemoryMarshal.Read<bool>(data[Constants.CostumeNameSize..]);
}
}

View File

@ -10,6 +10,8 @@ public struct ConnectPacket : IPacket {
public ConnectPacket() { }
public short Size => 4 + Constants.CostumeNameSize;
public void Serialize(Span<byte> data) {
MemoryMarshal.Write(data, ref ConnectionType);
Encoding.UTF8.GetBytes(ClientName).CopyTo(data[4..(4 + Constants.CostumeNameSize)]);

View File

@ -11,6 +11,8 @@ public struct CostumePacket : IPacket {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.CostumeNameSize)]
public string CapName;
public short Size => Constants.CostumeNameSize * 2;
public void Serialize(Span<byte> data) {
Encoding.UTF8.GetBytes(BodyName).CopyTo(data[..Constants.CostumeNameSize]);
Encoding.UTF8.GetBytes(CapName).CopyTo(data[Constants.CostumeNameSize..]);

View File

@ -3,6 +3,7 @@
[Packet(PacketType.Disconnect)]
public struct DisconnectPacket : IPacket {
//empty packet
public short Size => 0;
public void Serialize(Span<byte> data) { }
public void Deserialize(Span<byte> data) { }

View File

@ -2,6 +2,7 @@
// Packet interface for type safety
public interface IPacket {
short Size { get; }
void Serialize(Span<byte> data);
void Deserialize(Span<byte> data);
}

View File

@ -35,6 +35,8 @@ public struct PlayerPacket : IPacket {
public PlayerPacket() { }
public short Size => 0xE0;
public void Serialize(Span<byte> data) {
int offset = 0;
MemoryMarshal.Write(data, ref Position);

View File

@ -6,6 +6,8 @@ namespace Shared.Packet.Packets;
public struct ShinePacket : IPacket {
public int ShineId;
public short Size => 4;
public void Serialize(Span<byte> data) {
MemoryMarshal.Write(data, ref ShineId);
}

View File

@ -6,6 +6,8 @@ namespace Shared.Packet.Packets;
public struct TagPacket : IPacket {
public bool IsIt;
public short Size => 1;
public void Serialize(Span<byte> data) {
MemoryMarshal.Write(data, ref IsIt);
}

View File

@ -3,15 +3,19 @@
[Packet(PacketType.Unknown)] // empty like boss
// [Packet(PacketType.Command)]
public struct UnhandledPacket : IPacket {
public byte[] Data = new byte[Constants.PacketDataSize];
public byte[] Data;
public UnhandledPacket() { }
public UnhandledPacket() {
Data = null!;
}
public short Size => 0;
public void Serialize(Span<byte> data) {
Data.CopyTo(data);
}
public void Deserialize(Span<byte> data) {
data.CopyTo(Data);
Data = data.ToArray();
}
}

View File

@ -6,73 +6,73 @@ using Shared;
using Shared.Packet;
using Shared.Packet.Packets;
TcpClient client = new TcpClient(args[0], 1027);
// TcpClient client = new TcpClient(args[0], 1027);
Guid ownId = new Guid(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
// Guid ownId = Guid.NewGuid();
Guid otherId = Guid.Parse("d5feae62-2e71-1000-88fd-597ea147ae88");
Logger logger = new Logger("Client");
NetworkStream stream = client.GetStream();
Vector3 basePoint = Vector3.Zero;
PacketType[] reboundPackets = {
PacketType.Player,
PacketType.Cap,
PacketType.Capture,
PacketType.Costume,
PacketType.Tag,
PacketType.Shine
};
string lastCapture = "";
async Task S() {
IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(Constants.MaxPacketSize);
while (true) {
await stream.ReadAsync(owner.Memory);
PacketHeader header = MemoryMarshal.Read<PacketHeader>(owner.Memory.Span);
PacketType type = header.Type;
if (header.Id != otherId) continue;
if (type is PacketType.Player) {
// CapPacket cap = new CapPacket();
PlayerPacket playerPacket = new PlayerPacket();
playerPacket.Deserialize(owner.Memory.Span[Constants.HeaderSize..]);
logger.Info(playerPacket.Hack);
if (playerPacket.Hack != lastCapture) logger.Info($"Changed to hack: {lastCapture = playerPacket.Hack}");
// cap.Position = playerPacket.Position + Vector3.UnitY * 500f;
// cap.Rotation = Quaternion.CreateFromYawPitchRoll(0,0,0);
// cap.CapAnim = "StayR";
// playerPacket.Position = new Vector3(1000000f);
// playerPacket.ThrowingCap = true;
// header.Id = ownId;
// MemoryMarshal.Write(owner.Memory.Span, ref header);
// playerPacket.Serialize(owner.Memory.Span[Constants.HeaderSize..]);
// await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
// header.Type = PacketType.Cap;
// MemoryMarshal.Write(owner.Memory.Span, ref header);
// cap.Serialize(owner.Memory.Span[Constants.HeaderSize..]);
// await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
// continue;
}
if (reboundPackets.All(x => x != type)) continue;
header.Id = ownId;
MemoryMarshal.Write(owner.Memory.Span, ref header);
await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
}
}
PacketHeader coolHeader = new PacketHeader {
Type = PacketType.Connect,
Id = ownId
};
IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize);
MemoryMarshal.Write(owner.Memory.Span[..], ref coolHeader);
ConnectPacket connect = new ConnectPacket {
ConnectionType = ConnectionTypes.Reconnecting,
ClientName = "Test Sanae"
};
connect.Serialize(owner.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]);
await stream.WriteAsync(owner.Memory);
logger.Info("Connected");
await S();
// Guid otherId = Guid.Parse("d5feae62-2e71-1000-88fd-597ea147ae88");
// Logger logger = new Logger("Client");
// NetworkStream stream = client.GetStream();
//
// Vector3 basePoint = Vector3.Zero;
//
// PacketType[] reboundPackets = {
// PacketType.Player,
// PacketType.Cap,
// PacketType.Capture,
// PacketType.Costume,
// PacketType.Tag,
// PacketType.Shine
// };
//
// string lastCapture = "";
//
// async Task S() {
// IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(Constants.MaxPacketSize);
// while (true) {
// await stream.ReadAsync(owner.Memory);
// PacketHeader header = MemoryMarshal.Read<PacketHeader>(owner.Memory.Span);
// PacketType type = header.Type;
// if (header.Id != otherId) continue;
// if (type is PacketType.Player) {
// // CapPacket cap = new CapPacket();
// PlayerPacket playerPacket = new PlayerPacket();
// playerPacket.Deserialize(owner.Memory.Span[Constants.HeaderSize..]);
// logger.Info(playerPacket.Hack);
// if (playerPacket.Hack != lastCapture) logger.Info($"Changed to hack: {lastCapture = playerPacket.Hack}");
// // cap.Position = playerPacket.Position + Vector3.UnitY * 500f;
// // cap.Rotation = Quaternion.CreateFromYawPitchRoll(0,0,0);
// // cap.CapAnim = "StayR";
// // playerPacket.Position = new Vector3(1000000f);
// // playerPacket.ThrowingCap = true;
// // header.Id = ownId;
// // MemoryMarshal.Write(owner.Memory.Span, ref header);
// // playerPacket.Serialize(owner.Memory.Span[Constants.HeaderSize..]);
// // await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
// // header.Type = PacketType.Cap;
// // MemoryMarshal.Write(owner.Memory.Span, ref header);
// // cap.Serialize(owner.Memory.Span[Constants.HeaderSize..]);
// // await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
// // continue;
// }
//
// if (reboundPackets.All(x => x != type)) continue;
// header.Id = ownId;
// MemoryMarshal.Write(owner.Memory.Span, ref header);
// await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
// }
// }
//
// PacketHeader coolHeader = new PacketHeader {
// Type = PacketType.Connect,
// Id = ownId
// };
// IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize);
// MemoryMarshal.Write(owner.Memory.Span[..], ref coolHeader);
// ConnectPacket connect = new ConnectPacket {
// ConnectionType = ConnectionTypes.Reconnecting,
// ClientName = "Test Sanae"
// };
// connect.Serialize(owner.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]);
// await stream.WriteAsync(owner.Memory);
// logger.Info("Connected");
// await S();