From b2c9f151d30832a250092b02d2bbc624d72ebf3e Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sun, 9 May 2021 10:02:46 +0200 Subject: [PATCH] Change: multiple modes to send NewGRF data to client / Game Coordinator NewGRFs cannot be changed in multiplayer games, and consumes a lot of bytes. So only send it once to the Game Coordiantor on registration, and skip the field after that for any update. A new game will restart the registration, so any NewGRF change between games is picked up via the new registration. Clients that look at the NewGRFs a server has, want to know the names of the NewGRFs more than the IDs. So in addition to the ID and MD5, send the full name to the clients too. This solution is picked so the Game Coordinator isn't sending the names of all the NewGRFs to the clients constantly (which would make the server-listing very large), but still allow clinets to see the name of a specific server if he clicks the button. --- src/network/core/game_info.cpp | 66 ++++++++++++++++++----------- src/network/core/game_info.h | 18 +++++--- src/network/network_coordinator.cpp | 15 ++++--- src/network/network_coordinator.h | 2 +- src/network/network_gui.cpp | 5 ++- src/network/network_server.cpp | 2 +- 6 files changed, 70 insertions(+), 38 deletions(-) diff --git a/src/network/core/game_info.cpp b/src/network/core/game_info.cpp index 20c55283accb7..1637610bcaed1 100644 --- a/src/network/core/game_info.cpp +++ b/src/network/core/game_info.cpp @@ -158,17 +158,20 @@ const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo() * a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This * function must set all appropriate fields. This GRF is later appended to * the grfconfig list of the NetworkGameInfo. - * @param config the GRF to handle. + * @param config The GRF to handle. + * @param name The name of the GRF, if known (for example: the server send this info). */ -static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) +static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config, std::string &name) { /* Find the matching GRF file */ const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum); if (f == nullptr) { /* Don't know the GRF, so mark game incompatible and the (possibly) - * already resolved name for this GRF (another server has sent the - * name of the GRF already */ + * already resolved name for this GRF. */ config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true); + if (strcmp(GetGRFStringFromGRFText(config->name), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0 && !name.empty()) { + AddGRFTextToList(config->name, name.c_str()); + } config->status = GCS_NOT_FOUND; } else { config->filename = f->filename; @@ -181,10 +184,11 @@ static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) /** * Serializes the NetworkGameInfo struct to the packet. - * @param p the packet to write the data to. - * @param info the NetworkGameInfo struct to serialize from. + * @param p The packet to write the data to. + * @param info The NetworkGameInfo struct to serialize from. + * @param newgrf_mode The NewGRF mode of the NetworkGameInfo. See GameInfoNewGRFMode for details. */ -void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info) +void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, GameInfoNewGRFMode newgrf_mode) { p->Send_uint8 (NETWORK_GAME_INFO_VERSION); @@ -194,9 +198,10 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info) /* NETWORK_GAME_INFO_VERSION = 5 */ assert(info->join_key.empty() || info->join_key[0] == '+'); p->Send_string(info->join_key.empty() ? "" : info->join_key.substr(1)); + p->Send_uint8(newgrf_mode); /* NETWORK_GAME_INFO_VERSION = 4 */ - { + if (newgrf_mode != GAME_INFO_NEWGRF_MODE_NONE) { /* Only send the GRF Identification (GRF_ID and MD5 checksum) of * the GRFs that are needed, i.e. the ones that the server has * selected in the NewGRF GUI and not the ones that are used due @@ -212,7 +217,12 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info) /* Send actual GRF Identifications */ for (c = info->grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(p, &c->ident); + if (!HasBit(c->flags, GCF_STATIC)) { + SerializeGRFIdentifier(p, &c->ident); + if (newgrf_mode == GAME_INFO_NEWGRF_MODE_FULL) { + p->Send_string(c->GetName()); + } + } } } @@ -257,29 +267,37 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) /* Update the documentation in game_info.h on changes * to the NetworkGameInfo wire-protocol! */ + GameInfoNewGRFMode newgrf_mode = GAME_INFO_NEWGRF_MODE_SHORT; switch (game_info_version) { case 5: { std::string join_key = p->Recv_string(NETWORK_JOIN_KEY_LENGTH); info->join_key = join_key.empty() ? "" : "+" + join_key; + newgrf_mode = (GameInfoNewGRFMode)p->Recv_uint8(); FALLTHROUGH; } case 4: { - GRFConfig **dst = &info->grfconfig; - uint i; - uint num_grfs = p->Recv_uint8(); - - /* Broken/bad data. It cannot have that many NewGRFs. */ - if (num_grfs > NETWORK_MAX_GRF_COUNT) return; - - for (i = 0; i < num_grfs; i++) { - GRFConfig *c = new GRFConfig(); - DeserializeGRFIdentifier(p, &c->ident); - HandleIncomingNetworkGameInfoGRFConfig(c); - - /* Append GRFConfig to the list */ - *dst = c; - dst = &c->next; + if (newgrf_mode != GAME_INFO_NEWGRF_MODE_NONE) { + GRFConfig **dst = &info->grfconfig; + uint i; + uint num_grfs = p->Recv_uint8(); + + /* Broken/bad data. It cannot have that many NewGRFs. */ + if (num_grfs > NETWORK_MAX_GRF_COUNT) return; + + for (i = 0; i < num_grfs; i++) { + GRFConfig *c = new GRFConfig(); + DeserializeGRFIdentifier(p, &c->ident); + std::string name = {}; + if (newgrf_mode == GAME_INFO_NEWGRF_MODE_FULL) { + name = p->Recv_string(NETWORK_GRF_NAME_LENGTH); + } + HandleIncomingNetworkGameInfoGRFConfig(c, name); + + /* Append GRFConfig to the list */ + *dst = c; + dst = &c->next; + } } FALLTHROUGH; } diff --git a/src/network/core/game_info.h b/src/network/core/game_info.h index 6770de0ccf02a..edd9145478b56 100644 --- a/src/network/core/game_info.h +++ b/src/network/core/game_info.h @@ -26,11 +26,13 @@ * all 1 the version of this packet's structure * * 5+ var join key of the server - * 4+ 1 number of GRFs attached (n) - * 4+ n * 20 unique identifier for GRF files. Consists of: - * - one 4 byte variable with the GRF ID - * - 16 bytes (sent sequentially) for the MD5 checksum + * 5+ 1 NewGRF mode (0 = none: skip next two fields, 1 = short: skip name, 2 = full) + * 4+ 1 number of NewGRFs attached + * 4+ n * M unique identifier for NewGRF files. Consists of: + * 4+ - one 4 byte variable with the NewGRF ID + * 4+ - 16 bytes (sent sequentially) for the MD5 checksum * of the GRF + * 5+ - name of the NewGRF * * 3+ 4 current game date in days since 1-1-0 (DMY) * 3+ 4 game introduction date in days since 1-1-0 (DMY) @@ -89,6 +91,12 @@ struct NetworkGameInfo : NetworkServerGameInfo { bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match }; +enum GameInfoNewGRFMode : uint8 { + GAME_INFO_NEWGRF_MODE_NONE = 0, ///< Send/receive NetworkGameInfo without any NewGRF data. + GAME_INFO_NEWGRF_MODE_SHORT, ///< Send/receive NetworkGameInfo with only the ID + MD5 of NewGRFs. + GAME_INFO_NEWGRF_MODE_FULL, ///< Send/receive NetworkGameInfo with ID + MD5 + Name of NewGRFs. +}; + extern NetworkServerGameInfo _network_game_info; std::string_view GetNetworkRevisionString(); @@ -102,6 +110,6 @@ void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf); void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf); void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info); -void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info); +void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, GameInfoNewGRFMode newgrf_mode); #endif /* NETWORK_CORE_GAME_INFO_H */ diff --git a/src/network/network_coordinator.cpp b/src/network/network_coordinator.cpp index 79d8cf15957d1..f089896b9773a 100644 --- a/src/network/network_coordinator.cpp +++ b/src/network/network_coordinator.cpp @@ -167,9 +167,6 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_SERVER_ERROR(Packet *p) bool ClientNetworkCoordinatorSocketHandler::Receive_SERVER_REGISTER_ACK(Packet *p) { - /* Schedule sending an update. */ - this->next_update = std::chrono::steady_clock::now(); - _settings_client.network.server_join_key = "+" + p->Recv_string(NETWORK_JOIN_KEY_LENGTH); _settings_client.network.server_join_key_secret = p->Recv_string(NETWORK_JOIN_KEY_SECRET_LENGTH); _network_server_connection_type = (ConnectionType)p->Recv_uint8(); @@ -219,6 +216,11 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_SERVER_REGISTER_ACK(Packet * Debug(net, 3, "Game Coordinator registered our server with invite code '{}'", _network_game_info.join_key); } + /* Sendt a full update, including NewGRF data. */ + this->SendServerUpdate(GAME_INFO_NEWGRF_MODE_SHORT); + /* Schedule sending next update. */ + this->next_update = std::chrono::steady_clock::now() + NETWORK_COORDINATOR_DELAY_BETWEEN_UPDATES; + return true; } @@ -428,15 +430,16 @@ void ClientNetworkCoordinatorSocketHandler::Register() /** * Send an update of our server status to the Game Coordinator. + * @param include_newgrf_data Whether the server update should include NewGRF data. */ -void ClientNetworkCoordinatorSocketHandler::SendServerUpdate() +void ClientNetworkCoordinatorSocketHandler::SendServerUpdate(GameInfoNewGRFMode newgrf_mode) { Debug(net, 6, "Sending server update to Game Coordinator"); this->next_update = std::chrono::steady_clock::now() + NETWORK_COORDINATOR_DELAY_BETWEEN_UPDATES; Packet *p = new Packet(PACKET_COORDINATOR_CLIENT_UPDATE); p->Send_uint8(NETWORK_COORDINATOR_VERSION); - SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo()); + SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo(), newgrf_mode); this->SendPacket(p); } @@ -665,7 +668,7 @@ void ClientNetworkCoordinatorSocketHandler::SendReceive() } if (_network_server && _network_server_connection_type != CONNECTION_TYPE_UNKNOWN && std::chrono::steady_clock::now() > this->next_update) { - this->SendServerUpdate(); + this->SendServerUpdate(GAME_INFO_NEWGRF_MODE_NONE); } if (!_network_server && std::chrono::steady_clock::now() > this->last_activity + IDLE_TIMEOUT) { diff --git a/src/network/network_coordinator.h b/src/network/network_coordinator.h index 134b4402d7762..55ee399809257 100644 --- a/src/network/network_coordinator.h +++ b/src/network/network_coordinator.h @@ -92,7 +92,7 @@ class ClientNetworkCoordinatorSocketHandler : public NetworkCoordinatorSocketHan void CloseTurnHandler(const std::string &token); void Register(); - void SendServerUpdate(); + void SendServerUpdate(GameInfoNewGRFMode newgrf_mode); void GetListing(); void ConnectToServer(const std::string &join_key, TCPServerConnecter *connecter); diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index db6b4942c4f67..965a6d1b8769d 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -772,7 +772,10 @@ class NetworkGameWindow : public Window { break; case WID_NG_NEWGRF: // NewGRF Settings - if (this->server != nullptr) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig); + if (this->server != nullptr) { + NetworkQueryServer(this->server->connection_string); + ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig); + } break; case WID_NG_NEWGRF_MISSING: // Find missing content online diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 46d6918acd943..25717cc0a90fe 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -355,7 +355,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientIn NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo() { Packet *p = new Packet(PACKET_SERVER_GAME_INFO); - SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo()); + SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo(), GAME_INFO_NEWGRF_MODE_FULL); this->SendPacket(p);