From f932e399834b787f1b4b6553ffcd8beb854dee81 Mon Sep 17 00:00:00 2001 From: lotodore Date: Sun, 3 Jun 2007 14:57:33 +0000 Subject: [PATCH] Players should now be able to leave a network game, the other players can continue the game (if it wasn't the server who left). --- src/net/common/clientstate.cpp | 34 ++++++-- src/net/common/serverrecvstate.cpp | 128 ++++++++++++++++++---------- src/net/common/serverrecvthread.cpp | 14 ++- src/net/serverrecvstate.h | 5 +- 4 files changed, 125 insertions(+), 56 deletions(-) diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 1be41e19..09ceed73 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -385,6 +385,33 @@ AbstractClientStateReceiving::Process(ClientThread &client) if (tmpPlayer.get()) client.GetCallback().SignalNetClientChatMsg(tmpPlayer->GetName(), chatData.text); } + else if (tmpPacket->ToNetPacketPlayerLeft()) + { + // A player left the game. + NetPacketPlayerLeft::Data playerLeftData; + tmpPacket->ToNetPacketPlayerLeft()->GetData(playerLeftData); + + // Signal to GUI. + client.RemovePlayerData(playerLeftData.playerId); + + // If the game is running, deactivate player. + boost::shared_ptr curGame = client.GetGame(); + if (curGame.get()) + { + PlayerInterface *tmpPlayer = curGame->getPlayerByUniqueId(playerLeftData.playerId); + if (!tmpPlayer) + throw ClientException(ERR_NET_UNKNOWN_PLAYER_ID, 0); + + // Reset his action and his cash. + tmpPlayer->setMyAction(PLAYER_ACTION_FOLD); + tmpPlayer->setMyCash(0); + // Player is now inactive. + tmpPlayer->setMyActiveStatus(false); + + client.GetGui().refreshAction(); + client.GetGui().refreshCash(); + } + } else retVal = InternalProcess(client, tmpPacket); } @@ -490,13 +517,6 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptrSetName(netPlayerData.playerName); client.AddPlayerData(playerData); } - else if (packet->ToNetPacketPlayerLeft()) - { - // Another player left the network game. - NetPacketPlayerLeft::Data netPlayerData; - packet->ToNetPacketPlayerLeft()->GetData(netPlayerData); - client.RemovePlayerData(netPlayerData.playerId); - } // TODO: handle error packet (kicked from server) return retVal; diff --git a/src/net/common/serverrecvstate.cpp b/src/net/common/serverrecvstate.cpp index c64194a2..a18ab7a9 100644 --- a/src/net/common/serverrecvstate.cpp +++ b/src/net/common/serverrecvstate.cpp @@ -35,6 +35,34 @@ using namespace std; #define SERVER_WAIT_TIMEOUT_MSEC 50 #define SERVER_NEXT_HAND_DELAY_SEC 10 +// Helper functions + +static PlayerInterface *GetCurrentPlayer(Game &curGame) +{ + int curPlayerNum = 0; + // TODO: no switch needed here if game states are polymorphic + switch(curGame.getCurrentHand()->getActualRound()) { + case GAME_STATE_PREFLOP: { + curPlayerNum = curGame.getCurrentHand()->getPreflop()->getPlayersTurn(); + } break; + case GAME_STATE_FLOP: { + curPlayerNum = curGame.getCurrentHand()->getFlop()->getPlayersTurn(); + } break; + case GAME_STATE_TURN: { + curPlayerNum = curGame.getCurrentHand()->getTurn()->getPlayersTurn(); + } break; + case GAME_STATE_RIVER: { + curPlayerNum = curGame.getCurrentHand()->getRiver()->getPlayersTurn(); + } break; + default: { + // + } + } + assert(curPlayerNum < curGame.getStartQuantityPlayers()); // TODO: throw exception + return curGame.getPlayerArray()[curPlayerNum]; +} + +//----------------------------------------------------------------------------- ServerRecvState::~ServerRecvState() { @@ -567,32 +595,6 @@ ServerRecvStateStartRound::GameRun(Game &curGame) } } -PlayerInterface * -ServerRecvStateStartRound::GetCurrentPlayer(Game &curGame) -{ - int curPlayerNum = 0; - // TODO: no switch needed here if game states are polymorphic - switch(curGame.getCurrentHand()->getActualRound()) { - case GAME_STATE_PREFLOP: { - curPlayerNum = curGame.getCurrentHand()->getPreflop()->getPlayersTurn(); - } break; - case GAME_STATE_FLOP: { - curPlayerNum = curGame.getCurrentHand()->getFlop()->getPlayersTurn(); - } break; - case GAME_STATE_TURN: { - curPlayerNum = curGame.getCurrentHand()->getTurn()->getPlayersTurn(); - } break; - case GAME_STATE_RIVER: { - curPlayerNum = curGame.getCurrentHand()->getRiver()->getPlayersTurn(); - } break; - default: { - // - } - } - assert(curPlayerNum < curGame.getStartQuantityPlayers()); // TODO: throw exception - return curGame.getPlayerArray()[curPlayerNum]; -} - void ServerRecvStateStartRound::SendNewRoundCards(ServerRecvThread &server, Game &curGame, int state) { @@ -655,6 +657,28 @@ ServerRecvStateWaitPlayerAction::~ServerRecvStateWaitPlayerAction() { } +int +ServerRecvStateWaitPlayerAction::Process(ServerRecvThread &server) +{ + int retVal; + + // If the player we are waiting for left, continue without him. + PlayerInterface *tmpPlayer = GetCurrentPlayer(server.GetGame()); + assert(tmpPlayer); + if (!tmpPlayer->getMyActiveStatus()) + { + assert(tmpPlayer->getMyAction() == PLAYER_ACTION_FOLD && tmpPlayer->getMyCash() == 0); + PerformPlayerAction(server, tmpPlayer, PLAYER_ACTION_FOLD, 0); + + server.SetState(ServerRecvStateStartRound::Instance()); + retVal = MSG_NET_GAME_SERVER_ACTION; + } + else + retVal = ServerRecvStateReceiving::Process(server); + + return retVal; +} + int ServerRecvStateWaitPlayerAction::InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet) { @@ -668,28 +692,10 @@ ServerRecvStateWaitPlayerAction::InternalProcess(ServerRecvThread &server, Sessi Game &curGame = server.GetGame(); PlayerInterface *tmpPlayer = curGame.getPlayerByUniqueId(session.playerData->GetUniqueId()); assert(tmpPlayer); // TODO throw exception + // TODO: check whether this is the correct player + // TODO: check game state - tmpPlayer->setMyAction(actionData.playerAction); - // Only change the player bet if action is not fold/check - if (actionData.playerAction != PLAYER_ACTION_FOLD && actionData.playerAction != PLAYER_ACTION_CHECK) - { - tmpPlayer->setMySet(actionData.playerBet); - - if (tmpPlayer->getMySet() > GetHighestSet(curGame)) - SetHighestSet(curGame, tmpPlayer->getMySet()); - } - - boost::shared_ptr notifyActionDone(new NetPacketPlayersActionDone); - NetPacketPlayersActionDone::Data actionDoneData; - actionDoneData.gameState = static_cast(curGame.getCurrentHand()->getActualRound()); - actionDoneData.playerId = session.playerData->GetUniqueId(); - actionDoneData.playerAction = actionData.playerAction; - actionDoneData.totalPlayerBet = tmpPlayer->getMySet(); - actionDoneData.playerMoney = tmpPlayer->getMyCash(); - actionDoneData.potSize = curGame.getCurrentHand()->getBoard()->getPot(); - actionDoneData.curHandBets = curGame.getCurrentHand()->getBoard()->getSets(); - static_cast(notifyActionDone.get())->SetData(actionDoneData); - server.SendToAllPlayers(notifyActionDone); + PerformPlayerAction(server, tmpPlayer, actionData.playerAction, actionData.playerBet); server.SetState(ServerRecvStateStartRound::Instance()); retVal = MSG_NET_GAME_SERVER_ACTION; @@ -698,6 +704,34 @@ ServerRecvStateWaitPlayerAction::InternalProcess(ServerRecvThread &server, Sessi return retVal; } +void +ServerRecvStateWaitPlayerAction::PerformPlayerAction(ServerRecvThread &server, PlayerInterface *player, PlayerAction action, int bet) +{ + Game &curGame = server.GetGame(); + assert(player); + player->setMyAction(action); + // Only change the player bet if action is not fold/check + if (action != PLAYER_ACTION_FOLD && action != PLAYER_ACTION_CHECK) + { + player->setMySet(bet); + + if (player->getMySet() > GetHighestSet(curGame)) + SetHighestSet(curGame, player->getMySet()); + } + + boost::shared_ptr notifyActionDone(new NetPacketPlayersActionDone); + NetPacketPlayersActionDone::Data actionDoneData; + actionDoneData.gameState = static_cast(curGame.getCurrentHand()->getActualRound()); + actionDoneData.playerId = player->getMyUniqueID(); + actionDoneData.playerAction = static_cast(player->getMyAction()); + actionDoneData.totalPlayerBet = player->getMySet(); + actionDoneData.playerMoney = player->getMyCash(); + actionDoneData.potSize = curGame.getCurrentHand()->getBoard()->getPot(); + actionDoneData.curHandBets = curGame.getCurrentHand()->getBoard()->getSets(); + static_cast(notifyActionDone.get())->SetData(actionDoneData); + server.SendToAllPlayers(notifyActionDone); +} + int ServerRecvStateWaitPlayerAction::GetHighestSet(Game &curGame) { diff --git a/src/net/common/serverrecvthread.cpp b/src/net/common/serverrecvthread.cpp index 2df9973e..c9f99a38 100644 --- a/src/net/common/serverrecvthread.cpp +++ b/src/net/common/serverrecvthread.cpp @@ -346,7 +346,17 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session) boost::shared_ptr tmpPlayerData = session.playerData; if (tmpPlayerData.get() && !tmpPlayerData->GetName().empty()) { - GetCallback().SignalNetServerPlayerLeft(tmpPlayerData->GetName()); + // Set player inactive. + if (m_game.get()) + { + PlayerInterface *player = GetGame().getPlayerByUniqueId(tmpPlayerData->GetUniqueId()); + if (player) + { + player->setMyAction(PLAYER_ACTION_FOLD); + player->setMyCash(0); + player->setMyActiveStatus(false); + } + } // Send "Player Left" to clients. boost::shared_ptr thisPlayerLeft(new NetPacketPlayerLeft); @@ -354,6 +364,8 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session) thisPlayerLeftData.playerId = tmpPlayerData->GetUniqueId(); static_cast(thisPlayerLeft.get())->SetData(thisPlayerLeftData); SendToAllPlayers(thisPlayerLeft); + + GetCallback().SignalNetServerPlayerLeft(tmpPlayerData->GetName()); } boost::microsec_timer closeTimer; diff --git a/src/net/serverrecvstate.h b/src/net/serverrecvstate.h index 6a495fd8..9d0f61da 100644 --- a/src/net/serverrecvstate.h +++ b/src/net/serverrecvstate.h @@ -157,7 +157,6 @@ protected: ServerRecvStateStartRound(); static void GameRun(Game &curGame); - static PlayerInterface *GetCurrentPlayer(Game &curGame); static void SendNewRoundCards(ServerRecvThread &server, Game &curGame, int state); }; @@ -170,6 +169,9 @@ public: virtual ~ServerRecvStateWaitPlayerAction(); + // Handle leaving players. + virtual int Process(ServerRecvThread &server); + protected: // Protected constructor - this is a singleton. @@ -177,6 +179,7 @@ protected: virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet); + static void PerformPlayerAction(ServerRecvThread &server, PlayerInterface *player, PlayerAction action, int bet); static int GetHighestSet(Game &curGame); static void SetHighestSet(Game &curGame, int highestSet); };