mirror of
https://github.com/project-redbud/FunGame-Core.git
synced 2025-04-22 03:59:35 +08:00
parent
f41361289c
commit
7561c2c7e2
@ -1,12 +1,12 @@
|
|||||||
using Milimoe.FunGame.Core.Entity;
|
using Milimoe.FunGame.Core.Interface.Base;
|
||||||
using Milimoe.FunGame.Core.Interface.Base;
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Interface.Addons
|
namespace Milimoe.FunGame.Core.Interface.Addons
|
||||||
{
|
{
|
||||||
public interface IGameModuleServer : IAddon, IAddonController<IGameModuleServer>, IGameModuleDepend
|
public interface IGameModuleServer : IAddon, IAddonController<IGameModuleServer>, IGameModuleDepend
|
||||||
{
|
{
|
||||||
public bool StartServer(string GameModule, Room Room, List<User> Users, IServerModel RoomMasterServerModel, Dictionary<string, IServerModel> ServerModels, params object[] args);
|
public bool StartServer(GamingObject obj, params object[] args);
|
||||||
|
|
||||||
public Task<Dictionary<string, object>> GamingMessageHandler(IServerModel model, GamingType type, Dictionary<string, object> data);
|
public Task<Dictionary<string, object>> GamingMessageHandler(IServerModel model, GamingType type, Dictionary<string, object> data);
|
||||||
}
|
}
|
||||||
|
@ -129,31 +129,31 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
|
|
||||||
public override GameModuleDepend GameModuleDepend => ExampleGameModuleConstant.GameModuleDepend;
|
public override GameModuleDepend GameModuleDepend => ExampleGameModuleConstant.GameModuleDepend;
|
||||||
|
|
||||||
private readonly struct ModuleServerWorker(Room room, List<User> users, IServerModel roomMaster, Dictionary<string, IServerModel> serverModels)
|
/// <summary>
|
||||||
|
/// 创建一个工作类,接收服务器启动参数的同时,还能定义一些需要的属性
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
private readonly struct ModuleServerWorker(GamingObject obj)
|
||||||
{
|
{
|
||||||
public Room Room { get; } = room;
|
public GamingObject GamingObject { get; } = obj;
|
||||||
public List<User> Users { get; } = users;
|
|
||||||
public IServerModel RoomMaster { get; } = roomMaster;
|
|
||||||
public Dictionary<string, IServerModel> All { get; } = serverModels;
|
|
||||||
public List<User> ConnectedUser { get; } = [];
|
public List<User> ConnectedUser { get; } = [];
|
||||||
public Dictionary<string, Dictionary<string, object>> UserData { get; } = [];
|
public Dictionary<string, Dictionary<string, object>> UserData { get; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConcurrentDictionary<string, ModuleServerWorker> Workers { get; } = [];
|
private ConcurrentDictionary<string, ModuleServerWorker> Workers { get; } = [];
|
||||||
|
|
||||||
public override bool StartServer(string GameModule, Room Room, List<User> Users, IServerModel RoomMasterServerModel, Dictionary<string, IServerModel> ServerModels, params object[] Args)
|
public override bool StartServer(GamingObject obj, params object[] args)
|
||||||
{
|
{
|
||||||
// 因为模组是单例的,需要为这个房间创建一个工作类接收参数,不能直接用本地变量处理
|
// 因为模组是单例的,需要为这个房间创建一个工作类接收参数,不能直接用本地变量处理
|
||||||
ModuleServerWorker worker = new(Room, Users, RoomMasterServerModel, ServerModels);
|
ModuleServerWorker worker = new(obj);
|
||||||
Workers[Room.Roomid] = worker;
|
// 创建一个线程执行Test(),因为这个方法必须立即返回
|
||||||
// 创建一个线程执行Test()
|
TaskUtility.NewTask(async () => await Test(obj, worker)).OnError(Controller.Error);
|
||||||
TaskUtility.NewTask(async () => await Test(worker)).OnError(Controller.Error);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Test(ModuleServerWorker worker)
|
private async Task Test(GamingObject obj, ModuleServerWorker worker)
|
||||||
{
|
{
|
||||||
Controller.WriteLine("欢迎各位玩家进入房间 " + worker.Room.Roomid + " 。");
|
Controller.WriteLine("欢迎各位玩家进入房间 " + obj.Room.Roomid + " 。");
|
||||||
|
|
||||||
// 通常,我们可以对客户端的连接状态进行确认,此方法展示如何确认客户端的连接
|
// 通常,我们可以对客户端的连接状态进行确认,此方法展示如何确认客户端的连接
|
||||||
// 有两种确认的方式,1是服务器主动确认,2是客户端发起确认
|
// 有两种确认的方式,1是服务器主动确认,2是客户端发起确认
|
||||||
@ -168,7 +168,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
data.Add("connect_token", token);
|
data.Add("connect_token", token);
|
||||||
|
|
||||||
// 我们保存到字典UserData中,这样可以方便跨方法检查变量
|
// 我们保存到字典UserData中,这样可以方便跨方法检查变量
|
||||||
foreach (string username in worker.Users.Select(u => u.Username).Distinct())
|
foreach (string username in obj.Users.Select(u => u.Username).Distinct())
|
||||||
{
|
{
|
||||||
if (worker.UserData.TryGetValue(username, out Dictionary<string, object>? value))
|
if (worker.UserData.TryGetValue(username, out Dictionary<string, object>? value))
|
||||||
{
|
{
|
||||||
@ -180,16 +180,51 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
worker.UserData[username].Add("connect_token", token);
|
worker.UserData[username].Add("connect_token", token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await SendGamingMessage(worker.All.Values, GamingType.UpdateInfo, data);
|
await SendGamingMessage(obj.All.Values, GamingType.UpdateInfo, data);
|
||||||
|
|
||||||
// 新建一个线程等待所有玩家确认
|
// 新建一个线程等待所有玩家确认,如果超时则取消游戏,30秒
|
||||||
while (true)
|
CancellationTokenSource cts = new();
|
||||||
|
CancellationToken ct = cts.Token;
|
||||||
|
Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(30), ct);
|
||||||
|
|
||||||
|
Task completionTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (worker.ConnectedUser.Count == worker.Users.Count) break;
|
while (!ct.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
if (worker.ConnectedUser.Count == obj.Users.Count)
|
||||||
|
{
|
||||||
|
Controller.WriteLine("所有玩家都已经连接。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 每200ms确认一次,不需要太频繁
|
// 每200ms确认一次,不需要太频繁
|
||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
}
|
}
|
||||||
Controller.WriteLine("所有玩家都已经连接。");
|
}, ct);
|
||||||
|
|
||||||
|
// 等待完成或超时
|
||||||
|
Task completedTask = await Task.WhenAny(completionTask, timeoutTask);
|
||||||
|
|
||||||
|
if (completedTask == timeoutTask)
|
||||||
|
{
|
||||||
|
Controller.WriteLine("等待玩家连接超时,放弃该局游戏!", LogLevel.Warning);
|
||||||
|
cts.Cancel();
|
||||||
|
|
||||||
|
// 通知已连接的玩家
|
||||||
|
Dictionary<string, object> timeoutData = new()
|
||||||
|
{
|
||||||
|
{ "msg", "由于等待超时,游戏已取消!" }
|
||||||
|
};
|
||||||
|
// 结束
|
||||||
|
SendEndGame(obj);
|
||||||
|
worker.ConnectedUser.Clear();
|
||||||
|
Workers.Remove(obj.Room.Roomid, out _);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
cts.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<Dictionary<string, object>> GamingMessageHandler(IServerModel model, GamingType type, Dictionary<string, object> data)
|
public override async Task<Dictionary<string, object>> GamingMessageHandler(IServerModel model, GamingType type, Dictionary<string, object> data)
|
||||||
@ -197,6 +232,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
Dictionary<string, object> result = [];
|
Dictionary<string, object> result = [];
|
||||||
// 获取model所在的房间工作类
|
// 获取model所在的房间工作类
|
||||||
ModuleServerWorker worker = Workers[model.InRoom.Roomid];
|
ModuleServerWorker worker = Workers[model.InRoom.Roomid];
|
||||||
|
GamingObject obj = worker.GamingObject;
|
||||||
string username = model.User.Username;
|
string username = model.User.Username;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
@ -208,7 +244,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
Guid token = NetworkUtility.JsonDeserializeFromDictionary<Guid>(data, "connect_token");
|
Guid token = NetworkUtility.JsonDeserializeFromDictionary<Guid>(data, "connect_token");
|
||||||
if (un == username && worker.UserData.TryGetValue(username, out Dictionary<string, object>? value) && value != null && (value["connect_token"]?.Equals(token) ?? false))
|
if (un == username && worker.UserData.TryGetValue(username, out Dictionary<string, object>? value) && value != null && (value["connect_token"]?.Equals(token) ?? false))
|
||||||
{
|
{
|
||||||
worker.ConnectedUser.Add(worker.Users.Where(u => u.Username == username).First());
|
worker.ConnectedUser.Add(obj.Users.Where(u => u.Username == username).First());
|
||||||
Controller.WriteLine(username + " 已经连接。");
|
Controller.WriteLine(username + " 已经连接。");
|
||||||
}
|
}
|
||||||
else Controller.WriteLine(username + " 确认连接失败!", LogLevel.Warning);
|
else Controller.WriteLine(username + " 确认连接失败!", LogLevel.Warning);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
using Milimoe.FunGame.Core.Controller;
|
using Milimoe.FunGame.Core.Controller;
|
||||||
using Milimoe.FunGame.Core.Entity;
|
|
||||||
using Milimoe.FunGame.Core.Interface.Addons;
|
using Milimoe.FunGame.Core.Interface.Addons;
|
||||||
using Milimoe.FunGame.Core.Interface.Base;
|
using Milimoe.FunGame.Core.Interface.Base;
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
@ -68,16 +68,17 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
private ServerAddonController<IGameModuleServer>? _Controller;
|
private ServerAddonController<IGameModuleServer>? _Controller;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启动服务器监听 请在此处实现服务器逻辑
|
/// 此模组所有正在运行的游戏对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="GameModule"></param>
|
public ConcurrentDictionary<string, GamingObject> GamingObjects { get; } = [];
|
||||||
/// <param name="Room"></param>
|
|
||||||
/// <param name="Users"></param>
|
/// <summary>
|
||||||
/// <param name="RoomMasterServerModel"></param>
|
/// 启动服务器监听 请在此处实现服务器逻辑。注意,此方法必须立即返回
|
||||||
/// <param name="ServerModels"></param>
|
/// </summary>
|
||||||
/// <param name="Args"></param>
|
/// <param name="obj"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract bool StartServer(string GameModule, Room Room, List<User> Users, IServerModel RoomMasterServerModel, Dictionary<string, IServerModel> ServerModels, params object[] Args);
|
public abstract bool StartServer(GamingObject obj, params object[] args);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 接收并处理GamingMessage
|
/// 接收并处理GamingMessage
|
||||||
@ -162,6 +163,20 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 给所有客户端发送游戏结束通知
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
public virtual async void SendEndGame(GamingObject obj)
|
||||||
|
{
|
||||||
|
GamingObjects.TryRemove(obj.Room.Roomid, out _);
|
||||||
|
await Send(obj.All.Values, SocketMessageType.EndGame, obj.Room, obj.Users);
|
||||||
|
foreach (IServerModel model in obj.All.Values)
|
||||||
|
{
|
||||||
|
model.NowGamingServer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 给客户端发送局内消息
|
/// 给客户端发送局内消息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
13
Library/Common/Addon/GamingObject.cs
Normal file
13
Library/Common/Addon/GamingObject.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Interface.Base;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Library.Common.Addon
|
||||||
|
{
|
||||||
|
public readonly struct GamingObject(Room room, List<User> users, IServerModel roomMaster, Dictionary<string, IServerModel> serverModels)
|
||||||
|
{
|
||||||
|
public Room Room { get; } = room;
|
||||||
|
public List<User> Users { get; } = users;
|
||||||
|
public IServerModel RoomMaster { get; } = roomMaster;
|
||||||
|
public Dictionary<string, IServerModel> All { get; } = serverModels;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user