diff --git a/src/gui/qt/startwindow/startwindowimpl.cpp b/src/gui/qt/startwindow/startwindowimpl.cpp index 2d7c3286..b080d7b0 100644 --- a/src/gui/qt/startwindow/startwindowimpl.cpp +++ b/src/gui/qt/startwindow/startwindowimpl.cpp @@ -385,7 +385,8 @@ void startWindowImpl::callRejoinPossibleDialog(unsigned gameId) int ret = msgBox.exec(); switch (ret) { - case QMessageBox::Yes:; //rejoin + case QMessageBox::Yes:; + mySession->clientRejoinGame(gameId); break; case QMessageBox::No: showClientDialog(); break; diff --git a/src/net/clientthread.h b/src/net/clientthread.h index 2b8e65a8..4f63a3aa 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -74,6 +74,7 @@ public: void SendPrivateChatMessage(unsigned targetPlayerId, const std::string &msg); void SendJoinFirstGame(const std::string &password, bool autoLeave); void SendJoinGame(unsigned gameId, const std::string &password, bool autoLeave); + void SendRejoinGame(unsigned gameId, bool autoLeave); void SendCreateGame(const GameData &gameData, const std::string &name, const std::string &password, bool autoLeave); void SendResetTimeout(); void SendAskKickPlayer(unsigned playerId); diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index f1318389..87ae5ce7 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -1298,6 +1298,9 @@ ClientStateWaitJoin::InternalHandlePacket(boost::shared_ptr client case joinGameFailureReason_ipAddressBlocked : failureCode = NTF_NET_JOIN_IP_BLOCKED; break; + case joinGameFailureReason_rejoinFailed : + failureCode = NTF_NET_JOIN_REJOIN_FAILED; + break; default : failureCode = NTF_NET_INTERNAL; break; diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index 0b24a334..d96fa1e3 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -256,6 +256,22 @@ ClientThread::SendJoinGame(unsigned gameId, const std::string &password, bool au m_ioService->post(boost::bind(&ClientThread::SendSessionPacket, shared_from_this(), packet)); } +void +ClientThread::SendRejoinGame(unsigned gameId, bool autoLeave) +{ + // Warning: This function is called in the context of the GUI thread. + // Create a network packet to request rejoining a running game. + boost::shared_ptr packet(new NetPacket(NetPacket::Alloc)); + packet->GetMsg()->present = PokerTHMessage_PR_joinGameRequestMessage; + JoinGameRequestMessage_t *netJoinGame = &packet->GetMsg()->choice.joinGameRequestMessage; + netJoinGame->autoLeave = autoLeave; + netJoinGame->joinGameAction.present = joinGameAction_PR_rejoinExistingGame; + + RejoinExistingGame_t *rejoinExisting = &netJoinGame->joinGameAction.choice.rejoinExistingGame; + rejoinExisting->gameId = gameId; + m_ioService->post(boost::bind(&ClientThread::SendSessionPacket, shared_from_this(), packet)); +} + void ClientThread::SendCreateGame(const GameData &gameData, const std::string &name, const std::string &password, bool autoLeave) { diff --git a/src/net/common/servergame.cpp b/src/net/common/servergame.cpp index a21c6199..c66dcd5c 100644 --- a/src/net/common/servergame.cpp +++ b/src/net/common/servergame.cpp @@ -513,7 +513,9 @@ ServerGame::GetPlayerDataByUniqueId(unsigned playerId) const { boost::shared_ptr tmpPlayer; boost::shared_ptr session = GetSessionManager().GetSessionByUniquePlayerId(playerId); - tmpPlayer = session->GetPlayerData(); + if (session) { + tmpPlayer = session->GetPlayerData(); + } if (!tmpPlayer) { boost::mutex::scoped_lock lock(m_computerPlayerListMutex); PlayerDataList::const_iterator i = m_computerPlayerList.begin(); diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index af9565f1..3a8c8838 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -746,6 +746,19 @@ ServerGameStateStartGame::DoStart(boost::shared_ptr server) //----------------------------------------------------------------------------- +AbstractServerGameStateRunning::~AbstractServerGameStateRunning() +{ +} + +void +AbstractServerGameStateRunning::HandleNewSession(boost::shared_ptr server, boost::shared_ptr session) +{ + // Do not accept new sessions in this state. + server->MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING); +} + +//----------------------------------------------------------------------------- + ServerGameStateHand ServerGameStateHand::s_state; ServerGameStateHand & @@ -778,13 +791,6 @@ ServerGameStateHand::Exit(boost::shared_ptr server) server->GetStateTimer1().cancel(); } -void -ServerGameStateHand::HandleNewSession(boost::shared_ptr server, boost::shared_ptr session) -{ - // Do not accept new sessions in this state. - server->MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING); -} - void ServerGameStateHand::InternalProcessPacket(boost::shared_ptr /*server*/, boost::shared_ptr /*session*/, boost::shared_ptr /*packet*/) { @@ -1228,13 +1234,6 @@ ServerGameStateWaitPlayerAction::Exit(boost::shared_ptr server) server->GetStateTimer1().cancel(); } -void -ServerGameStateWaitPlayerAction::HandleNewSession(boost::shared_ptr server, boost::shared_ptr session) -{ - // Do not accept new sessions in this state. - server->MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING); -} - void ServerGameStateWaitPlayerAction::InternalProcessPacket(boost::shared_ptr server, boost::shared_ptr session, boost::shared_ptr packet) { @@ -1382,13 +1381,6 @@ ServerGameStateWaitNextHand::Exit(boost::shared_ptr server) server->GetStateTimer1().cancel(); } -void -ServerGameStateWaitNextHand::HandleNewSession(boost::shared_ptr server, boost::shared_ptr session) -{ - // Do not accept new sessions in this state. - server->MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING); -} - void ServerGameStateWaitNextHand::InternalProcessPacket(boost::shared_ptr server, boost::shared_ptr session, boost::shared_ptr packet) { diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index a65edd53..713953c6 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -702,26 +702,6 @@ ServerLobbyThread::GetBanManager() return *m_banManager; } -u_int32_t -ServerLobbyThread::GetRejoinGameIdForPlayer(const std::string &playerName, const std::string &guid, unsigned &outPlayerUniqueId) -{ - u_int32_t retGameId = 0; - GameMap::iterator i = m_gameMap.begin(); - GameMap::iterator end = m_gameMap.end(); - while (i != end) { - boost::shared_ptr tmpGame = i->second; - boost::shared_ptr tmpPlayer = tmpGame->GetPlayerInterfaceFromGame(playerName); - if (tmpPlayer && tmpPlayer->getMyGuid() == guid) - { - retGameId = tmpGame->GetId(); - outPlayerUniqueId = tmpPlayer->getMyUniqueID(); - break; - } - ++i; - } - return retGameId; -} - u_int32_t ServerLobbyThread::GetNextUniquePlayerId() { @@ -940,6 +920,8 @@ ServerLobbyThread::HandlePacket(boost::shared_ptr session, boost::s HandleNetPacketCreateGame(session, password, joinRequest->autoLeave, joinRequest->joinGameAction.choice.joinNewGame); else if (joinRequest->joinGameAction.present == joinGameAction_PR_joinExistingGame) HandleNetPacketJoinGame(session, password, joinRequest->autoLeave, joinRequest->joinGameAction.choice.joinExistingGame); + else if (joinRequest->joinGameAction.present == joinGameAction_PR_rejoinExistingGame) + HandleNetPacketRejoinGame(session, joinRequest->autoLeave, joinRequest->joinGameAction.choice.rejoinExistingGame); } else if (packet->GetMsg()->present == PokerTHMessage_PR_chatRequestMessage) HandleNetPacketChatRequest(session, packet->GetMsg()->choice.chatRequestMessage); else if (packet->GetMsg()->present == PokerTHMessage_PR_rejectGameInvitationMessage) @@ -1054,7 +1036,7 @@ ServerLobbyThread::HandleNetPacketInit(boost::shared_ptr session, c tmpPlayerData->SetAvatarMD5(avatarMD5); if (initMessage.myLastSessionId) { - tmpPlayerData->SetGuid(STL_STRING_FROM_OCTET_STRING(*initMessage.myLastSessionId)); + tmpPlayerData->SetOldGuid(STL_STRING_FROM_OCTET_STRING(*initMessage.myLastSessionId)); } // Set player data for session. @@ -1324,6 +1306,26 @@ ServerLobbyThread::HandleNetPacketJoinGame(boost::shared_ptr sessio } } +void +ServerLobbyThread::HandleNetPacketRejoinGame(boost::shared_ptr session, bool autoLeave, const RejoinExistingGame_t &rejoinGame) +{ + // Rejoin a running game. + GameMap::iterator pos = m_gameMap.find(rejoinGame.gameId); + + if (pos != m_gameMap.end()) { + boost::shared_ptr game = pos->second; + // Verify that the user is allowed to rejoin. + boost::shared_ptr tmpPlayer = game->GetPlayerInterfaceFromGame(session->GetPlayerData()->GetName()); + if (tmpPlayer && tmpPlayer->getMyGuid() == session->GetPlayerData()->GetOldGuid()) { + MoveSessionToGame(game, session, autoLeave); + } else { + SendJoinGameFailed(session, rejoinGame.gameId, NTF_NET_JOIN_REJOIN_FAILED); + } + } else { + SendJoinGameFailed(session, rejoinGame.gameId, NTF_NET_JOIN_GAME_INVALID); + } +} + void ServerLobbyThread::HandleNetPacketChatRequest(boost::shared_ptr session, const ChatRequestMessage_t &chatRequest) { @@ -1493,7 +1495,7 @@ ServerLobbyThread::EstablishSession(boost::shared_ptr session) throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0); u_int32_t rejoinPlayerId = 0; - u_int32_t rejoinGameId = GetRejoinGameIdForPlayer(session->GetPlayerData()->GetName(), session->GetPlayerData()->GetGuid(), rejoinPlayerId); + u_int32_t rejoinGameId = GetRejoinGameIdForPlayer(session->GetPlayerData()->GetName(), session->GetPlayerData()->GetOldGuid(), rejoinPlayerId); if (rejoinGameId != 0) { // Offer rejoin, and disconnect current player with the same name. @@ -1955,6 +1957,9 @@ ServerLobbyThread::SendJoinGameFailed(boost::shared_ptr s, unsigned case NTF_NET_JOIN_IP_BLOCKED : joinFailed->joinGameFailureReason = joinGameFailureReason_ipAddressBlocked; break; + case NTF_NET_JOIN_REJOIN_FAILED : + joinFailed->joinGameFailureReason = joinGameFailureReason_rejoinFailed; + break; default : joinFailed->joinGameFailureReason = joinGameFailureReason_invalidGame; break; @@ -2186,3 +2191,23 @@ ServerLobbyThread::CreateNetPacketGameListUpdate(unsigned gameId, GameMode mode) return packet; } +u_int32_t +ServerLobbyThread::GetRejoinGameIdForPlayer(const std::string &playerName, const std::string &guid, unsigned &outPlayerUniqueId) +{ + u_int32_t retGameId = 0; + GameMap::iterator i = m_gameMap.begin(); + GameMap::iterator end = m_gameMap.end(); + while (i != end) { + boost::shared_ptr tmpGame = i->second; + boost::shared_ptr tmpPlayer = tmpGame->GetPlayerInterfaceFromGame(playerName); + if (tmpPlayer && tmpPlayer->getMyGuid() == guid) + { + retGameId = tmpGame->GetId(); + outPlayerUniqueId = tmpPlayer->getMyUniqueID(); + break; + } + ++i; + } + return retGameId; +} + diff --git a/src/net/servergame.h b/src/net/servergame.h index 75a000e1..2c693c68 100644 --- a/src/net/servergame.h +++ b/src/net/servergame.h @@ -204,6 +204,7 @@ private: friend class ServerLobbyThread; friend class AbstractServerGameStateReceiving; + friend class AbstractServerGameStateRunning; friend class ServerGameStateInit; friend class ServerGameStateWaitAck; friend class ServerGameStateStartGame; diff --git a/src/net/servergamestate.h b/src/net/servergamestate.h index 25229786..2385aae2 100644 --- a/src/net/servergamestate.h +++ b/src/net/servergamestate.h @@ -129,8 +129,16 @@ private: static ServerGameStateStartGame s_state; }; +class AbstractServerGameStateRunning : public AbstractServerGameStateReceiving +{ +public: + virtual ~AbstractServerGameStateRunning(); + + virtual void HandleNewSession(boost::shared_ptr server, boost::shared_ptr session); +}; + // State: Within hand. -class ServerGameStateHand : public AbstractServerGameStateReceiving +class ServerGameStateHand : public AbstractServerGameStateRunning { public: static ServerGameStateHand &Instance(); @@ -141,7 +149,6 @@ public: virtual void NotifyGameAdminChanged(boost::shared_ptr /*server*/) {} virtual void NotifySessionRemoved(boost::shared_ptr /*server*/) {} - virtual void HandleNewSession(boost::shared_ptr server, boost::shared_ptr session); protected: ServerGameStateHand(); @@ -164,7 +171,7 @@ private: }; // State: Wait for a player action. -class ServerGameStateWaitPlayerAction : public AbstractServerGameStateReceiving +class ServerGameStateWaitPlayerAction : public AbstractServerGameStateRunning { public: static ServerGameStateWaitPlayerAction &Instance(); @@ -175,7 +182,6 @@ public: virtual void NotifyGameAdminChanged(boost::shared_ptr /*server*/) {} virtual void NotifySessionRemoved(boost::shared_ptr /*server*/) {} - virtual void HandleNewSession(boost::shared_ptr server, boost::shared_ptr session); protected: ServerGameStateWaitPlayerAction(); @@ -188,7 +194,7 @@ private: }; // State: Wait for the next hand. -class ServerGameStateWaitNextHand : public AbstractServerGameStateReceiving +class ServerGameStateWaitNextHand : public AbstractServerGameStateRunning { public: static ServerGameStateWaitNextHand &Instance(); @@ -199,7 +205,6 @@ public: virtual void NotifyGameAdminChanged(boost::shared_ptr /*server*/) {} virtual void NotifySessionRemoved(boost::shared_ptr /*server*/) {} - virtual void HandleNewSession(boost::shared_ptr server, boost::shared_ptr session); protected: ServerGameStateWaitNextHand(); diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index 633af9a5..69850ffe 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -110,8 +110,6 @@ public: boost::shared_ptr GetDatabase(); ServerBanManager &GetBanManager(); - u_int32_t GetRejoinGameIdForPlayer(const std::string &playerName, const std::string &guid, unsigned &outPlayerUniqueId); - protected: typedef std::deque > ConnectQueue; @@ -141,6 +139,7 @@ protected: void HandleNetPacketRetrieveAvatar(boost::shared_ptr session, const AvatarRequestMessage_t &retrieveAvatar); void HandleNetPacketCreateGame(boost::shared_ptr session, const std::string &password, bool autoLeave, const JoinNewGame_t &newGame); void HandleNetPacketJoinGame(boost::shared_ptr session, const std::string &password, bool autoLeave, const JoinExistingGame_t &joinGame); + void HandleNetPacketRejoinGame(boost::shared_ptr session, bool autoLeave, const RejoinExistingGame_t &rejoinGame); void HandleNetPacketChatRequest(boost::shared_ptr session, const ChatRequestMessage_t &chatRequest); void HandleNetPacketRejectGameInvitation(boost::shared_ptr session, const RejectGameInvitationMessage_t &reject); // TODO would be better to use state pattern here. @@ -199,6 +198,8 @@ protected: static boost::shared_ptr CreateNetPacketGameListNew(const ServerGame &game); static boost::shared_ptr CreateNetPacketGameListUpdate(unsigned gameId, GameMode mode); + u_int32_t GetRejoinGameIdForPlayer(const std::string &playerName, const std::string &guid, unsigned &outPlayerUniqueId); + private: boost::shared_ptr m_ioService; diff --git a/src/net/socket_msg.h b/src/net/socket_msg.h index b6d765f3..4aea8ba3 100644 --- a/src/net/socket_msg.h +++ b/src/net/socket_msg.h @@ -117,10 +117,11 @@ #define NTF_NET_JOIN_GAME_BAD_NAME 217 #define NTF_NET_JOIN_INVALID_SETTINGS 218 #define NTF_NET_JOIN_IP_BLOCKED 219 +#define NTF_NET_JOIN_REJOIN_FAILED 220 // Notifications - version -#define NTF_NET_NEW_RELEASE_AVAILABLE 220 -#define NTF_NET_OUTDATED_BETA 221 +#define NTF_NET_NEW_RELEASE_AVAILABLE 221 +#define NTF_NET_OUTDATED_BETA 222 // This is an internal message which is not reported. #define MSG_SOCK_INTERNAL_PENDING 0 diff --git a/src/playerdata.cpp b/src/playerdata.cpp index d586a47b..32742fb2 100644 --- a/src/playerdata.cpp +++ b/src/playerdata.cpp @@ -174,6 +174,20 @@ PlayerData::SetGuid(const std::string &guid) m_guid = guid; } +std::string +PlayerData::GetOldGuid() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_oldGuid; +} + +void +PlayerData::SetOldGuid(const std::string &guid) +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_oldGuid = guid; +} + DB_id PlayerData::GetDBId() const { diff --git a/src/playerdata.h b/src/playerdata.h index 8c2fe1fd..f477543f 100644 --- a/src/playerdata.h +++ b/src/playerdata.h @@ -94,6 +94,8 @@ public: void SetNumber(int number); std::string GetGuid() const; void SetGuid(const std::string &guid); + std::string GetOldGuid() const; + void SetOldGuid(const std::string &guid); DB_id GetDBId() const; void SetDBId(DB_id id); @@ -104,6 +106,7 @@ private: DB_id m_dbId; int m_number; std::string m_guid; + std::string m_oldGuid; std::string m_name; std::string m_password; std::string m_country; diff --git a/src/session.cpp b/src/session.cpp index 10652793..7de46e10 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -280,6 +280,16 @@ void Session::clientJoinGame(unsigned gameId, const std::string &password) ); } +void Session::clientRejoinGame(unsigned gameId) +{ + if (!myNetClient) + return; // only act if client is running. + myNetClient->SendRejoinGame( + gameId, + myConfig->readConfigInt("NetAutoLeaveGameAfterFinish") == 1 + ); +} + void Session::startNetworkServer(bool dedicated) { if (myNetServer) { diff --git a/src/session.h b/src/session.h index f9548081..73e519ba 100755 --- a/src/session.h +++ b/src/session.h @@ -73,6 +73,7 @@ public: void terminateNetworkClient(); void clientCreateGame(const GameData &gameData, const std::string &name, const std::string &password); void clientJoinGame(unsigned gameId, const std::string &password); + void clientRejoinGame(unsigned gameId); void startNetworkServer(bool dedicated); void sendLeaveCurrentGame();