<commit_before>/***************************************************************************
 *   Copyright (C) 2007-2010 by <NAME>                                 *
 *                                                                         *
 *   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/servergame.h>
#include <net/serverlobbythread.h>
#include <net/receiverhelper.h>
#include <net/senderhelper.h>
#include <net/netpacket.h>
#include <net/socket_msg.h>
#include <net/serverexception.h>
#include <net/net_helper.h>
#include <db/serverdbinterface.h>
#include <core/loghelper.h>
#include <gamedata.h>
#include <game.h>
#include <playerinterface.h>
#include <handinterface.h>

#include <boost/bind.hpp>

#include <sstream>

using namespace std;

//#define SERVER_TEST

#ifdef SERVER_TEST
	#define SERVER_DELAY_NEXT_GAME_SEC				0
	#define SERVER_DEAL_FLOP_CARDS_DELAY_SEC		0
	#define SERVER_DEAL_TURN_CARD_DELAY_SEC			0
	#define SERVER_DEAL_RIVER_CARD_DELAY_SEC		0
	#define SERVER_DEAL_ADD_ALL_IN_DELAY_SEC		0
	#define SERVER_SHOW_CARDS_DELAY_SEC				0
	#define SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC		0
	#define SERVER_COMPUTER_ACTION_DELAY_SEC		0
#else
	#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
#endif

#define SERVER_START_GAME_TIMEOUT_SEC				10
#define SERVER_AUTOSTART_GAME_DELAY_SEC				6
#define SERVER_GAME_ADMIN_WARNING_REMAINING_SEC		60
#define SERVER_GAME_ADMIN_TIMEOUT_SEC				300		// 5 min, MUST be > SERVER_GAME_ADMIN_WARNING_REMAINING_SEC
#define SERVER_VOTE_KICK_TIMEOUT_SEC				30
#define SERVER_LOOP_DELAY_MSEC						50

#define SERVER_WARNING_ACTION_TIMEOUT_THRESHOLD		6
#define SERVER_KICK_ACTION_TIMEOUT_REMAINING		2

// Helper functions

static void SendPlayerAction(ServerGame &server, boost::shared_ptr<PlayerInterface> player)
{
	if (!player.get())
		throw ServerException(__FILE__, __LINE__, ERR_NET_NO_CURRENT_PLAYER, 0);

	boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
	packet->GetMsg()->present = PokerTHMessage_PR_playersActionDoneMessage;
	PlayersActionDoneMessage_t *netActionDone = &packet->GetMsg()->choice.playersActionDoneMessage;

	netActionDone->gameId = server.GetId();
	netActionDone->gameState = server.GetCurRound();
	netActionDone->highestSet = server.GetGame().getCurrentHand()->getCurrentBeRo()->getHighestSet();
	netActionDone->minimumRaise = server.GetGame().getCurrentHand()->getCurrentBeRo()->getMinimumRaise();
	netActionDone->playerAction = static_cast<PlayerAction>(player->getMyAction());
	netActionDone->playerId = player->getMyUniqueID();
	netActionDone->playerMoney = player->getMyCash();
	netActionDone->totalPlayerBet = player->getMySet();
	server.SendToAllPlayers(packet, SessionData::Game);
}

static void SendNewRoundCards(ServerGame &server, Game &curGame, int state)
{
	int cards[5];
	curGame.getCurrentHand()->getBoard()->getMyCards(cards);
	switch(state) {
		case GAME_STATE_PREFLOP: {
			// nothing to do
		} break;
		case GAME_STATE_FLOP: {
			// deal flop cards
			boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
			packet->GetMsg()->present = PokerTHMessage_PR_dealFlopCardsMessage;
			DealFlopCardsMessage_t *netDealFlop = &packet->GetMsg()->choice.dealFlopCardsMessage;
			netDealFlop->gameId = server.GetId();
			netDealFlop->flopCard1 = cards[0];
			netDealFlop->flopCard2 = cards[1];
			netDealFlop->flopCard3 = cards[2];
			server.SendToAllPlayers(packet, SessionData::Game);
		} break;
		case GAME_STATE_TURN: {
			// deal turn card
			boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
			packet->GetMsg()->present = PokerTHMessage_PR_dealTurnCardMessage;
			DealTurnCardMessage_t *netDealTurn = &packet->GetMsg()->choice.dealTurnCardMessage;
			netDealTurn->gameId = server.GetId();
			netDealTurn->turnCard = cards[3];
			server.SendToAllPlayers(packet, SessionData::Game);
		} break;
		case GAME_STATE_RIVER: {
			// deal river card
			boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
			packet->GetMsg()->present = PokerTHMessage_PR_dealRiverCardMessage;
			DealRiverCardMessage_t *netDealRiver = &packet->GetMsg()->choice.dealRiverCardMessage;
			netDealRiver->gameId = server.GetId();
			netDealRiver->riverCard = cards[4];
			server.SendToAllPlayers(packet, SessionData::Game);
		} break;
		default: {
			// 
		}
	}
}

static void PerformPlayerAction(ServerGame &server, boost::shared_ptr<PlayerInterface> player, PlayerAction action, int bet)
{
	Game &curGame = server.GetGame();
	if (!player.get())
		throw ServerException(__FILE__, __LINE__, ERR_NET_NO_CURRENT_PLAYER, 0);
	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);

		// update minimumRaise and lastActionPlayer
		switch(action) {
			case PLAYER_ACTION_BET: {
				curGame.getCurrentHand()->getCurrentBeRo()->setMinimumRaise(bet);
				curGame.getCurrentHand()->setLastActionPlayer(player->getMyUniqueID());
			} break;
			case PLAYER_ACTION_RAISE: {
				curGame.getCurrentHand()->getCurrentBeRo()->setMinimumRaise(player->getMySet() - curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet());
				curGame.getCurrentHand()->setLastActionPlayer(player->getMyUniqueID());
			} break;
			case PLAYER_ACTION_ALLIN: {
				if(player->getMySet() - curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet() > curGame.getCurrentHand()->getCurrentBeRo()->getMinimumRaise()) {
					curGame.getCurrentHand()->getCurrentBeRo()->setMinimumRaise(player->getMySet() - curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet());
				}
				if(player->getMySet() - curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet() > 0) {
					curGame.getCurrentHand()->setLastActionPlayer(player->getMyUniqueID());
				}
			} break;
			default: {
			}
		}

		// update highestSet
		if (player->getMySet() > curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet())
			curGame.getCurrentHand()->getCurrentBeRo()->setHighestSet(player->getMySet());
		// Update total sets.
		curGame.getCurrentHand()->getBoard()->collectSets();
	}


	SendPlayerAction(server, player);
}

static void
SetPlayerResult(PlayerResult_t &playerResult, boost::shared_ptr<PlayerInterface> tmpPlayer)
{
	playerResult.playerId = tmpPlayer->getMyUniqueID();
	int tmpCards[2];
	int bestHandPos[5];
	tmpPlayer->getMyCards(tmpCards);
	playerResult.resultCard1 = tmpCards[0];
	playerResult.resultCard2 = tmpCards[1];
	tmpPlayer->getMyBestHandPosition(bestHandPos);
	for (int num = 0; num < 5; num++)
	{
		long *handPos = (long *)calloc(1, sizeof(long));
		*handPos = bestHandPos[num];
		ASN_SEQUENCE_ADD(&playerResult.bestHandPosition.list, handPos);
	}

	playerResult.cardsValue = tmpPlayer->getMyCardsValueInt();
	playerResult.moneyWon = tmpPlayer->getLastMoneyWon();
	playerResult.playerMoney = tmpPlayer->getMyCash();
}

//-----------------------------------------------------------------------------

ServerGameState::~ServerGameState()
{
}

//-----------------------------------------------------------------------------

AbstractServerGameStateReceiving::~AbstractServerGameStateReceiving()
{
}

void
AbstractServerGameStateReceiving::ProcessPacket(boost::shared_ptr<ServerGame> server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
{
	if (packet->IsClientActivity())
		session.sessionData->ResetActivityTimer();
	if (packet->GetMsg()->present == PokerTHMessage_PR_playerInfoRequestMessage)
	{
		// Delegate to Lobby.
		server->GetLobbyThread().HandleGameRetrievePlayerInfo(session, packet->GetMsg()->choice.playerInfoRequestMessage);
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_avatarRequestMessage)
	{
		// Delegate to Lobby.
		server->GetLobbyThread().HandleGameRetrieveAvatar(session, packet->GetMsg()->choice.avatarRequestMessage);
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_leaveGameRequestMessage)
	{
		server->MoveSessionToLobby(session, NTF_NET_REMOVED_ON_REQUEST);
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_kickPlayerRequestMessage)
	{
		// Only admins are allowed to kick, and only in the lobby.
		// After leaving the lobby, a vote needs to be initiated to kick.
		KickPlayerRequestMessage_t *netKickRequest = &packet->GetMsg()->choice.kickPlayerRequestMessage;
		if (session.playerData->IsGameAdmin() && !server->IsRunning()
			&& netKickRequest->gameId == server->GetId() && server->GetGameData().gameType != GAME_TYPE_RANKING)
		{
			server->InternalKickPlayer(netKickRequest->playerId);
		}
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_askKickPlayerMessage)
	{
		if (session.playerData && server->GetGameData().gameType != GAME_TYPE_RANKING)
		{
			AskKickPlayerMessage_t *netAskKick = &packet->GetMsg()->choice.askKickPlayerMessage;
			server->InternalAskVoteKick(session, netAskKick->playerId, SERVER_VOTE_KICK_TIMEOUT_SEC);
		}
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_voteKickRequestMessage)
	{
		if (session.playerData)
		{
			VoteKickRequestMessage_t *netVoteKick = &packet->GetMsg()->choice.voteKickRequestMessage;
			server->InternalVoteKick(session, netVoteKick->petitionId, netVoteKick->voteKick ? KICK_VOTE_IN_FAVOUR : KICK_VOTE_AGAINST);
		}
	}
	// Chat text is always allowed.
	else if (packet->GetMsg()->present == PokerTHMessage_PR_chatRequestMessage)
	{
		// Only forward if this player is known and not a guest.
		if (session.playerData && session.playerData->GetRights() != PLAYER_RIGHTS_GUEST)
		{
			// Forward chat text to all players.
			// TODO: Some limitation needed.
			ChatRequestMessage_t *netChatRequest = &packet->GetMsg()->choice.chatRequestMessage;
			if (netChatRequest->chatRequestType.present == chatRequestType_PR_chatRequestTypeLobby
				|| netChatRequest->chatRequestType.present == chatRequestType_PR_chatRequestTypePrivate)
			{
				if (!server->IsRunning())
					server->GetLobbyThread().HandleChatRequest(session, *netChatRequest);
			}
			else if (netChatRequest->chatRequestType.present == chatRequestType_PR_chatRequestTypeGame)
			{
				boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
				packet->GetMsg()->present = PokerTHMessage_PR_chatMessage;
				ChatMessage_t *netChat = &packet->GetMsg()->choice.chatMessage;
				netChat->chatType.present = chatType_PR_chatTypeGame;
				ChatTypeGame_t *netGameChat = &netChat->chatType.choice.chatTypeGame;
				netGameChat->gameId = server->GetId();
				netGameChat->playerId = session.playerData->GetUniqueId();
				OCTET_STRING_fromBuf(
					&netChat->chatText,
					(char *)netChatRequest->chatText.buf,
					netChatRequest->chatText.size);
				server->SendToAllPlayers(packet, SessionData::Game);
			}
		}
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_subscriptionRequestMessage)
	{
		SubscriptionRequestMessage_t *netSubscription = &packet->GetMsg()->choice.subscriptionRequestMessage;
		if (netSubscription->subscriptionAction == subscriptionAction_resubscribeGameList)
		{
			if (!session.sessionData->WantsLobbyMsg())
				server->GetLobbyThread().ResubscribeLobbyMsg(session);
		}
		else
			session.sessionData->ResetWantsLobbyMsg();
	}
	else
	{
		// Packet processing in subclass.
		InternalProcessPacket(server, session, packet);
	}
}

//-----------------------------------------------------------------------------

ServerGameStateInit ServerGameStateInit::s_state;

ServerGameStateInit &
ServerGameStateInit::Instance()
{
	return s_state;
}

ServerGameStateInit::ServerGameStateInit()
{
}

ServerGameStateInit::~ServerGameStateInit()
{
}

void
ServerGameStateInit::Enter(boost::shared_ptr<ServerGame> server)
{
	RegisterAdminTimer(server);
}

void
ServerGameStateInit::Exit(boost::shared_ptr<ServerGame> server)
{
	UnregisterAdminTimer(server);
	UnregisterAutoStartTimer(server);
}

void
ServerGameStateInit::NotifyGameAdminChanged(boost::shared_ptr<ServerGame> server)
{
	UnregisterAdminTimer(server);
	RegisterAdminTimer(server);
}

void
ServerGameStateInit::NotifySessionRemoved(boost::shared_ptr<ServerGame> server)
{
	UnregisterAutoStartTimer(server);
}

void
ServerGameStateInit::HandleNewSession(boost::shared_ptr<ServerGame> server, SessionWrapper session)
{
	if (session.sessionData && session.playerData)
	{
		const GameData &tmpGameData = server->GetGameData();
		// Check the number of players.
		if (server->GetCurNumberOfPlayers() >= (size_t)tmpGameData.maxNumberOfPlayers)
		{
			server->MoveSessionToLobby(session, NTF_NET_REMOVED_GAME_FULL);
		}
		else
		{
			session.playerData->SetGameAdmin(session.playerData->GetUniqueId() == server->GetAdminPlayerId());

			// Send ack to client.
			boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
			packet->GetMsg()->present = PokerTHMessage_PR_joinGameReplyMessage;
			JoinGameReplyMessage_t *netJoinReply = &packet->GetMsg()->choice.joinGameReplyMessage;
			netJoinReply->gameId = server->GetId();
			netJoinReply->joinGameResult.present = joinGameResult_PR_joinGameAck;
			JoinGameAck_t *joinAck = &netJoinReply->joinGameResult.choice.joinGameAck;
			joinAck->areYouGameAdmin = static_cast<PlayerInfoRights>(session.playerData->IsGameAdmin());

			NetPacket::SetGameData(server->GetGameData(), &joinAck->gameInfo);
			OCTET_STRING_fromBuf(
				&joinAck->gameInfo.gameName,
				session.playerData->GetName().c_str(),
				session.playerData->GetName().length());
			server->GetLobbyThread().GetSender().Send(session.sessionData, packet);

			// Send notifications for connected players to client.
			PlayerDataList tmpPlayerList = server->GetFullPlayerDataList();
			PlayerDataList::iterator player_i = tmpPlayerList.begin();
			PlayerDataList::iterator player_end = tmpPlayerList.end();
			while (player_i != player_end)
			{
				server->GetLobbyThread().GetSender().Send(session.sessionData, CreateNetPacketPlayerJoined(server->GetId(), *(*player_i)));
				++player_i;
			}

			// Send "Player Joined" to other fully connected clients.
			server->SendToAllPlayers(CreateNetPacketPlayerJoined(server->GetId(), *session.playerData), SessionData::Game);
<commit_msg>Fixing game create game ack text bug found through test case.<commit_after>/***************************************************************************
 *   Copyright (C) 2007-2010 by <NAME>                                 *
 *                                                                         *
 *   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/servergame.h>
#include <net/serverlobbythread.h>
#include <net/receiverhelper.h>
#include <net/senderhelper.h>
#include <net/netpacket.h>
#include <net/socket_msg.h>
#include <net/serverexception.h>
#include <net/net_helper.h>
#include <db/serverdbinterface.h>
#include <core/loghelper.h>
#include <gamedata.h>
#include <game.h>
#include <playerinterface.h>
#include <handinterface.h>

#include <boost/bind.hpp>

#include <sstream>

using namespace std;

//#define SERVER_TEST

#ifdef SERVER_TEST
	#define SERVER_DELAY_NEXT_GAME_SEC				0
	#define SERVER_DEAL_FLOP_CARDS_DELAY_SEC		0
	#define SERVER_DEAL_TURN_CARD_DELAY_SEC			0
	#define SERVER_DEAL_RIVER_CARD_DELAY_SEC		0
	#define SERVER_DEAL_ADD_ALL_IN_DELAY_SEC		0
	#define SERVER_SHOW_CARDS_DELAY_SEC				0
	#define SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC		0
	#define SERVER_COMPUTER_ACTION_DELAY_SEC		0
#else
	#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
#endif

#define SERVER_START_GAME_TIMEOUT_SEC				10
#define SERVER_AUTOSTART_GAME_DELAY_SEC				6
#define SERVER_GAME_ADMIN_WARNING_REMAINING_SEC		60
#define SERVER_GAME_ADMIN_TIMEOUT_SEC				300		// 5 min, MUST be > SERVER_GAME_ADMIN_WARNING_REMAINING_SEC
#define SERVER_VOTE_KICK_TIMEOUT_SEC				30
#define SERVER_LOOP_DELAY_MSEC						50

#define SERVER_WARNING_ACTION_TIMEOUT_THRESHOLD		6
#define SERVER_KICK_ACTION_TIMEOUT_REMAINING		2

// Helper functions

static void SendPlayerAction(ServerGame &server, boost::shared_ptr<PlayerInterface> player)
{
	if (!player.get())
		throw ServerException(__FILE__, __LINE__, ERR_NET_NO_CURRENT_PLAYER, 0);

	boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
	packet->GetMsg()->present = PokerTHMessage_PR_playersActionDoneMessage;
	PlayersActionDoneMessage_t *netActionDone = &packet->GetMsg()->choice.playersActionDoneMessage;

	netActionDone->gameId = server.GetId();
	netActionDone->gameState = server.GetCurRound();
	netActionDone->highestSet = server.GetGame().getCurrentHand()->getCurrentBeRo()->getHighestSet();
	netActionDone->minimumRaise = server.GetGame().getCurrentHand()->getCurrentBeRo()->getMinimumRaise();
	netActionDone->playerAction = static_cast<PlayerAction>(player->getMyAction());
	netActionDone->playerId = player->getMyUniqueID();
	netActionDone->playerMoney = player->getMyCash();
	netActionDone->totalPlayerBet = player->getMySet();
	server.SendToAllPlayers(packet, SessionData::Game);
}

static void SendNewRoundCards(ServerGame &server, Game &curGame, int state)
{
	int cards[5];
	curGame.getCurrentHand()->getBoard()->getMyCards(cards);
	switch(state) {
		case GAME_STATE_PREFLOP: {
			// nothing to do
		} break;
		case GAME_STATE_FLOP: {
			// deal flop cards
			boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
			packet->GetMsg()->present = PokerTHMessage_PR_dealFlopCardsMessage;
			DealFlopCardsMessage_t *netDealFlop = &packet->GetMsg()->choice.dealFlopCardsMessage;
			netDealFlop->gameId = server.GetId();
			netDealFlop->flopCard1 = cards[0];
			netDealFlop->flopCard2 = cards[1];
			netDealFlop->flopCard3 = cards[2];
			server.SendToAllPlayers(packet, SessionData::Game);
		} break;
		case GAME_STATE_TURN: {
			// deal turn card
			boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
			packet->GetMsg()->present = PokerTHMessage_PR_dealTurnCardMessage;
			DealTurnCardMessage_t *netDealTurn = &packet->GetMsg()->choice.dealTurnCardMessage;
			netDealTurn->gameId = server.GetId();
			netDealTurn->turnCard = cards[3];
			server.SendToAllPlayers(packet, SessionData::Game);
		} break;
		case GAME_STATE_RIVER: {
			// deal river card
			boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
			packet->GetMsg()->present = PokerTHMessage_PR_dealRiverCardMessage;
			DealRiverCardMessage_t *netDealRiver = &packet->GetMsg()->choice.dealRiverCardMessage;
			netDealRiver->gameId = server.GetId();
			netDealRiver->riverCard = cards[4];
			server.SendToAllPlayers(packet, SessionData::Game);
		} break;
		default: {
			// 
		}
	}
}

static void PerformPlayerAction(ServerGame &server, boost::shared_ptr<PlayerInterface> player, PlayerAction action, int bet)
{
	Game &curGame = server.GetGame();
	if (!player.get())
		throw ServerException(__FILE__, __LINE__, ERR_NET_NO_CURRENT_PLAYER, 0);
	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);

		// update minimumRaise and lastActionPlayer
		switch(action) {
			case PLAYER_ACTION_BET: {
				curGame.getCurrentHand()->getCurrentBeRo()->setMinimumRaise(bet);
				curGame.getCurrentHand()->setLastActionPlayer(player->getMyUniqueID());
			} break;
			case PLAYER_ACTION_RAISE: {
				curGame.getCurrentHand()->getCurrentBeRo()->setMinimumRaise(player->getMySet() - curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet());
				curGame.getCurrentHand()->setLastActionPlayer(player->getMyUniqueID());
			} break;
			case PLAYER_ACTION_ALLIN: {
				if(player->getMySet() - curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet() > curGame.getCurrentHand()->getCurrentBeRo()->getMinimumRaise()) {
					curGame.getCurrentHand()->getCurrentBeRo()->setMinimumRaise(player->getMySet() - curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet());
				}
				if(player->getMySet() - curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet() > 0) {
					curGame.getCurrentHand()->setLastActionPlayer(player->getMyUniqueID());
				}
			} break;
			default: {
			}
		}

		// update highestSet
		if (player->getMySet() > curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet())
			curGame.getCurrentHand()->getCurrentBeRo()->setHighestSet(player->getMySet());
		// Update total sets.
		curGame.getCurrentHand()->getBoard()->collectSets();
	}


	SendPlayerAction(server, player);
}

static void
SetPlayerResult(PlayerResult_t &playerResult, boost::shared_ptr<PlayerInterface> tmpPlayer)
{
	playerResult.playerId = tmpPlayer->getMyUniqueID();
	int tmpCards[2];
	int bestHandPos[5];
	tmpPlayer->getMyCards(tmpCards);
	playerResult.resultCard1 = tmpCards[0];
	playerResult.resultCard2 = tmpCards[1];
	tmpPlayer->getMyBestHandPosition(bestHandPos);
	for (int num = 0; num < 5; num++)
	{
		long *handPos = (long *)calloc(1, sizeof(long));
		*handPos = bestHandPos[num];
		ASN_SEQUENCE_ADD(&playerResult.bestHandPosition.list, handPos);
	}

	playerResult.cardsValue = tmpPlayer->getMyCardsValueInt();
	playerResult.moneyWon = tmpPlayer->getLastMoneyWon();
	playerResult.playerMoney = tmpPlayer->getMyCash();
}

//-----------------------------------------------------------------------------

ServerGameState::~ServerGameState()
{
}

//-----------------------------------------------------------------------------

AbstractServerGameStateReceiving::~AbstractServerGameStateReceiving()
{
}

void
AbstractServerGameStateReceiving::ProcessPacket(boost::shared_ptr<ServerGame> server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
{
	if (packet->IsClientActivity())
		session.sessionData->ResetActivityTimer();
	if (packet->GetMsg()->present == PokerTHMessage_PR_playerInfoRequestMessage)
	{
		// Delegate to Lobby.
		server->GetLobbyThread().HandleGameRetrievePlayerInfo(session, packet->GetMsg()->choice.playerInfoRequestMessage);
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_avatarRequestMessage)
	{
		// Delegate to Lobby.
		server->GetLobbyThread().HandleGameRetrieveAvatar(session, packet->GetMsg()->choice.avatarRequestMessage);
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_leaveGameRequestMessage)
	{
		server->MoveSessionToLobby(session, NTF_NET_REMOVED_ON_REQUEST);
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_kickPlayerRequestMessage)
	{
		// Only admins are allowed to kick, and only in the lobby.
		// After leaving the lobby, a vote needs to be initiated to kick.
		KickPlayerRequestMessage_t *netKickRequest = &packet->GetMsg()->choice.kickPlayerRequestMessage;
		if (session.playerData->IsGameAdmin() && !server->IsRunning()
			&& netKickRequest->gameId == server->GetId() && server->GetGameData().gameType != GAME_TYPE_RANKING)
		{
			server->InternalKickPlayer(netKickRequest->playerId);
		}
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_askKickPlayerMessage)
	{
		if (session.playerData && server->GetGameData().gameType != GAME_TYPE_RANKING)
		{
			AskKickPlayerMessage_t *netAskKick = &packet->GetMsg()->choice.askKickPlayerMessage;
			server->InternalAskVoteKick(session, netAskKick->playerId, SERVER_VOTE_KICK_TIMEOUT_SEC);
		}
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_voteKickRequestMessage)
	{
		if (session.playerData)
		{
			VoteKickRequestMessage_t *netVoteKick = &packet->GetMsg()->choice.voteKickRequestMessage;
			server->InternalVoteKick(session, netVoteKick->petitionId, netVoteKick->voteKick ? KICK_VOTE_IN_FAVOUR : KICK_VOTE_AGAINST);
		}
	}
	// Chat text is always allowed.
	else if (packet->GetMsg()->present == PokerTHMessage_PR_chatRequestMessage)
	{
		// Only forward if this player is known and not a guest.
		if (session.playerData && session.playerData->GetRights() != PLAYER_RIGHTS_GUEST)
		{
			// Forward chat text to all players.
			// TODO: Some limitation needed.
			ChatRequestMessage_t *netChatRequest = &packet->GetMsg()->choice.chatRequestMessage;
			if (netChatRequest->chatRequestType.present == chatRequestType_PR_chatRequestTypeLobby
				|| netChatRequest->chatRequestType.present == chatRequestType_PR_chatRequestTypePrivate)
			{
				if (!server->IsRunning())
					server->GetLobbyThread().HandleChatRequest(session, *netChatRequest);
			}
			else if (netChatRequest->chatRequestType.present == chatRequestType_PR_chatRequestTypeGame)
			{
				boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
				packet->GetMsg()->present = PokerTHMessage_PR_chatMessage;
				ChatMessage_t *netChat = &packet->GetMsg()->choice.chatMessage;
				netChat->chatType.present = chatType_PR_chatTypeGame;
				ChatTypeGame_t *netGameChat = &netChat->chatType.choice.chatTypeGame;
				netGameChat->gameId = server->GetId();
				netGameChat->playerId = session.playerData->GetUniqueId();
				OCTET_STRING_fromBuf(
					&netChat->chatText,
					(char *)netChatRequest->chatText.buf,
					netChatRequest->chatText.size);
				server->SendToAllPlayers(packet, SessionData::Game);
			}
		}
	}
	else if (packet->GetMsg()->present == PokerTHMessage_PR_subscriptionRequestMessage)
	{
		SubscriptionRequestMessage_t *netSubscription = &packet->GetMsg()->choice.subscriptionRequestMessage;
		if (netSubscription->subscriptionAction == subscriptionAction_resubscribeGameList)
		{
			if (!session.sessionData->WantsLobbyMsg())
				server->GetLobbyThread().ResubscribeLobbyMsg(session);
		}
		else
			session.sessionData->ResetWantsLobbyMsg();
	}
	else
	{
		// Packet processing in subclass.
		InternalProcessPacket(server, session, packet);
	}
}

//-----------------------------------------------------------------------------

ServerGameStateInit ServerGameStateInit::s_state;

ServerGameStateInit &
ServerGameStateInit::Instance()
{
	return s_state;
}

ServerGameStateInit::ServerGameStateInit()
{
}

ServerGameStateInit::~ServerGameStateInit()
{
}

void
ServerGameStateInit::Enter(boost::shared_ptr<ServerGame> server)
{
	RegisterAdminTimer(server);
}

void
ServerGameStateInit::Exit(boost::shared_ptr<ServerGame> server)
{
	UnregisterAdminTimer(server);
	UnregisterAutoStartTimer(server);
}

void
ServerGameStateInit::NotifyGameAdminChanged(boost::shared_ptr<ServerGame> server)
{
	UnregisterAdminTimer(server);
	RegisterAdminTimer(server);
}

void
ServerGameStateInit::NotifySessionRemoved(boost::shared_ptr<ServerGame> server)
{
	UnregisterAutoStartTimer(server);
}

void
ServerGameStateInit::HandleNewSession(boost::shared_ptr<ServerGame> server, SessionWrapper session)
{
	if (session.sessionData && session.playerData)
	{
		const GameData &tmpGameData = server->GetGameData();
		// Check the number of players.
		if (server->GetCurNumberOfPlayers() >= (size_t)tmpGameData.maxNumberOfPlayers)
		{
			server->MoveSessionToLobby(session, NTF_NET_REMOVED_GAME_FULL);
		}
		else
		{
			session.playerData->SetGameAdmin(session.playerData->GetUniqueId() == server->GetAdminPlayerId());

			// Send ack to client.
			boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
			packet->GetMsg()->present = PokerTHMessage_PR_joinGameReplyMessage;
			JoinGameReplyMessage_t *netJoinReply = &packet->GetMsg()->choice.joinGameReplyMessage;
			netJoinReply->gameId = server->GetId();
			netJoinReply->joinGameResult.present = joinGameResult_PR_joinGameAck;
			JoinGameAck_t *joinAck = &netJoinReply->joinGameResult.choice.joinGameAck;
			joinAck->areYouGameAdmin = static_cast<PlayerInfoRights>(session.playerData->IsGameAdmin());

			NetPacket::SetGameData(server->GetGameData(), &joinAck->gameInfo);
			OCTET_STRING_fromBuf(
				&joinAck->gameInfo.gameName,
				server->GetName().c_str(),
				server->GetName().length());
			server->GetLobbyThread().GetSender().Send(session.sessionData, packet);

			// Send notifications for connected players to client.
			PlayerDataList tmpPlayerList = server->GetFullPlayerDataList();
			PlayerDataList::iterator player_i = tmpPlayerList.begin();
			PlayerDataList::iterator player_end = tmpPlayerList.end();
			while (player_i != player_end)
			{
				server->GetLobbyThread().GetSender().Send(session.sessionData, CreateNetPacketPlayerJoined(server->GetId(), *(*player_i)));
				++player_i;
			}

			// Send "Player Joined" to other fully connected clients.
			server->SendToAllPlayers(CreateNetPacketPlayerJoined(server->GetId(), *session.playerData), SessionData::Game);

{'fraction_non_alphanumeric': 0.14047373176713568, 'fraction_numerical': 0.004905124564347489, 'mean_word_length': 4.569554277498202, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 451, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6700357', 'n_tokens_mistral': 10539, 'n_tokens_neox': 9742, 'n_words': 1596}