diff --git a/FunGame.Server/Main.cs b/FunGame.Server/Main.cs index f94b773..c238d06 100644 --- a/FunGame.Server/Main.cs +++ b/FunGame.Server/Main.cs @@ -70,6 +70,21 @@ void StartServer() try { ServerHelper.WriteLine("正在读取配置文件并初始化服务 . . ."); + + // 检查是否存在配置文件 + if (!INIHelper.ExistINIFile()) + { + ServerHelper.WriteLine("未检测到配置文件,将自动创建配置文件 . . ."); + INIHelper.Init(Config.FunGameType); + ServerHelper.WriteLine("配置文件FunGame.ini创建成功,请修改该配置文件,然后重启服务器。"); + return; + } + else + { + ServerHelper.GetServerSettings(); + Console.Title = Config.ServerName + " - FunGame Server Port: " + Config.ServerPort; + } + // 初始化命令菜单 ServerHelper.InitOrderList(); @@ -88,19 +103,6 @@ void StartServer() // 读取Server插件 FunGameSystem.GetServerPlugins(); - // 检查是否存在配置文件 - if (!INIHelper.ExistINIFile()) - { - ServerHelper.WriteLine("未检测到配置文件,将自动创建配置文件 . . ."); - INIHelper.Init(Config.FunGameType); - ServerHelper.WriteLine("配置文件FunGame.ini创建成功,请修改该配置文件,然后重启服务器。"); - return; - } - else - { - ServerHelper.GetServerSettings(); - Console.Title = Config.ServerName + " - FunGame Server Port: " + Config.ServerPort; - } ServerHelper.WriteLine("请输入 help 来获取帮助,按下 Ctrl+C 关闭服务器。"); ServerHelper.PrintFunGameTitle(); @@ -120,9 +122,11 @@ void StartServer() ServerHelper.WriteLine("服务器启动成功,开始监听 . . ."); if (Config.ServerNotice != "") - ServerHelper.WriteLine("\n\n********** 服务器公告 **********\n\n" + Config.ServerNotice + "\n"); + Console.WriteLine("\n\n********** 服务器公告 **********\n\n" + Config.ServerNotice + "\n"); else - ServerHelper.WriteLine("无法读取服务器公告"); + Console.WriteLine("无法读取服务器公告"); + + ServerHelper.Type(); while (Running) { diff --git a/FunGame.Server/Models/ServerModel.cs b/FunGame.Server/Models/ServerModel.cs index 04299e6..fca888d 100644 --- a/FunGame.Server/Models/ServerModel.cs +++ b/FunGame.Server/Models/ServerModel.cs @@ -75,9 +75,18 @@ namespace Milimoe.FunGame.Server.Model if (type == SocketMessageType.EndGame) { + if (NowGamingServer != null && NowGamingServer.IsAnonymous) + { + NowGamingServer.CloseAnonymousServer(this); + } NowGamingServer = null; return true; } + + if (type == SocketMessageType.AnonymousGameServer) + { + return await AnonymousGameServerHandler(obj); + } if (type == SocketMessageType.DataRequest) { @@ -110,7 +119,7 @@ namespace Milimoe.FunGame.Server.Model bool result = await Send(SocketMessageType.HeartBeat); if (!result) { - ServerHelper.WriteLine("[ " + _username + " ] " + nameof(HeartBeat) + ": " + result, InvokeMessageType.Error); + ServerHelper.WriteLine("[ " + GetClientName() + " ] " + nameof(HeartBeat) + ": " + result, InvokeMessageType.Error); } return result; } @@ -144,12 +153,12 @@ namespace Milimoe.FunGame.Server.Model bool sendResult = await Send(SocketMessageType.DataRequest, type, requestID, result); if (!sendResult) { - ServerHelper.WriteLine("[ " + _username + " ] " + nameof(DataRequestHandler) + ": " + sendResult, InvokeMessageType.Error); + ServerHelper.WriteLine("[ " + GetClientName() + " ] " + nameof(DataRequestHandler) + ": " + sendResult, InvokeMessageType.Error); } return sendResult; } - ServerHelper.WriteLine("[ " + _username + " ] " + nameof(DataRequestHandler) + ": " + false, InvokeMessageType.Error); + ServerHelper.WriteLine("[ " + GetClientName() + " ] " + nameof(DataRequestHandler) + ": " + false, InvokeMessageType.Error); return false; } @@ -169,7 +178,7 @@ namespace Milimoe.FunGame.Server.Model requestID = obj.GetParam(1); Dictionary data = obj.GetParam>(2) ?? []; - result = await NowGamingServer.GamingMessageHandler(_username, type, data); + result = await NowGamingServer.GamingMessageHandler(this, type, data); } catch (Exception e) { @@ -181,12 +190,12 @@ namespace Milimoe.FunGame.Server.Model bool sendResult = await Send(SocketMessageType.GamingRequest, type, requestID, result); if (!sendResult) { - ServerHelper.WriteLine("[ " + _username + " ] " + nameof(GamingRequestHandler) + ": " + sendResult, InvokeMessageType.Error); + ServerHelper.WriteLine("[ " + GetClientName() + " ] " + nameof(GamingRequestHandler) + ": " + sendResult, InvokeMessageType.Error); } return sendResult; } - ServerHelper.WriteLine("[ " + _username + " ] " + nameof(GamingRequestHandler) + ": " + false, InvokeMessageType.Error); + ServerHelper.WriteLine("[ " + GetClientName() + " ] " + nameof(GamingRequestHandler) + ": " + false, InvokeMessageType.Error); return false; } @@ -204,7 +213,7 @@ namespace Milimoe.FunGame.Server.Model type = obj.GetParam(0); Dictionary data = obj.GetParam>(1) ?? []; - result = await NowGamingServer.GamingMessageHandler(_username, type, data); + result = await NowGamingServer.GamingMessageHandler(this, type, data); } catch (Exception e) { @@ -216,12 +225,71 @@ namespace Milimoe.FunGame.Server.Model bool sendResult = await Send(SocketMessageType.Gaming, type, result); if (!sendResult) { - ServerHelper.WriteLine("[ " + _username + " ] " + nameof(GamingMessageHandler) + ": " + sendResult, InvokeMessageType.Error); + ServerHelper.WriteLine("[ " + GetClientName() + " ] " + nameof(GamingMessageHandler) + ": " + sendResult, InvokeMessageType.Error); } return sendResult; } - ServerHelper.WriteLine("[ " + _username + " ] " + nameof(GamingMessageHandler) + ": " + false, InvokeMessageType.Error); + ServerHelper.WriteLine("[ " + GetClientName() + " ] " + nameof(GamingMessageHandler) + ": " + false, InvokeMessageType.Error); + return false; + } + + protected async Task AnonymousGameServerHandler(SocketObject obj) + { + string serverName = ""; + Dictionary data = []; + Dictionary result = []; + if (obj.Parameters.Length > 0) serverName = obj.GetParam(0) ?? ""; + if (obj.Parameters.Length > 1) data = obj.GetParam>(1) ?? []; + + bool willSend = false; + if (NowGamingServer != null) + { + try + { + result = await NowGamingServer.AnonymousGameServerHandler(this, data); + willSend = true; + } + catch (Exception e) + { + ServerHelper.Error(e); + return await Send(SocketMessageType.AnonymousGameServer, result); + } + } + else + { + // 建立连接 + if (Config.GameModuleLoader != null && Config.GameModuleLoader.ModuleServers.ContainsKey(serverName)) + { + GameModuleServer mod = Config.GameModuleLoader.GetServerMode(serverName); + if (mod.StartAnonymousServer(this, data)) + { + NowGamingServer = mod; + try + { + result = await NowGamingServer.AnonymousGameServerHandler(this, data); + willSend = true; + } + catch (Exception e) + { + ServerHelper.Error(e); + return await Send(SocketMessageType.AnonymousGameServer, result); + } + } + } + } + + if (willSend) + { + bool sendResult = await Send(SocketMessageType.AnonymousGameServer, result); + if (!sendResult) + { + ServerHelper.WriteLine("[ " + GetClientName() + " ] " + nameof(AnonymousGameServerHandler) + ": " + sendResult, InvokeMessageType.Error); + } + return sendResult; + } + + ServerHelper.WriteLine("[ " + GetClientName() + " ] " + nameof(AnonymousGameServerHandler) + ": " + false, InvokeMessageType.Error); return false; } diff --git a/FunGame.Server/Others/Config.cs b/FunGame.Server/Others/Config.cs index afd1848..104e101 100644 --- a/FunGame.Server/Others/Config.cs +++ b/FunGame.Server/Others/Config.cs @@ -8,6 +8,36 @@ namespace Milimoe.FunGame.Server.Others { public static class Config { + /// + /// 使用 ASP.NET Core Web API + /// + public static bool AspNetCore { get; set; } = false; + + /// + /// 日志级别 + /// + public static string LogLevel { get; set; } = "INFO"; + + /// + /// 日志级别(枚举值) + /// + public static LogLevel LogLevelValue + { + get + { + return LogLevel.ToUpper() switch + { + "TRACE" => Core.Library.Constant.LogLevel.Trace, + "DEBUG" => Core.Library.Constant.LogLevel.Debug, + "INFO" => Core.Library.Constant.LogLevel.Info, + "WARN" => Core.Library.Constant.LogLevel.Warning, + "ERROR" => Core.Library.Constant.LogLevel.Error, + "CRIT" => Core.Library.Constant.LogLevel.Critical, + _ => Core.Library.Constant.LogLevel.Info + }; + } + } + /// /// 服务器名称 /// diff --git a/FunGame.Server/Others/FunGameSystem.cs b/FunGame.Server/Others/FunGameSystem.cs index 7a22f7b..6f8b879 100644 --- a/FunGame.Server/Others/FunGameSystem.cs +++ b/FunGame.Server/Others/FunGameSystem.cs @@ -93,7 +93,7 @@ namespace Milimoe.FunGame.Server.Others List supported = []; // 构建AddonController Dictionary delegates = []; - delegates.Add("WriteLine", new Action(msg => ServerHelper.WriteLine(msg, InvokeMessageType.GameModule))); + delegates.Add("WriteLine", new Action((name, msg, level, useLevel) => ServerHelper.WriteLine_Addons(name, msg, InvokeMessageType.GameModule, level, useLevel))); delegates.Add("Error", new Action(ServerHelper.Error)); // 读取modules目录下的模组 try @@ -107,12 +107,13 @@ namespace Milimoe.FunGame.Server.Others // 检查模组是否有相对应的地图 if (!Config.GameModuleLoader.Maps.ContainsKey(module.DefaultMap)) { - ServerHelper.WriteLine("GameModule Load Failed: " + module + " 没有找到相对应的地图,加载失败", InvokeMessageType.Error); + ServerHelper.WriteLine("GameModule Load Failed: " + module.Name + " 没有找到相对应的地图,加载失败", InvokeMessageType.Error); check = false; } if (check) { - supported.Add(module.Name); + if (!module.IsAnonymous) supported.Add(module.Name); + ServerHelper.WriteLine("Loaded: " + module.Name, InvokeMessageType.GameModule); } } catch (Exception e) @@ -127,10 +128,6 @@ namespace Milimoe.FunGame.Server.Others } // 设置全局 Config.GameModuleSupported = supported.Distinct().ToArray(); - foreach (string modename in Config.GameModuleSupported) - { - ServerHelper.WriteLine("Loaded: " + modename, InvokeMessageType.GameModule); - } return Config.GameModuleSupported.Length > 0; } @@ -141,7 +138,7 @@ namespace Milimoe.FunGame.Server.Others public static void GetServerPlugins() { Dictionary delegates = []; - delegates.Add("WriteLine", new Action(msg => ServerHelper.WriteLine(msg, InvokeMessageType.Plugin))); + delegates.Add("WriteLine", new Action((name, msg, level, useLevel) => ServerHelper.WriteLine_Addons(name, msg, InvokeMessageType.Plugin, level, useLevel))); delegates.Add("Error", new Action(ServerHelper.Error)); try { @@ -164,7 +161,7 @@ namespace Milimoe.FunGame.Server.Others public static void GetWebAPIPlugins() { Dictionary delegates = []; - delegates.Add("WriteLine", new Action(msg => ServerHelper.WriteLine(msg, InvokeMessageType.Plugin))); + delegates.Add("WriteLine", new Action((name, msg, level, useLevel) => ServerHelper.WriteLine_Addons(name, msg, InvokeMessageType.Plugin, level, useLevel))); delegates.Add("Error", new Action(ServerHelper.Error)); try { diff --git a/FunGame.Server/Utilities/General.cs b/FunGame.Server/Utilities/General.cs index 6ad9cbe..4afb9aa 100644 --- a/FunGame.Server/Utilities/General.cs +++ b/FunGame.Server/Utilities/General.cs @@ -17,7 +17,7 @@ namespace Milimoe.FunGame.Server.Utility Console.ResetColor(); } - public static string GetPrefix(InvokeMessageType type) + public static string GetPrefix(InvokeMessageType type, LogLevel level, string addon = "") { string prefix; switch (type) @@ -61,28 +61,69 @@ namespace Milimoe.FunGame.Server.Utility prefix = "[System] "; break; } + + string levelPrefix = CommonSet.GetLogLevelPrefix(level); + DateTime now = DateTime.Now; - return now.AddMilliseconds(-now.Millisecond).ToString() + " " + prefix + Config.ServerName + ":"; + return now.AddMilliseconds(-now.Millisecond).ToString() + " " + levelPrefix + prefix + (addon.Trim() != "" ? addon : Config.ServerName) + ":"; } public static void Error(Exception e) { - Console.WriteLine("\r" + GetPrefix(InvokeMessageType.Error) + e.Message + "\n" + e.StackTrace); - Console.ResetColor(); - Console.Write("\r> "); + Console.WriteLine("\r" + GetPrefix(InvokeMessageType.Error, LogLevel.Error) + e.Message + "\n" + e.StackTrace); + Type(); } - public static void Write(string msg, InvokeMessageType type = InvokeMessageType.System) + public static void Write(string msg, InvokeMessageType type = InvokeMessageType.System, LogLevel level = LogLevel.Info, bool useLevel = true) { - if (msg.Trim() != "") Console.Write("\r" + GetPrefix(type) + msg + "> "); - Console.ResetColor(); + if (type == InvokeMessageType.Warning) + { + level = LogLevel.Warning; + } + if (type == InvokeMessageType.Error) + { + level = LogLevel.Error; + } + if (!useLevel || (useLevel && (int)level >= (int)Config.LogLevelValue)) + { + if (msg.Trim() != "") Console.Write("\r" + GetPrefix(type, level) + msg + "> "); + Console.ResetColor(); + } + else Type(); } - public static void WriteLine(string msg, InvokeMessageType type = InvokeMessageType.System) + public static void WriteLine(string msg, InvokeMessageType type = InvokeMessageType.System, LogLevel level = LogLevel.Info, bool useLevel = true) { - if (msg.Trim() != "") Console.WriteLine("\r" + GetPrefix(type) + msg); - Console.ResetColor(); - Console.Write("\r> "); + if (type == InvokeMessageType.Warning) + { + level = LogLevel.Warning; + } + if (type == InvokeMessageType.Error) + { + level = LogLevel.Error; + } + if (!useLevel || ((int)level >= (int)Config.LogLevelValue)) + { + if (msg.Trim() != "") Console.WriteLine("\r" + GetPrefix(type, level) + msg); + } + Type(); + } + + public static void WriteLine_Addons(string addon, string msg, InvokeMessageType type = InvokeMessageType.System, LogLevel level = LogLevel.Info, bool useLevel = true) + { + if (type == InvokeMessageType.Warning) + { + level = LogLevel.Warning; + } + if (type == InvokeMessageType.Error) + { + level = LogLevel.Error; + } + if (!useLevel || ((int)level >= (int)Config.LogLevelValue)) + { + if (msg.Trim() != "") Console.WriteLine("\r" + GetPrefix(type, level, addon) + msg); + } + Type(); } public static void Type() @@ -106,9 +147,10 @@ namespace Milimoe.FunGame.Server.Utility Hashtable settings = []; if (INIHelper.ExistINIFile()) { + settings.Add("LogLevel", INIHelper.ReadINI("Console", "LogLevel")); settings.Add("Name", INIHelper.ReadINI("Server", "Name")); settings.Add("Password", INIHelper.ReadINI("Server", "Password")); - settings.Add("Describe", INIHelper.ReadINI("Server", "Describe")); + settings.Add("Description", INIHelper.ReadINI("Server", "Description")); settings.Add("Notice", INIHelper.ReadINI("Server", "Notice")); settings.Add("Key", INIHelper.ReadINI("Server", "Key")); settings.Add("Status", Convert.ToInt32(INIHelper.ReadINI("Server", "Status"))); @@ -134,16 +176,20 @@ namespace Milimoe.FunGame.Server.Utility Hashtable settings = GetServerSettingHashtable(); if (settings != null) { + string? LogLevel = (string?)settings["LogLevel"]; + + if (LogLevel != null) Config.LogLevel = LogLevel; + string? Name = (string?)settings["Name"]; string? Password = (string?)settings["Password"]; - string? Describe = (string?)settings["Describe"]; + string? Description = (string?)settings["Description"]; string? Notice = (string?)settings["Notice"]; string? Key = (string?)settings["Key"]; string? BannedList = (string?)settings["BannedList"]; if (Name != null) Config.ServerName = Name; if (Password != null) Config.ServerPassword = Password; - if (Describe != null) Config.ServerDescription = Describe; + if (Description != null) Config.ServerDescription = Description; if (Notice != null) Config.ServerNotice = Notice; if (Key != null) Config.ServerKey = Key; if (BannedList != null) Config.ServerBannedList = BannedList.Split(',').Select(s => s.Trim()).ToList(); @@ -174,6 +220,7 @@ namespace Milimoe.FunGame.Server.Utility if (MaxPlayer != null) Config.MaxPlayers = (int)MaxPlayer; if (MaxConnectFailed != null) Config.MaxConnectionFaileds = (int)MaxConnectFailed; } + WriteLine($"当前输出的日志级别为:{Config.LogLevelValue}", useLevel: false); } catch (Exception e) { diff --git a/FunGame.WebAPI/Models/RESTfulAPIModel.cs b/FunGame.WebAPI/Models/RESTfulAPIModel.cs index 6e098ca..851e77b 100644 --- a/FunGame.WebAPI/Models/RESTfulAPIModel.cs +++ b/FunGame.WebAPI/Models/RESTfulAPIModel.cs @@ -51,6 +51,21 @@ namespace Milimoe.FunGame.WebAPI.Models return false; } + if (type == SocketMessageType.EndGame) + { + if (NowGamingServer != null && NowGamingServer.IsAnonymous) + { + NowGamingServer.CloseAnonymousServer(this); + } + NowGamingServer = null; + return true; + } + + if (type == SocketMessageType.AnonymousGameServer) + { + return await AnonymousGameServerHandler(obj); + } + if (type == SocketMessageType.DataRequest) { return await DataRequestHandler(obj); diff --git a/FunGame.WebAPI/Program.cs b/FunGame.WebAPI/Program.cs index bec90f1..f06548d 100644 --- a/FunGame.WebAPI/Program.cs +++ b/FunGame.WebAPI/Program.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Microsoft.Extensions.Logging.Console; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using Milimoe.FunGame.Core.Api.Utility; @@ -27,8 +28,24 @@ try { Console.Title = Config.ServerName; Console.WriteLine(FunGameInfo.GetInfo(Config.FunGameType)); + Config.AspNetCore = true; ServerHelper.WriteLine("ڶȡļʼ . . ."); + + // Ƿļ + if (!INIHelper.ExistINIFile()) + { + ServerHelper.WriteLine("δ⵽ļԶļ . . ."); + INIHelper.Init(Config.FunGameType); + ServerHelper.WriteLine("ļFunGame.iniɹ޸ĸļȻ"); + Console.ReadKey(); + return; + } + else + { + ServerHelper.GetServerSettings(); + } + // ʼ˵ ServerHelper.InitOrderList(); @@ -50,20 +67,6 @@ try // ȡWeb API FunGameSystem.GetWebAPIPlugins(); - // Ƿļ - if (!INIHelper.ExistINIFile()) - { - ServerHelper.WriteLine("δ⵽ļԶļ . . ."); - INIHelper.Init(Config.FunGameType); - ServerHelper.WriteLine("ļFunGame.iniɹ޸ĸļȻ"); - Console.ReadKey(); - return; - } - else - { - ServerHelper.GetServerSettings(); - } - // RESTfulAPIListener apiListener = new(); RESTfulAPIListener.Instance = apiListener; @@ -165,6 +168,11 @@ try IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"] ?? "undefined")) }; }).AddScheme("CustomBearer", options => { }); + builder.Logging.AddConsole(options => + { + options.FormatterName = "CustomFormatter"; + }); + builder.Services.AddSingleton(); WebApplication app = builder.Build(); diff --git a/FunGame.WebAPI/Architecture/CustomBearerTokenHandler.cs b/FunGame.WebAPI/Services/CustomBearerTokenHandler.cs similarity index 97% rename from FunGame.WebAPI/Architecture/CustomBearerTokenHandler.cs rename to FunGame.WebAPI/Services/CustomBearerTokenHandler.cs index 6187537..f8cae0d 100644 --- a/FunGame.WebAPI/Architecture/CustomBearerTokenHandler.cs +++ b/FunGame.WebAPI/Services/CustomBearerTokenHandler.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Options; using Milimoe.FunGame.Core.Api.Utility; -namespace Milimoe.FunGame.WebAPI.Architecture +namespace Milimoe.FunGame.WebAPI.Services { public class CustomBearerAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder) : AuthenticationHandler(options, logger, encoder) { diff --git a/FunGame.WebAPI/Services/CustomConsoleFormatter.cs b/FunGame.WebAPI/Services/CustomConsoleFormatter.cs new file mode 100644 index 0000000..fda8e46 --- /dev/null +++ b/FunGame.WebAPI/Services/CustomConsoleFormatter.cs @@ -0,0 +1,39 @@ +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Logging.Console; + +namespace Milimoe.FunGame.WebAPI.Services +{ + public class CustomConsoleFormatter() : ConsoleFormatter("CustomFormatter") + { + public override void Write(in LogEntry logEntry, IExternalScopeProvider? scopeProvider, TextWriter textWriter) + { + string message = logEntry.Formatter(logEntry.State, logEntry.Exception); + string level = logEntry.LogLevel.ToString()[..1].ToUpper(); + string category = logEntry.Category.Split('.')[^1]; + string colorLevel = GetColorCode(logEntry.LogLevel); + DateTime now = DateTime.Now; + string timestamp = now.AddMilliseconds(-now.Millisecond).ToString(); + + if ((int)logEntry.LogLevel >= (int)Server.Others.Config.LogLevelValue) + { + textWriter.Write("\r"); + textWriter.WriteLine($"{colorLevel}{timestamp} {level}/[{category}] {message}"); + } + textWriter.Write("\x1b[0m\r> "); + } + + private static string GetColorCode(LogLevel logLevel) + { + return logLevel switch + { + LogLevel.Trace => "\x1b[37m", // 灰色 ConsoleColor.Gray + LogLevel.Debug => "\x1b[34m", // 蓝色 ConsoleColor.Blue + LogLevel.Information => "\x1b[32m", // 绿色 ConsoleColor.Green + LogLevel.Warning => "\x1b[33m", // 黄色 ConsoleColor.Yellow + LogLevel.Error => "\x1b[31m", // 红色 ConsoleColor.Red + LogLevel.Critical => "\x1b[31m", // 红色 ConsoleColor.Red + _ => "\x1b[0m" // 重置颜色 + }; + } + } +}