From 47fb7176511ff55c26168a992fd66db5056c21cf Mon Sep 17 00:00:00 2001 From: yeziuku <53083103+yeziuku@users.noreply.github.com> Date: Sun, 5 Apr 2026 17:09:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8F=92=E4=BB=B6=E4=B9=8B?= =?UTF-8?q?=E9=97=B4=E7=9A=84=E6=95=B0=E6=8D=AE=E8=AF=B7=E6=B1=82=EF=BC=9B?= =?UTF-8?q?=E8=A1=A5=E5=85=A8=E6=8F=92=E4=BB=B6=E7=A4=BA=E4=BE=8B=20(#150)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Api/Utility/GameModuleLoader.cs | 24 +++++ Api/Utility/ServerPluginLoader.cs | 20 ++++ Api/Utility/WebAPIPluginLoader.cs | 20 ++++ Controller/AddonController.cs | 52 ++++++++++ Library/Common/Addon/Example/ExamplePlugin.cs | 98 +++++++++++++++++-- Library/Common/Addon/GameModuleServer.cs | 14 +++ Library/Common/Addon/ServerPlugin.cs | 12 +++ Library/Common/Addon/WebAPIPlugin.cs | 12 +++ .../Common/Event/AddonDataRequestEventArgs.cs | 11 +++ Library/Constant/ConstantSet.cs | 14 ++- Library/Constant/TypeEnum.cs | 11 +++ 11 files changed, 281 insertions(+), 7 deletions(-) create mode 100644 Library/Common/Event/AddonDataRequestEventArgs.cs diff --git a/Api/Utility/GameModuleLoader.cs b/Api/Utility/GameModuleLoader.cs index 47a72dd..ef6a425 100644 --- a/Api/Utility/GameModuleLoader.cs +++ b/Api/Utility/GameModuleLoader.cs @@ -1,4 +1,5 @@ using Milimoe.FunGame.Core.Library.Common.Addon; +using Milimoe.FunGame.Core.Library.Common.Event; using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Service; @@ -196,6 +197,29 @@ namespace Milimoe.FunGame.Core.Api.Utility } } + /// + /// 处理服务器广播的非标准 DataRequest 请求 + /// + /// + /// + /// + public Dictionary HandleDataRequest(Dictionary data, AddonDataRequestEventArgs e) + { + Dictionary result = []; + if (ModuleServers.Count > 0) + { + foreach (GameModuleServer module in ModuleServers.Values) + { + Dictionary moduleResult = module.HandleDataRequest(data, e); + foreach (string key in moduleResult.Keys) + { + result[key] = moduleResult[key]; + } + } + } + return result; + } + /// /// 获取对应名称的模组实例 /// 如果需要取得服务器模组的实例,请调用 diff --git a/Api/Utility/ServerPluginLoader.cs b/Api/Utility/ServerPluginLoader.cs index cc005c5..d0b10f6 100644 --- a/Api/Utility/ServerPluginLoader.cs +++ b/Api/Utility/ServerPluginLoader.cs @@ -81,6 +81,26 @@ namespace Milimoe.FunGame.Core.Api.Utility } } + /// + /// 处理服务器广播的非标准 DataRequest 请求 + /// + /// + /// + /// + public virtual Dictionary HandleDataRequest(Dictionary data, AddonDataRequestEventArgs e) + { + Dictionary result = []; + foreach (ServerPlugin plugin in Plugins.Values) + { + Dictionary pluginResult = plugin.HandleDataRequest(data, e); + foreach (string key in pluginResult.Keys) + { + result[key] = pluginResult[key]; + } + } + return result; + } + public ServerPlugin this[string name] { get diff --git a/Api/Utility/WebAPIPluginLoader.cs b/Api/Utility/WebAPIPluginLoader.cs index 00c0b0f..5d728a2 100644 --- a/Api/Utility/WebAPIPluginLoader.cs +++ b/Api/Utility/WebAPIPluginLoader.cs @@ -81,6 +81,26 @@ namespace Milimoe.FunGame.Core.Api.Utility } } + /// + /// 处理服务器广播的非标准 DataRequest 请求 + /// + /// + /// + /// + public Dictionary HandleDataRequest(Dictionary data, AddonDataRequestEventArgs e) + { + Dictionary result = []; + foreach (WebAPIPlugin plugin in Plugins.Values) + { + Dictionary pluginResult = plugin.HandleDataRequest(data, e); + foreach (string key in pluginResult.Keys) + { + result[key] = pluginResult[key]; + } + } + return result; + } + public WebAPIPlugin this[string name] { get diff --git a/Controller/AddonController.cs b/Controller/AddonController.cs index f34aa07..3a01fd4 100644 --- a/Controller/AddonController.cs +++ b/Controller/AddonController.cs @@ -98,6 +98,58 @@ namespace Milimoe.FunGame.Core.Controller return MaskMethod_NewLongRunningGamingRequest(type); } + /// + /// 基于本地已连接的Socket创建非标准的数据请求(,具体类型由 决定) + /// 可以指定 ,以便发送给一个已知的服务器模组或服务器插件 + /// + /// + /// + /// + /// + public DataRequest NewDataRequest(string targetAddon = "", bool longRunning = false) + { + if (Addon is IPlugin) + { + DataRequest request; + if (longRunning) + { + request = NewLongRunningDataRequest(DataRequestType.Addon_Plugin); + } + else + { + request = NewDataRequest(DataRequestType.Addon_Plugin); + } + request.AddRequestData(SocketSet.AddonDataRequestMark_FromPlugin, Addon.Name); + request.AddRequestData(SocketSet.AddonDataRequestMark_TargetPlugin, targetAddon); + return request; + } + else if (Addon is IGameModule) + { + DataRequest request; + if (longRunning) + { + request = NewLongRunningDataRequest(DataRequestType.Addon_Module); + } + else + { + request = NewDataRequest(DataRequestType.Addon_Module); + } + request.AddRequestData(SocketSet.AddonDataRequestMark_FromModule, Addon.Name); + request.AddRequestData(SocketSet.AddonDataRequestMark_TargetModule, targetAddon); + return request; + } + throw new ConnectFailedException(); + } + + /// + /// 基于本地已连接的Socket创建长时间运行的、非标准的数据请求(,具体类型由 决定) + /// 可以指定 ,以便发送给一个已知的服务器模组或服务器插件 + /// + /// + /// + /// + public DataRequest NewLongRunningDataRequest(string targetAddon = "") => NewDataRequest(targetAddon, true); + /// /// 新建一个AddonController /// diff --git a/Library/Common/Addon/Example/ExamplePlugin.cs b/Library/Common/Addon/Example/ExamplePlugin.cs index 7a7985c..f205a48 100644 --- a/Library/Common/Addon/Example/ExamplePlugin.cs +++ b/Library/Common/Addon/Example/ExamplePlugin.cs @@ -1,13 +1,18 @@ -using Milimoe.FunGame.Core.Interface; +using System.Data; +using Milimoe.FunGame.Core.Api.Transmittal; +using Milimoe.FunGame.Core.Api.Utility; +using Milimoe.FunGame.Core.Interface; using Milimoe.FunGame.Core.Library.Common.Event; +using Milimoe.FunGame.Core.Library.Constant; +using Milimoe.FunGame.Core.Library.SQLScript.Entity; namespace Milimoe.FunGame.Core.Library.Common.Addon.Example { /// - /// 必须继承基类: - /// 继承事件接口并实现其方法来使插件生效。例如继承: + /// 客户端插件,必须继承基类: + /// 继承事件接口并实现其方法来使插件生效。例如继承: /// - public class ExamplePlugin : Plugin, ILoginEvent + public class ExamplePlugin : Plugin, IConnectEvent { public override string Name => "fungame.example.plugin"; @@ -17,6 +22,77 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example public override string Author => "FunGamer"; + public void AfterConnectEvent(object sender, ConnectEventArgs e) + { + // 每个事件接口都有 Before/After 两个介入点,根据自身需求实现即可 + // 可以在连接服务器完毕后做一些处理... + } + + public void BeforeConnectEvent(object sender, ConnectEventArgs e) + { + // 和服务器插件的联动示例 + // 假设服务器上有个名为“fungame.example.serverplugin”的服务器插件,当然也可以不指定,不指定时服务器会广播所有插件,性能可能较低 + DataRequest request = Controller.NewDataRequest(targetAddon: "fungame.example.serverplugin"); + long tick = DateTime.Now.Ticks; + request.AddRequestData("event", "ping"); + request.AddRequestData("tick", tick); + request.SendRequest(); + if (request.Result == RequestResult.Success) + { + long newTick = request.GetResult("tick"); + Controller.WriteLine($"服务器延迟:{Math.Min(999, new TimeSpan(newTick - tick).TotalMilliseconds)}ms"); + } + } + } + + /// + /// 服务器插件,必须继承基类: + /// 同样需继承事件接口并实现其方法来使插件生效。例如继承: + /// + public class ExampleServerPlugin : ServerPlugin, ILoginEvent + { + public override string Name => "fungame.example.serverplugin"; + + public override string Description => "My First Server Plugin"; + + public override string Version => "1.0.0"; + + public override string Author => "FunGamer"; + + public override void ProcessInput(string input) + { + // 该方法用于接收服务器控制台的输入并处理 + if (input.Equals("info", StringComparison.CurrentCultureIgnoreCase)) + { + // 使用PluginController的输出方式 + Controller.WriteLine($"This is {nameof(ExampleServerPlugin)}!!"); + } + } + + public override void AfterLoad(ServerPluginLoader loader, params object[] objs) + { + // 该方法可在插件加载完毕后执行代码 + } + + public override Dictionary HandleDataRequest(Dictionary data, AddonDataRequestEventArgs e) + { + // 此方法接收并处理数据请求,我们先前在客户端插件中发送了数据请求,这里就要处理它 + // 需要注意,data 是通用的,如果服务器将数据请求广播到所有的插件,这些插件是无法区分客户端的请求类型是什么的,所以这一部分更偏向于“约定” + // 可以约定好插件的名称,也可以约定好event,一切都完全由插件开发者掌控 + if (e.From == "fungame.example.plugin" && e.Target == Name) + { + string ent = NetworkUtility.JsonDeserializeFromDictionary(data, "event") ?? ""; + if (ent.Equals("ping", StringComparison.CurrentCultureIgnoreCase)) + { + return new() + { + { "tick", DateTime.Now.Ticks } + }; + } + } + return []; + } + public void AfterLoginEvent(object sender, LoginEventArgs e) { @@ -24,8 +100,18 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example public void BeforeLoginEvent(object sender, LoginEventArgs e) { - // 如果这里设置Cancel = true,将终止登录 - e.Cancel = true; + // 如果这里设置Cancel = true,将终止登录(可以加入自定义的验证机制等) + // 例如SQLHelper的使用: + if (Controller.SQLHelper != null) + { + // 服务器的标准功能会有登录检查,这里仅做一个示例 + DataRow? row = Controller.SQLHelper.ExecuteDataRow(UserQuery.Select_UserByUsername(Controller.SQLHelper, e.Username)); + if (row is null) + { + e.Cancel = true; + e.EventMsg = "用户名不存在。"; + } + } } } } diff --git a/Library/Common/Addon/GameModuleServer.cs b/Library/Common/Addon/GameModuleServer.cs index 7ba7e40..379d6c0 100644 --- a/Library/Common/Addon/GameModuleServer.cs +++ b/Library/Common/Addon/GameModuleServer.cs @@ -3,6 +3,7 @@ using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Controller; using Milimoe.FunGame.Core.Interface.Addons; using Milimoe.FunGame.Core.Interface.Base; +using Milimoe.FunGame.Core.Library.Common.Event; using Milimoe.FunGame.Core.Library.Constant; namespace Milimoe.FunGame.Core.Library.Common.Addon @@ -129,6 +130,19 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon return []; } + /// + /// 此方法为可选实现,接收并处理非标准 DataRequest 请求 + /// 此方法效率可能低于匿名服务器 + /// 请使用 方法获取 成员 + /// + /// + /// + /// 返回一个无需对成员序列化的字典 + public virtual Dictionary HandleDataRequest(Dictionary data, AddonDataRequestEventArgs e) + { + return []; + } + /// /// 加载标记 /// diff --git a/Library/Common/Addon/ServerPlugin.cs b/Library/Common/Addon/ServerPlugin.cs index f3c59a6..1c88695 100644 --- a/Library/Common/Addon/ServerPlugin.cs +++ b/Library/Common/Addon/ServerPlugin.cs @@ -96,6 +96,18 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon /// public abstract void ProcessInput(string input); + /// + /// 处理服务器广播的非标准 DataRequest 请求 + /// 请使用 方法获取 成员 + /// + /// + /// + /// 返回一个无需对成员序列化的字典 + public virtual Dictionary HandleDataRequest(Dictionary data, AddonDataRequestEventArgs e) + { + return []; + } + /// /// 插件完全加载后需要做的事 /// diff --git a/Library/Common/Addon/WebAPIPlugin.cs b/Library/Common/Addon/WebAPIPlugin.cs index 95fdb98..9577e6d 100644 --- a/Library/Common/Addon/WebAPIPlugin.cs +++ b/Library/Common/Addon/WebAPIPlugin.cs @@ -96,6 +96,18 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon /// public abstract void ProcessInput(string input); + /// + /// 处理服务器广播的非标准 DataRequest 请求 + /// 请使用 方法获取 成员 + /// + /// + /// + /// 返回一个无需对成员序列化的字典 + public virtual Dictionary HandleDataRequest(Dictionary data, AddonDataRequestEventArgs e) + { + return []; + } + /// /// 插件完全加载后需要做的事 /// diff --git a/Library/Common/Event/AddonDataRequestEventArgs.cs b/Library/Common/Event/AddonDataRequestEventArgs.cs new file mode 100644 index 0000000..3856089 --- /dev/null +++ b/Library/Common/Event/AddonDataRequestEventArgs.cs @@ -0,0 +1,11 @@ +using Milimoe.FunGame.Core.Interface.Base; + +namespace Milimoe.FunGame.Core.Library.Common.Event +{ + public class AddonDataRequestEventArgs(IServerModel client, string from, string target) : GeneralEventArgs + { + public IServerModel Client { get; set; } = client; + public string From { get; set; } = from; + public string Target { get; set; } = target; + } +} diff --git a/Library/Constant/ConstantSet.cs b/Library/Constant/ConstantSet.cs index 53224d3..380ead5 100644 --- a/Library/Constant/ConstantSet.cs +++ b/Library/Constant/ConstantSet.cs @@ -1,4 +1,5 @@ using System.Text; +using Milimoe.FunGame.Core.Interface.Addons; using Milimoe.FunGame.Core.Model; /** @@ -104,7 +105,11 @@ namespace Milimoe.FunGame.Core.Library.Constant public const int MaxConnection_1C2G = 10; public const int MaxConnection_2C2G = 20; public const int MaxConnection_4C4G = 40; - public const string Plugins_Mark = "plugins_mark"; + public const string Plugins_Mark = "$*plugins_mark*"; + public const string AddonDataRequestMark_FromPlugin = "$*from_plugin*"; + public const string AddonDataRequestMark_TargetPlugin = "$*target_plugin*"; + public const string AddonDataRequestMark_FromModule = "$*from_module*"; + public const string AddonDataRequestMark_TargetModule = "$*target_module*"; public const string Socket = "Socket"; public const string Unknown = "Unknown"; @@ -211,6 +216,11 @@ namespace Milimoe.FunGame.Core.Library.Constant public const string Inventory_MakeOffer = "Inventory::MakeOffer"; public const string Inventory_ReviseOffer = "Inventory::ReviseOffer"; public const string Inventory_RespondOffer = "Inventory::RespondOffer"; + /** + * Addon + */ + public const string Addon_Plugin = "Addon::Plugin"; + public const string Addon_Module = "Addon::Module"; /// /// 获取Type的等效字符串 @@ -256,6 +266,8 @@ namespace Milimoe.FunGame.Core.Library.Constant DataRequestType.Inventory_MakeOffer => Inventory_MakeOffer, DataRequestType.Inventory_ReviseOffer => Inventory_ReviseOffer, DataRequestType.Inventory_RespondOffer => Inventory_RespondOffer, + DataRequestType.Addon_Module => Addon_Module, + DataRequestType.Addon_Plugin => Addon_Plugin, _ => UnKnown }; } diff --git a/Library/Constant/TypeEnum.cs b/Library/Constant/TypeEnum.cs index f4f03ae..7e27f4e 100644 --- a/Library/Constant/TypeEnum.cs +++ b/Library/Constant/TypeEnum.cs @@ -122,6 +122,8 @@ namespace Milimoe.FunGame.Core.Library.Constant Inventory_MakeOffer, Inventory_ReviseOffer, Inventory_RespondOffer, + Addon_Plugin, + Addon_Module } /// @@ -1118,4 +1120,13 @@ namespace Milimoe.FunGame.Core.Library.Constant NumberInput, Custom } + + public enum PositionType + { + Center, + Left, + Right, + Top, + Bottom + } }