From cb2ef1ea4b74c3d73ba86d978c001784d398bf27 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Mon, 26 Apr 2021 15:18:10 +0200 Subject: Codechange: move all NetworkGameInfo related functions to a single file It currently was a bit scattered over the place. Part of NetworkGameInfo is also the GRF Identifiers that goes with it. --- src/network/core/CMakeLists.txt | 3 +- src/network/core/core.cpp | 28 ---- src/network/core/core.h | 2 - src/network/core/game.h | 55 ------- src/network/core/game_info.cpp | 323 ++++++++++++++++++++++++++++++++++++++++ src/network/core/game_info.h | 105 +++++++++++++ src/network/core/tcp_http.cpp | 1 + src/network/core/udp.cpp | 137 +---------------- src/network/core/udp.h | 48 +----- src/network/network.cpp | 81 +--------- src/network/network_admin.cpp | 1 + src/network/network_base.h | 1 + src/network/network_client.cpp | 3 +- src/network/network_func.h | 2 +- src/network/network_gamelist.h | 1 + src/network/network_gui.h | 1 + src/network/network_internal.h | 2 - src/network/network_server.cpp | 3 +- src/network/network_type.h | 2 +- src/network/network_udp.cpp | 54 +------ 20 files changed, 455 insertions(+), 398 deletions(-) delete mode 100644 src/network/core/game.h create mode 100644 src/network/core/game_info.cpp create mode 100644 src/network/core/game_info.h (limited to 'src/network') diff --git a/src/network/core/CMakeLists.txt b/src/network/core/CMakeLists.txt index c9368a5b4..37cc3e195 100644 --- a/src/network/core/CMakeLists.txt +++ b/src/network/core/CMakeLists.txt @@ -4,7 +4,8 @@ add_files( config.h core.cpp core.h - game.h + game_info.cpp + game_info.h host.cpp host.h os_abstraction.h diff --git a/src/network/core/core.cpp b/src/network/core/core.cpp index 8c5c5c229..5c12cb224 100644 --- a/src/network/core/core.cpp +++ b/src/network/core/core.cpp @@ -65,31 +65,3 @@ const char *NetworkGetErrorString(int error) return buffer; } #endif /* defined(_WIN32) */ - -/** - * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet - * @param p the packet to write the data to - * @param grf the GRFIdentifier to serialize - */ -void NetworkSocketHandler::SendGRFIdentifier(Packet *p, const GRFIdentifier *grf) -{ - uint j; - p->Send_uint32(grf->grfid); - for (j = 0; j < sizeof(grf->md5sum); j++) { - p->Send_uint8 (grf->md5sum[j]); - } -} - -/** - * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet - * @param p the packet to read the data from - * @param grf the GRFIdentifier to deserialize - */ -void NetworkSocketHandler::ReceiveGRFIdentifier(Packet *p, GRFIdentifier *grf) -{ - uint j; - grf->grfid = p->Recv_uint32(); - for (j = 0; j < sizeof(grf->md5sum); j++) { - grf->md5sum[j] = p->Recv_uint8(); - } -} diff --git a/src/network/core/core.h b/src/network/core/core.h index bf83adc72..aac36080f 100644 --- a/src/network/core/core.h +++ b/src/network/core/core.h @@ -71,8 +71,6 @@ public: */ void Reopen() { this->has_quit = false; } - void SendGRFIdentifier(Packet *p, const GRFIdentifier *grf); - void ReceiveGRFIdentifier(Packet *p, GRFIdentifier *grf); void SendCompanyInformation(Packet *p, const struct Company *c, const struct NetworkCompanyStats *stats, uint max_len = NETWORK_COMPANY_NAME_LENGTH); }; diff --git a/src/network/core/game.h b/src/network/core/game.h deleted file mode 100644 index 29eca418f..000000000 --- a/src/network/core/game.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** - * @file game.h Information about a game that is sent between a - * game server, game client and masterserver. - */ - -#ifndef NETWORK_CORE_GAME_H -#define NETWORK_CORE_GAME_H - -#include "config.h" -#include "../../newgrf_config.h" -#include "../../date_type.h" - -/** - * The game information that is not generated on-the-fly and has to - * be sent to the clients. - */ -struct NetworkServerGameInfo { - byte clients_on; ///< Current count of clients on server -}; - -/** - * The game information that is sent from the server to the clients. - */ -struct NetworkGameInfo : NetworkServerGameInfo { - GRFConfig *grfconfig; ///< List of NewGRF files used - Date start_date; ///< When the game started - Date game_date; ///< Current date - uint16 map_width; ///< Map width - uint16 map_height; ///< Map height - char server_name[NETWORK_NAME_LENGTH]; ///< Server name - char hostname[NETWORK_HOSTNAME_LENGTH]; ///< Hostname of the server (if any) - char server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) - bool dedicated; ///< Is this a dedicated server? - bool version_compatible; ///< Can we connect to this server or not? (based on server_revision) - bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match - bool use_password; ///< Is this server passworded? - byte game_info_version; ///< Version of the game info - byte clients_max; ///< Max clients allowed on server - byte companies_on; ///< How many started companies do we have - byte companies_max; ///< Max companies allowed on server - byte spectators_on; ///< How many spectators do we have? - byte spectators_max; ///< Max spectators allowed on server - byte map_set; ///< Graphical set -}; - -const char * GetNetworkRevisionString(); - -#endif /* NETWORK_CORE_GAME_H */ diff --git a/src/network/core/game_info.cpp b/src/network/core/game_info.cpp new file mode 100644 index 000000000..bea687af8 --- /dev/null +++ b/src/network/core/game_info.cpp @@ -0,0 +1,323 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file game_info.cpp Functions to convert NetworkGameInfo to Packet and back. + */ + +#include "../../stdafx.h" +#include "game_info.h" +#include "../../core/bitmath_func.hpp" +#include "../../company_base.h" +#include "../../date_func.h" +#include "../../debug.h" +#include "../../map_func.h" +#include "../../settings_type.h" +#include "../../string_func.h" +#include "../../rev.h" +#include "../network_func.h" +#include "../network.h" +#include "packet.h" + +#include "../../safeguards.h" + + +/** + * How many hex digits of the git hash to include in network revision string. + * Determined as 10 hex digits + 2 characters for -g/-u/-m prefix. + */ +static const uint GITHASH_SUFFIX_LEN = 12; + +NetworkServerGameInfo _network_game_info; ///< Information about our game. + +/** + * Get the network version string used by this build. + * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes. + */ +const char *GetNetworkRevisionString() +{ + /* This will be allocated on heap and never free'd, but only once so not a "real" leak. */ + static char *network_revision = nullptr; + + if (!network_revision) { + /* Start by taking a chance on the full revision string. */ + network_revision = stredup(_openttd_revision); + /* Ensure it's not longer than the packet buffer length. */ + if (strlen(network_revision) >= NETWORK_REVISION_LENGTH) network_revision[NETWORK_REVISION_LENGTH - 1] = '\0'; + + /* Tag names are not mangled further. */ + if (_openttd_revision_tagged) { + DEBUG(net, 1, "Network revision name is '%s'", network_revision); + return network_revision; + } + + /* Prepare a prefix of the git hash. + * Size is length + 1 for terminator, +2 for -g prefix. */ + assert(_openttd_revision_modified < 3); + char githash_suffix[GITHASH_SUFFIX_LEN + 1] = "-"; + githash_suffix[1] = "gum"[_openttd_revision_modified]; + for (uint i = 2; i < GITHASH_SUFFIX_LEN; i++) { + githash_suffix[i] = _openttd_revision_hash[i-2]; + } + + /* Where did the hash start in the original string? + * Overwrite from that position, unless that would go past end of packet buffer length. */ + ptrdiff_t hashofs = strrchr(_openttd_revision, '-') - _openttd_revision; + if (hashofs + strlen(githash_suffix) + 1 > NETWORK_REVISION_LENGTH) hashofs = strlen(network_revision) - strlen(githash_suffix); + /* Replace the git hash in revision string. */ + strecpy(network_revision + hashofs, githash_suffix, network_revision + NETWORK_REVISION_LENGTH); + assert(strlen(network_revision) < NETWORK_REVISION_LENGTH); // strlen does not include terminator, constant does, hence strictly less than + DEBUG(net, 1, "Network revision name is '%s'", network_revision); + } + + return network_revision; +} + +/** + * Extract the git hash from the revision string. + * @param revstr The revision string (formatted as DATE-BRANCH-GITHASH). + * @return The git has part of the revision. + */ +static const char *ExtractNetworkRevisionHash(const char *revstr) +{ + return strrchr(revstr, '-'); +} + +/** + * Checks whether the given version string is compatible with our version. + * First tries to match the full string, if that fails, attempts to compare just git hashes. + * @param other the version string to compare to + */ +bool IsNetworkCompatibleVersion(const char *other) +{ + if (strncmp(GetNetworkRevisionString(), other, NETWORK_REVISION_LENGTH - 1) == 0) return true; + + /* If this version is tagged, then the revision string must be a complete match, + * since there is no git hash suffix in it. + * This is needed to avoid situations like "1.9.0-beta1" comparing equal to "2.0.0-beta1". */ + if (_openttd_revision_tagged) return false; + + const char *hash1 = ExtractNetworkRevisionHash(GetNetworkRevisionString()); + const char *hash2 = ExtractNetworkRevisionHash(other); + return hash1 && hash2 && (strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0); +} + +/** + * Fill a NetworkGameInfo structure with the latest information of the server. + * @param ngi the NetworkGameInfo struct to fill with data. + */ +void FillNetworkGameInfo(NetworkGameInfo &ngi) +{ + /* Update some game_info */ + ngi.clients_on = _network_game_info.clients_on; + ngi.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); + + ngi.use_password = !StrEmpty(_settings_client.network.server_password); + ngi.clients_max = _settings_client.network.max_clients; + ngi.companies_on = (byte)Company::GetNumItems(); + ngi.companies_max = _settings_client.network.max_companies; + ngi.spectators_on = NetworkSpectatorCount(); + ngi.spectators_max = _settings_client.network.max_spectators; + ngi.game_date = _date; + ngi.map_width = MapSizeX(); + ngi.map_height = MapSizeY(); + ngi.map_set = _settings_game.game_creation.landscape; + ngi.dedicated = _network_dedicated; + ngi.grfconfig = _grfconfig; + + strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name)); + strecpy(ngi.server_revision, GetNetworkRevisionString(), lastof(ngi.server_revision)); +} + +/** + * Function that is called for every GRFConfig that is read when receiving + * 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. + */ +static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) +{ + /* 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 */ + config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true); + config->status = GCS_NOT_FOUND; + } else { + config->filename = f->filename; + config->name = f->name; + config->info = f->info; + config->url = f->url; + } + SetBit(config->flags, GCF_COPY); +} + +/** + * Serializes the NetworkGameInfo struct to the packet. + * @param p the packet to write the data to. + * @param info the NetworkGameInfo struct to serialize from. + */ +void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info) +{ + p->Send_uint8 (NETWORK_GAME_INFO_VERSION); + + /* + * Please observe the order. + * The parts must be read in the same order as they are sent! + */ + + /* Update the documentation in game_info.h on changes + * to the NetworkGameInfo wire-protocol! */ + + /* NETWORK_GAME_INFO_VERSION = 4 */ + { + /* 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 + * to the fact that they are in [newgrf-static] in openttd.cfg */ + const GRFConfig *c; + uint count = 0; + + /* Count number of GRFs to send information about */ + for (c = info->grfconfig; c != nullptr; c = c->next) { + if (!HasBit(c->flags, GCF_STATIC)) count++; + } + p->Send_uint8 (count); // Send number of GRFs + + /* Send actual GRF Identifications */ + for (c = info->grfconfig; c != nullptr; c = c->next) { + if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(p, &c->ident); + } + } + + /* NETWORK_GAME_INFO_VERSION = 3 */ + p->Send_uint32(info->game_date); + p->Send_uint32(info->start_date); + + /* NETWORK_GAME_INFO_VERSION = 2 */ + p->Send_uint8 (info->companies_max); + p->Send_uint8 (info->companies_on); + p->Send_uint8 (info->spectators_max); + + /* 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->map_set); + p->Send_bool (info->dedicated); +} + +/** + * Deserializes the NetworkGameInfo struct from the packet. + * @param p the packet to read the data from. + * @param info the NetworkGameInfo to deserialize into. + */ +void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) +{ + static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11 + + info->game_info_version = p->Recv_uint8(); + + /* + * Please observe the order. + * The parts must be read in the same order as they are sent! + */ + + /* Update the documentation in game_info.h on changes + * to the NetworkGameInfo wire-protocol! */ + + switch (info->game_info_version) { + 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; + } + FALLTHROUGH; + } + + case 3: + info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); + info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); + FALLTHROUGH; + + case 2: + info->companies_max = p->Recv_uint8 (); + info->companies_on = p->Recv_uint8 (); + info->spectators_max = p->Recv_uint8 (); + FALLTHROUGH; + + case 1: + p->Recv_string(info->server_name, sizeof(info->server_name)); + p->Recv_string(info->server_revision, sizeof(info->server_revision)); + 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 (); + info->spectators_on = p->Recv_uint8 (); + if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier + 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. + info->map_width = p->Recv_uint16(); + info->map_height = p->Recv_uint16(); + info->map_set = p->Recv_uint8 (); + info->dedicated = p->Recv_bool (); + + if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0; + } +} + +/** + * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet + * @param p the packet to write the data to. + * @param grf the GRFIdentifier to serialize. + */ +void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf) +{ + uint j; + p->Send_uint32(grf->grfid); + for (j = 0; j < sizeof(grf->md5sum); j++) { + p->Send_uint8(grf->md5sum[j]); + } +} + +/** + * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet + * @param p the packet to read the data from. + * @param grf the GRFIdentifier to deserialize. + */ +void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf) +{ + uint j; + grf->grfid = p->Recv_uint32(); + for (j = 0; j < sizeof(grf->md5sum); j++) { + grf->md5sum[j] = p->Recv_uint8(); + } +} diff --git a/src/network/core/game_info.h b/src/network/core/game_info.h new file mode 100644 index 000000000..776700511 --- /dev/null +++ b/src/network/core/game_info.h @@ -0,0 +1,105 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file game_info.h Convert NetworkGameInfo to Packet and back. + */ + +#ifndef NETWORK_CORE_GAME_INFO_H +#define NETWORK_CORE_GAME_INFO_H + +#include "config.h" +#include "core.h" +#include "../../newgrf_config.h" +#include "../../date_type.h" + +/* + * NetworkGameInfo has several revisions which we still need to support on the + * wire. The table below shows the version and size for each field of the + * serialized NetworkGameInfo. + * + * Version: Bytes: Description: + * all 1 the version of this packet's structure + * + * 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 + * + * 3+ 4 current game date in days since 1-1-0 (DMY) + * 3+ 4 game introduction date in days since 1-1-0 (DMY) + * + * 2+ 1 maximum number of companies allowed on the server + * 2+ 1 number of companies on the server + * 2+ 1 maximum number of spectators allowed on the server + * + * 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 + * (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 + * 1+ 1 number of clients on the server + * 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+ 2 width of the map in tiles + * 1+ 2 height of the map in tiles + * 1+ 1 type of map: + * (0 = temperate, 1 = arctic, 2 = desert, 3 = toyland) + * 1+ 1 whether the server is dedicated (0 = no, 1 = yes) + */ + +/** + * The game information that is not generated on-the-fly and has to + * be sent to the clients. + */ +struct NetworkServerGameInfo { + byte clients_on; ///< Current count of clients on server +}; + +/** + * The game information that is sent from the server to the clients. + */ +struct NetworkGameInfo : NetworkServerGameInfo { + GRFConfig *grfconfig; ///< List of NewGRF files used + Date start_date; ///< When the game started + Date game_date; ///< Current date + uint16 map_width; ///< Map width + uint16 map_height; ///< Map height + char server_name[NETWORK_NAME_LENGTH]; ///< Server name + char hostname[NETWORK_HOSTNAME_LENGTH]; ///< Hostname of the server (if any) + char server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) + bool dedicated; ///< Is this a dedicated server? + bool version_compatible; ///< Can we connect to this server or not? (based on server_revision) + bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match + bool use_password; ///< Is this server passworded? + byte game_info_version; ///< Version of the game info + byte clients_max; ///< Max clients allowed on server + byte companies_on; ///< How many started companies do we have + byte companies_max; ///< Max companies allowed on server + byte spectators_on; ///< How many spectators do we have? + byte spectators_max; ///< Max spectators allowed on server + byte map_set; ///< Graphical set +}; + +extern NetworkServerGameInfo _network_game_info; + +const char *GetNetworkRevisionString(); +bool IsNetworkCompatibleVersion(const char *other); + +void FillNetworkGameInfo(NetworkGameInfo &ngi); + +void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf); +void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf); + +void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info); +void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info); + +#endif /* NETWORK_CORE_GAME_INFO_H */ diff --git a/src/network/core/tcp_http.cpp b/src/network/core/tcp_http.cpp index d57f4eceb..ee74c4507 100644 --- a/src/network/core/tcp_http.cpp +++ b/src/network/core/tcp_http.cpp @@ -13,6 +13,7 @@ #include "../../debug.h" #include "../../rev.h" #include "../network_func.h" +#include "game_info.h" #include "tcp_http.h" diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp index df5140e2b..ffc86d825 100644 --- a/src/network/core/udp.cpp +++ b/src/network/core/udp.cpp @@ -12,6 +12,7 @@ #include "../../stdafx.h" #include "../../date_func.h" #include "../../debug.h" +#include "game_info.h" #include "udp.h" #include "../../safeguards.h" @@ -150,142 +151,6 @@ void NetworkUDPSocketHandler::ReceivePackets() } } - -/** - * Serializes the NetworkGameInfo struct to the packet - * @param p the packet to write the data to - * @param info the NetworkGameInfo struct to serialize - */ -void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info) -{ - p->Send_uint8 (NETWORK_GAME_INFO_VERSION); - - /* - * Please observe the order. - * The parts must be read in the same order as they are sent! - */ - - /* Update the documentation in udp.h on changes - * to the NetworkGameInfo wire-protocol! */ - - /* NETWORK_GAME_INFO_VERSION = 4 */ - { - /* 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 - * to the fact that they are in [newgrf-static] in openttd.cfg */ - const GRFConfig *c; - uint count = 0; - - /* Count number of GRFs to send information about */ - for (c = info->grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC)) count++; - } - p->Send_uint8 (count); // Send number of GRFs - - /* Send actual GRF Identifications */ - for (c = info->grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident); - } - } - - /* NETWORK_GAME_INFO_VERSION = 3 */ - p->Send_uint32(info->game_date); - p->Send_uint32(info->start_date); - - /* NETWORK_GAME_INFO_VERSION = 2 */ - p->Send_uint8 (info->companies_max); - p->Send_uint8 (info->companies_on); - p->Send_uint8 (info->spectators_max); - - /* 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->map_set); - p->Send_bool (info->dedicated); -} - -/** - * Deserializes the NetworkGameInfo struct from the packet - * @param p the packet to read the data from - * @param info the NetworkGameInfo to deserialize into - */ -void NetworkUDPSocketHandler::ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info) -{ - static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11 - - info->game_info_version = p->Recv_uint8(); - - /* - * Please observe the order. - * The parts must be read in the same order as they are sent! - */ - - /* Update the documentation in udp.h on changes - * to the NetworkGameInfo wire-protocol! */ - - switch (info->game_info_version) { - 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(); - this->ReceiveGRFIdentifier(p, &c->ident); - this->HandleIncomingNetworkGameInfoGRFConfig(c); - - /* Append GRFConfig to the list */ - *dst = c; - dst = &c->next; - } - FALLTHROUGH; - } - - case 3: - info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); - info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); - FALLTHROUGH; - - case 2: - info->companies_max = p->Recv_uint8 (); - info->companies_on = p->Recv_uint8 (); - info->spectators_max = p->Recv_uint8 (); - FALLTHROUGH; - - case 1: - p->Recv_string(info->server_name, sizeof(info->server_name)); - p->Recv_string(info->server_revision, sizeof(info->server_revision)); - 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 (); - info->spectators_on = p->Recv_uint8 (); - if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier - 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. - info->map_width = p->Recv_uint16(); - info->map_height = p->Recv_uint16(); - info->map_set = p->Recv_uint8 (); - info->dedicated = p->Recv_bool (); - - if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0; - } -} - /** * Handle an incoming packets by sending it to the correct function. * @param p the received packet diff --git a/src/network/core/udp.h b/src/network/core/udp.h index ddbbd4515..881fb0a61 100644 --- a/src/network/core/udp.h +++ b/src/network/core/udp.h @@ -13,7 +13,6 @@ #define NETWORK_CORE_UDP_H #include "address.h" -#include "game.h" #include "packet.h" /** Enum with all types of UDP packets. The order MUST not be changed **/ @@ -63,40 +62,7 @@ protected: /** * Return of server information to the client. - * This packet has several legacy versions, so we list the version and size of each "field": - * - * Version: Bytes: Description: - * all 1 the version of this packet's structure - * - * 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 - * - * 3+ 4 current game date in days since 1-1-0 (DMY) - * 3+ 4 game introduction date in days since 1-1-0 (DMY) - * - * 2+ 1 maximum number of companies allowed on the server - * 2+ 1 number of companies on the server - * 2+ 1 maximum number of spectators allowed on the server - * - * 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 - * (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 - * 1+ 1 number of clients on the server - * 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+ 2 width of the map in tiles - * 1+ 2 height of the map in tiles - * 1+ 1 type of map: - * (0 = temperate, 1 = arctic, 2 = desert, 3 = toyland) - * 1+ 1 whether the server is dedicated (0 = no, 1 = yes) + * Serialized NetworkGameInfo. See game_info.h for details. * @param p The received packet. * @param client_addr The origin of the packet. */ @@ -217,15 +183,6 @@ protected: virtual void Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr); void HandleUDPPacket(Packet *p, NetworkAddress *client_addr); - - /** - * Function that is called for every GRFConfig that is read when receiving - * 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 - */ - virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) { NOT_REACHED(); } public: NetworkUDPSocketHandler(NetworkAddressList *bind = nullptr); @@ -237,9 +194,6 @@ public: void SendPacket(Packet *p, NetworkAddress *recv, bool all = false, bool broadcast = false); void ReceivePackets(); - - void SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info); - void ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info); }; #endif /* NETWORK_CORE_UDP_H */ diff --git a/src/network/network.cpp b/src/network/network.cpp index 812456b4e..9a45ce06e 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -54,7 +54,6 @@ bool _network_server; ///< network-server is active bool _network_available; ///< is network mode available? bool _network_dedicated; ///< are we a dedicated server? bool _is_network_server; ///< Does this client wants to be a network-server? -NetworkServerGameInfo _network_game_info; ///< Information about our game. NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies. ClientID _network_own_client_id; ///< Our client identifier. ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client. @@ -603,9 +602,10 @@ public: } }; -/* Query a server to fetch his game-info - * If game_info is true, only the gameinfo is fetched, - * else only the client_info is fetched */ +/** + * Query a server to fetch his game-info. + * @param address the address to query. + */ void NetworkTCPQueryServer(NetworkAddress address) { if (!_network_available) return; @@ -1110,79 +1110,6 @@ void NetworkShutDown() NetworkCoreShutdown(); } -/** - * How many hex digits of the git hash to include in network revision string. - * Determined as 10 hex digits + 2 characters for -g/-u/-m prefix. - */ -static const uint GITHASH_SUFFIX_LEN = 12; - -/** - * Get the network version string used by this build. - * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes. - */ -const char * GetNetworkRevisionString() -{ - /* This will be allocated on heap and never free'd, but only once so not a "real" leak. */ - static char *network_revision = nullptr; - - if (!network_revision) { - /* Start by taking a chance on the full revision string. */ - network_revision = stredup(_openttd_revision); - /* Ensure it's not longer than the packet buffer length. */ - if (strlen(network_revision) >= NETWORK_REVISION_LENGTH) network_revision[NETWORK_REVISION_LENGTH - 1] = '\0'; - - /* Tag names are not mangled further. */ - if (_openttd_revision_tagged) { - DEBUG(net, 1, "Network revision name is '%s'", network_revision); - return network_revision; - } - - /* Prepare a prefix of the git hash. - * Size is length + 1 for terminator, +2 for -g prefix. */ - assert(_openttd_revision_modified < 3); - char githash_suffix[GITHASH_SUFFIX_LEN + 1] = "-"; - githash_suffix[1] = "gum"[_openttd_revision_modified]; - for (uint i = 2; i < GITHASH_SUFFIX_LEN; i++) { - githash_suffix[i] = _openttd_revision_hash[i-2]; - } - - /* Where did the hash start in the original string? - * Overwrite from that position, unless that would go past end of packet buffer length. */ - ptrdiff_t hashofs = strrchr(_openttd_revision, '-') - _openttd_revision; - if (hashofs + strlen(githash_suffix) + 1 > NETWORK_REVISION_LENGTH) hashofs = strlen(network_revision) - strlen(githash_suffix); - /* Replace the git hash in revision string. */ - strecpy(network_revision + hashofs, githash_suffix, network_revision + NETWORK_REVISION_LENGTH); - assert(strlen(network_revision) < NETWORK_REVISION_LENGTH); // strlen does not include terminator, constant does, hence strictly less than - DEBUG(net, 1, "Network revision name is '%s'", network_revision); - } - - return network_revision; -} - -static const char *ExtractNetworkRevisionHash(const char *revstr) -{ - return strrchr(revstr, '-'); -} - -/** - * Checks whether the given version string is compatible with our version. - * First tries to match the full string, if that fails, attempts to compare just git hashes. - * @param other the version string to compare to - */ -bool IsNetworkCompatibleVersion(const char *other) -{ - if (strncmp(GetNetworkRevisionString(), other, NETWORK_REVISION_LENGTH - 1) == 0) return true; - - /* If this version is tagged, then the revision string must be a complete match, - * since there is no git hash suffix in it. - * This is needed to avoid situations like "1.9.0-beta1" comparing equal to "2.0.0-beta1". */ - if (_openttd_revision_tagged) return false; - - const char *hash1 = ExtractNetworkRevisionHash(GetNetworkRevisionString()); - const char *hash2 = ExtractNetworkRevisionHash(other); - return hash1 && hash2 && (strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0); -} - #ifdef __EMSCRIPTEN__ extern "C" { diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index 1b86c3e56..7b4975451 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -10,6 +10,7 @@ #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" +#include "core/game_info.h" #include "network_admin.h" #include "network_base.h" #include "network_server.h" diff --git a/src/network/network_base.h b/src/network/network_base.h index 15f410dbc..9ad030062 100644 --- a/src/network/network_base.h +++ b/src/network/network_base.h @@ -14,6 +14,7 @@ #include "core/address.h" #include "../core/pool_type.hpp" #include "../company_type.h" +#include "../date_type.h" /** Type for the pool with client information. */ typedef Pool NetworkClientInfoPool; diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index d5fe64b11..f49692307 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -23,6 +23,7 @@ #include "../gfx_func.h" #include "../error.h" #include "../rev.h" +#include "core/game_info.h" #include "network.h" #include "network_base.h" #include "network_client.h" @@ -730,7 +731,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(P /* Check all GRFs */ for (; grf_count > 0; grf_count--) { GRFIdentifier c; - this->ReceiveGRFIdentifier(p, &c); + DeserializeGRFIdentifier(p, &c); /* Check whether we know this GRF */ const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); diff --git a/src/network/network_func.h b/src/network/network_func.h index 66719b216..a0f163345 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -22,8 +22,8 @@ #include "../gfx_type.h" #include "../openttd.h" #include "../company_type.h" +#include "../string_type.h" -extern NetworkServerGameInfo _network_game_info; extern NetworkCompanyState *_network_company_states; extern ClientID _network_own_client_id; diff --git a/src/network/network_gamelist.h b/src/network/network_gamelist.h index 8e61f3a93..ce35c01d8 100644 --- a/src/network/network_gamelist.h +++ b/src/network/network_gamelist.h @@ -11,6 +11,7 @@ #define NETWORK_GAMELIST_H #include "core/address.h" +#include "core/game_info.h" #include "network_type.h" /** Structure with information shown in the game list (GUI) */ diff --git a/src/network/network_gui.h b/src/network/network_gui.h index 512495562..b8ed68225 100644 --- a/src/network/network_gui.h +++ b/src/network/network_gui.h @@ -11,6 +11,7 @@ #define NETWORK_GUI_H #include "../company_type.h" +#include "../date_type.h" #include "../economy_type.h" #include "../window_type.h" #include "network_type.h" diff --git a/src/network/network_internal.h b/src/network/network_internal.h index 352416320..c64eac795 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -94,8 +94,6 @@ void NetworkAddServer(const char *b); void NetworkRebuildHostList(); void UpdateNetworkGameWindow(); -bool IsNetworkCompatibleVersion(const char *version); - /* From network_command.cpp */ /** * Everything we need to know about a command to be able to execute it. diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 67952bca6..6bc6f8291 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -10,6 +10,7 @@ #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" +#include "core/game_info.h" #include "network_admin.h" #include "network_server.h" #include "network_udp.h" @@ -477,7 +478,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck() p->Send_uint8 (grf_count); for (c = _grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident); + if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(p, &c->ident); } this->SendPacket(p); diff --git a/src/network/network_type.h b/src/network/network_type.h index 4c75346da..4dcdd8c03 100644 --- a/src/network/network_type.h +++ b/src/network/network_type.h @@ -10,7 +10,7 @@ #ifndef NETWORK_TYPE_H #define NETWORK_TYPE_H -#include "core/game.h" +#include "core/config.h" /** How many clients can we have */ static const uint MAX_CLIENTS = 255; diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index f7db689d4..8e661e939 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -16,6 +16,7 @@ #include "../date_func.h" #include "../map_func.h" #include "../debug.h" +#include "core/game_info.h" #include "network_gamelist.h" #include "network_internal.h" #include "network_udp.h" @@ -171,29 +172,10 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, Networ } NetworkGameInfo ngi; - - /* Update some game_info */ - ngi.clients_on = _network_game_info.clients_on; - ngi.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); - - ngi.use_password = !StrEmpty(_settings_client.network.server_password); - ngi.clients_max = _settings_client.network.max_clients; - ngi.companies_on = (byte)Company::GetNumItems(); - ngi.companies_max = _settings_client.network.max_companies; - ngi.spectators_on = NetworkSpectatorCount(); - ngi.spectators_max = _settings_client.network.max_spectators; - ngi.game_date = _date; - ngi.map_width = MapSizeX(); - ngi.map_height = MapSizeY(); - ngi.map_set = _settings_game.game_creation.landscape; - ngi.dedicated = _network_dedicated; - ngi.grfconfig = _grfconfig; - - strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name)); - strecpy(ngi.server_revision, GetNetworkRevisionString(), lastof(ngi.server_revision)); + FillNetworkGameInfo(ngi); Packet packet(PACKET_UDP_SERVER_RESPONSE); - this->SendNetworkGameInfo(&packet, &ngi); + SerializeNetworkGameInfo(&packet, &ngi); /* Let the client know that we are here */ this->SendPacket(&packet, client_addr); @@ -284,7 +266,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ GRFIdentifier c; const GRFConfig *f; - this->ReceiveGRFIdentifier(p, &c); + DeserializeGRFIdentifier(p, &c); /* Find the matching GRF file */ f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); @@ -311,7 +293,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ /* The name could be an empty string, if so take the filename */ strecpy(name, in_reply[i]->GetName(), lastof(name)); - this->SendGRFIdentifier(&packet, &in_reply[i]->ident); + SerializeGRFIdentifier(&packet, &in_reply[i]->ident); packet.Send_string(name); } @@ -326,7 +308,6 @@ protected: void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) override; void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) override; void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) override; - void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) override; public: virtual ~ClientNetworkUDPSocketHandler() {} }; @@ -344,7 +325,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd item = NetworkGameListAddItem(*client_addr); ClearGRFConfigList(&item->info.grfconfig); - this->ReceiveNetworkGameInfo(p, &item->info); + DeserializeNetworkGameInfo(p, &item->info); item->info.compatible = true; { @@ -373,7 +354,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd packet.Send_uint8(in_request_count); for (i = 0; i < in_request_count; i++) { - this->SendGRFIdentifier(&packet, &in_request[i]->ident); + SerializeGRFIdentifier(&packet, &in_request[i]->ident); } this->SendPacket(&packet, &item->address); @@ -447,7 +428,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd char name[NETWORK_GRF_NAME_LENGTH]; GRFIdentifier c; - this->ReceiveGRFIdentifier(p, &c); + DeserializeGRFIdentifier(p, &c); p->Recv_string(name, sizeof(name)); /* An empty name is not possible under normal circumstances @@ -464,25 +445,6 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd } } -void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) -{ - /* 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 */ - config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true); - config->status = GCS_NOT_FOUND; - } else { - config->filename = f->filename; - config->name = f->name; - config->info = f->info; - config->url = f->url; - } - SetBit(config->flags, GCF_COPY); -} - /** Broadcast to all ips */ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket) { -- cgit v1.2.3-54-g00ecf