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, IConnectEvent { public override string Name => "fungame.example.plugin"; public override string Description => "My First Plugin"; public override string Version => "1.0.0"; 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 order, string[] args) { // 该方法用于接收服务器控制台的输入并处理 if (order.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) { } public void BeforeLoginEvent(object sender, LoginEventArgs e) { // 如果这里设置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 = "用户名不存在。"; } } } } }