private void OnReceive(IAsyncResult ar) { try { Socket clientSocket = (Socket)ar.AsyncState; clientSocket.EndReceive(ar); //Transform the array of bytes received from the user into an //intelligent form of object Data Data msgReceived = new Data(byteData); //We will send this object in response the users request Data msgToSend = new Data(); lock (globalLocker) { int clientId = findClient(clientList, clientSocket); byte[] message; if (clientId == -1) writeToLog2("Получено " + msgReceived.cmdCommand.ToString() + " от " + clientSocket.LocalEndPoint.ToString(), true); else if (clientList[clientId].roomId == -1) writeToLog2("Получено " + msgReceived.cmdCommand.ToString() + " от " + clientList[clientId].login, true); else writeToLog2("Получено " + msgReceived.cmdCommand.ToString() + "\t от " + clientList[clientId].login + " в \"" + rooms[clientList[clientId].roomId].roomName + "\"", true); switch (msgReceived.cmdCommand) { case Command.Connect: /////////проверка разрешения пользователя на доступ к игре //если разрешено ClientInfo clientInfo = new ClientInfo(); clientInfo.socket = clientSocket; clientInfo.ip = clientInfo.socket.RemoteEndPoint.ToString(); clientInfo.login = msgReceived.login; clientInfo.roomId = -1; if (msgReceived.cardID != VERSION) { writeToLog("Попытка подключиться (старый клиент): " + clientInfo.login); msgToSend.cmdCommand = Command.OldVersion; message = msgToSend.ToByte(); //writeToLog2("Отправлено к " + clientInfo.login + " " + msgToSend.cmdCommand.ToString(), true); clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendOne), new PacketInfo(clientInfo.socket, Command.OldVersion, -1)); return; } if (isLoginOK(clientList, msgReceived.login)) { writeToLog("Подключился новый игрок: " + clientInfo.login); clientList.Add(clientInfo); msgToSend.cmdCommand = Command.Success; message = msgToSend.ToByte(); //writeToLog2("Отправлено к " + clientInfo.login + " " + msgToSend.cmdCommand.ToString(), true); clientInfo.acceptEvent.Reset(); clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendOne), new PacketInfo(clientInfo.socket, Command.Success, -1)); clientInfo.acceptEvent.WaitOne(); if (playersChanged != null) playersChanged(false, null); } else { writeToLog("Попытка подключиться: " + clientInfo.login); msgToSend.cmdCommand = Command.Failed; message = msgToSend.ToByte(); //writeToLog2("Отправлено к " + clientInfo.login + " " + msgToSend.cmdCommand.ToString(), true); clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendOne), new PacketInfo(clientInfo.socket, Command.Failed, -1)); } break; case Command.connectToGame: //найти и добавить в игру клиента if (clientId != -1) { clientList[clientId].roomId = findRoom(msgReceived.gameToConnectRoomName); rooms[clientList[clientId].roomId].gamersSend += clientList[clientId].login + " "; rooms[clientList[clientId].roomId].gamers += "; " + clientList[clientId].login; rooms[clientList[clientId].roomId].clientsInRoom.Add(clientList[clientId]); msgToSend.UsersInRoom = rooms[clientList[clientId].roomId].gamersSend; Send4All(clientId, Command.ListUsers, msgToSend); if (roomsChanged != null) roomsChanged(null, null); playersChanged(true, null); writeToLog(clientList[clientId].login + " присоединился в комнату " + rooms[clientList[clientId].roomId].roomName); } break; case Command.newGame: //создать новый стол if (clientId != -1 && clientList[clientId].roomId == -1) { Room r = new Room(); r.phase = 0; r.id = rooms.Count; r.roomName = msgReceived.gameToConnectRoomName; r.maxScores = msgReceived.cardID; r.gamers = clientList[clientId].login; r.password = msgReceived.login; r.gamersSend = r.gamers + " "; r.clientsInRoom = new List<ClientInfo>(); r.clientsInRoom.Add(clientList[clientId]); r.deckSize = Convert.ToInt32(msgReceived.UsersInRoom); r.Cards = new List<int>(); for (int i = 0; i < r.deckSize; i++) r.Cards.Add(i + 1); clientList[clientId].isAdmin = true; //первый создавший - админ, может запустить игру rooms.Add(r); clientList[clientId].roomId = r.id; writeToLog(clientList[clientId].login + " создал комнату: " + (r.roomName)); if (roomsChanged != null) roomsChanged(null, null); playersChanged(true, null); } break; #region GameLogic case Command.startGame: if (clientId != -1 && clientList[clientId].roomId != -1) { var r = rooms[clientList[clientId].roomId]; //активная комната r.status = 1; //идет игра r.phase = 1; if (roomsChanged != null) roomsChanged(null, null); r.gamersSend = r.gamersSend.Replace("# ", " "); r.gamersSend = r.gamersSend.Replace("? ", " "); r.gamersSend = r.gamersSend.Replace("* ", " "); writeToLog("В комнате " + r.roomName + " началась игра!"); //msgToSend.UsersInRoom = r.gamersSend; //Send4All(clientId, Command.ListUsers, msgToSend); //начинаем игру раздаем карты Random rnd = new Random(); r.sendCount = 0; r.acceptAllEvent.Reset(); for (int i = 0; i < r.clientsInRoom.Count; i++) { r.clientsInRoom[i].scores = 0; //очки в текущей партии r.clientsInRoom[i].voated = 0; r.clientsInRoom[i].discarded = 0; for (int j = 0; j < 5; j++) msgToSend.userCards[j] = NextCard(rnd, clientId); msgToSend.cardID = r.maxScores; msgToSend.cmdCommand = Command.startGame; message = msgToSend.ToByte(); if (r.clientsInRoom[i].socket.Connected) r.clientsInRoom[i].socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendRoom), new PacketInfo(r.clientsInRoom[i].socket, Command.startGame, -2)); else connectionLost("Socket disconnected", r.clientsInRoom[i].socket); //r.clientsInRoom[i].acceptEvent.WaitOne(); //writeToLog2("Отправлено к " + r.clientsInRoom[i].login + " " + msgToSend.cmdCommand.ToString()); } r.acceptAllEvent.WaitOne(); roundBegin(r, clientId, rnd, true); } break; case Command.LeaderTurn: if (clientId != -1 && clientList[clientId].roomId != -1) { var r = rooms[clientList[clientId].roomId]; //активная комната int clientRoomId = findClient(r.clientsInRoom, clientSocket); r.clientsInRoom[clientRoomId].discarded = msgReceived.cardID; //занесли в память что скинул msgToSend.cmdCommand = Command.GamersTurn; //передает словесное задание msgToSend.gameToConnectRoomName = msgReceived.gameToConnectRoomName; message = msgToSend.ToByte(); if (r.clientsInRoom.Count > 1) { r.acceptAllEvent.Reset(); r.sendCount = 1; for (int i = 0; i < r.clientsInRoom.Count; i++) { if (i == findLeaderID(clientId)) continue; if (r.clientsInRoom[i].socket.Connected) r.clientsInRoom[i].socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendRoom), new PacketInfo(r.clientsInRoom[i].socket, Command.GamersTurn, -2)); else connectionLost("Socket disconnected", r.clientsInRoom[i].socket); //writeToLog2("Отправлено к " + r.clientsInRoom[i].login + " " + msgToSend.cmdCommand.ToString()); } r.acceptAllEvent.WaitOne(); } //отчет в список r.gamersSend = r.gamersSend.Replace(clientList[clientId].login, clientList[clientId].login + "*"); msgToSend.UsersInRoom = rooms[clientList[clientId].roomId].gamersSend; Send4All(clientId, Command.ListUsers, msgToSend); r.phase = 4; //ассоциация пришла - отправили команду игрокам для сброса карт } break; case Command.GamersTurn: if (clientId != -1 && clientList[clientId].roomId != -1) { var r = rooms[clientList[clientId].roomId]; //активная комната int clientRoomId = findClient(r.clientsInRoom, clientSocket); r.clientsInRoom[clientRoomId].discarded = msgReceived.cardID; //занесли в память что скинул r.gamersSend = r.gamersSend.Replace(clientList[clientId].login, clientList[clientId].login + "#"); bool isReady = true; foreach (ClientInfo cl in r.clientsInRoom) if (cl.discarded <= 0) { isReady = false; break; } if (isReady) { Data msgToSendV = new Data(rooms[clientList[clientId].roomId].clientsInRoom.Count); msgToSendV.cmdCommand = Command.VoatingTurn; msgToSendV.userCards = ShuffleDiscarded(clientId); Send4All(clientId, Command.VoatingTurn, msgToSendV); r.phase = 5; //все сбросили карты - время для голосования! r.gamersSend = rooms[clientList[clientId].roomId].gamersSend.Replace("# ", " "); } msgToSend.UsersInRoom = rooms[clientList[clientId].roomId].gamersSend; Send4All(clientId, Command.ListUsers, msgToSend); } break; case Command.VoatingTurn: if (clientId != -1 && clientList[clientId].roomId != -1) { var r = rooms[clientList[clientId].roomId]; //активная комната int clientRoomId = findClient(r.clientsInRoom, clientSocket); r.clientsInRoom[clientRoomId].voated = msgReceived.cardID; //занесли в память что ответил r.gamersSend = r.gamersSend.Replace(clientList[clientId].login, clientList[clientId].login + "#"); bool isReady = true; foreach (ClientInfo cl in r.clientsInRoom) { if (cl.login == r.clientsInRoom[findLeaderID(clientId)].login) continue; if (cl.voated <= 0 && cl.ip != "LoggedOut") { isReady = false; break; } } if (isReady) calcResult(r, clientId, msgToSend); msgToSend.UsersInRoom = rooms[clientList[clientId].roomId].gamersSend; Send4All(clientId, Command.ListUsers, msgToSend); r.gamersSend = r.gamersSend.Replace("& ", " "); } break; case Command.Success: if (clientId != -1 && clientList[clientId].roomId != -1) { var r = rooms[clientList[clientId].roomId]; //активная комната int clientRoomId = findClient(r.clientsInRoom, clientSocket); r.clientsInRoom[clientRoomId].voated = 0; //сбрасываем сыгранные карты r.clientsInRoom[clientRoomId].discarded = 0; r.gamersSend = r.gamersSend.Replace(clientList[clientId].login, clientList[clientId].login + "#"); bool isReady = true; foreach (ClientInfo cl in r.clientsInRoom) if (cl.discarded > 0) { isReady = false; break; } if (isReady) roundBegin(r, clientId, new Random(), false); else { msgToSend.UsersInRoom = r.gamersSend; Send4All(clientId, Command.ListUsers, msgToSend); } } break; #endregion case Command.List: //сформировать список столов и вернуть назад msgToSend.cmdCommand = Command.List; msgToSend.list = rooms; message = msgToSend.ToByte(); //Send the message to all users if (clientSocket.Connected) clientSocket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendOne), new PacketInfo(clientSocket, Command.List, -1)); else connectionLost("Socket disconnected", clientSocket); //writeToLog2("Отправлено к " + clientList[clientId].login + " " + msgToSend.cmdCommand.ToString()); playersChanged(true, null); break; case Command.chat: if (clientId != -1) { if (msgReceived.cardID == 1) //сообщение пришло для игровой комнаты { if (msgReceived.UsersInRoom.StartsWith("@kick")) //получена команда if (clientList[clientId].isAdmin) { string target = msgReceived.UsersInRoom.Remove(0, 6); for (int i=0; i< rooms[clientList[clientId].roomId].clientsInRoom.Count; i++) if (rooms[clientList[clientId].roomId].clientsInRoom[i].login == target) { msgToSend.cmdCommand = Command.Disconnect; message = msgToSend.ToByte(); rooms[clientList[clientId].roomId].clientsInRoom[i].acceptEvent.Reset(); rooms[clientList[clientId].roomId].clientsInRoom[i].socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendOne), new PacketInfo(rooms[clientList[clientId].roomId].clientsInRoom[i].socket, Command.Disconnect, -1)); rooms[clientList[clientId].roomId].clientsInRoom[i].acceptEvent.WaitOne(); } } msgToSend.gameToConnectRoomName = msgReceived.UsersInRoom; msgToSend.login = clientList[clientId].login; msgToSend.cardID = 1; Send4All(clientId, Command.chat, msgToSend); } else { msgToSend.gameToConnectRoomName = msgReceived.UsersInRoom; msgToSend.login = clientList[clientId].login; msgToSend.cmdCommand = Command.chat; msgToSend.cardID = 0; message = msgToSend.ToByte(); lock (removeLobbyLocker) { acceptLobbyEvent.Reset(); sendLobby = 0; int waiterNum = 0; for (int i = 0; i < clientList.Count; i++) if (clientList[i].roomId == -1) waiterNum++; if (waiterNum == 0) return; for (int i = 0; i < clientList.Count; i++) if (clientList[i].roomId == -1) if (clientList[i].socket.Connected) clientList[i].socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendLobby), new PacketInfo(clientList[i].socket, Command.chat, waiterNum)); else connectionLost("Socket disconnected", clientList[i].socket); acceptLobbyEvent.WaitOne(); } } } break; case Command.logOut: if (clientId != -1) { writeToLog("Игрок " + clientList[clientId].login + " вышел из комнаты " + rooms[clientList[clientId].roomId].roomName); afterDisconnect(clientId, clientSocket, msgToSend); clientList[clientId].roomId = -1; roomsChanged(null, null); playersChanged(true, null); } break; case Command.Disconnect: if (clientId != -1) { if (clientList[clientId].roomId != -1) afterDisconnect(clientId, clientSocket, new Data()); writeToLog("Игрок " + clientList[clientId].login + " отключился"); lock (removeLobbyLocker) clientList.RemoveAt(clientId); roomsChanged(null, null); playersChanged(true, null); } break; } //If the user is logging out then we need not listen from her if (msgReceived.cmdCommand != Command.Disconnect && msgToSend.cmdCommand != Command.Failed) { //Start listening to the message send by the user clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket); } } log2Changed(log, null); } catch (Exception ex) { Socket clientSocket = (Socket)ar.AsyncState; connectionLost(ex.Message, clientSocket); } }
private void afterDisconnect(int clientId, Socket clientSocket, Data msgToSend) { bool IsNotRemoved = true; var r = rooms[clientList[clientId].roomId]; int clientRoomId = findClient(r.clientsInRoom, clientSocket); if (clientList[clientId].isAdmin == true) //вышел админ, меняем его чтобы могли запускать игру { clientList[clientId].isAdmin = false; int newAdminId = clientRoomId - 1; if (newAdminId == -1) newAdminId = clientRoomId + 1; if (newAdminId == r.clientsInRoom.Count) newAdminId = 0; if (r.clientsInRoom.Count > 1) { r.clientsInRoom[newAdminId].isAdmin = true; //отправляем уведомление об админстве msgToSend.cmdCommand = Command.setAdmin; byte[] message = msgToSend.ToByte(); //while (r.clientsInRoom[newAdminId].isBusy == true) Thread.Sleep(30); if (r.clientsInRoom[newAdminId].socket.Connected) { r.clientsInRoom[newAdminId].acceptEvent.Reset(); r.clientsInRoom[newAdminId].socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendOne), new PacketInfo(r.clientsInRoom[newAdminId].socket, Command.setAdmin, -1)); r.clientsInRoom[newAdminId].acceptEvent.WaitOne(); } else connectionLost("Socket disconnected", r.clientsInRoom[newAdminId].socket); //r.clientsInRoom[newAdminId].isBusy = true; //writeToLog2("Отправлено к " + r.clientsInRoom[newAdminId].login + " " + msgToSend.cmdCommand.ToString()); } } if (rooms[clientList[clientId].roomId].status == 1) { if (r.phase == 5 && r.clientsInRoom.Count > 1) //отключился в этап голосования { //делаем дамп его записи ClientInfo clone = new ClientInfo(); clone.isLeader = clientList[clientId].isLeader; clone.ip = "LoggedOut"; clone.socket = null; clone.voated = clientList[clientId].voated; clone.discarded = clientList[clientId].discarded; clone.login = clientList[clientId].login; clone.roomId = clientList[clientId].roomId; r.clientsInRoom.RemoveAt(clientRoomId); r.clientsInRoom.Insert(clientRoomId, clone); IsNotRemoved = false; //подменили данные чувака, его вынесли из списка клона вставили r.gamersSend = r.gamersSend.Replace(clientList[clientId].login, clientList[clientId].login + "?"); //типа пометили его как ушедшего но не удалили //проверка готовности, вдруг тот кто ушел - последний bool isReady = true; foreach (ClientInfo cl in r.clientsInRoom) { if (cl.login == clientList[clientId].login) continue; if (cl.login == r.clientsInRoom[findLeaderID(clientId)].login) continue; if (cl.voated <= 0 && cl.ip != "LoggedOut") { isReady = false; break; } } if (isReady) { calcResult(r, clientId, msgToSend); } r.gamersSend = r.gamersSend.Replace("& ", " "); } if (r.phase == 4 && r.clientsInRoom.Count > 1) //отключился когда сбрасывал карту { if (clientList[clientId].isLeader == true) { //делаем дамп его записи ClientInfo clone = new ClientInfo(); clone.isLeader = clientList[clientId].isLeader; clone.ip = "LoggedOut"; clone.socket = null; clone.voated = clientList[clientId].voated; clone.discarded = clientList[clientId].discarded; clone.login = clientList[clientId].login; clone.roomId = clientList[clientId].roomId; r.clientsInRoom.RemoveAt(clientRoomId); r.clientsInRoom.Insert(clientRoomId, clone); IsNotRemoved = false; //подменили данные чувака, его вынесли из списка клона вставили r.gamersSend = r.gamersSend.Replace(clientList[clientId].login, clientList[clientId].login + "?"); //типа пометили его как ушедшего но не удалили } //проверяем, что был ли он последним не сбросившим bool flag = true; foreach (ClientInfo ci in r.clientsInRoom) { if (ci.login == clientList[clientId].login) continue; if (ci.discarded == 0) { flag = false; break; }//кто-то тоже не скинул } if (flag) //он последний, его и ждали { r.clientsInRoom.RemoveAt(clientRoomId); //удаляем его наконец IsNotRemoved = false; Data msgToSendV = new Data(r.clientsInRoom.Count); msgToSendV.cmdCommand = Command.VoatingTurn; msgToSendV.userCards = ShuffleDiscarded(clientId); Send4All(clientId, Command.VoatingTurn, msgToSendV); r.phase = 5; //все сбросили карты - время для голосования! r.gamersSend = rooms[clientList[clientId].roomId].gamersSend.Replace("# ", " "); } } //ведущий игрок вышел из комнаты if (clientRoomId == findLeaderID(clientId)) { int curLeader = clientRoomId; if (r.clientsInRoom[clientRoomId].ip != "LoggedOut") { if (r.phase == 2) curLeader++; else curLeader--; if (curLeader == r.clientsInRoom.Count) curLeader = 0; if (curLeader == -1) curLeader = r.clientsInRoom.Count - 1; if (r.clientsInRoom.Count > 1) r.clientsInRoom[curLeader].isLeader = true; r.clientsInRoom[clientRoomId].isLeader = false; } if (r.phase == 2 && r.clientsInRoom.Count > 2) { msgToSend.cmdCommand = Command.LeaderTurn; byte[] message = msgToSend.ToByte(); //while (r.clientsInRoom[curLeader].isBusy == true) Thread.Sleep(30); if (r.clientsInRoom[curLeader].socket.Connected) { r.clientsInRoom[curLeader].acceptEvent.Reset(); r.clientsInRoom[curLeader].socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendOne), new PacketInfo(r.clientsInRoom[curLeader].socket, Command.LeaderTurn, -1)); r.clientsInRoom[curLeader].acceptEvent.WaitOne(); msgToSend.cmdCommand = Command.Waiting; msgToSend.login = r.clientsInRoom[curLeader].login; message = msgToSend.ToByte(); r.acceptAllEvent.Reset(); r.sendCount = 2; for (int i = 0; i < r.clientsInRoom.Count; i++) { if (i == curLeader || i == clientRoomId) continue; if (r.clientsInRoom[i].socket.Connected) r.clientsInRoom[i].socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendRoom), new PacketInfo(r.clientsInRoom[i].socket, Command.Waiting, -2)); else { connectionLost("Socket disconnected", r.clientsInRoom[i].socket); r.acceptAllEvent.Set(); } } r.acceptAllEvent.WaitOne(); r.gamersSend = r.gamersSend.Replace("# ", " "); } else connectionLost("Socket disconnected", r.clientsInRoom[curLeader].socket); } } if (r.phase == 6 && r.clientsInRoom.Count > 1) //отключился при ознакомлении с результатами { //тут пофиг кто ушел, проверка последнего bool isReady = true; foreach (ClientInfo cl in r.clientsInRoom) if (cl.discarded > 0 && cl.login != clientList[clientId].login) { isReady = false; break; } if (isReady) { r.clientsInRoom.RemoveAt(clientRoomId); //удаляем его наконец IsNotRemoved = false; roundBegin(r, clientId, new Random(), false); } } } //Thread.Sleep(100); string test = r.gamers; test = test.Replace(" " + clientList[clientId].login + ";", null); test = test.Replace(clientList[clientId].login + "; ", null); test = test.Replace("; " + clientList[clientId].login, null); r.gamers = test; r.gamersSend = r.gamersSend.Replace(clientList[clientId].login + " ", null); r.gamersSend = r.gamersSend.Replace(clientList[clientId].login + "* ", null); r.gamersSend = r.gamersSend.Replace(clientList[clientId].login + "# ", null); if (IsNotRemoved) r.clientsInRoom.RemoveAt(clientRoomId); //удаляем его наконец playersChanged(false, null); //обновляем таблицу на серваке //проверяем есть ли пустые комнаты if (r.clientsInRoom.Count == 0) { int rid = clientList[clientId].roomId; rooms.RemoveAt(rid); foreach (ClientInfo cl in clientList) if (cl.roomId > rid) cl.roomId--; } else Send4All(clientId, Command.ListUsers, msgToSend); }