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

Add scenario merging and run reformatting on solution

This commit is contained in:
Sanae 2022-03-01 15:08:53 -06:00
parent 3d4356ccfc
commit 00626ab12f
9 changed files with 86 additions and 36 deletions

View file

@ -25,15 +25,19 @@ public class Client : IDisposable {
Socket = socket; Socket = socket;
Logger = new Logger(socket.RemoteEndPoint?.ToString() ?? "Unknown User???"); Logger = new Logger(socket.RemoteEndPoint?.ToString() ?? "Unknown User???");
} }
public void Dispose() { public void Dispose() {
if (Socket?.Connected is true) if (Socket?.Connected is true)
Socket.Disconnect(false); Socket.Disconnect(false);
} }
public delegate IPacket PacketTransformerDel(Client? sender, IPacket packet);
public event PacketTransformerDel? PacketTransformer;
public async Task Send<T>(T packet, Client? sender = null) where T : struct, IPacket { public async Task Send<T>(T packet, Client? sender = null) where T : struct, IPacket {
IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize); IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize);
packet = (T) (PacketTransformer?.Invoke(sender, packet) ?? packet);
PacketHeader header = new PacketHeader { PacketHeader header = new PacketHeader {
Id = sender?.Id ?? Guid.Empty, Id = sender?.Id ?? Guid.Empty,
Type = Constants.PacketMap[typeof(T)].Type Type = Constants.PacketMap[typeof(T)].Type

View file

@ -19,7 +19,8 @@ public static class CommandHandler {
if (args.Length == 0) return "No command entered, see help command for valid commands"; if (args.Length == 0) return "No command entered, see help command for valid commands";
string commandName = args[0]; string commandName = args[0];
return Handlers.TryGetValue(commandName, out Handler? handler) ? handler(args[1..]) : $"Invalid command {args[0]}, see help command for valid commands"; return Handlers.TryGetValue(commandName, out Handler? handler) ? handler(args[1..]) : $"Invalid command {args[0]}, see help command for valid commands";
} catch (Exception e) { }
catch (Exception e) {
return $"An error occured while trying to process your command: {e}"; return $"An error occured while trying to process your command: {e}";
} }
} }

View file

@ -1,4 +1,4 @@
namespace Server; namespace Server;
public enum FlipOptions { public enum FlipOptions {
Both, Both,

View file

@ -15,6 +15,15 @@ Logger consoleLogger = new Logger("Console");
server.ClientJoined += async (c, type) => { server.ClientJoined += async (c, type) => {
c.Metadata["shineSync"] = new ConcurrentBag<int>(); c.Metadata["shineSync"] = new ConcurrentBag<int>();
c.Metadata["loadedSave"] = false; c.Metadata["loadedSave"] = false;
c.Metadata["scenario"] = 0;
c.PacketTransformer += (sender, packet) => {
if (Settings.Instance.Scenario.MergeEnabled && packet is PlayerPacket playerPacket) {
playerPacket.ScenarioNum = (int) c.Metadata["scenario"];
return playerPacket;
}
return packet;
};
}; };
async Task ClientSyncShineBag(Client client) { async Task ClientSyncShineBag(Client client) {
@ -23,7 +32,8 @@ async Task ClientSyncShineBag(Client client) {
await client.Send(new ShinePacket { await client.Send(new ShinePacket {
ShineId = shine ShineId = shine
}); });
} catch { }
catch {
// errors that can happen when sending will crash the server :) // errors that can happen when sending will crash the server :)
} }
} }
@ -39,8 +49,14 @@ timer.Elapsed += (_, _) => { SyncShineBag(); };
timer.Start(); timer.Start();
bool flipEnabled = Settings.Instance.Flip.EnabledOnStart; bool flipEnabled = Settings.Instance.Flip.EnabledOnStart;
float MarioSize(bool is2d) => is2d ? 180 : 160; float MarioSize(bool is2d) {
return is2d ? 180 : 160;
}
server.PacketHandler = (c, p) => { server.PacketHandler = (c, p) => {
{
if (p is PlayerPacket playerPacket) c.Metadata["scenario"] = playerPacket.ScenarioNum;
}
switch (p) { switch (p) {
case CostumePacket: case CostumePacket:
ClientSyncShineBag(c); ClientSyncShineBag(c);
@ -77,12 +93,25 @@ server.PacketHandler = (c, p) => {
return true; return true;
}; };
//
// CommandHandler.RegisterCommand("scenario", args => { CommandHandler.RegisterCommand("scenario", args => {
// const string optionUsage = "Valid options: split <" const string optionUsage = "Valid options: merge <true/false>";
// if (args.Length < 1) if (args.Length < 1)
// return return optionUsage;
// }); switch (args[0]) {
case "merge" when args.Length == 2: {
if (bool.TryParse(args[1], out bool result)) {
Settings.Instance.Scenario.MergeEnabled = result;
Settings.SaveSettings();
return result ? "Enabled scenario merge" : "Disabled scenario merge";
}
return optionUsage;
}
default:
return optionUsage;
}
});
CommandHandler.RegisterCommand("list", _ => $"List: {string.Join(", ", server.Clients.Select(x => $"{x.Name} ({x.Id})"))}"); CommandHandler.RegisterCommand("list", _ => $"List: {string.Join(", ", server.Clients.Select(x => $"{x.Name} ({x.Id})"))}");
@ -142,9 +171,8 @@ CommandHandler.RegisterCommand("shine", args => {
return $"Shines: {string.Join(", ", shineBag)}"; return $"Shines: {string.Join(", ", shineBag)}";
case "clear" when args.Length == 1: case "clear" when args.Length == 1:
shineBag.Clear(); shineBag.Clear();
foreach (ConcurrentBag<int> playerBag in server.Clients.Select(serverClient => (ConcurrentBag<int>) serverClient.Metadata["shineSync"])) { foreach (ConcurrentBag<int> playerBag in server.Clients.Select(serverClient => (ConcurrentBag<int>) serverClient.Metadata["shineSync"])) playerBag.Clear();
playerBag.Clear();
}
return "Cleared shine bags"; return "Cleared shine bags";
default: default:
return optionUsage; return optionUsage;

View file

@ -38,22 +38,28 @@ public class Server {
} }
Task.Run(() => HandleSocket(socket)); Task.Run(() => HandleSocket(socket));
} catch { }
catch {
// super ignore this // super ignore this
} }
} }
} catch (OperationCanceledException) { }
catch (OperationCanceledException) {
// ignore the exception, it's just for closing the server // ignore the exception, it's just for closing the server
} }
Logger.Info("Server closing"); Logger.Info("Server closing");
try { try {
serverSocket.Shutdown(SocketShutdown.Both); serverSocket.Shutdown(SocketShutdown.Both);
} catch (Exception) { }
catch (Exception) {
// ignore // ignore
} finally { }
finally {
serverSocket.Close(); serverSocket.Close();
} }
Logger.Info("Server closed"); Logger.Info("Server closed");
} }
@ -66,11 +72,11 @@ public class Server {
// broadcast packets to all clients // broadcast packets to all clients
public delegate void PacketReplacer<in T>(Client from, Client to, T value); // replacer must send public delegate void PacketReplacer<in T>(Client from, Client to, T value); // replacer must send
public async Task BroadcastReplace<T>(T packet, Client sender, PacketReplacer<T> packetReplacer) where T : struct, IPacket { public async Task BroadcastReplace<T>(T packet, Client sender, PacketReplacer<T> packetReplacer) where T : struct, IPacket {
foreach (Client client in Clients.Where(client => sender.Id != client.Id)) { foreach (Client client in Clients.Where(client => sender.Id != client.Id)) packetReplacer(sender, client, packet);
packetReplacer(sender, client, packet);
}
} }
public async Task Broadcast<T>(T packet, Client sender) where T : struct, IPacket { public async Task Broadcast<T>(T packet, Client sender) where T : struct, IPacket {
IMemoryOwner<byte> memory = memoryPool.RentZero(Constants.MaxPacketSize); IMemoryOwner<byte> memory = memoryPool.RentZero(Constants.MaxPacketSize);
@ -107,7 +113,7 @@ public class Server {
private async void HandleSocket(Socket socket) { private async void HandleSocket(Socket socket) {
Client client = new Client(socket) { Server = this }; Client client = new Client(socket) {Server = this};
IMemoryOwner<byte> memory = null!; IMemoryOwner<byte> memory = null!;
bool first = true; bool first = true;
try { try {
@ -205,7 +211,9 @@ public class Server {
}); });
Logger.Info($"Client {client.Name} ({client.Id}/{socket.RemoteEndPoint}) connected."); Logger.Info($"Client {client.Name} ({client.Id}/{socket.RemoteEndPoint}) connected.");
} else if (header.Id != client.Id && client.Id != Guid.Empty) throw new Exception($"Client {client.Name} sent packet with invalid client id {header.Id} instead of {client.Id}"); } else if (header.Id != client.Id && client.Id != Guid.Empty) {
throw new Exception($"Client {client.Name} sent packet with invalid client id {header.Id} instead of {client.Id}");
}
if (header.Type == PacketType.Costume) { if (header.Type == PacketType.Costume) {
CostumePacket costumePacket = new CostumePacket { CostumePacket costumePacket = new CostumePacket {
@ -223,14 +231,16 @@ public class Server {
memory.Dispose(); memory.Dispose();
continue; continue;
} }
} catch (Exception e){ }
catch (Exception e) {
client.Logger.Error($"Packet handler warning: {e}"); client.Logger.Error($"Packet handler warning: {e}");
} }
Broadcast(memory, client); Broadcast(memory, client);
} }
} catch (Exception e) { }
if (e is SocketException { SocketErrorCode: SocketError.ConnectionReset }) { catch (Exception e) {
if (e is SocketException {SocketErrorCode: SocketError.ConnectionReset}) {
client.Logger.Info($"Client {socket.RemoteEndPoint} ({client.Id}) disconnected from the server"); client.Logger.Info($"Client {socket.RemoteEndPoint} ({client.Id}) disconnected from the server");
} else { } else {
client.Logger.Error($"Exception on socket {socket.RemoteEndPoint} ({client.Id}) and disconnecting for: {e}"); client.Logger.Error($"Exception on socket {socket.RemoteEndPoint} ({client.Id}) and disconnecting for: {e}");

View file

@ -8,11 +8,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" /> <ProjectReference Include="..\Shared\Shared.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -20,7 +20,8 @@ public class Settings {
try { try {
Instance = JsonConvert.DeserializeObject<Settings>(text, new StringEnumConverter(new CamelCaseNamingStrategy())) ?? Instance; Instance = JsonConvert.DeserializeObject<Settings>(text, new StringEnumConverter(new CamelCaseNamingStrategy())) ?? Instance;
Logger.Info("Loaded settings from settings.json"); Logger.Info("Loaded settings from settings.json");
} catch (Exception e) { }
catch (Exception e) {
Logger.Warn($"Failed to load settings.json: {e}"); Logger.Warn($"Failed to load settings.json: {e}");
} }
} else { } else {
@ -32,19 +33,25 @@ public class Settings {
try { try {
File.WriteAllText("settings.json", JsonConvert.SerializeObject(Instance, Formatting.Indented, new StringEnumConverter(new CamelCaseNamingStrategy()))); File.WriteAllText("settings.json", JsonConvert.SerializeObject(Instance, Formatting.Indented, new StringEnumConverter(new CamelCaseNamingStrategy())));
Logger.Info("Saved settings to settings.json"); Logger.Info("Saved settings to settings.json");
} catch (Exception e) { }
catch (Exception e) {
Logger.Error($"Failed to save settings.json {e}"); Logger.Error($"Failed to save settings.json {e}");
} }
} }
public ServerTable Server { get; set; } = new ServerTable(); public ServerTable Server { get; set; } = new ServerTable();
public FlipTable Flip { get; set; } = new FlipTable(); public FlipTable Flip { get; set; } = new FlipTable();
public ScenarioTable Scenario { get; set; } = new ScenarioTable();
public class ServerTable { public class ServerTable {
public string Address { get; set; } = IPAddress.Any.ToString(); public string Address { get; set; } = IPAddress.Any.ToString();
public ushort Port { get; set; } = 1027; public ushort Port { get; set; } = 1027;
} }
public class ScenarioTable {
public bool MergeEnabled { get; set; } = false;
}
public class FlipTable { public class FlipTable {
public List<Guid> Players { get; set; } = new List<Guid>(); public List<Guid> Players { get; set; } = new List<Guid>();
public bool EnabledOnStart { get; set; } = true; public bool EnabledOnStart { get; set; } = true;

View file

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

View file

@ -25,6 +25,7 @@ PacketType[] reboundPackets = {
}; };
string lastCapture = ""; string lastCapture = "";
async Task S() { async Task S() {
IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(Constants.MaxPacketSize); IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(Constants.MaxPacketSize);
while (true) { while (true) {
@ -37,9 +38,7 @@ async Task S() {
PlayerPacket playerPacket = new PlayerPacket(); PlayerPacket playerPacket = new PlayerPacket();
playerPacket.Deserialize(owner.Memory.Span[Constants.HeaderSize..]); playerPacket.Deserialize(owner.Memory.Span[Constants.HeaderSize..]);
logger.Info(playerPacket.Hack); logger.Info(playerPacket.Hack);
if (playerPacket.Hack != lastCapture) { if (playerPacket.Hack != lastCapture) logger.Info($"Changed to hack: {lastCapture = playerPacket.Hack}");
logger.Info($"Changed to hack: {lastCapture = playerPacket.Hack}");
}
// cap.Position = playerPacket.Position + Vector3.UnitY * 500f; // cap.Position = playerPacket.Position + Vector3.UnitY * 500f;
// cap.Rotation = Quaternion.CreateFromYawPitchRoll(0,0,0); // cap.Rotation = Quaternion.CreateFromYawPitchRoll(0,0,0);
// cap.CapAnim = "StayR"; // cap.CapAnim = "StayR";
@ -55,6 +54,7 @@ async Task S() {
// await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]); // await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
// continue; // continue;
} }
if (reboundPackets.All(x => x != type)) continue; if (reboundPackets.All(x => x != type)) continue;
header.Id = ownId; header.Id = ownId;
MemoryMarshal.Write(owner.Memory.Span, ref header); MemoryMarshal.Write(owner.Memory.Span, ref header);