任务39:牌局结束清理房间与更新房间、gamer状态
牌局结束时,有如下两种情况:
- 如果无人继续新的牌局,在服务端清除玩家与房间数据,通知房间内玩家前端退出房间
- 如果有人继续新的牌局,修改玩家匹配状态与更改房间状态为空闲房间,通知房间内玩家前端有玩家退出房间
服务端GameControllerComponentSystem的修改
\Server\Hotfix\Landlords\System\GameControllerComponentSystem.cs
- 如果前端有玩家继续匹配新的牌局,取消房间等待
- 如果2分钟没有一个玩家继续新的牌局,清除玩家与房间
GameOver方法中添加清除房间玩家与房间等待逻辑
/// <summary> /// 游戏结束 /// </summary> /// <param name="self"></param> public static async void GameOver(this GameControllerComponent self, List<GamerScore> gamersScore, Identity winnerIdentity) { Room room = self.GetParent<Room>(); Gamer[] gamers = room.gamers; //清理所有卡牌 self.BackToDeck(); room.GetComponent<DeskCardsCacheComponent>().Clear(); Dictionary<long, long> gamersMoney = new Dictionary<long, long>(); foreach (GamerScore gamerScore in gamersScore) { //结算玩家余额 Gamer gamer = room.GetGamerFromUserID(gamerScore.UserID); long gamerMoney = await self.StatisticalIntegral(gamer, gamerScore.Score); gamersMoney[gamer.UserID] = gamerMoney; } //广播游戏结束消息 room.Broadcast(new Actor_Gameover_Ntt() { Winner = (byte)winnerIdentity, BasePointPerMatch = self.BasePointPerMatch, Multiples = self.Multiples, GamersScore = To.RepeatedField(gamersScore) }); //清理房间玩家 LandMatchComponent Match = Game.Scene.GetComponent<LandMatchComponent>(); foreach (var _gamer in gamers) { //踢出离线玩家 if (_gamer.isOffline) { Match.Playing.Remove(_gamer.UserID); _gamer.Dispose(); } //踢出余额不足玩家 else if (gamersMoney[_gamer.UserID] < self.MinThreshold) { //... }else{ //修改玩家匹配状态 Match.Playing.Remove(_gamer.UserID); Match.Waiting.Add(_gamer.UserID, room); } } GameoverRoomWaiting(room).Coroutine(); }
GameControllerComponentSystem添加游戏结束房间等待协程
/// <summary> /// 游戏结束房间等待 /// </summary> public static async ETVoid GameoverRoomWaiting(Room room){ //只处理两种情况:1 有玩家选择继续;2 等待两分钟,无玩家继续 LandMatchComponent Match = Game.Scene.GetComponent<LandMatchComponent>(); //更改房间状态为空闲房间 Match.GamingLandlordsRooms.Remove(room.Id); Match.FreeLandlordsRooms.Add(room.Id, room); //有玩家继续,通过room的cts取消清房waiting,保留房间 //玩家继续的handler中调用room.CancellationTokenSource?.Cancel(); //等待2分钟,无玩家继续,清除玩家与房间 TimerComponent timer = Game.Scene.GetComponent<TimerComponent>(); room.CancellationTokenSource = new CancellationTokenSource(); await timer.WaitAsync(120000,room.CancellationTokenSource.Token); //广播消息给房间内玩家客户端通知房间清除返回大厅界面 //... room.CancellationTokenSource.Dispose(); room.CancellationTokenSource = null; room.ClearRoom(); }
服务端RoomSystem添加ClearRoom方法
\Server\Hotfix\Landlords\System\RoomSystem.cs
public static void ClearRoom(this Room self){ LandMatchComponent Match = Game.Scene.GetComponent<LandMatchComponent>(); for(int i=0;i<self.gamers.Length;i++) { Gamer gamer = self.gamers[i]; Match.Playing.Remove(gamer.UserID); gamer.Dispose(); self.Dispose(); } }
Room实体中添加清房间waiting的cts属性
\Server\ET.Core\Landlords\Entity\Map\Room.cs
//清房间waiting的cts public CancellationTokenSource CancellationTokenSource;
扩展知识:
前面代码,我们看到游戏结束时,挂起了2分钟等待,看有没有玩家要继续游戏。
await timer.WaitAsync(120000,room.CancellationTokenSource.Token);
在这里把CancellationTokenSource.Token作为WaitAsync的参数,这样当前端发请求到房间要继续游戏,请求的handler中就可以执行
room.CancellationTokenSource?.Cancel(),来取消挂起的线程。
TimerComponent组件 https://www.cnblogs.com/cnxkey/articles/9743882.html
C# TaskCompletionSource https://www.cnblogs.com/kybs0/p/11143858.html
C# CancellationTokenSource https://blog.csdn.net/chenweicode/article/details/90904438
课堂练习:
清理房间玩家逻辑中有踢除余额不足玩家,需要大家自己尝试实现
1、房间移除此玩家,匹配中的Playing移除此玩家
2、通知余额不足玩家,发消息到此玩家客户端退出房间
3、广播消息给房间内玩家客户端通知房间清除返回大厅界面
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
2022-02-21 C#获取程序所在的路径