diff --git a/Interface/Base/ISocketListener.cs b/Interface/Base/ISocketListener.cs index 13db755..140a1de 100644 --- a/Interface/Base/ISocketListener.cs +++ b/Interface/Base/ISocketListener.cs @@ -1,4 +1,6 @@ -using Milimoe.FunGame.Core.Api.Utility; +using System.Collections.Concurrent; +using Milimoe.FunGame.Core.Api.Utility; +using Milimoe.FunGame.Core.Library.Common.Addon; namespace Milimoe.FunGame.Core.Interface.Base { @@ -15,10 +17,15 @@ namespace Milimoe.FunGame.Core.Interface.Base public ConcurrentModelList ClientList { get; } /// - /// 已登录的用户列表 + /// 已登录的用户列表 /// public ConcurrentModelList UserList { get; } + /// + /// 记录玩家与正在游戏的服务器 + /// + public ConcurrentDictionary NowGamingServers { get; } + /// /// 黑名单IP地址列表 /// diff --git a/Library/Common/Addon/Example/ExampleGameModule.cs b/Library/Common/Addon/Example/ExampleGameModule.cs index 88a0b04..defc09f 100644 --- a/Library/Common/Addon/Example/ExampleGameModule.cs +++ b/Library/Common/Addon/Example/ExampleGameModule.cs @@ -277,7 +277,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example Workers.Remove(obj.Room.Roomid, out _); } - private async Task WaitForUsers(int waitSeconds, Func> waitSomething, int delay, Func onTimeout, Func onCompleted) + protected override async Task WaitForUsers(int waitSeconds, Func> waitSomething, int delay, Func onTimeout, Func onCompleted) { // 这是一个用于等待的通用辅助方法 using CancellationTokenSource cts = new(TimeSpan.FromSeconds(waitSeconds)); @@ -433,7 +433,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example hp.TryAdd(c, Calculation.Round4Digits(c.HP / c.MaxHP)); } double maxhp = hp.Values.Max(); - Character winner = hp.Keys.Where(c => hp[c] == maxhp).First(); + Character winner = hp.Keys.First(c => hp[c] == maxhp); await SendAllTextMessage(obj, "[ " + winner + " ] 成为了天选之人!!"); foreach (Character c in finalList.Where(c => c != winner && c.HP > 0)) { diff --git a/Library/Common/Addon/GameModuleServer.cs b/Library/Common/Addon/GameModuleServer.cs index 379d6c0..f8cf9c0 100644 --- a/Library/Common/Addon/GameModuleServer.cs +++ b/Library/Common/Addon/GameModuleServer.cs @@ -1,6 +1,7 @@ using System.Collections.Concurrent; using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Controller; +using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Interface.Addons; using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Library.Common.Event; @@ -198,6 +199,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon /// public virtual async void SendEndGame(GamingObject obj) { + obj.Running = false; GamingObjects.TryRemove(obj.Room.Roomid, out _); await Send(obj.All.Values, SocketMessageType.EndGame, obj.Room, obj.Users); foreach (IServerModel model in obj.All.Values) @@ -206,6 +208,66 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon } } + /// + /// 获取玩家所在的游戏对象 + /// + /// + /// + public GamingObject? GetGamingObjectOfUser(long id) + { + GamingObject? obj = GamingObjects.Values.FirstOrDefault(obj => obj.HasUser(id)); + return obj; + } + + /// + /// 获取玩家所在的房间 + /// + /// + /// + /// + public Room GetRoomOfUser(long id, GamingObject? obj = null) + { + obj ??= GamingObjects.Values.FirstOrDefault(obj => obj.HasUser(id)); + return obj?.Room ?? Room.Empty; + } + + /// + /// 这是一个用于等待的通用辅助方法 + /// + /// 等待时间(秒) + /// 等待的条件 + /// 检查间隔(毫秒) + /// 任务超时则... + /// 任务完成则... + /// + protected virtual async Task WaitForUsers(int waitSeconds, Func> waitSomething, int delay, Func onTimeout, Func onCompleted) + { + using CancellationTokenSource cts = new(TimeSpan.FromSeconds(waitSeconds)); + CancellationToken ct = cts.Token; + + while (!ct.IsCancellationRequested) + { + try + { + if (await waitSomething()) + { + await onCompleted(); + return; + } + await Task.Delay(delay, ct); + } + catch (System.Exception e) when (e is not OperationCanceledException) + { + Controller.Error(e); + await onTimeout(); + return; + } + } + + // 异常和超时都走超时逻辑 + await onTimeout(); + } + /// /// 给客户端发送局内消息 /// diff --git a/Library/Common/Addon/GamingObject.cs b/Library/Common/Addon/GamingObject.cs index 2067c83..401a050 100644 --- a/Library/Common/Addon/GamingObject.cs +++ b/Library/Common/Addon/GamingObject.cs @@ -3,11 +3,23 @@ using Milimoe.FunGame.Core.Interface.Base; namespace Milimoe.FunGame.Core.Library.Common.Addon { - public readonly struct GamingObject(Room room, List users, IServerModel roomMaster, Dictionary serverModels) + public class GamingObject(Room room, List users, IServerModel roomMaster, Dictionary serverModels) { + public bool Running { get; set; } = true; public Room Room { get; } = room; public List Users { get; } = users; public IServerModel RoomMaster { get; } = roomMaster; public Dictionary All { get; } = serverModels; + + public bool HasUser(long id) + { + return Users.Any(u => u.Id == id); + } + + public void UserReconnect(User newUser) + { + Users.RemoveAll(u => u.Id == newUser.Id); + Users.Add(newUser); + } } } diff --git a/Library/Common/Network/HTTPListener.cs b/Library/Common/Network/HTTPListener.cs index 607688a..9083fde 100644 --- a/Library/Common/Network/HTTPListener.cs +++ b/Library/Common/Network/HTTPListener.cs @@ -1,8 +1,10 @@ -using System.Net; +using System.Collections.Concurrent; +using System.Net; using System.Net.WebSockets; using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.HTTP; +using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Service; @@ -16,6 +18,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Network public Guid Token { get; } = Guid.Empty; public ConcurrentModelList ClientList { get; } = []; public ConcurrentModelList UserList { get; } = []; + public ConcurrentDictionary NowGamingServers { get; } = []; public List BannedList { get; } = []; private HTTPListener(HttpListener instance) diff --git a/Library/Common/Network/SocketListener.cs b/Library/Common/Network/SocketListener.cs index d5bc88d..1c0a285 100644 --- a/Library/Common/Network/SocketListener.cs +++ b/Library/Common/Network/SocketListener.cs @@ -1,6 +1,8 @@ -using Milimoe.FunGame.Core.Api.Utility; +using System.Collections.Concurrent; +using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Sockets; +using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Service; @@ -15,6 +17,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Network public bool Connected => Instance != null && Instance.Connected; public ConcurrentModelList ClientList { get; } = []; public ConcurrentModelList UserList { get; } = []; + public ConcurrentDictionary NowGamingServers { get; } = []; public List BannedList { get; } = []; private SocketListener(System.Net.Sockets.Socket instance) diff --git a/Library/Constant/ConstantSet.cs b/Library/Constant/ConstantSet.cs index 380ead5..d95a2c7 100644 --- a/Library/Constant/ConstantSet.cs +++ b/Library/Constant/ConstantSet.cs @@ -127,6 +127,7 @@ namespace Milimoe.FunGame.Core.Library.Constant public const string EndGame = "EndGame"; public const string Gaming = "Gaming"; public const string AnonymousGameServer = "AnonymousGameServer"; + public const string ReconnectToGame = "ReconnectToGame"; /// /// 将通信类型的枚举转换为字符串 diff --git a/Library/Constant/TypeEnum.cs b/Library/Constant/TypeEnum.cs index 7e27f4e..549c091 100644 --- a/Library/Constant/TypeEnum.cs +++ b/Library/Constant/TypeEnum.cs @@ -78,7 +78,8 @@ namespace Milimoe.FunGame.Core.Library.Constant StartGame, EndGame, Gaming, - AnonymousGameServer + AnonymousGameServer, + ReconnectToGame } ///