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

 

posted @   Domefy  阅读(37)  评论(0编辑  收藏  举报
编辑推荐:
· 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#获取程序所在的路径
点击右上角即可分享
微信分享提示