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).
This commit is contained in:
@@ -385,6 +385,33 @@ AbstractClientStateReceiving::Process(ClientThread &client)
|
|||||||
if (tmpPlayer.get())
|
if (tmpPlayer.get())
|
||||||
client.GetCallback().SignalNetClientChatMsg(tmpPlayer->GetName(), chatData.text);
|
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<Game> 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
|
else
|
||||||
retVal = InternalProcess(client, tmpPacket);
|
retVal = InternalProcess(client, tmpPacket);
|
||||||
}
|
}
|
||||||
@@ -490,13 +517,6 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptr<Net
|
|||||||
playerData->SetName(netPlayerData.playerName);
|
playerData->SetName(netPlayerData.playerName);
|
||||||
client.AddPlayerData(playerData);
|
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)
|
// TODO: handle error packet (kicked from server)
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|||||||
@@ -35,6 +35,34 @@ using namespace std;
|
|||||||
#define SERVER_WAIT_TIMEOUT_MSEC 50
|
#define SERVER_WAIT_TIMEOUT_MSEC 50
|
||||||
#define SERVER_NEXT_HAND_DELAY_SEC 10
|
#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()
|
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
|
void
|
||||||
ServerRecvStateStartRound::SendNewRoundCards(ServerRecvThread &server, Game &curGame, int state)
|
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
|
int
|
||||||
ServerRecvStateWaitPlayerAction::InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
ServerRecvStateWaitPlayerAction::InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
||||||
{
|
{
|
||||||
@@ -668,28 +692,10 @@ ServerRecvStateWaitPlayerAction::InternalProcess(ServerRecvThread &server, Sessi
|
|||||||
Game &curGame = server.GetGame();
|
Game &curGame = server.GetGame();
|
||||||
PlayerInterface *tmpPlayer = curGame.getPlayerByUniqueId(session.playerData->GetUniqueId());
|
PlayerInterface *tmpPlayer = curGame.getPlayerByUniqueId(session.playerData->GetUniqueId());
|
||||||
assert(tmpPlayer); // TODO throw exception
|
assert(tmpPlayer); // TODO throw exception
|
||||||
|
// TODO: check whether this is the correct player
|
||||||
|
// TODO: check game state
|
||||||
|
|
||||||
tmpPlayer->setMyAction(actionData.playerAction);
|
PerformPlayerAction(server, tmpPlayer, actionData.playerAction, actionData.playerBet);
|
||||||
// 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<NetPacket> notifyActionDone(new NetPacketPlayersActionDone);
|
|
||||||
NetPacketPlayersActionDone::Data actionDoneData;
|
|
||||||
actionDoneData.gameState = static_cast<GameState>(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<NetPacketPlayersActionDone *>(notifyActionDone.get())->SetData(actionDoneData);
|
|
||||||
server.SendToAllPlayers(notifyActionDone);
|
|
||||||
|
|
||||||
server.SetState(ServerRecvStateStartRound::Instance());
|
server.SetState(ServerRecvStateStartRound::Instance());
|
||||||
retVal = MSG_NET_GAME_SERVER_ACTION;
|
retVal = MSG_NET_GAME_SERVER_ACTION;
|
||||||
@@ -698,6 +704,34 @@ ServerRecvStateWaitPlayerAction::InternalProcess(ServerRecvThread &server, Sessi
|
|||||||
return retVal;
|
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<NetPacket> notifyActionDone(new NetPacketPlayersActionDone);
|
||||||
|
NetPacketPlayersActionDone::Data actionDoneData;
|
||||||
|
actionDoneData.gameState = static_cast<GameState>(curGame.getCurrentHand()->getActualRound());
|
||||||
|
actionDoneData.playerId = player->getMyUniqueID();
|
||||||
|
actionDoneData.playerAction = static_cast<PlayerAction>(player->getMyAction());
|
||||||
|
actionDoneData.totalPlayerBet = player->getMySet();
|
||||||
|
actionDoneData.playerMoney = player->getMyCash();
|
||||||
|
actionDoneData.potSize = curGame.getCurrentHand()->getBoard()->getPot();
|
||||||
|
actionDoneData.curHandBets = curGame.getCurrentHand()->getBoard()->getSets();
|
||||||
|
static_cast<NetPacketPlayersActionDone *>(notifyActionDone.get())->SetData(actionDoneData);
|
||||||
|
server.SendToAllPlayers(notifyActionDone);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ServerRecvStateWaitPlayerAction::GetHighestSet(Game &curGame)
|
ServerRecvStateWaitPlayerAction::GetHighestSet(Game &curGame)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -346,7 +346,17 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session)
|
|||||||
boost::shared_ptr<PlayerData> tmpPlayerData = session.playerData;
|
boost::shared_ptr<PlayerData> tmpPlayerData = session.playerData;
|
||||||
if (tmpPlayerData.get() && !tmpPlayerData->GetName().empty())
|
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.
|
// Send "Player Left" to clients.
|
||||||
boost::shared_ptr<NetPacket> thisPlayerLeft(new NetPacketPlayerLeft);
|
boost::shared_ptr<NetPacket> thisPlayerLeft(new NetPacketPlayerLeft);
|
||||||
@@ -354,6 +364,8 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session)
|
|||||||
thisPlayerLeftData.playerId = tmpPlayerData->GetUniqueId();
|
thisPlayerLeftData.playerId = tmpPlayerData->GetUniqueId();
|
||||||
static_cast<NetPacketPlayerLeft *>(thisPlayerLeft.get())->SetData(thisPlayerLeftData);
|
static_cast<NetPacketPlayerLeft *>(thisPlayerLeft.get())->SetData(thisPlayerLeftData);
|
||||||
SendToAllPlayers(thisPlayerLeft);
|
SendToAllPlayers(thisPlayerLeft);
|
||||||
|
|
||||||
|
GetCallback().SignalNetServerPlayerLeft(tmpPlayerData->GetName());
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::microsec_timer closeTimer;
|
boost::microsec_timer closeTimer;
|
||||||
|
|||||||
@@ -157,7 +157,6 @@ protected:
|
|||||||
ServerRecvStateStartRound();
|
ServerRecvStateStartRound();
|
||||||
|
|
||||||
static void GameRun(Game &curGame);
|
static void GameRun(Game &curGame);
|
||||||
static PlayerInterface *GetCurrentPlayer(Game &curGame);
|
|
||||||
static void SendNewRoundCards(ServerRecvThread &server, Game &curGame, int state);
|
static void SendNewRoundCards(ServerRecvThread &server, Game &curGame, int state);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -170,6 +169,9 @@ public:
|
|||||||
|
|
||||||
virtual ~ServerRecvStateWaitPlayerAction();
|
virtual ~ServerRecvStateWaitPlayerAction();
|
||||||
|
|
||||||
|
// Handle leaving players.
|
||||||
|
virtual int Process(ServerRecvThread &server);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Protected constructor - this is a singleton.
|
// Protected constructor - this is a singleton.
|
||||||
@@ -177,6 +179,7 @@ protected:
|
|||||||
|
|
||||||
virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||||
|
|
||||||
|
static void PerformPlayerAction(ServerRecvThread &server, PlayerInterface *player, PlayerAction action, int bet);
|
||||||
static int GetHighestSet(Game &curGame);
|
static int GetHighestSet(Game &curGame);
|
||||||
static void SetHighestSet(Game &curGame, int highestSet);
|
static void SetHighestSet(Game &curGame, int highestSet);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user