diff --git a/pokerth.proto b/pokerth.proto index f8563d69..3f7632b3 100644 --- a/pokerth.proto +++ b/pokerth.proto @@ -223,6 +223,7 @@ message GameListNewMessage { repeated uint32 playerIds = 4 [packed = true]; required uint32 adminPlayerId = 5; required NetGameInfo gameInfo = 6; + repeated uint32 spectatorIds = 7 [packed = true]; } message GameListUpdateMessage { @@ -288,8 +289,8 @@ message SubscriptionRequestMessage { message JoinExistingGameMessage { required uint32 gameId = 1; optional string password = 2; - optional bool autoLeave = 3; - optional bool spectateOnly = 4; + optional bool autoLeave = 3 [default = false]; + optional bool spectateOnly = 4 [default = false]; } message JoinNewGameMessage { diff --git a/src/net/common/servergame.cpp b/src/net/common/servergame.cpp index 4e6cbcb0..d09aa757 100644 --- a/src/net/common/servergame.cpp +++ b/src/net/common/servergame.cpp @@ -178,13 +178,13 @@ ServerGame::GetCurRound() const } void -ServerGame::SendToAllPlayers(boost::shared_ptr packet, SessionData::State state) +ServerGame::SendToAllPlayers(boost::shared_ptr packet, int state) { GetSessionManager().SendToAllSessions(GetLobbyThread().GetSender(), packet, state); } void -ServerGame::SendToAllButOnePlayers(boost::shared_ptr packet, SessionId except, SessionData::State state) +ServerGame::SendToAllButOnePlayers(boost::shared_ptr packet, SessionId except, int state) { GetSessionManager().SendToAllButOneSessions(GetLobbyThread().GetSender(), packet, except, state); } @@ -625,6 +625,12 @@ ServerGame::GetPlayerIdList() const return idList; } +PlayerIdList +ServerGame::GetSpectatorIdList() const +{ + return GetSessionManager().GetPlayerIdList(SessionData::Spectating); +} + bool ServerGame::IsPlayerConnected(const std::string &name) const { @@ -747,6 +753,22 @@ ServerGame::GetAndResetReactivatePlayers() return tmpList; } +void +ServerGame::AddNewSpectator(unsigned playerId) +{ + boost::mutex::scoped_lock lock(m_newSpectatorListMutex); + m_newSpectatorList.push_back(playerId); +} + +PlayerIdList +ServerGame::GetAndResetNewSpectators() +{ + boost::mutex::scoped_lock lock(m_newSpectatorListMutex); + PlayerIdList tmpList(m_newSpectatorList); + m_newSpectatorList.clear(); + return tmpList; +} + void ServerGame::SetNameReported() { diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index 374b1f01..c1bc64c8 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -102,7 +102,7 @@ static void SendPlayerAction(ServerGame &server, boost::shared_ptrset_playerid(player->getMyUniqueID()); netActionDone->set_playermoney(player->getMyCash()); netActionDone->set_totalplayerbet(player->getMySet()); - server.SendToAllPlayers(packet, SessionData::Game); + server.SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating); } static void SendNewRoundCards(ServerGame &server, Game &curGame, int state) @@ -122,7 +122,7 @@ static void SendNewRoundCards(ServerGame &server, Game &curGame, int state) netDealFlop->set_flopcard1(cards[0]); netDealFlop->set_flopcard2(cards[1]); netDealFlop->set_flopcard3(cards[2]); - server.SendToAllPlayers(packet, SessionData::Game); + server.SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating); } break; case GAME_STATE_TURN: { @@ -132,7 +132,7 @@ static void SendNewRoundCards(ServerGame &server, Game &curGame, int state) DealTurnCardMessage *netDealTurn = packet->GetMsg()->mutable_dealturncardmessage(); netDealTurn->set_gameid(server.GetId()); netDealTurn->set_turncard(cards[3]); - server.SendToAllPlayers(packet, SessionData::Game); + server.SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating); } break; case GAME_STATE_RIVER: { @@ -142,7 +142,7 @@ static void SendNewRoundCards(ServerGame &server, Game &curGame, int state) DealRiverCardMessage *netDealRiver = packet->GetMsg()->mutable_dealrivercardmessage(); netDealRiver->set_gameid(server.GetId()); netDealRiver->set_rivercard(cards[4]); - server.SendToAllPlayers(packet, SessionData::Game); + server.SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating); } break; default: { @@ -286,7 +286,7 @@ AbstractServerGameStateReceiving::ProcessPacket(boost::shared_ptr se netChat->set_playerid(session->GetPlayerData()->GetUniqueId()); netChat->set_chattype(ChatMessage::chatTypeGame); netChat->set_chattext(netChatRequest.chattext()); - server->SendToAllPlayers(packet, SessionData::Game); + server->SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating); chatSent = true; // Send the message to the chat cleaner bot for ranking games. @@ -410,6 +410,37 @@ AbstractServerGameStateReceiving::CreateNetPacketJoinGameAck(const ServerGame &s return packet; } +boost::shared_ptr +AbstractServerGameStateReceiving::CreateNetPacketHandStart(const ServerGame &server) +{ + const Game &curGame = server.GetGame(); + + boost::shared_ptr notifyCards(new NetPacket); + notifyCards->GetMsg()->set_messagetype(PokerTHMessage::Type_HandStartMessage); + HandStartMessage *netHandStart = notifyCards->GetMsg()->mutable_handstartmessage(); + netHandStart->set_gameid(server.GetId()); + + PlayerListIterator player_i = curGame.getSeatsList()->begin(); + PlayerListIterator player_end = curGame.getSeatsList()->end(); + int playerCounter = 0; + while (player_i != player_end && playerCounter < server.GetStartData().numberOfPlayers) { + NetPlayerState seatState; + if (!(*player_i)->getMyActiveStatus()) { + seatState = netPlayerStateNoMoney; + } else if (!(*player_i)->isSessionActive()) { + seatState = netPlayerStateSessionInactive; + } else { + seatState = netPlayerStateNormal; + } + netHandStart->add_seatstates(seatState); + ++player_i; + ++playerCounter; + } + + netHandStart->set_smallblind(curGame.getCurrentHand()->getSmallBlind()); + return notifyCards; +} + void AbstractServerGameStateReceiving::AcceptNewSession(boost::shared_ptr server, boost::shared_ptr session, bool spectateOnly) { @@ -430,9 +461,9 @@ AbstractServerGameStateReceiving::AcceptNewSession(boost::shared_ptr // Send "Player Joined"/"Spectator Joined" to other fully connected clients. if (spectateOnly) { - server->SendToAllPlayers(CreateNetPacketSpectatorJoined(server->GetId(), *session->GetPlayerData()), SessionData::Game); + server->SendToAllPlayers(CreateNetPacketSpectatorJoined(server->GetId(), *session->GetPlayerData()), SessionData::Game | SessionData::Spectating); } else { - server->SendToAllPlayers(CreateNetPacketPlayerJoined(server->GetId(), *session->GetPlayerData()), SessionData::Game); + server->SendToAllPlayers(CreateNetPacketPlayerJoined(server->GetId(), *session->GetPlayerData()), SessionData::Game | SessionData::Spectating); } // Accept session. @@ -513,6 +544,9 @@ ServerGameStateInit::HandleNewPlayer(boost::shared_ptr server, boost void ServerGameStateInit::HandleNewSpectator(boost::shared_ptr server, boost::shared_ptr session) { + if (session && session->GetPlayerData()) { + AcceptNewSession(server, session, true); + } } void @@ -613,7 +647,7 @@ ServerGameStateInit::SendStartEvent(ServerGame &server, bool fillWithComputerPla server.AddComputerPlayer(tmpPlayerData); // Send "Player Joined" to other fully connected clients. - server.SendToAllPlayers(CreateNetPacketPlayerJoined(server.GetId(), *tmpPlayerData), SessionData::Game); + server.SendToAllPlayers(CreateNetPacketPlayerJoined(server.GetId(), *tmpPlayerData), SessionData::Game | SessionData::Spectating); // Notify lobby. server.GetLobbyThread().NotifyPlayerJoinedGame(server.GetId(), tmpPlayerData->GetUniqueId()); @@ -735,6 +769,9 @@ ServerGameStateStartGame::HandleNewPlayer(boost::shared_ptr server, void ServerGameStateStartGame::HandleNewSpectator(boost::shared_ptr server, boost::shared_ptr session) { + if (session && session->GetPlayerData()) { + AcceptNewSession(server, session, false); + } } void @@ -789,7 +826,7 @@ ServerGameStateStartGame::DoStart(boost::shared_ptr server) ++player_i; } - server->SendToAllPlayers(packet, SessionData::Game); + server->SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating); // Start the first hand. ServerGameStateHand::StartNewHand(server); @@ -835,6 +872,10 @@ AbstractServerGameStateRunning::HandleNewPlayer(boost::shared_ptr se void AbstractServerGameStateRunning::HandleNewSpectator(boost::shared_ptr server, boost::shared_ptr session) { + if (session && session->GetPlayerData()) { + AcceptNewSession(server, session, false); + server->AddNewSpectator(session->GetPlayerData()->GetUniqueId()); + } } void @@ -941,7 +982,7 @@ ServerGameStateHand::EngineLoop(boost::shared_ptr server) playerAllIn->set_allincard2(tmpCards[1]); ++i; } - server->SendToAllPlayers(allIn, SessionData::Game); + server->SendToAllPlayers(allIn, SessionData::Game | SessionData::Spectating); curGame.getCurrentHand()->setCardsShown(true); server->GetStateTimer1().expires_from_now( @@ -976,7 +1017,7 @@ ServerGameStateHand::EngineLoop(boost::shared_ptr server) netPlayersTurn->set_gameid(server->GetId()); netPlayersTurn->set_gamestate(static_cast(curGame.getCurrentHand()->getCurrentRound())); netPlayersTurn->set_playerid(curPlayer->getMyUniqueID()); - server->SendToAllPlayers(notification, SessionData::Game); + server->SendToAllPlayers(notification, SessionData::Game | SessionData::Spectating); // If the player is computer controlled, let the engine act. if (curPlayer->getMyType() == PLAYER_TYPE_COMPUTER) { @@ -1018,7 +1059,7 @@ ServerGameStateHand::EngineLoop(boost::shared_ptr server) netEndHand->set_playerid(player->getMyUniqueID()); netEndHand->set_moneywon(player->getLastMoneyWon()); netEndHand->set_playermoney(player->getMyCash()); - server->SendToAllPlayers(endHand, SessionData::Game); + server->SendToAllPlayers(endHand, SessionData::Game | SessionData::Spectating); } else { // End of Hand - show cards. const PlayerIdList showList(curGame.getCurrentHand()->getBoard()->getPlayerNeedToShowCards()); @@ -1038,7 +1079,7 @@ ServerGameStateHand::EngineLoop(boost::shared_ptr server) } ++i; } - server->SendToAllPlayers(endHand, SessionData::Game); + server->SendToAllPlayers(endHand, SessionData::Game | SessionData::Spectating); } // Remove disconnected players. This is the one and only place to do this. @@ -1123,7 +1164,7 @@ ServerGameStateHand::TimerNextGame(const boost::system::error_code &ec, boost::s EndOfGameMessage *netEndGame = endGame->GetMsg()->mutable_endofgamemessage(); netEndGame->set_gameid(server->GetId()); netEndGame->set_winnerplayerid(winnerPlayerId); - server->SendToAllPlayers(endGame, SessionData::Game); + server->SendToAllPlayers(endGame, SessionData::Game | SessionData::Spectating); // Wait for the start of a new game. server->RemoveAutoLeavePlayers(); @@ -1168,6 +1209,9 @@ ServerGameStateHand::StartNewHand(boost::shared_ptr server) // This has to be done before initialising the new hand, because there are side effects. InitRejoiningPlayers(server); + // Initialize new spectators. + InitNewSpectators(server); + // Kick inactive players. CheckPlayerTimeouts(server); @@ -1193,10 +1237,8 @@ ServerGameStateHand::StartNewHand(boost::shared_ptr server) bool errorFlag = false; tmpPlayer->getMyCards(cards); - boost::shared_ptr notifyCards(new NetPacket); - notifyCards->GetMsg()->set_messagetype(PokerTHMessage::Type_HandStartMessage); + boost::shared_ptr notifyCards = CreateNetPacketHandStart(*server); HandStartMessage *netHandStart = notifyCards->GetMsg()->mutable_handstartmessage(); - netHandStart->set_gameid(server->GetId()); string tmpPassword(tmpSession->AuthGetPassword()); if (tmpPassword.empty()) { // encrypt only if password is present HandStartMessage::PlainCards *plainCards = netHandStart->mutable_plaincards(); @@ -1222,30 +1264,14 @@ ServerGameStateHand::StartNewHand(boost::shared_ptr server) errorFlag = true; } } - PlayerListIterator player_i = curGame.getSeatsList()->begin(); - PlayerListIterator player_end = curGame.getSeatsList()->end(); - int playerCounter = 0; - while (player_i != player_end && playerCounter < server->GetStartData().numberOfPlayers) { - NetPlayerState seatState; - if (!(*player_i)->getMyActiveStatus()) { - seatState = netPlayerStateNoMoney; - } else if (!(*player_i)->isSessionActive()) { - seatState = netPlayerStateSessionInactive; - } else { - seatState = netPlayerStateNormal; - } - netHandStart->add_seatstates(seatState); - ++player_i; - ++playerCounter; - } if (!errorFlag) { - netHandStart->set_smallblind(curGame.getCurrentHand()->getSmallBlind()); server->GetLobbyThread().GetSender().Send(tmpSession, notifyCards); } } ++i; } + server->SendToAllPlayers(CreateNetPacketHandStart(*server), SessionData::Spectating); // Start hand. curGame.startHand(); @@ -1268,7 +1294,7 @@ ServerGameStateHand::StartNewHand(boost::shared_ptr server) netSmallBlind->set_playermoney(tmpPlayer->getMyCash()); netSmallBlind->set_highestset(server->GetGame().getCurrentHand()->getCurrentBeRo()->getHighestSet()); netSmallBlind->set_minimumraise(server->GetGame().getCurrentHand()->getCurrentBeRo()->getMinimumRaise()); - server->SendToAllPlayers(notifySmallBlind, SessionData::Game); + server->SendToAllPlayers(notifySmallBlind, SessionData::Game | SessionData::Spectating); break; } ++i; @@ -1290,7 +1316,7 @@ ServerGameStateHand::StartNewHand(boost::shared_ptr server) netBigBlind->set_playermoney(tmpPlayer->getMyCash()); netBigBlind->set_highestset(server->GetGame().getCurrentHand()->getCurrentBeRo()->getHighestSet()); netBigBlind->set_minimumraise(server->GetGame().getCurrentHand()->getCurrentBeRo()->getMinimumRaise()); - server->SendToAllPlayers(notifyBigBlind, SessionData::Game); + server->SendToAllPlayers(notifyBigBlind, SessionData::Game | SessionData::Spectating); break; } ++i; @@ -1364,6 +1390,21 @@ ServerGameStateHand::InitRejoiningPlayers(boost::shared_ptr server) } } +void +ServerGameStateHand::InitNewSpectators(boost::shared_ptr server) +{ + PlayerIdList spectatorIdList(server->GetAndResetNewSpectators()); + PlayerIdList::iterator i = spectatorIdList.begin(); + PlayerIdList::iterator end = spectatorIdList.end(); + while (i != end) { + boost::shared_ptr session(server->GetSessionManager().GetSessionByUniquePlayerId(*i)); + if (session && session->GetPlayerData()) { + SendGameData(server, session); + } + ++i; + } +} + void ServerGameStateHand::PerformRejoin(boost::shared_ptr server, boost::shared_ptr session) { @@ -1377,7 +1418,7 @@ ServerGameStateHand::PerformRejoin(boost::shared_ptr server, boost:: PlayerIdChangedMessage *netIdChanged = packet->GetMsg()->mutable_playeridchangedmessage(); netIdChanged->set_oldplayerid(rejoinPlayer->getMyUniqueID()); netIdChanged->set_newplayerid(session->GetPlayerData()->GetUniqueId()); - server->SendToAllButOnePlayers(packet, session->GetId(), SessionData::Game); + server->SendToAllButOnePlayers(packet, session->GetId(), SessionData::Game | SessionData::Spectating); // Update the dealer, if necessary. curGame.replaceDealer(rejoinPlayer->getMyUniqueID(), session->GetPlayerData()->GetUniqueId()); @@ -1388,32 +1429,38 @@ ServerGameStateHand::PerformRejoin(boost::shared_ptr server, boost:: rejoinPlayer->setMyGuid(session->GetPlayerData()->GetGuid()); rejoinPlayer->markRemoteAction(); rejoinPlayer->setIsSessionActive(true); - - // Send game start notification to rejoining client. - packet.reset(new NetPacket); - packet->GetMsg()->set_messagetype(PokerTHMessage::Type_GameStartRejoinMessage); - GameStartRejoinMessage *netGameStart = packet->GetMsg()->mutable_gamestartrejoinmessage(); - netGameStart->set_gameid(server->GetId()); - netGameStart->set_startdealerplayerid(curGame.getDealerPosition()); - netGameStart->set_handnum(curGame.getCurrentHandID()); - PlayerListIterator player_i = curGame.getSeatsList()->begin(); - PlayerListIterator player_end = curGame.getSeatsList()->end(); - int player_count = 0; - while (player_i != player_end && player_count < server->GetStartData().numberOfPlayers) { - boost::shared_ptr tmpPlayer = *player_i; - GameStartRejoinMessage::RejoinPlayerData *playerSlot = netGameStart->add_rejoinplayerdata(); - playerSlot->set_playerid(tmpPlayer->getMyUniqueID()); - playerSlot->set_playermoney(tmpPlayer->getMyCash()); - ++player_i; - ++player_count; - } - - server->GetLobbyThread().GetSender().Send(session, packet); + SendGameData(server, session); } else { server->SessionError(session, ERR_SOCK_INVALID_STATE); } } +void +ServerGameStateHand::SendGameData(boost::shared_ptr server, boost::shared_ptr session) +{ + Game &curGame = server->GetGame(); + // Send game start notification to rejoining client. + boost::shared_ptr packet(new NetPacket); + packet->GetMsg()->set_messagetype(PokerTHMessage::Type_GameStartRejoinMessage); + GameStartRejoinMessage *netGameStart = packet->GetMsg()->mutable_gamestartrejoinmessage(); + netGameStart->set_gameid(server->GetId()); + netGameStart->set_startdealerplayerid(curGame.getDealerPosition()); + netGameStart->set_handnum(curGame.getCurrentHandID()); + PlayerListIterator player_i = curGame.getSeatsList()->begin(); + PlayerListIterator player_end = curGame.getSeatsList()->end(); + int player_count = 0; + while (player_i != player_end && player_count < server->GetStartData().numberOfPlayers) { + boost::shared_ptr tmpPlayer = *player_i; + GameStartRejoinMessage::RejoinPlayerData *playerSlot = netGameStart->add_rejoinplayerdata(); + playerSlot->set_playerid(tmpPlayer->getMyUniqueID()); + playerSlot->set_playermoney(tmpPlayer->getMyCash()); + ++player_i; + ++player_count; + } + + server->GetLobbyThread().GetSender().Send(session, packet); +} + //----------------------------------------------------------------------------- @@ -1604,7 +1651,7 @@ ServerGameStateWaitNextHand::InternalProcessPacket(boost::shared_ptr boost::shared_ptr tmpPlayer(curGame.getPlayerByUniqueId(session->GetPlayerData()->GetUniqueId())); if (tmpPlayer) { SetPlayerResult(*netShowCards->mutable_playerresult(), tmpPlayer, curGame.getCurrentHand()->getRoundBeforePostRiver()); - server->SendToAllPlayers(show, SessionData::Game); + server->SendToAllPlayers(show, SessionData::Game | SessionData::Spectating); } } } diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 9b42e3b9..b96d6f55 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -426,7 +426,7 @@ ServerLobbyThread::NotifyPlayerJoinedLobby(unsigned playerId) { boost::shared_ptr notify = CreateNetPacketPlayerListNew(playerId); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Game | SessionData::Spectating); } void @@ -434,7 +434,7 @@ ServerLobbyThread::NotifyPlayerLeftLobby(unsigned playerId) { boost::shared_ptr notify = CreateNetPacketPlayerListLeft(playerId); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Game | SessionData::Spectating); } void @@ -448,7 +448,7 @@ ServerLobbyThread::NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId) netListMsg->set_playerid(playerId); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -462,7 +462,7 @@ ServerLobbyThread::NotifyPlayerLeftGame(unsigned gameId, unsigned playerId) netListMsg->set_playerid(playerId); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -476,7 +476,7 @@ ServerLobbyThread::NotifySpectatorJoinedGame(unsigned gameId, unsigned playerId) netListMsg->set_playerid(playerId); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -490,7 +490,7 @@ ServerLobbyThread::NotifySpectatorLeftGame(unsigned gameId, unsigned playerId) netListMsg->set_playerid(playerId); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -505,7 +505,7 @@ ServerLobbyThread::NotifyGameAdminChanged(unsigned gameId, unsigned newAdminPlay netListMsg->set_newadminplayerid(newAdminPlayerId); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -513,7 +513,7 @@ ServerLobbyThread::NotifyStartingGame(unsigned gameId) { boost::shared_ptr packet = CreateNetPacketGameListUpdate(gameId, GAME_MODE_STARTED); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -521,7 +521,7 @@ ServerLobbyThread::NotifyReopeningGame(unsigned gameId) { boost::shared_ptr packet = CreateNetPacketGameListUpdate(gameId, GAME_MODE_CREATED); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -649,7 +649,7 @@ ServerLobbyThread::SendGlobalChat(const string &message) netChat->set_chattext(message); m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -661,7 +661,7 @@ ServerLobbyThread::SendGlobalMsgBox(const string &message) netDialog->set_notificationtext(message); m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -674,7 +674,7 @@ ServerLobbyThread::SendChatBotMsg(const std::string &message) netChat->set_chattext(message); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); GetIrcBotCallback().SignalLobbyMessage( 0, @@ -694,7 +694,7 @@ ServerLobbyThread::SendChatBotMsg(unsigned gameId, const std::string &message) GameMap::const_iterator pos = m_gameMap.find(gameId); if (pos != m_gameMap.end()) { - pos->second->SendToAllPlayers(packet, SessionData::Game); + pos->second->SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating); } } @@ -1415,7 +1415,7 @@ ServerLobbyThread::HandleNetPacketChatRequest(boost::shared_ptr ses netChat->set_chattext(chatMsg); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); // Send the message to the chat cleaner bot. m_chatCleanerManager->HandleLobbyChatText( @@ -1481,7 +1481,7 @@ ServerLobbyThread::HandleNetPacketRejectGameInvitation(boost::shared_ptrset_playerid(tmpPlayerId); netReject->set_playerrejectreason(reject.myrejectreason()); - game.SendToAllPlayers(packet, SessionData::Game); + game.SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating); } } } @@ -1902,7 +1902,7 @@ ServerLobbyThread::InternalAddGame(boost::shared_ptr game) m_gameMap.insert(GameMap::value_type(game->GetId(), game)); // Notify all players. m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Game | SessionData::Spectating); { boost::mutex::scoped_lock lock(m_statMutex); @@ -1934,7 +1934,7 @@ ServerLobbyThread::InternalRemoveGame(boost::shared_ptr game) // Notify all players. boost::shared_ptr packet = CreateNetPacketGameListUpdate(game->GetId(), GAME_MODE_CLOSED); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } void @@ -2098,7 +2098,7 @@ ServerLobbyThread::SendPlayerList(boost::shared_ptr s) { // Retrieve all player ids. PlayerIdList idList(m_sessionManager.GetPlayerIdList(SessionData::Established)); - PlayerIdList gameIdList(m_gameSessionManager.GetPlayerIdList(SessionData::Game)); + PlayerIdList gameIdList(m_gameSessionManager.GetPlayerIdList(SessionData::Game | SessionData::Spectating)); idList.splice(idList.begin(), gameIdList); // Send all player ids to client. PlayerIdList::const_iterator i = idList.begin(); @@ -2152,7 +2152,7 @@ ServerLobbyThread::BroadcastStatisticsUpdate(const ServerStats &stats) data->set_statisticsvalue(m_sessionManager.GetRawSessionCount() + m_gameSessionManager.GetRawSessionCount()); m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating); } } @@ -2293,6 +2293,14 @@ ServerLobbyThread::CreateNetPacketGameListNew(const ServerGame &game) ++i; } + tmpList = game.GetSpectatorIdList(); + i = tmpList.begin(); + end = tmpList.end(); + while (i != end) { + netGameList->add_spectatorids(*i); + ++i; + } + return packet; } diff --git a/src/net/servergame.h b/src/net/servergame.h index 6d74b4d8..16a8b694 100644 --- a/src/net/servergame.h +++ b/src/net/servergame.h @@ -77,8 +77,8 @@ public: ServerCallback &GetCallback(); GameState GetCurRound() const; - void SendToAllPlayers(boost::shared_ptr packet, SessionData::State state); - void SendToAllButOnePlayers(boost::shared_ptr packet, SessionId except, SessionData::State state); + void SendToAllPlayers(boost::shared_ptr packet, int state); + void SendToAllButOnePlayers(boost::shared_ptr packet, SessionId except, int state); void RemoveAllSessions(); bool IsPasswordProtected() const; @@ -88,6 +88,7 @@ public: boost::shared_ptr GetPlayerDataByUniqueId(unsigned playerId) const; PlayerIdList GetPlayerIdList() const; + PlayerIdList GetSpectatorIdList() const; bool IsPlayerConnected(const std::string &name) const; bool IsPlayerConnected(unsigned playerId) const; bool IsClientAddressConnected(const std::string &clientAddress) const; @@ -111,6 +112,9 @@ public: void AddReactivatePlayer(unsigned playerId); PlayerIdList GetAndResetReactivatePlayers(); + void AddNewSpectator(unsigned playerId); + PlayerIdList GetAndResetNewSpectators(); + void SetNameReported(); bool IsNameReported() const; @@ -205,6 +209,9 @@ private: PlayerIdList m_reactivatePlayerList; mutable boost::mutex m_reactivatePlayerListMutex; + PlayerIdList m_newSpectatorList; + mutable boost::mutex m_newSpectatorListMutex; + PlayerIdList m_reportedAvatarList; RankingMap m_rankingMap; diff --git a/src/net/servergamestate.h b/src/net/servergamestate.h index 3999a3bd..83058267 100644 --- a/src/net/servergamestate.h +++ b/src/net/servergamestate.h @@ -82,6 +82,7 @@ public: static boost::shared_ptr CreateNetPacketPlayerJoined(unsigned gameId, const PlayerData &playerData); static boost::shared_ptr CreateNetPacketSpectatorJoined(unsigned gameId, const PlayerData &playerData); static boost::shared_ptr CreateNetPacketJoinGameAck(const ServerGame &server, const PlayerData &playerData, bool spectateOnly); + static boost::shared_ptr CreateNetPacketHandStart(const ServerGame &server); static void AcceptNewSession(boost::shared_ptr server, boost::shared_ptr session, bool spectateOnly); @@ -190,7 +191,9 @@ protected: static void CheckPlayerTimeouts(boost::shared_ptr server); static void ReactivatePlayers(boost::shared_ptr server); static void InitRejoiningPlayers(boost::shared_ptr server); + static void InitNewSpectators(boost::shared_ptr server); static void PerformRejoin(boost::shared_ptr server, boost::shared_ptr session); + static void SendGameData(boost::shared_ptr server, boost::shared_ptr session); private: static ServerGameStateHand s_state; diff --git a/src/third_party/protobuf/pokerth.pb.cc b/src/third_party/protobuf/pokerth.pb.cc index 0f3c20e9..872ff030 100644 --- a/src/third_party/protobuf/pokerth.pb.cc +++ b/src/third_party/protobuf/pokerth.pb.cc @@ -4569,6 +4569,7 @@ const int GameListNewMessage::kIsPrivateFieldNumber; const int GameListNewMessage::kPlayerIdsFieldNumber; const int GameListNewMessage::kAdminPlayerIdFieldNumber; const int GameListNewMessage::kGameInfoFieldNumber; +const int GameListNewMessage::kSpectatorIdsFieldNumber; #endif // !_MSC_VER GameListNewMessage::GameListNewMessage() @@ -4646,6 +4647,7 @@ void GameListNewMessage::Clear() { } } playerids_.Clear(); + spectatorids_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -4752,6 +4754,27 @@ bool GameListNewMessage::MergePartialFromCodedStream( } else { goto handle_uninterpreted; } + if (input->ExpectTag(58)) goto parse_spectatorIds; + break; + } + + // repeated uint32 spectatorIds = 7 [packed = true]; + case 7: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_spectatorIds: + DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive< + ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( + input, this->mutable_spectatorids()))); + } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) + == ::google::protobuf::internal::WireFormatLite:: + WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline< + ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( + 1, 58, input, this->mutable_spectatorids()))); + } else { + goto handle_uninterpreted; + } if (input->ExpectAtEnd()) return true; break; } @@ -4810,6 +4833,16 @@ void GameListNewMessage::SerializeWithCachedSizes( 6, this->gameinfo(), output); } + // repeated uint32 spectatorIds = 7 [packed = true]; + if (this->spectatorids_size() > 0) { + ::google::protobuf::internal::WireFormatLite::WriteTag(7, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(_spectatorids_cached_byte_size_); + } + for (int i = 0; i < this->spectatorids_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteUInt32NoTag( + this->spectatorids(i), output); + } + } int GameListNewMessage::ByteSize() const { @@ -4866,6 +4899,23 @@ int GameListNewMessage::ByteSize() const { total_size += data_size; } + // repeated uint32 spectatorIds = 7 [packed = true]; + { + int data_size = 0; + for (int i = 0; i < this->spectatorids_size(); i++) { + data_size += ::google::protobuf::internal::WireFormatLite:: + UInt32Size(this->spectatorids(i)); + } + if (data_size > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size(data_size); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _spectatorids_cached_byte_size_ = data_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + total_size += data_size; + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; GOOGLE_SAFE_CONCURRENT_WRITES_END(); @@ -4880,6 +4930,7 @@ void GameListNewMessage::CheckTypeAndMergeFrom( void GameListNewMessage::MergeFrom(const GameListNewMessage& from) { GOOGLE_CHECK_NE(&from, this); playerids_.MergeFrom(from.playerids_); + spectatorids_.MergeFrom(from.spectatorids_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_gameid()) { set_gameid(from.gameid()); @@ -4922,6 +4973,7 @@ void GameListNewMessage::Swap(GameListNewMessage* other) { playerids_.Swap(&other->playerids_); std::swap(adminplayerid_, other->adminplayerid_); std::swap(gameinfo_, other->gameinfo_); + spectatorids_.Swap(&other->spectatorids_); std::swap(_has_bits_[0], other->_has_bits_[0]); std::swap(_cached_size_, other->_cached_size_); } @@ -7394,7 +7446,7 @@ bool JoinExistingGameMessage::MergePartialFromCodedStream( break; } - // optional bool autoLeave = 3; + // optional bool autoLeave = 3 [default = false]; case 3: { if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { @@ -7410,7 +7462,7 @@ bool JoinExistingGameMessage::MergePartialFromCodedStream( break; } - // optional bool spectateOnly = 4; + // optional bool spectateOnly = 4 [default = false]; case 4: { if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { @@ -7454,12 +7506,12 @@ void JoinExistingGameMessage::SerializeWithCachedSizes( 2, this->password(), output); } - // optional bool autoLeave = 3; + // optional bool autoLeave = 3 [default = false]; if (has_autoleave()) { ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->autoleave(), output); } - // optional bool spectateOnly = 4; + // optional bool spectateOnly = 4 [default = false]; if (has_spectateonly()) { ::google::protobuf::internal::WireFormatLite::WriteBool(4, this->spectateonly(), output); } @@ -7484,12 +7536,12 @@ int JoinExistingGameMessage::ByteSize() const { this->password()); } - // optional bool autoLeave = 3; + // optional bool autoLeave = 3 [default = false]; if (has_autoleave()) { total_size += 1 + 1; } - // optional bool spectateOnly = 4; + // optional bool spectateOnly = 4 [default = false]; if (has_spectateonly()) { total_size += 1 + 1; } diff --git a/src/third_party/protobuf/pokerth.pb.h b/src/third_party/protobuf/pokerth.pb.h index 95a07c44..2e791ee4 100644 --- a/src/third_party/protobuf/pokerth.pb.h +++ b/src/third_party/protobuf/pokerth.pb.h @@ -2443,6 +2443,18 @@ class GameListNewMessage : public ::google::protobuf::MessageLite { inline ::NetGameInfo* release_gameinfo(); inline void set_allocated_gameinfo(::NetGameInfo* gameinfo); + // repeated uint32 spectatorIds = 7 [packed = true]; + inline int spectatorids_size() const; + inline void clear_spectatorids(); + static const int kSpectatorIdsFieldNumber = 7; + inline ::google::protobuf::uint32 spectatorids(int index) const; + inline void set_spectatorids(int index, ::google::protobuf::uint32 value); + inline void add_spectatorids(::google::protobuf::uint32 value); + inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >& + spectatorids() const; + inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >* + mutable_spectatorids(); + // @@protoc_insertion_point(class_scope:GameListNewMessage) private: inline void set_has_gameid(); @@ -2463,9 +2475,11 @@ class GameListNewMessage : public ::google::protobuf::MessageLite { bool isprivate_; ::google::protobuf::uint32 adminplayerid_; ::NetGameInfo* gameinfo_; + ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > spectatorids_; + mutable int _spectatorids_cached_byte_size_; mutable int _cached_size_; - ::google::protobuf::uint32 _has_bits_[(6 + 31) / 32]; + ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32]; #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER friend void protobuf_AddDesc_pokerth_2eproto_impl(); @@ -3625,14 +3639,14 @@ class JoinExistingGameMessage : public ::google::protobuf::MessageLite { inline ::std::string* release_password(); inline void set_allocated_password(::std::string* password); - // optional bool autoLeave = 3; + // optional bool autoLeave = 3 [default = false]; inline bool has_autoleave() const; inline void clear_autoleave(); static const int kAutoLeaveFieldNumber = 3; inline bool autoleave() const; inline void set_autoleave(bool value); - // optional bool spectateOnly = 4; + // optional bool spectateOnly = 4 [default = false]; inline bool has_spectateonly() const; inline void clear_spectateonly(); static const int kSpectateOnlyFieldNumber = 4; @@ -13381,6 +13395,31 @@ inline void GameListNewMessage::set_allocated_gameinfo(::NetGameInfo* gameinfo) } } +// repeated uint32 spectatorIds = 7 [packed = true]; +inline int GameListNewMessage::spectatorids_size() const { + return spectatorids_.size(); +} +inline void GameListNewMessage::clear_spectatorids() { + spectatorids_.Clear(); +} +inline ::google::protobuf::uint32 GameListNewMessage::spectatorids(int index) const { + return spectatorids_.Get(index); +} +inline void GameListNewMessage::set_spectatorids(int index, ::google::protobuf::uint32 value) { + spectatorids_.Set(index, value); +} +inline void GameListNewMessage::add_spectatorids(::google::protobuf::uint32 value) { + spectatorids_.Add(value); +} +inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >& +GameListNewMessage::spectatorids() const { + return spectatorids_; +} +inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >* +GameListNewMessage::mutable_spectatorids() { + return &spectatorids_; +} + // ------------------------------------------------------------------- // GameListUpdateMessage @@ -14218,7 +14257,7 @@ inline void JoinExistingGameMessage::set_allocated_password(::std::string* passw } } -// optional bool autoLeave = 3; +// optional bool autoLeave = 3 [default = false]; inline bool JoinExistingGameMessage::has_autoleave() const { return (_has_bits_[0] & 0x00000004u) != 0; } @@ -14240,7 +14279,7 @@ inline void JoinExistingGameMessage::set_autoleave(bool value) { autoleave_ = value; } -// optional bool spectateOnly = 4; +// optional bool spectateOnly = 4 [default = false]; inline bool JoinExistingGameMessage::has_spectateonly() const { return (_has_bits_[0] & 0x00000008u) != 0; } diff --git a/tests/src/de/pokerth/protocol/ProtoBuf.java b/tests/src/de/pokerth/protocol/ProtoBuf.java index d3fb8bbb..df31b13d 100644 --- a/tests/src/de/pokerth/protocol/ProtoBuf.java +++ b/tests/src/de/pokerth/protocol/ProtoBuf.java @@ -10182,6 +10182,20 @@ public final class ProtoBuf { * required .NetGameInfo gameInfo = 6; */ de.pokerth.protocol.ProtoBuf.NetGameInfo getGameInfo(); + + // repeated uint32 spectatorIds = 7 [packed = true]; + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + java.util.List getSpectatorIdsList(); + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + int getSpectatorIdsCount(); + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + int getSpectatorIds(int index); } /** * Protobuf type {@code GameListNewMessage} @@ -10284,6 +10298,27 @@ public final class ProtoBuf { bitField0_ |= 0x00000010; break; } + case 56: { + if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) { + spectatorIds_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000040; + } + spectatorIds_.add(input.readUInt32()); + break; + } + case 58: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000040) == 0x00000040) && input.getBytesUntilLimit() > 0) { + spectatorIds_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000040; + } + while (input.getBytesUntilLimit() > 0) { + spectatorIds_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -10295,6 +10330,9 @@ public final class ProtoBuf { if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { playerIds_ = java.util.Collections.unmodifiableList(playerIds_); } + if (((mutable_bitField0_ & 0x00000040) == 0x00000040)) { + spectatorIds_ = java.util.Collections.unmodifiableList(spectatorIds_); + } makeExtensionsImmutable(); } } @@ -10418,6 +10456,30 @@ public final class ProtoBuf { return gameInfo_; } + // repeated uint32 spectatorIds = 7 [packed = true]; + public static final int SPECTATORIDS_FIELD_NUMBER = 7; + private java.util.List spectatorIds_; + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public java.util.List + getSpectatorIdsList() { + return spectatorIds_; + } + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public int getSpectatorIdsCount() { + return spectatorIds_.size(); + } + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public int getSpectatorIds(int index) { + return spectatorIds_.get(index); + } + private int spectatorIdsMemoizedSerializedSize = -1; + private void initFields() { gameId_ = 0; gameMode_ = de.pokerth.protocol.ProtoBuf.NetGameMode.netGameCreated; @@ -10425,6 +10487,7 @@ public final class ProtoBuf { playerIds_ = java.util.Collections.emptyList(); adminPlayerId_ = 0; gameInfo_ = de.pokerth.protocol.ProtoBuf.NetGameInfo.getDefaultInstance(); + spectatorIds_ = java.util.Collections.emptyList(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -10484,6 +10547,13 @@ public final class ProtoBuf { if (((bitField0_ & 0x00000010) == 0x00000010)) { output.writeMessage(6, gameInfo_); } + if (getSpectatorIdsList().size() > 0) { + output.writeRawVarint32(58); + output.writeRawVarint32(spectatorIdsMemoizedSerializedSize); + } + for (int i = 0; i < spectatorIds_.size(); i++) { + output.writeUInt32NoTag(spectatorIds_.get(i)); + } } private int memoizedSerializedSize = -1; @@ -10526,6 +10596,20 @@ public final class ProtoBuf { size += com.google.protobuf.CodedOutputStream .computeMessageSize(6, gameInfo_); } + { + int dataSize = 0; + for (int i = 0; i < spectatorIds_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(spectatorIds_.get(i)); + } + size += dataSize; + if (!getSpectatorIdsList().isEmpty()) { + size += 1; + size += com.google.protobuf.CodedOutputStream + .computeInt32SizeNoTag(dataSize); + } + spectatorIdsMemoizedSerializedSize = dataSize; + } memoizedSerializedSize = size; return size; } @@ -10629,6 +10713,8 @@ public final class ProtoBuf { bitField0_ = (bitField0_ & ~0x00000010); gameInfo_ = de.pokerth.protocol.ProtoBuf.NetGameInfo.getDefaultInstance(); bitField0_ = (bitField0_ & ~0x00000020); + spectatorIds_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040); return this; } @@ -10677,6 +10763,11 @@ public final class ProtoBuf { to_bitField0_ |= 0x00000010; } result.gameInfo_ = gameInfo_; + if (((bitField0_ & 0x00000040) == 0x00000040)) { + spectatorIds_ = java.util.Collections.unmodifiableList(spectatorIds_); + bitField0_ = (bitField0_ & ~0x00000040); + } + result.spectatorIds_ = spectatorIds_; result.bitField0_ = to_bitField0_; return result; } @@ -10708,6 +10799,16 @@ public final class ProtoBuf { if (other.hasGameInfo()) { mergeGameInfo(other.getGameInfo()); } + if (!other.spectatorIds_.isEmpty()) { + if (spectatorIds_.isEmpty()) { + spectatorIds_ = other.spectatorIds_; + bitField0_ = (bitField0_ & ~0x00000040); + } else { + ensureSpectatorIdsIsMutable(); + spectatorIds_.addAll(other.spectatorIds_); + } + + } return this; } @@ -11020,6 +11121,72 @@ public final class ProtoBuf { return this; } + // repeated uint32 spectatorIds = 7 [packed = true]; + private java.util.List spectatorIds_ = java.util.Collections.emptyList(); + private void ensureSpectatorIdsIsMutable() { + if (!((bitField0_ & 0x00000040) == 0x00000040)) { + spectatorIds_ = new java.util.ArrayList(spectatorIds_); + bitField0_ |= 0x00000040; + } + } + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public java.util.List + getSpectatorIdsList() { + return java.util.Collections.unmodifiableList(spectatorIds_); + } + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public int getSpectatorIdsCount() { + return spectatorIds_.size(); + } + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public int getSpectatorIds(int index) { + return spectatorIds_.get(index); + } + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public Builder setSpectatorIds( + int index, int value) { + ensureSpectatorIdsIsMutable(); + spectatorIds_.set(index, value); + + return this; + } + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public Builder addSpectatorIds(int value) { + ensureSpectatorIdsIsMutable(); + spectatorIds_.add(value); + + return this; + } + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public Builder addAllSpectatorIds( + java.lang.Iterable values) { + ensureSpectatorIdsIsMutable(); + super.addAll(values, spectatorIds_); + + return this; + } + /** + * repeated uint32 spectatorIds = 7 [packed = true]; + */ + public Builder clearSpectatorIds() { + spectatorIds_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040); + + return this; + } + // @@protoc_insertion_point(builder_scope:GameListNewMessage) } @@ -16272,23 +16439,23 @@ public final class ProtoBuf { com.google.protobuf.ByteString getPasswordBytes(); - // optional bool autoLeave = 3; + // optional bool autoLeave = 3 [default = false]; /** - * optional bool autoLeave = 3; + * optional bool autoLeave = 3 [default = false]; */ boolean hasAutoLeave(); /** - * optional bool autoLeave = 3; + * optional bool autoLeave = 3 [default = false]; */ boolean getAutoLeave(); - // optional bool spectateOnly = 4; + // optional bool spectateOnly = 4 [default = false]; /** - * optional bool spectateOnly = 4; + * optional bool spectateOnly = 4 [default = false]; */ boolean hasSpectateOnly(); /** - * optional bool spectateOnly = 4; + * optional bool spectateOnly = 4 [default = false]; */ boolean getSpectateOnly(); } @@ -16441,33 +16608,33 @@ public final class ProtoBuf { } } - // optional bool autoLeave = 3; + // optional bool autoLeave = 3 [default = false]; public static final int AUTOLEAVE_FIELD_NUMBER = 3; private boolean autoLeave_; /** - * optional bool autoLeave = 3; + * optional bool autoLeave = 3 [default = false]; */ public boolean hasAutoLeave() { return ((bitField0_ & 0x00000004) == 0x00000004); } /** - * optional bool autoLeave = 3; + * optional bool autoLeave = 3 [default = false]; */ public boolean getAutoLeave() { return autoLeave_; } - // optional bool spectateOnly = 4; + // optional bool spectateOnly = 4 [default = false]; public static final int SPECTATEONLY_FIELD_NUMBER = 4; private boolean spectateOnly_; /** - * optional bool spectateOnly = 4; + * optional bool spectateOnly = 4 [default = false]; */ public boolean hasSpectateOnly() { return ((bitField0_ & 0x00000008) == 0x00000008); } /** - * optional bool spectateOnly = 4; + * optional bool spectateOnly = 4 [default = false]; */ public boolean getSpectateOnly() { return spectateOnly_; @@ -16826,22 +16993,22 @@ public final class ProtoBuf { return this; } - // optional bool autoLeave = 3; + // optional bool autoLeave = 3 [default = false]; private boolean autoLeave_ ; /** - * optional bool autoLeave = 3; + * optional bool autoLeave = 3 [default = false]; */ public boolean hasAutoLeave() { return ((bitField0_ & 0x00000004) == 0x00000004); } /** - * optional bool autoLeave = 3; + * optional bool autoLeave = 3 [default = false]; */ public boolean getAutoLeave() { return autoLeave_; } /** - * optional bool autoLeave = 3; + * optional bool autoLeave = 3 [default = false]; */ public Builder setAutoLeave(boolean value) { bitField0_ |= 0x00000004; @@ -16850,7 +17017,7 @@ public final class ProtoBuf { return this; } /** - * optional bool autoLeave = 3; + * optional bool autoLeave = 3 [default = false]; */ public Builder clearAutoLeave() { bitField0_ = (bitField0_ & ~0x00000004); @@ -16859,22 +17026,22 @@ public final class ProtoBuf { return this; } - // optional bool spectateOnly = 4; + // optional bool spectateOnly = 4 [default = false]; private boolean spectateOnly_ ; /** - * optional bool spectateOnly = 4; + * optional bool spectateOnly = 4 [default = false]; */ public boolean hasSpectateOnly() { return ((bitField0_ & 0x00000008) == 0x00000008); } /** - * optional bool spectateOnly = 4; + * optional bool spectateOnly = 4 [default = false]; */ public boolean getSpectateOnly() { return spectateOnly_; } /** - * optional bool spectateOnly = 4; + * optional bool spectateOnly = 4 [default = false]; */ public Builder setSpectateOnly(boolean value) { bitField0_ |= 0x00000008; @@ -16883,7 +17050,7 @@ public final class ProtoBuf { return this; } /** - * optional bool spectateOnly = 4; + * optional bool spectateOnly = 4 [default = false]; */ public Builder clearSpectateOnly() { bitField0_ = (bitField0_ & ~0x00000008); diff --git a/tests/src/de/pokerth/test/AllTests.java b/tests/src/de/pokerth/test/AllTests.java index 9bcdfee7..a4bdda2c 100644 --- a/tests/src/de/pokerth/test/AllTests.java +++ b/tests/src/de/pokerth/test/AllTests.java @@ -40,7 +40,8 @@ import org.junit.runners.Suite; RunRankingGameTest.class, RejoinGameTest.class, RejoinMultiGameTest.class, - SeatStateTest.class + SeatStateTest.class, + SpectatorJoinTest.class }) public class AllTests { public static void main(String[] args) diff --git a/tests/src/de/pokerth/test/SpectatorJoinTest.java b/tests/src/de/pokerth/test/SpectatorJoinTest.java new file mode 100644 index 00000000..6013c5e3 --- /dev/null +++ b/tests/src/de/pokerth/test/SpectatorJoinTest.java @@ -0,0 +1,262 @@ +/* PokerTH automated tests. + Copyright (C) 2013 Lothar May + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package de.pokerth.test; + +import static org.junit.Assert.*; + +import java.net.Socket; +import java.util.ArrayList; +import java.util.Collection; + +import org.junit.Test; + +import de.pokerth.protocol.ProtoBuf.NetGameInfo; +import de.pokerth.protocol.ProtoBuf.PokerTHMessage; +import de.pokerth.protocol.ProtoBuf.StartEventAckMessage; +import de.pokerth.protocol.ProtoBuf.NetGameInfo.EndRaiseMode; +import de.pokerth.protocol.ProtoBuf.NetGameInfo.NetGameType; +import de.pokerth.protocol.ProtoBuf.PokerTHMessage.PokerTHMessageType; + +public class SpectatorJoinTest extends TestBase { + + @Test + public void testSpectatorJoinGameBeforeStart() throws Exception { + Guid firstPlayerSession = new Guid(); + int firstPlayerId = userInit(sock, AuthUser, AuthPassword, null, firstPlayerSession); + + // Waiting for player list update. + PokerTHMessage msg; + msg = receiveMessage(); + if (!msg.hasPlayerListMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + + Collection l = new ArrayList(); + String gameName = AuthUser + " rejoin game"; + NetGameInfo gameInfo = createGameInfo(NetGameType.normalGame, 5, 7, 5, EndRaiseMode.doubleBlinds, 0, 50, gameName, l, 10, 0, 11, 10000); + sendMessage(createGameRequestMsg( + gameInfo, + "", + false)); + + // Game list update (new game) + msg = receiveMessage(); + if (!msg.hasGameListNewMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + + // Join game ack. + msg = receiveMessage(); + if (!msg.hasJoinGameAckMessage()) { + failOnErrorMessage(msg); + fail("Could not create game!"); + } + int gameId = msg.getJoinGameAckMessage().getGameId(); + + // Game list update (player joined). + msg = receiveMessage(); + if (!msg.hasGameListPlayerJoinedMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + + // Let a spectator join. + Socket spectatorSock = new Socket("localhost", 7234); + int spectatorId = userInit(spectatorSock, "test20", "test20"); + + msg = receiveMessage(spectatorSock); + if (!msg.hasPlayerListMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + msg = receiveMessage(spectatorSock); + if (!msg.hasGameListNewMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + msg = receiveMessage(spectatorSock); + if (!msg.hasPlayerListMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + // Player List should also be updated for first player. + msg = receiveMessage(); + if (!msg.hasPlayerListMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + + sendMessage(joinGameRequestMsg(gameId, "", false, true), spectatorSock); + msg = receiveMessage(spectatorSock); + if (!msg.hasJoinGameAckMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + assertTrue(msg.getJoinGameAckMessage().getSpectateOnly()); + + msg = receiveMessage(spectatorSock); + if (!msg.hasGamePlayerJoinedMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + assertEquals(firstPlayerId, msg.getGamePlayerJoinedMessage().getPlayerId()); + // TODO Spectator joined message is missing here! + + msg = receiveMessage(spectatorSock); + if (!msg.hasGameListSpectatorJoinedMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + assertEquals(gameId, msg.getGameListSpectatorJoinedMessage().getGameId()); + assertEquals(spectatorId, msg.getGameListSpectatorJoinedMessage().getPlayerId()); + + // Spectator should be visible for first player. + msg = receiveMessage(); + if (!msg.hasGameSpectatorJoinedMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + msg = receiveMessage(); + if (!msg.hasGameListSpectatorJoinedMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + + // Let 9 additional clients join. + Socket s[] = new Socket[9]; + int playerId[] = new int[9]; + for (int i = 0; i < 9; i++) { + s[i] = new Socket("localhost", 7234); + String username = "test" + (i+1); + String password = username; + playerId[i] = userInit(s[i], username, password); + + // Waiting for player list update. + do { + msg = receiveMessage(s[i]); + } while (msg.hasPlayerListMessage()); + + if (!msg.hasGameListNewMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + assertEquals(1, msg.getGameListNewMessage().getSpectatorIdsCount()); + assertEquals(spectatorId, msg.getGameListNewMessage().getSpectatorIds(0)); + do { + msg = receiveMessage(s[i]); + } while (msg.hasGameListPlayerJoinedMessage() || msg.hasGamePlayerJoinedMessage()); + sendMessage(joinGameRequestMsg(gameId, "", false), s[i]); + do { + msg = receiveMessage(s[i]); + failOnErrorMessage(msg); + } while (!msg.hasJoinGameAckMessage() && !msg.hasJoinGameFailedMessage()); + if (!msg.hasJoinGameAckMessage()) { + fail("User " + username + " could not join ranking game."); + } + + // The player should have joined the game. + msg = receiveMessage(); + if (!msg.hasPlayerListMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + msg = receiveMessage(); + if (!msg.hasGamePlayerJoinedMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + msg = receiveMessage(); + if (!msg.hasGameListPlayerJoinedMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + // The spectator should also receive the updates. + msg = receiveMessage(spectatorSock); + if (!msg.hasPlayerListMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + msg = receiveMessage(spectatorSock); + if (!msg.hasGamePlayerJoinedMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + msg = receiveMessage(spectatorSock); + if (!msg.hasGameListPlayerJoinedMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + } + + // Server should automatically send start event. + msg = receiveMessage(); + if (!msg.hasStartEventMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + for (int i = 0; i < 9; i++) { + do { + msg = receiveMessage(s[i]); + failOnErrorMessage(msg); + } while (!msg.hasStartEventMessage()); + } + // Acknowledge start event. + StartEventAckMessage startAck = StartEventAckMessage.newBuilder() + .setGameId(gameId) + .build(); + msg = PokerTHMessage.newBuilder() + .setMessageType(PokerTHMessageType.Type_StartEventAckMessage) + .setStartEventAckMessage(startAck) + .build(); + sendMessage(msg); + for (int i = 0; i < 9; i++) { + sendMessage(msg, s[i]); + } + + // Game list update (game now running). + msg = receiveMessage(spectatorSock); + if (!msg.hasGameListUpdateMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + + msg = receiveMessage(spectatorSock); + if (!msg.hasGameStartInitialMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + + // Spectator should receive a hand start message without cards. + msg = receiveMessage(spectatorSock); + if (!msg.hasHandStartMessage()) { + failOnErrorMessage(msg); + fail("Invalid message: " + msg.getMessageType()); + } + assertFalse(msg.getHandStartMessage().hasEncryptedCards()); + assertFalse(msg.getHandStartMessage().hasPlainCards()); + assertEquals(gameId, msg.getHandStartMessage().getGameId()); + + for (int i = 0; i < 9; i++) { + s[i].close(); + } + spectatorSock.close(); + } + +} diff --git a/tests/src/de/pokerth/test/TestBase.java b/tests/src/de/pokerth/test/TestBase.java index 1b8019fe..4e80c327 100644 --- a/tests/src/de/pokerth/test/TestBase.java +++ b/tests/src/de/pokerth/test/TestBase.java @@ -289,9 +289,14 @@ public abstract class TestBase { } public PokerTHMessage joinGameRequestMsg(int gameId, String password, boolean autoLeave) { + return joinGameRequestMsg(gameId, password, autoLeave, false); + } + + public PokerTHMessage joinGameRequestMsg(int gameId, String password, boolean autoLeave, boolean spectateOnly) { JoinExistingGameMessage.Builder joinBuilder = JoinExistingGameMessage.newBuilder(); joinBuilder.setGameId(gameId); joinBuilder.setAutoLeave(autoLeave); + joinBuilder.setSpectateOnly(spectateOnly); if (!password.isEmpty()) { joinBuilder.setPassword(password); }