diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 87ae5ce7..9d38eefc 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -1500,28 +1500,49 @@ ClientStateWaitStart::InternalHandlePacket(boost::shared_ptr clien StartData startData; startData.startDealerPlayerId = netGameStart->startDealerPlayerId; - if (netGameStart->gameStartMode.present != gameStartMode_PR_gameStartModeInitial) + if (netGameStart->gameStartMode.present == gameStartMode_PR_gameStartModeInitial) + { + GameStartModeInitial_t *netStartModeInitial = &netGameStart->gameStartMode.choice.gameStartModeInitial; + startData.numberOfPlayers = netStartModeInitial->playerSeats.list.count; + client->SetStartData(startData); + + // Set player numbers using the game start data slots. + NonZeroId_t **playerIds = netStartModeInitial->playerSeats.list.array; + unsigned numPlayers = netStartModeInitial->playerSeats.list.count; + // Request player info for players if needed. + if (numPlayers && playerIds && *playerIds) { + for (unsigned i = 0; i < numPlayers; i++) { + unsigned playerId = *playerIds[i]; + boost::shared_ptr tmpPlayer = client->GetPlayerDataByUniqueId(playerId); + if (!tmpPlayer.get()) + throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); + tmpPlayer->SetNumber(i); + } + } else + throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PLAYER_COUNT, 0); + } else if (netGameStart->gameStartMode.present == gameStartMode_PR_gameStartModeRejoin) { + GameStartModeRejoin_t *netStartModeRejoin = &netGameStart->gameStartMode.choice.gameStartModeRejoin; + startData.numberOfPlayers = netStartModeRejoin->rejoinPlayerData.list.count; + client->SetStartData(startData); + + // Set player numbers using the game start data slots. + RejoinPlayerData_t **playerInfos = netStartModeRejoin->rejoinPlayerData.list.array; + unsigned numPlayers = netStartModeRejoin->rejoinPlayerData.list.count; + // Request player info for players if needed. + if (numPlayers && playerInfos && *playerInfos) { + for (unsigned i = 0; i < numPlayers; i++) { + RejoinPlayerData_t *playerData = playerInfos[i]; + boost::shared_ptr tmpPlayer = client->GetPlayerDataByUniqueId(playerData->playerId); + if (!tmpPlayer.get()) + throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); + tmpPlayer->SetNumber(i); + // TODO set money + } + } else + throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PLAYER_COUNT, 0); + } else { throw ClientException(__FILE__, __LINE__, ERR_NET_INTERNAL_GAME_ERROR, 0); - - GameStartModeInitial_t *netStartModeInitial = &netGameStart->gameStartMode.choice.gameStartModeInitial; - startData.numberOfPlayers = netStartModeInitial->playerSeats.list.count; - client->SetStartData(startData); - - // Set player numbers using the game start data slots. - NonZeroId_t **playerIds = netStartModeInitial->playerSeats.list.array; - unsigned numPlayers = netStartModeInitial->playerSeats.list.count; - // Request player info for players if needed. - if (numPlayers && playerIds && *playerIds) { - for (unsigned i = 0; i < numPlayers; i++) { - unsigned playerId = *playerIds[i]; - boost::shared_ptr tmpPlayer = client->GetPlayerDataByUniqueId(playerId); - if (!tmpPlayer.get()) - throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); - tmpPlayer->SetNumber(i); - } - } else - throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PLAYER_COUNT, 0); - + } client->InitGame(); client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_START); client->SetState(ClientStateWaitHand::Instance()); diff --git a/src/net/common/servergame.cpp b/src/net/common/servergame.cpp index c66dcd5c..422fee72 100644 --- a/src/net/common/servergame.cpp +++ b/src/net/common/servergame.cpp @@ -627,6 +627,22 @@ ServerGame::SetPlayerAutoLeaveOnFinish(unsigned playerId) m_autoLeavePlayerList.push_back(playerId); } +void +ServerGame::AddRejoinPlayer(unsigned playerId) +{ + boost::mutex::scoped_lock lock(m_rejoinPlayerListMutex); + m_rejoinPlayerList.push_back(playerId); +} + +PlayerIdList +ServerGame::GetAndResetRejoinPlayers() +{ + boost::mutex::scoped_lock lock(m_rejoinPlayerListMutex); + PlayerIdList tmpList(m_rejoinPlayerList); + m_rejoinPlayerList.clear(); + return tmpList; +} + void ServerGame::AddComputerPlayer(boost::shared_ptr player) { diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index 3a8c8838..4ebd5e14 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -357,6 +357,20 @@ AbstractServerGameStateReceiving::ProcessPacket(boost::shared_ptr se } } +boost::shared_ptr +AbstractServerGameStateReceiving::CreateNetPacketPlayerJoined(unsigned gameId, const PlayerData &playerData) +{ + boost::shared_ptr packet(new NetPacket(NetPacket::Alloc)); + packet->GetMsg()->present = PokerTHMessage_PR_gamePlayerMessage; + GamePlayerMessage_t *netGamePlayer = &packet->GetMsg()->choice.gamePlayerMessage; + netGamePlayer->gameId = gameId; + netGamePlayer->gamePlayerNotification.present = gamePlayerNotification_PR_gamePlayerJoined; + GamePlayerJoined_t *playerJoined = &netGamePlayer->gamePlayerNotification.choice.gamePlayerJoined; + playerJoined->playerId = playerData.GetUniqueId(); + playerJoined->isGameAdmin = playerData.IsGameAdmin(); + return packet; +} + //----------------------------------------------------------------------------- ServerGameStateInit ServerGameStateInit::s_state; @@ -429,7 +443,7 @@ ServerGameStateInit::HandleNewSession(boost::shared_ptr server, boos server->GetLobbyThread().GetSender().Send(session, packet); // Send notifications for connected players to client. - PlayerDataList tmpPlayerList = server->GetFullPlayerDataList(); + PlayerDataList tmpPlayerList(server->GetFullPlayerDataList()); PlayerDataList::iterator player_i = tmpPlayerList.begin(); PlayerDataList::iterator player_end = tmpPlayerList.end(); while (player_i != player_end) { @@ -624,20 +638,6 @@ ServerGameStateInit::InternalProcessPacket(boost::shared_ptr server, } } -boost::shared_ptr -ServerGameStateInit::CreateNetPacketPlayerJoined(unsigned gameId, const PlayerData &playerData) -{ - boost::shared_ptr packet(new NetPacket(NetPacket::Alloc)); - packet->GetMsg()->present = PokerTHMessage_PR_gamePlayerMessage; - GamePlayerMessage_t *netGamePlayer = &packet->GetMsg()->choice.gamePlayerMessage; - netGamePlayer->gameId = gameId; - netGamePlayer->gamePlayerNotification.present = gamePlayerNotification_PR_gamePlayerJoined; - GamePlayerJoined_t *playerJoined = &netGamePlayer->gamePlayerNotification.choice.gamePlayerJoined; - playerJoined->playerId = playerData.GetUniqueId(); - playerJoined->isGameAdmin = playerData.IsGameAdmin(); - return packet; -} - //----------------------------------------------------------------------------- ServerGameStateStartGame ServerGameStateStartGame::s_state; @@ -753,8 +753,65 @@ 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); + + // Verify that the user is allowed to rejoin. + boost::shared_ptr tmpPlayer = server->GetPlayerInterfaceFromGame(session->GetPlayerData()->GetName()); + if (tmpPlayer && tmpPlayer->getMyGuid() == session->GetPlayerData()->GetOldGuid()) { + // Perform rejoin at hand start. + // Send ack to client. + // TODO this code is partly copy & paste. + { + boost::shared_ptr packet(new NetPacket(NetPacket::Alloc)); + packet->GetMsg()->present = PokerTHMessage_PR_joinGameReplyMessage; + JoinGameReplyMessage_t *netJoinReply = &packet->GetMsg()->choice.joinGameReplyMessage; + netJoinReply->gameId = server->GetId(); + netJoinReply->joinGameResult.present = joinGameResult_PR_joinGameAck; + JoinGameAck_t *joinAck = &netJoinReply->joinGameResult.choice.joinGameAck; + joinAck->areYouGameAdmin = static_cast(session->GetPlayerData()->IsGameAdmin()); + + NetPacket::SetGameData(server->GetGameData(), &joinAck->gameInfo); + OCTET_STRING_fromBuf( + &joinAck->gameInfo.gameName, + server->GetName().c_str(), + (int)server->GetName().length()); + server->GetLobbyThread().GetSender().Send(session, packet); + } + + // Send notifications for connected players to client. + PlayerDataList tmpPlayerList = server->GetFullPlayerDataList(); + PlayerDataList::iterator player_i = tmpPlayerList.begin(); + PlayerDataList::iterator player_end = tmpPlayerList.end(); + while (player_i != player_end) { + server->GetLobbyThread().GetSender().Send(session, CreateNetPacketPlayerJoined(server->GetId(), *(*player_i))); + ++player_i; + } + + // Send "Player Joined" to other fully connected clients. + server->SendToAllPlayers(CreateNetPacketPlayerJoined(server->GetId(), *session->GetPlayerData()), SessionData::Game); + + // Accept session. + server->GetSessionManager().AddSession(session); + // Remember: We need to initiate a rejoin when starting the next hand. + server->AddRejoinPlayer(session->GetPlayerData()->GetUniqueId()); + + // Notify lobby. + server->GetLobbyThread().NotifyPlayerJoinedGame(server->GetId(), session->GetPlayerData()->GetUniqueId()); + + // Send start event right away. + { + boost::shared_ptr packet(new NetPacket(NetPacket::Alloc)); + packet->GetMsg()->present = PokerTHMessage_PR_startEventMessage; + StartEventMessage_t *netStartEvent = &packet->GetMsg()->choice.startEventMessage; + netStartEvent->gameId = server->GetId(); + netStartEvent->fillWithComputerPlayers = false; + + // Wait for rejoining player to confirm start of game. + server->GetLobbyThread().GetSender().Send(session, packet); + } + } else { + // Do not accept "new" sessions in this state, only rejoin is allowed. + server->MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING); + } } //----------------------------------------------------------------------------- @@ -963,7 +1020,7 @@ ServerGameStateHand::EngineLoop(boost::shared_ptr server) // Remove disconnected players. This is the one and only place to do this. server->RemoveDisconnectedPlayers(); - // Update rankings of all remaining players. + // Update rankings of all remaining players server->UpdateRankingMap(); // Start next hand - if enough players are left. @@ -1079,6 +1136,41 @@ ServerGameStateHand::StartNewHand(boost::shared_ptr server) // Initialize hand. Game &curGame = server->GetGame(); curGame.initHand(); + // Initialize rejoining players. + { + PlayerIdList rejoinIdList(server->GetAndResetRejoinPlayers()); + PlayerIdList::iterator i = rejoinIdList.begin(); + PlayerIdList::iterator end = rejoinIdList.end(); + while (i != end) { + boost::shared_ptr session(server->GetSessionManager().GetSessionByUniquePlayerId(*i)); + if (session) { + boost::shared_ptr packet(new NetPacket(NetPacket::Alloc)); + packet->GetMsg()->present = PokerTHMessage_PR_gameStartMessage; + GameStartMessage_t *netGameStart = &packet->GetMsg()->choice.gameStartMessage; + netGameStart->gameId = server->GetId(); + netGameStart->startDealerPlayerId = curGame.getDealerPosition(); + netGameStart->gameStartMode.present = gameStartMode_PR_gameStartModeRejoin; + GameStartModeRejoin_t *netStartModeRejoin = &netGameStart->gameStartMode.choice.gameStartModeRejoin; + + // Send player data to client. + PlayerListIterator player_i = curGame.getSeatsList()->begin(); + PlayerListIterator player_end = curGame.getSeatsList()->end(); + while (player_i != player_end) { + boost::shared_ptr tmpPlayer = *player_i; + if (tmpPlayer->getMyActiveStatus()) { + RejoinPlayerData_t *playerSlot = (RejoinPlayerData_t *)calloc(1, sizeof(RejoinPlayerData_t)); + playerSlot->playerId = tmpPlayer->getMyUniqueID(); + playerSlot->playerMoney = tmpPlayer->getMyCash(); + ASN_SEQUENCE_ADD(&netStartModeRejoin->rejoinPlayerData.list, playerSlot); + } + ++player_i; + } + + server->GetLobbyThread().GetSender().Send(session, packet); + } + ++i; + } + } // HACK: Skip GUI notification run curGame.getCurrentHand()->getFlop()->skipFirstRunGui(); diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 713953c6..2a14ded5 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -1314,13 +1314,7 @@ ServerLobbyThread::HandleNetPacketRejoinGame(boost::shared_ptr sess 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); - } + MoveSessionToGame(game, session, autoLeave); } else { SendJoinGameFailed(session, rejoinGame.gameId, NTF_NET_JOIN_GAME_INVALID); } diff --git a/src/net/servergame.h b/src/net/servergame.h index 2c693c68..406464ce 100644 --- a/src/net/servergame.h +++ b/src/net/servergame.h @@ -87,6 +87,9 @@ public: void SetPlayerAutoLeaveOnFinish(unsigned playerId); + void AddRejoinPlayer(unsigned playerId); + PlayerIdList GetAndResetRejoinPlayers(); + unsigned GetSmallDelaySec() const; // should be protected, but is needed in function. @@ -173,6 +176,9 @@ private: PlayerIdList m_autoLeavePlayerList; mutable boost::mutex m_autoLeavePlayerListMutex; + PlayerIdList m_rejoinPlayerList; + mutable boost::mutex m_rejoinPlayerListMutex; + PlayerIdList m_reportedAvatarList; RankingMap m_rankingMap; diff --git a/src/net/servergamestate.h b/src/net/servergamestate.h index 2385aae2..bec099a8 100644 --- a/src/net/servergamestate.h +++ b/src/net/servergamestate.h @@ -64,6 +64,8 @@ public: // Calls InternalProcess if packet has not been processed. virtual void ProcessPacket(boost::shared_ptr server, boost::shared_ptr session, boost::shared_ptr packet); + static boost::shared_ptr CreateNetPacketPlayerJoined(unsigned gameId, const PlayerData &playerData); + protected: virtual void InternalProcessPacket(boost::shared_ptr server, boost::shared_ptr session, boost::shared_ptr packet) = 0; @@ -98,8 +100,6 @@ protected: virtual void InternalProcessPacket(boost::shared_ptr server, boost::shared_ptr session, boost::shared_ptr packet); - static boost::shared_ptr CreateNetPacketPlayerJoined(unsigned gameId, const PlayerData &playerData); - private: static ServerGameStateInit s_state; };