任务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、广播消息给房间内玩家客户端通知房间清除返回大厅界面