diff --git a/BLHX.Server.Common/Utils/Logger.cs b/BLHX.Server.Common/Utils/Logger.cs index b659e8c..de08336 100644 --- a/BLHX.Server.Common/Utils/Logger.cs +++ b/BLHX.Server.Common/Utils/Logger.cs @@ -26,7 +26,7 @@ namespace BLHX.Server.Common.Utils Console.Write(_name); Console.ResetColor(); Console.Write("> "); - Console.WriteLine(string.Join("\t", message)); + Console.Write(string.Join("\t", message.Append(Environment.NewLine))); Console.ResetColor(); } @@ -40,14 +40,14 @@ namespace BLHX.Server.Common.Utils Console.Write(_name); Console.ResetColor(); Console.Write("> "); - Console.WriteLine(string.Join("\t", message)); + Console.Write(string.Join("\t", message.Append(Environment.NewLine))); Console.ResetColor(); } public void Trail(params string[] msg) { Console.ForegroundColor = ConsoleColor.DarkGray; - Console.WriteLine($"\t└── {string.Join(' ', msg)}"); + Console.Write($"\t└── {string.Join(' ', msg)}\n"); Console.ResetColor(); } @@ -64,7 +64,7 @@ namespace BLHX.Server.Common.Utils Console.ForegroundColor = ConsoleColor.White; if (TraceOnError) Console.BackgroundColor = ConsoleColor.DarkRed; - Console.WriteLine(string.Join("\t", message)); + Console.Write(string.Join("\t", message.Append(Environment.NewLine))); Console.ResetColor(); #if DEBUG StackTrace trace = new(true); @@ -86,7 +86,7 @@ namespace BLHX.Server.Common.Utils Console.Write("> "); Console.ForegroundColor = ConsoleColor.White; Console.BackgroundColor = ConsoleColor.DarkMagenta; - Console.WriteLine(string.Join("\t", message)); + Console.Write(string.Join("\t", message.Append(Environment.NewLine))); Console.ResetColor(); Console.BackgroundColor = ConsoleColor.Black; diff --git a/BLHX.Server.Game/Connection.cs b/BLHX.Server.Game/Connection.cs index 9980427..631ae33 100644 --- a/BLHX.Server.Game/Connection.cs +++ b/BLHX.Server.Game/Connection.cs @@ -5,14 +5,16 @@ using ProtoBuf; using System.Buffers.Binary; using System.Net; using System.Net.Sockets; +using System.Security.AccessControl; +using System.Text; using System.Text.Json; namespace BLHX.Server.Game { public class Connection { + public readonly Logger c; readonly TcpClient tcpClient; - readonly Logger c; readonly CancellationTokenSource cts = new(); readonly Task loopTask; ushort packetIdx = 0; @@ -32,6 +34,7 @@ namespace BLHX.Server.Game { var ns = tcpClient.GetStream(); var buf = GC.AllocateUninitializedArray(ushort.MaxValue); + // TODO: pos isn't actually doing anything var pos = 0; while (!cts.Token.IsCancellationRequested) @@ -47,32 +50,51 @@ namespace BLHX.Server.Game int readLen = 0; while (readLen < len) { + if (buf.AsSpan(0, 22).SequenceEqual(Encoding.UTF8.GetBytes("GET /?cmd=load_server?"))) + { + string svrList = @"[{""id"":1,""name"":""BLHX.Server"",""state"":0,""flag"":0,""sort"":0}]"; + SendHttpResponse(svrList, "application/json"); + readLen = len; + cts.Cancel(); + break; + } + if (len - readLen < Packet.HEADER_SIZE + Packet.LENGTH_SIZE) break; var packet = new Packet(buf[readLen..]); - if (packet.command == Command.Cs10800) - { - var dec = packet.Decode(); - c.Debug(JsonSerializer.Serialize(dec, jsonSerializerOptions)); - } + c.Log(packet.command.ToString()); + + var handler = PacketFactory.GetPacketHandler(packet.command); + if (handler is not null) + handler(this, packet); + else + c.Warn($"{packet.command} unhandled!" +#if DEBUG + , Enum.IsDefined(packet.command) ? BitConverter.ToString(packet.bytes).Replace("-", "") : BitConverter.ToString(buf[readLen..]).Replace("-", "") +#endif + ); + readLen += packet.length + Packet.LENGTH_SIZE; } - pos += len - readLen; - if (pos > 0) - Array.Copy(buf, readLen, buf, 0, pos); + if (len == readLen) + pos = 0; } catch (Exception ex) { c.Error($"An error occured while reading packets {ex}"); + break; } } + + EndProtocol(); } public void Send(T packet) where T : IExtensible { Command command = Enum.Parse(packet.GetType().Name); + c.Log(command.ToString()); var ns = tcpClient.GetStream(); using var ms = new MemoryStream(); @@ -85,10 +107,21 @@ namespace BLHX.Server.Game BinaryPrimitives.WriteUInt16BigEndian(sendBuf.AsSpan(Packet.HEADER_SIZE), NextPacketIdx); ms.ToArray().CopyTo(sendBuf.AsSpan(Packet.LENGTH_SIZE + Packet.HEADER_SIZE)); - c.Debug(BitConverter.ToString(sendBuf).Replace("-", "")); + // c.Debug(BitConverter.ToString(sendBuf).Replace("-", "")); ns.Write(sendBuf); } + public void SendHttpResponse(string rsp, string type = "text/plain") + { + tcpClient.GetStream().Write(Encoding.UTF8.GetBytes( + "HTTP/1.1 200 OK" + Environment.NewLine + + "Content-Length: " + rsp.Length + Environment.NewLine + + "Content-Type: " + type + Environment.NewLine + + Environment.NewLine + + rsp + + Environment.NewLine + Environment.NewLine)); + } + public void EndProtocol() { cts.Cancel(); diff --git a/BLHX.Server.Game/GameServer.cs b/BLHX.Server.Game/GameServer.cs index 1d4927c..5d7c481 100644 --- a/BLHX.Server.Game/GameServer.cs +++ b/BLHX.Server.Game/GameServer.cs @@ -13,6 +13,9 @@ namespace BLHX.Server.Game static GameServer() { + // Preload + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(PacketFactory).TypeHandle); + EndPoint = new(IPAddress.Any, 20000); listener = new TcpListener(EndPoint); } diff --git a/BLHX.Server.Game/Handlers/P10.cs b/BLHX.Server.Game/Handlers/P10.cs new file mode 100644 index 0000000..398a478 --- /dev/null +++ b/BLHX.Server.Game/Handlers/P10.cs @@ -0,0 +1,72 @@ +using BHXY.Server.Common.Proto.p10; +using BLHX.Server.Common.Proto; + +namespace BLHX.Server.Game.Handlers +{ + internal static class P10 + { + [PacketHandler(Command.Cs10800)] + static void Cs10800Handler(Connection connection, Packet packet) + { + var req = packet.Decode(); + connection.Send(new Sc10801() + { + GatewayIp = "192.168.1.4", + GatewayPort = 20000, + Url = "http://192.168.1.4", + ProxyIp = "192.168.1.4", + ProxyPort = 20000, + Versions = [ + "$azhash$7$1$459$470aa097fec844d6", + "$cvhash$467$98edcdd4e7dac668", + "$l2dhash$514$b59cdb747b1c64c9", + "$pichash$15$0d6f59289972cc8a", + "$bgmhash$13$76fdc897426a138d", + "$paintinghash$82$6daa07fa50583c60", + "$mangahash$24$3cefad85368b3296", + "$cipherhash$24$3cefad85368b3296", + "dTag-1" + ], + Timestamp = (uint)DateTimeOffset.Now.ToUnixTimeSeconds(), + Monday0oclockTimestamp = 1606114800 + }); + } + + [PacketHandler(Command.Cs10020)] + static void Cs10020Handler(Connection connection, Packet packet) + { + // Arg2 uid + // Arg3 accessToken + // CheckKey md5(Arg1 + salt) + var req = packet.Decode(); + connection.Send(new Sc10021() + { + Result = 0, + AccountId = 1, + Serverlists = [ + new Serverinfo() + { + Ids = [0], + Name = "BLHX.Server", + Ip = "192.168.1.4", + Port = 20000, + ProxyIp = "192.168.1.4", + ProxyPort = 20000 + } + ], + ServerTicket = req.Arg3 + }); + } + + [PacketHandler(Command.Cs10022)] + static void Cs10022Handler(Connection connection, Packet packet) + { + var req = packet.Decode(); + connection.Send(new Sc10023() + { + Result = 0, + UserId = 1 + }); + } + } +} diff --git a/BLHX.Server.Game/Packet.cs b/BLHX.Server.Game/Packet.cs index 2de0266..d57cac8 100644 --- a/BLHX.Server.Game/Packet.cs +++ b/BLHX.Server.Game/Packet.cs @@ -1,6 +1,8 @@ using BLHX.Server.Common.Proto; +using BLHX.Server.Common.Utils; using ProtoBuf; using System.Buffers.Binary; +using System.Reflection; namespace BLHX.Server.Game { @@ -26,4 +28,43 @@ namespace BLHX.Server.Game public T Decode() where T : IExtensible => Serializer.Deserialize(bytes.AsSpan()); } + + static class PacketFactory + { + static readonly Logger c = new(nameof(PacketFactory), ConsoleColor.DarkGreen); + static readonly Dictionary handlers = []; + + static PacketFactory() + { + LoadPacketHandlers(); + } + + private static void LoadPacketHandlers() + { + foreach (var method in Assembly.GetExecutingAssembly().GetTypes().SelectMany(x => x.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Where(x => x.GetCustomAttribute() is not null))) + { + var attr = method.GetCustomAttribute()!; + if (handlers.ContainsKey(attr.command)) + continue; + + handlers.Add(attr.command, (PacketHandlerDelegate)Delegate.CreateDelegate(typeof(PacketHandlerDelegate), method)); + c.Log($"Loaded {method.Name} for {attr.command}"); + } + c.Log($"{handlers.Count} packet handlers loaded!"); + } + + public static PacketHandlerDelegate? GetPacketHandler(Command command) + { + handlers.TryGetValue(command, out var handler); + return handler; + } + } + + delegate void PacketHandlerDelegate(Connection connection, Packet packet); + + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + class PacketHandlerAttribute(Command command) : Attribute + { + public Command command = command; + } } diff --git a/BLHX.Server/Program.cs b/BLHX.Server/Program.cs index d5a5121..c4e0fdd 100644 --- a/BLHX.Server/Program.cs +++ b/BLHX.Server/Program.cs @@ -8,7 +8,7 @@ internal class Program static void Main() { Logger.c.Log("Starting..."); - + Task.Run(GameServer.Start); Task.Run(InputSystem.Start).Wait(); }