From 3eaa4706325556bfb1351d2ff392b5bc205fd238 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 18 Jul 2021 13:42:01 +0200 Subject: Feature: [Network] Optionally send NewGRF names with NewGRFs in GameInfo Before 8a2da49 the NewGRF names were synchronized using UDP packets, however those have been removed. With this a new version of the GameInfo packet is introduced that allows to specify the type of serialisation happens for NewGRFs. Either only the GRF ID and checksum, or those two plus the name of the NewGRF. On this request for local servers will send the NewGRFs names. The Game Coordinator will get the names on the first registration, and after that only the GRF ID and checksum. --- src/network/core/config.h | 2 +- src/network/core/game_info.cpp | 58 ++++++++++++++++++++++++++++++------- src/network/core/game_info.h | 46 ++++++++++++++++++++++++----- src/network/network_coordinator.cpp | 5 ++-- 4 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/network/core/config.h b/src/network/core/config.h index 6039c4252..ccc9cd263 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -47,7 +47,7 @@ static const uint16 TCP_MTU = 32767; ///< Numbe static const uint16 COMPAT_MTU = 1460; ///< Number of bytes we can pack in a single packet for backward compatibility static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use? -static const byte NETWORK_GAME_INFO_VERSION = 5; ///< What version of game-info do we use? +static const byte NETWORK_GAME_INFO_VERSION = 6; ///< What version of game-info do we use? static const byte NETWORK_COMPANY_INFO_VERSION = 6; ///< What version of company info is this? static const byte NETWORK_COORDINATOR_VERSION = 3; ///< What version of game-coordinator-protocol do we use? diff --git a/src/network/core/game_info.cpp b/src/network/core/game_info.cpp index d3c0491ba..138053b05 100644 --- a/src/network/core/game_info.cpp +++ b/src/network/core/game_info.cpp @@ -159,14 +159,15 @@ 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 NewGRF, empty when unknown. */ -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) { - AddGRFTextToList(config->name, GetString(STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN)); + AddGRFTextToList(config->name, name.empty() ? GetString(STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN) : name); config->status = GCS_NOT_FOUND; } else { config->filename = f->filename; @@ -182,7 +183,7 @@ static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) * @param p the packet to write the data to. * @param info the NetworkGameInfo struct to serialize from. */ -void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info) +void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool send_newgrf_names) { p->Send_uint8 (NETWORK_GAME_INFO_VERSION); @@ -194,6 +195,9 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info) /* Update the documentation in game_info.h on changes * to the NetworkGameInfo wire-protocol! */ + /* NETWORK_GAME_INFO_VERSION = 6 */ + p->Send_uint8(send_newgrf_names ? NST_GRFID_MD5_NAME : NST_GRFID_MD5); + /* NETWORK_GAME_INFO_VERSION = 5 */ GameInfo *game_info = Game::GetInfo(); p->Send_uint32(game_info == nullptr ? -1 : (uint32)game_info->GetVersion()); @@ -216,7 +220,10 @@ 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)) continue; + + SerializeGRFIdentifier(p, &c->ident); + if (send_newgrf_names) p->Send_string(c->GetName()); } } @@ -232,12 +239,10 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info) /* NETWORK_GAME_INFO_VERSION = 1 */ p->Send_string(info->server_name); p->Send_string(info->server_revision); - p->Send_uint8 (0); // Used to be server-lang. p->Send_bool (info->use_password); p->Send_uint8 (info->clients_max); p->Send_uint8 (info->clients_on); p->Send_uint8 (info->spectators_on); - p->Send_string(""); // Used to be map-name. p->Send_uint16(info->map_width); p->Send_uint16(info->map_height); p->Send_uint8 (info->landscape); @@ -254,6 +259,7 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11 byte game_info_version = p->Recv_uint8(); + NewGRFSerializationType newgrf_serialisation = NST_GRFID_MD5; /* * Please observe the order. @@ -264,6 +270,11 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) * to the NetworkGameInfo wire-protocol! */ switch (game_info_version) { + case 6: + newgrf_serialisation = (NewGRFSerializationType)p->Recv_uint8(); + if (newgrf_serialisation >= NST_END) return; + FALLTHROUGH; + case 5: { info->gamescript_version = (int)p->Recv_uint32(); info->gamescript_name = p->Recv_string(NETWORK_NAME_LENGTH); @@ -279,9 +290,23 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) if (num_grfs > NETWORK_MAX_GRF_COUNT) return; for (i = 0; i < num_grfs; i++) { + NamedGRFIdentifier grf; + switch (newgrf_serialisation) { + case NST_GRFID_MD5: + DeserializeGRFIdentifier(p, &grf.ident); + break; + + case NST_GRFID_MD5_NAME: + DeserializeGRFIdentifierWithName(p, &grf); + break; + + default: + NOT_REACHED(); + } + GRFConfig *c = new GRFConfig(); - DeserializeGRFIdentifier(p, &c->ident); - HandleIncomingNetworkGameInfoGRFConfig(c); + c->ident = grf.ident; + HandleIncomingNetworkGameInfoGRFConfig(c, grf.name); /* Append GRFConfig to the list */ *dst = c; @@ -304,7 +329,7 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) case 1: info->server_name = p->Recv_string(NETWORK_NAME_LENGTH); info->server_revision = p->Recv_string(NETWORK_REVISION_LENGTH); - p->Recv_uint8 (); // Used to contain server-lang. + if (game_info_version < 6) p->Recv_uint8 (); // Used to contain server-lang. info->use_password = p->Recv_bool (); info->clients_max = p->Recv_uint8 (); info->clients_on = p->Recv_uint8 (); @@ -313,7 +338,7 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) info->game_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR; info->start_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR; } - while (p->Recv_uint8() != 0) {} // Used to contain the map-name. + if (game_info_version < 6) while (p->Recv_uint8() != 0) {} // Used to contain the map-name. info->map_width = p->Recv_uint16(); info->map_height = p->Recv_uint16(); info->landscape = p->Recv_uint8 (); @@ -350,3 +375,14 @@ void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf) grf->md5sum[j] = p->Recv_uint8(); } } + +/** + * Deserializes the NamedGRFIdentifier (GRF ID, MD5 checksum and name) from the packet + * @param p the packet to read the data from. + * @param grf the NamedGRFIdentifier to deserialize. + */ +void DeserializeGRFIdentifierWithName(Packet *p, NamedGRFIdentifier *grf) +{ + DeserializeGRFIdentifier(p, &grf->ident); + grf->name = p->Recv_string(NETWORK_GRF_NAME_LENGTH); +} diff --git a/src/network/core/game_info.h b/src/network/core/game_info.h index a1719acd7..1d17b6f41 100644 --- a/src/network/core/game_info.h +++ b/src/network/core/game_info.h @@ -25,14 +25,27 @@ * Version: Bytes: Description: * all 1 the version of this packet's structure * + * 6+ 1 type of storage for the NewGRFs below: + * 0 = NewGRF ID and MD5 checksum. + * Used as default for version 5 and below, and for + * later game updates to the Game Coordinator. + * 1 = NewGRF ID, MD5 checksum and name. + * Used for direct requests and the first game + * update to Game Coordinator. + * * 5+ 4 version number of the Game Script (-1 is case none is selected). * 5+ var string with the name of the Game Script. * - * 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 - * of the GRF + * 4+ 1 number of GRFs attached (n). + * 4+ n * var identifiers for GRF files. Consists of: + * Note: the 'vN' refers to packet version and 'type' + * refers to the v6+ type of storage for the NewGRFs. + * - 4 byte variable with the GRF ID. + * For v4, v5, and v6+ in case of type 0 and/or type 1. + * - 16 bytes with the MD5 checksum of the GRF. + * For v4, v5, and v6+ in case of type 0 and/or type 1. + * - string with name of NewGRF. + * For v6+ in case of type 1. * * 3+ 4 current game date in days since 1-1-0 (DMY) * 3+ 4 game introduction date in days since 1-1-0 (DMY) @@ -43,7 +56,7 @@ * * 1+ var string with the name of the server * 1+ var string with the revision of the server - * 1+ 1 the language run on the server + * 1 - 5 1 the language run on the server * (0 = any, 1 = English, 2 = German, 3 = French) * 1+ 1 whether the server uses a password (0 = no, 1 = yes) * 1+ 1 maximum number of clients allowed on the server @@ -51,7 +64,7 @@ * 1+ 1 number of spectators on the server * 1 & 2 2 current game date in days since 1-1-1920 (DMY) * 1 & 2 2 game introduction date in days since 1-1-1920 (DMY) - * 1+ var string with the name of the map + * 1 - 5 var string with the name of the map * 1+ 2 width of the map in tiles * 1+ 2 height of the map in tiles * 1+ 1 type of map: @@ -59,6 +72,13 @@ * 1+ 1 whether the server is dedicated (0 = no, 1 = yes) */ +/** The different types/ways a NewGRF can be serialized in the GameInfo since version 6. */ +enum NewGRFSerializationType { + NST_GRFID_MD5 = 0, ///< Unique GRF ID and MD5 checksum. + NST_GRFID_MD5_NAME = 1, ///< Unique GRF ID, MD5 checksum and name. + NST_END ///< The end of the list (period). +}; + /** * The game information that is sent from the server to the client. */ @@ -92,6 +112,15 @@ struct NetworkGameInfo : NetworkServerGameInfo { bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match }; +/** + * Container to hold the GRF identifier (GRF ID + MD5 checksum) and the name + * associated with that NewGRF. + */ +struct NamedGRFIdentifier { + GRFIdentifier ident; ///< The unique identifier of the NewGRF. + std::string name; ///< The name of the NewGRF. +}; + extern NetworkServerGameInfo _network_game_info; std::string_view GetNetworkRevisionString(); @@ -102,9 +131,10 @@ void FillStaticNetworkServerGameInfo(); const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo(); void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf); +void DeserializeGRFIdentifierWithName(Packet *p, NamedGRFIdentifier *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, bool send_newgrf_names = true); #endif /* NETWORK_CORE_GAME_INFO_H */ diff --git a/src/network/network_coordinator.cpp b/src/network/network_coordinator.cpp index bf8e06261..ab0f21050 100644 --- a/src/network/network_coordinator.cpp +++ b/src/network/network_coordinator.cpp @@ -410,13 +410,14 @@ void ClientNetworkCoordinatorSocketHandler::Register() void ClientNetworkCoordinatorSocketHandler::SendServerUpdate() { 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_SERVER_UPDATE, TCP_MTU); p->Send_uint8(NETWORK_COORDINATOR_VERSION); - SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo()); + SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo(), this->next_update.time_since_epoch() != std::chrono::nanoseconds::zero()); this->SendPacket(p); + + this->next_update = std::chrono::steady_clock::now() + NETWORK_COORDINATOR_DELAY_BETWEEN_UPDATES; } /** -- cgit v1.2.3-70-g09d2