From 26299e80c05e1946ca1b739e97d21b1223c5e81d Mon Sep 17 00:00:00 2001 From: lotodore Date: Sat, 11 Aug 2007 10:02:04 +0000 Subject: [PATCH] Server states can now handle multiple games (are multithreading capable). --- src/game.cpp | 8 ++ src/game.h | 1 + src/net/common/serverrecvstate.cpp | 149 ++++++++++++++++++----------- src/net/serverrecvstate.h | 77 +++++++++++---- src/net/serverrecvthread.h | 4 +- 5 files changed, 163 insertions(+), 76 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 287060ea..d16b1e53 100755 --- a/src/game.cpp +++ b/src/game.cpp @@ -199,3 +199,11 @@ boost::shared_ptr Game::getPlayerByUniqueId(unsigned id) } return tmpPlayer; } + +boost::shared_ptr Game::getCurrentPlayer() +{ + int curPlayerNum = getCurrentHand()->getCurrentBeRo()->getPlayersTurn(); + assert(curPlayerNum < getStartQuantityPlayers()); + return getPlayerArray()[curPlayerNum]; +} + diff --git a/src/game.h b/src/game.h index 7ad078ea..df7a5e5a 100755 --- a/src/game.h +++ b/src/game.h @@ -74,6 +74,7 @@ public: int getActualHandID() const { return actualHandID; } boost::shared_ptr getPlayerByUniqueId(unsigned id); + boost::shared_ptr getCurrentPlayer(); private: boost::shared_ptr myFactory; diff --git a/src/net/common/serverrecvstate.cpp b/src/net/common/serverrecvstate.cpp index e07841d9..db8eef0a 100644 --- a/src/net/common/serverrecvstate.cpp +++ b/src/net/common/serverrecvstate.cpp @@ -45,13 +45,6 @@ using namespace std; // Helper functions // TODO: these are hacks. -static boost::shared_ptr GetCurrentPlayer(Game &curGame) -{ - int curPlayerNum = curGame.getCurrentHand()->getCurrentBeRo()->getPlayersTurn(); - assert(curPlayerNum < curGame.getStartQuantityPlayers()); // TODO: throw exception - return curGame.getPlayerArray()[curPlayerNum]; -} - static void SendNewRoundCards(ServerRecvThread &server, Game &curGame, int state) { // TODO: no switch needed here if game states are polymorphic @@ -104,40 +97,44 @@ ServerRecvState::~ServerRecvState() //----------------------------------------------------------------------------- -ServerRecvStateReceiving::ServerRecvStateReceiving() +AbstractServerRecvStateReceiving::AbstractServerRecvStateReceiving() { } -ServerRecvStateReceiving::~ServerRecvStateReceiving() +AbstractServerRecvStateReceiving::~AbstractServerRecvStateReceiving() { } int -ServerRecvStateReceiving::Process(ServerRecvThread &server) +AbstractServerRecvStateReceiving::Process(ServerRecvThread &server) { + // This is the receive loop for the server. int retVal = MSG_SOCK_INTERNAL_PENDING; SOCKET recvSock = server.Select(); if (recvSock != INVALID_SOCKET) { + // If data is available, find the corresponding session. SessionWrapper session = server.GetSession(recvSock); + // The session must exist. + assert(session.sessionData.get()); + boost::shared_ptr packet; try { + // Receive the packet. packet = server.GetReceiver().Recv(recvSock); } catch (const NetException &) { - if (session.sessionData.get()) - { - server.CloseSessionDelayed(session); - return retVal; - } + server.CloseSessionDelayed(session); + return retVal; } - // Ignore if no session / no packet. - if (packet.get() && session.sessionData.get()) + // Process packet if one was received. + if (packet.get()) { - if (packet->ToNetPacketSendChatText()) // Chat text is always allowed. + // Chat text is always allowed. + if (packet->ToNetPacketSendChatText()) { if (session.playerData.get()) // Only forward if this player is known. { @@ -155,7 +152,10 @@ ServerRecvStateReceiving::Process(ServerRecvThread &server) } } else - retVal = InternalProcess(server, session, packet); // Let other class handle this. + { + // Packet processing in subclass. + retVal = InternalProcess(server, session, packet); + } } } return retVal; @@ -163,16 +163,16 @@ ServerRecvStateReceiving::Process(ServerRecvThread &server) //----------------------------------------------------------------------------- -ServerRecvStateTimer::ServerRecvStateTimer() +AbstractServerRecvStateTimer::AbstractServerRecvStateTimer() { } -ServerRecvStateTimer::~ServerRecvStateTimer() +AbstractServerRecvStateTimer::~AbstractServerRecvStateTimer() { } void -ServerRecvStateTimer::Init() +AbstractServerRecvStateTimer::Init() { m_timer.reset(); m_timer.start(); @@ -180,11 +180,15 @@ ServerRecvStateTimer::Init() //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateInit::Ptr; + ServerRecvStateInit & ServerRecvStateInit::Instance() { - static ServerRecvStateInit state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateInit); + + return *Ptr; } ServerRecvStateInit::ServerRecvStateInit() @@ -358,16 +362,16 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se //----------------------------------------------------------------------------- -ServerRecvStateRunning::ServerRecvStateRunning() +AbstractServerRecvStateRunning::AbstractServerRecvStateRunning() { } -ServerRecvStateRunning::~ServerRecvStateRunning() +AbstractServerRecvStateRunning::~AbstractServerRecvStateRunning() { } void -ServerRecvStateRunning::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr connData) +AbstractServerRecvStateRunning::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr connData) { // Do not accept new connections in this state. server.RejectNewConnection(connData); @@ -375,11 +379,15 @@ ServerRecvStateRunning::HandleNewConnection(ServerRecvThread &server, boost::sha //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateStartGame::Ptr; + ServerRecvStateStartGame & ServerRecvStateStartGame::Instance() { - static ServerRecvStateStartGame state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateStartGame); + + return *Ptr; } ServerRecvStateStartGame::ServerRecvStateStartGame() @@ -398,7 +406,8 @@ ServerRecvStateStartGame::Process(ServerRecvThread &server) NetPacketGameStart::Data gameStartData; gameStartData.startData = server.GetStartData(); - // Assign player numbers. Assume Player List is sorted by number. + // Send player order to clients. + // Assume player list is sorted by number. PlayerDataList tmpPlayerList = server.GetPlayerDataList(); PlayerDataList::iterator player_i = tmpPlayerList.begin(); PlayerDataList::iterator player_end = tmpPlayerList.end(); @@ -421,11 +430,15 @@ ServerRecvStateStartGame::Process(ServerRecvThread &server) //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateStartHand::Ptr; + ServerRecvStateStartHand & ServerRecvStateStartHand::Instance() { - static ServerRecvStateStartHand state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateStartHand); + + return *Ptr; } ServerRecvStateStartHand::ServerRecvStateStartHand() @@ -514,11 +527,15 @@ ServerRecvStateStartHand::Process(ServerRecvThread &server) //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateStartRound::Ptr; + ServerRecvStateStartRound & ServerRecvStateStartRound::Instance() { - static ServerRecvStateStartRound state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateStartRound); + + return *Ptr; } ServerRecvStateStartRound::ServerRecvStateStartRound() @@ -595,8 +612,8 @@ ServerRecvStateStartRound::Process(ServerRecvThread &server) assert (!curGame.getCurrentHand()->getAllInCondition()); // this would be an error. // Retrieve current player. - boost::shared_ptr curPlayer = GetCurrentPlayer(curGame); - assert(curPlayer); // TODO throw exception + boost::shared_ptr curPlayer = curGame.getCurrentPlayer(); + assert(curPlayer.get()); // TODO throw exception assert(curPlayer->getMyActiveStatus()); // TODO throw exception boost::shared_ptr notification(new NetPacketPlayersTurn); @@ -713,11 +730,15 @@ ServerRecvStateStartRound::GetActivePlayers(Game &curGame) //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateWaitPlayerAction::Ptr; + ServerRecvStateWaitPlayerAction & ServerRecvStateWaitPlayerAction::Instance() { - static ServerRecvStateWaitPlayerAction state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateWaitPlayerAction); + + return *Ptr; } ServerRecvStateWaitPlayerAction::ServerRecvStateWaitPlayerAction() @@ -733,7 +754,7 @@ ServerRecvStateWaitPlayerAction::Process(ServerRecvThread &server) { int retVal; - boost::shared_ptr tmpPlayer = GetCurrentPlayer(server.GetGame()); + boost::shared_ptr tmpPlayer = server.GetGame().getCurrentPlayer(); assert(tmpPlayer.get()); assert(!tmpPlayer->getMyName().empty()); @@ -766,7 +787,7 @@ ServerRecvStateWaitPlayerAction::Process(ServerRecvThread &server) retVal = MSG_NET_GAME_SERVER_ACTION; } else - retVal = ServerRecvStateReceiving::Process(server); + retVal = AbstractServerRecvStateReceiving::Process(server); return retVal; } @@ -835,11 +856,15 @@ ServerRecvStateWaitPlayerAction::SendPlayerAction(ServerRecvThread &server, boos //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateDealCardsDelay::Ptr; + ServerRecvStateDealCardsDelay & ServerRecvStateDealCardsDelay::Instance() { - static ServerRecvStateDealCardsDelay state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateDealCardsDelay); + + return *Ptr; } ServerRecvStateDealCardsDelay::ServerRecvStateDealCardsDelay() @@ -853,7 +878,7 @@ ServerRecvStateDealCardsDelay::~ServerRecvStateDealCardsDelay() int ServerRecvStateDealCardsDelay::Process(ServerRecvThread &server) { - int retVal = ServerRecvStateReceiving::Process(server); + int retVal = AbstractServerRecvStateReceiving::Process(server); Game &curGame = server.GetGame(); @@ -886,11 +911,15 @@ ServerRecvStateDealCardsDelay::InternalProcess(ServerRecvThread &server, Session //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateShowCardsDelay::Ptr; + ServerRecvStateShowCardsDelay & ServerRecvStateShowCardsDelay::Instance() { - static ServerRecvStateShowCardsDelay state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateShowCardsDelay); + + return *Ptr; } ServerRecvStateShowCardsDelay::ServerRecvStateShowCardsDelay() @@ -904,7 +933,7 @@ ServerRecvStateShowCardsDelay::~ServerRecvStateShowCardsDelay() int ServerRecvStateShowCardsDelay::Process(ServerRecvThread &server) { - int retVal = ServerRecvStateReceiving::Process(server); + int retVal = AbstractServerRecvStateReceiving::Process(server); if (GetTimer().elapsed().total_seconds() >= SERVER_SHOW_CARDS_DELAY_SEC) { @@ -926,11 +955,15 @@ ServerRecvStateShowCardsDelay::InternalProcess(ServerRecvThread &server, Session //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateNextHandDelay::Ptr; + ServerRecvStateNextHandDelay & ServerRecvStateNextHandDelay::Instance() { - static ServerRecvStateNextHandDelay state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateNextHandDelay); + + return *Ptr; } ServerRecvStateNextHandDelay::ServerRecvStateNextHandDelay() @@ -944,7 +977,7 @@ ServerRecvStateNextHandDelay::~ServerRecvStateNextHandDelay() int ServerRecvStateNextHandDelay::Process(ServerRecvThread &server) { - int retVal = ServerRecvStateReceiving::Process(server); + int retVal = AbstractServerRecvStateReceiving::Process(server); if (GetTimer().elapsed().total_seconds() >= SERVER_DELAY_NEXT_HAND_SEC) server.SetState(ServerRecvStateStartHand::Instance()); @@ -960,11 +993,15 @@ ServerRecvStateNextHandDelay::InternalProcess(ServerRecvThread &server, SessionW //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateNextGameDelay::Ptr; + ServerRecvStateNextGameDelay & ServerRecvStateNextGameDelay::Instance() { - static ServerRecvStateNextGameDelay state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateNextGameDelay); + + return *Ptr; } ServerRecvStateNextGameDelay::ServerRecvStateNextGameDelay() @@ -978,7 +1015,7 @@ ServerRecvStateNextGameDelay::~ServerRecvStateNextGameDelay() int ServerRecvStateNextGameDelay::Process(ServerRecvThread &server) { - int retVal = ServerRecvStateReceiving::Process(server); + int retVal = AbstractServerRecvStateReceiving::Process(server); if (GetTimer().elapsed().total_seconds() >= SERVER_DELAY_NEXT_GAME_SEC) { @@ -1014,11 +1051,15 @@ ServerRecvStateNextGameDelay::InternalProcess(ServerRecvThread &server, SessionW //----------------------------------------------------------------------------- +boost::thread_specific_ptr ServerRecvStateFinal::Ptr; + ServerRecvStateFinal & ServerRecvStateFinal::Instance() { - static ServerRecvStateFinal state; - return state; + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateFinal); + + return *Ptr; } ServerRecvStateFinal::ServerRecvStateFinal() diff --git a/src/net/serverrecvstate.h b/src/net/serverrecvstate.h index 37d7a733..e940e550 100644 --- a/src/net/serverrecvstate.h +++ b/src/net/serverrecvstate.h @@ -52,10 +52,10 @@ public: }; // Abstract State: Receiving. -class ServerRecvStateReceiving : virtual public ServerRecvState +class AbstractServerRecvStateReceiving : virtual public ServerRecvState { public: - virtual ~ServerRecvStateReceiving(); + virtual ~AbstractServerRecvStateReceiving(); // Globally handle packets which are allowed in all running states. // Calls InternalProcess if packet has not been processed. @@ -63,16 +63,16 @@ public: protected: - ServerRecvStateReceiving(); + AbstractServerRecvStateReceiving(); virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet) = 0; }; // Abstract State: Timer. -class ServerRecvStateTimer : virtual public ServerRecvState +class AbstractServerRecvStateTimer : virtual public ServerRecvState { public: - virtual ~ServerRecvStateTimer(); + virtual ~AbstractServerRecvStateTimer(); virtual void Init(); @@ -80,28 +80,28 @@ public: protected: - ServerRecvStateTimer(); + AbstractServerRecvStateTimer(); private: boost::microsec_timer m_timer; }; // Abstract State: Game is running. -class ServerRecvStateRunning : virtual public ServerRecvState +class AbstractServerRecvStateRunning : virtual public ServerRecvState { public: - virtual ~ServerRecvStateRunning(); + virtual ~AbstractServerRecvStateRunning(); // Reject new connections. virtual void HandleNewConnection(ServerRecvThread &server, boost::shared_ptr data); protected: - ServerRecvStateRunning(); + AbstractServerRecvStateRunning(); }; // State: Initialization. -class ServerRecvStateInit : public ServerRecvStateReceiving +class ServerRecvStateInit : public AbstractServerRecvStateReceiving { public: // Access the state singleton. @@ -122,11 +122,12 @@ protected: private: - u_int16_t m_curUniquePlayerId; + u_int16_t m_curUniquePlayerId; + static boost::thread_specific_ptr Ptr; }; // State: Start server game. -class ServerRecvStateStartGame : public ServerRecvStateRunning +class ServerRecvStateStartGame : public AbstractServerRecvStateRunning { public: // Access the state singleton. @@ -143,10 +144,14 @@ protected: // Protected constructor - this is a singleton. ServerRecvStateStartGame(); + +private: + + static boost::thread_specific_ptr Ptr; }; // State: Start new hand. -class ServerRecvStateStartHand : public ServerRecvStateRunning +class ServerRecvStateStartHand : public AbstractServerRecvStateRunning { public: // Access the state singleton. @@ -163,10 +168,14 @@ protected: // Protected constructor - this is a singleton. ServerRecvStateStartHand(); + +private: + + static boost::thread_specific_ptr Ptr; }; // State: Start new round. -class ServerRecvStateStartRound : public ServerRecvStateRunning +class ServerRecvStateStartRound : public AbstractServerRecvStateRunning { public: // Access the state singleton. @@ -185,10 +194,14 @@ protected: ServerRecvStateStartRound(); static std::list > GetActivePlayers(Game &curGame); + +private: + + static boost::thread_specific_ptr Ptr; }; // State: Wait for a player action. -class ServerRecvStateWaitPlayerAction : public ServerRecvStateReceiving, public ServerRecvStateRunning, public ServerRecvStateTimer +class ServerRecvStateWaitPlayerAction : public AbstractServerRecvStateReceiving, public AbstractServerRecvStateRunning, public AbstractServerRecvStateTimer { public: // Access the state singleton. @@ -208,10 +221,14 @@ protected: static void PerformPlayerAction(ServerRecvThread &server, boost::shared_ptr player, PlayerAction action, int bet); static void SendPlayerAction(ServerRecvThread &server, boost::shared_ptr player); + +private: + + static boost::thread_specific_ptr Ptr; }; // State: Delay after dealing cards -class ServerRecvStateDealCardsDelay : public ServerRecvStateReceiving, public ServerRecvStateRunning, public ServerRecvStateTimer +class ServerRecvStateDealCardsDelay : public AbstractServerRecvStateReceiving, public AbstractServerRecvStateRunning, public AbstractServerRecvStateTimer { public: // Access the state singleton. @@ -228,10 +245,14 @@ protected: ServerRecvStateDealCardsDelay(); virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet); + +private: + + static boost::thread_specific_ptr Ptr; }; // State: Delay after showing cards (all in) -class ServerRecvStateShowCardsDelay : public ServerRecvStateReceiving, public ServerRecvStateRunning, public ServerRecvStateTimer +class ServerRecvStateShowCardsDelay : public AbstractServerRecvStateReceiving, public AbstractServerRecvStateRunning, public AbstractServerRecvStateTimer { public: // Access the state singleton. @@ -248,10 +269,14 @@ protected: ServerRecvStateShowCardsDelay(); virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet); + +private: + + static boost::thread_specific_ptr Ptr; }; // State: Delay before next hand. -class ServerRecvStateNextHandDelay : public ServerRecvStateReceiving, public ServerRecvStateRunning, public ServerRecvStateTimer +class ServerRecvStateNextHandDelay : public AbstractServerRecvStateReceiving, public AbstractServerRecvStateRunning, public AbstractServerRecvStateTimer { public: // Access the state singleton. @@ -268,10 +293,14 @@ protected: ServerRecvStateNextHandDelay(); virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet); + +private: + + static boost::thread_specific_ptr Ptr; }; // State: Delay before next hand. -class ServerRecvStateNextGameDelay : public ServerRecvStateReceiving, public ServerRecvStateRunning, public ServerRecvStateTimer +class ServerRecvStateNextGameDelay : public AbstractServerRecvStateReceiving, public AbstractServerRecvStateRunning, public AbstractServerRecvStateTimer { public: // Access the state singleton. @@ -288,10 +317,14 @@ protected: ServerRecvStateNextGameDelay(); virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet); + +private: + + static boost::thread_specific_ptr Ptr; }; // State: Final. -class ServerRecvStateFinal : public ServerRecvStateReceiving, public ServerRecvStateRunning +class ServerRecvStateFinal : public AbstractServerRecvStateReceiving, public AbstractServerRecvStateRunning { public: // Access the state singleton. @@ -307,6 +340,10 @@ protected: ServerRecvStateFinal(); virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet); + +private: + + static boost::thread_specific_ptr Ptr; }; #ifdef _MSC_VER diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h index 402d4831..4801d84b 100644 --- a/src/net/serverrecvthread.h +++ b/src/net/serverrecvthread.h @@ -169,8 +169,8 @@ private: ConfigFile *m_playerConfig; friend class ServerRecvStateInit; -friend class ServerRecvStateReceiving; -friend class ServerRecvStateRunning; +friend class AbstractServerRecvStateReceiving; +friend class AbstractServerRecvStateRunning; friend class ServerRecvStateStartGame; friend class ServerRecvStateStartHand; friend class ServerRecvStateStartRound;