mirror of
https://github.com/Sanae6/SmoOnlineServer.git
synced 2024-11-24 20:25:18 +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;
|
||||
public readonly List<Client> Clients = new List<Client>();
|
||||
public readonly Logger Logger = new Logger("Server");
|
||||
private static int HeaderSize => Marshal.SizeOf<PacketHeader>();
|
||||
public async Task Listen(ushort port) {
|
||||
TcpListener listener = TcpListener.Create(port);
|
||||
|
||||
|
@ -34,12 +33,12 @@ public class Server {
|
|||
Span<byte> data = memory.Span;
|
||||
|
||||
MemoryMarshal.Write(data, ref header);
|
||||
MemoryMarshal.Write(data[HeaderSize..], ref packet);
|
||||
MemoryMarshal.Write(data[Constants.HeaderSize..], ref packet);
|
||||
}
|
||||
|
||||
// broadcast packets to all clients
|
||||
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 {
|
||||
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}");
|
||||
}
|
||||
|
||||
ConnectPacket connect = MemoryMarshal.Read<ConnectPacket>(memory.Memory.Span[HeaderSize..size]);
|
||||
ConnectPacket connect = MemoryMarshal.Read<ConnectPacket>(memory.Memory.Span[Constants.HeaderSize..size]);
|
||||
lock (Clients) {
|
||||
switch (connect.ConnectionType) {
|
||||
case ConnectionTypes.FirstConnection: {
|
||||
|
@ -136,7 +135,10 @@ public class Server {
|
|||
|
||||
|
||||
// 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 {
|
||||
//todo handle server packets :)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Shared.Packet;
|
||||
using Shared.Packet.Packets;
|
||||
|
||||
|
@ -7,6 +8,7 @@ namespace Shared;
|
|||
public static class Constants {
|
||||
public const int MaxPacketSize = 256;
|
||||
public const int MaxClients = 4;
|
||||
public static int HeaderSize => Marshal.SizeOf<PacketHeader>();
|
||||
|
||||
// dictionary of packet types to packet
|
||||
public static readonly Dictionary<Type, PacketAttribute> Packets = Assembly
|
||||
|
|
|
@ -2,4 +2,11 @@
|
|||
|
||||
[Packet(PacketType.Command)]
|
||||
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)]
|
||||
public struct ConnectPacket : IPacket {
|
||||
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 const int CostumeNameSize = 0x20;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CostumeNameSize)]
|
||||
public string BodyName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CostumeNameSize)]
|
||||
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)]
|
||||
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
|
||||
public interface IPacket {
|
||||
void Serialize(Span<byte> data);
|
||||
void Deserialize(Span<byte> data);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Shared.Packet.Packets;
|
||||
namespace Shared.Packet.Packets;
|
||||
|
||||
[Packet(PacketType.Player)]
|
||||
public struct PlayerPacket : IPacket {
|
||||
|
@ -9,17 +9,52 @@ public struct PlayerPacket : IPacket {
|
|||
|
||||
public Vector3 Position;
|
||||
public Quaternion Rotation;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public float[] AnimationBlendWeights;
|
||||
public float AnimationRate;
|
||||
public bool Flat;
|
||||
public bool ThrowingCap;
|
||||
public bool Seeker;
|
||||
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;
|
||||
|
||||
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)]
|
||||
public struct ShinePacket : IPacket {
|
||||
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 Shared;
|
||||
using Shared.Packet;
|
||||
|
@ -8,9 +11,53 @@ TcpClient client = new TcpClient("127.0.0.1", 1027);
|
|||
Guid ownId = new Guid();
|
||||
Logger logger = new Logger("Client");
|
||||
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) {
|
||||
// MemoryMarshal.Write();
|
||||
// }
|
||||
// stream.Write();
|
||||
async Task S() {
|
||||
IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(256);
|
||||
while (true) {
|
||||
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>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
Loading…
Reference in a new issue