From b092b47a58506e19f99bcea87af499429e0483be Mon Sep 17 00:00:00 2001 From: hiker Date: Fri, 27 Nov 2015 08:24:02 +1100 Subject: [PATCH] Send the player's online or local (if not online) name to the server and all clients. --- src/network/network_player_profile.cpp | 7 +- src/network/network_player_profile.hpp | 21 ++- src/network/network_string.cpp | 57 +++++++- src/network/network_string.hpp | 8 +- .../protocols/client_lobby_room_protocol.cpp | 130 ++++++++++-------- .../protocols/server_lobby_room_protocol.cpp | 129 +++++++++-------- 6 files changed, 225 insertions(+), 127 deletions(-) diff --git a/src/network/network_player_profile.cpp b/src/network/network_player_profile.cpp index 7a7c33313..8d4b132bd 100644 --- a/src/network/network_player_profile.cpp +++ b/src/network/network_player_profile.cpp @@ -20,13 +20,18 @@ #include "online/online_player_profile.hpp" -NetworkPlayerProfile::NetworkPlayerProfile(int race_player_id) +/** Constructor. The player id is a unique number assigned from the server + * to this player (though it might not be the index in the peer list). + */ +NetworkPlayerProfile::NetworkPlayerProfile(int race_player_id, + const irr::core::stringw &name) { m_race_player_id = race_player_id; m_online_profile = NULL; m_kart_name = ""; m_world_kart_id = 0; m_per_player_difficulty = PLAYER_DIFFICULTY_NORMAL; + m_player_name = name; } // BetworkPlayerProfile // ---------------------------------------------------------------------------- diff --git a/src/network/network_player_profile.hpp b/src/network/network_player_profile.hpp index f42461885..a1b988aec 100644 --- a/src/network/network_player_profile.hpp +++ b/src/network/network_player_profile.hpp @@ -36,12 +36,17 @@ namespace Online { class OnlineProfile; } class NetworkPlayerProfile { private: - /** The id of the player for the race. */ + /** The unique id of the player for this race. The number is assigned + * by the server (and it might not be the index of this player in the + * peer list. */ uint8_t m_race_player_id; - /** The selected kart. */ + /** The selected kart id. */ std::string m_kart_name; + /** The name of the player. */ + irr::core::stringw m_player_name; + /** Pointer to the online profile of this player. */ Online::OnlineProfile* m_online_profile; @@ -51,8 +56,9 @@ private: /** Per player difficulty. */ PerPlayerDifficulty m_per_player_difficulty; public: - NetworkPlayerProfile(int race_player_id); - ~NetworkPlayerProfile(); + NetworkPlayerProfile(int race_player_id, + const irr::core::stringw &name); + ~NetworkPlayerProfile(); int getGlobalID() const; // ------------------------------------------------------------------------ @@ -85,8 +91,13 @@ public: Online::OnlineProfile *getOnlineProfile() { return m_online_profile; } // ------------------------------------------------------------------------ /** Returns the per-player difficulty. */ - PerPlayerDifficulty getPerPlayerDifficulty() const { return m_per_player_difficulty; } + PerPlayerDifficulty getPerPlayerDifficulty() const + { + return m_per_player_difficulty; + } // getPerPlayerDifficulty // ------------------------------------------------------------------------ + /** Returns the name of this player. */ + const irr::core::stringw& getName() const { return m_player_name; } // ------------------------------------------------------------------------ }; // class NetworkPlayerProfile diff --git a/src/network/network_string.cpp b/src/network/network_string.cpp index 597b13078..61d3900a7 100644 --- a/src/network/network_string.cpp +++ b/src/network/network_string.cpp @@ -16,9 +16,64 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "network/network_string.hpp" +#include "utils/string_utils.hpp" + NetworkString operator+(NetworkString const& a, NetworkString const& b) { NetworkString ns(a); ns += b; return ns; -} +} // operator+ + +// ---------------------------------------------------------------------------- +/** Adds one byte for the length of the string, and then (up to 255 of) +* the characters of the given string. */ +NetworkString& NetworkString::encodeString(const std::string &value) +{ + int len = value.size(); + if(len<=255) + return addUInt8(len).addString(value); + else + return addUInt8(255).addString(value.substr(0, 255)); +} // encodeString + +// ---------------------------------------------------------------------------- +/** Adds one byte for the length of the string, and then (up to 255 of) + * the characters of the given string. */ +NetworkString& NetworkString::encodeString(const irr::core::stringw &value) +{ + std::string v = StringUtils::wideToUtf8(value); + return encodeString(v); +} // encodeString + +// ---------------------------------------------------------------------------- +/** Returns a string at the given position. The first byte indicates the + * length, followed by the actual string (not 0 terminated). + * \param[in] pos Buffer position where the encoded string starts. + * \param[out] out The decoded string. + * \return number of bytes read = 1+length of string + */ +int NetworkString::decodeString(int pos, std::string *out) const +{ + uint8_t len = getUInt8(pos); + *out = getString(pos+1, len); + return len; +} // decodeString + +// ---------------------------------------------------------------------------- +/** Returns an irrlicht wide string from the utf8 encoded string at the + * given position. + * \param[in] pos Buffer position where the encoded string starts. + * \param[out] out The decoded string. + * \return number of bytes read. If there are no special characters in the + * string that will be 1+length of string, but multi-byte encoded + * characters can mean that the length of the returned string is + * less than the number of bytes read. + */ +int NetworkString::decodeStringW(int pos, irr::core::stringw *out) const +{ + std::string s; + int len = decodeString(pos, &s); + *out = StringUtils::utf8ToWide(s); + return len; +} // decodeString diff --git a/src/network/network_string.hpp b/src/network/network_string.hpp index a84be54fa..69139f421 100644 --- a/src/network/network_string.hpp +++ b/src/network/network_string.hpp @@ -25,6 +25,8 @@ #include "utils/types.hpp" +#include "irrString.h" + #include #include #include @@ -85,6 +87,11 @@ public: memcpy(m_string.data(), p, len); } // NetworkString(char*, int) // ------------------------------------------------------------------------ + NetworkString& encodeString(const std::string &value); + NetworkString& encodeString(const irr::core::stringw &value); + int decodeString(int n, std::string *out) const; + int decodeStringW(int n, irr::core::stringw *out) const; + // ------------------------------------------------------------------------ NetworkString& add(const std::string &s) { return addUInt8(uint8_t(s.size())).as(s); @@ -218,7 +225,6 @@ public: /** Adds a single character. */ inline NetworkString& ac(const char& value) { return addChar(value); } - // ------------------------------------------------------------------------ /** Adds a string. */ NetworkString& addString(const std::string& value) { diff --git a/src/network/protocols/client_lobby_room_protocol.cpp b/src/network/protocols/client_lobby_room_protocol.cpp index 74459e9cc..46b02a262 100644 --- a/src/network/protocols/client_lobby_room_protocol.cpp +++ b/src/network/protocols/client_lobby_room_protocol.cpp @@ -234,10 +234,18 @@ void ClientLobbyRoomProtocol::update() break; case LINKED: { - NetworkString ns(6); + core::stringw name; + if(PlayerManager::getCurrentOnlineState()==PlayerProfile::OS_SIGNED_IN) + name = PlayerManager::getCurrentOnlineUserName(); + else + name = PlayerManager::getCurrentPlayer()->getName(); + + std::string name_u8 = StringUtils::wideToUtf8(name); + NetworkString ns(6+1+name_u8.size()); // 4 (size of id), global id ns.ai8(LE_CONNECTION_REQUESTED).ai8(4) - .ai32(PlayerManager::getCurrentOnlineId()); + .addUInt32(PlayerManager::getCurrentOnlineId()) + .encodeString(name); sendMessage(ns); m_state = REQUESTING_CONNECTION; } @@ -283,11 +291,11 @@ void ClientLobbyRoomProtocol::update() * \param event : Event providing the information. * * Format of the data : - * Byte 0 1 5 6 7 - * ------------------------------------------------ - * Size | 1 | 4 | 1 | 1 | - * Data | 4 | player global id | 1 | 0 <= race id < 16 | - * ------------------------------------------------ + * Byte 0 1 5 6 7 8 + * ------------------------------------------------------------------- + * Size | 1 | 4 | 1 | 1 | 1 | | + * Data | 4 | player global id | 1 | 0 <= race id < 16 | len | player name| + * ------------------------------------------------------------------- */ void ClientLobbyRoomProtocol::newPlayer(Event* event) { @@ -302,7 +310,9 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event) uint32_t global_id = data.gui32(1); uint8_t player_id = data.gui8(6); - + int name_len = data.getUInt8(7); + std::string name_utf8 = data.getString(8, name_len); + core::stringw name = StringUtils::utf8ToWide(name_utf8); if (global_id == PlayerManager::getCurrentOnlineId()) { Log::error("ClientLobbyRoomProtocol", @@ -313,8 +323,7 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event) m_setup->getProfile(global_id) == NULL) { Log::verbose("ClientLobbyRoomProtocol", "New player connected."); - // FIXME: what player id to use? - NetworkPlayerProfile* profile = new NetworkPlayerProfile(-1); + NetworkPlayerProfile* profile = new NetworkPlayerProfile(player_id, name); profile->setPlayerID(player_id); // FIXME: memory leak?? profile->setOnlineProfile(new Online::OnlineProfile(global_id, "")); @@ -369,13 +378,13 @@ void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event) * Byte 0 1 2 3 7 8 12 * ---------------------------------------------------------- * Size | 1 | 1 | 1 | 4 | 1 | 4 | - * Data | 1 | 0 <= race id < 16 | 4 | priv token | 4 | global id | + * Data | 1 | 0 <= race id < 16 | 4 | priv token | 4 | global id | playernames* * ---------------------------------------------------------- */ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) { NetworkString &data = event->data(); - // 12 bytes should remain now + // At least 12 bytes should remain now if (data.size() < 12 || data[0] != 1 || data[2] != 4 || data[7] != 4) { Log::error("ClientLobbyRoomProtocol", @@ -386,55 +395,60 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) STKPeer* peer = event->getPeer(); uint32_t global_id = data.gui32(8); - if (global_id == PlayerManager::getCurrentOnlineId()) + if (global_id != PlayerManager::getCurrentOnlineId()) { - Log::info("ClientLobbyRoomProtocol", - "The server accepted the connection."); - - // self profile - //FIXME - NetworkPlayerProfile* profile = new NetworkPlayerProfile(-1); - profile->setPlayerID(data.gui8(1)); - profile->setOnlineProfile(PlayerManager::getCurrentOnlineProfile()); - m_setup->addPlayer(profile); - // connection token - uint32_t token = data.gui32(3); - peer->setClientServerToken(token); - // add all players - data.removeFront(12); // remove the 12 first bytes - int remaining = data.size(); - if (remaining%7 != 0) - { - Log::error("ClientLobbyRoomProtocol", - "ConnectionAccepted : Error in the server list"); - } - remaining /= 7; - for (int i = 0; i < remaining; i++) - { - if (data[0] != 1 || data[2] != 4) - Log::error("ClientLobbyRoomProtocol", - "Bad format in players list."); - - uint8_t race_id = data[1]; - uint32_t global_id = data.gui32(3); - Online::OnlineProfile* new_user = - new Online::OnlineProfile(global_id, ""); - - // FIXME - NetworkPlayerProfile* profile2 = new NetworkPlayerProfile(-1); - profile2->setPlayerID(race_id); - profile2->setOnlineProfile(new_user); - m_setup->addPlayer(profile2); - data.removeFront(7); - } - - // add self - m_server = event->getPeer(); - m_state = CONNECTED; - } - else Log::info("ClientLobbyRoomProtocol", "Failure during the connection acceptation process."); + return; + } + + // Accepted + // ======== + Log::info("ClientLobbyRoomProtocol", + "The server accepted the connection."); + + // self profile + irr::core::stringw name; + if (PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_IN) + name = PlayerManager::getCurrentOnlineUserName(); + else + name = PlayerManager::getCurrentPlayer()->getName(); + NetworkPlayerProfile* profile = new NetworkPlayerProfile(-1, name); + profile->setPlayerID(data.gui8(1)); + profile->setOnlineProfile(PlayerManager::getCurrentOnlineProfile()); + m_setup->addPlayer(profile); + // connection token + uint32_t token = data.gui32(3); + peer->setClientServerToken(token); + + // Add all players + // =============== + int n = 12; + while (n < data.size()) + { + if (data[n] != 1 || data[n + 2] != 4) + Log::error("ClientLobbyRoomProtocol", + "Bad format in players list."); + + uint8_t race_player_id = data[n + 1]; + uint32_t global_id = data.gui32(n + 3); + irr::core::stringw name; + int bytes_read = data.decodeStringW(n + 7, &name); + // FIXME - leak? + Online::OnlineProfile* new_user = + new Online::OnlineProfile(global_id, name); + + NetworkPlayerProfile* profile2 = + new NetworkPlayerProfile(race_player_id, name); + profile2->setPlayerID(race_player_id); + profile2->setOnlineProfile(new_user); + m_setup->addPlayer(profile2); + n += bytes_read+7; + } + + // add self + m_server = event->getPeer(); + m_state = CONNECTED; } // connectionAccepted //----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby_room_protocol.cpp b/src/network/protocols/server_lobby_room_protocol.cpp index 570aacac7..24170135d 100644 --- a/src/network/protocols/server_lobby_room_protocol.cpp +++ b/src/network/protocols/server_lobby_room_protocol.cpp @@ -412,16 +412,16 @@ void ServerLobbyRoomProtocol::kartDisconnected(Event* event) * * Format of the data : * Byte 0 1 5 - * ------------------------ - * Size | 1 | 4 | - * Data | 4 | global player id | - * ------------------------ + * ---------------------------------------- + * Size | 1 | 4 |1| | + * Data | 4 | global player id |n| player name | + * ---------------------------------------- */ void ServerLobbyRoomProtocol::connectionRequested(Event* event) { STKPeer* peer = event->getPeer(); const NetworkString &data = event->data(); - if (data.size() != 5 || data[0] != 4) + if (data[0] != 4) { Log::warn("ServerLobbyRoomProtocol", "Receiving badly formated message. Size is %d and first byte %d", @@ -431,68 +431,75 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) uint32_t player_id = 0; player_id = data.getUInt32(1); // can we add the player ? - if (m_setup->getPlayerCount() < NetworkConfig::get()->getMaxPlayers() && - m_state==ACCEPTING_CLIENTS ) - { - // add the player to the game setup - m_next_id = m_setup->getPlayerCount(); - // notify everybody that there is a new player - NetworkString message(8); - // size of id -- id -- size of local id -- local id; - message.ai8(LE_NEW_PLAYER_CONNECTED).ai8(4).ai32(player_id) - .ai8(1).ai8(m_next_id); - ProtocolManager::getInstance()->sendMessageExcept(this, peer, message); - - /// now answer to the peer that just connected - RandomGenerator token_generator; - // use 4 random numbers because rand_max is probably 2^15-1. - uint32_t token = (uint32_t)(((token_generator.get(RAND_MAX)<<24) & 0xff) + - ((token_generator.get(RAND_MAX)<<16) & 0xff) + - ((token_generator.get(RAND_MAX)<<8) & 0xff) + - ((token_generator.get(RAND_MAX) & 0xff))); - - std::vector players = m_setup->getPlayers(); - // send a message to the one that asked to connect - // Size is overestimated, probably one player's data will not be sent - NetworkString message_ack(13+players.size()*7); - // connection success (129) -- size of token -- token - message_ack.ai8(LE_CONNECTION_ACCEPTED).ai8(1).ai8(m_next_id).ai8(4) - .ai32(token).ai8(4).ai32(player_id); - // add all players so that this user knows - for (unsigned int i = 0; i < players.size(); i++) - { - // do not duplicate the player into the message - if (players[i]->getPlayerID() != m_next_id && - players[i]->getGlobalID() != player_id) - { - message_ack.ai8(1).ai8(players[i]->getPlayerID()).ai8(4) - .ai32(players[i]->getGlobalID()); - } - } - sendMessage(peer, message_ack); - - peer->setClientServerToken(token); - - NetworkPlayerProfile* profile = new NetworkPlayerProfile(m_next_id); - // FIXME: memory leak OnlineProfile - profile->setOnlineProfile(new Online::OnlineProfile(player_id, "")); - m_setup->addPlayer(profile); - peer->setPlayerProfile(profile); - Log::verbose("ServerLobbyRoomProtocol", "New player."); - } // accept player - else // refuse the connection with code 0 (too much players) + if (m_setup->getPlayerCount() >= NetworkConfig::get()->getMaxPlayers() || + m_state!=ACCEPTING_CLIENTS ) { NetworkString message(3); - message.ai8(LE_CONNECTION_REFUSED); - message.ai8(1); // 1 bytes for the error code - if(m_state!=ACCEPTING_CLIENTS) - message.ai8(2); // 2 = Busy - else - message.ai8(0); // 0 = too many players + // Len, error code: 2 = busy, 0 = too many players + message.ai8(LE_CONNECTION_REFUSED).ai8(1) + .ai8(m_state!=ACCEPTING_CLIENTS ? 2 : 0); + // send only to the peer that made the request sendMessage(peer, message); Log::verbose("ServerLobbyRoomProtocol", "Player refused"); + return; } + + // Connection accepted. + // ==================== + std::string name_u8; + int name_len = data.decodeString(5, &name_u8); + core::stringw name = StringUtils::utf8ToWide(name_u8); + + // add the player to the game setup + m_next_id = m_setup->getPlayerCount(); + + NetworkPlayerProfile* profile = new NetworkPlayerProfile(m_next_id, name); + // FIXME: memory leak OnlineProfile + profile->setOnlineProfile(new Online::OnlineProfile(player_id, "")); + m_setup->addPlayer(profile); + peer->setPlayerProfile(profile); + + // notify everybody that there is a new player + NetworkString message(8); + // size of id -- id -- size of local id -- local id; + message.ai8(LE_NEW_PLAYER_CONNECTED).ai8(4).ai32(player_id) + .ai8(1).ai8(m_next_id).encodeString(name_u8); + ProtocolManager::getInstance()->sendMessageExcept(this, peer, message); + + // Now answer to the peer that just connected + RandomGenerator token_generator; + // use 4 random numbers because rand_max is probably 2^15-1. + uint32_t token = (uint32_t)(((token_generator.get(RAND_MAX) << 24) & 0xff) + + ((token_generator.get(RAND_MAX) << 16) & 0xff) + + ((token_generator.get(RAND_MAX) << 8) & 0xff) + + ((token_generator.get(RAND_MAX) & 0xff))); + + std::vector players = m_setup->getPlayers(); + // send a message to the one that asked to connect + // Size is overestimated, probably one player's data will not be sent + NetworkString message_ack(13 + players.size() * 7); + // connection success (129) -- size of token -- token + message_ack.ai8(LE_CONNECTION_ACCEPTED).ai8(1).ai8(m_next_id).ai8(4) + .ai32(token).ai8(4).ai32(player_id); + // add all players so that this user knows + for (unsigned int i = 0; i < players.size(); i++) + { + // do not duplicate the player into the message + if (players[i]->getPlayerID() != m_next_id && + players[i]->getGlobalID() != player_id) + { + message_ack.ai8(1).ai8(players[i]->getPlayerID()).ai8(4) + .ai32(players[i]->getGlobalID()) + .encodeString(players[i]->getName()); + } + } + sendMessage(peer, message_ack); + + peer->setClientServerToken(token); + + Log::verbose("ServerLobbyRoomProtocol", "New player."); + } // connectionRequested //-----------------------------------------------------------------------------