From aa93d76223f0411b54f5150adbe2c83c33fd61af Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sat, 3 Jul 2021 11:12:28 +0200 Subject: Add: use Game Coordinator to get latest public server listing --- src/network/core/tcp_coordinator.cpp | 4 +++ src/network/core/tcp_coordinator.h | 29 ++++++++++++++++ src/network/network_coordinator.cpp | 66 +++++++++++++++++++++++++++++++++++- src/network/network_coordinator.h | 10 ++++++ src/network/network_gui.cpp | 40 +++++++++++++++------- 5 files changed, 136 insertions(+), 13 deletions(-) diff --git a/src/network/core/tcp_coordinator.cpp b/src/network/core/tcp_coordinator.cpp index 1cf5cd676..bbcb59b14 100644 --- a/src/network/core/tcp_coordinator.cpp +++ b/src/network/core/tcp_coordinator.cpp @@ -31,6 +31,8 @@ bool NetworkCoordinatorSocketHandler::HandlePacket(Packet *p) case PACKET_COORDINATOR_SERVER_REGISTER: return this->Receive_SERVER_REGISTER(p); case PACKET_COORDINATOR_GC_REGISTER_ACK: return this->Receive_GC_REGISTER_ACK(p); case PACKET_COORDINATOR_SERVER_UPDATE: return this->Receive_SERVER_UPDATE(p); + case PACKET_COORDINATOR_CLIENT_LISTING: return this->Receive_CLIENT_LISTING(p); + case PACKET_COORDINATOR_GC_LISTING: return this->Receive_GC_LISTING(p); default: Debug(net, 0, "[tcp/coordinator] Received invalid packet type {}", type); @@ -78,3 +80,5 @@ bool NetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p) { return this- bool NetworkCoordinatorSocketHandler::Receive_SERVER_REGISTER(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_REGISTER); } bool NetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_REGISTER_ACK); } bool NetworkCoordinatorSocketHandler::Receive_SERVER_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_UPDATE); } +bool NetworkCoordinatorSocketHandler::Receive_CLIENT_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_LISTING); } +bool NetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_LISTING); } diff --git a/src/network/core/tcp_coordinator.h b/src/network/core/tcp_coordinator.h index a438f07aa..e95916816 100644 --- a/src/network/core/tcp_coordinator.h +++ b/src/network/core/tcp_coordinator.h @@ -29,6 +29,8 @@ enum PacketCoordinatorType { PACKET_COORDINATOR_SERVER_REGISTER, ///< Server registration. PACKET_COORDINATOR_GC_REGISTER_ACK, ///< Game Coordinator accepts the registration. PACKET_COORDINATOR_SERVER_UPDATE, ///< Server sends an set intervals an update of the server. + PACKET_COORDINATOR_CLIENT_LISTING, ///< Client is requesting a listing of all public servers. + PACKET_COORDINATOR_GC_LISTING, ///< Game Coordinator returns a listing of all public servers. PACKET_COORDINATOR_END, ///< Must ALWAYS be on the end of this list!! (period). }; @@ -101,6 +103,33 @@ protected: */ virtual bool Receive_SERVER_UPDATE(Packet *p); + /** + * Client requests a list of all public servers. + * + * uint8 Game Coordinator protocol version. + * uint8 Game-info version used by this client. + * string Revision of the client. + * + * @param p The packet that was just received. + * @return True upon success, otherwise false. + */ + virtual bool Receive_CLIENT_LISTING(Packet *p); + + /** + * Game Coordinator replies with a list of all public servers. Multiple + * of these packets are received after a request till all servers are + * sent over. Last packet will have server count of 0. + * + * uint16 Amount of public servers in this packet. + * For each server: + * string Connection string for this server. + * Serialized NetworkGameInfo. See game_info.hpp for details. + * + * @param p The packet that was just received. + * @return True upon success, otherwise false. + */ + virtual bool Receive_GC_LISTING(Packet *p); + bool HandlePacket(Packet *p); public: /** diff --git a/src/network/network_coordinator.cpp b/src/network/network_coordinator.cpp index 3e4079740..b9299d549 100644 --- a/src/network/network_coordinator.cpp +++ b/src/network/network_coordinator.cpp @@ -19,6 +19,7 @@ #include "network.h" #include "network_coordinator.h" #include "network_gamelist.h" +#include "network_internal.h" #include "table/strings.h" #include "../safeguards.h" @@ -47,6 +48,7 @@ public: assert(_network_coordinator_client.sock == INVALID_SOCKET); _network_coordinator_client.sock = s; + _network_coordinator_client.last_activity = std::chrono::steady_clock::now(); _network_coordinator_client.connecting = false; } }; @@ -111,6 +113,42 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p) return true; } +bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p) +{ + uint8 servers = p->Recv_uint16(); + + /* End of list; we can now remove all expired items from the list. */ + if (servers == 0) { + NetworkGameListRemoveExpired(); + return true; + } + + for (; servers > 0; servers--) { + std::string connection_string = p->Recv_string(NETWORK_HOSTNAME_PORT_LENGTH); + + /* Read the NetworkGameInfo from the packet. */ + NetworkGameInfo ngi = {}; + DeserializeNetworkGameInfo(p, &ngi); + + /* Now we know the join-key, we can add it to our list. */ + NetworkGameList *item = NetworkGameListAddItem(connection_string); + + /* Clear any existing GRFConfig chain. */ + ClearGRFConfigList(&item->info.grfconfig); + /* Copy the new NetworkGameInfo info. */ + item->info = ngi; + /* Check for compatability with the client. */ + CheckGameCompatibility(item->info); + /* Mark server as online. */ + item->online = true; + /* Mark the item as up-to-date. */ + item->version = _network_game_list_version; + } + + UpdateNetworkGameWindow(); + return true; +} + void ClientNetworkCoordinatorSocketHandler::Connect() { /* We are either already connected or are trying to connect. */ @@ -119,6 +157,8 @@ void ClientNetworkCoordinatorSocketHandler::Connect() this->Reopen(); this->connecting = true; + this->last_activity = std::chrono::steady_clock::now(); + new NetworkCoordinatorConnecter(NETWORK_COORDINATOR_SERVER_HOST); } @@ -172,6 +212,23 @@ void ClientNetworkCoordinatorSocketHandler::SendServerUpdate() this->SendPacket(p); } +/** + * Request a listing of all public servers. + */ +void ClientNetworkCoordinatorSocketHandler::GetListing() +{ + this->Connect(); + + _network_game_list_version++; + + Packet *p = new Packet(PACKET_COORDINATOR_CLIENT_LISTING); + p->Send_uint8(NETWORK_COORDINATOR_VERSION); + p->Send_uint8(NETWORK_GAME_INFO_VERSION); + p->Send_string(_openttd_revision); + + this->SendPacket(p); +} + /** * Check whether we received/can send some data from/to the Game Coordinator server and * when that's the case handle it appropriately. @@ -226,8 +283,15 @@ void ClientNetworkCoordinatorSocketHandler::SendReceive() this->SendServerUpdate(); } + if (!_network_server && std::chrono::steady_clock::now() > this->last_activity + IDLE_TIMEOUT) { + this->CloseConnection(); + return; + } + if (this->CanSendReceive()) { - this->ReceivePackets(); + if (this->ReceivePackets()) { + this->last_activity = std::chrono::steady_clock::now(); + } } this->SendPackets(); diff --git a/src/network/network_coordinator.h b/src/network/network_coordinator.h index 1dbce063b..7399ce1fc 100644 --- a/src/network/network_coordinator.h +++ b/src/network/network_coordinator.h @@ -21,6 +21,10 @@ * - Game Coordinator probes server to check if it can directly connect. * - Game Coordinator sends GC_REGISTER_ACK with type of connection. * - Server sends every 30 seconds SERVER_UPDATE. + * + * For clients (listing): + * - Client sends CLIENT_LISTING. + * - Game Coordinator returns the full list of public servers via GC_LISTING (multiple packets). */ /** Class for handling the client side of the Game Coordinator connection. */ @@ -31,8 +35,13 @@ private: protected: bool Receive_GC_ERROR(Packet *p) override; bool Receive_GC_REGISTER_ACK(Packet *p) override; + bool Receive_GC_LISTING(Packet *p) override; public: + /** The idle timeout; when to close the connection because it's idle. */ + static constexpr std::chrono::seconds IDLE_TIMEOUT = std::chrono::seconds(60); + + std::chrono::steady_clock::time_point last_activity; ///< The last time there was network activity. bool connecting; ///< Are we connecting to the Game Coordinator? ClientNetworkCoordinatorSocketHandler() : connecting(false) {} @@ -44,6 +53,7 @@ public: void Register(); void SendServerUpdate(); + void GetListing(); }; extern ClientNetworkCoordinatorSocketHandler _network_coordinator_client; diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 6f48bf022..24884ed16 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -18,6 +18,7 @@ #include "network_base.h" #include "network_content.h" #include "network_server.h" +#include "network_coordinator.h" #include "../gui.h" #include "network_udp.h" #include "../window_func.h" @@ -54,6 +55,8 @@ static void ShowNetworkStartServerWindow(); static void ShowNetworkLobbyWindow(NetworkGameList *ngl); +static const int NETWORK_LIST_REFRESH_DELAY = 30; ///< Time, in seconds, between updates of the network list. + static ClientID _admin_client_id = INVALID_CLIENT_ID; ///< For what client a confirmation window is open. static CompanyID _admin_company_id = INVALID_COMPANY; ///< For what company a confirmation window is open. @@ -219,14 +222,15 @@ protected: static GUIGameServerList::SortFunction * const sorter_funcs[]; static GUIGameServerList::FilterFunction * const filter_funcs[]; - NetworkGameList *server; ///< selected server - NetworkGameList *last_joined; ///< the last joined server - GUIGameServerList servers; ///< list with game servers. - ServerListPosition list_pos; ///< position of the selected server - Scrollbar *vscroll; ///< vertical scrollbar of the list of servers - QueryString name_editbox; ///< Client name editbox. - QueryString filter_editbox; ///< Editbox for filter on servers - GUITimer requery_timer; ///< Timer for network requery + NetworkGameList *server; ///< Selected server. + NetworkGameList *last_joined; ///< The last joined server. + GUIGameServerList servers; ///< List with game servers. + ServerListPosition list_pos; ///< Position of the selected server. + Scrollbar *vscroll; ///< Vertical scrollbar of the list of servers. + QueryString name_editbox; ///< Client name editbox. + QueryString filter_editbox; ///< Editbox for filter on servers. + GUITimer requery_timer; ///< Timer for network requery. + bool searched_internet = false; ///< Did we ever press "Search Internet" button? int lock_offset; ///< Left offset for lock icon. int blot_offset; ///< Left offset for green/yellow/red compatibility icon. @@ -244,8 +248,18 @@ protected: /* Create temporary array of games to use for listing */ this->servers.clear(); + bool found_current_server = false; for (NetworkGameList *ngl = _network_game_list; ngl != nullptr; ngl = ngl->next) { this->servers.push_back(ngl); + if (ngl == this->server) { + found_current_server = true; + } + } + /* A refresh can cause the current server to be delete; so unselect. */ + if (!found_current_server) { + if (this->server == this->last_joined) this->last_joined = nullptr; + this->server = nullptr; + this->list_pos = SLP_INVALID; } /* Apply the filter condition immediately, if a search string has been provided. */ @@ -479,7 +493,7 @@ public: this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false); this->server = this->last_joined; - this->requery_timer.SetInterval(MILLISECONDS_PER_TICK); + this->requery_timer.SetInterval(NETWORK_LIST_REFRESH_DELAY * 1000); this->servers.SetListing(this->last_sorting); this->servers.SetSortFuncs(this->sorter_funcs); @@ -725,7 +739,8 @@ public: } case WID_NG_SEARCH_INTERNET: - NetworkUDPQueryMasterServer(); + _network_coordinator_client.GetListing(); + this->searched_internet = true; break; case WID_NG_SEARCH_LAN: @@ -841,10 +856,11 @@ public: void OnRealtimeTick(uint delta_ms) override { + if (!this->searched_internet) return; if (!this->requery_timer.Elapsed(delta_ms)) return; - this->requery_timer.SetInterval(MILLISECONDS_PER_TICK); + this->requery_timer.SetInterval(NETWORK_LIST_REFRESH_DELAY * 1000); - NetworkGameListRequery(); + _network_coordinator_client.GetListing(); } }; -- cgit v1.2.3-70-g09d2