mirror of
https://github.com/Sanae6/SmoOnlineServer.git
synced 2024-11-28 14:13:05 +00:00
Update TestClient and add custom ser/deser for packets
This commit is contained in:
parent
6afb232953
commit
eaa03467e6
11 changed files with 149 additions and 19 deletions
|
@ -11,7 +11,6 @@ public class Server {
|
||||||
private readonly MemoryPool<byte> memoryPool = MemoryPool<byte>.Shared;
|
private readonly MemoryPool<byte> memoryPool = MemoryPool<byte>.Shared;
|
||||||
public readonly List<Client> Clients = new List<Client>();
|
public readonly List<Client> Clients = new List<Client>();
|
||||||
public readonly Logger Logger = new Logger("Server");
|
public readonly Logger Logger = new Logger("Server");
|
||||||
private static int HeaderSize => Marshal.SizeOf<PacketHeader>();
|
|
||||||
public async Task Listen(ushort port) {
|
public async Task Listen(ushort port) {
|
||||||
TcpListener listener = TcpListener.Create(port);
|
TcpListener listener = TcpListener.Create(port);
|
||||||
|
|
||||||
|
@ -34,12 +33,12 @@ public class Server {
|
||||||
Span<byte> data = memory.Span;
|
Span<byte> data = memory.Span;
|
||||||
|
|
||||||
MemoryMarshal.Write(data, ref header);
|
MemoryMarshal.Write(data, ref header);
|
||||||
MemoryMarshal.Write(data[HeaderSize..], ref packet);
|
MemoryMarshal.Write(data[Constants.HeaderSize..], ref packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// broadcast packets to all clients
|
// broadcast packets to all clients
|
||||||
public async void Broadcast<T>(T packet, Client? sender = null) where T : unmanaged, IPacket {
|
public async void Broadcast<T>(T packet, Client? sender = null) where T : unmanaged, IPacket {
|
||||||
IMemoryOwner<byte> memory = memoryPool.Rent(Marshal.SizeOf<T>() + HeaderSize);
|
IMemoryOwner<byte> memory = memoryPool.Rent(Marshal.SizeOf<T>() + Constants.HeaderSize);
|
||||||
|
|
||||||
PacketHeader header = new PacketHeader {
|
PacketHeader header = new PacketHeader {
|
||||||
Id = sender?.Id ?? Guid.Empty,
|
Id = sender?.Id ?? Guid.Empty,
|
||||||
|
@ -97,7 +96,7 @@ public class Server {
|
||||||
throw new Exception($"First packet was not init, instead it was {header.Type}");
|
throw new Exception($"First packet was not init, instead it was {header.Type}");
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectPacket connect = MemoryMarshal.Read<ConnectPacket>(memory.Memory.Span[HeaderSize..size]);
|
ConnectPacket connect = MemoryMarshal.Read<ConnectPacket>(memory.Memory.Span[Constants.HeaderSize..size]);
|
||||||
lock (Clients) {
|
lock (Clients) {
|
||||||
switch (connect.ConnectionType) {
|
switch (connect.ConnectionType) {
|
||||||
case ConnectionTypes.FirstConnection: {
|
case ConnectionTypes.FirstConnection: {
|
||||||
|
@ -136,7 +135,10 @@ public class Server {
|
||||||
|
|
||||||
|
|
||||||
// todo support variable length packets when they show up
|
// todo support variable length packets when they show up
|
||||||
if (header.Sender == PacketSender.Client) await Broadcast(memory, client);
|
if (header.Sender == PacketSender.Client) {
|
||||||
|
Logger.Warn($"broadcasting {header.Type}");
|
||||||
|
await Broadcast(memory, client);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
//todo handle server packets :)
|
//todo handle server packets :)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using Shared.Packet;
|
using Shared.Packet;
|
||||||
using Shared.Packet.Packets;
|
using Shared.Packet.Packets;
|
||||||
|
|
||||||
|
@ -7,6 +8,7 @@ namespace Shared;
|
||||||
public static class Constants {
|
public static class Constants {
|
||||||
public const int MaxPacketSize = 256;
|
public const int MaxPacketSize = 256;
|
||||||
public const int MaxClients = 4;
|
public const int MaxClients = 4;
|
||||||
|
public static int HeaderSize => Marshal.SizeOf<PacketHeader>();
|
||||||
|
|
||||||
// dictionary of packet types to packet
|
// dictionary of packet types to packet
|
||||||
public static readonly Dictionary<Type, PacketAttribute> Packets = Assembly
|
public static readonly Dictionary<Type, PacketAttribute> Packets = Assembly
|
||||||
|
|
|
@ -2,4 +2,11 @@
|
||||||
|
|
||||||
[Packet(PacketType.Command)]
|
[Packet(PacketType.Command)]
|
||||||
public struct CommandPacket : IPacket {
|
public struct CommandPacket : IPacket {
|
||||||
|
public void Serialize(Span<byte> data) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(Span<byte> data) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,15 @@
|
||||||
namespace Shared.Packet.Packets;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Shared.Packet.Packets;
|
||||||
|
|
||||||
[Packet(PacketType.Connect)]
|
[Packet(PacketType.Connect)]
|
||||||
public struct ConnectPacket : IPacket {
|
public struct ConnectPacket : IPacket {
|
||||||
public ConnectionTypes ConnectionType;
|
public ConnectionTypes ConnectionType;
|
||||||
|
public void Serialize(Span<byte> data) {
|
||||||
|
MemoryMarshal.Write(data, ref ConnectionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(Span<byte> data) {
|
||||||
|
ConnectionType = MemoryMarshal.Read<ConnectionTypes>(data);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -6,8 +6,17 @@ namespace Shared.Packet.Packets;
|
||||||
public struct CostumePacket : IPacket {
|
public struct CostumePacket : IPacket {
|
||||||
public const int CostumeNameSize = 0x20;
|
public const int CostumeNameSize = 0x20;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CostumeNameSize)]
|
|
||||||
public string BodyName;
|
public string BodyName;
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CostumeNameSize)]
|
|
||||||
public string CapName;
|
public string CapName;
|
||||||
|
public void Serialize(Span<byte> data) {
|
||||||
|
Span<char> strData = MemoryMarshal.Cast<byte, char>(data);
|
||||||
|
BodyName.CopyTo(strData[..CostumeNameSize]);
|
||||||
|
CapName.CopyTo(strData[CostumeNameSize..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(Span<byte> data) {
|
||||||
|
Span<char> strData = MemoryMarshal.Cast<byte, char>(data);
|
||||||
|
BodyName = new string(strData[..CostumeNameSize].TrimEnd('\0'));
|
||||||
|
CapName = new string(strData[CostumeNameSize..].TrimEnd('\0'));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,4 +2,11 @@
|
||||||
|
|
||||||
[Packet(PacketType.Disconnect)]
|
[Packet(PacketType.Disconnect)]
|
||||||
public struct DisconnectPacket : IPacket {
|
public struct DisconnectPacket : IPacket {
|
||||||
|
public void Serialize(Span<byte> data) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(Span<byte> data) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,4 +2,6 @@
|
||||||
|
|
||||||
// Packet interface for type safety
|
// Packet interface for type safety
|
||||||
public interface IPacket {
|
public interface IPacket {
|
||||||
|
void Serialize(Span<byte> data);
|
||||||
|
void Deserialize(Span<byte> data);
|
||||||
}
|
}
|
|
@ -9,17 +9,52 @@ public struct PlayerPacket : IPacket {
|
||||||
|
|
||||||
public Vector3 Position;
|
public Vector3 Position;
|
||||||
public Quaternion Rotation;
|
public Quaternion Rotation;
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
|
||||||
public float[] AnimationBlendWeights;
|
public float[] AnimationBlendWeights;
|
||||||
public float AnimationRate;
|
public float AnimationRate;
|
||||||
public bool Flat;
|
public bool Flat;
|
||||||
public bool ThrowingCap;
|
public bool ThrowingCap;
|
||||||
public bool Seeker;
|
public bool Seeker;
|
||||||
public int ScenarioNum;
|
public int ScenarioNum;
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NameSize)]
|
|
||||||
public string Stage;
|
public string Stage;
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NameSize)]
|
|
||||||
public string Act;
|
public string Act;
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NameSize)]
|
|
||||||
public string SubAct;
|
public string SubAct;
|
||||||
|
|
||||||
|
public void Serialize(Span<byte> data) {
|
||||||
|
int offset = 0;
|
||||||
|
MemoryMarshal.Write(data, ref Position);
|
||||||
|
offset += Marshal.SizeOf<Vector3>();
|
||||||
|
MemoryMarshal.Write(data[offset..], ref Rotation);
|
||||||
|
offset += Marshal.SizeOf<Quaternion>();
|
||||||
|
AnimationBlendWeights.CopyTo(MemoryMarshal.Cast<byte, float>(data[offset..(offset += 4 * 6)]));
|
||||||
|
MemoryMarshal.Write(data[(offset += 4)..], ref AnimationRate);
|
||||||
|
offset += 4;
|
||||||
|
MemoryMarshal.Write(data[offset++..], ref Flat);
|
||||||
|
MemoryMarshal.Write(data[offset++..], ref ThrowingCap);
|
||||||
|
MemoryMarshal.Write(data[offset++..], ref Seeker);
|
||||||
|
MemoryMarshal.Write(data[(offset += 4)..], ref ScenarioNum);
|
||||||
|
Span<char> strData = MemoryMarshal.Cast<byte, char>(data[offset..]);
|
||||||
|
Stage.CopyTo(strData[..NameSize]);
|
||||||
|
Act.CopyTo(strData[NameSize..(2 * NameSize)]);
|
||||||
|
SubAct.CopyTo(strData[(2 * NameSize)..(3 * NameSize)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(Span<byte> data) {
|
||||||
|
int offset = 0;
|
||||||
|
Position = MemoryMarshal.Read<Vector3>(data);
|
||||||
|
offset += Marshal.SizeOf<Vector3>();
|
||||||
|
Rotation = MemoryMarshal.Read<Quaternion>(data[offset..]);
|
||||||
|
offset += Marshal.SizeOf<Quaternion>();
|
||||||
|
AnimationBlendWeights = MemoryMarshal.Cast<byte, float>(data[offset..(offset + 4 * 6)]).ToArray();
|
||||||
|
offset += 4 * 6;
|
||||||
|
AnimationRate = MemoryMarshal.Read<float>(data[(offset += 4)..]);
|
||||||
|
offset += 4;
|
||||||
|
Flat = MemoryMarshal.Read<bool>(data[offset++..]);
|
||||||
|
ThrowingCap = MemoryMarshal.Read<bool>(data[offset++..]);
|
||||||
|
Seeker = MemoryMarshal.Read<bool>(data[offset++..]);
|
||||||
|
ScenarioNum = MemoryMarshal.Read<int>(data[(offset += 4)..]);
|
||||||
|
Span<char> strData = MemoryMarshal.Cast<byte, char>(data[offset..]);
|
||||||
|
Stage = new string(strData[..NameSize].TrimEnd('\0'));
|
||||||
|
Act = new string(strData[NameSize..(2 * NameSize)].TrimEnd('\0'));
|
||||||
|
SubAct = new string(strData[(2 * NameSize)..(3 * NameSize)].TrimEnd('\0'));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,15 @@
|
||||||
namespace Shared.Packet.Packets;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Shared.Packet.Packets;
|
||||||
|
|
||||||
[Packet(PacketType.Shine)]
|
[Packet(PacketType.Shine)]
|
||||||
public struct ShinePacket : IPacket {
|
public struct ShinePacket : IPacket {
|
||||||
public int ShineId;
|
public int ShineId;
|
||||||
|
public void Serialize(Span<byte> data) {
|
||||||
|
MemoryMarshal.Write(data, ref ShineId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(Span<byte> data) {
|
||||||
|
ShineId = MemoryMarshal.Read<int>(data);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
using System.Net.Sockets;
|
using System.Buffers;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Shared;
|
using Shared;
|
||||||
using Shared.Packet;
|
using Shared.Packet;
|
||||||
|
@ -8,9 +11,53 @@ TcpClient client = new TcpClient("127.0.0.1", 1027);
|
||||||
Guid ownId = new Guid();
|
Guid ownId = new Guid();
|
||||||
Logger logger = new Logger("Client");
|
Logger logger = new Logger("Client");
|
||||||
NetworkStream stream = client.GetStream();
|
NetworkStream stream = client.GetStream();
|
||||||
|
PacketHeader coolHeader = new PacketHeader {
|
||||||
|
Type = PacketType.Connect,
|
||||||
|
Sender = PacketSender.Client,
|
||||||
|
Id = Guid.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
int e = 0;
|
||||||
|
double d = 0;
|
||||||
|
|
||||||
// void WritePacket(Span<byte> data, IPacket packet) {
|
async Task S() {
|
||||||
// MemoryMarshal.Write();
|
IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(256);
|
||||||
// }
|
while (true) {
|
||||||
// stream.Write();
|
await stream.ReadAsync(owner.Memory);
|
||||||
|
PacketHeader header = MemoryMarshal.Read<PacketHeader>(owner.Memory.Span);
|
||||||
|
if (header.Type == PacketType.Player) {
|
||||||
|
if (e++ != 0) {
|
||||||
|
e %= 3;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
d += Math.PI;
|
||||||
|
for (int i = 0; i < 1; i++) {
|
||||||
|
unsafe {
|
||||||
|
coolHeader.Id = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)i);
|
||||||
|
MemoryMarshal.Write(owner.Memory.Span, ref coolHeader);
|
||||||
|
// unbelievably shitty way to marshal playerpacket
|
||||||
|
fixed (byte* basePtr = owner.Memory.Span) {
|
||||||
|
byte* dataPtr = basePtr + Constants.HeaderSize;
|
||||||
|
Vector3 pos = Unsafe.Read<Vector3>(dataPtr);
|
||||||
|
pos.X += 1000f * (float)Math.Cos(d);
|
||||||
|
pos.Z += 1000f * (float)Math.Sin(d);
|
||||||
|
Unsafe.Write(dataPtr, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Console.WriteLine($"aargh {coolHeader.Id} {owner.Memory.Span.Hex()}");
|
||||||
|
await stream.WriteAsync(owner.Memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(256);
|
||||||
|
MemoryMarshal.Write(owner.Memory.Span[..], ref coolHeader);
|
||||||
|
ConnectPacket connect = new ConnectPacket {
|
||||||
|
ConnectionType = ConnectionTypes.FirstConnection
|
||||||
|
};
|
||||||
|
MemoryMarshal.Write(owner.Memory.Span[Constants.HeaderSize..256], ref connect);
|
||||||
|
await stream.WriteAsync(owner.Memory);
|
||||||
|
coolHeader.Type = PacketType.Player;
|
||||||
|
MemoryMarshal.Write(owner.Memory.Span[..], ref coolHeader);
|
||||||
|
await S();
|
|
@ -5,6 +5,7 @@
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
Loading…
Reference in a new issue