From 386ef4dac3c42a4454fb9cdfdcf7d6acfa9a3d0a Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 17 Jul 2021 23:42:43 +0200 Subject: Feature: [Game Coordinator] Send NewGRF names to the client --- src/network/core/config.h | 2 +- src/network/core/game_info.cpp | 10 +++++++++- src/network/core/game_info.h | 12 +++++++++++- src/network/core/tcp_coordinator.cpp | 2 ++ src/network/core/tcp_coordinator.h | 25 +++++++++++++++++++++++++ src/network/network_coordinator.cpp | 15 ++++++++++++++- src/network/network_coordinator.h | 4 ++++ 7 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/network/core/config.h b/src/network/core/config.h index ccc9cd263..1b66c26cf 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -49,7 +49,7 @@ static const uint16 COMPAT_MTU = 1460; ///< Numbe static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network 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? +static const byte NETWORK_COORDINATOR_VERSION = 4; ///< What version of game-coordinator-protocol do we use? static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0' static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0' diff --git a/src/network/core/game_info.cpp b/src/network/core/game_info.cpp index 138053b05..85d66807b 100644 --- a/src/network/core/game_info.cpp +++ b/src/network/core/game_info.cpp @@ -254,7 +254,7 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool * @param p the packet to read the data from. * @param info the NetworkGameInfo to deserialize into. */ -void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) +void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfoNewGRFLookupTable *newgrf_lookup_table) { static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11 @@ -300,6 +300,14 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) DeserializeGRFIdentifierWithName(p, &grf); break; + case NST_LOOKUP_ID: { + if (newgrf_lookup_table == nullptr) return; + auto it = newgrf_lookup_table->find(p->Recv_uint32()); + if (it == newgrf_lookup_table->end()) return; + grf = it->second; + break; + } + default: NOT_REACHED(); } diff --git a/src/network/core/game_info.h b/src/network/core/game_info.h index 1d17b6f41..91fd96ad9 100644 --- a/src/network/core/game_info.h +++ b/src/network/core/game_info.h @@ -17,6 +17,8 @@ #include "../../newgrf_config.h" #include "../../date_type.h" +#include + /* * 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 @@ -32,6 +34,9 @@ * 1 = NewGRF ID, MD5 checksum and name. * Used for direct requests and the first game * update to Game Coordinator. + * 2 = Index in NewGRF lookup table. + * Used for sending server listing from the Game + * Coordinator to the clients. * * 5+ 4 version number of the Game Script (-1 is case none is selected). * 5+ var string with the name of the Game Script. @@ -46,6 +51,8 @@ * 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. + * - 4 byte lookup table index. + * For v6+ in case of type 2. * * 3+ 4 current game date in days since 1-1-0 (DMY) * 3+ 4 game introduction date in days since 1-1-0 (DMY) @@ -76,6 +83,7 @@ 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_LOOKUP_ID = 2, ///< Unique ID into a lookup table that is sent before. NST_END ///< The end of the list (period). }; @@ -120,6 +128,8 @@ struct NamedGRFIdentifier { GRFIdentifier ident; ///< The unique identifier of the NewGRF. std::string name; ///< The name of the NewGRF. }; +/** Lookup table for the GameInfo in case of #NST_LOOKUP_ID. */ +typedef std::unordered_map GameInfoNewGRFLookupTable; extern NetworkServerGameInfo _network_game_info; @@ -134,7 +144,7 @@ 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 DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfoNewGRFLookupTable *newgrf_lookup_table = nullptr); void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool send_newgrf_names = true); #endif /* NETWORK_CORE_GAME_INFO_H */ diff --git a/src/network/core/tcp_coordinator.cpp b/src/network/core/tcp_coordinator.cpp index abcff9579..75f3f246f 100644 --- a/src/network/core/tcp_coordinator.cpp +++ b/src/network/core/tcp_coordinator.cpp @@ -42,6 +42,7 @@ bool NetworkCoordinatorSocketHandler::HandlePacket(Packet *p) case PACKET_COORDINATOR_GC_STUN_REQUEST: return this->Receive_GC_STUN_REQUEST(p); case PACKET_COORDINATOR_SERCLI_STUN_RESULT: return this->Receive_SERCLI_STUN_RESULT(p); case PACKET_COORDINATOR_GC_STUN_CONNECT: return this->Receive_GC_STUN_CONNECT(p); + case PACKET_COORDINATOR_GC_NEWGRF_LOOKUP: return this->Receive_GC_NEWGRF_LOOKUP(p); default: Debug(net, 0, "[tcp/coordinator] Received invalid packet type {}", type); @@ -100,3 +101,4 @@ bool NetworkCoordinatorSocketHandler::Receive_GC_DIRECT_CONNECT(Packet *p) { ret bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_REQUEST(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_REQUEST); } bool NetworkCoordinatorSocketHandler::Receive_SERCLI_STUN_RESULT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERCLI_STUN_RESULT); } bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_CONNECT); } +bool NetworkCoordinatorSocketHandler::Receive_GC_NEWGRF_LOOKUP(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_NEWGRF_LOOKUP); } diff --git a/src/network/core/tcp_coordinator.h b/src/network/core/tcp_coordinator.h index 40502e7e3..b5395ad73 100644 --- a/src/network/core/tcp_coordinator.h +++ b/src/network/core/tcp_coordinator.h @@ -41,6 +41,7 @@ enum PacketCoordinatorType { PACKET_COORDINATOR_GC_STUN_REQUEST, ///< Game Coordinator tells client/server to initiate a STUN request. PACKET_COORDINATOR_SERCLI_STUN_RESULT, ///< Client/server informs the Game Coordinator of the result of the STUN request. PACKET_COORDINATOR_GC_STUN_CONNECT, ///< Game Coordinator tells client/server to connect() reusing the STUN local address. + PACKET_COORDINATOR_GC_NEWGRF_LOOKUP, ///< Game Coordinator informs client about NewGRF lookup table updates needed for GC_LISTING. PACKET_COORDINATOR_END, ///< Must ALWAYS be on the end of this list!! (period) }; @@ -125,6 +126,7 @@ protected: * uint8 Game Coordinator protocol version. * uint8 Game-info version used by this client. * string Revision of the client. + * uint32 (Game Coordinator protocol >= 4) Cursor as received from GC_NEWGRF_LOOKUP, or zero. * * @param p The packet that was just received. * @return True upon success, otherwise false. @@ -263,6 +265,29 @@ protected: */ virtual bool Receive_GC_STUN_CONNECT(Packet *p); + /** + * Game Coordinator informs the client of updates for the NewGRFs lookup table + * as used by the NewGRF deserialization in GC_LISTING. + * This packet is sent after a CLIENT_LISTING request, but before GC_LISTING. + * + * uint32 Lookup table cursor. + * uint16 Number of NewGRFs in the packet, with for each of the NewGRFs: + * uint32 Lookup table index for the NewGRF. + * uint32 Unique NewGRF ID. + * byte[16] MD5 checksum of the NewGRF + * string Name of the NewGRF. + * + * The lookup table built using these packets are used by the deserialisation + * of the NewGRFs for servers in the GC_LISTING. These updates are additive, + * i.e. each update will add NewGRFs but never remove them. However, this + * lookup table is specific to the connection with the Game Coordinator, and + * should be considered invalid after disconnecting from the Game Coordinator. + * + * @param p The packet that was just received. + * @return True upon success, otherwise false. + */ + virtual bool Receive_GC_NEWGRF_LOOKUP(Packet *p); + bool HandlePacket(Packet *p); public: /** diff --git a/src/network/network_coordinator.cpp b/src/network/network_coordinator.cpp index ab0f21050..21937c7c6 100644 --- a/src/network/network_coordinator.cpp +++ b/src/network/network_coordinator.cpp @@ -231,7 +231,7 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p) /* Read the NetworkGameInfo from the packet. */ NetworkGameInfo ngi = {}; - DeserializeNetworkGameInfo(p, &ngi); + DeserializeNetworkGameInfo(p, &ngi, &this->newgrf_lookup_table); /* Now we know the connection string, we can add it to our list. */ NetworkGameList *item = NetworkGameListAddItem(connection_string); @@ -347,6 +347,18 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_STUN_CONNECT(Packet *p) return true; } +bool ClientNetworkCoordinatorSocketHandler::Receive_GC_NEWGRF_LOOKUP(Packet *p) +{ + this->newgrf_lookup_table_cursor = p->Recv_uint32(); + + uint16 newgrfs = p->Recv_uint16(); + for (; newgrfs> 0; newgrfs--) { + uint32 index = p->Recv_uint32(); + DeserializeGRFIdentifierWithName(p, &this->newgrf_lookup_table[index]); + } + return true; +} + void ClientNetworkCoordinatorSocketHandler::Connect() { /* We are either already connected or are trying to connect. */ @@ -433,6 +445,7 @@ void ClientNetworkCoordinatorSocketHandler::GetListing() p->Send_uint8(NETWORK_COORDINATOR_VERSION); p->Send_uint8(NETWORK_GAME_INFO_VERSION); p->Send_string(_openttd_revision); + p->Send_uint32(this->newgrf_lookup_table_cursor); this->SendPacket(p); } diff --git a/src/network/network_coordinator.h b/src/network/network_coordinator.h index f6859f859..63ced5121 100644 --- a/src/network/network_coordinator.h +++ b/src/network/network_coordinator.h @@ -54,6 +54,9 @@ private: std::map>> stun_handlers; ///< All pending STUN handlers, stored by token:family. TCPConnecter *game_connecter = nullptr; ///< Pending connecter to the game server. + uint32 newgrf_lookup_table_cursor = 0; ///< Last received cursor for the #GameInfoNewGRFLookupTable updates. + GameInfoNewGRFLookupTable newgrf_lookup_table; ///< Table to look up NewGRFs in the GC_LISTING packets. + protected: bool Receive_GC_ERROR(Packet *p) override; bool Receive_GC_REGISTER_ACK(Packet *p) override; @@ -63,6 +66,7 @@ protected: bool Receive_GC_DIRECT_CONNECT(Packet *p) override; bool Receive_GC_STUN_REQUEST(Packet *p) override; bool Receive_GC_STUN_CONNECT(Packet *p) override; + bool Receive_GC_NEWGRF_LOOKUP(Packet *p) override; public: /** The idle timeout; when to close the connection because it's idle. */ -- cgit v1.2.3-54-g00ecf