diff --git a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp index f6153ba5..f84b7309 100644 --- a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp +++ b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp @@ -21,6 +21,9 @@ gameLobbyDialogImpl::gameLobbyDialogImpl(QWidget *parent, ConfigFile *c) connect( pushButton_CreateGame, SIGNAL( clicked() ), this, SLOT( createGame() ) ); connect( pushButton_JoinGame, SIGNAL( clicked() ), this, SLOT( joinGame() ) ); + connect( treeWidget_GameList, SIGNAL( itemClicked ( QTreeWidgetItem*, int) ), this, SLOT( gameSelected(QTreeWidgetItem*, int) ) ); + + pushButton_JoinGame->setEnabled(false); } void gameLobbyDialogImpl::exec() @@ -53,18 +56,28 @@ void gameLobbyDialogImpl::createGame() //Speeds gameData.guiSpeed = myConfig->readConfigInt("GameSpeed"); - mySession->clientCreateGame(gameData, "default", ""); + mySession->clientCreateGame(gameData, myConfig->readConfigString("MyName") + "'s game", ""); accept(); } void gameLobbyDialogImpl::joinGame() { - assert(mySession); + QTreeWidgetItem *item = treeWidget_GameList->currentItem(); + if (item) + { + QString gameName = item->text(0); - mySession->clientJoinGame("default", ""); + assert(mySession); + mySession->clientJoinGame(gameName.toUtf8().constData(), ""); - accept(); + accept(); + } +} + +void gameLobbyDialogImpl::gameSelected(QTreeWidgetItem*, int) +{ + pushButton_JoinGame->setEnabled(true); } void gameLobbyDialogImpl::addGame(QString gameName) diff --git a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h index aba56047..865b3a8e 100644 --- a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h +++ b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h @@ -39,6 +39,8 @@ public slots: void createGame(); void joinGame(); + void gameSelected(QTreeWidgetItem*, int); + void addGame(QString gameName); void removeGame(QString gameName); diff --git a/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp b/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp index 3374ec51..50f59995 100644 --- a/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp +++ b/src/gui/qt/startnetworkgamedialog/startnetworkgamedialogimpl.cpp @@ -32,8 +32,8 @@ startNetworkGameDialogImpl::startNetworkGameDialogImpl(QWidget *parent, ConfigFi connect( pushButton_Kick, SIGNAL( clicked() ), this, SLOT( kickPlayer() ) ); connect( treeWidget, SIGNAL( itemClicked ( QTreeWidgetItem*, int) ), this, SLOT( playerSelected(QTreeWidgetItem*, int) ) ); - pushButton_Kick->setEnabled(FALSE); - pushButton_startGame->setEnabled(FALSE); + pushButton_Kick->setEnabled(false); + pushButton_startGame->setEnabled(false); } void startNetworkGameDialogImpl::startGame() { diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index 92616710..b63ff315 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -655,9 +655,13 @@ ServerGameStateStartRound::Process(ServerGameThread &server) if (curGame.getCurrentHand()->getPlayerArray()[i]->getMyCash() > 0) playersPositiveCashCounter++; } - // TODO: this is not an assert - terminate game if true. - assert(playersPositiveCashCounter); - if (playersPositiveCashCounter == 1) + if (!playersPositiveCashCounter) + { + // No more players left - restart. + server.SetState(SERVER_INITIAL_STATE::Instance()); + retVal = MSG_NET_GAME_SERVER_END; + } + else if (playersPositiveCashCounter == 1) { // View a dialog for a new game - delayed. server.SetState(ServerGameStateNextGameDelay::Instance()); diff --git a/src/net/common/servergamethread.cpp b/src/net/common/servergamethread.cpp index 92c26e83..6d3139b9 100644 --- a/src/net/common/servergamethread.cpp +++ b/src/net/common/servergamethread.cpp @@ -109,7 +109,7 @@ ServerGameThread::Main() try { - while (!ShouldTerminate()) + do { { // Handle one new session at a time. @@ -127,13 +127,15 @@ ServerGameThread::Main() } // Process current state. GetState().Process(*this); - } + } while (!ShouldTerminate() && GetSessionManager().HasSessions()); } catch (const NetException &e) { GetCallback().SignalNetServerError(e.GetErrorId(), e.GetOsErrorCode()); } GetSender().SignalTermination(); GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT); + + GetLobbyThread().RemoveGame(GetId()); } void diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index c0de1cae..3b6d7ba1 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -93,6 +93,13 @@ ServerLobbyThread::CloseSessionDelayed(SessionWrapper session) m_closeSessionList.push_back(closeSessionData); } +void +ServerLobbyThread::RemoveGame(unsigned id) +{ + boost::mutex::scoped_lock lock(m_removeGameListMutex); + m_removeGameList.push_back(id); +} + u_int32_t ServerLobbyThread::GetNextUniquePlayerId() { @@ -132,6 +139,8 @@ ServerLobbyThread::Main() ProcessLoop(); // Close sessions. CloseSessionLoop(); + // Remove games. + RemoveGameLoop(); } } catch (const NetException &e) { @@ -221,7 +230,7 @@ ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const NetPacketIn } // Check whether this player is already connected. - if (m_sessionManager.IsPlayerConnected(initData.playerName)) + if (IsPlayerConnected(initData.playerName)) { SessionError(session, ERR_NET_PLAYER_NAME_IN_USE); return; @@ -289,7 +298,6 @@ ServerLobbyThread::HandleNetPacketJoinGame(SessionWrapper session, const NetPack GameMap::iterator pos = m_gameMap.find(joinGameData.gameId); - // TODO: handle errors if (pos != m_gameMap.end()) { ServerGameThread &game = *pos->second; @@ -300,6 +308,14 @@ ServerLobbyThread::HandleNetPacketJoinGame(SessionWrapper session, const NetPack // Add session to the game. game.AddSession(session); } + else + { + SessionError(session, ERR_NET_INVALID_PASSWORD); + } + } + else + { + SessionError(session, ERR_NET_UNKNOWN_GAME); } } @@ -320,6 +336,30 @@ ServerLobbyThread::CloseSessionLoop() } } +void +ServerLobbyThread::RemoveGameLoop() +{ + boost::mutex::scoped_lock lock(m_removeGameListMutex); + + RemoveGameList::iterator i = m_removeGameList.begin(); + RemoveGameList::iterator end = m_removeGameList.end(); + + // Synchronously remove games which have been closed. + while (i != end) + { + GameMap::iterator pos = m_gameMap.find(*i); + if (pos != m_gameMap.end()) + { + boost::shared_ptr tmpGame = pos->second; + tmpGame->SignalTermination(); + tmpGame->Join(GAME_THREAD_TERMINATE_TIMEOUT); + m_gameMap.erase(pos); + } + ++i; + } + m_removeGameList.clear(); +} + void ServerLobbyThread::TerminateGames() { @@ -427,6 +467,30 @@ ServerLobbyThread::GetGui() return m_gui; } +bool +ServerLobbyThread::IsPlayerConnected(const string &name) +{ + bool retVal = false; + + 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->GetSessionManager().IsPlayerConnected(name)) + { + retVal = true; + break; + } + ++game_i; + } + } + return retVal; +} + boost::shared_ptr ServerLobbyThread::CreateNetPacketGameListNew(const ServerGameThread &game) { diff --git a/src/net/common/sessionmanager.cpp b/src/net/common/sessionmanager.cpp index 3410b48c..cf2f6406 100644 --- a/src/net/common/sessionmanager.cpp +++ b/src/net/common/sessionmanager.cpp @@ -34,6 +34,13 @@ SessionManager::~SessionManager() Clear(); } +bool +SessionManager::HasSessions() const +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); + return !m_sessionMap.empty(); +} + void SessionManager::AddSession(boost::shared_ptr sessionData) { diff --git a/src/net/servergamethread.h b/src/net/servergamethread.h index 6f1090f6..b2d8a4b9 100644 --- a/src/net/servergamethread.h +++ b/src/net/servergamethread.h @@ -60,6 +60,9 @@ public: bool CheckPassword(const std::string &password) const; const GameData &GetGameData() const; + const SessionManager &GetSessionManager() const; + SessionManager &GetSessionManager(); + protected: typedef std::deque SessionQueue; @@ -82,8 +85,6 @@ protected: size_t GetCurNumberOfPlayers() const; void AssignPlayerNumbers(); - SessionManager &GetSessionManager(); - const SessionManager &GetSessionManager() const; ServerLobbyThread &GetLobbyThread(); ServerGameState &GetState(); diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index 5082ad54..b81a376b 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -53,6 +53,8 @@ public: void AddConnection(boost::shared_ptr data); void CloseSessionDelayed(SessionWrapper session); + void RemoveGame(unsigned id); + u_int32_t GetNextUniquePlayerId(); u_int32_t GetNextGameId(); ServerCallback &GetCallback(); @@ -63,6 +65,7 @@ protected: typedef std::list SessionList; typedef std::list > > CloseSessionList; typedef std::map > GameMap; + typedef std::list RemoveGameList; // Main function of the thread. virtual void Main(); @@ -72,6 +75,8 @@ protected: void HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket); void HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket); void CloseSessionLoop(); + void RemoveGameLoop(); + void TerminateGames(); void HandleNewConnection(boost::shared_ptr connData); @@ -92,6 +97,8 @@ protected: ServerSenderCallback &GetSenderCallback(); GuiInterface &GetGui(); + bool IsPlayerConnected(const std::string &name); + static boost::shared_ptr CreateNetPacketGameListNew(const ServerGameThread &game); private: @@ -104,6 +111,9 @@ private: CloseSessionList m_closeSessionList; mutable boost::mutex m_closeSessionListMutex; + RemoveGameList m_removeGameList; + mutable boost::mutex m_removeGameListMutex; + GameMap m_gameMap; std::auto_ptr m_receiver; diff --git a/src/net/sessionmanager.h b/src/net/sessionmanager.h index 7a5c03bb..9ef49ce4 100644 --- a/src/net/sessionmanager.h +++ b/src/net/sessionmanager.h @@ -46,6 +46,8 @@ public: SessionManager(); virtual ~SessionManager(); + bool HasSessions() const; + void AddSession(boost::shared_ptr sessionData); // new Sessions without player data void AddSession(SessionWrapper session); void SetSessionPlayerData(SOCKET session, boost::shared_ptr playerData);