0
0
Fork 0
mirror of https://github.com/Sanae6/SmoOnlineServer.git synced 2024-11-23 19:55:18 +00:00

Reformat solution

This commit is contained in:
Sanae 2022-02-09 19:44:50 -06:00
parent 351304f99f
commit 7dbe2ecd55
25 changed files with 89 additions and 73 deletions

View file

@ -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<string, object> Metadata = new Dictionary<string, object>(); // 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<string, object> Metadata = new Dictionary<string, object>(); // 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<byte> 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);
}
}

View file

@ -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);

View file

@ -9,19 +9,20 @@ using Shared.Packet.Packets;
namespace Server;
public class Server {
private readonly MemoryPool<byte> memoryPool = MemoryPool<byte>.Shared;
public readonly List<Client> Clients = new List<Client>();
public readonly Logger Logger = new Logger("Server");
private readonly MemoryPool<byte> memoryPool = MemoryPool<byte>.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);
}
/// <summary>
/// Takes ownership of data and disposes once done.
/// Takes ownership of data and disposes once done.
/// </summary>
/// <param name="data">Memory owner to dispose once done</param>
/// <param name="sender">Optional sender to not broadcast data to</param>
@ -67,7 +68,7 @@ public class Server {
}
/// <summary>
/// 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.
/// </summary>
/// <param name="data">Memory to send to the clients</param>
/// <param name="sender">Optional sender to not broadcast data to</param>
@ -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<byte> 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<ConnectPacket>(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<Client> 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<Client> otherConnectedPlayers = Clients.FindAll(c => c.Id != header.Id && c.Connected && c.Socket != null);
await Parallel.ForEachAsync(otherConnectedPlayers, async (other, _) => {
IMemoryOwner<byte> connectBuffer = MemoryPool<byte>.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}");

View file

@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj"/>
</ItemGroup>
</Project>

View file

@ -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<PacketHeader>();
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<PacketAttribute>()!);
public static int HeaderSize { get; } = Marshal.SizeOf<PacketHeader>();
public static int PacketDataSize { get; } = MaxPacketSize - HeaderSize;
}

View file

@ -1,16 +1,18 @@
using System.Text;
namespace Shared;
namespace Shared;
public static class Extensions {
public static string Hex(this Span<byte> span) {
return span.ToArray().Hex();
}
public static string Hex(this IEnumerable<byte> array) => string.Join(' ', array.ToArray().Select(x => x.ToString("X2")));
public static string Hex(this IEnumerable<byte> array) {
return string.Join(' ', array.ToArray().Select(x => x.ToString("X2")));
}
public static unsafe byte* Ptr(this Span<byte> span) {
fixed (byte* data = span) return data;
fixed (byte* data = span) {
return data;
}
}
public static string TrimNullTerm(this string text) {

View file

@ -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}");

View file

@ -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; }
}

View file

@ -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<byte> data) {
// MemoryMarshal.Write(data, ref Length);
MemoryMarshal.Write(data, ref Id);

View file

@ -1,4 +1,4 @@
namespace Shared.Packet;
namespace Shared.Packet;
public enum PacketType {
Unknown,

View file

@ -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<T>(Span<byte> data, PacketHeader header, T t) where T : struct, IPacket {
header.Serialize(data);
t.Serialize(data[Constants.HeaderSize..]);
}
public static T Deserialize<T>(Span<byte> data) where T : IPacket, new() {
T packet = new T();
packet.Deserialize(data);

View file

@ -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<byte> data) {
MemoryMarshal.Write(data, ref Position);
MemoryMarshal.Write(data[12..], ref Position);

View file

@ -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<byte> data) {
Encoding.UTF8.GetBytes(ModelName).CopyTo(data[..Constants.CostumeNameSize]);
MemoryMarshal.Write(data[Constants.CostumeNameSize..], ref IsCaptured);

View file

@ -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<byte> data) {
MemoryMarshal.Write(data, ref ConnectionType);
}

View file

@ -1,4 +1,4 @@
namespace Shared.Packet.Packets;
namespace Shared.Packet.Packets;
public enum ConnectionTypes {
FirstConnection,

View file

@ -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<byte> data) {
Encoding.UTF8.GetBytes(BodyName).CopyTo(data[..Constants.CostumeNameSize]);
Encoding.UTF8.GetBytes(CapName).CopyTo(data[Constants.CostumeNameSize..]);

View file

@ -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<byte> data) {
}
public void Serialize(Span<byte> data) { }
public void Deserialize(Span<byte> data) {
}
public void Deserialize(Span<byte> data) { }
}

View file

@ -1,6 +1,4 @@
using System.Runtime.InteropServices;
namespace Shared.Packet.Packets;
namespace Shared.Packet.Packets;
// Packet interface for type safety
public interface IPacket {

View file

@ -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;

View file

@ -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<byte> data) {
MemoryMarshal.Write(data, ref ShineId);
MemoryMarshal.Write(data, ref IsGrand);

View file

@ -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<byte> data) {
MemoryMarshal.Write(data, ref IsIt);
}

View file

@ -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<byte> data) {
Data.CopyTo(data);
}

View file

@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0"/>
</ItemGroup>
</Project>

View file

@ -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;

View file

@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj"/>
</ItemGroup>
</Project>