diff --git a/src/network/core/config.h b/src/network/core/config.h --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -47,7 +47,7 @@ static const uint16 TCP_MTU 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 --- a/src/network/core/game_info.cpp +++ b/src/network/core/game_info.cpp @@ -159,14 +159,15 @@ const NetworkServerGameInfo *GetCurrentN * 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 HandleIncomingNetworkGameInf * @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, /* 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, /* 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, /* 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 * 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 * * 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 * 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 * 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 * 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, 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 --- 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 : NetworkServerGa 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 --- a/src/network/network_coordinator.cpp +++ b/src/network/network_coordinator.cpp @@ -410,13 +410,14 @@ void ClientNetworkCoordinatorSocketHandl 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; } /**