From 4221c1b4412f2bf889bd603a26424003f5367f6a Mon Sep 17 00:00:00 2001 From: red-001 Date: Thu, 8 Jun 2017 14:30:09 +0100 Subject: [PATCH] Have the server send the player list to the client (#5924) * 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 | 1 + src/content_cao.cpp | 5 +++-- src/network/clientopcodes.cpp | 2 +- src/network/clientpackethandler.cpp | 22 ++++++++++++++++++++++ src/network/networkprotocol.h | 22 +++++++++++++++++++++- src/network/serveropcodes.cpp | 2 +- src/network/serverpackethandler.cpp | 13 +++++++++++++ src/server.cpp | 6 ++++++ 8 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/client.h b/src/client.h index 9aec0d061..c94936d85 100644 --- a/src/client.h +++ b/src/client.h @@ -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); diff --git a/src/content_cao.cpp b/src/content_cao.cpp index c904082d6..a5a55fd7e 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -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); diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index bdcb1dfce..cb504b373 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -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, diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index d002ae10d..9eb6d8dca 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -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) diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 7126c237b..f003cf26a 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -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 diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp index 19978a2b6..3f9706d6a 100644 --- a/src/network/serveropcodes.cpp +++ b/src/network/serveropcodes.cpp @@ -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, diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 90b747e46..f33b1a523 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -705,6 +705,19 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt) peer_id, major_ver, minor_ver, patch_ver, full_ver); + const std::vector &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(¬ice_pkt); + m_clients.event(peer_id, CSE_SetClientReady); m_script->on_joinplayer(playersao); // Send shutdown timer if shutdown has been scheduled diff --git a/src/server.cpp b/src/server.cpp index b2fdecfa9..0351fa13b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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(¬ice); + // run scripts m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT); playersao->disconnected();