diff --git a/docs/net_protocol.txt b/docs/net_protocol.txt index 83133625..6852fae4 100644 --- a/docs/net_protocol.txt +++ b/docs/net_protocol.txt @@ -1,3 +1,9 @@ +Changelog: +07-24-2007: Join Game ACK / Player Joined do not specify player number. + Player order is transferred on game start. + This is not compatible to the previous protocol. + + PokerTH general message format: 0 1 2 3 @@ -59,19 +65,15 @@ Server Reply: Join Game ACK +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Your Session ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Your Player ID | Your Player Number | + | Your Player ID | Max Number of Players | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Max Number of Players | Small Blind | + | Small Blind | Hands before raise | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Hands before raise | Proposed GUI Speed | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player Action Timeout | Reserved | + | Proposed GUI Speed | Player Action Timeout | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Start Money | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -Player Number: - 0 to (NumberOfPlayers - 1), "position". Player ID: Unique Player ID Proposed GUI Speed: @@ -87,9 +89,9 @@ Server Notification: Player Joined +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Message Type = 3 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player ID | Player Number | + | Player ID | Player Flags | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player Flags | Name Length | + | Name Length | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | \ \ Name (UTF-8) / @@ -105,7 +107,7 @@ Server Notification: Player Left +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Message Type = 4 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player ID | Reserved | + | Player ID | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -114,10 +116,22 @@ Server Notification: Game Start 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 5 | Message Length = 8 | + | Message Type = 5 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Start Dealer Player Id | Number of Players | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Player ID Slot #1 | Player ID Slot #2 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | \ + \ Additional Player Slots / + / | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Player ID Slot #n | Padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +The player slots are the positions of the players on the table. Each slot +contains the ID for the corresponding player. The slots are ordered. +The number of player slots is the number of players. [ Dealer Pos can be different for each game, therefore it is not transmitted in Join Game ACK. ] diff --git a/src/net/clientthread.h b/src/net/clientthread.h index b8b1fcfe..413a1b56 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -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 GetGame(); @@ -109,7 +109,7 @@ private: boost::shared_ptr m_game; unsigned m_curGameId; - int m_guiPlayerNum; + unsigned m_guiPlayerId; friend class AbstractClientStateReceiving; friend class ClientStateInit; diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index f88a6683..986ebc59 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -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( - 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 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_ptrToNetPacketPlayerJoined()->GetData(netPlayerData); boost::shared_ptr 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; } diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index c7fb5443..f232bb0f 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -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 @@ -303,21 +303,27 @@ ClientThread::RemovePlayerData(unsigned playerId) void ClientThread::MapPlayerDataList() { + // Retrieve the GUI player. + boost::shared_ptr 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 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 & diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp index a50429ae..d565e98f 100644 --- a/src/net/common/netpacket.cpp +++ b/src/net/common/netpacket.cpp @@ -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 } //----------------------------------------------------------------------------- diff --git a/src/net/common/serverrecvstate.cpp b/src/net/common/serverrecvstate.cpp index 91e912fb..f5ded7e0 100644 --- a/src/net/common/serverrecvstate.cpp +++ b/src/net/common/serverrecvstate.cpp @@ -290,7 +290,7 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se // Create player data object. boost::shared_ptr 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(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(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(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(answer.get())->SetData(gameStartData); server.SendToAllPlayers(answer); diff --git a/src/net/common/serverrecvthread.cpp b/src/net/common/serverrecvthread.cpp index d7e83a55..d48816b4 100644 --- a/src/net/common/serverrecvthread.cpp +++ b/src/net/common/serverrecvthread.cpp @@ -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 diff --git a/src/net/netpacket.h b/src/net/netpacket.h index d388d477..00c534d8 100644 --- a/src/net/netpacket.h +++ b/src/net/netpacket.h @@ -26,7 +26,7 @@ #include #include -#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 PlayerSlotList; + struct Data { - StartData startData; + StartData startData; + PlayerSlotList playerSlots; }; NetPacketGameStart(); diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h index 1b977c88..8334a9a8 100644 --- a/src/net/serverrecvthread.h +++ b/src/net/serverrecvthread.h @@ -121,7 +121,7 @@ protected: void SetSessionPlayerData(boost::shared_ptr sessionData, boost::shared_ptr playerData); PlayerDataList GetPlayerDataList() const; - int GetNextPlayerNumber() const; + void AssignPlayerNumbers(); ServerRecvState &GetState(); void SetState(ServerRecvState &newState); diff --git a/src/net/socket_msg.h b/src/net/socket_msg.h index e5d43790..eea46630 100644 --- a/src/net/socket_msg.h +++ b/src/net/socket_msg.h @@ -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