Have the server send the player list to the client (#5924)
authorred-001 <red-001@outlook.ie>
Thu, 8 Jun 2017 13:30:09 +0000 (14:30 +0100)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Thu, 8 Jun 2017 13:30:09 +0000 (15:30 +0200)
* Have the server send the player list to the client

Currently the client generates the player list based on the Client active object list, the issue with this is that we can't be sure all player active objects will be sent to the client, so this could result in players showing up when someone run `/status` but auto complete not working with their nick and CSM not being aware of the player

src/client.h
src/content_cao.cpp
src/network/clientopcodes.cpp
src/network/clientpackethandler.cpp
src/network/networkprotocol.h
src/network/serveropcodes.cpp
src/network/serverpackethandler.cpp
src/server.cpp

index 9aec0d0619dc1d4b4a52cecdbb3c02bd9d7c2ee1..c94936d8508856b5f71c620434e96ed42fec118c 100644 (file)
@@ -348,6 +348,7 @@ public:
        void handleCommand_OverrideDayNightRatio(NetworkPacket* pkt);
        void handleCommand_LocalPlayerAnimations(NetworkPacket* pkt);
        void handleCommand_EyeOffset(NetworkPacket* pkt);
+       void handleCommand_UpdatePlayerList(NetworkPacket* pkt);
        void handleCommand_SrpBytesSandB(NetworkPacket* pkt);
 
        void ProcessData(NetworkPacket *pkt);
index c904082d6e9eb433c9e1c669af65666feacb9934..a5a55fd7e5adc7ee53f18f6e638f61303ca581fe 100644 (file)
@@ -624,7 +624,8 @@ void GenericCAO::initialize(const std::string &data)
                        m_is_visible = false;
                        player->setCAO(this);
                }
-               m_env->addPlayerName(m_name.c_str());
+               if (m_client->getProtoVersion() < 33)
+                       m_env->addPlayerName(m_name.c_str());
        }
 }
 
@@ -667,7 +668,7 @@ void GenericCAO::processInitData(const std::string &data)
 
 GenericCAO::~GenericCAO()
 {
-       if (m_is_player) {
+       if (m_is_player && m_client->getProtoVersion() < 33) {
                m_env->removePlayerName(m_name.c_str());
        }
        removeFromScene(true);
index bdcb1dfce0709fd82f46193f48cfd09957d1dec0..cb504b373a9e62e9ba8ef5f90cdbf7b68723addd 100644 (file)
@@ -110,7 +110,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
        { "TOCLIENT_DELETE_PARTICLESPAWNER",   TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeleteParticleSpawner }, // 0x53
        { "TOCLIENT_CLOUD_PARAMS",             TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CloudParams }, // 0x54
        { "TOCLIENT_FADE_SOUND",               TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FadeSound }, // 0x55
-       null_command_handler,
+       { "TOCLIENT_UPDATE_PLAYER_LIST",       TOCLIENT_STATE_CONNECTED, &Client::handleCommand_UpdatePlayerList }, // 0x56
        null_command_handler,
        null_command_handler,
        null_command_handler,
index d002ae10d8a50ee4d204dea2444ed7b2d741c5d1..9eb6d8dca2747bdae4ab7bdcaec65cf082285b67 100644 (file)
@@ -1270,6 +1270,28 @@ void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
        *pkt >> player->eye_offset_first >> player->eye_offset_third;
 }
 
+void Client::handleCommand_UpdatePlayerList(NetworkPacket* pkt)
+{
+       u8 type;
+       u16 num_players;
+       *pkt >> type >> num_players;
+       PlayerListModifer notice_type = (PlayerListModifer) type;
+
+       for (u16 i = 0; i < num_players; i++) {
+               std::string name;
+               *pkt >> name;
+               switch (notice_type) {
+               case PLAYER_LIST_INIT:
+               case PLAYER_LIST_ADD:
+                       m_env.addPlayerName(name);
+                       continue;
+               case PLAYER_LIST_REMOVE:
+                       m_env.removePlayerName(name);
+                       continue;
+               }
+       }
+}
+
 void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
 {
        if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
index 7126c237be2b30f6f3b77d0ee11f0b8ace401fcf..f003cf26a4c9d2d627e10a134c62a2c11fed440d 100644 (file)
@@ -155,9 +155,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
                Stop sending TOSERVER_CLIENT_READY
        PROTOCOL VERSION 32:
                Add fading sounds
+       PROTOCOL VERSION 33:
+               Add TOCLIENT_UPDATE_PLAYER_LIST and send the player list to the client,
+                       instead of guessing based on the active object list.
+
 */
 
-#define LATEST_PROTOCOL_VERSION 32
+#define LATEST_PROTOCOL_VERSION 33
 
 // Server's supported network protocol range
 #define SERVER_PROTOCOL_VERSION_MIN 24
@@ -629,6 +633,14 @@ enum ToClientCommand
                float step
                float gain
        */
+       TOCLIENT_UPDATE_PLAYER_LIST = 0x56,
+       /*
+               u8 type
+               u16 number of players
+               for each player
+                       u16 len
+                       u8[len] player name
+       */
 
        TOCLIENT_SRP_BYTES_S_B = 0x60,
        /*
@@ -965,4 +977,12 @@ const static std::string accessDeniedStrings[SERVER_ACCESSDENIED_MAX] = {
        "This server has experienced an internal error. You will now be disconnected."
 };
 
+enum PlayerListModifer: u8
+{
+       PLAYER_LIST_INIT,
+       PLAYER_LIST_ADD,
+       PLAYER_LIST_REMOVE,
+};
+
+
 #endif
index 19978a2b64f06cc7e0ee2b358791a8fb6b854f08..3f9706d6aba3fb921b37d4c28fbe751a1220e6e6 100644 (file)
@@ -199,7 +199,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
        { "TOCLIENT_DELETE_PARTICLESPAWNER",   0, true }, // 0x53
        { "TOCLIENT_CLOUD_PARAMS",             0, true }, // 0x54
        { "TOCLIENT_FADE_SOUND",               0, true }, // 0x55
-       null_command_factory,
+       { "TOCLIENT_UPDATE_PLAYER_LIST",       0, true }, // 0x56
        null_command_factory,
        null_command_factory,
        null_command_factory,
index 90b747e46357114043474db019e5eda85a790c2e..f33b1a523cb4590f46463ad8d2acab6b4b1a6696 100644 (file)
@@ -705,6 +705,19 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt)
                        peer_id, major_ver, minor_ver, patch_ver,
                        full_ver);
 
+       const std::vector<std::string> &players = m_clients.getPlayerNames();
+       NetworkPacket list_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, peer_id);
+       list_pkt << (u8) PLAYER_LIST_INIT << (u16) players.size();
+       for (const std::string &player: players) {
+               list_pkt <<  player;
+       }
+       m_clients.send(peer_id, 0, &list_pkt, true);
+
+       NetworkPacket notice_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
+       // (u16) 1 + std::string represents a pseudo vector serialization representation
+       notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << std::string(playersao->getPlayer()->getName());
+       m_clients.sendToAll(&notice_pkt);
+
        m_clients.event(peer_id, CSE_SetClientReady);
        m_script->on_joinplayer(playersao);
        // Send shutdown timer if shutdown has been scheduled
index b2fdecfa94d509d41e4f07cc558cf7e3e97b3c99..0351fa13b5403147b9473984e6be8e36d26f3dfe 100644 (file)
@@ -2787,6 +2787,12 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
                        PlayerSAO *playersao = player->getPlayerSAO();
                        assert(playersao);
 
+                       // inform connected clients
+                       NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
+                       // (u16) 1 + std::string represents a vector serialization representation
+                       notice << (u8) PLAYER_LIST_REMOVE  << (u16) 1 << std::string(playersao->getPlayer()->getName());
+                       m_clients.sendToAll(&notice);
+                       // run scripts
                        m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
 
                        playersao->disconnected();