/// <summary> /// 根据房间编号给房间内的客户端用户发底牌数据(只需在一局游戏中第一轮发) /// </summary> /// <param name="roomId"></param> public void GetTouchCardByRoomId(int roomId) { LogMessage.Instance.SetLogMessage("没发底牌之前剩余的牌数:" + this.resCards.Count.ToString()); RoomInfo tmpRoomInfo = GetRoomInfoByRoomId(roomId); if (tmpRoomInfo != null) //如果不为空的话 表示根据房间编号取到了对应的房间数据 { this.RecordsNumberByRoomId(roomId); //记录游戏次数 ClientPeer tmpClientPeer = null; //临时存储要发牌的客户端连接代码 //LogMessage.Instance.SetLogMessage("要发底牌的房间中的用户个数:" + tmpRoomInfo.UserInfos.Count.ToString()); foreach (UserInfo user in tmpRoomInfo.UserInfos) //循环遍历这个房间中的客户端用户列表 { //判断用户是否为空 if (user != null) //如果不为空,再进行具体的发牌细节处理 { tmpClientPeer = this.clientPeers.Find(clientPeer => clientPeer.ClientSocket == user.ClientUserSocket); //校验是不是同一个客户端连接对象 if (tmpClientPeer != null) //如果不为空 则表示是同一个客户端连接对象 { string tmpCardValue = this.GetRandomCard(); //随机取出一张牌(这张牌发给当前客户端对象) //根据房间编号和用户信息记录用户分数 this.SetUserScoreByRoomId(roomId, user, tmpCardValue, PasseServiceUserScoreCode.底牌); //这里需要发送两次消息(第一次是当前客户端自己的底牌数据,第二次是要给这个客户端发送一些假数据,表示是其他客户端对象的底牌数据) LogMessage.Instance.SetLogMessage("玩家[ " + tmpClientPeer.ClientSocket.RemoteEndPoint.ToString() + " ]发到的底牌-> " + tmpCardValue + "," + user.ClientIndex.ToString()); #region 给客户端对象发送消息 //第一次发消息: //给当前客户端对象先发一张自己的底牌 this.message.ChangeMessage(OperationCode.Service, (int)ServiceCode.Passe_Response, tmpCardValue + "," + user.ClientIndex.ToString()); tmpClientPeer.OnSendMessage(this.message); //发送真的底牌数据给客户端对象 //循环遍历所有客户端对象 找到不是当前发底牌的客户端对象 for (int clientPeerIndex = 0; clientPeerIndex < this.clientPeers.Count; clientPeerIndex++) { ClientPeer clientPeer = this.clientPeers[clientPeerIndex]; if (clientPeer != tmpClientPeer)//如果不是当前客户端对象 { //第二次发消息: //给当前抽到底牌的客户端对象发送假数据 this.message.ChangeMessage(OperationCode.Service, (int)ServiceCode.Passe_Response, "底牌" + "," + user.ClientIndex.ToString()); tmpClientPeer.OnSendMessage(this.message);//发送假的底牌数据给客户端对象 } } #endregion } } } } LogMessage.Instance.SetLogMessage("发了底牌之前剩余的牌数:" + this.resCards.Count.ToString()); }
}//房间聊天 #endregion #region 房间内消息广播 /// <summary> /// 处理广播消息 /// </summary> /// <param name="clientPeer"></param> /// <param name="roomId"></param> /// <param name="message"></param> private void ProcessBroadcastMessage(ClientPeer clientPeer, int roomId, SocketMessage message) { //在离开房间之前需要通知这个离开房间的客户端对象 clientPeer.OnSendMessage(message); //通过房间数据缓存对象根据指定房间编号进行房间内的消息广播,将网络消息发送给每一个房间内的客户端用户对象 this.roomCache.BroadcastMessageByRoomId(roomId, message); }//房间消息广播
/// <summary> /// 处理下注的业务请求 /// </summary> /// <param name="clientPeer">要进行下注的玩家</param> /// <param name="roomId">在哪个房间进行的下注</param> /// <param name="money">下了多少注</param> private void ProcessBottomPourRequest(ClientPeer clientPeer, int roomId, int money) { Console.WriteLine("接收到客户端发送过来的下注请求~"); bool isSuccess = this.userCache.SubMoney(clientPeer, money); //使用用户数据缓存对象减少玩家的钱数 if (isSuccess) //减少钱数成功了 { RoomInfo roomInfo = this.roomCache.GetRoomInfoByRoomId(roomId); //根据指定房间编号获取房间信息数据 //记录最后一个下注的玩家 if (!this.passeServiceCache.roomLastBottompourUserDict.ContainsKey(roomInfo)) { this.passeServiceCache.roomLastBottompourUserDict.Add(roomInfo, clientPeer); } else { this.passeServiceCache.roomLastBottompourUserDict[roomInfo] = clientPeer; } //Todo:给客户端发送消息 //通知客户端减少的钱数 UserInfo userInfo = this.roomCache.GetUserInfoByClientPeer(clientPeer);//根据客户端连接对象获取用户信息 //构造要发送给下注客户端的一条网络消息 //业务模块/帕斯响应码/下注响应码|下的注数,下注的玩家座位索引 SocketMessage message = new SocketMessage() { OperationCode = OperationCode.Service, SubOperationCode = (int)ServiceCode.Passe_BottomPourResponse, DataValue = money + "," + userInfo.ClientIndex.ToString()//发送的消息:下注响应码|减少的钱数,减少钱数的客户端座位号 }; Thread.Sleep(1000); //广播消息给每一个房间内的玩家 this.roomCache.BroadcastMessageByRoomId(roomId, message); //通知给房间内的每一个客户端对象,告知他们有玩家下注了. List <ClientPeer> clientPeers = this.roomCache.GetClientPeersByRoomId(roomId); //根据指定房间编号获取房间内的客户端连接对象列表 int tmpIndex = (clientPeers.FindIndex(client => client == clientPeer) + 1); //找出当前玩家的下一个玩家 通知他该跟注了 if (tmpIndex > clientPeers.Count - 1) { tmpIndex = clientPeers.Count - 1; } ClientPeer nextClientPeer = clientPeers[tmpIndex]; //判断当前玩家是否是最后一个玩家 如果是的话 需要给玩家列表中的第一个玩家发跟注释响应消息 if (nextClientPeer == clientPeers[clientPeers.Count - 1] && nextClientPeer == clientPeer) { nextClientPeer = clientPeers[0]; } else//不做任何处理 直接正常发送即可(这里表示当前玩家不是玩家列表中最后一个玩家) { } Thread.Sleep(1000); //将消息更改至跟注释的一条网络消息 //业务模块/帕斯响应码/跟牌响应码 message.ChangeMessage(OperationCode.Service, (int)ServiceCode.Passe_Response, (int)PasseGameCode.Follow_Response); nextClientPeer.OnSendMessage(message);//给下一个玩家发送跟注消息,提示他需要进行跟注 } else//减少钱数失败了 { //Todo:给客户端发送消息,告诉你钱不够了,不能进行下注了.... } }
/// <summary> /// 给指定的客户端发明牌 /// </summary> /// <param name="peer">分发明牌的指定客户端对象</param> /// <param name="roomId">该玩家所在的房间的房间编号</param> public void GetClearCardToClient(ClientPeer peer, int roomId) { RoomInfo roomInfo = this.roomCache.GetRoomInfoByRoomId(roomId);//根据指定房间编号获取房间数据 #region 这儿用来校验当前发起跟牌请求的时候玩家是否已经处于不跟牌数状态 foreach (KeyValuePair <RoomInfo, Dictionary <ClientPeer, bool> > roomItem in this.roomFollowcardUserDict) //循环遍历存储房间数据 和 房间内弃牌的玩家对象 数据字典 { foreach (KeyValuePair <ClientPeer, bool> clientItem in roomItem.Value) //循环遍历已经不跟牌的玩家对象列表 { if (clientItem.Key == peer && clientItem.Value == true) //如果在遍历的过程中 找到了引用相同的玩家对象(这里如果相同,表示玩家已经弃牌,不需要继续处理给这个玩家发牌了) { return; //直接return } } } #endregion #region 这儿用来校验当前发起跟牌请求的时候玩家是否已经处于弃牌状态 foreach (KeyValuePair <RoomInfo, List <ClientPeer> > item in this.roomDiscardDict) //循环遍历存储房间数据 和 房间内弃牌的玩家对象 数据字典 { for (int clientIndex = 0; clientIndex < item.Value.Count; clientIndex++) //循环遍历已经弃牌的玩家对象列表 { if (item.Value[clientIndex] == peer) //如果在遍历的过程中 找到了引用相同的玩家对象(这里如果相同,表示玩家已经弃牌,不需要继续处理给这个玩家发牌了) { return; //直接return } } } #endregion for (int userIndex = 0; userIndex < roomInfo.UserInfos.Count; userIndex++)//循环遍历房间内的玩家列表 直到找到要发明牌的客户端玩家对象为止 { UserInfo tmpUserInfo = roomInfo.UserInfos[userIndex]; if (tmpUserInfo.ClientUserSocket == peer.ClientSocket) //如果找到了 { string tmpCard = this.GetRandomCard(); //获取一张随机牌 LogMessage.Instance.SetLogMessage(peer.ClientSocket.RemoteEndPoint.ToString() + "得到的明牌:" + tmpCard); //构建网络消息给他发过去 this.message.ChangeMessage(OperationCode.Service, (int)ServiceCode.Passe_Response, tmpCard + "," + tmpUserInfo.ClientIndex); peer.OnSendMessage(this.message); //发送消息 break; //这儿使用break的原因是因为只需要给一个客户端对象发明牌就可以了,发完之后,需要跳出循环,完成一次发明牌的操作。 } } //判断存不存在这个房间信息 if (this.roomPlayCardIndexDict.ContainsKey(roomInfo))//存在重新赋值 { this.roomPlayCardIndexDict[roomInfo]++; } }
/// <summary> /// 游戏结束的逻辑处理 /// </summary> /// <param name="tmpRoomInfo">结束游戏的房间</param> /// <param name="userInfo">获胜的玩家对象</param> private void Gameover(RoomInfo tmpRoomInfo, UserInfo userInfo) { #region 推送比较后的消息结果 ClientPeer tmpClientPeer = this.roomCache.GetClientPeerByUserInfo(userInfo); //根据用户信息获取客户端连接对象 if (tmpClientPeer != null) //如果获取到了 { LogMessage.Instance.SetLogMessage(userInfo.UserName + " 取得了游戏胜利~"); //给获胜的玩家发送胜利消息 this.message.ChangeMessage(OperationCode.GameResult, (int)GameResultCode.Game_Success_Response, "你的分数最大,你胜利了~" + "," + userInfo.ClientIndex.ToString()); //消息格式:胜利|失败的消息,胜利的客户端索引 tmpClientPeer.OnSendMessage(this.message); //发送给这一局游戏胜利的玩家,通知他获取了这一局游戏的胜利 //给失败的玩家发送消息 this.message.ChangeMessage(OperationCode.GameResult, (int)GameResultCode.Game_Faild_Response, "你失败了~胜利的玩家是 [" + userInfo.ClientIndex.ToString() + "] ," + userInfo.ClientIndex.ToString()); //消息格式:胜利|失败的消息,胜利的客户端索引 this.roomCache.BroadCastMessageByExClient(tmpClientPeer, tmpRoomInfo.Id, this.message); //广播给所有失败的客户端对象,并通知他们哪个客户端这一局游戏获取了最终的胜利 } #endregion }
/// <summary> /// 通过房间进入码处理加入房间的业务请求 /// </summary> /// <param name="clientPeer">加入房间的客户端对象</param> /// <param name="roomEnterCode">要加入的房间进入码</param> private void ProcessJoinRoomRequestByRoomEnterCode(ClientPeer clientPeer, int roomEnterCode) { RoomInfo tmpRoom = this.roomCache.JoinRoomByRoomEnterCode(clientPeer, roomEnterCode); //获取要加入的房间 if (tmpRoom != null) { if (tmpRoom.RoomState == RoomState.Waiting) //如果房间处于等待状态 { this.ProcessJoinRoom(tmpRoom, clientPeer); //加入房间 } else//房间不处于等待状态中 不能加入 { this.message.ChangeMessage(OperationCode.Message, (int)MessageCode.SingleMessage, "房间已经满员,不能加入~"); clientPeer.OnSendMessage(this.message);//通知这个客户端对象,告诉它,房间已经满员了,不能进行加入. return; } } }
}//接收消息 #region 获取房间列表 /// <summary> /// 处理客户端对象获取房间列表的请求 /// </summary> /// <param name="clientPeer"></param> private void ProcessGetRoomListRequest(ClientPeer clientPeer) { if (clientPeer == null) { return; } List <RoomInfo> rooms = this.roomCache.Rooms; //取出所有房间 string roomData = string.Empty; //用于存储所有房间的数据 StringBuilder sb = new StringBuilder(); //用于房间数据之间的拼接工作 foreach (RoomInfo room in rooms) //遍历所有房间 { sb.Append(room.Id + "," + room.Name + "|"); //进行房间数据之间的拼接 } if (sb.Length > 0) { roomData = sb.ToString().Remove(sb.Length - 1, 1); } //拼接完成后,将数据发送给请求获取房间列表的客户端对象 message.ChangeMessage(OperationCode.Room, (int)RoomCode.GetRoomList_Response, roomData); clientPeer.OnSendMessage(message); }
/// <summary> /// 进入房间 /// </summary> /// <param name="clientPeer">进入房间的客户端对象</param> /// <param name="tmpRoom">要进入的房间</param> private void EnterRoom(ClientPeer clientPeer, RoomInfo tmpRoom) { tmpRoom.PersonNumber++;//累加房间人数 LogMessage.Instance.SetLogMessage( string.Format("客户端对象IP地址为 [ {0} ] 的用户加入了一个房间编号为 [ {1} ] 的房间,这个房间的进入码为 [ {2} ]~", clientPeer.ClientSocket.RemoteEndPoint.ToString(), tmpRoom.Id.ToString(), tmpRoom.EnterCode.ToString())); #region 构建要传输的数据房间对象并把客户端需要的数据发送过去 int currentClientIndex = this.roomCache.GetRoomClientIndexByRoomId(clientPeer, tmpRoom.Id); #region 通知客户端所在房间的座位号 //通知客户端 你所在的房间中的座位号是 clientPeer.OnSendMessage(new SocketMessage() { OperationCode = OperationCode.Message, SubOperationCode = (int)MessageCode.SingleMessage, DataValue = currentClientIndex.ToString() }); #endregion //构建房间信息传输数据对象(用于服务端把房间数据传输给客户端) RoomInfoDto roomInfoDto = new RoomInfoDto() { Id = tmpRoom.Id, Name = tmpRoom.Name, PersonNumber = tmpRoom.PersonNumber, ServiceType = (RoomInfoDto.RoomGameServiceType)tmpRoom.ServiceType }; //循环遍历房间内的客户端用户对象列表 for (int userIndex = 0; userIndex < tmpRoom.UserInfos.Count; userIndex++) { UserInfo userInfo = tmpRoom.UserInfos[userIndex]; //取得当前循环遍历到的客户端用户对象数据 //构建一个用户信息传输数据添加至房间信息数据传输对象的用户列表中 roomInfoDto.Users.Add(new UserInfoDto() { Id = userInfo.Id, UserName = userInfo.UserName, Money = userInfo.Money, ClientIndex = currentClientIndex, RoomId = tmpRoom.Id }); LogMessage.Instance.SetLogMessage(userInfo.Id.ToString()); } #endregion #region 构造网络消息对象 广播给房间内的每一个客户端对象 //构造服务端发送给客户端的网络消息对象 this.message.ChangeMessage(OperationCode.Room, (int)RoomCode.JoinRoom_Response, roomInfoDto); //通过房间数据缓存对象根据指定房间编号进行房间内的消息广播,将网络消息发送给每一个房间内的客户端用户对象 this.roomCache.BroadcastMessageByRoomId(tmpRoom.Id, this.message); #endregion #region 给房主广播一条空数据(没有实际作用,只是为了房主的数据同步工作,不会影响其他客户端对象) RoomInfo tmpRoomInfo = this.roomCache.RoomIdRooms[tmpRoom.Id]; //获取房间信息对象 List <ClientPeer> clients = this.roomCache.RoomClientsDict[tmpRoomInfo]; //通过房间信息对象获取该房间内的客户端用户列表 if (clients != null) //如果不为空的情况下 { //默认给房主发送一个null数据(之前不这样做,会导致房主的数据不进行同步处理,出现了Bug,之后这样做,竟然神奇地解决了) this.message.ChangeMessage(OperationCode.Service, (int)ServiceCode.Passe_Response, "null"); clients[0].OnSendMessage(this.message); } #endregion }
/// <summary> /// 处理客户端对象创建房间的请求 /// </summary> /// <param name="clientPeer">创建房间的客户端对象</param> /// <param name="createRoomData">客户端创建房间时传递过来的创建房间数据</param> private void ProcessCreateRoomRequest(ClientPeer clientPeer, object createRoomData = null) { RoomInfo newRoom = this.roomCache.CreateRoom(clientPeer); //通过房间数据缓存对象创建并返回一个新的房间信息对象 newRoom.PersonNumber++; //累加房间人数 int currentClientIndex = this.roomCache.GetRoomClientIndexByRoomId(clientPeer, newRoom.Id); //记录当前玩家所在的房间座位号 #region 构建一个新的用户对象[后期从存储用户的用户数据服务器中取出对应的玩家数据] UserInfo userInfo = new UserInfo() { UserName = clientPeer.ClientSocket.RemoteEndPoint.ToString(), RoomId = newRoom.Id, Money = 5000, ClientUserSocket = clientPeer.ClientSocket, ClientIndex = currentClientIndex }; this.userCache.AddUser(clientPeer, userInfo); //将构建好的用户对象保存起来 userInfo.Id = this.userCache.GetUserIdByUserInfo(userInfo); //设置用户编号 #endregion #region 将用户添加到房间内 //将用户对象添加到新房间的客户端用户列表中去 newRoom.UserInfos.Add(userInfo); #endregion #region 构建要传输的数据房间对象并把客户端需要的数据发送过去 //构建房间信息传输数据对象(用于服务端把房间数据传输给客户端) RoomInfoDto roomInfoDto = new RoomInfoDto() { Id = newRoom.Id, EnterCode = newRoom.EnterCode, Name = newRoom.Name, PersonNumber = newRoom.PersonNumber, ServiceType = (RoomInfoDto.RoomGameServiceType)Enum.Parse(typeof(GameServiceTypeCode), createRoomData.ToString()) }; #region 循环取出当前房间内的用户数据 //循环遍历房间内的客户端用户对象列表 for (int userIndex = 0; userIndex < newRoom.UserInfos.Count; userIndex++) { UserInfo tmpUserInfo = newRoom.UserInfos[userIndex];//取得当前循环遍历到的客户端用户对象数据 //构建一个用户信息传输数据添加至房间信息数据传输对象的用户列表中 roomInfoDto.Users.Add ( new UserInfoDto() { Id = tmpUserInfo.Id, UserName = tmpUserInfo.UserName, Money = tmpUserInfo.Money, ClientIndex = currentClientIndex, RoomId = newRoom.Id } ); } #region 通知客户端所在房间的座位号 //通知客户端 你所在的房间中的座位号是 this.message.ChangeMessage(OperationCode.Message, (int)MessageCode.SingleMessage, currentClientIndex.ToString()); clientPeer.OnSendMessage(this.message); #endregion #endregion #endregion #region 构建网络消息并发送给创建房间的客户端对象 //构造服务端发送给客户端的网络消息对象 this.message.ChangeMessage(OperationCode.Room, (int)RoomCode.CreateRoom_Response, roomInfoDto); clientPeer.OnSendMessage(this.message);//由于只有一个创建房间的客户端对象,所以直接给这一个客户端对象发送网络消息即可 #endregion LogMessage.Instance.SetLogMessage( string.Format("客户端对象唯一编号为 [ {0} ] 的用户创建了一个房间编号为 [ {1} ] 的新房间,这个房间的进入码为 [ {2} ]~", userInfo.Id.ToString(), newRoom.Id.ToString(), newRoom.EnterCode.ToString())); newRoom.RoomState = RoomState.Waiting;//将房间状态更改至等待中 #region 创建房间后的 [洗牌] 和 [发牌] 阶段 this.ProcessInitCreateRoomCardData(clientPeer, createRoomData, newRoom);//处理创建房间后需要做的一些初始化卡牌数据 #endregion }
/// <summary> /// 接收客户端发送过来的消息 /// </summary> /// <param name="clientPeer">发送消息的客户端对象</param> /// <param name="subOperationCode">发送给指定模块的子操作码</param> /// <param name="dataValue">消息附带的数据</param> public void OnReceiveMessage(ClientPeer clientPeer, int subOperationCode, object dataValue) { PasseGameCode passeGameCode = (PasseGameCode)Enum.Parse(typeof(PasseGameCode), subOperationCode.ToString()); switch (passeGameCode) { case PasseGameCode.Follow_Request: //处理跟的业务请求 { //判断客户端传递过来的房间编号值是否能够转换成功 if (int.TryParse(dataValue.ToString(), out int roomId)) //如果转换成功了 { this.ProcessFollowRequest(clientPeer, roomId); //处理跟牌 } } break; case PasseGameCode.NoFollow_Request: //处理不跟的业务请求 { //不跟 //判断客户端传递过来的房间编号值是否能够转换成功 if (int.TryParse(dataValue.ToString(), out int roomId)) //如果转换成功了 { this.ProcessNoFollowRequest(clientPeer, roomId); //处理不跟牌 } } break; case PasseGameCode.Play_Request: //处理踢的业务请求 { //解析客户端发送过来的踢牌的数据 //解析格式:房间编号,筹码(钱) string[] playDataSplit = dataValue.ToString().Split(','); string roomIdStr = playDataSplit[0]; //取出解析完毕的房间号 string moneyStr = playDataSplit[1]; //取出解析完毕要下注的筹码值 //判断客户端传递过来的房间编号值是否能够转换成功 if (int.TryParse(roomIdStr, out int roomId)) //如果转换成功了 { if (int.TryParse(moneyStr, out int money)) { this.ProcessPlayRequest(clientPeer, roomId, money); } } } break; case PasseGameCode.Discard_Request: //处理弃牌的业务请求 { //判断客户端传递过来的房间编号值是否能够转换成功 if (int.TryParse(dataValue.ToString(), out int roomId)) //如果转换成功了 { this.ProcessDiscardRequest(clientPeer, roomId); } } break; case PasseGameCode.DispalyFollow_Request: //处理显示跟的请求 SocketMessage message = new SocketMessage() { OperationCode = OperationCode.Service, SubOperationCode = (int)ServiceCode.Passe_BroadcastResponse, DataValue = "null" }; clientPeer.OnSendMessage(message); //给下注的客户端对象发送消息(通知下注玩家,准备开始下注) break; case PasseGameCode.BottomPour_Request: //处理下注的业务请求 { //判断客户端传递过来的下注的钱数值是否能够转换成功 //if (int.TryParse(dataValue.ToString(), out int money))//如果转换成功了 // this.ProcessBottomPourRequest(clientPeer, money);//处理下注 string[] roomDataSplits = dataValue.ToString().Split(','); //解析客户端传递过来的下注时的数据 string strRoomId = roomDataSplits[0]; //解析出来的房间编号 string strMoney = roomDataSplits[1]; //解析出来的玩家的下的注数 if (int.TryParse(strRoomId, out int roomId)) //判断房间编号是否可以转换成整数类型 { if (int.TryParse(strMoney, out int money)) //判断玩家下的注数是否可以转换成整数类型 { this.ProcessBottomPourRequest(clientPeer, roomId, money); //都转换成功了,处理客户端发送过来的下注业务请求 } } } break; } }
/// <summary> /// 根据房间编号比较房间内的客户端用户分数 /// </summary> /// <param name="roomId">要进行比较的房间</param> /// <param name="userScoreCode">用户分数码</param> public void CompleteUserScoreByRoomId(int roomId, PasseServiceUserScoreCode userScoreCode) { RoomInfo tmpRoomInfo = this.GetRoomInfoByRoomId(roomId); if (tmpRoomInfo != null) { UserInfo userInfo = null; //存储分数最大的玩家信息数据 int maxUserScore = int.MinValue; //存储最大分数 switch (userScoreCode) { case PasseServiceUserScoreCode.明牌: //仅处理比较明牌 { #region 记录玩家的明牌分数 //这里遍历明牌的玩家分数数据字典 foreach (KeyValuePair <UserInfo, int> userItem in this.roomUserClearCardScoreDict[tmpRoomInfo]) { int tmpUserScore = userItem.Value; userInfo = userItem.Key; //判断用户存不存在 if (!userScoreDict.ContainsKey(userInfo)) //不存在 { userScoreDict.Add(userInfo, tmpUserScore); //添加 } else //存在 { userScoreDict[userInfo] = tmpUserScore; //累加并重新赋值 } } #endregion } break; case PasseServiceUserScoreCode.底明牌: //处理比较底牌 + 明牌 { #region 记录玩家的底牌分数 //这里遍历底牌的玩家分数数据字典 foreach (KeyValuePair <UserInfo, int> userItem in this.roomUserTouchCardScoreDict[tmpRoomInfo]) { int tmpUserScore = userItem.Value; //取得当前遍历到的用户分数 userInfo = userItem.Key; //保存当前遍历到的用户 //判断用户存不存在 if (!userScoreDict.ContainsKey(userInfo)) //不存在 { userScoreDict.Add(userInfo, tmpUserScore); //添加 } else //存在 { userScoreDict[userInfo] = tmpUserScore; //累加并重新赋值 } } #endregion #region 记录玩家的明牌分数 //这里遍历明牌的玩家分数数据字典 foreach (KeyValuePair <UserInfo, int> userItem in this.roomUserClearCardScoreDict[tmpRoomInfo]) { int tmpUserScore = userItem.Value; userInfo = userItem.Key; //判断用户存不存在 if (!userScoreDict.ContainsKey(userInfo)) //不存在 { userScoreDict.Add(userInfo, tmpUserScore); //添加 } else //存在 { userScoreDict[userInfo] = tmpUserScore; //累加并重新赋值 } } #endregion } break; } #region 判断谁是最大分数玩家 //这里遍历存储用户分数的数据字典 foreach (KeyValuePair <UserInfo, int> userItem in userScoreDict) { int tmpScore = userItem.Value; //取得当前遍历到的玩家分数 if (tmpScore > maxUserScore) //如果大于最大分数 { maxUserScore = tmpScore; //设置最大分数 userInfo = userItem.Key; //设置最大分数的玩家 } } #endregion #region 记录最大分数的玩家 if (!this.roomUserMaxScoreDict.ContainsKey(tmpRoomInfo))//如果不存在房间这个键 { this.roomUserMaxScoreDict.Add(tmpRoomInfo, new Dictionary <UserInfo, int>() { { userInfo, maxUserScore } }); //添加 } else//存在 { this.roomUserMaxScoreDict[tmpRoomInfo][userInfo] = maxUserScore;//重新赋值 } #endregion #region 显示所有玩家的分数值 //这里循环遍历 底牌 或者 明牌的分数数据字典都可以,因为存储的玩家都是保持一致的 foreach (KeyValuePair <UserInfo, int> userItem in this.roomUserClearCardScoreDict[tmpRoomInfo]) { if (this.userScoreDict.ContainsKey(userItem.Key))//如果存储用户分数的数据字典中存在这个玩家 { LogMessage.Instance.SetLogMessage("玩家[ " + userItem.Key.UserName + " ] 当前一共获得了[ " + this.userScoreDict[userItem.Key] + " ]分数~"); } else { continue; } } #endregion #region 广播通知每一个客户端对象(告知他们谁的分数最大) //消息格式:前边是废话|最大分数,最大分数的玩家座位索引 string msg = "本轮游戏 [" + userInfo.UserName + "] 获得了胜利.|" + maxUserScore + "," + userInfo.ClientIndex; this.message.ChangeMessage(OperationCode.Service, (int)ServiceCode.Passe_GetMaxScoreResponse, msg); this.roomCache.BroadcastMessageByRoomId(tmpRoomInfo.Id, this.message); Thread.Sleep(1000); #endregion if (tmpRoomInfo.RoomState != RoomState.Ending) { #region 提示玩家下注 Thread.Sleep(1000); //Todo:这里提示玩家进行下注操作[客户端接收到下注响应之后,需要进行下注] this.message.ChangeMessage(OperationCode.Service, (int)ServiceCode.Passe_Response, (int)PasseGameCode.BottomPour_Response); ClientPeer maxScoreClinePeer = this.roomCache.GetClientPeerByUserInfo(userInfo); maxScoreClinePeer.OnSendMessage(this.message);//先告诉最大玩家下注 #endregion } else if (tmpRoomInfo.RoomState == RoomState.Ending && userScoreCode == PasseServiceUserScoreCode.底明牌) { //msg = "你获得了胜利"; //ClientPeer winClientpeer = this.roomCache.GetClientPeerByUserInfo(userInfo); //this.message.ChangeMessage(OperationCode.GameResult, (int)GameResultCode.Game_Success_Response, msg); //winClientpeer.OnSendMessage(this.message); ////给其他玩家广播消息 //msg = "你失败了,座位号为 [" + userInfo.ClientIndex + "] 获得了游戏胜利~"; //this.message.ChangeMessage(OperationCode.GameResult, (int)GameResultCode.Game_Faild_Response, msg); //this.roomCache.BroadCastMessageByExClient(winClientpeer, tmpRoomInfo.Id, this.message); this.Gameover(tmpRoomInfo, userInfo); } } }
/// <summary> /// 通过房间编号更改存储用户信息和用户是否跟牌的数据字典 /// </summary> /// <param name="roomId"></param> /// <param name="clients"></param> public void ChangeRoomFollowcardUserDictionaryByRoomId(int roomId, params ClientPeer[] clients) { RoomInfo tmpRoomInfo = this.GetRoomInfoByRoomId(roomId); //根据房间编号获取房间信息数据 if (tmpRoomInfo != null) //如果获取到了房间 { for (int clientIndex = 0; clientIndex < clients.Length; clientIndex++) //使用循环遍历新进房间来的用户 { if (!this.roomFollowcardUserDict[tmpRoomInfo].ContainsKey(clientPeers[clientIndex])) { this.roomFollowcardUserDict[tmpRoomInfo].Remove(clientPeers[clientIndex]); this.roomFollowcardUserDict[tmpRoomInfo].Add(clients[clientIndex], true);//将他们添加到数据字典中 } else { this.roomFollowcardUserDict[tmpRoomInfo][clientPeers[clientIndex]] = true; } } foreach (KeyValuePair <RoomInfo, Dictionary <ClientPeer, bool> > roomItem in this.roomFollowcardUserDict) { foreach (KeyValuePair <ClientPeer, bool> clientItem in roomItem.Value) { if (clientItem.Value == true) //如果等于true 就表示跟牌 { List <ClientPeer> clientPeers = this.roomCache.GetClientPeersByRoomId(roomId); //根据指定房间编号获取房间内的客户端连接对象列表 int tmpIndex = (clientPeers.FindIndex(client => client == clients[0]) + 1); //找出当前玩家的下一个玩家 通知他该跟注了 if (tmpIndex > clientPeers.Count - 1) { tmpIndex = 0; } ClientPeer nextClientPeer = clientPeers[tmpIndex]; ClientPeer peer = this.roomLastBottompourUserDict[tmpRoomInfo]; if (nextClientPeer != peer) { //业务模块/帕斯响应码/跟牌响应码 message.ChangeMessage(OperationCode.Service, (int)ServiceCode.Passe_Response, (int)PasseGameCode.Follow_Response); nextClientPeer.OnSendMessage(message);//给下一个玩家发送跟注消息,提示他需要进行跟注 } else { LogMessage.Instance.SetLogMessage("跟牌的玩家个数和玩家出牌的索引值一致,开始进行下一轮发牌的工作~"); //Todo:再发一轮明牌 //Todo:下完注之后给这个玩家发牌 ClientPeer clientPeer = null; foreach (KeyValuePair <UserInfo, int> user in this.roomUserMaxScoreDict[tmpRoomInfo]) { clientPeer = this.roomCache.GetClientPeerByUserInfo(user.Key);//根据用户信息获取连接对象[这个对象就是本轮获胜者] break; } if (clientPeer != null) { this.GetClearCardByRoomId(tmpRoomInfo.Id); break; } } } else//如果不等于true 就表示不跟牌 { continue;//直接使用continue 关键字 终止本次循环 开始下次循环 } } break; } } }