diff --git a/Server/Client.cs b/Server/Client.cs index 6c0f31c..8ad978b 100644 --- a/Server/Client.cs +++ b/Server/Client.cs @@ -1,28 +1,34 @@ -using System.Buffers; -using System.Net.Sockets; +using System.Net.Sockets; using Shared.Packet.Packets; -namespace Server; +namespace Server; public class Client : IDisposable { - public Socket? Socket; + public readonly Dictionary Metadata = new Dictionary(); // can be used to store any information about a player public bool Connected = false; - public Guid Id; + public CostumePacket CurrentCostume = new CostumePacket { BodyName = "", CapName = "" }; - public readonly Dictionary Metadata = new Dictionary(); // can be used to store any information about a player + + public Guid Id; + public Socket? Socket; + + public void Dispose() { + Socket?.Disconnect(false); + } public async Task Send(Memory data) { if (!Connected) return; await Socket!.SendAsync(data, SocketFlags.None); } - public void Dispose() { - Socket?.Disconnect(false); + public static bool operator ==(Client? left, Client? right) { + return left is { } leftClient && right is { } rightClient && leftClient.Id == rightClient.Id; } - public static bool operator ==(Client? left, Client? right) => left is { } leftClient && right is { } rightClient && leftClient.Id == rightClient.Id; - public static bool operator !=(Client? left, Client? right) => !(left == right); + public static bool operator !=(Client? left, Client? right) { + return !(left == right); + } } \ No newline at end of file diff --git a/Server/Program.cs b/Server/Program.cs index a354723..2a201e9 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -1,6 +1,3 @@ -using System.Buffers; -using System.Net.Sockets; - -Server.Server server = new Server.Server(); +Server.Server server = new Server.Server(); await server.Listen(1027); \ No newline at end of file diff --git a/Server/Server.cs b/Server/Server.cs index db0ba3c..3beb789 100644 --- a/Server/Server.cs +++ b/Server/Server.cs @@ -9,19 +9,20 @@ using Shared.Packet.Packets; namespace Server; public class Server { - private readonly MemoryPool memoryPool = MemoryPool.Shared; public readonly List Clients = new List(); public readonly Logger Logger = new Logger("Server"); + private readonly MemoryPool memoryPool = MemoryPool.Shared; + public async Task Listen(ushort port) { Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(new IPEndPoint(IPAddress.Any, port)); serverSocket.Listen(); - + Logger.Info($"Listening on port {port}"); while (true) { Socket socket = await serverSocket.AcceptAsync(); - + Logger.Warn("ok"); if (Clients.Count > Constants.MaxClients) { @@ -47,14 +48,14 @@ public class Server { PacketHeader header = new PacketHeader { Id = sender?.Id ?? Guid.Empty, - Type = Constants.Packets[typeof(T)].Type, + Type = Constants.Packets[typeof(T)].Type }; FillPacket(header, packet, memory.Memory); await Broadcast(memory, sender); } /// - /// Takes ownership of data and disposes once done. + /// Takes ownership of data and disposes once done. /// /// Memory owner to dispose once done /// Optional sender to not broadcast data to @@ -67,7 +68,7 @@ public class Server { } /// - /// Broadcasts memory whose memory shouldn't be disposed, should only be fired by server code. + /// Broadcasts memory whose memory shouldn't be disposed, should only be fired by server code. /// /// Memory to send to the clients /// Optional sender to not broadcast data to @@ -81,14 +82,15 @@ public class Server { private async void HandleSocket(Socket socket) { - Client client = new Client {Socket = socket}; + Client client = new Client { Socket = socket }; IMemoryOwner memory = null!; bool first = true; try { while (true) { memory = memoryPool.Rent(Constants.MaxPacketSize); int size = await socket.ReceiveAsync(memory.Memory, SocketFlags.None); - if (size == 0) { // treat it as a disconnect and exit + if (size == 0) { + // treat it as a disconnect and exit Logger.Info($"Socket {socket.RemoteEndPoint} disconnected."); await socket.DisconnectAsync(false); break; @@ -99,9 +101,7 @@ public class Server { // connection initialization if (first) { first = false; - if (header.Type != PacketType.Connect) { - throw new Exception($"First packet was not init, instead it was {header.Type}"); - } + if (header.Type != PacketType.Connect) throw new Exception($"First packet was not init, instead it was {header.Type}"); ConnectPacket connect = MemoryMarshal.Read(memory.Memory.Span[Constants.HeaderSize..size]); lock (Clients) { @@ -119,6 +119,7 @@ public class Server { } else { firstConn = true; } + break; } default: @@ -130,7 +131,7 @@ public class Server { // do any cleanup required when it comes to new clients List toDisconnect = Clients.FindAll(c => c.Id == header.Id && c.Connected && c.Socket != null); Clients.RemoveAll(c => c.Id == header.Id); - + client.Id = header.Id; Clients.Add(client); @@ -138,33 +139,32 @@ public class Server { // done disconnecting and removing stale clients with the same id } } + List otherConnectedPlayers = Clients.FindAll(c => c.Id != header.Id && c.Connected && c.Socket != null); await Parallel.ForEachAsync(otherConnectedPlayers, async (other, _) => { IMemoryOwner connectBuffer = MemoryPool.Shared.Rent(256); - PacketHeader connectHeader = new PacketHeader() { + PacketHeader connectHeader = new PacketHeader { Id = other.Id, Type = PacketType.Connect }; MemoryMarshal.Write(connectBuffer.Memory.Span, ref connectHeader); - ConnectPacket connectPacket = new ConnectPacket() { + ConnectPacket connectPacket = new ConnectPacket { ConnectionType = ConnectionTypes.FirstConnection // doesn't matter what it is :) }; MemoryMarshal.Write(connectBuffer.Memory.Span, ref connectPacket); await client.Send(connectBuffer.Memory); connectBuffer.Dispose(); }); - + Logger.Info($"Client {socket.RemoteEndPoint} ({client.Id}) connected."); } - // todo support variable length packets if they show up Logger.Warn($"broadcasting {header.Type} from {client.Id}"); await Broadcast(memory, client); } - } - catch (Exception e) { - if (e is SocketException {SocketErrorCode: SocketError.ConnectionReset}) { + } catch (Exception e) { + if (e is SocketException { SocketErrorCode: SocketError.ConnectionReset }) { Logger.Info($"Client {socket.RemoteEndPoint} ({client.Id}) disconnected from the server"); } else { Logger.Error($"Exception on socket {socket.RemoteEndPoint} ({client.Id}) and disconnecting for: {e}"); diff --git a/Server/Server.csproj b/Server/Server.csproj index 7d518c2..c7ce3d6 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -8,7 +8,7 @@ - + diff --git a/Shared/Constants.cs b/Shared/Constants.cs index 7100594..5141a8b 100644 --- a/Shared/Constants.cs +++ b/Shared/Constants.cs @@ -3,13 +3,11 @@ using System.Runtime.InteropServices; using Shared.Packet; using Shared.Packet.Packets; -namespace Shared; +namespace Shared; public static class Constants { public const int MaxPacketSize = 256; public const int MaxClients = 4; - public static int HeaderSize { get; } = Marshal.SizeOf(); - public static int PacketDataSize { get; } = MaxPacketSize - HeaderSize; public const int CostumeNameSize = 0x20; // dictionary of packet types to packet @@ -18,4 +16,7 @@ public static class Constants { .GetTypes() .Where(type => type.IsAssignableTo(typeof(IPacket))) .ToDictionary(type => type, type => type.GetCustomAttribute()!); + + public static int HeaderSize { get; } = Marshal.SizeOf(); + public static int PacketDataSize { get; } = MaxPacketSize - HeaderSize; } \ No newline at end of file diff --git a/Shared/Extensions.cs b/Shared/Extensions.cs index 0438bb5..4129327 100644 --- a/Shared/Extensions.cs +++ b/Shared/Extensions.cs @@ -1,16 +1,18 @@ -using System.Text; - -namespace Shared; +namespace Shared; public static class Extensions { public static string Hex(this Span span) { return span.ToArray().Hex(); } - - public static string Hex(this IEnumerable array) => string.Join(' ', array.ToArray().Select(x => x.ToString("X2"))); + + public static string Hex(this IEnumerable array) { + return string.Join(' ', array.ToArray().Select(x => x.ToString("X2"))); + } public static unsafe byte* Ptr(this Span span) { - fixed (byte* data = span) return data; + fixed (byte* data = span) { + return data; + } } public static string TrimNullTerm(this string text) { diff --git a/Shared/Logger.cs b/Shared/Logger.cs index b5c6fa3..93123ce 100644 --- a/Shared/Logger.cs +++ b/Shared/Logger.cs @@ -1,11 +1,12 @@ -namespace Shared; +namespace Shared; public class Logger { - public string Name { get; } public Logger(string name) { Name = name; } + public string Name { get; } + public void Info(string text) { Console.ResetColor(); Console.WriteLine($"Info [{Name}] {text}"); diff --git a/Shared/Packet/PacketAttribute.cs b/Shared/Packet/PacketAttribute.cs index a411749..4bb95a9 100644 --- a/Shared/Packet/PacketAttribute.cs +++ b/Shared/Packet/PacketAttribute.cs @@ -1,9 +1,10 @@ -namespace Shared.Packet; +namespace Shared.Packet; [AttributeUsage(AttributeTargets.Struct, AllowMultiple = true)] public class PacketAttribute : Attribute { - public PacketType Type { get; } public PacketAttribute(PacketType type) { Type = type; } + + public PacketType Type { get; } } \ No newline at end of file diff --git a/Shared/Packet/PacketHeader.cs b/Shared/Packet/PacketHeader.cs index 1e620e8..b5cc99a 100644 --- a/Shared/Packet/PacketHeader.cs +++ b/Shared/Packet/PacketHeader.cs @@ -1,13 +1,14 @@ using System.Runtime.InteropServices; using Shared.Packet.Packets; -namespace Shared.Packet; +namespace Shared.Packet; [StructLayout(LayoutKind.Sequential)] public struct PacketHeader : IPacket { // public int Length; public Guid Id; public PacketType Type; + public void Serialize(Span data) { // MemoryMarshal.Write(data, ref Length); MemoryMarshal.Write(data, ref Id); diff --git a/Shared/Packet/PacketType.cs b/Shared/Packet/PacketType.cs index 12cb7a1..39356f0 100644 --- a/Shared/Packet/PacketType.cs +++ b/Shared/Packet/PacketType.cs @@ -1,4 +1,4 @@ -namespace Shared.Packet; +namespace Shared.Packet; public enum PacketType { Unknown, diff --git a/Shared/Packet/PacketUtils.cs b/Shared/Packet/PacketUtils.cs index 5ec94c8..2a455a7 100644 --- a/Shared/Packet/PacketUtils.cs +++ b/Shared/Packet/PacketUtils.cs @@ -1,13 +1,14 @@ using System.Runtime.InteropServices; using Shared.Packet.Packets; -namespace Shared.Packet; +namespace Shared.Packet; public static class PacketUtils { public static void SerializeHeaded(Span data, PacketHeader header, T t) where T : struct, IPacket { header.Serialize(data); t.Serialize(data[Constants.HeaderSize..]); } + public static T Deserialize(Span data) where T : IPacket, new() { T packet = new T(); packet.Deserialize(data); diff --git a/Shared/Packet/Packets/CapPacket.cs b/Shared/Packet/Packets/CapPacket.cs index 3a67290..411d030 100644 --- a/Shared/Packet/Packets/CapPacket.cs +++ b/Shared/Packet/Packets/CapPacket.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using System.Text; -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; [Packet(PacketType.Cap)] public struct CapPacket : IPacket { @@ -10,6 +10,7 @@ public struct CapPacket : IPacket { public Vector3 Position; public Quaternion Rotation; public string CapAnim; + 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 549108f..7b70df3 100644 --- a/Shared/Packet/Packets/CapturePacket.cs +++ b/Shared/Packet/Packets/CapturePacket.cs @@ -1,13 +1,15 @@ using System.Runtime.InteropServices; using System.Text; -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; [Packet(PacketType.Capture)] public struct CapturePacket : IPacket { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.CostumeNameSize)] public string ModelName; + public bool IsCaptured; + public void Serialize(Span data) { Encoding.UTF8.GetBytes(ModelName).CopyTo(data[..Constants.CostumeNameSize]); MemoryMarshal.Write(data[Constants.CostumeNameSize..], ref IsCaptured); diff --git a/Shared/Packet/Packets/ConnectPacket.cs b/Shared/Packet/Packets/ConnectPacket.cs index d36eacc..f97f80b 100644 --- a/Shared/Packet/Packets/ConnectPacket.cs +++ b/Shared/Packet/Packets/ConnectPacket.cs @@ -1,10 +1,11 @@ using System.Runtime.InteropServices; -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; [Packet(PacketType.Connect)] public struct ConnectPacket : IPacket { public ConnectionTypes ConnectionType; + public void Serialize(Span data) { MemoryMarshal.Write(data, ref ConnectionType); } diff --git a/Shared/Packet/Packets/ConnectionTypes.cs b/Shared/Packet/Packets/ConnectionTypes.cs index 1056318..1666258 100644 --- a/Shared/Packet/Packets/ConnectionTypes.cs +++ b/Shared/Packet/Packets/ConnectionTypes.cs @@ -1,4 +1,4 @@ -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; public enum ConnectionTypes { FirstConnection, diff --git a/Shared/Packet/Packets/CostumePacket.cs b/Shared/Packet/Packets/CostumePacket.cs index fa62643..7abae54 100644 --- a/Shared/Packet/Packets/CostumePacket.cs +++ b/Shared/Packet/Packets/CostumePacket.cs @@ -1,14 +1,16 @@ using System.Runtime.InteropServices; using System.Text; -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; [Packet(PacketType.Costume)] public struct CostumePacket : IPacket { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.CostumeNameSize)] public string BodyName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.CostumeNameSize)] public string CapName; + 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 2ba6b06..edf8ffe 100644 --- a/Shared/Packet/Packets/DisconnectPacket.cs +++ b/Shared/Packet/Packets/DisconnectPacket.cs @@ -1,13 +1,9 @@ -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; [Packet(PacketType.Disconnect)] public struct DisconnectPacket : IPacket { //empty packet - public void Serialize(Span data) { - - } + public void Serialize(Span data) { } - public void Deserialize(Span data) { - - } + public void Deserialize(Span data) { } } \ No newline at end of file diff --git a/Shared/Packet/Packets/IPacket.cs b/Shared/Packet/Packets/IPacket.cs index 556f8ca..509f510 100644 --- a/Shared/Packet/Packets/IPacket.cs +++ b/Shared/Packet/Packets/IPacket.cs @@ -1,6 +1,4 @@ -using System.Runtime.InteropServices; - -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; // Packet interface for type safety public interface IPacket { diff --git a/Shared/Packet/Packets/PlayerPacket.cs b/Shared/Packet/Packets/PlayerPacket.cs index dbaf859..f344a43 100644 --- a/Shared/Packet/Packets/PlayerPacket.cs +++ b/Shared/Packet/Packets/PlayerPacket.cs @@ -1,5 +1,4 @@ using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -11,17 +10,22 @@ public struct PlayerPacket : IPacket { public Vector3 Position; public Quaternion Rotation; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public float[] AnimationBlendWeights; + public float AnimationRate; public bool Is2d; public bool ThrowingCap; public bool IsIt; public int ScenarioNum; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NameSize)] public string Stage; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NameSize)] public string Act; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NameSize)] public string SubAct; diff --git a/Shared/Packet/Packets/ShinePacket.cs b/Shared/Packet/Packets/ShinePacket.cs index 072bc00..850c987 100644 --- a/Shared/Packet/Packets/ShinePacket.cs +++ b/Shared/Packet/Packets/ShinePacket.cs @@ -1,11 +1,12 @@ using System.Runtime.InteropServices; -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; [Packet(PacketType.Shine)] public struct ShinePacket : IPacket { public int ShineId; public bool IsGrand; + public void Serialize(Span data) { MemoryMarshal.Write(data, ref ShineId); MemoryMarshal.Write(data, ref IsGrand); diff --git a/Shared/Packet/Packets/TagPacket.cs b/Shared/Packet/Packets/TagPacket.cs index 695ecb7..a8a9196 100644 --- a/Shared/Packet/Packets/TagPacket.cs +++ b/Shared/Packet/Packets/TagPacket.cs @@ -1,10 +1,11 @@ using System.Runtime.InteropServices; -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; [Packet(PacketType.Tag)] public struct TagPacket : IPacket { - public bool IsIt = false; + public bool IsIt; + 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 ad7350c..3088a71 100644 --- a/Shared/Packet/Packets/UnhandledPacket.cs +++ b/Shared/Packet/Packets/UnhandledPacket.cs @@ -1,9 +1,10 @@ -namespace Shared.Packet.Packets; +namespace Shared.Packet.Packets; [Packet(PacketType.Unknown)] // empty like boss // [Packet(PacketType.Command)] public struct UnhandledPacket : IPacket { public byte[] Data = new byte[Constants.PacketDataSize]; + public void Serialize(Span data) { Data.CopyTo(data); } diff --git a/Shared/Shared.csproj b/Shared/Shared.csproj index 94fa761..f7c9978 100644 --- a/Shared/Shared.csproj +++ b/Shared/Shared.csproj @@ -8,7 +8,7 @@ - + diff --git a/TestClient/Program.cs b/TestClient/Program.cs index 9c9e981..decf98c 100644 --- a/TestClient/Program.cs +++ b/TestClient/Program.cs @@ -1,7 +1,6 @@ using System.Buffers; using System.Net.Sockets; using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Shared; using Shared.Packet; diff --git a/TestClient/TestClient.csproj b/TestClient/TestClient.csproj index ee81c78..6510b73 100644 --- a/TestClient/TestClient.csproj +++ b/TestClient/TestClient.csproj @@ -9,7 +9,7 @@ - +