More than one game cannot be created yet, but this is only due to no name input. Lots of issues still, don't expect this to be stable.
1066 lines
33 KiB
C++
1066 lines
33 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2007 by Lothar May *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
***************************************************************************/
|
|
|
|
#include <net/servergamestate.h>
|
|
#include <net/servergamethread.h>
|
|
#include <net/receiverhelper.h>
|
|
#include <net/senderthread.h>
|
|
#include <net/netpacket.h>
|
|
#include <net/socket_msg.h>
|
|
#include <net/netexception.h>
|
|
#include <core/rand.h>
|
|
#include <gamedata.h>
|
|
#include <game.h>
|
|
#include <playerinterface.h>
|
|
#include <handinterface.h>
|
|
|
|
#include <sstream>
|
|
|
|
using namespace std;
|
|
|
|
#define SERVER_WAIT_TIMEOUT_MSEC 50
|
|
#define SERVER_DELAY_NEXT_HAND_SEC 10
|
|
#define SERVER_DELAY_NEXT_GAME_SEC 10
|
|
#define SERVER_DEAL_FLOP_CARDS_DELAY_SEC 5
|
|
#define SERVER_DEAL_TURN_CARD_DELAY_SEC 2
|
|
#define SERVER_DEAL_RIVER_CARD_DELAY_SEC 2
|
|
#define SERVER_DEAL_ADD_ALL_IN_DELAY_SEC 2
|
|
#define SERVER_SHOW_CARDS_DELAY_SEC 2
|
|
#define SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC 2
|
|
#define SERVER_COMPUTER_ACTION_DELAY_SEC 2
|
|
|
|
#define SERVER_COMPUTER_PLAYER_NAME "Computer"
|
|
|
|
// Helper functions
|
|
// TODO: these are hacks.
|
|
|
|
static void SendPlayerAction(ServerGameThread &server, boost::shared_ptr<PlayerInterface> player)
|
|
{
|
|
assert(player);
|
|
|
|
boost::shared_ptr<NetPacket> notifyActionDone(new NetPacketPlayersActionDone);
|
|
NetPacketPlayersActionDone::Data actionDoneData;
|
|
actionDoneData.gameState = server.GetCurRound();
|
|
actionDoneData.playerId = player->getMyUniqueID();
|
|
actionDoneData.playerAction = static_cast<PlayerAction>(player->getMyAction());
|
|
actionDoneData.totalPlayerBet = player->getMySet();
|
|
actionDoneData.playerMoney = player->getMyCash();
|
|
static_cast<NetPacketPlayersActionDone *>(notifyActionDone.get())->SetData(actionDoneData);
|
|
server.SendToAllPlayers(notifyActionDone, SessionData::Game);
|
|
}
|
|
|
|
static void SendNewRoundCards(ServerGameThread &server, Game &curGame, int state)
|
|
{
|
|
// TODO: no switch needed here if game states are polymorphic
|
|
switch(state) {
|
|
case GAME_STATE_PREFLOP: {
|
|
// nothing to do
|
|
} break;
|
|
case GAME_STATE_FLOP: {
|
|
// deal flop cards
|
|
int cards[5];
|
|
curGame.getCurrentHand()->getBoard()->getMyCards(cards);
|
|
boost::shared_ptr<NetPacket> notifyCards(new NetPacketDealFlopCards);
|
|
NetPacketDealFlopCards::Data notifyCardsData;
|
|
for (int num = 0; num < 3; num++)
|
|
notifyCardsData.flopCards[num] = static_cast<u_int16_t>(cards[num]);
|
|
static_cast<NetPacketDealFlopCards *>(notifyCards.get())->SetData(notifyCardsData);
|
|
server.SendToAllPlayers(notifyCards, SessionData::Game);
|
|
} break;
|
|
case GAME_STATE_TURN: {
|
|
// deal turn card
|
|
int cards[5];
|
|
curGame.getCurrentHand()->getBoard()->getMyCards(cards);
|
|
boost::shared_ptr<NetPacket> notifyCards(new NetPacketDealTurnCard);
|
|
NetPacketDealTurnCard::Data notifyCardsData;
|
|
notifyCardsData.turnCard = static_cast<u_int16_t>(cards[3]);
|
|
static_cast<NetPacketDealTurnCard *>(notifyCards.get())->SetData(notifyCardsData);
|
|
server.SendToAllPlayers(notifyCards, SessionData::Game);
|
|
} break;
|
|
case GAME_STATE_RIVER: {
|
|
// deal river card
|
|
int cards[5];
|
|
curGame.getCurrentHand()->getBoard()->getMyCards(cards);
|
|
boost::shared_ptr<NetPacket> notifyCards(new NetPacketDealRiverCard);
|
|
NetPacketDealRiverCard::Data notifyCardsData;
|
|
notifyCardsData.riverCard = static_cast<u_int16_t>(cards[4]);
|
|
static_cast<NetPacketDealRiverCard *>(notifyCards.get())->SetData(notifyCardsData);
|
|
server.SendToAllPlayers(notifyCards, SessionData::Game);
|
|
} break;
|
|
default: {
|
|
//
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
ServerGameState::~ServerGameState()
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
AbstractServerGameStateReceiving::AbstractServerGameStateReceiving()
|
|
{
|
|
}
|
|
|
|
AbstractServerGameStateReceiving::~AbstractServerGameStateReceiving()
|
|
{
|
|
}
|
|
|
|
int
|
|
AbstractServerGameStateReceiving::Process(ServerGameThread &server)
|
|
{
|
|
// This is the receive loop for the server.
|
|
int retVal = MSG_SOCK_INTERNAL_PENDING;
|
|
SessionWrapper session = server.GetSessionManager().Select(RECV_TIMEOUT_MSEC);
|
|
|
|
if (session.sessionData.get())
|
|
{
|
|
boost::shared_ptr<NetPacket> packet;
|
|
try
|
|
{
|
|
// Receive the packet.
|
|
packet = server.GetReceiver().Recv(session.sessionData->GetSocket());
|
|
} catch (const NetException &)
|
|
{
|
|
server.CloseSessionDelayed(session);
|
|
return retVal;
|
|
}
|
|
|
|
// Process packet if one was received.
|
|
if (packet.get())
|
|
{
|
|
// Chat text is always allowed.
|
|
if (packet->ToNetPacketSendChatText())
|
|
{
|
|
if (session.playerData.get()) // Only forward if this player is known.
|
|
{
|
|
// Forward chat text to all players.
|
|
// TODO: Some limitation needed.
|
|
NetPacketSendChatText::Data inChatData;
|
|
packet->ToNetPacketSendChatText()->GetData(inChatData);
|
|
|
|
boost::shared_ptr<NetPacket> outChat(new NetPacketChatText);
|
|
NetPacketChatText::Data outChatData;
|
|
outChatData.playerId = session.playerData->GetUniqueId();
|
|
outChatData.text = inChatData.text;
|
|
static_cast<NetPacketChatText *>(outChat.get())->SetData(outChatData);
|
|
server.SendToAllPlayers(outChat, SessionData::Game);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Packet processing in subclass.
|
|
retVal = InternalProcess(server, session, packet);
|
|
}
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
AbstractServerGameStateTimer::AbstractServerGameStateTimer()
|
|
{
|
|
}
|
|
|
|
AbstractServerGameStateTimer::~AbstractServerGameStateTimer()
|
|
{
|
|
}
|
|
|
|
void
|
|
AbstractServerGameStateTimer::Init()
|
|
{
|
|
m_timer.reset();
|
|
m_timer.start();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateInit> ServerGameStateInit::Ptr;
|
|
|
|
ServerGameStateInit &
|
|
ServerGameStateInit::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateInit);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateInit::ServerGameStateInit()
|
|
: m_curUniquePlayerId(0)
|
|
{
|
|
}
|
|
|
|
ServerGameStateInit::~ServerGameStateInit()
|
|
{
|
|
}
|
|
|
|
void
|
|
ServerGameStateInit::HandleNewSession(ServerGameThread &server, SessionWrapper session)
|
|
{
|
|
if (session.sessionData.get() && session.playerData.get())
|
|
{
|
|
size_t curNumPlayers = server.GetCurNumberOfPlayers();
|
|
|
|
// Check the number of players.
|
|
if (curNumPlayers >= (size_t)server.GetGameData().maxNumberOfPlayers)
|
|
{
|
|
server.SessionError(session, ERR_NET_SERVER_FULL);
|
|
}
|
|
else
|
|
{
|
|
if (curNumPlayers == 0)
|
|
{
|
|
// First player is admin.
|
|
session.playerData->SetRights(PLAYER_RIGHTS_ADMIN);
|
|
}
|
|
|
|
// Send ack to client.
|
|
boost::shared_ptr<NetPacket> joinGameAck(new NetPacketJoinGameAck);
|
|
NetPacketJoinGameAck::Data joinGameAckData;
|
|
joinGameAckData.gameId = server.GetId();
|
|
joinGameAckData.prights = session.playerData->GetRights();
|
|
joinGameAckData.gameData = server.GetGameData();
|
|
static_cast<NetPacketJoinGameAck *>(joinGameAck.get())->SetData(joinGameAckData);
|
|
server.GetSender().Send(session.sessionData->GetSocket(), joinGameAck);
|
|
|
|
// Send notifications for connected players to client.
|
|
PlayerDataList tmpPlayerList = server.GetSessionManager().GetPlayerDataList();
|
|
PlayerDataList::iterator player_i = tmpPlayerList.begin();
|
|
PlayerDataList::iterator player_end = tmpPlayerList.end();
|
|
while (player_i != player_end)
|
|
{
|
|
server.GetSender().Send(session.sessionData->GetSocket(), CreateNetPacketPlayerJoined(*(*player_i)));
|
|
++player_i;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
ServerGameStateInit::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
|
{
|
|
int retVal = MSG_SOCK_INIT_DONE;
|
|
|
|
if (packet->ToNetPacketStartEvent())
|
|
{
|
|
server.ResetComputerPlayerList();
|
|
/* int remainingSlots = server.GetGameData().maxNumberOfPlayers - server.GetCurNumberOfPlayers();
|
|
for (int i = 1; i <= remainingSlots; i++)
|
|
{
|
|
boost::shared_ptr<PlayerData> tmpPlayerData(
|
|
new PlayerData(m_curUniquePlayerId++, 0, PLAYER_TYPE_COMPUTER, PLAYER_RIGHTS_NORMAL));
|
|
|
|
ostringstream name;
|
|
name << SERVER_COMPUTER_PLAYER_NAME << i;
|
|
tmpPlayerData->SetName(name.str());
|
|
|
|
// Send "Player Joined" to other fully connected clients.
|
|
server.SendToAllPlayers(CreateNetPacketPlayerJoined(*tmpPlayerData));
|
|
server.AddComputerPlayer(tmpPlayerData);
|
|
}*/
|
|
|
|
server.InternalStartGame();
|
|
server.SetState(SERVER_START_GAME_STATE::Instance());
|
|
}
|
|
else if (packet->ToNetPacketKickPlayer())
|
|
{
|
|
NetPacketKickPlayer::Data kickPlayerData;
|
|
packet->ToNetPacketKickPlayer()->GetData(kickPlayerData);
|
|
|
|
server.InternalKickPlayer(kickPlayerData.playerId);
|
|
}
|
|
else
|
|
{
|
|
server.SessionError(session, ERR_SOCK_INVALID_PACKET);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
boost::shared_ptr<NetPacket>
|
|
ServerGameStateInit::CreateNetPacketPlayerJoined(const PlayerData &playerData)
|
|
{
|
|
boost::shared_ptr<NetPacket> thisPlayerJoined(new NetPacketPlayerJoined);
|
|
NetPacketPlayerJoined::Data thisPlayerJoinedData;
|
|
thisPlayerJoinedData.playerId = playerData.GetUniqueId();
|
|
thisPlayerJoinedData.playerName = playerData.GetName();
|
|
thisPlayerJoinedData.ptype = playerData.GetType();
|
|
thisPlayerJoinedData.prights = playerData.GetRights();
|
|
static_cast<NetPacketPlayerJoined *>(thisPlayerJoined.get())->SetData(thisPlayerJoinedData);
|
|
return thisPlayerJoined;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
AbstractServerGameStateRunning::AbstractServerGameStateRunning()
|
|
{
|
|
}
|
|
|
|
AbstractServerGameStateRunning::~AbstractServerGameStateRunning()
|
|
{
|
|
}
|
|
|
|
void
|
|
AbstractServerGameStateRunning::HandleNewSession(ServerGameThread &server, SessionWrapper session)
|
|
{
|
|
// Do not accept new sessions in this state.
|
|
// TODO
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateStartGame> ServerGameStateStartGame::Ptr;
|
|
|
|
ServerGameStateStartGame &
|
|
ServerGameStateStartGame::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateStartGame);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateStartGame::ServerGameStateStartGame()
|
|
{
|
|
}
|
|
|
|
ServerGameStateStartGame::~ServerGameStateStartGame()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateStartGame::Process(ServerGameThread &server)
|
|
{
|
|
boost::shared_ptr<NetPacket> answer(new NetPacketGameStart);
|
|
|
|
NetPacketGameStart::Data gameStartData;
|
|
gameStartData.startData = server.GetStartData();
|
|
|
|
// Send player order to clients.
|
|
// Assume player list is sorted by number.
|
|
PlayerDataList tmpPlayerList = server.GetSessionManager().GetPlayerDataList();
|
|
PlayerDataList::iterator player_i = tmpPlayerList.begin();
|
|
PlayerDataList::iterator player_end = tmpPlayerList.end();
|
|
while (player_i != player_end)
|
|
{
|
|
NetPacketGameStart::PlayerSlot tmpPlayerSlot;
|
|
tmpPlayerSlot.playerId = (*player_i)->GetUniqueId();
|
|
gameStartData.playerSlots.push_back(tmpPlayerSlot);
|
|
|
|
++player_i;
|
|
}
|
|
|
|
static_cast<NetPacketGameStart *>(answer.get())->SetData(gameStartData);
|
|
|
|
server.SendToAllPlayers(answer, SessionData::Game);
|
|
server.SetState(ServerGameStateStartHand::Instance());
|
|
|
|
return MSG_NET_GAME_SERVER_START;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateStartHand> ServerGameStateStartHand::Ptr;
|
|
|
|
ServerGameStateStartHand &
|
|
ServerGameStateStartHand::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateStartHand);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateStartHand::ServerGameStateStartHand()
|
|
{
|
|
}
|
|
|
|
ServerGameStateStartHand::~ServerGameStateStartHand()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateStartHand::Process(ServerGameThread &server)
|
|
{
|
|
boost::shared_ptr<NetPacket> answer(new NetPacketHandStart);
|
|
|
|
// Initialize hand.
|
|
Game &curGame = server.GetGame();
|
|
curGame.initHand();
|
|
|
|
// HACK: Skip GUI notification run
|
|
curGame.getCurrentHand()->getFlop()->resetFirstRun();
|
|
curGame.getCurrentHand()->getTurn()->resetFirstRun();
|
|
curGame.getCurrentHand()->getRiver()->resetFirstRun();
|
|
|
|
std::vector<boost::shared_ptr<PlayerInterface> >playerArray = curGame.getPlayerArray();
|
|
|
|
// Send cards to all players.
|
|
for (int i = 0; i < curGame.getStartQuantityPlayers(); i++)
|
|
{
|
|
// also send to inactive players, but not to disconnected players.
|
|
if (playerArray[i]->getNetSessionData().get())
|
|
{
|
|
int cards[2];
|
|
playerArray[i]->getMyCards(cards);
|
|
boost::shared_ptr<NetPacket> notifyCards(new NetPacketHandStart);
|
|
NetPacketHandStart::Data handStartData;
|
|
handStartData.yourCards[0] = static_cast<unsigned>(cards[0]);
|
|
handStartData.yourCards[1] = static_cast<unsigned>(cards[1]);
|
|
static_cast<NetPacketHandStart *>(notifyCards.get())->SetData(handStartData);
|
|
|
|
server.GetSender().Send(playerArray[i]->getNetSessionData()->GetSocket(), notifyCards);
|
|
}
|
|
}
|
|
|
|
// Start hand.
|
|
curGame.startHand();
|
|
|
|
// Auto small blind / big blind at the beginning of hand.
|
|
for (int i = 0; i < curGame.getStartQuantityPlayers(); i++)
|
|
{
|
|
if(playerArray[i]->getMyButton() == BUTTON_SMALL_BLIND)
|
|
{
|
|
boost::shared_ptr<NetPacket> notifySmallBlind(new NetPacketPlayersActionDone);
|
|
NetPacketPlayersActionDone::Data actionDoneData;
|
|
actionDoneData.gameState = GAME_STATE_PREFLOP_SMALL_BLIND;
|
|
actionDoneData.playerId = playerArray[i]->getMyUniqueID();
|
|
actionDoneData.playerAction = (PlayerAction)playerArray[i]->getMyAction();
|
|
actionDoneData.totalPlayerBet = playerArray[i]->getMySet();
|
|
actionDoneData.playerMoney = playerArray[i]->getMyCash();
|
|
static_cast<NetPacketPlayersActionDone *>(notifySmallBlind.get())->SetData(actionDoneData);
|
|
server.SendToAllPlayers(notifySmallBlind, SessionData::Game);
|
|
break;
|
|
}
|
|
}
|
|
for (int i = 0; i < curGame.getStartQuantityPlayers(); i++)
|
|
{
|
|
if(playerArray[i]->getMyButton() == BUTTON_BIG_BLIND)
|
|
{
|
|
boost::shared_ptr<NetPacket> notifyBigBlind(new NetPacketPlayersActionDone);
|
|
NetPacketPlayersActionDone::Data actionDoneData;
|
|
actionDoneData.gameState = GAME_STATE_PREFLOP_BIG_BLIND;
|
|
actionDoneData.playerId = playerArray[i]->getMyUniqueID();
|
|
actionDoneData.playerAction = (PlayerAction)playerArray[i]->getMyAction();
|
|
actionDoneData.totalPlayerBet = playerArray[i]->getMySet();
|
|
actionDoneData.playerMoney = playerArray[i]->getMyCash();
|
|
static_cast<NetPacketPlayersActionDone *>(notifyBigBlind.get())->SetData(actionDoneData);
|
|
server.SendToAllPlayers(notifyBigBlind, SessionData::Game);
|
|
break;
|
|
}
|
|
}
|
|
|
|
server.SetState(ServerGameStateStartRound::Instance());
|
|
|
|
return MSG_NET_GAME_SERVER_HAND_START;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateStartRound> ServerGameStateStartRound::Ptr;
|
|
|
|
ServerGameStateStartRound &
|
|
ServerGameStateStartRound::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateStartRound);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateStartRound::ServerGameStateStartRound()
|
|
{
|
|
}
|
|
|
|
ServerGameStateStartRound::~ServerGameStateStartRound()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateStartRound::Process(ServerGameThread &server)
|
|
{
|
|
int retVal = MSG_SOCK_INTERNAL_PENDING;
|
|
Game &curGame = server.GetGame();
|
|
|
|
// Main game loop.
|
|
int curRound = curGame.getCurrentHand()->getActualRound();
|
|
curGame.getCurrentHand()->switchRounds();
|
|
if (!curGame.getCurrentHand()->getAllInCondition() && curGame.getCurrentHand()->getActualRound() != GAME_STATE_POST_RIVER)
|
|
curGame.getCurrentHand()->getCurrentBeRo()->run();
|
|
int newRound = curGame.getCurrentHand()->getActualRound();
|
|
|
|
// If round changes, deal cards if needed.
|
|
if (newRound != curRound && newRound != GAME_STATE_POST_RIVER)
|
|
{
|
|
assert(newRound > curRound);
|
|
// Retrieve active players. If only one player is left, no cards are shown.
|
|
std::list<boost::shared_ptr<PlayerInterface> > activePlayers = GetActivePlayers(curGame);
|
|
|
|
if (curGame.getCurrentHand()->getAllInCondition()
|
|
&& !curGame.getCurrentHand()->getCardsShown()
|
|
&& activePlayers.size() > 1)
|
|
{
|
|
// Send cards of all active players to all players (all in).
|
|
boost::shared_ptr<NetPacket> allIn(new NetPacketAllInShowCards);
|
|
NetPacketAllInShowCards::Data allInData;
|
|
|
|
std::list<boost::shared_ptr<PlayerInterface> >::iterator i = activePlayers.begin();
|
|
std::list<boost::shared_ptr<PlayerInterface> >::iterator end = activePlayers.end();
|
|
|
|
while (i != end)
|
|
{
|
|
NetPacketAllInShowCards::PlayerCards tmpPlayerCards;
|
|
tmpPlayerCards.playerId = (*i)->getMyUniqueID();
|
|
|
|
int tmpCards[2];
|
|
(*i)->getMyCards(tmpCards);
|
|
tmpPlayerCards.cards[0] = static_cast<u_int16_t>(tmpCards[0]);
|
|
tmpPlayerCards.cards[1] = static_cast<u_int16_t>(tmpCards[1]);
|
|
|
|
allInData.playerCards.push_back(tmpPlayerCards);
|
|
++i;
|
|
}
|
|
static_cast<NetPacketAllInShowCards *>(allIn.get())->SetData(allInData);
|
|
server.SendToAllPlayers(allIn, SessionData::Game);
|
|
curGame.getCurrentHand()->setCardsShown(true);
|
|
|
|
server.SetState(ServerGameStateShowCardsDelay::Instance());
|
|
retVal = MSG_NET_GAME_SERVER_CARDS_DELAY;
|
|
}
|
|
else
|
|
{
|
|
SendNewRoundCards(server, curGame, newRound);
|
|
|
|
server.SetState(ServerGameStateDealCardsDelay::Instance());
|
|
retVal = MSG_NET_GAME_SERVER_CARDS_DELAY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (newRound != GAME_STATE_POST_RIVER) // continue hand
|
|
{
|
|
assert (!curGame.getCurrentHand()->getAllInCondition()); // this would be an error.
|
|
|
|
// Retrieve current player.
|
|
boost::shared_ptr<PlayerInterface> curPlayer = curGame.getCurrentPlayer();
|
|
assert(curPlayer.get()); // TODO throw exception
|
|
assert(curPlayer->getMyActiveStatus()); // TODO throw exception
|
|
|
|
boost::shared_ptr<NetPacket> notification(new NetPacketPlayersTurn);
|
|
NetPacketPlayersTurn::Data playersTurnData;
|
|
playersTurnData.gameState = (GameState)curGame.getCurrentHand()->getActualRound();
|
|
playersTurnData.playerId = curPlayer->getMyUniqueID();
|
|
static_cast<NetPacketPlayersTurn *>(notification.get())->SetData(playersTurnData);
|
|
|
|
server.SendToAllPlayers(notification, SessionData::Game);
|
|
|
|
server.SetState(ServerGameStateWaitPlayerAction::Instance());
|
|
|
|
retVal = MSG_NET_GAME_SERVER_ROUND;
|
|
}
|
|
else // hand is over
|
|
{
|
|
// Engine will find out who won.
|
|
curGame.getCurrentHand()->getCurrentBeRo()->run();
|
|
|
|
// Retrieve active players. If only one player is left, no cards are shown.
|
|
std::list<boost::shared_ptr<PlayerInterface> > activePlayers = GetActivePlayers(curGame);
|
|
// if (activePlayers.empty()) TODO throw exception
|
|
|
|
if (activePlayers.size() == 1)
|
|
{
|
|
// End of Hand, but keep cards hidden.
|
|
boost::shared_ptr<PlayerInterface> player = activePlayers.front();
|
|
boost::shared_ptr<NetPacket> endHand(new NetPacketEndOfHandHideCards);
|
|
NetPacketEndOfHandHideCards::Data endHandData;
|
|
endHandData.playerId = player->getMyUniqueID();
|
|
endHandData.moneyWon = 0; // TODO
|
|
endHandData.playerMoney = player->getMyCash();
|
|
static_cast<NetPacketEndOfHandHideCards *>(endHand.get())->SetData(endHandData);
|
|
|
|
server.SendToAllPlayers(endHand, SessionData::Game);
|
|
}
|
|
else
|
|
{
|
|
// End of Hand - show cards of active players.
|
|
boost::shared_ptr<NetPacket> endHand(new NetPacketEndOfHandShowCards);
|
|
NetPacketEndOfHandShowCards::Data endHandData;
|
|
|
|
std::list<boost::shared_ptr<PlayerInterface> >::iterator i = activePlayers.begin();
|
|
std::list<boost::shared_ptr<PlayerInterface> >::iterator end = activePlayers.end();
|
|
|
|
while (i != end)
|
|
{
|
|
NetPacketEndOfHandShowCards::PlayerResult tmpPlayerResult;
|
|
tmpPlayerResult.playerId = (*i)->getMyUniqueID();
|
|
|
|
int tmpCards[2];
|
|
int bestHandPos[5];
|
|
(*i)->getMyCards(tmpCards);
|
|
tmpPlayerResult.cards[0] = static_cast<u_int16_t>(tmpCards[0]);
|
|
tmpPlayerResult.cards[1] = static_cast<u_int16_t>(tmpCards[1]);
|
|
|
|
(*i)->getMyBestHandPosition(bestHandPos);
|
|
for (int num = 0; num < 5; num++)
|
|
tmpPlayerResult.bestHandPos[num] = bestHandPos[num];
|
|
|
|
tmpPlayerResult.valueOfCards = (*i)->getMyCardsValueInt();
|
|
tmpPlayerResult.moneyWon = 0; // TODO
|
|
tmpPlayerResult.playerMoney = (*i)->getMyCash();
|
|
|
|
endHandData.playerResults.push_back(tmpPlayerResult);
|
|
++i;
|
|
}
|
|
static_cast<NetPacketEndOfHandShowCards *>(endHand.get())->SetData(endHandData);
|
|
|
|
server.SendToAllPlayers(endHand, SessionData::Game);
|
|
}
|
|
|
|
// Remove disconnected players. This is the one and only place to do this.
|
|
server.RemoveDisconnectedPlayers();
|
|
|
|
// Start next hand - if enough players are left.
|
|
int playersPositiveCashCounter = 0;
|
|
for (int i = 0; i < curGame.getStartQuantityPlayers(); i++)
|
|
{
|
|
if (curGame.getCurrentHand()->getPlayerArray()[i]->getMyCash() > 0)
|
|
playersPositiveCashCounter++;
|
|
}
|
|
// TODO: this is not an assert - terminate game if true.
|
|
assert(playersPositiveCashCounter);
|
|
if (playersPositiveCashCounter == 1)
|
|
{
|
|
// View a dialog for a new game - delayed.
|
|
server.SetState(ServerGameStateNextGameDelay::Instance());
|
|
retVal = MSG_NET_GAME_SERVER_END;
|
|
}
|
|
else
|
|
{
|
|
server.SetState(ServerGameStateNextHandDelay::Instance());
|
|
retVal = MSG_NET_GAME_SERVER_HAND_END;
|
|
}
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
std::list<boost::shared_ptr<PlayerInterface> >
|
|
ServerGameStateStartRound::GetActivePlayers(Game &curGame)
|
|
{
|
|
std::list<boost::shared_ptr<PlayerInterface> > activePlayers;
|
|
for (int i = 0; i < curGame.getStartQuantityPlayers() ; i++)
|
|
{
|
|
if (curGame.getPlayerArray()[i]->getMyActiveStatus()
|
|
&& curGame.getPlayerArray()[i]->getMyAction() != PLAYER_ACTION_FOLD)
|
|
{
|
|
activePlayers.push_back(curGame.getPlayerArray()[i]);
|
|
}
|
|
}
|
|
return activePlayers;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateWaitPlayerAction> ServerGameStateWaitPlayerAction::Ptr;
|
|
|
|
ServerGameStateWaitPlayerAction &
|
|
ServerGameStateWaitPlayerAction::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateWaitPlayerAction);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateWaitPlayerAction::ServerGameStateWaitPlayerAction()
|
|
{
|
|
}
|
|
|
|
ServerGameStateWaitPlayerAction::~ServerGameStateWaitPlayerAction()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateWaitPlayerAction::Process(ServerGameThread &server)
|
|
{
|
|
int retVal;
|
|
|
|
boost::shared_ptr<PlayerInterface> tmpPlayer = server.GetGame().getCurrentPlayer();
|
|
assert(tmpPlayer.get());
|
|
assert(!tmpPlayer->getMyName().empty());
|
|
|
|
// If the player is computer controlled, let the engine act.
|
|
if (tmpPlayer->getMyType() == PLAYER_TYPE_COMPUTER)
|
|
{
|
|
server.SetState(ServerGameStateComputerAction::Instance());
|
|
retVal = MSG_SOCK_INTERNAL_PENDING;
|
|
}
|
|
// If the player we are waiting for left, continue without him.
|
|
else if (!server.GetSessionManager().IsPlayerConnected(tmpPlayer->getMyName()))
|
|
{
|
|
PerformPlayerAction(server, tmpPlayer, PLAYER_ACTION_FOLD, 0);
|
|
|
|
server.SetState(ServerGameStateStartRound::Instance());
|
|
retVal = MSG_NET_GAME_SERVER_ACTION;
|
|
}
|
|
else if (GetTimer().elapsed().total_seconds() >= server.GetGameData().playerActionTimeoutSec + SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC)
|
|
{
|
|
// Player did not act fast enough. Act for him.
|
|
if (server.GetGame().getCurrentHand()->getCurrentBeRo()->getHighestSet() == tmpPlayer->getMySet())
|
|
PerformPlayerAction(server, tmpPlayer, PLAYER_ACTION_CHECK, 0);
|
|
else
|
|
PerformPlayerAction(server, tmpPlayer, PLAYER_ACTION_FOLD, 0);
|
|
|
|
server.SetState(ServerGameStateStartRound::Instance());
|
|
retVal = MSG_NET_GAME_SERVER_ACTION;
|
|
}
|
|
else
|
|
retVal = AbstractServerGameStateReceiving::Process(server);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
int
|
|
ServerGameStateWaitPlayerAction::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
|
{
|
|
int retVal = MSG_SOCK_INTERNAL_PENDING;
|
|
|
|
if (packet->ToNetPacketPlayersAction())
|
|
{
|
|
NetPacketPlayersAction::Data actionData;
|
|
packet->ToNetPacketPlayersAction()->GetData(actionData);
|
|
|
|
Game &curGame = server.GetGame();
|
|
boost::shared_ptr<PlayerInterface> tmpPlayer = curGame.getPlayerByUniqueId(session.playerData->GetUniqueId());
|
|
assert(tmpPlayer.get()); // TODO throw exception
|
|
// TODO: check whether this is the correct player
|
|
// TODO: check game state
|
|
|
|
PerformPlayerAction(server, tmpPlayer, actionData.playerAction, actionData.playerBet);
|
|
|
|
server.SetState(ServerGameStateStartRound::Instance());
|
|
retVal = MSG_NET_GAME_SERVER_ACTION;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
void
|
|
ServerGameStateWaitPlayerAction::PerformPlayerAction(ServerGameThread &server, boost::shared_ptr<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() > curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet())
|
|
curGame.getCurrentHand()->getCurrentBeRo()->setHighestSet(player->getMySet());
|
|
// Update total sets.
|
|
curGame.getCurrentHand()->getBoard()->collectSets();
|
|
}
|
|
|
|
SendPlayerAction(server, player);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateComputerAction> ServerGameStateComputerAction::Ptr;
|
|
|
|
ServerGameStateComputerAction &
|
|
ServerGameStateComputerAction::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateComputerAction);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateComputerAction::ServerGameStateComputerAction()
|
|
{
|
|
}
|
|
|
|
ServerGameStateComputerAction::~ServerGameStateComputerAction()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateComputerAction::Process(ServerGameThread &server)
|
|
{
|
|
int retVal = AbstractServerGameStateReceiving::Process(server);
|
|
|
|
if (GetTimer().elapsed().total_seconds() >= SERVER_COMPUTER_ACTION_DELAY_SEC)
|
|
{
|
|
boost::shared_ptr<PlayerInterface> tmpPlayer = server.GetGame().getCurrentPlayer();
|
|
|
|
tmpPlayer->action();
|
|
SendPlayerAction(server, tmpPlayer);
|
|
|
|
server.SetState(ServerGameStateStartRound::Instance());
|
|
retVal = MSG_NET_GAME_SERVER_ACTION;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
int
|
|
ServerGameStateComputerAction::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
|
{
|
|
return MSG_SOCK_INTERNAL_PENDING;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateDealCardsDelay> ServerGameStateDealCardsDelay::Ptr;
|
|
|
|
ServerGameStateDealCardsDelay &
|
|
ServerGameStateDealCardsDelay::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateDealCardsDelay);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateDealCardsDelay::ServerGameStateDealCardsDelay()
|
|
{
|
|
}
|
|
|
|
ServerGameStateDealCardsDelay::~ServerGameStateDealCardsDelay()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateDealCardsDelay::Process(ServerGameThread &server)
|
|
{
|
|
int retVal = AbstractServerGameStateReceiving::Process(server);
|
|
|
|
Game &curGame = server.GetGame();
|
|
|
|
int allInDelay = curGame.getCurrentHand()->getAllInCondition() ? SERVER_DEAL_ADD_ALL_IN_DELAY_SEC : 0;
|
|
int delay = 0;
|
|
|
|
switch(curGame.getCurrentHand()->getActualRound())
|
|
{
|
|
case GAME_STATE_FLOP:
|
|
delay = SERVER_DEAL_FLOP_CARDS_DELAY_SEC;
|
|
break;
|
|
case GAME_STATE_TURN:
|
|
delay = SERVER_DEAL_TURN_CARD_DELAY_SEC + allInDelay;
|
|
break;
|
|
case GAME_STATE_RIVER:
|
|
delay = SERVER_DEAL_RIVER_CARD_DELAY_SEC;
|
|
break;
|
|
}
|
|
if (!delay || GetTimer().elapsed().total_seconds() >= delay)
|
|
server.SetState(ServerGameStateStartRound::Instance());
|
|
|
|
return retVal;
|
|
}
|
|
|
|
int
|
|
ServerGameStateDealCardsDelay::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
|
{
|
|
return MSG_SOCK_INTERNAL_PENDING;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateShowCardsDelay> ServerGameStateShowCardsDelay::Ptr;
|
|
|
|
ServerGameStateShowCardsDelay &
|
|
ServerGameStateShowCardsDelay::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateShowCardsDelay);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateShowCardsDelay::ServerGameStateShowCardsDelay()
|
|
{
|
|
}
|
|
|
|
ServerGameStateShowCardsDelay::~ServerGameStateShowCardsDelay()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateShowCardsDelay::Process(ServerGameThread &server)
|
|
{
|
|
int retVal = AbstractServerGameStateReceiving::Process(server);
|
|
|
|
if (GetTimer().elapsed().total_seconds() >= SERVER_SHOW_CARDS_DELAY_SEC)
|
|
{
|
|
Game &curGame = server.GetGame();
|
|
SendNewRoundCards(server, curGame, curGame.getCurrentHand()->getActualRound());
|
|
|
|
server.SetState(ServerGameStateDealCardsDelay::Instance());
|
|
retVal = MSG_NET_GAME_SERVER_CARDS_DELAY;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
int
|
|
ServerGameStateShowCardsDelay::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
|
{
|
|
return MSG_SOCK_INTERNAL_PENDING;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateNextHandDelay> ServerGameStateNextHandDelay::Ptr;
|
|
|
|
ServerGameStateNextHandDelay &
|
|
ServerGameStateNextHandDelay::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateNextHandDelay);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateNextHandDelay::ServerGameStateNextHandDelay()
|
|
{
|
|
}
|
|
|
|
ServerGameStateNextHandDelay::~ServerGameStateNextHandDelay()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateNextHandDelay::Process(ServerGameThread &server)
|
|
{
|
|
int retVal = AbstractServerGameStateReceiving::Process(server);
|
|
|
|
if (GetTimer().elapsed().total_seconds() >= SERVER_DELAY_NEXT_HAND_SEC)
|
|
server.SetState(ServerGameStateStartHand::Instance());
|
|
|
|
return retVal;
|
|
}
|
|
|
|
int
|
|
ServerGameStateNextHandDelay::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
|
{
|
|
return MSG_SOCK_INTERNAL_PENDING;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateNextGameDelay> ServerGameStateNextGameDelay::Ptr;
|
|
|
|
ServerGameStateNextGameDelay &
|
|
ServerGameStateNextGameDelay::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateNextGameDelay);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateNextGameDelay::ServerGameStateNextGameDelay()
|
|
{
|
|
}
|
|
|
|
ServerGameStateNextGameDelay::~ServerGameStateNextGameDelay()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateNextGameDelay::Process(ServerGameThread &server)
|
|
{
|
|
int retVal = AbstractServerGameStateReceiving::Process(server);
|
|
|
|
if (GetTimer().elapsed().total_seconds() >= SERVER_DELAY_NEXT_GAME_SEC)
|
|
{
|
|
Game &curGame = server.GetGame();
|
|
// The game has ended. Notify all clients.
|
|
boost::shared_ptr<PlayerInterface> winnerPlayer;
|
|
for (int i = 0; i < curGame.getStartQuantityPlayers(); i++)
|
|
{
|
|
winnerPlayer = curGame.getCurrentHand()->getPlayerArray()[i];
|
|
if (winnerPlayer->getMyCash() > 0)
|
|
break;
|
|
}
|
|
|
|
boost::shared_ptr<NetPacket> endGame(new NetPacketEndOfGame);
|
|
NetPacketEndOfGame::Data endGameData;
|
|
endGameData.winnerPlayerId = winnerPlayer->getMyUniqueID();
|
|
static_cast<NetPacketEndOfGame *>(endGame.get())->SetData(endGameData);
|
|
|
|
server.SendToAllPlayers(endGame, SessionData::Game);
|
|
|
|
// Wait for the start of a new game.
|
|
server.SetState(ServerGameStateInit::Instance());
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
int
|
|
ServerGameStateNextGameDelay::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
|
{
|
|
return MSG_SOCK_INTERNAL_PENDING;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
boost::thread_specific_ptr<ServerGameStateFinal> ServerGameStateFinal::Ptr;
|
|
|
|
ServerGameStateFinal &
|
|
ServerGameStateFinal::Instance()
|
|
{
|
|
if (!Ptr.get())
|
|
Ptr.reset(new ServerGameStateFinal);
|
|
|
|
return *Ptr;
|
|
}
|
|
|
|
ServerGameStateFinal::ServerGameStateFinal()
|
|
{
|
|
}
|
|
|
|
ServerGameStateFinal::~ServerGameStateFinal()
|
|
{
|
|
}
|
|
|
|
int
|
|
ServerGameStateFinal::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
|
{
|
|
return MSG_SOCK_INTERNAL_PENDING;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|