From 3c88ba8bbebc9477217107aac307b78a0746cdfb Mon Sep 17 00:00:00 2001 From: lotodore Date: Sat, 29 Sep 2007 14:05:41 +0000 Subject: [PATCH] Game list in Lobby is now shown and updated even after joining or creating a game. Game updates will be sent by the server at all times (even during the game). --- .../gamelobbydialog/gamelobbydialogimpl.cpp | 72 +++++++++--- .../qt/gamelobbydialog/gamelobbydialogimpl.h | 4 +- .../gamelobbydialog/lobbychat/lobbychat.cpp | 1 - src/gui/qt/mainwindow/mainwindowimpl.cpp | 9 +- .../startnetworkgamedialogimpl.cpp | 1 - src/net/common/clientstate.cpp | 99 ++++++++--------- src/net/common/ircthread.cpp | 3 +- src/net/common/servergamestate.cpp | 25 +---- src/net/common/servergamethread.cpp | 31 +++++- src/net/common/serverlobbythread.cpp | 101 ++++++++--------- src/net/common/sessiondata.cpp | 49 ++++++++ src/net/common/sessionmanager.cpp | 15 +++ src/net/genericsocket.h | 1 + src/net/servergamethread.h | 4 +- src/net/serverlobbythread.h | 7 +- src/net/sessiondata.h | 26 ++--- src/net/sessionmanager.h | 3 + src/playerdata.cpp | 105 ++++++++++++++++++ src/playerdata.h | 48 ++++---- 19 files changed, 407 insertions(+), 197 deletions(-) diff --git a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp index 2428c04e..cabbf836 100644 --- a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp +++ b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp @@ -18,7 +18,7 @@ #include gameLobbyDialogImpl::gameLobbyDialogImpl(QWidget *parent, ConfigFile *c) - : QDialog(parent), myW(NULL), myConfig(c), mySession(NULL), currentGameName(""), isAdmin(false), myChat(NULL) + : QDialog(parent), myW(NULL), myConfig(c), mySession(NULL), currentGameName(""), isAdmin(false), inGame(false), myChat(NULL) { setupUi(this); @@ -50,7 +50,6 @@ void gameLobbyDialogImpl::exec() mySession->startIrcClient(); QDialog::exec(); mySession->terminateIrcClient(); - clearDialog(); } @@ -162,12 +161,14 @@ void gameLobbyDialogImpl::refresh(int actionID) { void gameLobbyDialogImpl::removedFromGame(int reason) { - clearDialog(); + inGame = false; + isAdmin = false; + leftGameDialogUpdate(); } void gameLobbyDialogImpl::gameSelected(QTreeWidgetItem* item, QTreeWidgetItem*) { - if (item) + if (!inGame && item) { pushButton_JoinGame->setEnabled(true); @@ -234,12 +235,15 @@ void gameLobbyDialogImpl::removeGame(unsigned gameId) void gameLobbyDialogImpl::gameAddPlayer(unsigned gameId, unsigned playerId) { - QTreeWidgetItem *item = treeWidget_GameList->currentItem(); - if (item && item->data(0, Qt::UserRole) == gameId) + if (!inGame) { - assert(mySession); - PlayerInfo info(mySession->getClientPlayerInfo(playerId)); - addConnectedPlayer(playerId, QString::fromUtf8(info.playerName.c_str()), PLAYER_RIGHTS_NORMAL); + QTreeWidgetItem *item = treeWidget_GameList->currentItem(); + if (item && item->data(0, Qt::UserRole) == gameId) + { + assert(mySession); + PlayerInfo info(mySession->getClientPlayerInfo(playerId)); + addConnectedPlayer(playerId, QString::fromUtf8(info.playerName.c_str()), PLAYER_RIGHTS_NORMAL); + } } QTreeWidgetItemIterator it(treeWidget_GameList); @@ -255,12 +259,15 @@ void gameLobbyDialogImpl::gameAddPlayer(unsigned gameId, unsigned playerId) void gameLobbyDialogImpl::gameRemovePlayer(unsigned gameId, unsigned playerId) { - QTreeWidgetItem *item = treeWidget_GameList->currentItem(); - if (item && item->data(0, Qt::UserRole) == gameId) + if (!inGame) { - assert(mySession); - PlayerInfo info(mySession->getClientPlayerInfo(playerId)); - removePlayer(playerId, QString::fromUtf8(info.playerName.c_str())); + QTreeWidgetItem *item = treeWidget_GameList->currentItem(); + if (item && item->data(0, Qt::UserRole) == gameId) + { + assert(mySession); + PlayerInfo info(mySession->getClientPlayerInfo(playerId)); + removePlayer(playerId, QString::fromUtf8(info.playerName.c_str())); + } } QTreeWidgetItemIterator it(treeWidget_GameList); @@ -307,6 +314,8 @@ void gameLobbyDialogImpl::clearDialog() pushButton_CreateGame->clearFocus(); lineEdit_ChatInput->setFocus(); myChat->clearChat(); + inGame = false; + isAdmin = false; } void gameLobbyDialogImpl::checkPlayerQuantity() { @@ -328,7 +337,8 @@ void gameLobbyDialogImpl::checkPlayerQuantity() { void gameLobbyDialogImpl::joinedNetworkGame(unsigned playerId, QString playerName, int rights) { // Update dialog - gameModeDialogUpdate(); + inGame = true; + joinedGameDialogUpdate(); isAdmin = rights == PLAYER_RIGHTS_ADMIN; addConnectedPlayer(playerId, playerName, rights); @@ -382,17 +392,43 @@ void gameLobbyDialogImpl::removePlayer(unsigned playerId, QString) { checkPlayerQuantity(); } -void gameLobbyDialogImpl::gameModeDialogUpdate() { +void gameLobbyDialogImpl::joinedGameDialogUpdate() { groupBox_GameInfo->setEnabled(true); groupBox_GameInfo->setTitle(currentGameName); - treeWidget_GameList->clear(); - treeWidget_GameList->hide(); treeWidget_connectedPlayers->clear(); pushButton_CreateGame->hide(); pushButton_JoinGame->hide(); pushButton_Leave->show(); } +void gameLobbyDialogImpl::leftGameDialogUpdate() { + + // un-select current game. + treeWidget_GameList->clearSelection(); + + groupBox_GameInfo->setTitle(tr("Game Info")); + groupBox_GameInfo->setEnabled(false); + currentGameName = ""; + + label_SmallBlind->setText(""); + label_StartCash->setText(""); + label_MaximumNumberOfPlayers->setText(""); + label_HandsToRaiseSmallBlind->setText(""); + label_TimeoutForPlayerAction->setText(""); + + treeWidget_connectedPlayers->clear(); + pushButton_StartGame->hide(); + pushButton_Leave->hide(); + pushButton_Kick->hide(); + pushButton_Kick->setEnabled(false); + checkBox_fillUpWithComputerOpponents->hide(); + pushButton_CreateGame->show(); + pushButton_JoinGame->show(); + pushButton_JoinGame->setEnabled(false); + + lineEdit_ChatInput->setFocus(); +} + void gameLobbyDialogImpl::playerSelected(QTreeWidgetItem* item, QTreeWidgetItem*) { if (item) diff --git a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h index dd718bc9..6e5bca5e 100644 --- a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h +++ b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h @@ -82,7 +82,8 @@ public slots: void leaveGame(); void kickPlayer(); - void gameModeDialogUpdate(); + void joinedGameDialogUpdate(); + void leftGameDialogUpdate(); void clearDialog(); void sendChatMessage(); @@ -98,6 +99,7 @@ private: createInternetGameDialogImpl *myCreateInternetGameDialog; QString currentGameName; bool isAdmin; + bool inGame; LobbyChat *myChat; }; diff --git a/src/gui/qt/gamelobbydialog/lobbychat/lobbychat.cpp b/src/gui/qt/gamelobbydialog/lobbychat/lobbychat.cpp index cf314ce1..8de657b2 100644 --- a/src/gui/qt/gamelobbydialog/lobbychat/lobbychat.cpp +++ b/src/gui/qt/gamelobbydialog/lobbychat/lobbychat.cpp @@ -59,7 +59,6 @@ void LobbyChat::selfJoined(QString ownName, QString channel) myNick = ownName; myLobby->textBrowser_ChatDisplay->append(tr("Joined channel:") + " " + channel + " " + tr("as user") + " " + ownName + "."); myLobby->textBrowser_ChatDisplay->append(""); - playerJoined(ownName); myLobby->lineEdit_ChatInput->setEnabled(true); myLobby->lineEdit_ChatInput->setFocus(); } diff --git a/src/gui/qt/mainwindow/mainwindowimpl.cpp b/src/gui/qt/mainwindow/mainwindowimpl.cpp index 8df34ccf..ebccdfb7 100755 --- a/src/gui/qt/mainwindow/mainwindowimpl.cpp +++ b/src/gui/qt/mainwindow/mainwindowimpl.cpp @@ -884,6 +884,9 @@ void mainWindowImpl::callCreateNetworkGameDialog() { myGameLobbyDialog->setSession(&getSession()); myStartNetworkGameDialog->setSession(&getSession()); + // Clear network game dialog. + myStartNetworkGameDialog->clearDialog(); + myServerGuiInterface->getSession().startNetworkServer(); mySession->startNetworkClientForLocalServer(gameData); @@ -908,6 +911,8 @@ void mainWindowImpl::callJoinNetworkGameDialog() { myGameLobbyDialog->setSession(&getSession()); myStartNetworkGameDialog->setSession(&getSession()); + // Clear network game dialog + myStartNetworkGameDialog->clearDialog(); // Maybe use QUrl::toPunycode. mySession->startNetworkClient( myJoinNetworkGameDialog->lineEdit_ipAddress->text().toUtf8().constData(), @@ -957,7 +962,9 @@ void mainWindowImpl::joinGameLobby() { myServerGuiInterface->getSession().terminateNetworkServer(); myGameLobbyDialog->setSession(&getSession()); myStartNetworkGameDialog->setSession(&getSession()); - + + // Clear Lobby dialog. + myGameLobbyDialog->clearDialog(); // Start client for dedicated server. mySession->startInternetClient(); diff --git a/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp b/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp index 2eb29d95..5d7455d4 100644 --- a/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp +++ b/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp @@ -43,7 +43,6 @@ void startNetworkGameDialogImpl::exec() { label_maxPlayerNumber->setText(QString::number(info.data.maxNumberOfPlayers)); QDialog::exec(); - clearDialog(); } void startNetworkGameDialogImpl::startGame() { diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 0d599921..8111e777 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -399,7 +399,6 @@ AbstractClientStateReceiving::Process(ClientThread &client) NetPacketRemovedFromGame::Data removedData; tmpPacket->ToNetPacketRemovedFromGame()->GetData(removedData); client.ClearPlayerDataList(); - client.ClearGameInfoMap(); client.GetCallback().SignalNetClientRemovedFromGame(removedData.removeReason); client.SetState(ClientStateWaitJoin::Instance()); } @@ -430,6 +429,54 @@ AbstractClientStateReceiving::Process(ClientThread &client) // Signal to GUI and remove from data list. client.RemovePlayerData(playerLeftData.playerId); } + else if (tmpPacket->ToNetPacketGameListNew()) + { + // A new game was created on the server. + NetPacketGameListNew::Data gameListNewData; + tmpPacket->ToNetPacketGameListNew()->GetData(gameListNewData); + + // Request player info for players if needed. + PlayerIdList::const_iterator i = gameListNewData.gameInfo.players.begin(); + PlayerIdList::const_iterator end = gameListNewData.gameInfo.players.end(); + while (i != end) + { + PlayerInfo info; + if (!client.GetCachedPlayerInfo(*i, info)) + { + // Request player info. + client.RequestPlayerInfo(*i); + } + ++i; + } + + client.AddGameInfo(gameListNewData.gameId, gameListNewData.gameInfo); + } + else if (tmpPacket->ToNetPacketGameListUpdate()) + { + // An existing game was updated on the server. + NetPacketGameListUpdate::Data gameListUpdateData; + tmpPacket->ToNetPacketGameListUpdate()->GetData(gameListUpdateData); + if (gameListUpdateData.gameMode == GAME_MODE_CLOSED) + client.RemoveGameInfo(gameListUpdateData.gameId); + } + else if (tmpPacket->ToNetPacketGameListPlayerJoined()) + { + NetPacketGameListPlayerJoined::Data playerJoinedData; + tmpPacket->ToNetPacketGameListPlayerJoined()->GetData(playerJoinedData); + client.ModifyGameInfoAddPlayer(playerJoinedData.gameId, playerJoinedData.playerId); + // Request player info if needed. + PlayerInfo info; + if (!client.GetCachedPlayerInfo(playerJoinedData.playerId, info)) + { + client.RequestPlayerInfo(playerJoinedData.playerId); + } + } + else if (tmpPacket->ToNetPacketGameListPlayerLeft()) + { + NetPacketGameListPlayerLeft::Data playerLeftData; + tmpPacket->ToNetPacketGameListPlayerLeft()->GetData(playerLeftData); + client.ModifyGameInfoRemovePlayer(playerLeftData.gameId, playerLeftData.playerId); + } else retVal = InternalProcess(client, tmpPacket); } @@ -497,55 +544,7 @@ ClientStateWaitJoin::InternalProcess(ClientThread &client, boost::shared_ptrToNetPacketGameListNew()) - { - // A new game was created on the server. - NetPacketGameListNew::Data gameListNewData; - packet->ToNetPacketGameListNew()->GetData(gameListNewData); - - // Request player info for players if needed. - PlayerIdList::const_iterator i = gameListNewData.gameInfo.players.begin(); - PlayerIdList::const_iterator end = gameListNewData.gameInfo.players.end(); - while (i != end) - { - PlayerInfo info; - if (!client.GetCachedPlayerInfo(*i, info)) - { - // Request player info. - client.RequestPlayerInfo(*i); - } - ++i; - } - - client.AddGameInfo(gameListNewData.gameId, gameListNewData.gameInfo); - } - else if (packet->ToNetPacketGameListUpdate()) - { - // An existing game was updated on the server. - NetPacketGameListUpdate::Data gameListUpdateData; - packet->ToNetPacketGameListUpdate()->GetData(gameListUpdateData); - if (gameListUpdateData.gameMode == GAME_MODE_CLOSED) - client.RemoveGameInfo(gameListUpdateData.gameId); - } - else if (packet->ToNetPacketGameListPlayerJoined()) - { - NetPacketGameListPlayerJoined::Data playerJoinedData; - packet->ToNetPacketGameListPlayerJoined()->GetData(playerJoinedData); - client.ModifyGameInfoAddPlayer(playerJoinedData.gameId, playerJoinedData.playerId); - // Request player info if needed. - PlayerInfo info; - if (!client.GetCachedPlayerInfo(playerJoinedData.playerId, info)) - { - client.RequestPlayerInfo(playerJoinedData.playerId); - } - } - else if (packet->ToNetPacketGameListPlayerLeft()) - { - NetPacketGameListPlayerLeft::Data playerLeftData; - packet->ToNetPacketGameListPlayerLeft()->GetData(playerLeftData); - client.ModifyGameInfoRemovePlayer(playerLeftData.gameId, playerLeftData.playerId); - } - else if (packet->ToNetPacketJoinGameAck()) + if (packet->ToNetPacketJoinGameAck()) { // Successfully joined a game. NetPacketJoinGameAck::Data joinGameAckData; diff --git a/src/net/common/ircthread.cpp b/src/net/common/ircthread.cpp index 1751f987..6f8b5fef 100644 --- a/src/net/common/ircthread.cpp +++ b/src/net/common/ircthread.cpp @@ -70,8 +70,7 @@ void irc_notify_player_list(irc_session_t *session, const char *players) input >> name; while (!input.fail() && !input.eof()) { - if (name != context->nick) - context->ircThread.GetCallback().SignalIrcPlayerJoined(name); + context->ircThread.GetCallback().SignalIrcPlayerJoined(name); input >> name; } } diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index 78e36ba1..94aec201 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -141,7 +141,7 @@ AbstractServerGameStateReceiving::Process(ServerGameThread &server) packet = server.GetReceiver().Recv(session.sessionData->GetSocket(), session.sessionData->GetReceiveBuffer()); } catch (const NetException &) { - server.RemoveSession(session); + server.ErrorRemoveSession(session); return retVal; } @@ -150,25 +150,8 @@ AbstractServerGameStateReceiving::Process(ServerGameThread &server) { if (packet->ToNetPacketRetrievePlayerInfo()) { - NetPacketRetrievePlayerInfo::Data reqData; - packet->ToNetPacketRetrievePlayerInfo()->GetData(reqData); - - SessionWrapper tmpSession = server.GetSessionManager().GetSessionByUniquePlayerId(reqData.playerId); - if (tmpSession.sessionData.get() && tmpSession.playerData.get()) - { - // Send player info to client. - // TODO this is a copy and paste - boost::shared_ptr info(new NetPacketPlayerInfo); - NetPacketPlayerInfo::Data infoData; - infoData.playerId = tmpSession.playerData->GetUniqueId(); - infoData.playerInfo.ptype = tmpSession.playerData->GetType(); - infoData.playerInfo.playerName = tmpSession.playerData->GetName(); - infoData.playerInfo.hasAvatar = !tmpSession.playerData->GetAvatarFile().empty(); - if (infoData.playerInfo.hasAvatar) - infoData.playerInfo.avatar.FromString(tmpSession.playerData->GetAvatarFile()); - static_cast(info.get())->SetData(infoData); - server.GetSender().Send(session.sessionData->GetSocket(), info); - } + // Delegate to Lobby. + server.GetLobbyThread().HandleGameRetrievePlayerInfo(session, *packet->ToNetPacketRetrievePlayerInfo()); } else if (packet->ToNetPacketLeaveCurrentGame()) { @@ -282,8 +265,6 @@ ServerGameStateInit::HandleNewSession(ServerGameThread &server, SessionWrapper s // Send "Player Joined" to other fully connected clients. server.SendToAllPlayers(CreateNetPacketPlayerJoined(*session.playerData), SessionData::Game); - // Session is now in game state. - session.sessionData->SetState(SessionData::Game); // Accept session. server.GetSessionManager().AddSession(session); diff --git a/src/net/common/servergamethread.cpp b/src/net/common/servergamethread.cpp index a134cfc0..21ed2c54 100644 --- a/src/net/common/servergamethread.cpp +++ b/src/net/common/servergamethread.cpp @@ -29,6 +29,8 @@ #include #include +#include + using namespace std; @@ -100,6 +102,22 @@ ServerGameThread::SendToAllPlayers(boost::shared_ptr packet, SessionD GetSessionManager().SendToAllSessions(GetSender(), packet, state); } +void +ServerGameThread::RemoveAllSessions() +{ + // Called from lobby thread. + // Clean up ALL sessions which are left. + ServerLobbyThread &lobbyThread = GetLobbyThread(); + boost::mutex::scoped_lock lock(m_sessionQueueMutex); + while (!m_sessionQueue.empty()) + { + SessionWrapper tmpSession = m_sessionQueue.front(); + m_sessionQueue.pop_front(); + lobbyThread.RemoveSessionFromGame(tmpSession); + } + GetSessionManager().ForEach(boost::bind(&ServerLobbyThread::RemoveSessionFromGame, boost::ref(lobbyThread), _1)); +} + void ServerGameThread::Main() { @@ -262,7 +280,7 @@ ServerGameThread::ResetComputerPlayerList() } void -ServerGameThread::RemoveSession(SessionWrapper session) +ServerGameThread::GracefulRemoveSession(SessionWrapper session) { assert(session.sessionData.get()); GetSessionManager().RemoveSession(session.sessionData->GetSocket()); @@ -281,18 +299,25 @@ ServerGameThread::RemoveSession(SessionWrapper session) } } +void +ServerGameThread::ErrorRemoveSession(SessionWrapper session) +{ + GetLobbyThread().RemoveSessionFromGame(session); + GracefulRemoveSession(session); +} + void ServerGameThread::SessionError(SessionWrapper session, int errorCode) { assert(session.sessionData.get()); - RemoveSession(session); + ErrorRemoveSession(session); GetLobbyThread().SessionError(session, errorCode); } void ServerGameThread::MoveSessionToLobby(SessionWrapper session, int reason) { - RemoveSession(session); + GracefulRemoveSession(session); GetLobbyThread().ReAddSession(session, reason); } diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 245af462..96b9df7f 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -29,7 +29,7 @@ #include #define SERVER_CLOSE_SESSION_DELAY_SEC 10 -#define SERVER_MAX_NUM_SESSIONS 64 // Maximum number of idle users in lobby. +#define SERVER_MAX_NUM_SESSIONS 512 // Maximum number of idle users in lobby. #define SERVER_COMPUTER_PLAYER_NAME "Computer" @@ -93,10 +93,31 @@ ServerLobbyThread::ReAddSession(SessionWrapper session, int reason) m_sessionQueue.push_back(session); } +void +ServerLobbyThread::MoveSessionToGame(ServerGameThread &game, SessionWrapper session) +{ + // Remove session from the lobby. + m_sessionManager.RemoveSession(session.sessionData->GetSocket()); + // Session is now in game state. + session.sessionData->SetState(SessionData::Game); + // Store it in the list of game sessions. + m_gameSessionManager.AddSession(session); + // Add session to the game. + game.AddSession(session); +} + +void +ServerLobbyThread::RemoveSessionFromGame(SessionWrapper session) +{ + // Just remove the session. Only for fatal errors. + m_gameSessionManager.RemoveSession(session.sessionData->GetSocket()); +} + void ServerLobbyThread::CloseSessionDelayed(SessionWrapper session) { m_sessionManager.RemoveSession(session.sessionData->GetSocket()); + m_gameSessionManager.RemoveSession(session.sessionData->GetSocket()); boost::timers::portable::microsec_timer closeTimer; closeTimer.start(); @@ -116,6 +137,7 @@ ServerLobbyThread::NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId) packetData.playerId = playerId; static_cast(packet.get())->SetData(packetData); m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); + m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); } void @@ -128,6 +150,14 @@ ServerLobbyThread::NotifyPlayerLeftGame(unsigned gameId, unsigned playerId) packetData.playerId = playerId; static_cast(packet.get())->SetData(packetData); m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); + m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); +} + +void +ServerLobbyThread::HandleGameRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket) +{ + // Someone within a game requested player info. + HandleNetPacketRetrievePlayerInfo(session, tmpPacket); } void @@ -185,7 +215,7 @@ ServerLobbyThread::Main() } } if (tmpSession.sessionData.get() && tmpSession.playerData.get()) - HandleNewSession(tmpSession); + HandleReAddedSession(tmpSession); } // Process loop. ProcessLoop(); @@ -205,7 +235,6 @@ ServerLobbyThread::Main() GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT); CleanupConnectQueue(); - m_sessionManager.Clear(); } void @@ -326,17 +355,7 @@ ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, con // Find player in lobby or in a game. boost::shared_ptr tmpPlayer = m_sessionManager.GetSessionByUniquePlayerId(request.playerId).playerData; if (!tmpPlayer.get()) - { - GameMap::const_iterator game_i = m_gameMap.begin(); - GameMap::const_iterator game_end = m_gameMap.end(); - while (game_i != game_end) - { - tmpPlayer = game_i->second->GetPlayerDataByUniqueId(request.playerId); - if (tmpPlayer.get()) - break; - ++game_i; - } - } + tmpPlayer = m_gameSessionManager.GetSessionByUniquePlayerId(request.playerId).playerData; if (tmpPlayer.get()) { @@ -371,10 +390,7 @@ ServerLobbyThread::HandleNetPacketCreateGame(SessionWrapper session, const NetPa m_playerConfig)); game->Init(createGameData.gameData); - // Remove session from the lobby. - m_sessionManager.RemoveSession(session.sessionData->GetSocket()); - // Add session to the game. - game->AddSession(session); + MoveSessionToGame(*game, session); // Add game to list of games. InternalAddGame(game); @@ -397,10 +413,7 @@ ServerLobbyThread::HandleNetPacketJoinGame(SessionWrapper session, const NetPack ServerGameThread &game = *pos->second; if (game.CheckPassword(joinGameData.password)) { - // Remove session from the lobby. - m_sessionManager.RemoveSession(session.sessionData->GetSocket()); - // Add session to the game. - game.AddSession(session); + MoveSessionToGame(game, session); } else { @@ -461,6 +474,7 @@ ServerLobbyThread::InternalAddGame(boost::shared_ptr game) m_gameMap.insert(GameMap::value_type(game->GetId(), game)); // Notify all players. m_sessionManager.SendToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Established); + m_gameSessionManager.SendToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Game); } void @@ -468,8 +482,11 @@ ServerLobbyThread::InternalRemoveGame(boost::shared_ptr game) { // Remove game from list. m_gameMap.erase(game->GetId()); + // Remove all sessions left in the game. + game->RemoveAllSessions(); // Notify all players. m_sessionManager.SendToAllSessions(GetSender(), CreateNetPacketGameListUpdate(*game, GAME_MODE_CLOSED), SessionData::Established); + m_gameSessionManager.SendToAllSessions(GetSender(), CreateNetPacketGameListUpdate(*game, GAME_MODE_CLOSED), SessionData::Game); } void @@ -517,26 +534,17 @@ ServerLobbyThread::HandleNewConnection(boost::shared_ptr connData) } void -ServerLobbyThread::HandleNewSession(SessionWrapper session) +ServerLobbyThread::HandleReAddedSession(SessionWrapper session) { + // Remove session from game session list. + m_gameSessionManager.RemoveSession(session.sessionData->GetSocket()); + if (m_sessionManager.GetRawSessionCount() <= SERVER_MAX_NUM_SESSIONS) { - // This session has been temporarily stored - check if no - // one else got the player name during that time. - if (!m_sessionManager.IsPlayerConnected(session.playerData->GetName())) - { - // Send the list of games. - SendGameList(session.sessionData->GetSocket()); - // Set state (back) to established. - session.sessionData->SetState(SessionData::Established); - // Add session to lobby list. - m_sessionManager.AddSession(session); - } - else - { - // Gracefully close this session. - SessionError(session, ERR_NET_PLAYER_NAME_IN_USE); - } + // Set state (back) to established. + session.sessionData->SetState(SessionData::Established); + // Add session to lobby list. + m_sessionManager.AddSession(session); } else { @@ -643,19 +651,8 @@ ServerLobbyThread::IsPlayerConnected(const string &name) retVal = m_sessionManager.IsPlayerConnected(name); if (!retVal) - { - GameMap::const_iterator game_i = m_gameMap.begin(); - GameMap::const_iterator game_end = m_gameMap.end(); - while (game_i != game_end) - { - if (game_i->second->IsPlayerConnected(name)) - { - retVal = true; - break; - } - ++game_i; - } - } + retVal = m_gameSessionManager.IsPlayerConnected(name); + return retVal; } diff --git a/src/net/common/sessiondata.cpp b/src/net/common/sessiondata.cpp index 030175ed..36fd4553 100644 --- a/src/net/common/sessiondata.cpp +++ b/src/net/common/sessiondata.cpp @@ -30,3 +30,52 @@ SessionData::~SessionData() CLOSESOCKET(m_sockfd); } +unsigned +SessionData::GetId() const +{ + // const value - no mutex needed. + return m_id; +} + +SessionData::State +SessionData::GetState() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_state; +} + +void +SessionData::SetState(SessionData::State state) +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_state = state; +} + +SOCKET +SessionData::GetSocket() const +{ + // value never modified - no mutex needed. + return m_sockfd; +} + +const std::string & +SessionData::GetClientAddr() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_clientAddr; +} + +void +SessionData::SetClientAddr(const std::string &addr) +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_clientAddr = addr; +} + +ReceiveBuffer & +SessionData::GetReceiveBuffer() +{ + // mutex protection, if needed, within buffer. + return m_receiveBuffer; +} + diff --git a/src/net/common/sessionmanager.cpp b/src/net/common/sessionmanager.cpp index d3501669..33f70420 100644 --- a/src/net/common/sessionmanager.cpp +++ b/src/net/common/sessionmanager.cpp @@ -277,6 +277,21 @@ SessionManager::IsPlayerConnected(unsigned uniqueId) const return retVal; } +void +SessionManager::ForEach(boost::function func) +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SessionMap::iterator i = m_sessionMap.begin(); + SessionMap::iterator end = m_sessionMap.end(); + + while (i != end) + { + func((*i).second); + ++i; + } +} + void SessionManager::Clear() { diff --git a/src/net/genericsocket.h b/src/net/genericsocket.h index 0c8a06bf..32cdc071 100644 --- a/src/net/genericsocket.h +++ b/src/net/genericsocket.h @@ -21,6 +21,7 @@ #define _GENERICSOCKET_H_ #ifdef _WIN32 +#define FD_SETSIZE 512 #include #include #else diff --git a/src/net/servergamethread.h b/src/net/servergamethread.h index e2284433..feedc1ac 100644 --- a/src/net/servergamethread.h +++ b/src/net/servergamethread.h @@ -56,6 +56,7 @@ public: GameState GetCurRound() const; void SendToAllPlayers(boost::shared_ptr packet, SessionData::State state); + void RemoveAllSessions(); bool IsPasswordProtected() const; bool CheckPassword(const std::string &password) const; @@ -80,7 +81,8 @@ protected: void AddComputerPlayer(boost::shared_ptr player); void ResetComputerPlayerList(); - void RemoveSession(SessionWrapper session); + void GracefulRemoveSession(SessionWrapper session); + void ErrorRemoveSession(SessionWrapper session); void SessionError(SessionWrapper session, int errorCode); void MoveSessionToLobby(SessionWrapper session, int reason); diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index f2dad0cc..d32f1b23 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -52,10 +52,14 @@ public: void AddConnection(boost::shared_ptr data); void ReAddSession(SessionWrapper session, int reason); + void MoveSessionToGame(ServerGameThread &game, SessionWrapper session); + void RemoveSessionFromGame(SessionWrapper session); void SessionError(SessionWrapper session, int errorCode); void NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId); void NotifyPlayerLeftGame(unsigned gameId, unsigned playerId); + void HandleGameRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket); + void RemoveGame(unsigned id); u_int32_t GetNextUniquePlayerId(); @@ -88,7 +92,7 @@ protected: void TerminateGames(); void HandleNewConnection(boost::shared_ptr connData); - void HandleNewSession(SessionWrapper session); + void HandleReAddedSession(SessionWrapper session); SOCKET Select(); @@ -122,6 +126,7 @@ private: mutable boost::mutex m_sessionQueueMutex; SessionManager m_sessionManager; + SessionManager m_gameSessionManager; CloseSessionList m_closeSessionList; mutable boost::mutex m_closeSessionListMutex; diff --git a/src/net/sessiondata.h b/src/net/sessiondata.h index c8f184b0..109ca893 100644 --- a/src/net/sessiondata.h +++ b/src/net/sessiondata.h @@ -24,6 +24,7 @@ #include #include #include +#include #define SESSION_ID_INIT 0 @@ -35,30 +36,25 @@ public: SessionData(SOCKET sockfd, unsigned id); ~SessionData(); - unsigned GetId() const - {return m_id;} - State GetState() const - {return m_state;} - void SetState(State state) - {m_state = state;} + unsigned GetId() const; + State GetState() const; + void SetState(State state); - SOCKET GetSocket() const - {return m_sockfd;} + SOCKET GetSocket() const; - const std::string &GetClientAddr() const - {return m_clientAddr;} - void SetClientAddr(const std::string &addr) - {m_clientAddr = addr;} + const std::string &GetClientAddr() const; + void SetClientAddr(const std::string &addr); - ReceiveBuffer &GetReceiveBuffer() - {return m_receiveBuffer;} + ReceiveBuffer &GetReceiveBuffer(); private: SOCKET m_sockfd; - unsigned m_id; + const unsigned m_id; State m_state; std::string m_clientAddr; ReceiveBuffer m_receiveBuffer; + + mutable boost::mutex m_dataMutex; }; #endif diff --git a/src/net/sessionmanager.h b/src/net/sessionmanager.h index 9debe541..7fda762f 100644 --- a/src/net/sessionmanager.h +++ b/src/net/sessionmanager.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -62,6 +63,8 @@ public: bool IsPlayerConnected(const std::string &playerName) const; bool IsPlayerConnected(unsigned uniqueId) const; + void ForEach(boost::function func); + void Clear(); unsigned GetRawSessionCount(); diff --git a/src/playerdata.cpp b/src/playerdata.cpp index 53c4b88a..a7fb0f1a 100644 --- a/src/playerdata.cpp +++ b/src/playerdata.cpp @@ -24,7 +24,112 @@ PlayerData::PlayerData(unsigned uniqueId, int number, PlayerType type, PlayerRig { } +PlayerData::PlayerData(const PlayerData &other) +: m_uniqueId(other.GetUniqueId()), m_number(other.GetNumber()), m_name(other.GetName()), + m_avatarFile(other.GetAvatarFile()), m_type(other.GetType()), m_rights(other.GetRights()), + m_netSessionData(other.GetNetSessionData()) +{ +} + PlayerData::~PlayerData() { } +const std::string & +PlayerData::GetName() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_name; +} + +void +PlayerData::SetName(const std::string &name) +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_name = name; +} + +const std::string & +PlayerData::GetAvatarFile() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_avatarFile; +} + +void +PlayerData::SetAvatarFile(const std::string &avatarFile) +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_avatarFile = avatarFile; +} + +boost::shared_ptr +PlayerData::GetNetSessionData() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_netSessionData; +} + +void +PlayerData::SetNetSessionData(boost::shared_ptr session) +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_netSessionData = session; +} + +PlayerType +PlayerData::GetType() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_type; +} + +void +PlayerData::SetType(PlayerType type) +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_type = type; +} + +PlayerRights +PlayerData::GetRights() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_rights; +} + +void +PlayerData::SetRights(PlayerRights rights) +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_rights = rights; +} + +unsigned +PlayerData::GetUniqueId() const +{ + // const value - no mutex needed. + return m_uniqueId; +} + +int +PlayerData::GetNumber() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_number; +} + +void +PlayerData::SetNumber(int number) +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_number = number; +} + +bool +PlayerData::operator<(const PlayerData &other) const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_number < other.GetNumber(); +} + diff --git a/src/playerdata.h b/src/playerdata.h index 2d16ed27..08fdc15f 100644 --- a/src/playerdata.h +++ b/src/playerdata.h @@ -26,6 +26,7 @@ #include #include #include +#include class SessionData; @@ -54,46 +55,35 @@ class PlayerData { public: PlayerData(unsigned uniqueId, int number, PlayerType type, PlayerRights rights); + PlayerData(const PlayerData &other); ~PlayerData(); - const std::string &GetName() const - {return m_name;} - void SetName(const std::string &name) - {m_name = name;} - const std::string &GetAvatarFile() const - {return m_avatarFile;} - void SetAvatarFile(const std::string &avatarFile) - {m_avatarFile = avatarFile;} - boost::shared_ptr GetNetSessionData() - {return m_netSessionData;} - void SetNetSessionData(boost::shared_ptr session) - {m_netSessionData = session;} - PlayerType GetType() const - {return m_type;} - void SetType(PlayerType type) - {m_type = type;} - PlayerRights GetRights() const - {return m_rights;} - void SetRights(PlayerRights rights) - {m_rights = rights;} - unsigned GetUniqueId() const - {return m_uniqueId;} - int GetNumber() const - {return m_number;} - void SetNumber(int number) - {m_number = number;} + const std::string &GetName() const; + void SetName(const std::string &name); + const std::string &GetAvatarFile() const; + void SetAvatarFile(const std::string &avatarFile); + boost::shared_ptr GetNetSessionData() const; + void SetNetSessionData(boost::shared_ptr session); + PlayerType GetType() const; + void SetType(PlayerType type); + PlayerRights GetRights() const; + void SetRights(PlayerRights rights); + unsigned GetUniqueId() const; + int GetNumber() const; + void SetNumber(int number); - bool operator<(const PlayerData &other) - {return m_number < other.GetNumber();} + bool operator<(const PlayerData &other) const; private: - unsigned m_uniqueId; + const unsigned m_uniqueId; int m_number; std::string m_name; std::string m_avatarFile; PlayerType m_type; PlayerRights m_rights; boost::shared_ptr m_netSessionData; + + mutable boost::mutex m_dataMutex; }; typedef std::list PlayerIdList;