From 2de1e57e0ca4830a3cd2cd2a7adf5ef3f266235d Mon Sep 17 00:00:00 2001 From: milimoe <110188673+milimoe@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:24:53 +0800 Subject: [PATCH] =?UTF-8?q?=E9=92=88=E5=AF=B9=E6=9C=8D=E5=8A=A1=E5=99=A8?= =?UTF-8?q?=E7=AB=AF=E7=9A=84=E6=96=B0=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=B8=8E=E6=94=B9=E8=BF=9B=20(#90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 添加SQLite模式 * 将Hashtable转为Dictionary,因为它具有性能优势 * 添加GamingRequest用于区分Gaming * 模组中AfterLoad方法现已移动至加载器完全加载完毕后触发 * 删除了服务器对GameModule的加载,现在只会加载GameModuleServer --- Api/Transmittal/DataRequest.cs | 63 +++++---- Api/Transmittal/SQLHelper.cs | 1 + Api/Utility/ActionQueue.cs | 6 +- Api/Utility/GameModuleLoader.cs | 34 +++-- Api/Utility/General.cs | 9 ++ Api/Utility/JsonTool.cs | 12 +- Api/Utility/TextReader.cs | 6 + Entity/Character/Character.cs | 4 +- Entity/Item/Item.cs | 12 +- Entity/Skill/Skill.cs | 6 +- FunGame.Core.csproj | 4 +- Interface/Base/Addons/IGameModule.cs | 5 +- Interface/Base/Addons/IGameModuleServer.cs | 5 +- Interface/Base/IBaseSocket.cs | 4 - Interface/Base/IServerModel.cs | 16 ++- Interface/Base/ISocketMessageProcessor.cs | 15 +++ Interface/Base/Sockets/IWebSocket.cs | 10 ++ Interface/Event/GamingEventHandlers.cs | 45 ++++--- Interface/Event/GamingEvents.cs | 43 +++--- .../Common/Addon/Example/ExampleGameModule.cs | 73 ++--------- Library/Common/Addon/GameModule.cs | 56 ++++---- Library/Common/Addon/GameModuleServer.cs | 47 ++++++- .../JsonConverter/CharacterConverter.cs | 4 + Library/Common/JsonConverter/ItemConverter.cs | 3 +- Library/Common/Network/ClientSocket.cs | 31 +++-- Library/Common/Network/ClientWebSocket.cs | 43 ++++++ Library/Common/Network/HTTPClient.cs | 6 +- Library/Common/Network/HTTPListener.cs | 39 ++++-- Library/Common/Network/ServerSocket.cs | 32 ++--- Library/Common/Network/Socket.cs | 14 +- Library/Constant/ConstantSet.cs | 1 + Library/Constant/General.cs | 2 +- Library/Constant/TypeEnum.cs | 10 +- Library/Exception/Exception.cs | 9 +- Model/Gaming.cs | 50 ++++--- Service/AddonManager.cs | 17 +-- Service/HTTPManager.cs | 27 ++-- Service/JsonManager.cs | 43 ++++++ Service/SocketManager.cs | 123 ++++++++++++------ 39 files changed, 566 insertions(+), 364 deletions(-) create mode 100644 Interface/Base/ISocketMessageProcessor.cs create mode 100644 Interface/Base/Sockets/IWebSocket.cs create mode 100644 Library/Common/Network/ClientWebSocket.cs diff --git a/Api/Transmittal/DataRequest.cs b/Api/Transmittal/DataRequest.cs index 1377317..90b1a5b 100644 --- a/Api/Transmittal/DataRequest.cs +++ b/Api/Transmittal/DataRequest.cs @@ -1,5 +1,4 @@ -using System.Collections; -using Milimoe.FunGame.Core.Controller; +using Milimoe.FunGame.Core.Controller; using Milimoe.FunGame.Core.Library.Common.Network; using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Exception; @@ -37,7 +36,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal } set { - AddRequestData(key, value); + if (value != null) AddRequestData(key, value); } } @@ -114,17 +113,15 @@ namespace Milimoe.FunGame.Core.Api.Transmittal /// /// /// - public void AddRequestData(string key, object? value) + public void AddRequestData(string key, object value) { if (Worker != null) { - if (Worker.RequestData.ContainsKey(key)) Worker.RequestData[key] = value; - else Worker.RequestData.Add(key, value); + if (!Worker.RequestData.TryAdd(key, value)) Worker.RequestData[key] = value; } else if (GamingWorker != null) { - if (GamingWorker.RequestData.ContainsKey(key)) GamingWorker.RequestData[key] = value; - else GamingWorker.RequestData.Add(key, value); + if (!GamingWorker.RequestData.TryAdd(key, value)) GamingWorker.RequestData[key] = value; } } @@ -142,7 +139,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal /// 警告: 调用此方法将抛出异常。请调用并等待 /// /// - /// + /// public RequestResult SendRequest() { Worker?.SendRequest(); @@ -177,11 +174,11 @@ namespace Milimoe.FunGame.Core.Api.Transmittal { if (Worker != null) { - return GetHashtableJsonObject(Worker.ResultData, key); + return GetDictionaryJsonObject(Worker.ResultData, key); } else if (GamingWorker != null) { - return GetHashtableJsonObject(GamingWorker.ResultData, key); + return GetDictionaryJsonObject(GamingWorker.ResultData, key); } return default; } @@ -191,8 +188,8 @@ namespace Milimoe.FunGame.Core.Api.Transmittal /// private class SocketRequest : SocketHandlerController { - public Hashtable RequestData { get; } = []; - public Hashtable ResultData => _ResultData; + public Dictionary RequestData { get; } = []; + public Dictionary ResultData => _ResultData; public RequestResult Result => _Result; public string Error => _Error; @@ -202,7 +199,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal private readonly Guid RequestID = Guid.Empty; private readonly bool IsLongRunning = false; private readonly SocketRuntimeType RuntimeType = SocketRuntimeType.Client; - private Hashtable _ResultData = []; + private Dictionary _ResultData = []; private RequestResult _Result = RequestResult.Missing; private string _Error = ""; @@ -229,7 +226,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal try { SetWorking(); - if (RuntimeType == SocketRuntimeType.Addon || RuntimeType == SocketRuntimeType.Addon) + if (RuntimeType == SocketRuntimeType.Addon) { if (RequestData.ContainsKey(SocketSet.Plugins_Mark)) RequestData[SocketSet.Plugins_Mark] = "true"; else RequestData.Add(SocketSet.Plugins_Mark, true); @@ -241,7 +238,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal } else if (WebSocket != null) { - throw new AsyncRequestException(); + throw new AsyncSendException(); } else throw new ConnectFailedException(); } @@ -258,7 +255,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal try { SetWorking(); - if (RuntimeType == SocketRuntimeType.Addon || RuntimeType == SocketRuntimeType.Addon) + if (RuntimeType == SocketRuntimeType.Addon) { if (RequestData.ContainsKey(SocketSet.Plugins_Mark)) RequestData[SocketSet.Plugins_Mark] = "true"; else RequestData.Add(SocketSet.Plugins_Mark, true); @@ -295,7 +292,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal if (!IsLongRunning) Dispose(); Work = SocketObject; Working = false; - _ResultData = SocketObject.GetParam(2) ?? []; + _ResultData = SocketObject.GetParam>(2) ?? []; _Result = RequestResult.Success; } } @@ -314,8 +311,8 @@ namespace Milimoe.FunGame.Core.Api.Transmittal /// private class GamingRequest : SocketHandlerController { - public Hashtable RequestData { get; } = []; - public Hashtable ResultData => _ResultData; + public Dictionary RequestData { get; } = []; + public Dictionary ResultData => _ResultData; public RequestResult Result => _Result; public string Error => _Error; @@ -325,7 +322,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal private readonly Guid RequestID = Guid.Empty; private readonly bool IsLongRunning = false; private readonly SocketRuntimeType RuntimeType = SocketRuntimeType.Client; - private Hashtable _ResultData = []; + private Dictionary _ResultData = []; private RequestResult _Result = RequestResult.Missing; private string _Error = ""; @@ -352,19 +349,19 @@ namespace Milimoe.FunGame.Core.Api.Transmittal try { SetWorking(); - if (RuntimeType == SocketRuntimeType.Addon || RuntimeType == SocketRuntimeType.Addon) + if (RuntimeType == SocketRuntimeType.Addon) { if (RequestData.ContainsKey(SocketSet.Plugins_Mark)) RequestData[SocketSet.Plugins_Mark] = "true"; else RequestData.Add(SocketSet.Plugins_Mark, true); } else RequestData.Remove(SocketSet.Plugins_Mark); - if (Socket != null && Socket.Send(SocketMessageType.DataRequest, GamingType, RequestID, RequestData) == SocketResult.Success) + if (Socket != null && Socket.Send(SocketMessageType.GamingRequest, GamingType, RequestID, RequestData) == SocketResult.Success) { WaitForWorkDone(); } else if (WebSocket != null) { - throw new AsyncRequestException(); + throw new AsyncSendException(); } else throw new ConnectFailedException(); } @@ -381,17 +378,17 @@ namespace Milimoe.FunGame.Core.Api.Transmittal try { SetWorking(); - if (RuntimeType == SocketRuntimeType.Addon || RuntimeType == SocketRuntimeType.Addon) + if (RuntimeType == SocketRuntimeType.Addon) { if (RequestData.ContainsKey(SocketSet.Plugins_Mark)) RequestData[SocketSet.Plugins_Mark] = "true"; else RequestData.Add(SocketSet.Plugins_Mark, true); } else RequestData.Remove(SocketSet.Plugins_Mark); - if (Socket != null && Socket.Send(SocketMessageType.DataRequest, GamingType, RequestID, RequestData) == SocketResult.Success) + if (Socket != null && Socket.Send(SocketMessageType.GamingRequest, GamingType, RequestID, RequestData) == SocketResult.Success) { await WaitForWorkDoneAsync(); } - else if (WebSocket != null && await WebSocket.Send(SocketMessageType.DataRequest, GamingType, RequestID, RequestData) == SocketResult.Success) + else if (WebSocket != null && await WebSocket.Send(SocketMessageType.GamingRequest, GamingType, RequestID, RequestData) == SocketResult.Success) { await WaitForWorkDoneAsync(); } @@ -409,7 +406,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal { try { - if (SocketObject.SocketType == SocketMessageType.DataRequest) + if (SocketObject.SocketType == SocketMessageType.GamingRequest) { GamingType type = SocketObject.GetParam(0); Guid id = SocketObject.GetParam(1); @@ -418,7 +415,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal if (!IsLongRunning) Dispose(); Work = SocketObject; Working = false; - _ResultData = SocketObject.GetParam(2) ?? []; + _ResultData = SocketObject.GetParam>(2) ?? []; _Result = RequestResult.Success; } } @@ -433,15 +430,15 @@ namespace Milimoe.FunGame.Core.Api.Transmittal } /// - /// 反序列化Hashtable中的Json对象 + /// 反序列化Dictionary中的Json对象 /// /// - /// + /// /// /// - public static T? GetHashtableJsonObject(Hashtable hashtable, string key) + public static T? GetDictionaryJsonObject(Dictionary dict, string key) { - return Service.JsonManager.GetObject(hashtable, key); + return Service.JsonManager.GetObject(dict, key); } } } diff --git a/Api/Transmittal/SQLHelper.cs b/Api/Transmittal/SQLHelper.cs index 5c69dc0..3aa15ec 100644 --- a/Api/Transmittal/SQLHelper.cs +++ b/Api/Transmittal/SQLHelper.cs @@ -11,6 +11,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal public abstract class SQLHelper : ISQLHelper { public abstract FunGameInfo.FunGame FunGameType { get; } + public abstract SQLMode Mode { get; } public abstract string Script { get; set; } public abstract CommandType CommandType { get; set; } public abstract SQLResult Result { get; } diff --git a/Api/Utility/ActionQueue.cs b/Api/Utility/ActionQueue.cs index d892b7c..5d56639 100644 --- a/Api/Utility/ActionQueue.cs +++ b/Api/Utility/ActionQueue.cs @@ -17,7 +17,7 @@ namespace Milimoe.FunGame.Core.Api.Utility /// 当前的行动顺序 /// public List Queue => _queue; - + /// /// 当前已死亡的角色顺序(第一个是最早死的) /// @@ -342,7 +342,7 @@ namespace Milimoe.FunGame.Core.Api.Utility // 技能列表 List skills = [.. character.Skills.Where(s => s.Level > 0 && s.SkillType != SkillType.Passive && s.Enable && !s.IsInEffect && s.CurrentCD == 0 && (((s.SkillType == SkillType.SuperSkill || s.SkillType == SkillType.Skill) && s.RealEPCost <= character.EP) || (s.SkillType == SkillType.Magic && s.RealMPCost <= character.MP)))]; - + // 物品列表 List items = [.. character.Items.Where(i => i.IsActive && i.Skills.Active != null && i.Enable && i.IsInGameItem && i.Skills.Active.SkillType == SkillType.Item && i.Skills.Active.Enable && !i.Skills.Active.IsInEffect && i.Skills.Active.CurrentCD == 0 && i.Skills.Active.RealMPCost <= character.MP && i.Skills.Active.RealEPCost <= character.EP)]; @@ -1260,7 +1260,7 @@ namespace Milimoe.FunGame.Core.Api.Utility { return CharacterActionType.PreCastSkill; } - + if (rand < pUseItem + pCastSkill + pNormalAttack) { return CharacterActionType.NormalAttack; diff --git a/Api/Utility/GameModuleLoader.cs b/Api/Utility/GameModuleLoader.cs index 323a928..a64c030 100644 --- a/Api/Utility/GameModuleLoader.cs +++ b/Api/Utility/GameModuleLoader.cs @@ -15,7 +15,7 @@ namespace Milimoe.FunGame.Core.Api.Utility /// /// 适用于服务器的模组集 /// - public Dictionary ServerModules { get; } = []; + public Dictionary ModuleServers { get; } = []; /// /// 游戏地图集 @@ -37,11 +37,6 @@ namespace Milimoe.FunGame.Core.Api.Utility /// public Dictionary Items { get; } = []; - /// - /// 客户端模组与服务器模组的关联字典 - /// - public Dictionary AssociatedServers { get; } = []; - /// /// 已加载的模组DLL名称对应的路径 /// @@ -52,7 +47,7 @@ namespace Milimoe.FunGame.Core.Api.Utility /// /// 传入 类型来创建指定端的模组读取器 /// runtime = 时,仅读取 - /// runtime = 时,都会读取,并且生成关联字典 + /// runtime = 时,仅读取 /// 都会读取 /// /// 传入 类型来创建指定端的模组读取器 @@ -66,20 +61,23 @@ namespace Milimoe.FunGame.Core.Api.Utility { AddonManager.LoadGameModules(loader.Modules, loader.Characters, loader.Skills, loader.Items, delegates, otherobjs); AddonManager.LoadGameMaps(loader.Maps, otherobjs); + foreach (GameModule module in loader.Modules.Values) + { + // 读取模组的依赖集合 + module.GameModuleDepend.GetDependencies(loader); + // 如果模组加载后需要执行代码,请重写AfterLoad方法 + module.AfterLoad(runtime, loader); + } } else if (runtime == FunGameInfo.FunGame.FunGame_Server) { - AddonManager.LoadGameModulesForServer(loader.Modules, loader.ServerModules, loader.Characters, loader.Skills, loader.Items, delegates, otherobjs); - foreach (GameModule module in loader.Modules.Values) - { - // AssociatedServerModuleName 已经存包含 IsConnectToOtherServerModule 的判断,因此无需重复判断 - if (loader.ServerModules.TryGetValue(module.AssociatedServerModuleName, out GameModuleServer? server) && server != null) - { - loader.AssociatedServers.Add(module, server); - } - else loader.AssociatedServers.Add(module, null); // 服务器获取GameModuleServer时需要判断是否存在模组。 - } + AddonManager.LoadGameModulesForServer(loader.ModuleServers, loader.Characters, loader.Skills, loader.Items, delegates, otherobjs); AddonManager.LoadGameMaps(loader.Maps, otherobjs); + foreach (GameModuleServer server in loader.ModuleServers.Values) + { + server.GameModuleDepend.GetDependencies(loader); + server.AfterLoad(loader); + } } return loader; } @@ -109,7 +107,7 @@ namespace Milimoe.FunGame.Core.Api.Utility /// public GameModuleServer GetServerMode(string name) { - return ServerModules[name]; + return ModuleServers[name]; } /// diff --git a/Api/Utility/General.cs b/Api/Utility/General.cs index 058971a..935d3c1 100644 --- a/Api/Utility/General.cs +++ b/Api/Utility/General.cs @@ -217,6 +217,15 @@ namespace Milimoe.FunGame.Core.Api.Utility /// public static T? JsonDeserializeFromHashtable(Hashtable hashtable, string key) => Service.JsonManager.GetObject(hashtable, key); + /// + /// 反序列化Dictionary中的Json对象 + /// + /// + /// + /// + /// + public static T? JsonDeserializeFromDictionary(Dictionary dict, string key) => Service.JsonManager.GetObject(dict, key); + /// /// 反序列化IEnumerable中的Json对象 /// diff --git a/Api/Utility/JsonTool.cs b/Api/Utility/JsonTool.cs index d0059d7..e3f2479 100644 --- a/Api/Utility/JsonTool.cs +++ b/Api/Utility/JsonTool.cs @@ -75,6 +75,15 @@ namespace Milimoe.FunGame.Core.Api.Utility /// public T? GetObject(Hashtable table, string key) => JsonManager.GetObject(table, key, options); + /// + /// 反序列化Dictionary中Key对应的Json对象 + /// + /// + /// + /// + /// + public T? GetObject(Dictionary dict, string key) => JsonManager.GetObject(dict, key, options); + /// /// 反序列化IEnumerable中的Json对象 可指定反序列化选项 /// @@ -100,7 +109,8 @@ namespace Milimoe.FunGame.Core.Api.Utility { WriteIndented = true, ReferenceHandler = ReferenceHandler.IgnoreCycles, - Converters = { new DateTimeConverter(), new DataTableConverter(), new DataSetConverter(), new UserConverter(), new RoomConverter() } + Converters = { new DateTimeConverter(), new DataTableConverter(), new DataSetConverter(), new UserConverter(), new RoomConverter(), + new CharacterConverter(), new MagicResistanceConverter(), new EquipSlotConverter(), new SkillConverter(), new EffectConverter(), new ItemConverter() } }; } } diff --git a/Api/Utility/TextReader.cs b/Api/Utility/TextReader.cs index 21832f5..e7d8f88 100644 --- a/Api/Utility/TextReader.cs +++ b/Api/Utility/TextReader.cs @@ -105,11 +105,17 @@ namespace Milimoe.FunGame.Core.Api.Utility /** * MySQL */ + WriteINI("MySQL", "UseMySQL", "false"); WriteINI("MySQL", "DBServer", "localhost"); WriteINI("MySQL", "DBPort", "3306"); WriteINI("MySQL", "DBName", "fungame"); WriteINI("MySQL", "DBUser", "root"); WriteINI("MySQL", "DBPassword", "pass"); + /** + * SQLite + */ + WriteINI("SQLite", "UseSQLite", "true"); + WriteINI("SQLite", "DataSource", "FunGameDB"); /** * Mailer */ diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs index 12d3a85..5b8b20f 100644 --- a/Entity/Character/Character.cs +++ b/Entity/Character/Character.cs @@ -1006,7 +1006,7 @@ namespace Milimoe.FunGame.Core.Entity } return str; } - + /// /// 获取角色实例的名字、昵称 /// @@ -1122,7 +1122,7 @@ namespace Milimoe.FunGame.Core.Entity builder.Append(skill.ToString()); } } - + if (EquipSlot.Any()) { builder.AppendLine("== 装备栏 =="); diff --git a/Entity/Item/Item.cs b/Entity/Item/Item.cs index d4846dd..b71deac 100644 --- a/Entity/Item/Item.cs +++ b/Entity/Item/Item.cs @@ -20,7 +20,7 @@ namespace Milimoe.FunGame.Core.Entity /// 物品的通用描述 /// public virtual string GeneralDescription { get; set; } = ""; - + /// /// 物品的背景故事 /// @@ -45,7 +45,7 @@ namespace Milimoe.FunGame.Core.Entity /// 装备槽位 /// public virtual EquipSlotType EquipSlotType { get; set; } = EquipSlotType.None; - + /// /// 武器类型(如果是武器) /// @@ -65,7 +65,7 @@ namespace Milimoe.FunGame.Core.Entity /// 是否可用(涉及冷却和禁用等) /// public bool Enable { get; set; } = true; - + /// /// 是否是局内使用的物品(局内是指对角色生效的物品) /// @@ -95,7 +95,7 @@ namespace Milimoe.FunGame.Core.Entity /// 是否允许交易 /// public bool IsTradable { get; set; } = true; - + /// /// 下次可交易的时间 /// @@ -160,7 +160,7 @@ namespace Milimoe.FunGame.Core.Entity } if (Character != null) OnItemEquipped(Character, this, type); } - + /// /// 当取消装备物品时 /// @@ -236,7 +236,7 @@ namespace Milimoe.FunGame.Core.Entity { } - + /// /// 当物品被玩家使用时 /// diff --git a/Entity/Skill/Skill.cs b/Entity/Skill/Skill.cs index ab25ba4..147e630 100644 --- a/Entity/Skill/Skill.cs +++ b/Entity/Skill/Skill.cs @@ -19,7 +19,7 @@ namespace Milimoe.FunGame.Core.Entity /// 技能描述 /// public virtual string Description { get; set; } = ""; - + /// /// 技能的通用描述 /// @@ -145,7 +145,7 @@ namespace Milimoe.FunGame.Core.Entity /// 游戏中的行动顺序表实例,在技能效果被触发时,此实例会获得赋值,使用时需要判断其是否存在 /// public ActionQueue? ActionQueue { get; set; } = null; - + /// /// 技能是否属于某个物品 /// @@ -302,7 +302,7 @@ namespace Milimoe.FunGame.Core.Entity { return Id + "." + Name; } - + /// /// 判断两个技能是否相同 检查Id.Name /// diff --git a/FunGame.Core.csproj b/FunGame.Core.csproj index 832f0b0..c452b13 100644 --- a/FunGame.Core.csproj +++ b/FunGame.Core.csproj @@ -21,12 +21,12 @@ embedded - 1701;1702;CS1591;CS1587 + 1701;1702;CS1591;CS1587;IDE0130 embedded - 1701;1702;CS1591;CS1587 + 1701;1702;CS1591;CS1587;IDE0130 diff --git a/Interface/Base/Addons/IGameModule.cs b/Interface/Base/Addons/IGameModule.cs index fde6564..866ba17 100644 --- a/Interface/Base/Addons/IGameModule.cs +++ b/Interface/Base/Addons/IGameModule.cs @@ -6,7 +6,8 @@ namespace Milimoe.FunGame.Core.Interface.Addons IGamingRandomEventHandler, IGamingRoundEventHandler, IGamingLevelUpEventHandler, IGamingMoveEventHandler, IGamingAttackEventHandler, IGamingSkillEventHandler, IGamingItemEventHandler, IGamingMagicEventHandler, IGamingBuyEventHandler, IGamingSuperSkillEventHandler, IGamingPauseEventHandler, IGamingUnpauseEventHandler, IGamingSurrenderEventHandler, IGamingUpdateInfoEventHandler, IGamingPunishEventHandler, IGameModuleDepend { - public abstract void StartGame(Gaming instance, params object[] args); - public abstract void StartUI(params object[] args); + public bool HideMain { get; } + public void StartGame(Gaming instance, params object[] args); + public void StartUI(params object[] args); } } diff --git a/Interface/Base/Addons/IGameModuleServer.cs b/Interface/Base/Addons/IGameModuleServer.cs index 4fdce63..1c4ad41 100644 --- a/Interface/Base/Addons/IGameModuleServer.cs +++ b/Interface/Base/Addons/IGameModuleServer.cs @@ -1,5 +1,4 @@ -using System.Collections; -using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Library.Constant; @@ -9,6 +8,6 @@ namespace Milimoe.FunGame.Core.Interface.Addons { public bool StartServer(string GameModule, Room Room, List Users, IServerModel RoomMasterServerModel, Dictionary ServerModels, params object[] args); - public Hashtable GamingMessageHandler(string username, GamingType type, Hashtable data); + public Dictionary GamingMessageHandler(string username, GamingType type, Dictionary data); } } diff --git a/Interface/Base/IBaseSocket.cs b/Interface/Base/IBaseSocket.cs index 8b93c4f..6eb6718 100644 --- a/Interface/Base/IBaseSocket.cs +++ b/Interface/Base/IBaseSocket.cs @@ -6,10 +6,6 @@ namespace Milimoe.FunGame.Core.Interface.Base { public SocketRuntimeType Runtime { get; } public Guid Token { get; } - public string ServerAddress { get; } - public int ServerPort { get; } - public string ServerName { get; } - public string ServerNotice { get; } public void Close(); } } diff --git a/Interface/Base/IServerModel.cs b/Interface/Base/IServerModel.cs index d993e9d..8ac4c31 100644 --- a/Interface/Base/IServerModel.cs +++ b/Interface/Base/IServerModel.cs @@ -1,4 +1,5 @@ using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Common.Network; using Milimoe.FunGame.Core.Library.Constant; @@ -14,7 +15,7 @@ namespace Milimoe.FunGame.Core.Interface.Base /// /// 客户端的套接字实例 /// - public abstract ClientSocket? Socket { get; } + public abstract ISocketMessageProcessor? Socket { get; } /// /// 客户端的用户实例,在用户登录后有效 @@ -31,6 +32,11 @@ namespace Milimoe.FunGame.Core.Interface.Base /// public bool IsDebugMode { get; } + /// + /// 客户端的游戏模组服务器 + /// + public GameModuleServer? NowGamingServer { get; set; } + /// /// 向客户端发送消息 /// @@ -38,7 +44,7 @@ namespace Milimoe.FunGame.Core.Interface.Base /// /// /// - public bool Send(ClientSocket socket, SocketMessageType type, params object[] objs); + public bool Send(ISocketMessageProcessor socket, SocketMessageType type, params object[] objs); /// /// 向客户端发送系统消息 @@ -58,15 +64,15 @@ namespace Milimoe.FunGame.Core.Interface.Base /// /// 开始接收客户端消息 - /// 请勿在 中调用此方法 + /// 请勿在 中调用此方法 /// /// /// - public bool Read(ClientSocket socket); + public bool Read(ISocketMessageProcessor socket); /// /// 启动对客户端的监听 - /// 请勿在 中调用此方法 + /// 请勿在 中调用此方法 /// public void Start(); } diff --git a/Interface/Base/ISocketMessageProcessor.cs b/Interface/Base/ISocketMessageProcessor.cs new file mode 100644 index 0000000..d9e212f --- /dev/null +++ b/Interface/Base/ISocketMessageProcessor.cs @@ -0,0 +1,15 @@ +using Milimoe.FunGame.Core.Library.Constant; + +namespace Milimoe.FunGame.Core.Interface.Base +{ + public interface ISocketMessageProcessor + { + public Type InstanceType { get; } + public string ClientIP { get; } + public string ClientName { get; } + + public SocketResult Send(SocketMessageType type, params object[] objs); + public Task SendAsync(SocketMessageType type, params object[] objs); + public void Close(); + } +} diff --git a/Interface/Base/Sockets/IWebSocket.cs b/Interface/Base/Sockets/IWebSocket.cs new file mode 100644 index 0000000..07ab29b --- /dev/null +++ b/Interface/Base/Sockets/IWebSocket.cs @@ -0,0 +1,10 @@ +using Milimoe.FunGame.Core.Interface.Base; + +namespace Milimoe.FunGame.Core.Interface.Sockets +{ + public interface IWebSocket : IBaseSocket + { + public System.Net.WebSockets.WebSocket Instance { get; } + public bool Connected => Instance != null && Instance.State == System.Net.WebSockets.WebSocketState.Open; + } +} diff --git a/Interface/Event/GamingEventHandlers.cs b/Interface/Event/GamingEventHandlers.cs index 2f885f5..71156ba 100644 --- a/Interface/Event/GamingEventHandlers.cs +++ b/Interface/Event/GamingEventHandlers.cs @@ -1,5 +1,4 @@ -using System.Collections; -using Milimoe.FunGame.Core.Library.Common.Addon; +using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Common.Event; namespace Milimoe.FunGame.Core.Interface @@ -9,146 +8,146 @@ namespace Milimoe.FunGame.Core.Interface /// public interface IGamingEventHandler { - public delegate void GamingEventHandler(object sender, GamingEventArgs e, Hashtable data); + public delegate void GamingEventHandler(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingConnectEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingConnect; - public void OnGamingConnectEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingConnectEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingDisconnectEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingDisconnect; - public void OnGamingDisconnectEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingDisconnectEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingReconnectEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingReconnect; - public void OnGamingReconnectEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingReconnectEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingBanCharacterEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingBanCharacter; - public void OnGamingBanCharacterEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingBanCharacterEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingPickCharacterEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingPickCharacter; - public void OnGamingPickCharacterEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingPickCharacterEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingRandomEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingRandom; - public void OnGamingRandomEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingRandomEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingRoundEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingRound; - public void OnGamingRoundEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingRoundEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingLevelUpEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingLevelUp; - public void OnGamingLevelUpEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingLevelUpEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingMoveEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingMove; - public void OnGamingMoveEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingMoveEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingAttackEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingAttack; - public void OnGamingAttackEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingAttackEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingSkillEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingSkill; - public void OnGamingSkillEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingSkillEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingItemEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingItem; - public void OnGamingItemEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingItemEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingMagicEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingMagic; - public void OnGamingMagicEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingMagicEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingBuyEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingBuy; - public void OnGamingBuyEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingBuyEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingSuperSkillEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingSuperSkill; - public void OnGamingSuperSkillEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingSuperSkillEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingPauseEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingPause; - public void OnGamingPauseEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingPauseEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingUnpauseEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingUnpause; - public void OnGamingUnpauseEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingUnpauseEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingSurrenderEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingSurrender; - public void OnGamingSurrenderEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingSurrenderEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingUpdateInfoEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingUpdateInfo; - public void OnGamingUpdateInfoEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingUpdateInfoEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingPunishEventHandler : IGamingEventHandler { public event GamingEventHandler? GamingPunish; - public void OnGamingPunishEvent(object sender, GamingEventArgs e, Hashtable data); + public void OnGamingPunishEvent(object sender, GamingEventArgs e, Dictionary data); } } diff --git a/Interface/Event/GamingEvents.cs b/Interface/Event/GamingEvents.cs index 4061ae8..9d291a6 100644 --- a/Interface/Event/GamingEvents.cs +++ b/Interface/Event/GamingEvents.cs @@ -1,106 +1,105 @@ -using System.Collections; -using Milimoe.FunGame.Core.Library.Common.Event; +using Milimoe.FunGame.Core.Library.Common.Event; // 模组需要实现什么事件就继承什么接口 namespace Milimoe.FunGame.Core.Interface { public interface IGamingConnectEvent { - public void GamingConnectEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingConnectEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingDisconnectEvent { - public void GamingDisconnectEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingDisconnectEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingReconnectEvent { - public void GamingReconnectEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingReconnectEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingBanCharacterEvent { - public void GamingBanCharacterEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingBanCharacterEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingPickCharacterEvent { - public void GamingPickCharacterEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingPickCharacterEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingRandomEvent { - public void GamingRandomEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingRandomEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingRoundEvent { - public void GamingRoundEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingRoundEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingLevelUpEvent { - public void GamingLevelUpEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingLevelUpEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingMoveEvent { - public void GamingMoveEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingMoveEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingAttackEvent { - public void GamingAttackEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingAttackEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingSkillEvent { - public void GamingSkillEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingSkillEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingItemEvent { - public void GamingItemEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingItemEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingMagicEvent { - public void GamingMagicEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingMagicEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingBuyEvent { - public void GamingBuyEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingBuyEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingSuperSkillEvent { - public void GamingSuperSkillEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingSuperSkillEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingPauseEvent { - public void GamingPauseEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingPauseEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingUnpauseEvent { - public void GamingUnpauseEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingUnpauseEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingSurrenderEvent { - public void GamingSurrenderEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingSurrenderEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingUpdateInfoEvent { - public void GamingUpdateInfoEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingUpdateInfoEvent(object sender, GamingEventArgs e, Dictionary data); } public interface IGamingPunishEvent { - public void GamingPunishEvent(object sender, GamingEventArgs e, Hashtable data); + public void GamingPunishEvent(object sender, GamingEventArgs e, Dictionary data); } } diff --git a/Library/Common/Addon/Example/ExampleGameModule.cs b/Library/Common/Addon/Example/ExampleGameModule.cs index 0ecc9ff..986dfd8 100644 --- a/Library/Common/Addon/Example/ExampleGameModule.cs +++ b/Library/Common/Addon/Example/ExampleGameModule.cs @@ -1,4 +1,3 @@ -using System.Collections; using Milimoe.FunGame.Core.Api.Transmittal; using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Entity; @@ -49,6 +48,8 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example public override RoomType RoomType => RoomType.Mix; + public override bool HideMain => false; + public ExampleGameModule() { // 构造函数中可以指定模组连接到哪个模组服务器。 @@ -78,16 +79,16 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example // 如果没有,则不需要重写此方法 } - public void GamingUpdateInfoEvent(object sender, GamingEventArgs e, Hashtable data) + public void GamingUpdateInfoEvent(object sender, GamingEventArgs e, Dictionary data) { // 在下方的Server示例中,服务器发来的data中,包含check字符串,因此客户端要主动发起确认连接的请求。 if (data.ContainsKey("info_type")) { // 反序列化得到指定key的值 - string info_type = DataRequest.GetHashtableJsonObject(data, "info_type") ?? ""; + string info_type = DataRequest.GetDictionaryJsonObject(data, "info_type") ?? ""; if (info_type == "check") { - Guid token = DataRequest.GetHashtableJsonObject(data, "connect_token"); + Guid token = DataRequest.GetDictionaryJsonObject(data, "connect_token"); // 发起连接确认请求 DataRequest request = Controller.NewDataRequest(GamingType.Connect); // 传递参数 @@ -143,7 +144,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example } private readonly List ConnectedUser = []; - private readonly Dictionary UserData = []; + private readonly Dictionary> UserData = []; private async Task Test() { @@ -154,7 +155,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example // 在FunGame项目中,建议永远使用客户端主动发起请求,因为服务器主动发起的实现难度较高 // 下面的演示基于综合的两种情况:服务器主动发送通知,客户端收到后,发起确认 // UpdateInfo是一个灵活的类型。如果发送check字符串,意味着服务器要求客户端发送确认 - Hashtable data = []; + Dictionary data = []; data.Add("info_type", "check"); // 进阶示例:传递一个token,让客户端返回 @@ -164,7 +165,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example // 我们保存到字典UserData中,这样可以方便跨方法检查变量 foreach (string username in Users.Select(u => u.Username).Distinct()) { - if (UserData.TryGetValue(username, out Hashtable? value)) + if (UserData.TryGetValue(username, out Dictionary? value)) { value.Add("connect_token", token); } @@ -174,7 +175,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example UserData[username].Add("connect_token", token); } } - SendAllGamingMessage(GamingType.UpdateInfo, data); + SendGamingMessage(All.Values, GamingType.UpdateInfo, data); // 新建一个线程等待所有玩家确认 while (true) @@ -186,18 +187,18 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example Controller.WriteLine("所有玩家都已经连接。"); } - public override Hashtable GamingMessageHandler(string username, GamingType type, Hashtable data) + public override Dictionary GamingMessageHandler(string username, GamingType type, Dictionary data) { - Hashtable result = []; + Dictionary result = []; switch (type) { case GamingType.Connect: // 编写处理“连接”命令的逻辑 // 如果需要处理客户端传递的参数:获取与客户端约定好的参数key对应的值 - string un = NetworkUtility.JsonDeserializeFromHashtable(data, "username") ?? ""; - Guid token = NetworkUtility.JsonDeserializeFromHashtable(data, "connect_token"); - if (un == username && UserData.TryGetValue(username, out Hashtable? value) && value != null && (value["connect_token"]?.Equals(token) ?? false)) + string un = NetworkUtility.JsonDeserializeFromDictionary(data, "username") ?? ""; + Guid token = NetworkUtility.JsonDeserializeFromDictionary(data, "connect_token"); + if (un == username && UserData.TryGetValue(username, out Dictionary? value) && value != null && (value["connect_token"]?.Equals(token) ?? false)) { ConnectedUser.Add(Users.Where(u => u.Username == username).First()); Controller.WriteLine(username + " 已经连接。"); @@ -208,52 +209,6 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example return result; } - - // === 下面是一些常用的工具方法,用于服务器给客户端发送消息,可以直接添加到你的项目中 === // - - protected void SendAllGamingMessage(GamingType type, Hashtable data) - { - // 循环服务线程,向所有玩家发送局内消息 - foreach (IServerModel s in All.Values) - { - if (s != null && s.Socket != null) - { - s.Send(s.Socket, SocketMessageType.Gaming, type, data); - } - } - } - - protected void SendGamingMessage(string username, GamingType type, Hashtable data) - { - // 向指定玩家发送局内消息 - IServerModel s = All[username]; - if (s != null && s.Socket != null) - { - s.Send(s.Socket, SocketMessageType.Gaming, type, data); - } - } - - protected void SendAll(SocketMessageType type, params object[] args) - { - // 循环服务线程,向所有玩家发送消息 - foreach (IServerModel s in All.Values) - { - if (s != null && s.Socket != null) - { - s.Send(s.Socket, type, args); - } - } - } - - protected void Send(string username, SocketMessageType type, params object[] args) - { - // 向指定玩家发送消息 - IServerModel s = All[username]; - if (s != null && s.Socket != null) - { - s.Send(s.Socket, type, args); - } - } } /// diff --git a/Library/Common/Addon/GameModule.cs b/Library/Common/Addon/GameModule.cs index e6d42f0..64fb782 100644 --- a/Library/Common/Addon/GameModule.cs +++ b/Library/Common/Addon/GameModule.cs @@ -1,4 +1,3 @@ -using System.Collections; using Milimoe.FunGame.Core.Controller; using Milimoe.FunGame.Core.Interface; using Milimoe.FunGame.Core.Interface.Addons; @@ -45,6 +44,11 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon /// public abstract RoomType RoomType { get; } + /// + /// 是否隐藏主界面 + /// + public abstract bool HideMain { get; } + /// /// 是否连接其他的服务器模组 /// @@ -116,7 +120,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon return false; } // BeforeLoad可以阻止加载此模组 - if (BeforeLoad()) + if (BeforeLoad(objs)) { // 模组加载后,不允许再次加载此模组 IsLoaded = true; @@ -124,16 +128,14 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon Init(objs); // 触发绑定事件 BindEvent(); - // 如果加载后需要执行代码,请重写AfterLoad方法 - AfterLoad(); } return IsLoaded; } /// - /// 模组加载后需要做的事 + /// 模组完全加载后需要做的事 /// - protected virtual void AfterLoad() + public virtual void AfterLoad(params object[] args) { // override } @@ -142,7 +144,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon /// 允许返回false来阻止加载此模组 /// /// - protected virtual bool BeforeLoad() + protected virtual bool BeforeLoad(params object[] objs) { return true; } @@ -318,102 +320,102 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon public event IGamingEventHandler.GamingEventHandler? GamingUpdateInfo; public event IGamingEventHandler.GamingEventHandler? GamingPunish; - public void OnGamingConnectEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingConnectEvent(object sender, GamingEventArgs e, Dictionary data) { GamingConnect?.Invoke(sender, e, data); } - public void OnGamingDisconnectEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingDisconnectEvent(object sender, GamingEventArgs e, Dictionary data) { GamingDisconnect?.Invoke(sender, e, data); } - public void OnGamingReconnectEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingReconnectEvent(object sender, GamingEventArgs e, Dictionary data) { GamingReconnect?.Invoke(sender, e, data); } - public void OnGamingBanCharacterEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingBanCharacterEvent(object sender, GamingEventArgs e, Dictionary data) { GamingBanCharacter?.Invoke(sender, e, data); } - public void OnGamingPickCharacterEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingPickCharacterEvent(object sender, GamingEventArgs e, Dictionary data) { GamingPickCharacter?.Invoke(sender, e, data); } - public void OnGamingRandomEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingRandomEvent(object sender, GamingEventArgs e, Dictionary data) { GamingRandom?.Invoke(sender, e, data); } - public void OnGamingRoundEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingRoundEvent(object sender, GamingEventArgs e, Dictionary data) { GamingRound?.Invoke(sender, e, data); } - public void OnGamingLevelUpEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingLevelUpEvent(object sender, GamingEventArgs e, Dictionary data) { GamingLevelUp?.Invoke(sender, e, data); } - public void OnGamingMoveEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingMoveEvent(object sender, GamingEventArgs e, Dictionary data) { GamingMove?.Invoke(sender, e, data); } - public void OnGamingAttackEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingAttackEvent(object sender, GamingEventArgs e, Dictionary data) { GamingAttack?.Invoke(sender, e, data); } - public void OnGamingSkillEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingSkillEvent(object sender, GamingEventArgs e, Dictionary data) { GamingSkill?.Invoke(sender, e, data); } - public void OnGamingItemEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingItemEvent(object sender, GamingEventArgs e, Dictionary data) { GamingItem?.Invoke(sender, e, data); } - public void OnGamingMagicEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingMagicEvent(object sender, GamingEventArgs e, Dictionary data) { GamingMagic?.Invoke(sender, e, data); } - public void OnGamingBuyEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingBuyEvent(object sender, GamingEventArgs e, Dictionary data) { GamingBuy?.Invoke(sender, e, data); } - public void OnGamingSuperSkillEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingSuperSkillEvent(object sender, GamingEventArgs e, Dictionary data) { GamingSuperSkill?.Invoke(sender, e, data); } - public void OnGamingPauseEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingPauseEvent(object sender, GamingEventArgs e, Dictionary data) { GamingPause?.Invoke(sender, e, data); } - public void OnGamingUnpauseEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingUnpauseEvent(object sender, GamingEventArgs e, Dictionary data) { GamingUnpause?.Invoke(sender, e, data); } - public void OnGamingSurrenderEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingSurrenderEvent(object sender, GamingEventArgs e, Dictionary data) { GamingSurrender?.Invoke(sender, e, data); } - public void OnGamingUpdateInfoEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingUpdateInfoEvent(object sender, GamingEventArgs e, Dictionary data) { GamingUpdateInfo?.Invoke(sender, e, data); } - public void OnGamingPunishEvent(object sender, GamingEventArgs e, Hashtable data) + public void OnGamingPunishEvent(object sender, GamingEventArgs e, Dictionary data) { GamingPunish?.Invoke(sender, e, data); } diff --git a/Library/Common/Addon/GameModuleServer.cs b/Library/Common/Addon/GameModuleServer.cs index 731ea82..97aa741 100644 --- a/Library/Common/Addon/GameModuleServer.cs +++ b/Library/Common/Addon/GameModuleServer.cs @@ -1,4 +1,3 @@ -using System.Collections; using Milimoe.FunGame.Core.Controller; using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Interface.Addons; @@ -72,8 +71,8 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon /// 发送此消息的账号 /// 消息类型 /// 消息参数 - /// 底层会将哈希表中的数据发送给客户端 - public abstract Hashtable GamingMessageHandler(string username, GamingType type, Hashtable data); + /// 底层会将字典中的数据发送给客户端 + public abstract Dictionary GamingMessageHandler(string username, GamingType type, Dictionary data); /// /// 加载标记 @@ -94,16 +93,14 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon { // 模组加载后,不允许再次加载此模组 IsLoaded = true; - // 如果加载后需要执行代码,请重写AfterLoad方法 - AfterLoad(); } return IsLoaded; } /// - /// 模组加载后需要做的事 + /// 模组完全加载后需要做的事 /// - protected virtual void AfterLoad() + public virtual void AfterLoad(params object[] args) { // override } @@ -116,5 +113,41 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon { return true; } + + /// + /// 给客户端发送局内消息 + /// + /// + /// + /// + protected virtual void SendGamingMessage(IEnumerable clients, GamingType type, Dictionary data) + { + // 发送局内消息 + foreach (IServerModel s in clients) + { + if (s != null && s.Socket != null) + { + s.Send(s.Socket, SocketMessageType.Gaming, type, data); + } + } + } + + /// + /// 给客户端发送消息 + /// + /// + /// + /// + protected virtual void Send(IEnumerable clients, SocketMessageType type, params object[] args) + { + // 发送消息 + foreach (IServerModel s in clients) + { + if (s != null && s.Socket != null) + { + s.Send(s.Socket, type, args); + } + } + } } } diff --git a/Library/Common/JsonConverter/CharacterConverter.cs b/Library/Common/JsonConverter/CharacterConverter.cs index d8c0841..983af79 100644 --- a/Library/Common/JsonConverter/CharacterConverter.cs +++ b/Library/Common/JsonConverter/CharacterConverter.cs @@ -17,6 +17,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter { switch (propertyName) { + case nameof(Character.Id): + result.Id = reader.GetInt64(); + break; case nameof(Character.Name): result.Name = reader.GetString() ?? ""; break; @@ -190,6 +193,7 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter public override void Write(Utf8JsonWriter writer, Character value, JsonSerializerOptions options) { writer.WriteStartObject(); + writer.WriteNumber(nameof(Character.Id), value.Id); writer.WriteString(nameof(Character.Name), value.Name); writer.WriteString(nameof(Character.FirstName), value.FirstName); writer.WriteString(nameof(Character.NickName), value.NickName); diff --git a/Library/Common/JsonConverter/ItemConverter.cs b/Library/Common/JsonConverter/ItemConverter.cs index 28f943e..ce45eb2 100644 --- a/Library/Common/JsonConverter/ItemConverter.cs +++ b/Library/Common/JsonConverter/ItemConverter.cs @@ -1,5 +1,4 @@ -using System; -using System.Text.Json; +using System.Text.Json; using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Library.Common.Architecture; diff --git a/Library/Common/Network/ClientSocket.cs b/Library/Common/Network/ClientSocket.cs index bac6577..6be9172 100644 --- a/Library/Common/Network/ClientSocket.cs +++ b/Library/Common/Network/ClientSocket.cs @@ -1,27 +1,25 @@ -using Milimoe.FunGame.Core.Interface.Sockets; +using Milimoe.FunGame.Core.Interface.Base; +using Milimoe.FunGame.Core.Interface.Sockets; using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Service; namespace Milimoe.FunGame.Core.Library.Common.Network { - public class ClientSocket(System.Net.Sockets.Socket Instance, int ServerPort, string ClientIP, string ClientName, Guid Token) : IClientSocket + public class ClientSocket(System.Net.Sockets.Socket instance, string clientIP, string clientName, Guid token) : IClientSocket, ISocketMessageProcessor { - public System.Net.Sockets.Socket Instance { get; } = Instance; + public System.Net.Sockets.Socket Instance { get; } = instance; public SocketRuntimeType Runtime => SocketRuntimeType.Server; - public Guid Token { get; } = Token; - public string ServerAddress { get; } = ""; - public int ServerPort { get; } = ServerPort; - public string ServerName { get; } = ""; - public string ServerNotice { get; } = ""; - public string ClientIP { get; } = ClientIP; + public Guid Token { get; } = token; + public string ClientIP { get; } = clientIP; public string ClientName => _ClientName; public bool Connected => Instance != null && Instance.Connected; public bool Receiving => _Receiving; + public Type InstanceType => typeof(ClientSocket); private Task? ReceivingTask; private bool _Receiving; - private readonly string _ClientName = ClientName; + private readonly string _ClientName = clientName; public void Close() { @@ -54,6 +52,19 @@ namespace Milimoe.FunGame.Core.Library.Common.Network return SocketResult.NotSent; } + public async Task SendAsync(SocketMessageType type, params object[] objs) + { + if (Instance != null) + { + if (await SocketManager.SendAsync(Instance, new(type, Token, objs)) == SocketResult.Success) + { + return SocketResult.Success; + } + else return SocketResult.Fail; + } + return SocketResult.NotSent; + } + public void BindEvent(Delegate method, bool remove = false) { if (!remove) diff --git a/Library/Common/Network/ClientWebSocket.cs b/Library/Common/Network/ClientWebSocket.cs new file mode 100644 index 0000000..c72736c --- /dev/null +++ b/Library/Common/Network/ClientWebSocket.cs @@ -0,0 +1,43 @@ +using System.Net.WebSockets; +using Milimoe.FunGame.Core.Api.Utility; +using Milimoe.FunGame.Core.Interface.Base; +using Milimoe.FunGame.Core.Interface.Sockets; +using Milimoe.FunGame.Core.Library.Constant; +using Milimoe.FunGame.Core.Service; + +namespace Milimoe.FunGame.Core.Library.Common.Network +{ + public class ClientWebSocket(HTTPListener listener, WebSocket instance, string clientIP, string clientName, Guid token) : IWebSocket, ISocketMessageProcessor + { + public HTTPListener Listener => listener; + public WebSocket Instance => instance; + public SocketRuntimeType Runtime => SocketRuntimeType.Server; + public Guid Token => token; + public string ClientIP => clientIP; + public string ClientName => clientName; + public Type InstanceType => typeof(ClientWebSocket); + + public void Close() + { + TaskUtility.NewTask(async () => + { + if (Instance.State == WebSocketState.Open) + { + // 安全关闭 WebSocket 连接 + await Instance.CloseAsync(WebSocketCloseStatus.NormalClosure, "服务器正在关闭,断开连接!", CancellationToken.None); + Listener.ClientSockets.Remove(Token); + } + }); + } + + public SocketResult Send(SocketMessageType type, params object[] objs) + { + throw new AsyncSendException(); + } + + public async Task SendAsync(SocketMessageType type, params object[] objs) + { + return await HTTPManager.Send(Instance, new(type, token, objs)); + } + } +} diff --git a/Library/Common/Network/HTTPClient.cs b/Library/Common/Network/HTTPClient.cs index 8b77099..5ed0b49 100644 --- a/Library/Common/Network/HTTPClient.cs +++ b/Library/Common/Network/HTTPClient.cs @@ -9,7 +9,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Network { public class HTTPClient : IHTTPClient { - public ClientWebSocket? Instance { get; } = null; + public System.Net.WebSockets.ClientWebSocket? Instance { get; } = null; public SocketRuntimeType Runtime => SocketRuntimeType.Client; public Guid Token { get; } = Guid.Empty; public string ServerAddress { get; } = ""; @@ -20,7 +20,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Network private bool _Listening = false; private readonly HeartBeat HeartBeat; - private HTTPClient(ClientWebSocket Instance, string ServerAddress, int ServerPort, params object[] args) + private HTTPClient(System.Net.WebSockets.ClientWebSocket Instance, string ServerAddress, int ServerPort, params object[] args) { this.Instance = Instance; this.ServerAddress = ServerAddress; @@ -34,7 +34,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Network { string ServerIP = Api.Utility.NetworkUtility.GetIPAddress(ServerAddress); Uri uri = new((SSL ? "wss://" : "ws://") + ServerIP + ":" + ServerPort + "/" + SubDirectory); - ClientWebSocket? socket = await HTTPManager.Connect(uri); + System.Net.WebSockets.ClientWebSocket? socket = await HTTPManager.Connect(uri); if (socket != null && socket.State == WebSocketState.Open) { HTTPClient client = new(socket, ServerAddress, ServerPort, args); diff --git a/Library/Common/Network/HTTPListener.cs b/Library/Common/Network/HTTPListener.cs index b911480..d9d8fb4 100644 --- a/Library/Common/Network/HTTPListener.cs +++ b/Library/Common/Network/HTTPListener.cs @@ -1,5 +1,6 @@ using System.Net; using System.Net.WebSockets; +using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Interface.HTTP; using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Service; @@ -11,24 +12,20 @@ namespace Milimoe.FunGame.Core.Library.Common.Network public HttpListener Instance { get; } public SocketRuntimeType Runtime => SocketRuntimeType.Server; public Guid Token { get; } = Guid.Empty; - public string ServerAddress { get; } = ""; - public int ServerPort { get; } = 0; - public string ServerName { get; } = ""; - public string ServerNotice { get; } = ""; public Dictionary ClientSockets { get; } = []; - private HTTPListener(HttpListener Instance, int ServerPort) + private HTTPListener(HttpListener instance) { - this.Instance = Instance; - this.ServerPort = ServerPort; + Instance = instance; + Token = Guid.NewGuid(); } - public static HTTPListener StartListening(int Port, bool SSL = false) + public static HTTPListener StartListening(int port, bool ssl = false) { - HttpListener? socket = HTTPManager.StartListening(Port, SSL); + HttpListener? socket = HTTPManager.StartListening(port, ssl); if (socket != null) { - HTTPListener instance = new(socket, Port); + HTTPListener instance = new(socket); Task t = Task.Run(async () => await HTTPManager.Receiving(instance)); return instance; } @@ -55,7 +52,27 @@ namespace Milimoe.FunGame.Core.Library.Common.Network public void Close() { - Instance?.Close(); + bool closing = true; + TaskUtility.NewTask(async () => + { + // 关闭所有 WebSocket 连接 + foreach (WebSocket socket in ClientSockets.Values) + { + if (socket.State == WebSocketState.Open) + { + // 安全关闭 WebSocket 连接 + await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "服务器正在关闭,断开连接!", CancellationToken.None); + } + } + ClientSockets.Clear(); + Instance?.Close(); + closing = true; + }); + while (closing) + { + if (!closing) break; + Thread.Sleep(100); + } } } } diff --git a/Library/Common/Network/ServerSocket.cs b/Library/Common/Network/ServerSocket.cs index 7c604b2..d5e86ae 100644 --- a/Library/Common/Network/ServerSocket.cs +++ b/Library/Common/Network/ServerSocket.cs @@ -10,10 +10,6 @@ namespace Milimoe.FunGame.Core.Library.Common.Network public System.Net.Sockets.Socket Instance { get; } public SocketRuntimeType Runtime => SocketRuntimeType.Server; public Guid Token { get; } = Guid.Empty; - public string ServerAddress { get; } = ""; - public int ServerPort { get; } = 0; - public string ServerName { get; } = ""; - public string ServerNotice { get; } = ""; public bool Connected => Instance != null && Instance.Connected; public List ClientList => OnlineClients.GetList(); public List UserList => OnlineUsers.GetList(); @@ -25,38 +21,38 @@ namespace Milimoe.FunGame.Core.Library.Common.Network private readonly ModelManager OnlineClients; private readonly ModelManager OnlineUsers; - private ServerSocket(System.Net.Sockets.Socket Instance, int ServerPort, int MaxConnection = 0) + private ServerSocket(System.Net.Sockets.Socket instance, int maxConnection = 0) { - this.Instance = Instance; - this.ServerPort = ServerPort; - if (MaxConnection <= 0) + Token = Guid.NewGuid(); + Instance = instance; + if (maxConnection <= 0) { OnlineClients = []; OnlineUsers = []; } else { - OnlineClients = new(MaxConnection); - OnlineUsers = new(MaxConnection); + OnlineClients = new(maxConnection); + OnlineUsers = new(maxConnection); } } - public static ServerSocket StartListening(int Port = 22222, int MaxConnection = 0) + public static ServerSocket StartListening(int port = 22222, int maxConnection = 0) { - if (MaxConnection <= 0) MaxConnection = SocketSet.MaxConnection_2C2G; - System.Net.Sockets.Socket? socket = SocketManager.StartListening(Port, MaxConnection); - if (socket != null) return new ServerSocket(socket, Port); + if (maxConnection <= 0) maxConnection = SocketSet.MaxConnection_2C2G; + System.Net.Sockets.Socket? socket = SocketManager.StartListening(port, maxConnection); + if (socket != null) return new ServerSocket(socket, port); else throw new SocketCreateListenException(); } - public ClientSocket Accept(Guid Token) + public static ClientSocket Accept(Guid token) { object[] result = SocketManager.Accept(); if (result != null && result.Length == 2) { - string ClientIP = (string)result[0]; - System.Net.Sockets.Socket Client = (System.Net.Sockets.Socket)result[1]; - return new ClientSocket(Client, ServerPort, ClientIP, ClientIP, Token); + string clientIP = (string)result[0]; + System.Net.Sockets.Socket client = (System.Net.Sockets.Socket)result[1]; + return new ClientSocket(client, clientIP, clientIP, token); } throw new SocketGetClientException(); } diff --git a/Library/Common/Network/Socket.cs b/Library/Common/Network/Socket.cs index a3a32b6..e769e5e 100644 --- a/Library/Common/Network/Socket.cs +++ b/Library/Common/Network/Socket.cs @@ -22,19 +22,19 @@ namespace Milimoe.FunGame.Core.Library.Common.Network private readonly HeartBeat HeartBeat; private bool _Receiving = false; - private Socket(System.Net.Sockets.Socket Instance, string ServerAddress, int ServerPort) + private Socket(System.Net.Sockets.Socket instance, string serverAddress, int serverPort) { - this.Instance = Instance; - this.ServerAddress = ServerAddress; - this.ServerPort = ServerPort; + this.Instance = instance; + this.ServerAddress = serverAddress; + this.ServerPort = serverPort; HeartBeat = new(this); HeartBeat.StartSendingHeartBeat(); } - public static Socket Connect(string Address, int Port = 22222) + public static Socket Connect(string address, int port = 22222) { - System.Net.Sockets.Socket? socket = SocketManager.Connect(Address, Port); - if (socket != null) return new Socket(socket, Address, Port); + System.Net.Sockets.Socket? socket = SocketManager.Connect(address, port); + if (socket != null) return new Socket(socket, address, port); else throw new ConnectFailedException(); } diff --git a/Library/Constant/ConstantSet.cs b/Library/Constant/ConstantSet.cs index f0abee3..9519dee 100644 --- a/Library/Constant/ConstantSet.cs +++ b/Library/Constant/ConstantSet.cs @@ -37,6 +37,7 @@ namespace Milimoe.FunGame.Core.Library.Constant public const string Socket = "Socket"; public const string Unknown = "Unknown"; public const string DataRequest = "DataRequest"; + public const string GamingRequest = "GamingRequest"; public const string Connect = "Connect"; public const string Disconnect = "Disconnect"; public const string System = "System"; diff --git a/Library/Constant/General.cs b/Library/Constant/General.cs index 4229a5f..6821e29 100644 --- a/Library/Constant/General.cs +++ b/Library/Constant/General.cs @@ -44,7 +44,7 @@ namespace Milimoe.FunGame.Core.Library.Constant /// 默认的时间格式 yyyy-MM-dd HH:mm:ss.fff /// public static string GeneralDateTimeFormat => "yyyy-MM-dd HH:mm:ss.fff"; - + /// /// yyyy年MM月dd日 HH:mm:ss /// diff --git a/Library/Constant/TypeEnum.cs b/Library/Constant/TypeEnum.cs index 4cb38b2..4090910 100644 --- a/Library/Constant/TypeEnum.cs +++ b/Library/Constant/TypeEnum.cs @@ -66,6 +66,7 @@ namespace Milimoe.FunGame.Core.Library.Constant { Unknown, DataRequest, + GamingRequest, Connect, Disconnect, System, @@ -217,7 +218,7 @@ namespace Milimoe.FunGame.Core.Library.Constant /// 无特殊效果 /// None, - + /// /// 这是来自装备的特效 /// @@ -844,4 +845,11 @@ namespace Milimoe.FunGame.Core.Library.Constant Plugin, GameModule } + + public enum SQLMode + { + None, + MySQL, + SQLite + } } diff --git a/Library/Exception/Exception.cs b/Library/Exception/Exception.cs index 4f283ea..1c7d0ba 100644 --- a/Library/Exception/Exception.cs +++ b/Library/Exception/Exception.cs @@ -165,8 +165,13 @@ public override string Message => "试图在不支持的类中创建数据请求 (#10033)"; } - public class AsyncRequestException : Exception + public class AsyncSendException : Exception { - public override string Message => "数据请求必须以异步方式发送 (#10034)"; + public override string Message => "必须以异步方式发送数据 (#10034)"; + } + + public class SQLServiceException : Exception + { + public override string Message => "SQL服务遇到错误,请检查SQL配置 (#10035)"; } } diff --git a/Model/Gaming.cs b/Model/Gaming.cs index e4dfd84..845aae9 100644 --- a/Model/Gaming.cs +++ b/Model/Gaming.cs @@ -1,5 +1,4 @@ -using System.Collections; -using Milimoe.FunGame.Core.Api.Utility; +using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Common.Event; @@ -51,10 +50,7 @@ namespace Milimoe.FunGame.Core.Model // 读取模组的依赖集合 module.GameModuleDepend.GetDependencies(loader); // 新建线程来启动模组的界面 - TaskUtility.NewTask(() => - { - module.StartUI(); - }); + TaskUtility.NewTask(() => module.StartUI()); // 启动模组主线程 module.StartGame(instance, args); return instance; @@ -67,7 +63,7 @@ namespace Milimoe.FunGame.Core.Model /// /// 消息类型 /// 接收到的数据 - public void GamingHandler(GamingType type, Hashtable data) + public void GamingHandler(GamingType type, Dictionary data) { switch (type) { @@ -137,102 +133,102 @@ namespace Milimoe.FunGame.Core.Model } } - private void Connect(Hashtable data) + private void Connect(Dictionary data) { GameModule.OnGamingConnectEvent(this, EventArgs, data); } - private void Disconnect(Hashtable data) + private void Disconnect(Dictionary data) { GameModule.OnGamingDisconnectEvent(this, EventArgs, data); } - private void Reconnect(Hashtable data) + private void Reconnect(Dictionary data) { GameModule.OnGamingReconnectEvent(this, EventArgs, data); } - private void BanCharacter(Hashtable data) + private void BanCharacter(Dictionary data) { GameModule.OnGamingBanCharacterEvent(this, EventArgs, data); } - private void PickCharacter(Hashtable data) + private void PickCharacter(Dictionary data) { GameModule.OnGamingPickCharacterEvent(this, EventArgs, data); } - private void Random(Hashtable data) + private void Random(Dictionary data) { GameModule.OnGamingRandomEvent(this, EventArgs, data); } - private void Round(Hashtable data) + private void Round(Dictionary data) { GameModule.OnGamingRoundEvent(this, EventArgs, data); } - private void LevelUp(Hashtable data) + private void LevelUp(Dictionary data) { GameModule.OnGamingLevelUpEvent(this, EventArgs, data); } - private void Move(Hashtable data) + private void Move(Dictionary data) { GameModule.OnGamingMoveEvent(this, EventArgs, data); } - private void Attack(Hashtable data) + private void Attack(Dictionary data) { GameModule.OnGamingAttackEvent(this, EventArgs, data); } - private void Skill(Hashtable data) + private void Skill(Dictionary data) { GameModule.OnGamingSkillEvent(this, EventArgs, data); } - private void Item(Hashtable data) + private void Item(Dictionary data) { GameModule.OnGamingItemEvent(this, EventArgs, data); } - private void Magic(Hashtable data) + private void Magic(Dictionary data) { GameModule.OnGamingMagicEvent(this, EventArgs, data); } - private void Buy(Hashtable data) + private void Buy(Dictionary data) { GameModule.OnGamingBuyEvent(this, EventArgs, data); } - private void SuperSkill(Hashtable data) + private void SuperSkill(Dictionary data) { GameModule.OnGamingSuperSkillEvent(this, EventArgs, data); } - private void Pause(Hashtable data) + private void Pause(Dictionary data) { GameModule.OnGamingPauseEvent(this, EventArgs, data); } - private void Unpause(Hashtable data) + private void Unpause(Dictionary data) { GameModule.OnGamingUnpauseEvent(this, EventArgs, data); } - private void Surrender(Hashtable data) + private void Surrender(Dictionary data) { GameModule.OnGamingSurrenderEvent(this, EventArgs, data); } - private void UpdateInfo(Hashtable data) + private void UpdateInfo(Dictionary data) { GameModule.OnGamingUpdateInfoEvent(this, EventArgs, data); } - private void Punish(Hashtable data) + private void Punish(Dictionary data) { GameModule.OnGamingPunishEvent(this, EventArgs, data); } diff --git a/Service/AddonManager.cs b/Service/AddonManager.cs index 62b86d8..21f453b 100644 --- a/Service/AddonManager.cs +++ b/Service/AddonManager.cs @@ -118,7 +118,6 @@ namespace Milimoe.FunGame.Core.Service /// /// 从modules目录加载所有适用于服务器的模组 /// - /// /// /// /// @@ -126,7 +125,7 @@ namespace Milimoe.FunGame.Core.Service /// /// /// - internal static Dictionary LoadGameModulesForServer(Dictionary modules, Dictionary servers, Dictionary characters, Dictionary skills, Dictionary items, Hashtable delegates, params object[] otherobjs) + internal static Dictionary LoadGameModulesForServer(Dictionary servers, Dictionary characters, Dictionary skills, Dictionary items, Hashtable delegates, params object[] otherobjs) { if (!Directory.Exists(ReflectionSet.GameModuleFolderPath)) return servers; @@ -140,19 +139,7 @@ namespace Milimoe.FunGame.Core.Service { bool isAdded = false; - if (type.IsSubclassOf(typeof(GameModule))) - { - isAdded = AddAddonInstances(type, modules, (instance) => - { - if (instance.Load(otherobjs)) - { - instance.Controller = new(instance, delegates); - return true; - } - return false; - }); - } - else if (type.IsSubclassOf(typeof(GameModuleServer))) + if (type.IsSubclassOf(typeof(GameModuleServer))) { isAdded = AddAddonInstances(type, servers, (instance) => { diff --git a/Service/HTTPManager.cs b/Service/HTTPManager.cs index 3ec263a..7e692a6 100644 --- a/Service/HTTPManager.cs +++ b/Service/HTTPManager.cs @@ -13,17 +13,17 @@ namespace Milimoe.FunGame.Core.Service internal static HttpListener? ServerSocket => _ServerSocket; private static HttpListener? _ServerSocket = null; - internal static HttpListener StartListening(int Port = 22227, bool SSL = false) + internal static HttpListener StartListening(int port = 22227, bool ssl = false) { HttpListener listener = new(); - listener.Prefixes.Add((SSL ? "https://" : "http://") + "localhost:" + Port + "/"); + listener.Prefixes.Add((ssl ? "https://" : "http://") + "localhost:" + port + "/ws"); listener.Start(); return listener; } - internal static async Task Connect(Uri uri) + internal static async Task Connect(Uri uri) { - ClientWebSocket socket = new(); + System.Net.WebSockets.ClientWebSocket socket = new(); await socket.ConnectAsync(uri, CancellationToken.None); if (socket.State == WebSocketState.Open) { @@ -32,7 +32,7 @@ namespace Milimoe.FunGame.Core.Service return null; } - internal static async Task Send(ClientWebSocket socket, SocketObject obj) + internal static async Task Send(System.Net.WebSockets.ClientWebSocket socket, SocketObject obj) { if (socket != null) { @@ -79,7 +79,7 @@ namespace Milimoe.FunGame.Core.Service HttpListenerContext context = await ServerSocket.GetContextAsync(); if (context.Request.IsWebSocketRequest) { - await AddClientWebSocket(listener, context); + TaskUtility.NewTask(async () => await AddClientWebSocket(listener, context)); } else { @@ -154,12 +154,19 @@ namespace Milimoe.FunGame.Core.Service listener.ClientSockets.TryAdd(token, socket); await Send(socket, sendobject); - while (!result.CloseStatus.HasValue) + while (socket.State == WebSocketState.Open) { try { buffer = new byte[General.SocketByteSize]; result = await socket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + + if (result.CloseStatus.HasValue) + { + await socket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + return; + } + msg = Encoding.UTF8.GetString(buffer).Replace("\0", "").Trim(); objs = await GetSocketObjects(socket, result, msg); foreach (SocketObject obj in objs) @@ -167,7 +174,7 @@ namespace Milimoe.FunGame.Core.Service sendobject = listener.SocketObject_Handler(obj); if (obj.SocketType == SocketMessageType.Disconnect) { - await socket.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, result.CloseStatusDescription, CancellationToken.None); + await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Disconnect received", CancellationToken.None); return; } await Send(socket, sendobject); @@ -175,8 +182,10 @@ namespace Milimoe.FunGame.Core.Service } catch (Exception e) { + // 处理其他异常 TXTHelper.AppendErrorLog(e.GetErrorInfo()); - await socket.CloseAsync(WebSocketCloseStatus.InternalServerError, result.CloseStatusDescription, CancellationToken.None); + await socket.CloseAsync(WebSocketCloseStatus.InternalServerError, "Server Error", CancellationToken.None); + return; } } } diff --git a/Service/JsonManager.cs b/Service/JsonManager.cs index c582ac7..a32c62e 100644 --- a/Service/JsonManager.cs +++ b/Service/JsonManager.cs @@ -138,6 +138,27 @@ namespace Milimoe.FunGame.Core.Service return default; } + /// + /// 反序列化Dictionary中Key对应的Json对象 + /// + /// + /// + /// + /// + internal static T? GetObject(Dictionary dict, string key) + { + if (dict.TryGetValue(key, out object? value)) + { + JsonElement? element = (JsonElement?)value; + if (element != null) + { + T? result = ((JsonElement)element).Deserialize(GeneralOptions); + return result; + } + } + return default; + } + /// /// 反序列化IEnumerable中的Json对象 /// @@ -205,6 +226,28 @@ namespace Milimoe.FunGame.Core.Service return default; } + /// + /// 反序列化Dictionary中Key对应的Json对象 + /// + /// + /// + /// + /// + /// + internal static T? GetObject(Dictionary dict, string key, JsonSerializerOptions options) + { + if (dict.TryGetValue(key, out object? value)) + { + JsonElement? element = (JsonElement?)value; + if (element != null) + { + T? result = ((JsonElement)element).Deserialize(options); + return result; + } + } + return default; + } + /// /// 反序列化多个Json对象 /// 注意必须是相同的Json对象才可以使用此方法解析 diff --git a/Service/SocketManager.cs b/Service/SocketManager.cs index 36aee0a..4bee11d 100644 --- a/Service/SocketManager.cs +++ b/Service/SocketManager.cs @@ -1,6 +1,8 @@ using System.Net; using System.Net.Sockets; +using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Library.Constant; +using Milimoe.FunGame.Core.Library.Exception; namespace Milimoe.FunGame.Core.Service { @@ -145,6 +147,25 @@ namespace Milimoe.FunGame.Core.Service return SocketResult.NotSent; } + /// + /// 用于服务器端向客户端Socket发送信息 [ 异步版 ] + /// + /// 客户端Socket + /// Socket信息容器 + /// 通信结果 + internal static async Task SendAsync(Socket ClientSocket, Library.Common.Network.SocketObject SocketObject) + { + if (ClientSocket != null) + { + if (await ClientSocket.SendAsync(General.DefaultEncoding.GetBytes(JsonManager.GetString(SocketObject))) > 0) + { + return SocketResult.Success; + } + else return SocketResult.Fail; + } + return SocketResult.NotSent; + } + /// /// 用于客户端向服务器Socket发送信息 /// @@ -163,6 +184,24 @@ namespace Milimoe.FunGame.Core.Service return SocketResult.NotSent; } + /// + /// 用于客户端向服务器Socket发送信息 [ 异步版 ] + /// + /// Socket信息容器 + /// 通信结果 + internal static async Task SendAsync(Library.Common.Network.SocketObject SocketObject) + { + if (Socket != null) + { + if (await Socket.SendAsync(General.DefaultEncoding.GetBytes(JsonManager.GetString(SocketObject))) > 0) + { + return SocketResult.Success; + } + else return SocketResult.Fail; + } + return SocketResult.NotSent; + } + /// /// 接收数据流中的信息 /// 如果是服务器接收信息需要传入客户端Socket @@ -171,54 +210,62 @@ namespace Milimoe.FunGame.Core.Service /// SocketObjects internal static Library.Common.Network.SocketObject[] Receive(Socket? ClientSocket = null) { - List result = []; - Socket? tempSocket = ClientSocket is null ? Socket : ClientSocket; - if (tempSocket != null) + try { - // 从服务器接收消息 - byte[] buffer = new byte[General.SocketByteSize]; - int length = tempSocket.Receive(buffer, buffer.Length, SocketFlags.None); - string msg = ""; - if (length > 0) + List result = []; + Socket? tempSocket = ClientSocket is null ? Socket : ClientSocket; + if (tempSocket != null) { - msg = General.DefaultEncoding.GetString(buffer, 0, length); - if (JsonManager.IsCompleteJson(msg)) + // 从服务器接收消息 + byte[] buffer = new byte[General.SocketByteSize]; + int length = tempSocket.Receive(buffer, buffer.Length, SocketFlags.None); + string msg = ""; + if (length > 0) { - foreach (Library.Common.Network.SocketObject obj in JsonManager.GetObjects(msg)) + msg = General.DefaultEncoding.GetString(buffer, 0, length); + if (JsonManager.IsCompleteJson(msg)) { - result.Add(obj); - // 客户端接收消息,广播ScoketObject到每个UIModel - if (ClientSocket is null) OnSocketReceive(obj); - } - return [.. result]; - } - else - { - Thread.Sleep(20); - while (true) - { - if (tempSocket.Available > 0) + foreach (Library.Common.Network.SocketObject obj in JsonManager.GetObjects(msg)) { - length = tempSocket.Receive(buffer, buffer.Length, SocketFlags.None); - msg += General.DefaultEncoding.GetString(buffer, 0, length); - if (JsonManager.IsCompleteJson(msg)) - { - break; - } - Thread.Sleep(20); + result.Add(obj); + // 客户端接收消息,广播ScoketObject到每个UIModel + if (ClientSocket is null) OnSocketReceive(obj); + } + return [.. result]; + } + else + { + Thread.Sleep(20); + while (true) + { + if (tempSocket.Available > 0) + { + length = tempSocket.Receive(buffer, buffer.Length, SocketFlags.None); + msg += General.DefaultEncoding.GetString(buffer, 0, length); + if (JsonManager.IsCompleteJson(msg)) + { + break; + } + Thread.Sleep(20); + } + else break; } - else break; } } + foreach (Library.Common.Network.SocketObject obj in JsonManager.GetObjects(msg)) + { + result.Add(obj); + // 客户端接收消息,广播ScoketObject到每个UIModel + if (ClientSocket is null) OnSocketReceive(obj); + } } - foreach (Library.Common.Network.SocketObject obj in JsonManager.GetObjects(msg)) - { - result.Add(obj); - // 客户端接收消息,广播ScoketObject到每个UIModel - if (ClientSocket is null) OnSocketReceive(obj); - } + return [.. result]; + } + catch (Exception e) + { + TXTHelper.AppendErrorLog(e.GetErrorInfo()); + return []; } - return [.. result]; } #endregion