Added error handling for networking stuff. Now checking the player action.

This commit is contained in:
lotodore
2007-10-10 22:21:24 +00:00
parent de0f16a6fc
commit 253778bf30
15 changed files with 176 additions and 85 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ public:
boost::shared_ptr<AvatarFileState> OpenAvatarFileForChunkRead(const std::string &fileName, unsigned &outFileSize, AvatarFileType &outFileType);
unsigned ChunkReadAvatarFile(boost::shared_ptr<AvatarFileState> fileState, unsigned char *data, unsigned chunkSize);
bool AvatarFileToNetPackets(const std::string &fileName, unsigned requestId, NetPacketList &packets);
int AvatarFileToNetPackets(const std::string &fileName, unsigned requestId, NetPacketList &packets);
bool GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf) const;
bool GetAvatarFileName(const MD5Buf &md5buf, std::string &fileName) const;
+24 -14
View File
@@ -22,6 +22,7 @@
#include <boost/filesystem.hpp>
#include <boost/lambda/lambda.hpp>
#include <openssl/md5.h>
#include <net/socket_msg.h>
#include <fstream>
#include <cstring>
@@ -52,20 +53,25 @@ AvatarManager::~AvatarManager()
bool
AvatarManager::Init(const std::string &dataDir, const std::string &cacheDir)
{
bool retVal = true;
bool tmpRet;
{
boost::mutex::scoped_lock lock(m_cacheDirMutex);
m_cacheDir = cacheDir;
}
{
boost::mutex::scoped_lock lock(m_avatarsMutex);
InternalReadDirectory(dataDir + "gfx/avatars/default/people/", m_avatars);
InternalReadDirectory(dataDir + "gfx/avatars/default/misc/", m_avatars);
tmpRet = InternalReadDirectory(dataDir + "gfx/avatars/default/people/", m_avatars);
retVal = retVal && tmpRet;
tmpRet = InternalReadDirectory(dataDir + "gfx/avatars/default/misc/", m_avatars);
retVal = retVal && tmpRet;
}
{
boost::mutex::scoped_lock lock(m_cachedAvatarsMutex);
InternalReadDirectory(cacheDir, m_cachedAvatars);
tmpRet = InternalReadDirectory(cacheDir, m_cachedAvatars);
retVal = retVal && tmpRet;
}
return true; // TODO handle errors
return retVal;
}
boost::shared_ptr<AvatarFileState>
@@ -126,10 +132,10 @@ AvatarManager::ChunkReadAvatarFile(boost::shared_ptr<AvatarFileState> fileState,
return retVal;
}
bool
int
AvatarManager::AvatarFileToNetPackets(const string &fileName, unsigned requestId, NetPacketList &packets)
{
bool retVal = false;
int retVal = ERR_NET_INVALID_AVATAR_FILE;
unsigned fileSize;
AvatarFileType fileType;
boost::shared_ptr<AvatarFileState> tmpState = OpenAvatarFileForChunkRead(fileName, fileSize, fileType);
@@ -160,15 +166,19 @@ AvatarManager::AvatarFileToNetPackets(const string &fileName, unsigned requestId
packets.push_back(avatarFile);
}
} while (numBytes);
// TODO error handling if numBytes != totalBytesRead
boost::shared_ptr<NetPacket> avatarEnd(new NetPacketAvatarEnd);
NetPacketAvatarEnd::Data avatarEndData;
avatarEndData.requestId = requestId;
static_cast<NetPacketAvatarEnd *>(avatarEnd.get())->SetData(avatarEndData);
packets.push_back(avatarEnd);
retVal = true;
if (fileSize != totalBytesRead)
retVal = ERR_NET_WRONG_AVATAR_SIZE;
else
{
boost::shared_ptr<NetPacket> avatarEnd(new NetPacketAvatarEnd);
NetPacketAvatarEnd::Data avatarEndData;
avatarEndData.requestId = requestId;
static_cast<NetPacketAvatarEnd *>(avatarEnd.get())->SetData(avatarEndData);
packets.push_back(avatarEnd);
retVal = 0;
}
}
// else TODO error handling
return retVal;
}
+8 -8
View File
@@ -994,41 +994,41 @@ void LocalPlayer::action() {
// cout << "playerID in action(): " << (*(actualHand->getCurrentBeRo()->getCurrentPlayersTurnIt()))->getMyID() << endl;
}
int LocalPlayer::checkMyAction(int targetAction, int targetBet, int alreadySet, int myCash, int highestSet, int minimumRaise, int smallBlind) {
int LocalPlayer::checkMyAction(int targetAction, int targetBet, int highestSet, int minimumRaise, int smallBlind) {
switch(targetAction) {
case PLAYER_ACTION_FOLD: {
return 0;
} break;
case PLAYER_ACTION_CHECK: {
if(alreadySet == highestSet) {
if(getMySet() == highestSet) {
return 0;
}
} break;
case PLAYER_ACTION_CALL: {
if(alreadySet < highestSet && targetBet <= myCash) {
if(getMySet() < highestSet && targetBet <= getMyCash()) {
// not all in
if(myCash + alreadySet >= highestSet && targetBet == highestSet - alreadySet) {
if(getMyCash() + getMySet() >= highestSet && targetBet == highestSet - getMySet()) {
return 0;
}
// all in
if(myCash + alreadySet <= highestSet) {
if(getMyCash() + getMySet() <= highestSet) {
return 0;
}
}
} break;
case PLAYER_ACTION_BET: {
if(highestSet == 0 && targetBet <= myCash && targetBet >= 2*smallBlind) {
if(highestSet == 0 && targetBet <= getMyCash() && targetBet >= 2*smallBlind) {
return 0;
}
} break;
case PLAYER_ACTION_RAISE: {
if(highestSet > 0 && targetBet >= minimumRaise && targetBet <= myCash) {
if(highestSet > 0 && targetBet >= minimumRaise && targetBet <= getMyCash()) {
return 0;
}
} break;
case PLAYER_ACTION_ALLIN: {
if(targetBet == myCash) {
if(targetBet == getMyCash()) {
return 0;
}
} break;
+1 -1
View File
@@ -151,7 +151,7 @@ public:
void action();
int checkMyAction(int targetAction, int targetBet, int alreadySet, int myCash, int highestSet, int minimumRaise, int smallBlind);
int checkMyAction(int targetAction, int targetBet, int highestSet, int minimumRaise, int smallBlind);
void preflopEngine();
void flopEngine();
@@ -395,6 +395,11 @@ ClientPlayer::action()
{
}
int
ClientPlayer::checkMyAction(int /*targetAction*/, int /*targetBet*/, int /*highestSet*/, int /*minimumRaise*/, int /*smallBlind*/)
{
return 0;
}
void
ClientPlayer::preflopEngine()
+2 -1
View File
@@ -105,7 +105,8 @@ public:
bool getMyWinnerState() const;
void action();
int checkMyAction(int targetAction, int targetBet, int highestSet, int minimumRaise, int smallBlind);
void preflopEngine();
void flopEngine();
void turnEngine();
+3 -2
View File
@@ -100,9 +100,10 @@ public:
virtual void setMyWinnerState ( bool theValue, int pot ) =0;
virtual bool getMyWinnerState() const =0;
virtual void action() =0;
virtual int checkMyAction(int targetAction, int targetBet, int highestSet, int minimumRaise, int smallBlind) = 0;
virtual void preflopEngine() =0;
virtual void flopEngine() =0;
virtual void turnEngine() =0;
+9
View File
@@ -46,6 +46,15 @@ enum PlayerAction {
PLAYER_ACTION_RAISE,
PLAYER_ACTION_ALLIN };
enum PlayerActionCode
{
ACTION_CODE_VALID = 0,
ACTION_CODE_INVALID_STATE,
ACTION_CODE_NOT_YOUR_TURN,
ACTION_CODE_NOT_ALLOWED
};
enum Button {
BUTTON_NONE = 0,
BUTTON_DEALER,
+7 -6
View File
@@ -555,14 +555,15 @@ ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr<
packet->ToNetPacketRetrieveAvatar()->GetData(retrieveAvatarData);
NetPacketList tmpList;
if (client.GetAvatarManager().AvatarFileToNetPackets(
int avatarError = client.GetAvatarManager().AvatarFileToNetPackets(
client.GetContext().GetAvatarFile(),
retrieveAvatarData.requestId,
tmpList))
{
tmpList);
if (!avatarError)
client.GetSender().SendLowPrio(client.GetContext().GetSocket(), tmpList);
}
// TODO handle error
else
throw NetException(avatarError, 0);
}
return retVal;
@@ -716,7 +717,7 @@ ClientStateSynchronizeStart::Process(ClientThread &client)
}
int
ClientStateSynchronizeStart::InternalProcess(ClientThread &client, boost::shared_ptr<NetPacket> packet)
ClientStateSynchronizeStart::InternalProcess(ClientThread &/*client*/, boost::shared_ptr<NetPacket> packet)
{
int retVal = MSG_SOCK_INTERNAL_PENDING;
+30 -7
View File
@@ -100,6 +100,9 @@ using namespace std;
#define NET_ERR_INIT_INVALID_PASSWORD 0x0004
#define NET_ERR_INIT_PLAYER_NAME_IN_USE 0x0005
#define NET_ERR_INIT_INVALID_PLAYER_NAME 0x0006
#define NET_ERR_AVATAR_TOO_LARGE 0x0010
#define NET_ERR_AVATAR_WRONG_SIZE 0x0011
#define NET_ERR_JOIN_GAME_UNKNOWN_GAME 0x0020
#define NET_ERR_GENERAL_INVALID_PACKET 0xFF01
#define NET_ERR_GENERAL_INVALID_STATE 0xFF02
#define NET_ERR_GENERAL_PLAYER_KICKED 0xFF03
@@ -3200,9 +3203,7 @@ NetPacketPlayersActionRejected::SetData(const NetPacketPlayersActionRejected::Da
tmpData->gameState = htons(inData.gameState);
tmpData->playerAction = htons(inData.playerAction);
tmpData->playerBet = htonl(inData.playerBet);
// TODO: set rejection reason
tmpData->rejectionReason = htons(0);
tmpData->rejectionReason = htons(inData.rejectionReason);
// Check the packet - just in case.
Check(GetRawData());
@@ -3216,8 +3217,7 @@ NetPacketPlayersActionRejected::GetData(NetPacketPlayersActionRejected::Data &ou
outData.gameState = static_cast<GameState>(ntohs(tmpData->gameState));
outData.playerAction = static_cast<PlayerAction>(ntohs(tmpData->playerAction));
outData.playerBet = ntohl(tmpData->playerBet);
// TODO: set rejection reason
outData.rejectionReason = static_cast<PlayerActionCode>(ntohs(tmpData->rejectionReason));
}
const NetPacketPlayersActionRejected *
@@ -3240,7 +3240,10 @@ NetPacketPlayersActionRejected::InternalCheck(const NetPacketHeader* data) const
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
// TODO: check rejection reason
if (!ntohs(tmpData->rejectionReason))
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
}
//-----------------------------------------------------------------------------
@@ -4097,7 +4100,17 @@ NetPacketError::SetData(const NetPacketError::Data &inData)
case ERR_NET_INVALID_PLAYER_NAME :
tmpData->errorReason = htons(NET_ERR_INIT_INVALID_PLAYER_NAME);
break;
// General Errors.
case ERR_NET_AVATAR_TOO_LARGE :
tmpData->errorReason = htons(NET_ERR_AVATAR_TOO_LARGE);
break;
case ERR_NET_WRONG_AVATAR_SIZE :
tmpData->errorReason = htons(NET_ERR_AVATAR_WRONG_SIZE);
break;
case ERR_NET_UNKNOWN_GAME :
tmpData->errorReason = htons(NET_ERR_JOIN_GAME_UNKNOWN_GAME);
break;
// General Errors.
case ERR_SOCK_INVALID_PACKET :
tmpData->errorReason = htons(NET_ERR_GENERAL_INVALID_PACKET);
break;
@@ -4139,6 +4152,16 @@ NetPacketError::GetData(NetPacketError::Data &outData) const
case NET_ERR_INIT_INVALID_PLAYER_NAME :
outData.errorCode = ERR_NET_INVALID_PLAYER_NAME;
break;
case NET_ERR_AVATAR_TOO_LARGE :
outData.errorCode = ERR_NET_AVATAR_TOO_LARGE;
break;
case NET_ERR_AVATAR_WRONG_SIZE :
outData.errorCode = ERR_NET_WRONG_AVATAR_SIZE;
break;
case NET_ERR_JOIN_GAME_UNKNOWN_GAME :
outData.errorCode = ERR_NET_UNKNOWN_GAME;
break;
// General Errors.
case NET_ERR_GENERAL_INVALID_PACKET :
outData.errorCode = ERR_SOCK_INVALID_PACKET;
+58 -19
View File
@@ -683,8 +683,10 @@ ServerGameStateStartRound::Process(ServerGameThread &server)
// Retrieve current player.
boost::shared_ptr<PlayerInterface> curPlayer = curGame.getCurrentPlayer();
assert(curPlayer.get()); // TODO throw exception
assert(curPlayer->getMyActiveStatus()); // TODO throw exception
if (!curPlayer.get())
throw NetException(ERR_NET_NO_CURRENT_PLAYER, 0);
if (!curPlayer->getMyActiveStatus())
throw NetException(ERR_NET_PLAYER_NOT_ACTIVE, 0);
boost::shared_ptr<NetPacket> notification(new NetPacketPlayersTurn);
NetPacketPlayersTurn::Data playersTurnData;
@@ -707,7 +709,6 @@ ServerGameStateStartRound::Process(ServerGameThread &server)
// Retrieve non-fold players. If only one player is left, no cards are shown.
list<boost::shared_ptr<PlayerInterface> > nonFoldPlayers = *curGame.getActivePlayerList();
nonFoldPlayers.remove_if(boost::bind(&PlayerInterface::getMyAction, _1) == PLAYER_ACTION_FOLD);
// if (nonFoldPlayers.empty()) TODO throw exception
if (nonFoldPlayers.size() == 1)
{
@@ -813,20 +814,20 @@ ServerGameStateWaitPlayerAction::Process(ServerGameThread &server)
{
int retVal;
boost::shared_ptr<PlayerInterface> tmpPlayer = server.GetGame().getCurrentPlayer();
assert(tmpPlayer.get());
assert(!tmpPlayer->getMyName().empty());
boost::shared_ptr<PlayerInterface> curPlayer = server.GetGame().getCurrentPlayer();
if (!curPlayer.get())
throw NetException(ERR_NET_NO_CURRENT_PLAYER, 0);
// If the player is computer controlled, let the engine act.
if (tmpPlayer->getMyType() == PLAYER_TYPE_COMPUTER)
if (curPlayer->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()))
else if (!server.GetSessionManager().IsPlayerConnected(curPlayer->getMyName()))
{
PerformPlayerAction(server, tmpPlayer, PLAYER_ACTION_FOLD, 0);
PerformPlayerAction(server, curPlayer, PLAYER_ACTION_FOLD, 0);
server.SetState(ServerGameStateStartRound::Instance());
retVal = MSG_NET_GAME_SERVER_ACTION;
@@ -834,10 +835,10 @@ ServerGameStateWaitPlayerAction::Process(ServerGameThread &server)
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);
if (server.GetGame().getCurrentHand()->getCurrentBeRo()->getHighestSet() == curPlayer->getMySet())
PerformPlayerAction(server, curPlayer, PLAYER_ACTION_CHECK, 0);
else
PerformPlayerAction(server, tmpPlayer, PLAYER_ACTION_FOLD, 0);
PerformPlayerAction(server, curPlayer, PLAYER_ACTION_FOLD, 0);
server.SetState(ServerGameStateStartRound::Instance());
retVal = MSG_NET_GAME_SERVER_ACTION;
@@ -857,17 +858,55 @@ ServerGameStateWaitPlayerAction::InternalProcess(ServerGameThread &server, Sessi
{
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
if (!tmpPlayer.get())
throw NetException(ERR_NET_UNKNOWN_PLAYER_ID, 0);
PerformPlayerAction(server, tmpPlayer, actionData.playerAction, actionData.playerBet);
// Check whether this is the correct round.
PlayerActionCode code = ACTION_CODE_VALID;
if (curGame.getCurrentHand()->getActualRound() != actionData.gameState)
code = ACTION_CODE_INVALID_STATE;
server.SetState(ServerGameStateStartRound::Instance());
retVal = MSG_NET_GAME_SERVER_ACTION;
// Check whether this is the correct player.
boost::shared_ptr<PlayerInterface> curPlayer = server.GetGame().getCurrentPlayer();
if (code == ACTION_CODE_VALID
&& (curPlayer->getMyUniqueID() != tmpPlayer->getMyUniqueID()))
{
code = ACTION_CODE_NOT_YOUR_TURN;
}
// Check whether the action is valid.
if (code == ACTION_CODE_VALID
&& (tmpPlayer->checkMyAction(
actionData.playerAction,
actionData.playerBet,
curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet(),
curGame.getCurrentHand()->getCurrentBeRo()->getMinimumRaise(),
curGame.getCurrentHand()->getSmallBlind()) != 0))
{
code = ACTION_CODE_NOT_ALLOWED;
}
if (code == ACTION_CODE_VALID)
{
PerformPlayerAction(server, tmpPlayer, actionData.playerAction, actionData.playerBet);
server.SetState(ServerGameStateStartRound::Instance());
retVal = MSG_NET_GAME_SERVER_ACTION;
}
else
{
// Send reject message.
boost::shared_ptr<NetPacket> reject(new NetPacketPlayersActionRejected);
NetPacketPlayersActionRejected::Data rejectData;
rejectData.gameState = actionData.gameState;
rejectData.playerAction = actionData.playerAction;
rejectData.playerBet = actionData.playerBet;
rejectData.rejectionReason = code;
static_cast<NetPacketPlayersActionRejected *>(reject.get())->SetData(rejectData);
server.GetSender().Send(session.sessionData->GetSocket(), reject);
}
}
return retVal;
+6 -3
View File
@@ -414,7 +414,8 @@ ServerLobbyThread::HandleNetPacketAvatarHeader(SessionWrapper session, const Net
// Session is now receiving an avatar.
session.sessionData->SetState(SessionData::ReceivingAvatar);
}
// TODO error handling
else
SessionError(session, ERR_NET_AVATAR_TOO_LARGE);
}
}
@@ -435,7 +436,7 @@ ServerLobbyThread::HandleNetPacketAvatarFile(SessionWrapper session, const NetPa
}
void
ServerLobbyThread::HandleNetPacketAvatarEnd(SessionWrapper session, const NetPacketAvatarEnd &tmpPacket)
ServerLobbyThread::HandleNetPacketAvatarEnd(SessionWrapper session, const NetPacketAvatarEnd &/*tmpPacket*/)
{
if (session.playerData.get())
{
@@ -453,7 +454,8 @@ ServerLobbyThread::HandleNetPacketAvatarEnd(SessionWrapper session, const NetPac
// Init finished - start session.
EstablishSession(session);
}
// TODO error handling
else
SessionError(session, ERR_NET_WRONG_AVATAR_SIZE);
}
}
}
@@ -505,6 +507,7 @@ ServerLobbyThread::HandleNetPacketRetrieveAvatar(SessionWrapper session, const N
NetPacketList tmpPackets;
if (GetAvatarManager().AvatarFileToNetPackets(tmpFile, request.requestId, tmpPackets))
GetSender().SendLowPrio(session.sessionData->GetSocket(), tmpPackets);
// TODO handle error
}
}
+4 -4
View File
@@ -839,10 +839,10 @@ public:
struct Data
{
GameState gameState;
PlayerAction playerAction;
u_int32_t playerBet;
int rejectionReason;
GameState gameState;
PlayerAction playerAction;
u_int32_t playerBet;
PlayerActionCode rejectionReason;
};
NetPacketPlayersActionRejected();
+12 -8
View File
@@ -54,14 +54,18 @@
#define ERR_NET_UNKNOWN_GAME 110
#define ERR_NET_INVALID_CHAT_TEXT 111
#define ERR_NET_UNKNOWN_PLAYER_ID 112
#define ERR_NET_INVALID_ROUND 113
#define ERR_NET_PLAYER_KICKED 114
#define ERR_NET_INVALID_PLAYER_COUNT 115
#define ERR_NET_TOO_MANY_MANUAL_BLINDS 116
#define ERR_NET_BUF_INVALID_SIZE 117
#define ERR_NET_INVALID_REQUEST_ID 118
#define ERR_NET_WRONG_AVATAR_SIZE 119
#define ERR_NET_START_TIMEOUT 120
#define ERR_NET_NO_CURRENT_PLAYER 113
#define ERR_NET_PLAYER_NOT_ACTIVE 114
#define ERR_NET_INVALID_ROUND 115
#define ERR_NET_PLAYER_KICKED 116
#define ERR_NET_INVALID_PLAYER_COUNT 117
#define ERR_NET_TOO_MANY_MANUAL_BLINDS 118
#define ERR_NET_INVALID_AVATAR_FILE 119
#define ERR_NET_AVATAR_TOO_LARGE 120
#define ERR_NET_BUF_INVALID_SIZE 121
#define ERR_NET_INVALID_REQUEST_ID 122
#define ERR_NET_WRONG_AVATAR_SIZE 123
#define ERR_NET_START_TIMEOUT 124
#define ERR_IRC_INTERNAL 151
#define ERR_IRC_CONNECT_FAILED 152