(Hopefully) solved the player number problem, when players join and leave an existing game. Numbers are now assigned on game start, not before. Note: Network play is not compatible to the current official version.

This commit is contained in:
lotodore
2007-07-24 14:55:14 +00:00
parent 561b974cdc
commit bd08245c1c
10 changed files with 146 additions and 60 deletions
+3 -3
View File
@@ -77,8 +77,8 @@ protected:
void SetGameData(const GameData &gameData);
const StartData &GetStartData() const;
void SetStartData(const StartData &startData);
int GetGuiPlayerNum() const;
void SetGuiPlayerNum(int guiPlayerNum);
int GetGuiPlayerId() const;
void SetGuiPlayerId(int guiPlayerId);
boost::shared_ptr<Game> GetGame();
@@ -109,7 +109,7 @@ private:
boost::shared_ptr<Game> m_game;
unsigned m_curGameId;
int m_guiPlayerNum;
unsigned m_guiPlayerId;
friend class AbstractClientStateReceiving;
friend class ClientStateInit;
+21 -4
View File
@@ -443,11 +443,12 @@ ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr<
NetPacketJoinGameAck::Data joinGameAckData;
packet->ToNetPacketJoinGameAck()->GetData(joinGameAckData);
client.SetGameData(joinGameAckData.gameData);
client.SetGuiPlayerNum(joinGameAckData.yourPlayerNum);
client.SetGuiPlayerId(joinGameAckData.yourPlayerUniqueId);
// TODO: Type Human is fixed here.
// Player number is 0 on join. Will be set when the game starts.
boost::shared_ptr<PlayerData> playerData(
new PlayerData(joinGameAckData.yourPlayerUniqueId, joinGameAckData.yourPlayerNum, PLAYER_TYPE_HUMAN));
new PlayerData(joinGameAckData.yourPlayerUniqueId, 0, PLAYER_TYPE_HUMAN));
playerData->SetName(context.GetPlayerName());
client.AddPlayerData(playerData);
@@ -489,6 +490,23 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptr<Net
client.SetStartData(gameStartData.startData);
// Set player numbers using the game start data slots.
NetPacketGameStart::PlayerSlotList::const_iterator slot_i = gameStartData.playerSlots.begin();
NetPacketGameStart::PlayerSlotList::const_iterator slot_end = gameStartData.playerSlots.end();
int num = 0;
while (slot_i != slot_end)
{
unsigned playerId = (*slot_i).playerId;
boost::shared_ptr<PlayerData> tmpPlayer = client.GetPlayerDataByUniqueId(playerId);
if (!tmpPlayer.get())
throw ClientException(ERR_NET_UNKNOWN_PLAYER_ID, 0);
tmpPlayer->SetNumber(num);
++num;
++slot_i;
}
client.SetState(ClientStateWaitHand::Instance());
retVal = MSG_NET_GAME_CLIENT_START;
}
@@ -499,11 +517,10 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptr<Net
packet->ToNetPacketPlayerJoined()->GetData(netPlayerData);
boost::shared_ptr<PlayerData> playerData(
new PlayerData(netPlayerData.playerId, netPlayerData.playerNumber, netPlayerData.ptype));
new PlayerData(netPlayerData.playerId, 0, netPlayerData.ptype));
playerData->SetName(netPlayerData.playerName);
client.AddPlayerData(playerData);
}
// TODO: handle error packet (kicked from server)
return retVal;
}
+15 -10
View File
@@ -53,7 +53,7 @@ private:
ClientThread::ClientThread(GuiInterface &gui)
: m_curState(NULL), m_gui(gui), m_curGameId(1), m_guiPlayerNum(0)
: m_curState(NULL), m_gui(gui), m_curGameId(1), m_guiPlayerId(0)
{
m_context.reset(new ClientContext);
m_senderCallback.reset(new ClientSenderCallback(*this));
@@ -244,15 +244,15 @@ ClientThread::SetStartData(const StartData &startData)
}
int
ClientThread::GetGuiPlayerNum() const
ClientThread::GetGuiPlayerId() const
{
return m_guiPlayerNum;
return m_guiPlayerId;
}
void
ClientThread::SetGuiPlayerNum(int guiPlayerNum)
ClientThread::SetGuiPlayerId(int guiPlayerId)
{
m_guiPlayerNum = guiPlayerNum;
m_guiPlayerId = guiPlayerId;
}
boost::shared_ptr<Game>
@@ -303,21 +303,27 @@ ClientThread::RemovePlayerData(unsigned playerId)
void
ClientThread::MapPlayerDataList()
{
// Retrieve the GUI player.
boost::shared_ptr<PlayerData> guiPlayer = GetPlayerDataByUniqueId(GetGuiPlayerId());
assert(guiPlayer.get());
int guiPlayerNum = guiPlayer->GetNumber();
// Create a copy of the player list so that the GUI player
// is player 0. This is mapped because the GUI depends on it.
PlayerDataList mappedList;
PlayerDataList::const_iterator i = m_playerDataList.begin();
PlayerDataList::const_iterator end = m_playerDataList.end();
int numPlayers = GetStartData().numberOfPlayers;
// Create a copy of the player list so that the GUI player
// is player 0. This is mapped because the GUI depends on it.
while (i != end)
{
boost::shared_ptr<PlayerData> tmpData(new PlayerData(*(*i)));
int numberDiff = tmpData->GetNumber() - GetGuiPlayerNum();
int numberDiff = tmpData->GetNumber() - guiPlayerNum;
if (numberDiff >= 0)
tmpData->SetNumber(numberDiff);
else
tmpData->SetNumber(GetStartData().numberOfPlayers + numberDiff);
tmpData->SetNumber(numPlayers + numberDiff);
mappedList.push_back(tmpData);
++i;
}
@@ -326,7 +332,6 @@ ClientThread::MapPlayerDataList()
mappedList.sort(*boost::lambda::_1 < *boost::lambda::_2);
m_playerDataList = mappedList;
SetGuiPlayerNum(0);
}
const PlayerDataList &
+46 -10
View File
@@ -93,13 +93,11 @@ struct GCC_PACKED NetPacketJoinGameAckData
NetPacketHeader head;
u_int32_t sessionId;
u_int16_t playerId;
u_int16_t playerNumber;
u_int16_t maxNumberOfPlayers;
u_int16_t smallBlind;
u_int16_t handsBeforeRaise;
u_int16_t proposedGuiSpeed;
u_int16_t playerActionTimeout;
u_int16_t reserved;
u_int32_t startMoney;
};
@@ -114,9 +112,9 @@ struct GCC_PACKED NetPacketPlayerJoinedData
{
NetPacketHeader head;
u_int16_t playerId;
u_int16_t playerNumber;
u_int16_t playerFlags;
u_int16_t playerNameLength;
u_int16_t reserved;
};
struct GCC_PACKED NetPacketPlayerLeftData
@@ -133,6 +131,11 @@ struct GCC_PACKED NetPacketGameStartData
u_int16_t numberOfPlayers;
};
struct GCC_PACKED PlayerSlotData
{
u_int16_t playerId;
};
struct GCC_PACKED NetPacketHandStartData
{
NetPacketHeader head;
@@ -736,7 +739,6 @@ NetPacketJoinGameAck::SetData(const NetPacketJoinGameAck::Data &inData)
tmpData->sessionId = htonl(inData.sessionId);
tmpData->playerId = htons(inData.yourPlayerUniqueId);
tmpData->playerNumber = htons(inData.yourPlayerNum);
tmpData->maxNumberOfPlayers = htons(inData.gameData.maxNumberOfPlayers);
tmpData->smallBlind = htons(inData.gameData.smallBlind);
tmpData->handsBeforeRaise = htons(inData.gameData.handsBeforeRaise);
@@ -753,7 +755,6 @@ NetPacketJoinGameAck::GetData(NetPacketJoinGameAck::Data &outData) const
outData.sessionId = ntohl(tmpData->sessionId);
outData.yourPlayerUniqueId = ntohs(tmpData->playerId);
outData.yourPlayerNum = ntohs(tmpData->playerNumber);
outData.gameData.maxNumberOfPlayers = ntohs(tmpData->maxNumberOfPlayers);
outData.gameData.smallBlind = ntohs(tmpData->smallBlind);
outData.gameData.handsBeforeRaise = ntohs(tmpData->handsBeforeRaise);
@@ -824,7 +825,6 @@ NetPacketPlayerJoined::SetData(const NetPacketPlayerJoined::Data &inData)
// Set the data.
tmpData->playerFlags = htons((inData.ptype == PLAYER_TYPE_HUMAN) ? NET_PLAYER_FLAG_HUMAN : 0);
tmpData->playerId = htons(inData.playerId);
tmpData->playerNumber = htons(inData.playerNumber);
tmpData->playerNameLength = htons(playerNameLen);
char *namePtr = (char *)tmpData + sizeof(NetPacketPlayerJoinedData);
memcpy(namePtr, inData.playerName.c_str(), playerNameLen);
@@ -839,7 +839,6 @@ NetPacketPlayerJoined::GetData(NetPacketPlayerJoined::Data &outData) const
outData.ptype = (ntohs(tmpData->playerFlags) & NET_PLAYER_FLAG_HUMAN) ? PLAYER_TYPE_HUMAN : PLAYER_TYPE_COMPUTER;
outData.playerId = ntohs(tmpData->playerId);
outData.playerNumber = ntohs(tmpData->playerNumber);
char *namePtr = (char *)tmpData + sizeof(NetPacketPlayerJoinedData);
outData.playerName = string(namePtr, ntohs(tmpData->playerNameLength));
}
@@ -969,11 +968,33 @@ NetPacketGameStart::Clone() const
void
NetPacketGameStart::SetData(const NetPacketGameStart::Data &inData)
{
u_int16_t numPlayers = (u_int16_t)inData.playerSlots.size();
if (!numPlayers || numPlayers > MAX_NUMBER_OF_PLAYERS || numPlayers != inData.startData.numberOfPlayers)
throw NetException(ERR_NET_INVALID_PLAYER_COUNT, 0);
// Resize the packet so that the data fits in.
Resize((u_int16_t)
(sizeof(NetPacketGameStartData) + ADD_PADDING(numPlayers * sizeof(PlayerSlotData))));
NetPacketGameStartData *tmpData = (NetPacketGameStartData *)GetRawData();
assert(tmpData);
tmpData->startDealerPlayerId = htons(inData.startData.startDealerPlayerId);
tmpData->numberOfPlayers = htons(inData.startData.numberOfPlayers);
tmpData->numberOfPlayers = htons(numPlayers);
PlayerSlotList::const_iterator i = inData.playerSlots.begin();
PlayerSlotList::const_iterator end = inData.playerSlots.end();
// Copy the player slot data to continous memory
PlayerSlotData *curPlayerSlotData =
(PlayerSlotData *)((char *)tmpData + sizeof(NetPacketGameStartData));
while (i != end)
{
curPlayerSlotData->playerId = htons((*i).playerId);
++curPlayerSlotData;
++i;
}
}
void
@@ -983,7 +1004,21 @@ NetPacketGameStart::GetData(NetPacketGameStart::Data &outData) const
assert(tmpData);
outData.startData.startDealerPlayerId = ntohs(tmpData->startDealerPlayerId);
outData.startData.numberOfPlayers = ntohs(tmpData->numberOfPlayers);
u_int16_t numPlayers = ntohs(tmpData->numberOfPlayers);
outData.startData.numberOfPlayers = numPlayers;
PlayerSlotData *curPlayerSlotData =
(PlayerSlotData *)((char *)tmpData + sizeof(NetPacketGameStartData));
// Store all available player slots.
for (int i = 0; i < numPlayers; i++)
{
PlayerSlot tmpPlayerSlot;
tmpPlayerSlot.playerId = ntohs(curPlayerSlotData->playerId);
outData.playerSlots.push_back(tmpPlayerSlot);
++curPlayerSlotData;
}
}
const NetPacketGameStart *
@@ -998,10 +1033,11 @@ NetPacketGameStart::Check(const NetPacketHeader* data) const
assert(data);
u_int16_t dataLen = ntohs(data->length);
if (dataLen != sizeof(NetPacketGameStartData))
if (dataLen < sizeof(NetPacketGameStartData))
{
throw NetException(ERR_SOCK_INVALID_PACKET, 0);
}
// TODO additional checking
}
//-----------------------------------------------------------------------------
+15 -4
View File
@@ -290,7 +290,7 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se
// Create player data object.
boost::shared_ptr<PlayerData> tmpPlayerData(
new PlayerData(m_curUniquePlayerId++, server.GetNextPlayerNumber(), joinGameData.ptype));
new PlayerData(m_curUniquePlayerId++, 0, joinGameData.ptype));
tmpPlayerData->SetName(joinGameData.playerName);
tmpPlayerData->SetNetSessionData(session.sessionData);
@@ -299,7 +299,6 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se
NetPacketJoinGameAck::Data joinGameAckData;
joinGameAckData.sessionId = session.sessionData->GetId(); // TODO: currently unused.
joinGameAckData.yourPlayerUniqueId = tmpPlayerData->GetUniqueId();
joinGameAckData.yourPlayerNum = tmpPlayerData->GetNumber();
joinGameAckData.gameData = server.GetGameData();
static_cast<NetPacketJoinGameAck *>(answer.get())->SetData(joinGameAckData);
server.GetSender().Send(session.sessionData->GetSocket(), answer);
@@ -314,7 +313,6 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se
NetPacketPlayerJoined::Data otherPlayerJoinedData;
otherPlayerJoinedData.playerId = (*player_i)->GetUniqueId();
otherPlayerJoinedData.playerName = (*player_i)->GetName();
otherPlayerJoinedData.playerNumber = (*player_i)->GetNumber();
otherPlayerJoinedData.ptype = (*player_i)->GetType();
static_cast<NetPacketPlayerJoined *>(otherPlayerJoined.get())->SetData(otherPlayerJoinedData);
server.GetSender().Send(session.sessionData->GetSocket(), otherPlayerJoined);
@@ -327,7 +325,6 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se
NetPacketPlayerJoined::Data thisPlayerJoinedData;
thisPlayerJoinedData.playerId = tmpPlayerData->GetUniqueId();
thisPlayerJoinedData.playerName = tmpPlayerData->GetName();
thisPlayerJoinedData.playerNumber = tmpPlayerData->GetNumber();
thisPlayerJoinedData.ptype = tmpPlayerData->GetType();
static_cast<NetPacketPlayerJoined *>(thisPlayerJoined.get())->SetData(thisPlayerJoinedData);
server.SendToAllPlayers(thisPlayerJoined);
@@ -382,6 +379,20 @@ ServerRecvStateStartGame::Process(ServerRecvThread &server)
NetPacketGameStart::Data gameStartData;
gameStartData.startData = server.GetStartData();
// Assign player numbers. Assume Player List is sorted by number.
PlayerDataList tmpPlayerList = server.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);
+8 -13
View File
@@ -253,6 +253,8 @@ ServerRecvThread::InternalStartGame()
// Kick all players which are not fully connected.
RemoveNotEstablishedSessions();
// Set order of players.
AssignPlayerNumbers();
// Initialize the game.
GuiInterface &gui = GetGui();
@@ -559,31 +561,24 @@ ServerRecvThread::GetPlayerDataList() const
}
++session_i;
}
// Sort the list by player number.
playerList.sort(*boost::lambda::_1 < *boost::lambda::_2);
return playerList;
}
int
ServerRecvThread::GetNextPlayerNumber() const
void
ServerRecvThread::AssignPlayerNumbers()
{
int playerNumber = 0;
PlayerDataList playerList = GetPlayerDataList();
PlayerDataList::const_iterator player_i = playerList.begin();
PlayerDataList::const_iterator player_end = playerList.end();
PlayerDataList::iterator player_i = playerList.begin();
PlayerDataList::iterator player_end = playerList.end();
// Assume the player list is sorted by player number.
while (player_i != player_end)
{
if ((*player_i)->GetNumber() == playerNumber)
playerNumber++;
else
break;
(*player_i)->SetNumber(playerNumber);
++playerNumber;
++player_i;
}
return playerNumber;
}
void
+11 -4
View File
@@ -26,7 +26,7 @@
#include <gamedata.h>
#include <net/socket_helper.h>
#define NET_VERSION_MAJOR 1
#define NET_VERSION_MAJOR 2
#define NET_VERSION_MINOR 0
#define MIN_PACKET_SIZE 4
@@ -143,7 +143,6 @@ public:
struct Data
{
u_int32_t sessionId;
int16_t yourPlayerNum;
u_int16_t yourPlayerUniqueId;
GameData gameData;
};
@@ -169,7 +168,6 @@ public:
struct Data
{
u_int16_t playerId;
u_int16_t playerNumber;
PlayerType ptype;
std::string playerName;
};
@@ -215,9 +213,18 @@ protected:
class NetPacketGameStart : public NetPacket
{
public:
struct PlayerSlot
{
unsigned playerId;
};
typedef std::list<PlayerSlot> PlayerSlotList;
struct Data
{
StartData startData;
StartData startData;
PlayerSlotList playerSlots;
};
NetPacketGameStart();
+1 -1
View File
@@ -121,7 +121,7 @@ protected:
void SetSessionPlayerData(boost::shared_ptr<SessionData> sessionData, boost::shared_ptr<PlayerData> playerData);
PlayerDataList GetPlayerDataList() const;
int GetNextPlayerNumber() const;
void AssignPlayerNumbers();
ServerRecvState &GetState();
void SetState(ServerRecvState &newState);
+1
View File
@@ -55,6 +55,7 @@
#define ERR_NET_INVALID_ROUND 112
#define ERR_NET_PLAYER_KICKED 113
#define ERR_NET_INVALID_PLAYER_COUNT 114
#define ERR_NET_PLAYER_NOT_IN_GAME 115
// This is an internal message which is not reported.
#define MSG_SOCK_INTERNAL_PENDING 0