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
+ }
}