diff --git a/.gitignore b/.gitignore index 384714a..ac58666 100644 --- a/.gitignore +++ b/.gitignore @@ -364,4 +364,5 @@ FodyWeavers.xsd #FunGame.Implement FunGame.Implement/*.cs -FunGame.Implement/Implement/*.cs \ No newline at end of file +FunGame.Implement/Implement/*.cs +/FunGame.WebAPI/wwwroot/* diff --git a/FunGame.Server/Main.cs b/FunGame.Server/Main.cs index 45147f5..191e3da 100644 --- a/FunGame.Server/Main.cs +++ b/FunGame.Server/Main.cs @@ -65,12 +65,21 @@ void StartServer() // 初始化命令菜单 ServerHelper.InitOrderList(); + // 创建全局SQLHelper + Config.InitSQLHelper(); + + // 创建全局MailSender + Config.InitMailSender(); + // 读取游戏模组 if (!Config.GetGameModuleList()) { ServerHelper.WriteLine("服务器似乎未安装任何游戏模组,请检查是否正确安装它们。"); } + // 读取Server插件 + Config.GetServerPlugins(); + // 检查是否存在配置文件 if (!INIHelper.ExistINIFile()) { @@ -86,9 +95,6 @@ void StartServer() } ServerHelper.WriteLine("请输入 help 来获取帮助,输入 quit 关闭服务器。"); - // 创建全局SQLHelper - Config.InitSQLHelper(); - // 使用Socket还是WebSocket bool useWebSocket = Config.UseWebSocket; diff --git a/FunGame.Server/Models/ConsoleModel.cs b/FunGame.Server/Models/ConsoleModel.cs index 344f11c..16e7e02 100644 --- a/FunGame.Server/Models/ConsoleModel.cs +++ b/FunGame.Server/Models/ConsoleModel.cs @@ -1,4 +1,5 @@ using Milimoe.FunGame.Core.Interface.Base; +using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Server.Others; using Milimoe.FunGame.Server.Utility; @@ -47,6 +48,23 @@ namespace Milimoe.FunGame.Server.Model case OrderDictionary.Help: ShowHelp(); break; + default: + break; + } + // 广播到插件 + if (Config.ServerPluginLoader != null) + { + foreach (ServerPlugin plugin in Config.ServerPluginLoader.Plugins.Values) + { + plugin.ProcessInput(order); + } + } + if (Config.WebAPIPluginLoader != null) + { + foreach (WebAPIPlugin plugin in Config.WebAPIPluginLoader.Plugins.Values) + { + plugin.ProcessInput(order); + } } } catch (Exception e) diff --git a/FunGame.Server/Models/ServerModel.cs b/FunGame.Server/Models/ServerModel.cs index 7567de2..4c25ba6 100644 --- a/FunGame.Server/Models/ServerModel.cs +++ b/FunGame.Server/Models/ServerModel.cs @@ -49,10 +49,11 @@ namespace Milimoe.FunGame.Server.Model Socket = socket; DataRequestController = new(this); IsDebugMode = isDebugMode; - if (Config.SQLMode == SQLMode.MySQL) _sqlHelper = new MySQLHelper(this); - else if (Config.SQLMode == SQLMode.SQLite) _sqlHelper = Config.SQLHelper; - else ServerHelper.WriteLine("SQL 服务处于关闭状态", InvokeMessageType.Warning); - _mailer = SmtpHelper.GetMailSender(); + if (Config.SQLMode != SQLMode.None) + { + _sqlHelper = Config.SQLHelper; + } + _mailer = Config.MailSender; } public virtual async Task SocketMessageHandler(ISocketMessageProcessor socket, SocketObject obj) @@ -282,7 +283,6 @@ namespace Milimoe.FunGame.Server.Model public async Task Start() { - TaskUtility.NewTask(CreatePeriodicalQuerier); await CreateStreamReader(); } @@ -496,37 +496,10 @@ namespace Milimoe.FunGame.Server.Model } } - protected async Task CreatePeriodicalQuerier() - { - await Task.Delay(20); - ServerHelper.WriteLine("Creating: PeriodicalQuerier -> " + GetClientName() + " ...OK"); - while (Running) - { - // 每两小时触发一次SQL服务器的心跳查询,防止SQL服务器掉线 - try - { - await Task.Delay(2 * 1000 * 3600); - SQLHelper?.ExecuteDataSet(UserQuery.Select_IsExistUsername(_username)); - } - catch (Exception e) - { - ServerHelper.Error(e); - RemoveUser(); - await Close(); - ServerHelper.WriteLine(GetClientName() + " Error -> Socket is Closed."); - ServerHelper.WriteLine(GetClientName() + " Close -> StringStream is Closed."); - } - } - } - protected async Task Close() { try { - SQLHelper?.Close(); - _sqlHelper = null; - MailSender?.Dispose(); - _mailer = null; await Socket.CloseAsync(); _running = false; Listener.ClientList.Remove(ClientName); diff --git a/FunGame.Server/Others/Config.cs b/FunGame.Server/Others/Config.cs index 8ca94e5..d709bb3 100644 --- a/FunGame.Server/Others/Config.cs +++ b/FunGame.Server/Others/Config.cs @@ -129,6 +129,16 @@ namespace Milimoe.FunGame.Server.Others /// public static GameModuleLoader? GameModuleLoader { get; set; } + /// + /// Server插件 + /// + public static ServerPluginLoader? ServerPluginLoader { get; set; } + + /// + /// Web API插件 + /// + public static WebAPIPluginLoader? WebAPIPluginLoader { get; set; } + /// /// 未Loadmodules时,此属性表示至少需要安装的模组 /// @@ -146,7 +156,13 @@ namespace Milimoe.FunGame.Server.Others } } + /// + /// 全局邮件发送器 + /// + public static MailSender? MailSender => _MailSender; + private static SQLHelper? _SQLHelper; + private static MailSender? _MailSender; /// /// 初始化数据库连接器 @@ -162,17 +178,13 @@ namespace Milimoe.FunGame.Server.Others _SQLHelper = new MySQLHelper("", false); if (((MySQLHelper)_SQLHelper).Connection != null) { - SQLMode = _SQLHelper.Mode; - ServerLogin(); - ClearRoomList(); + AfterCreateSQLService(_SQLHelper); } } else if (INIHelper.ReadINI("SQLite", "UseSQLite").Trim() == "true") { _SQLHelper = new SQLiteHelper(); - SQLMode = _SQLHelper.Mode; - ServerLogin(); - ClearRoomList(); + AfterCreateSQLService(_SQLHelper); } else { @@ -187,29 +199,62 @@ namespace Milimoe.FunGame.Server.Others } } + /// + /// 初始化邮件发送器 + /// + public static void InitMailSender() + { + try + { + _MailSender = SmtpHelper.GetMailSender(); + } + catch (Exception e) + { + ServerHelper.Error(e); + } + if (_MailSender != null) + { + Singleton.AddOrUpdate(_MailSender); + } + } + public static bool GetGameModuleList() { List supported = []; // 构建AddonController - Hashtable delegates = []; + Dictionary delegates = []; delegates.Add("WriteLine", new Action(msg => ServerHelper.WriteLine(msg, InvokeMessageType.GameModule))); delegates.Add("Error", new Action(ServerHelper.Error)); // 读取modules目录下的模组 - GameModuleLoader = GameModuleLoader.LoadGameModules(FunGameType, delegates); - foreach (GameModuleServer module in GameModuleLoader.ModuleServers.Values) + try { - bool check = true; - // 检查模组是否有相对应的地图 - if (!GameModuleLoader.Maps.ContainsKey(module.DefaultMap)) + GameModuleLoader = GameModuleLoader.LoadGameModules(FunGameType, delegates); + foreach (GameModuleServer module in GameModuleLoader.ModuleServers.Values) { - ServerHelper.WriteLine("GameModule Load Failed: " + module + " 没有找到相对应的地图,加载失败", InvokeMessageType.Error); - check = false; - } - if (check) - { - supported.Add(module.Name); + try + { + bool check = true; + // 检查模组是否有相对应的地图 + if (!GameModuleLoader.Maps.ContainsKey(module.DefaultMap)) + { + ServerHelper.WriteLine("GameModule Load Failed: " + module + " 没有找到相对应的地图,加载失败", InvokeMessageType.Error); + check = false; + } + if (check) + { + supported.Add(module.Name); + } + } + catch (Exception e) + { + ServerHelper.Error(e); + } } } + catch (Exception e2) + { + ServerHelper.Error(e2); + } // 设置全局 GameModuleSupported = supported.Distinct().ToArray(); foreach (string modename in GameModuleSupported) @@ -220,6 +265,46 @@ namespace Milimoe.FunGame.Server.Others return GameModuleSupported.Length > 0; } + public static void GetServerPlugins() + { + Dictionary delegates = []; + delegates.Add("WriteLine", new Action(msg => ServerHelper.WriteLine(msg, InvokeMessageType.Plugin))); + delegates.Add("Error", new Action(ServerHelper.Error)); + try + { + // 读取plugins目录下的插件 + ServerPluginLoader = ServerPluginLoader.LoadPlugins(delegates); + foreach (ServerPlugin plugin in ServerPluginLoader.Plugins.Values) + { + ServerHelper.WriteLine("Loaded: " + plugin.Name, InvokeMessageType.Plugin); + } + } + catch (Exception e) + { + ServerHelper.Error(e); + } + } + + public static void GetWebAPIPlugins() + { + Dictionary delegates = []; + delegates.Add("WriteLine", new Action(msg => ServerHelper.WriteLine(msg, InvokeMessageType.Plugin))); + delegates.Add("Error", new Action(ServerHelper.Error)); + try + { + // 读取plugins目录下的插件 + WebAPIPluginLoader = WebAPIPluginLoader.LoadPlugins(delegates); + foreach (WebAPIPlugin plugin in WebAPIPluginLoader.Plugins.Values) + { + ServerHelper.WriteLine("Loaded: " + plugin.Name, InvokeMessageType.Plugin); + } + } + catch (Exception e) + { + ServerHelper.Error(e); + } + } + /// /// 服务器启动登记 /// @@ -241,6 +326,30 @@ namespace Milimoe.FunGame.Server.Others SQLHelper.Execute(RoomQuery.Delete_Rooms()); } } + + public static void AfterCreateSQLService(SQLHelper sqlHelper) + { + SQLMode = sqlHelper.Mode; + Singleton.AddOrUpdate(sqlHelper, true); + ServerLogin(); + ClearRoomList(); + Task t = Task.Run(async () => + { + while (true) + { + // 每两小时触发一次SQL服务器的心跳查询,防止SQL服务器掉线 + try + { + await Task.Delay(2 * 1000 * 3600); + SQLHelper?.ExecuteDataSet(ServerLoginLogs.Select_GetLastLoginTime()); + } + catch (Exception e) + { + ServerHelper.Error(e); + } + } + }); + } } /// diff --git a/FunGame.Server/Utilities/General.cs b/FunGame.Server/Utilities/General.cs index cad0202..f197ae2 100644 --- a/FunGame.Server/Utilities/General.cs +++ b/FunGame.Server/Utilities/General.cs @@ -59,8 +59,9 @@ namespace Milimoe.FunGame.Server.Utility public static void Error(Exception e) { - Console.Write("\r" + GetPrefix(InvokeMessageType.Error) + e.Message + "\n" + e.StackTrace + "\n\r> "); + Console.WriteLine("\r" + GetPrefix(InvokeMessageType.Error) + e.Message + "\n" + e.StackTrace); Console.ResetColor(); + Console.Write("\r> "); } public static void Write(string msg, InvokeMessageType type = InvokeMessageType.System) @@ -71,8 +72,9 @@ namespace Milimoe.FunGame.Server.Utility public static void WriteLine(string msg, InvokeMessageType type = InvokeMessageType.System) { - if (msg.Trim() != "") Console.Write("\r" + GetPrefix(type) + msg + "\n\r> "); + if (msg.Trim() != "") Console.WriteLine("\r" + GetPrefix(type) + msg); Console.ResetColor(); + Console.Write("\r> "); } public static void Type() @@ -211,7 +213,11 @@ namespace Milimoe.FunGame.Server.Utility SmtpPort = Port; if (bool.TryParse(INIHelper.ReadINI("Mailer", "OpenSSL").ToLower(), out bool SSL)) OpenSSL = SSL; - if (SmtpPort > 0) return new MailSender(SenderMailAddress, SenderName, SenderPassword, SmtpHost, SmtpPort, OpenSSL); + if (SmtpPort > 0) + { + ServerHelper.WriteLine("SMTP 服务已启动!"); + return new MailSender(SenderMailAddress, SenderName, SenderPassword, SmtpHost, SmtpPort, OpenSSL); + } } } ServerHelper.WriteLine("SMTP 服务处于关闭状态", InvokeMessageType.Warning); diff --git a/FunGame.WebAPI/Architecture/RESTfulAPIListener.cs b/FunGame.WebAPI/Architecture/RESTfulAPIListener.cs index 5b16b99..48b20f5 100644 --- a/FunGame.WebAPI/Architecture/RESTfulAPIListener.cs +++ b/FunGame.WebAPI/Architecture/RESTfulAPIListener.cs @@ -5,6 +5,8 @@ namespace Milimoe.FunGame.WebAPI.Architecture { public class RESTfulAPIListener : ISocketListener { + public static RESTfulAPIListener? Instance { get; set; } = null; + public string Name => "RESTfulAPIListener"; public ConcurrentModelList ClientList { get; } = []; diff --git a/FunGame.WebAPI/Controllers/PostDataController.cs b/FunGame.WebAPI/Controllers/PostDataController.cs index 2821c57..c795f16 100644 --- a/FunGame.WebAPI/Controllers/PostDataController.cs +++ b/FunGame.WebAPI/Controllers/PostDataController.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Library.Common.Network; using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.WebAPI.Architecture; @@ -22,7 +21,7 @@ namespace Milimoe.FunGame.WebAPI.Controllers { try { - RESTfulAPIListener? apiListener = Singleton.Get(); + RESTfulAPIListener? apiListener = RESTfulAPIListener.Instance; if (apiListener != null && apiListener.UserList.ContainsKey(username)) { RESTfulAPIModel model = (RESTfulAPIModel)apiListener.UserList[username]; diff --git a/FunGame.WebAPI/Controllers/UserController.cs b/FunGame.WebAPI/Controllers/UserController.cs index 855e667..96d2ceb 100644 --- a/FunGame.WebAPI/Controllers/UserController.cs +++ b/FunGame.WebAPI/Controllers/UserController.cs @@ -22,7 +22,7 @@ namespace Milimoe.FunGame.WebAPI.Controllers ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 通过 RESTful API 连接至服务器,正在登录 . . .", Core.Library.Constant.InvokeMessageType.Core); string username = loginModel.Username; string password = loginModel.Password; - RESTfulAPIListener? apiListener = Singleton.Get(); + RESTfulAPIListener? apiListener = RESTfulAPIListener.Instance; if (apiListener != null) { // 移除旧模型 diff --git a/FunGame.WebAPI/FunGame.WebAPI.csproj b/FunGame.WebAPI/FunGame.WebAPI.csproj index 545abd7..c490edb 100644 --- a/FunGame.WebAPI/FunGame.WebAPI.csproj +++ b/FunGame.WebAPI/FunGame.WebAPI.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -45,4 +45,8 @@ + + + + diff --git a/FunGame.WebAPI/Program.cs b/FunGame.WebAPI/Program.cs index 1b743ca..5fe6bd1 100644 --- a/FunGame.WebAPI/Program.cs +++ b/FunGame.WebAPI/Program.cs @@ -1,13 +1,16 @@ using System.Net.WebSockets; +using System.Reflection; using System.Text; using System.Text.Encodings.Web; using System.Text.Json.Serialization; using System.Text.Unicode; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Diagnostics; +using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using Milimoe.FunGame.Core.Api.Utility; +using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Common.JsonConverter; using Milimoe.FunGame.Core.Library.Common.Network; using Milimoe.FunGame.Core.Library.Constant; @@ -29,12 +32,24 @@ try // ʼ˵ ServerHelper.InitOrderList(); + // ȫSQLHelper + Config.InitSQLHelper(); + + // ȫMailSender + Config.InitMailSender(); + // ȡϷģ if (!Config.GetGameModuleList()) { ServerHelper.WriteLine("ƺδװκϷģ飬Ƿȷװǡ"); } + // ȡServer + Config.GetServerPlugins(); + + // ȡWeb API + Config.GetWebAPIPlugins(); + // Ƿļ if (!INIHelper.ExistINIFile()) { @@ -51,18 +66,36 @@ try // RESTfulAPIListener apiListener = new(); - Singleton.Add(apiListener); + RESTfulAPIListener.Instance = apiListener; ServerHelper.WriteLine(" help ȡ quit رշ"); - // ȫSQLHelper - Config.InitSQLHelper(); + if (Config.ServerNotice != "") + Console.WriteLine("\r \n********** **********\n\n" + Config.ServerNotice + "\n"); + else + Console.WriteLine("޷ȡ"); ServerHelper.WriteLine(" Web API . . ."); + Console.WriteLine("\r "); WebApplicationBuilder builder = WebApplication.CreateBuilder(args); // Add services to the container. + // ȡչ + if (Config.WebAPIPluginLoader != null) + { + foreach (WebAPIPlugin plugin in Config.WebAPIPluginLoader.Plugins.Values) + { + Assembly? pluginAssembly = Assembly.GetAssembly(plugin.GetType()); + + if (pluginAssembly != null) + { + // עп + builder.Services.AddControllers().PartManager.ApplicationParts.Add(new AssemblyPart(pluginAssembly)); + } + } + } + // JSON ת builder.Services.AddControllers().AddJsonOptions(options => { options.JsonSerializerOptions.WriteIndented = true; @@ -146,6 +179,10 @@ try app.UseSwaggerUI(); } + app.UseDefaultFiles(); + + app.UseStaticFiles(); + app.UseHttpsRedirection(); app.UseAuthorization(); @@ -184,11 +221,6 @@ try // ʼ listener.BannedList.AddRange(Config.ServerBannedList); - if (Config.ServerNotice != "") - Console.WriteLine("\n\n********** **********\n\n" + Config.ServerNotice + "\n"); - else - Console.WriteLine("޷ȡ"); - Task order = Task.Factory.StartNew(GetConsoleOrder); app.Run();