diff --git a/os/emscripten/pre.js b/os/emscripten/pre.js index 1563e4f95b..82664004ea 100644 --- a/os/emscripten/pre.js +++ b/os/emscripten/pre.js @@ -65,10 +65,14 @@ Module.preRun.push(function() { } window.openttd_server_list = function() { - add_server = Module.cwrap("em_openttd_add_server", null, ["string", "number"]); + add_server = Module.cwrap("em_openttd_add_server", null, ["string"]); - /* Add servers that support WebSocket here. Example: - * add_server("localhost", 3979); */ + /* Add servers that support WebSocket here. Examples: + * add_server("localhost"); + * add_server("localhost:3979"); + * add_server("127.0.0.1:3979"); + * add_server("[::1]:3979"); + */ } var leftButtonDown = false; diff --git a/src/lang/english.txt b/src/lang/english.txt index 3037bf90fe..f8e3618e51 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2217,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Your com STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Your computer took too long to download the map STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Your computer took too long to join the server STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Your player name is not valid +STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}The queried server is too old for this client ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :general error diff --git a/src/network/network.cpp b/src/network/network.cpp index d7cf9367a1..c31a67487d 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -602,8 +602,11 @@ static void NetworkInitialize(bool close_admins = true) /** Non blocking connection create to query servers */ class TCPQueryConnecter : TCPConnecter { +private: + bool request_company_info; + public: - TCPQueryConnecter(const NetworkAddress &address) : TCPConnecter(address) {} + TCPQueryConnecter(const NetworkAddress &address, bool request_company_info) : TCPConnecter(address), request_company_info(request_company_info) {} void OnFailure() override { @@ -613,36 +616,53 @@ public: void OnConnect(SOCKET s) override { _networking = true; - new ClientNetworkGameSocketHandler(s); - MyClient::SendInformationQuery(); + new ClientNetworkGameSocketHandler(s, address); + MyClient::SendInformationQuery(request_company_info); } }; /** * Query a server to fetch his game-info. * @param address the address to query. + * @param request_company_info Whether to request company info too. */ -void NetworkTCPQueryServer(NetworkAddress address) +void NetworkTCPQueryServer(NetworkAddress address, bool request_company_info) { if (!_network_available) return; NetworkDisconnect(); NetworkInitialize(); - new TCPQueryConnecter(address); + new TCPQueryConnecter(address, request_company_info); } /** * Validates an address entered as a string and adds the server to * the list. If you use this function, the games will be marked * as manually added. - * @param connection_string The IP:port to add to the list. + * @param connection_string The IP:port of the server to add. + * @return The entry on the game list. */ -void NetworkAddServer(const char *connection_string) +NetworkGameList *NetworkAddServer(const std::string &connection_string) { - if (StrEmpty(connection_string)) return; + if (connection_string.empty()) return nullptr; - NetworkUDPQueryServer(ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT), true); + NetworkAddress address = ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT); + + /* Ensure the item already exists in the list */ + NetworkGameList *item = NetworkGameListAddItem(address); + if (StrEmpty(item->info.server_name)) { + ClearGRFConfigList(&item->info.grfconfig); + address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name)); + item->manually = true; + + NetworkRebuildHostList(); + UpdateNetworkGameWindow(); + } + + NetworkTCPQueryServer(address); + + return item; } /** @@ -687,7 +707,7 @@ public: void OnConnect(SOCKET s) override { _networking = true; - new ClientNetworkGameSocketHandler(s); + new ClientNetworkGameSocketHandler(s, this->address); IConsoleCmdExec("exec scripts/on_client.scr 0"); NetworkClient_Connected(); } @@ -1132,9 +1152,9 @@ void NetworkShutDown() #ifdef __EMSCRIPTEN__ extern "C" { -void CDECL em_openttd_add_server(const char *host, int port) +void CDECL em_openttd_add_server(const char *connection_string) { - NetworkUDPQueryServer(NetworkAddress(host, port), true); + NetworkAddServer(connection_string); } } diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index af7073e558..f73c8be528 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -145,7 +145,7 @@ void ClientNetworkEmergencySave() * Create a new socket for the client side of the game connection. * @param s The socket to connect with. */ -ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s), savegame(nullptr), status(STATUS_INACTIVE) +ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s, NetworkAddress address) : NetworkGameSocketHandler(s), address(address), savegame(nullptr), status(STATUS_INACTIVE) { assert(ClientNetworkGameSocketHandler::my_client == nullptr); ClientNetworkGameSocketHandler::my_client = this; @@ -345,14 +345,18 @@ static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1); /** * Query the server for server information. */ -NetworkRecvStatus ClientNetworkGameSocketHandler::SendInformationQuery() +NetworkRecvStatus ClientNetworkGameSocketHandler::SendInformationQuery(bool request_company_info) { - my_client->status = STATUS_COMPANY_INFO; - _network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO; - SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); - + my_client->status = STATUS_GAME_INFO; my_client->SendPacket(new Packet(PACKET_CLIENT_GAME_INFO)); - my_client->SendPacket(new Packet(PACKET_CLIENT_COMPANY_INFO)); + + if (request_company_info) { + my_client->status = STATUS_COMPANY_INFO; + _network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO; + SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); + + my_client->SendPacket(new Packet(PACKET_CLIENT_COMPANY_INFO)); + } return NETWORK_RECV_STATUS_OKAY; } @@ -577,9 +581,13 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet * NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet *p) { - if (this->status != STATUS_COMPANY_INFO && this->status != STATUS_INACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; + if (this->status != STATUS_COMPANY_INFO && this->status != STATUS_GAME_INFO) return NETWORK_RECV_STATUS_MALFORMED_PACKET; NetworkGameList *item = GetLobbyGameInfo(); + if (item == nullptr) { + /* This is not the lobby, so add it to the game list. */ + item = NetworkGameListAddItem(this->address); + } /* Clear any existing GRFConfig chain. */ ClearGRFConfigList(&item->info.grfconfig); @@ -590,6 +598,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packe /* Ensure we consider the server online. */ item->online = true; + /* It could be either window, but only one is open, so redraw both. */ + SetWindowDirty(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); SetWindowDirty(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY); /* We will receive company info next, so keep connection open. */ @@ -727,6 +737,15 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p NetworkErrorCode error = (NetworkErrorCode)p->Recv_uint8(); + /* If we query a server that is 1.11.1 or older, we get an + * NETWORK_ERROR_NOT_EXPECTED on requesting the game info. Show a special + * error popup in that case. + */ + if (error == NETWORK_ERROR_NOT_EXPECTED && (this->status == STATUS_GAME_INFO || this->status == STATUS_COMPANY_INFO)) { + ShowErrorMessage(STR_NETWORK_ERROR_SERVER_TOO_OLD, INVALID_STRING_ID, WL_CRITICAL); + return NETWORK_RECV_STATUS_CLOSE_QUERY; + } + StringID err = STR_NETWORK_ERROR_LOSTCONNECTION; if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error]; /* In case of kicking a client, we assume there is a kick message in the packet if we can read one byte */ diff --git a/src/network/network_client.h b/src/network/network_client.h index 66cdb8ba57..40b8eedf92 100644 --- a/src/network/network_client.h +++ b/src/network/network_client.h @@ -15,12 +15,14 @@ /** Class for handling the client side of the game connection. */ class ClientNetworkGameSocketHandler : public ZeroedMemoryAllocator, public NetworkGameSocketHandler { private: + NetworkAddress address; ///< Address we are connected to. struct PacketReader *savegame; ///< Packet reader for reading the savegame. byte token; ///< The token we need to send back to the server to prove we're the right client. /** Status of the connection with the server. */ enum ServerStatus { STATUS_INACTIVE, ///< The client is not connected nor active. + STATUS_GAME_INFO, ///< We are trying to get the game information. STATUS_COMPANY_INFO, ///< We are trying to get company information. STATUS_JOIN, ///< We are trying to join a server. STATUS_NEWGRFS_CHECK, ///< Last action was checking NewGRFs. @@ -74,13 +76,13 @@ protected: static NetworkRecvStatus SendMapOk(); void CheckConnection(); public: - ClientNetworkGameSocketHandler(SOCKET s); + ClientNetworkGameSocketHandler(SOCKET s, NetworkAddress address); ~ClientNetworkGameSocketHandler(); NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override; void ClientError(NetworkRecvStatus res); - static NetworkRecvStatus SendInformationQuery(); + static NetworkRecvStatus SendInformationQuery(bool request_company_info); static NetworkRecvStatus SendJoin(); static NetworkRecvStatus SendCommand(const CommandPacket *cp); diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index 6d4285c854..12dbbce615 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -69,15 +69,6 @@ static void NetworkGameListHandleDelayedInsert() */ NetworkGameList *NetworkGameListAddItem(NetworkAddress address) { - const char *hostname = address.GetHostname(); - - /* Do not query the 'any' address. */ - if (StrEmpty(hostname) || - strcmp(hostname, "0.0.0.0") == 0 || - strcmp(hostname, "::") == 0) { - return nullptr; - } - NetworkGameList *item, *prev_item; prev_item = nullptr; @@ -95,7 +86,6 @@ NetworkGameList *NetworkGameListAddItem(NetworkAddress address) } else { prev_item->next = item; } - DEBUG(net, 4, "[gamelist] added server to list"); UpdateNetworkGameWindow(); diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 3204b2b962..590f2f5e09 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -472,9 +472,8 @@ public: EM_ASM(if (window["openttd_server_list"]) openttd_server_list()); #endif - this->last_joined = NetworkGameListAddItem(ParseConnectionString(_settings_client.network.last_joined, NETWORK_DEFAULT_PORT)); + this->last_joined = NetworkAddServer(_settings_client.network.last_joined); this->server = this->last_joined; - if (this->last_joined != nullptr) NetworkUDPQueryServer(this->last_joined->address); this->requery_timer.SetInterval(MILLISECONDS_PER_TICK); @@ -750,7 +749,7 @@ public: break; case WID_NG_REFRESH: // Refresh - if (this->server != nullptr) NetworkUDPQueryServer(this->server->address); + if (this->server != nullptr) NetworkTCPQueryServer(this->server->address); break; case WID_NG_NEWGRF: // NewGRF Settings @@ -971,7 +970,7 @@ void ShowNetworkGameWindow() first = false; /* Add all servers from the config file to our list. */ for (const auto &iter : _network_host_list) { - NetworkAddServer(iter.c_str()); + NetworkAddServer(iter); } } @@ -1485,7 +1484,7 @@ struct NetworkLobbyWindow : public Window { /* Clear the information so removed companies don't remain */ for (auto &company : this->company_info) company = {}; - NetworkTCPQueryServer(this->server->address); + NetworkTCPQueryServer(this->server->address, true); break; } } @@ -1555,7 +1554,7 @@ static void ShowNetworkLobbyWindow(NetworkGameList *ngl) strecpy(_settings_client.network.last_joined, ngl->address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined)); - NetworkTCPQueryServer(ngl->address); + NetworkTCPQueryServer(ngl->address, true); new NetworkLobbyWindow(&_network_lobby_window_desc, ngl); } diff --git a/src/network/network_internal.h b/src/network/network_internal.h index ff3c8c22d2..683c954e82 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -87,10 +87,10 @@ extern uint8 _network_reconnect; extern CompanyMask _network_company_passworded; -void NetworkTCPQueryServer(NetworkAddress address); +void NetworkTCPQueryServer(NetworkAddress address, bool request_company_info = false); void GetBindAddresses(NetworkAddressList *addresses, uint16 port); -void NetworkAddServer(const char *b); +struct NetworkGameList *NetworkAddServer(const std::string &connection_string); void NetworkRebuildHostList(); void UpdateNetworkGameWindow();