diff --git a/Server/Client.cs b/Server/Client.cs index 2ef9012..7497d0e 100644 --- a/Server/Client.cs +++ b/Server/Client.cs @@ -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 packet, Client? sender = null) where T : struct, IPacket { - IMemoryOwner memory = MemoryPool.Shared.RentZero(Constants.MaxPacketSize); + IMemoryOwner memory = MemoryPool.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 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(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(data.Span[18..]); + await Socket!.SendAsync(data[..(Constants.HeaderSize + packetSize)], SocketFlags.None); } public static bool operator ==(Client? left, Client? right) { diff --git a/Server/Server.cs b/Server/Server.cs index d3efbcd..eaff525 100644 --- a/Server/Server.cs +++ b/Server/Server.cs @@ -78,11 +78,11 @@ public class Server { } public async Task Broadcast(T packet, Client sender) where T : struct, IPacket { - IMemoryOwner memory = memoryPool.RentZero(Constants.MaxPacketSize); - + IMemoryOwner memory = MemoryPool.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 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 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 otherConnectedPlayers = Clients.FindAll(c => c.Id != header.Id && c.Connected && c.Socket != null); await Parallel.ForEachAsync(otherConnectedPlayers, async (other, _) => { - IMemoryOwner tempBuffer = MemoryPool.Shared.RentZero(Constants.MaxPacketSize); + IMemoryOwner tempBuffer = MemoryPool.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; diff --git a/Shared/Constants.cs b/Shared/Constants.cs index 2482f6a..1559465 100644 --- a/Shared/Constants.cs +++ b/Shared/Constants.cs @@ -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()!.Type, type => type); public static int HeaderSize { get; } = Marshal.SizeOf(); - public static int PacketDataSize { get; } = MaxPacketSize - HeaderSize; } \ No newline at end of file diff --git a/Shared/Packet/PacketHeader.cs b/Shared/Packet/PacketHeader.cs index b5cc99a..862b08a 100644 --- a/Shared/Packet/PacketHeader.cs +++ b/Shared/Packet/PacketHeader.cs @@ -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 data) { // MemoryMarshal.Write(data, ref Length); @@ -18,5 +21,6 @@ public struct PacketHeader : IPacket { public void Deserialize(Span data) { Id = MemoryMarshal.Read(data); Type = MemoryMarshal.Read(data[16..]); + Type = MemoryMarshal.Read(data[16..]); } } \ No newline at end of file diff --git a/Shared/Packet/PacketType.cs b/Shared/Packet/PacketType.cs index 39356f0..b458bb2 100644 --- a/Shared/Packet/PacketType.cs +++ b/Shared/Packet/PacketType.cs @@ -1,6 +1,6 @@ namespace Shared.Packet; -public enum PacketType { +public enum PacketType : short { Unknown, Player, Cap, diff --git a/Shared/Packet/Packets/CapPacket.cs b/Shared/Packet/Packets/CapPacket.cs index 411d030..c9c8d32 100644 --- a/Shared/Packet/Packets/CapPacket.cs +++ b/Shared/Packet/Packets/CapPacket.cs @@ -11,6 +11,8 @@ public struct CapPacket : IPacket { public Quaternion Rotation; public string CapAnim; + public short Size => 0x4C; + public void Serialize(Span data) { MemoryMarshal.Write(data, ref Position); MemoryMarshal.Write(data[12..], ref Position); diff --git a/Shared/Packet/Packets/CapturePacket.cs b/Shared/Packet/Packets/CapturePacket.cs index 7b70df3..3b2bbee 100644 --- a/Shared/Packet/Packets/CapturePacket.cs +++ b/Shared/Packet/Packets/CapturePacket.cs @@ -10,6 +10,7 @@ public struct CapturePacket : IPacket { public bool IsCaptured; + public short Size => Constants.CostumeNameSize + 1; public void Serialize(Span 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(data[Constants.CostumeNameSize..]); } + } \ No newline at end of file diff --git a/Shared/Packet/Packets/ConnectPacket.cs b/Shared/Packet/Packets/ConnectPacket.cs index c4a9d39..fe31e62 100644 --- a/Shared/Packet/Packets/ConnectPacket.cs +++ b/Shared/Packet/Packets/ConnectPacket.cs @@ -10,6 +10,8 @@ public struct ConnectPacket : IPacket { public ConnectPacket() { } + public short Size => 4 + Constants.CostumeNameSize; + public void Serialize(Span data) { MemoryMarshal.Write(data, ref ConnectionType); Encoding.UTF8.GetBytes(ClientName).CopyTo(data[4..(4 + Constants.CostumeNameSize)]); diff --git a/Shared/Packet/Packets/CostumePacket.cs b/Shared/Packet/Packets/CostumePacket.cs index 7abae54..854cc84 100644 --- a/Shared/Packet/Packets/CostumePacket.cs +++ b/Shared/Packet/Packets/CostumePacket.cs @@ -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 data) { Encoding.UTF8.GetBytes(BodyName).CopyTo(data[..Constants.CostumeNameSize]); Encoding.UTF8.GetBytes(CapName).CopyTo(data[Constants.CostumeNameSize..]); diff --git a/Shared/Packet/Packets/DisconnectPacket.cs b/Shared/Packet/Packets/DisconnectPacket.cs index edf8ffe..0ec4fae 100644 --- a/Shared/Packet/Packets/DisconnectPacket.cs +++ b/Shared/Packet/Packets/DisconnectPacket.cs @@ -3,6 +3,7 @@ [Packet(PacketType.Disconnect)] public struct DisconnectPacket : IPacket { //empty packet + public short Size => 0; public void Serialize(Span data) { } public void Deserialize(Span data) { } diff --git a/Shared/Packet/Packets/IPacket.cs b/Shared/Packet/Packets/IPacket.cs index 509f510..6a18212 100644 --- a/Shared/Packet/Packets/IPacket.cs +++ b/Shared/Packet/Packets/IPacket.cs @@ -2,6 +2,7 @@ // Packet interface for type safety public interface IPacket { + short Size { get; } void Serialize(Span data); void Deserialize(Span data); } \ No newline at end of file diff --git a/Shared/Packet/Packets/PlayerPacket.cs b/Shared/Packet/Packets/PlayerPacket.cs index 6e90b47..6652f12 100644 --- a/Shared/Packet/Packets/PlayerPacket.cs +++ b/Shared/Packet/Packets/PlayerPacket.cs @@ -35,6 +35,8 @@ public struct PlayerPacket : IPacket { public PlayerPacket() { } + public short Size => 0xE0; + public void Serialize(Span data) { int offset = 0; MemoryMarshal.Write(data, ref Position); diff --git a/Shared/Packet/Packets/ShinePacket.cs b/Shared/Packet/Packets/ShinePacket.cs index f0f5566..123ae1a 100644 --- a/Shared/Packet/Packets/ShinePacket.cs +++ b/Shared/Packet/Packets/ShinePacket.cs @@ -6,6 +6,8 @@ namespace Shared.Packet.Packets; public struct ShinePacket : IPacket { public int ShineId; + public short Size => 4; + public void Serialize(Span data) { MemoryMarshal.Write(data, ref ShineId); } diff --git a/Shared/Packet/Packets/TagPacket.cs b/Shared/Packet/Packets/TagPacket.cs index a8a9196..0463992 100644 --- a/Shared/Packet/Packets/TagPacket.cs +++ b/Shared/Packet/Packets/TagPacket.cs @@ -6,6 +6,8 @@ namespace Shared.Packet.Packets; public struct TagPacket : IPacket { public bool IsIt; + public short Size => 1; + public void Serialize(Span data) { MemoryMarshal.Write(data, ref IsIt); } diff --git a/Shared/Packet/Packets/UnhandledPacket.cs b/Shared/Packet/Packets/UnhandledPacket.cs index de38bae..3fcfa71 100644 --- a/Shared/Packet/Packets/UnhandledPacket.cs +++ b/Shared/Packet/Packets/UnhandledPacket.cs @@ -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 data) { Data.CopyTo(data); } public void Deserialize(Span data) { - data.CopyTo(Data); + Data = data.ToArray(); } + } \ No newline at end of file diff --git a/TestClient/Program.cs b/TestClient/Program.cs index e3bc6a0..61a51c9 100644 --- a/TestClient/Program.cs +++ b/TestClient/Program.cs @@ -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 owner = MemoryPool.Shared.Rent(Constants.MaxPacketSize); - while (true) { - await stream.ReadAsync(owner.Memory); - PacketHeader header = MemoryMarshal.Read(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 owner = MemoryPool.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(); \ No newline at end of file +// 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 owner = MemoryPool.Shared.Rent(Constants.MaxPacketSize); +// while (true) { +// await stream.ReadAsync(owner.Memory); +// PacketHeader header = MemoryMarshal.Read(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 owner = MemoryPool.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(); \ No newline at end of file