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/console_cmds.cpp b/src/console_cmds.cpp index d34fbb55c2..11a1c72864 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -969,16 +969,15 @@ DEF_CONSOLE_CMD(ConNetworkReconnect) break; } - if (StrEmpty(_settings_client.network.last_host)) { + if (StrEmpty(_settings_client.network.last_joined)) { IConsolePrint(CC_DEFAULT, "No server for reconnecting."); return true; } /* Don't resolve the address first, just print it directly as it comes from the config file. */ - IConsolePrintF(CC_DEFAULT, "Reconnecting to %s:%d...", _settings_client.network.last_host, _settings_client.network.last_port); + IConsolePrintF(CC_DEFAULT, "Reconnecting to %s ...", _settings_client.network.last_joined); - NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, playas); - return true; + return NetworkClientConnectGame(_settings_client.network.last_joined, playas); } DEF_CONSOLE_CMD(ConNetworkConnect) @@ -991,37 +990,8 @@ DEF_CONSOLE_CMD(ConNetworkConnect) } if (argc < 2) return false; - if (_networking) NetworkDisconnect(); // we are in network-mode, first close it! - - const char *port = nullptr; - const char *company = nullptr; - char *ip = argv[1]; - /* Default settings: default port and new company */ - uint16 rport = NETWORK_DEFAULT_PORT; - CompanyID join_as = COMPANY_NEW_COMPANY; - - ParseGameConnectionString(&company, &port, ip); - - IConsolePrintF(CC_DEFAULT, "Connecting to %s...", ip); - if (company != nullptr) { - join_as = (CompanyID)atoi(company); - IConsolePrintF(CC_DEFAULT, " company-no: %d", join_as); - - /* From a user pov 0 is a new company, internally it's different and all - * companies are offset by one to ease up on users (eg companies 1-8 not 0-7) */ - if (join_as != COMPANY_SPECTATOR) { - if (join_as > MAX_COMPANIES) return false; - join_as--; - } - } - if (port != nullptr) { - rport = atoi(port); - IConsolePrintF(CC_DEFAULT, " port: %s", port); - } - - NetworkClientConnectGame(ip, rport, join_as); - return true; + return NetworkClientConnectGame(argv[1], COMPANY_NEW_COMPANY); } /********************************* diff --git a/src/engine.cpp b/src/engine.cpp index de112e70ad..8936097eb1 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -67,12 +67,6 @@ static_assert(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_in const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT]; -Engine::Engine() : - overrides_count(0), - overrides(nullptr) -{ -} - Engine::Engine(VehicleType type, EngineID base) { this->type = type; @@ -137,11 +131,6 @@ Engine::Engine(VehicleType type, EngineID base) } } -Engine::~Engine() -{ - UnloadWagonOverrides(this); -} - /** * Checks whether the engine is a valid (non-articulated part of an) engine. * @return true if enabled diff --git a/src/engine_base.h b/src/engine_base.h index 3eabf67382..39899f302a 100644 --- a/src/engine_base.h +++ b/src/engine_base.h @@ -18,6 +18,12 @@ #include "3rdparty/cpp-btree/btree_map.h" +struct WagonOverride { + std::vector engines; + CargoID cargo; + const SpriteGroup *group; +}; + typedef Pool EnginePool; extern EnginePool _engine_pool; @@ -59,17 +65,15 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> { * evaluating callbacks. */ GRFFilePropsBase grf_prop; - uint16 overrides_count; - struct WagonOverride *overrides; + std::vector overrides; uint16 list_position; SpriteGroupCallbacksUsed callbacks_used = SGCU_ALL; uint64 cb36_properties_used = UINT64_MAX; btree::btree_map sprite_group_cb36_properties_used; - Engine(); + Engine() {} Engine(VehicleType type, EngineID base); - ~Engine(); bool IsEnabled() const; /** diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index ee5c62c399..cd5098ccc5 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -960,7 +960,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit Malaio STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Dirigem na esquerda STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Dirigem na direita -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nomes das cidades +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nome das cidades: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Selecionar o estilo dos nomes das cidades ############ start of townname region @@ -1000,6 +1000,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :A cada 12 meses STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Selecionar o idioma da interface do jogo +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% concluído) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Tela cheia STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Marcar esta caixa para jogar OpenTTD modo de tela cheia @@ -1997,6 +1998,8 @@ STR_FACE_TIE :Gravata: STR_FACE_EARRING :Brinco: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Alterar gravata ou brinco +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privado +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Público # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multi-jogador @@ -2060,6 +2063,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}O nome d STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Definir senha STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Proteja o jogo com uma senha se não desejar que seja publicamente acessível +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilidade +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Se outras pessoas podem ver seu servidor na lista pública STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} cliente{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Num máx de clientes: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Escolha o número máximo de clientes. Não é necessário estarem todos preenchidos @@ -2123,12 +2128,45 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Empresa está protegida. Digite a senha # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clientes +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jogadores online STR_NETWORK_COMPANY_LIST_SPECTATE :Assistir # Network client list - - +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijogador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nome +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nome do servidor que você está jogando +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Edita o nome do seu servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nome do servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilidade +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Se outras pessoas podem ver seu servidor na lista pública +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nome +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Seu nome de jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Edita seu nome de jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Seu nome de jogador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Ações administrativas a serem executadas para esse cliente +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Ações administrativas a serem executadas para essa empresa +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Junta-se a essa empresa +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Envia uma mensagem a esse jogador +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Envia uma mensagem a todos os jogadores dessa empresa +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Envia uma mensagem a todos os espectadores +STR_NETWORK_CLIENT_LIST_SPECTATORS :Espectadores +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nova empresa) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Cria uma nova empresa e se une a ela +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Esse é você +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Esse é o hospedeiro do jogo + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Expulsar +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Banir +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Excluir +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Desbloqueio com senha + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Ação de administrador +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Você tem certeza que quer expulsar o jogador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Você tem certeza que quer banir o jogador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Você tem certeza que quer excluir a empresa '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Você tem certeza que quer restaurar a senha da empresa '{COMPANY}'? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Cliente @@ -2173,6 +2211,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Não foi STR_NETWORK_ERROR_CLIENT_START :{WHITE}Não foi possível estabelecer conexão STR_NETWORK_ERROR_TIMEOUT :{WHITE}Tempo de espera esgotado na conexão #{NUM} STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Ocorreu um erro de protocolo e a conexão foi encerrada +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Seu nome de jogador não foi definido. O nome pode ser definido no topo da janela de Multijogador STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}A versão deste cliente não condiz com a versão do servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Senha incorreta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}O servidor está cheio @@ -2185,6 +2224,8 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Você de STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Seu computador é lento demais para acompanhar o servidor STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Seu computador demorou demais para baixar o mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Seu computador demorou demais para entrar no servidor +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Seu nome de jogador não é válido +STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}O servidor requisitado é muito antigo para esse cliente ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :erro geral @@ -2207,6 +2248,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :não recebeu se STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :tempo esgotado STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :a baixa do mapa demorou demais STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :o processamento do mapa demorou demais +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nome de cliente inválido ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possível perda de conexão @@ -3050,6 +3092,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Atenção: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Erro: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Erro Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Um erro de NewGRF fatal ocorreu:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Um erro NewGRF ocorreu:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} não irá funcionar com a versão do TTDPatch encontrada pelo OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} funciona na versão {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} é projetado para ser usado com {STRING} diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index 1c8f0e0c36..f14a89e620 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -2225,6 +2225,7 @@ STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}El teu o STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}El teu ordinador ha tardat massa a descarregar el mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}El teu ordinador ha tardat massa a unir-se al servidor STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}El vostre nom de jugador no és vàlid. +STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}El servidor és massa antic per a aquest client. ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :error general @@ -3091,6 +3092,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Alerta: {S STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}S'ha produït un error fatal de NewGRF:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}S'ha produït un error relacionat amb els NewGRF:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} no funcionarà amb la versió TTDPatch informada per l'OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} és per la versió {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} està dissenyat per ser utilitzat amb {STRING} diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index 6b615ef2ba..862a9c4447 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -959,7 +959,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Maleisische Rin STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Links rijden STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Rechts rijden -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Plaatsnamen +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Plaatsnamen: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Stijl voor plaatsnamen kiezen ############ start of townname region @@ -999,6 +999,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Iedere 12 maand STR_GAME_OPTIONS_LANGUAGE :{BLACK}Taal STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Taal selecteren voor gebruikersscherm +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% voltooid) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Volledig scherm STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Vink dit vakje aan om OpenTTD in het volledige scherm te spelen @@ -1996,6 +1997,8 @@ STR_FACE_TIE :Stropdas: STR_FACE_EARRING :Oorbel: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Verander das of oorbel +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privé +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Openbaar # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Netwerkspel @@ -2052,13 +2055,15 @@ STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Vul je n STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Voer het IP-adres van de server in # Start new multiplayer server -STR_NETWORK_START_SERVER_CAPTION :{WHITE}Start nieuw multiplayerspel +STR_NETWORK_START_SERVER_CAPTION :{WHITE}Nieuw spel met meerdere spelers starten STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Spelnaam: -STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}De spelnaam wordt weergegeven aan andere spelers in het multiplayerspelselectiemenu +STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}De spelnaam wordt weergegeven aan andere spelers in het spelselectiemenu voor meerdere spelers STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Wachtwoord instellen STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Beveilig je spel met een wachtwoord als je niet wilt dat dit algemeen toegankelijk is +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Zichtbaarheid +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Bepaalt of andere mensen je server kunnen zien in de openbare lijst STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} speler{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximumaantal spelers: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Kies het maximaal aantal toegestane spelers. Niet alle posities hoeven gebruikt te worden. @@ -2122,12 +2127,45 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server i STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Bedrijf is beveiligd. Voer wachtwoord in # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Spelerslijst +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Spelers online STR_NETWORK_COMPANY_LIST_SPECTATE :Toekijken # Network client list - - +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Meerdere spelers +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Server +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Naam +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}De naam van de server waar je speelt +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}De naam van je server bewerken +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Servernaam +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Zichtbaarheid +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Bepaalt of andere mensen je server kunnen zien in de openbare lijst +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Speler +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Naam +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Je spelernaam +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Je spelernaam bewerken +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Je spelernaam +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Beheeracties die nodig zijn voor deze client +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Beheeracties die nodig zijn voor dit bedrijf +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Meedoen met dit bedrijf +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Een bericht sturen naar deze speler +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Een bericht versturen naar alle spelers van dit bedrijf +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Een bericht sturen naar alle toeschouwers +STR_NETWORK_CLIENT_LIST_SPECTATORS :Toeschouwers +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nieuw bedrijf) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Een nieuw bedrijf maken en meedoen +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Dit ben jij +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dit is de host van het spel + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Eruit schoppen +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Bannen +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Verwijderen +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Wachtwoord ontgrendelen + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Beheeractie +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Weet je zeker dat je de speler '{STRING}' eruit wilt schoppen? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Weet je zeker dat je de speler '{STRING}' wilt bannen? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Weet je zeker dat je het bedrijf '{COMPANY}' wilt verwijderen? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Weet je zeker dat je het wachtwoord voor bedrijf '{COMPANY}' wilt terugstellen? STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Speler @@ -2172,6 +2210,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Kan serv STR_NETWORK_ERROR_CLIENT_START :{WHITE}Kan geen verbinding maken STR_NETWORK_ERROR_TIMEOUT :{WHITE}Verbinding nr. {NUM} kostte te veel tijd STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Er is een protocolfout gedetecteerd en de verbinding werd gesloten +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Je spelernaam is nog niet ingesteld. Je stelt de naam in bovenin het venster Meerdere spelers STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}De revisie van deze client komt niet overeen met de revisie van de server STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Ongeldig wachtwoord STR_NETWORK_ERROR_SERVER_FULL :{WHITE}De server is vol @@ -2184,6 +2223,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Het invo STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Uw computer is te traag om de server bij te houden STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Uw computer deed er te lang over om de kaart te downloaden STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Uw computer deed er te lang over om met de server te verbinden +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Je spelernaam is niet geldig ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :algemene fout @@ -2206,6 +2246,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :wachtwoord niet STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :algemene time-out STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :downloaden van de kaart duurde te lang STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :verwerken van de kaart duurde te lang +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :ongeldige clientnaam ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Mogelijk verbinding verbroken @@ -3049,6 +3090,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Waarschuwi STR_NEWGRF_ERROR_MSG_ERROR :{RED}Fout: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatale fout: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Een fatale NewGRF-fout is ontstaan:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Er is een NewGRF-fout opgetreden:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} werkt niet met de TTDPatch-versie die is opgegeven door OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} is voor versie {STRING} van TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} is ontwikkeld voor {STRING} diff --git a/src/lang/english.txt b/src/lang/english.txt index 820866a6e5..092789135f 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2649,6 +2649,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/lang/english_US.txt b/src/lang/english_US.txt index b553105ca6..f61ccdd38d 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -3114,6 +3114,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warning: { STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}A fatal NewGRF error has occurred:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}A NewGRF error has occurred:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} will not work with the TTDPatch version reported by OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} is for the {STRING} version of TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} is designed to be used with {STRING} diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 70685c32c1..c7a557ccab 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -3090,6 +3090,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Varoitus: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Virhe: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Virhe: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Vakava NewGRF-virhe on tapahtunut:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}NewGRF-virhe on tapahtunut:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} ei toimi OpenTTD:n ilmoittaman TTDPatch-version kanssa STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} on TTD:n {STRING}-versiota varten STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} ja {STRING} on suunniteltu toimimaan yhdessä @@ -4473,7 +4474,7 @@ STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Ei voi r STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Satamaa ei voi rakentaa tähän... STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Lentokenttää ei voi rakentaa... -STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Liitä yhteen useampi asema/lastausalue. +STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Vieressä on useampi kuin yksi olemassaoleva asema tai kuormausalue. STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... asema liian levittäytynyt STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Liian monta asemaa ja lastausaluetta. STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Rautatieasema on jakautunut liian moneen osaan @@ -4506,7 +4507,7 @@ STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Satama p STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Lentokenttä pitää tuhota ensin. # Waypoint related errors -STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Liittää useamman kuin yhden reittipisteen +STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Vieressä on useampi kuin yksi olemassaoleva reittipiste. STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Liian lähellä toista reittipistettä STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Junien reittipistettä ei voi rakentaa tähän... diff --git a/src/lang/french.txt b/src/lang/french.txt index 368b0d76f2..629bb573fd 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -960,7 +960,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Malaysian Ringg STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Conduite à gauche STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Conduite à droite -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Noms des villes +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nom des villes{NBSP}: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Sélectionner la nationalité des noms des villes ############ start of townname region @@ -1000,6 +1000,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Tous les 12 moi STR_GAME_OPTIONS_LANGUAGE :{BLACK}Langue STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Sélectionner la langue à utiliser pour l'interface +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}{NBSP}% terminé{P "" s}) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Plein écran STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Cocher cette case pour jouer à OpenTTD en plein écran @@ -1997,6 +1998,8 @@ STR_FACE_TIE :Cravate{NBSP}: STR_FACE_EARRING :Boucle d'oreille{NBSP}: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Modifier la cravate ou la boucle d'oreille +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privé +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Public # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multijoueurs @@ -2060,6 +2063,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Les autr STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Choisir le mot de passe STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protégez votre partie avec un mot de passe si vous ne souhaitez pas que d'autres l'utilisent +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilité +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Possibilité pour les autres personnes de vous voir dans la liste publique STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Nombre de clients maximum{NBSP}: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Choisir un nombre maximum de clients. Tous les emplacements n'auront pas besoin d'être remplis @@ -2123,12 +2128,45 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Le serve STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}La compagnie est protégée. Entrez le mot de passe # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Liste des clients +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Joueurs en ligne STR_NETWORK_COMPANY_LIST_SPECTATE :Spectateur # Network client list - - +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijoueur +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Serveur +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nom +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nom du serveur sur lequel vous jouez +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Éditer le nom de votre serveur +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nom du serveur +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilité +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Possibilité pour les autres personnes de voir votre serveur dans la liste publique +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Joueur +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nom +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Votre nom de jeu +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Éditer votre nom +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Votre nom de jeu +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Actions administratives à accomplir pour ce client +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Actions administratives à accomplir pour cette compagnie +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Rejoindre cette compagnie +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Envoyer un message à cette personne +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Envoyer un message à tous les joueurs de cette compagnie +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Envoyer un message à tous les spectateurs +STR_NETWORK_CLIENT_LIST_SPECTATORS :Spectateurs +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nouvelle compagnie) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Créer une nouvelle compagnie et la rejoindre +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}C'est vous +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}C'est l'hôte du jeu + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Exclure +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Bannir +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Supprimer +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Débloquer le mot de passe + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Action administrative +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Êtes-vous sûr de vouloir exclure '{STRING}'{NBSP}? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Êtes-vous sûr de vouloir bannir '{STRING}'{NBSP}? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Êtes-vous sûr de vouloir supprimer la compagnie '{COMPANY}'{NBSP}? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Êtes-vous sûr de vouloir réinitialiser le mot de passe de la compagnie '{COMPANY}'? STR_NETWORK_SERVER :Serveur STR_NETWORK_CLIENT :Client @@ -2173,6 +2211,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Le serve STR_NETWORK_ERROR_CLIENT_START :{WHITE}Échec de la connexion STR_NETWORK_ERROR_TIMEOUT :{WHITE}La connexion n°{NBSP}{NUM} a dépassé le temps d'attente STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Une erreur de protocole a été détectée et la connexion a été fermée +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Vous n'avez pas de nom. Il doit être entré en haut de la fenêtre Multijoueur STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Le numéro de version/révision de ce client ne correspond pas à celui du serveur STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Mot de passe incorrect STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Le serveur est complet @@ -2185,6 +2224,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Vous ave STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Votre ordinateur est trop lent pour suivre le serveur STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Votre ordinateur a mis trop de temps pour télécharger la carte STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Votre ordinateur a mis trop de temps pour rejoindre le serveur +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Votre nom n'est pas valide ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :erreur générale @@ -2207,6 +2247,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :aucun mot de pa STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :délai dépassé STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :télécharger la carte a pris trop de temps STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :le traitement de la carte a pris trop de temps +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nom client invalide ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible perte de connexion @@ -3050,6 +3091,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Attention{ STR_NEWGRF_ERROR_MSG_ERROR :{RED}Erreur{NBSP}: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Erreur fatale{NBSP}: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Une erreur NewGRF fatale est survenue{NBSP}:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Une erreur NewGRF est survenue{NBSP}:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} ne fonctionnera pas avec la version de TTDPatch rapportée par OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} est conçu pour la version {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} est conçu pour être utilisé avec {STRING} diff --git a/src/lang/german.txt b/src/lang/german.txt index 458300e6c6..d3b96e785b 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -3785,6 +3785,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warnung: { STR_NEWGRF_ERROR_MSG_ERROR :{RED}Fehler: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Schwerer Fehler: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Ein schwerer NewGRF-Fehler ist aufgetreten:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ein NewGRF-Fehler ist aufgetreten:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} funktioniert nicht im Zusammenhang mit der von OpenTTD ermittelten TTDPatch-Version STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} ist für die {STRING}-Version von TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} ist für die Nutzung mit {STRING} vorgesehen diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 264a6f2231..ea0d5d4cf6 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -2231,8 +2231,8 @@ STR_CONFIG_ERROR :{WHITE}설정 STR_CONFIG_ERROR_ARRAY :{WHITE}... 배열 '{STRING}'에서 오류 발생 STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... '{1:STRING}'에 잘못된 값('{0:STRING}')이 지정되었습니다. STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... '{STRING}' 설정의 끝에 후행 문자가 있습니다. -STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... NewGRF '{STRING}' 무시중: '{STRING}'{G 1 "과" "와"} GRF ID가 겹침 -STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... 유효하지 않은 NewGRF '{STRING}' 무시중: {STRING} +STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... '{STRING}' NewGRF를 무시합니다: '{STRING}'{G 1 "과" "와"} GRF ID가 겹침 +STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... 유효하지 않은 '{STRING}' NewGRF를 무시합니다: {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :찾을 수 없음 STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :사용하기에 불안함 STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :NewGRF 시스템 @@ -2649,6 +2649,7 @@ STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}사용 STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}지도 다운로드 시간을 초과하였습니다 STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}서버 접속 시간을 초과하였습니다 STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}사용할 수 없는 이름입니다 +STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}검색한 서버는 현재 버전에 비해 너무 오래된 서버입니다 ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :일반 오류 @@ -3927,7 +3928,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}경고: {S STR_NEWGRF_ERROR_MSG_ERROR :{RED}오류: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}치명적 오류: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}치명적인 NewGRF 오류가 발생했습니다:{}{STRING} -STR_NEWGRF_ERROR_POPUP :{WHITE}NewGRF 오류가 발생했습니다: {}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}NewGRF 관련 오류가 발생했습니다:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING}{G 1 "은" "는"} OpenTTD에서 보고된 TTDPatch 버전에서 작동하지 않을 것입니다 STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING}{G 1 "은" "는"} {STRING} 버전의 TTD를 위한 것입니다 STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING}{G 1 "은" "는"} {STRING}{G 1 "와" "과"} 같이 사용해야 합니다 diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index 799e7e0c1f..2a6c98b96a 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -961,7 +961,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Malaysisk Ringg STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Venstrekjøring STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Høyrekjøring -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Bynavn +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Bynavn: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Velg nasjonalitet på bynavn ############ start of townname region @@ -2000,6 +2000,8 @@ STR_FACE_TIE :Slips: STR_FACE_EARRING :Ørering: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Endre slips eller ørering +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privat +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Offentlig # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Flerspiller @@ -2063,6 +2065,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Spillnav STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Sett passord STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Beskytt ditt spill med et passord hvis du ikke vil at hvem som helst skal bli med på det +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Synlighet +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Om andre mennesker kan se serveren din i den offentlige oppføringen STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" er} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maks antall klienter: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS.small :dra og slipp @@ -2127,12 +2131,45 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Tjeneren STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Firmaet er beskyttet. Skriv inn passord # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Liste over klienter +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Påloggede spillere STR_NETWORK_COMPANY_LIST_SPECTATE :Vær tilskuer # Network client list - - +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Flerspiller +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Server +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Navn +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Navnet på serveren du spiller på +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Rediger navnet på serveren +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Servernavn +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Synlighet +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Om andre mennesker kan se serveren din i den offentlige oppføringen +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Spiller +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Navn +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Ditt spillernavn +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Rediger ditt spillernavn +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Ditt spillernavn +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Administrative handlinger å utføre for denne klienten +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Administrative tiltak å utføre for dette firmaet +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Bli med i dette firmaet +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Send en melding til denne spilleren +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Send en melding til alle spillerne i dette firmaet +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Send en melding til alle tilskuerne +STR_NETWORK_CLIENT_LIST_SPECTATORS :Tilskuere +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nytt firma) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Opprett et nytt firma og bli med i det +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Dette er deg +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dette er verten for spillet + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Spark +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Utesteng +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Slett +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Låse opp passord + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Administratorhandling +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Er du sikker på at du vil utestenge spiller '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Er du sikker på at du vil utestenge spiller '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Er du sikker på at du vil slette firmaet '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Er du sikker på at du vil tilbakestille passordet til firma '{COMPANY}'? STR_NETWORK_SERVER :Tjener STR_NETWORK_CLIENT :Klient @@ -2191,6 +2228,7 @@ STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Din data STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Din datamaskin brukte for lang tid på å laste ned kartet STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Din datamaskin brukte for lang tid på å koble til tjeneren STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Spillernavnet ditt er ugyldig +STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}Den forespurte serveren er for gammel for denne klienten ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :generell feil @@ -3057,6 +3095,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Advarsel: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Feil: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}En fatal NewGRF-feil har oppstått:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}En NewGRF feil har oppstått:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} virker ikke med TTDPatch-versjonen som er rapportert av OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} er for versjon {STRING} av TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} er laget for bruk med {STRING} diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 0f0eec5c80..e8e3d3a9a2 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -960,7 +960,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit da Mal STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Circular pela esquerda STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Circular pela direita -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nomes das localidades +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nomes das localidades: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Seleccionar o estilo dos nomes das localidades ############ start of townname region @@ -1000,6 +1000,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Cada 12 meses STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Seleccionar o idioma da interface do jogo +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% completado) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Ecrã Inteiro STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Seleccione esta opção para jogar o OpenTTD em modo de ecrã inteiro @@ -1997,6 +1998,8 @@ STR_FACE_TIE :Gravata: STR_FACE_EARRING :Brinco: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Mudar gravata ou brinco +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privado +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Público # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multi-jogador @@ -2049,7 +2052,7 @@ STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Adiciona STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Iniciar servidor STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Iniciar um servidor próprio -STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Digite teu nome +STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Introduza o seu nome STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Introduza o endereço IP do servidor # Start new multiplayer server @@ -2060,6 +2063,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}O nome d STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Definir palavra-chave STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Proteja o jogo com uma senha se não desejar que pessoas indesejadas se juntem +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilidade +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Se as outras pessoas podem ver o seu servidor na lista pública STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} cliente{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Máximo de clientes: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Escolha o número máximo de clientes. Não necessitam estar todos presentes. @@ -2123,12 +2128,45 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Empresa protegida. Introduza palavra-chave # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clientes +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jogadores "online" STR_NETWORK_COMPANY_LIST_SPECTATE :Assistir # Network client list - - +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multi-jogador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nome +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nome do servidor onde está a jogar +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Editar o nome do seu servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nome do servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilidade +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Se as outras pessoas podem ver o seu servidor na lista pública +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nome +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}O seu nome de jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Editar o seu nome de jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :O seu nome de jogador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Ações administrativas para executar a este cliente +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Ações administrativas para executar a esta empresa +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Juntar-se a esta empresa +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Enviar uma mensagem a este jogador +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Enviar uma mensagem a todos os jogadores desta empresa +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Enviar uma mensagem a todos os espectadores +STR_NETWORK_CLIENT_LIST_SPECTATORS :Espectadores +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nova empresa) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Criar uma nova empresa e juntar-se a ela +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Este é você +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Este é o anfitrião do jogo + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Expulsar +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Banir +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Apagar +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :desbloquear com palavra-passe + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Ação administrativa +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Tem a certeza que quer expulsar o jogador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Tem a certeza que quer banir o jogador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Tem a certeza que quer apagar a empresa '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Tem a certeza que quer restabelecer a palavra-chave da empresa '{COMPANY}'? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Cliente @@ -2173,6 +2211,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Não foi STR_NETWORK_ERROR_CLIENT_START :{WHITE}Não foi possível estabelecer ligação STR_NETWORK_ERROR_TIMEOUT :{WHITE}Tempo de espera esgotado na conexão #{NUM}. STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Ocorreu um erro de protocolo e a ligação foi encerrada +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}O seu nome de jogador não foi definido. O nome pode ser definido no topo da janela de Multi-jogador STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}A revisão deste cliente não condiz com a revisão do servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Palavra-chave incorrecta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Servidor cheio @@ -2185,6 +2224,8 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Demorou STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}O seu computador é demasiado lento para acompanhar com o servidor STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}O seu computador demorou demasiado a transferir o mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}O seu computador demorou demasiado a ligar ao servidor +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}O seu nome de jogador não é válido +STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}O servidor consultado é muito antigo para este cliente ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :erro geral @@ -2207,6 +2248,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :não foi recebi STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :demasiado tempo (geral) STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :demorou demasiado a transferir o mapa STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :demorou demasiado a processar o mapa +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nome de cliente inválido ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possível perda de conexão @@ -3050,6 +3092,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Aviso: {SI STR_NEWGRF_ERROR_MSG_ERROR :{RED}Erro: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Ocorreu um erro fatal num NewGRF:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ocorreu um erro de NewGRF:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} não funciona com a versão do TTDPatch reportada por OpenTTD. STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} é para a versão {STRING} do TTD. STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} foi concebido para ser usado com {STRING} diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 7ed54543c2..56aaa95642 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -396,7 +396,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Если STR_BUTTON_DEFAULT :{BLACK}По умолчанию STR_BUTTON_CANCEL :{BLACK}Отмена STR_BUTTON_OK :{BLACK}OK -STR_WARNING_PASSWORD_SECURITY :{YELLOW}Внимание: администраторы сервера могут увидеть ваш пароль. +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Внимание: администраторы сервера могут увидеть текст, введённый в это поле. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . @@ -931,7 +931,7 @@ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Отоб STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Показать последнее сообщение или новость STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * ПАУЗА * * -STR_STATUSBAR_PAUSED_LINK_GRAPH :{ORANGE}* * ПАУЗА (ожидает обновления графы ссылок) * * +STR_STATUSBAR_PAUSED_LINK_GRAPH :{ORANGE}* * ПАУЗА (ожидает обновления графа распределения) * * STR_STATUSBAR_AUTOSAVE :{RED}АВТОСОХРАНЕНИЕ STR_STATUSBAR_SAVING_GAME :{RED}* * СОХРАНЕНИЕ ИГРЫ * * @@ -2151,6 +2151,8 @@ STR_FACE_TIE :Галстук: STR_FACE_EARRING :Серьга: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Изменить галстук или серьгу +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Публичный +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Частный # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Сетевая игра @@ -2169,7 +2171,7 @@ STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Дата STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Текущая дата STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Года STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Количество лет{}в игре -STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Язык, версия сервера и т.п. +STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Язык, версия сервера и{NBSP}т.{NBSP}п. STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Выберите игру из списка STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}Последний сервер, к которому вы подключались: @@ -2184,20 +2186,20 @@ STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Вер STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Адрес сервера: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Дата начала: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Текущая дата: {WHITE}{DATE_SHORT} -STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Защищено паролем! -STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}СЕРВЕР ОТКЛЮЧЕН +STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Защищён паролем! +STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}СЕРВЕР ОТКЛЮЧЁН STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}СЕРВЕР ЗАПОЛНЕН STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}ВЕРСИЯ НЕ ПОДХОДИТ STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}НЕ СОВПАДАЕТ НАБОР NEWGRF STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Присоединиться -STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Обновить сервер +STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Обновить информацию STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Обновить информацию о сервере STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :{BLACK}Искать в интернете -STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK} Искать в Интернете общедоступные серверы -STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Искать LAN -STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK} Поиск серверов в локальной сети +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Поиск общедоступных серверов в интернете +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Искать в ЛВС +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Поиск серверов в локальной сети STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Добавить сервер STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Добавить сервер в список, который будет автоматически проверяться на идущие игры STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Запуск сервера @@ -2214,15 +2216,17 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Назв STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Установить пароль STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Защитите вашу игру паролем, если не хотите, чтобы к ней могли подключиться посторонние. +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Видимость +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Видимость вашего сервера в публичном списке STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} клиент{P "" а ов} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Макс. количество клиентов: -STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Выбор максимального числа клиентов. Не все места должны быть заняты +STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Выбор максимального числа клиентов. Не все места обязательно должны быть заняты. STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} компани{P я и й} STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Макс. количество компаний: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Ограничить максимальное количество компаний на сервере -STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} наблюдател{P ь я ей} -STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Макс. количество наблюдателей: -STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Ограничить максимальное количество наблюдателей на сервере +STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} зрител{P ь я ей} +STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Макс. количество зрителей: +STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Ограничить максимальное количество зрителей на сервере STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Язык общения: STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Другие игроки будут знать, на каком языке общаются на сервере @@ -2232,7 +2236,7 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Введ STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Состояние сетевой игры STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Подготовка соединения: {ORANGE}{STRING} -STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}Список компаний в игре. Вы можете присоединиться к существующей или основать новую, если есть свободный слот +STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}Список компаний в игре. Вы можете присоединиться к одной из существующих или основать новую, если есть свободная позиция. STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}ИНФОРМАЦИЯ О КОМПАНИИ STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Название компании: {WHITE}{STRING} @@ -2277,22 +2281,49 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Серв STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Компания защищена. Введите пароль. # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Список клиентов +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Список игроков STR_NETWORK_COMPANY_LIST_SPECTATE :Наблюдать # Network client list -STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Действия администратора, применимые к этому клиенту +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Сетевая игра +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Сервер +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Название +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Название вашего сервера +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Сменить название сервера +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Название сервера +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Видимость +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Видимость вашего сервера в публичном списке +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Игрок +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Имя +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Ваше игровое имя +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Изменить имя игрока +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Ваше игровое имя +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Административные действия, применимые к этому игроку +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Административные действия, применимые к этой компании +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Присоединиться к этой компании +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Отправить сообщение этому игроку +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Послать сообщение всем игрокам этой компании +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Послать сообщение всем зрителям +STR_NETWORK_CLIENT_LIST_SPECTATORS :Зрители +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Новая компания) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Основать новую транспортную компанию и присоединиться к ней +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Это вы! +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Это организатор игры STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Отключить STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Заблокировать +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Удалить +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Сбросить пароль STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Подтверждение действия STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Отключить игрока «{STRING}»? STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Заблокировать игрока «{STRING}»? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Удалить компанию «{COMPANY}»? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Сбросить пароль у компании «{COMPANY}»? STR_NETWORK_SERVER :Сервер STR_NETWORK_CLIENT :Клиент -STR_NETWORK_SPECTATORS :Наблюдатели +STR_NETWORK_SPECTATORS :Зрители # Network set password STR_COMPANY_PASSWORD_CANCEL :{BLACK}Не сохранять пароль @@ -2337,8 +2368,8 @@ STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Не у STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Версия этого клиента не совместима с версией сервера STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Неверный пароль STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Сервер переполнен -STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Вас забанили на этом сервере -STR_NETWORK_ERROR_KICKED :{WHITE}Вас выкинули из игры +STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Вас заблокировали на этом сервере +STR_NETWORK_ERROR_KICKED :{WHITE}Вас отключили от игры STR_NETWORK_ERROR_KICK_MESSAGE :{WHITE}Причина: {STRING} STR_NETWORK_ERROR_CHEATER :{WHITE}Чит-коды не разрешены на этом сервере STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}Вы посылали на сервер слишком много команд @@ -2347,6 +2378,7 @@ STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Ваш STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Ваш компьютер тратит много времени на загрузку карты STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Ваш компьютер тратит много времени на подключение к серверу STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Неверно указано имя игрока +STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}На сервере запущена устаревшая версия игры ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :общая ошибка @@ -2389,13 +2421,13 @@ STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :количес STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :подключение клиентов STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :вручную STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :игровой скрипт -STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :ожидает обновления графы ссылок +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :ожидает обновления графа распределения ############ End of leave-in-this-order -STR_NETWORK_MESSAGE_CLIENT_LEAVING :покинул +STR_NETWORK_MESSAGE_CLIENT_LEAVING :отключение STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} подключился к игре STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} подключился к игре (клиент #{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} подключился к компании #{2:NUM} -STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} подключился наблюдателем +STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} подключился в качестве зрителя STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} основал новую компанию (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} покинул игру ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} изменил имя на {STRING} @@ -3240,6 +3272,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Внима STR_NEWGRF_ERROR_MSG_ERROR :{RED}Ошибка: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Критическая ошибка: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Ошибка при работе с NewGRF:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ошибка, связанная с модулем NewGRF:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} не будет работать с версией TTDPatch, сообщенной OpenTTD. STR_NEWGRF_ERROR_DOS_OR_WINDOWS :Файл {1:STRING} требует {STRING}-версию TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} сделан для использования совместно с {STRING} @@ -5371,7 +5404,7 @@ STR_DEFAULT_SIGN_NAME :Табличк STR_COMPANY_SOMEONE :кто-то STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING} -STR_SAVEGAME_NAME_SPECTATOR :Наблюдатель, {1:STRING} +STR_SAVEGAME_NAME_SPECTATOR :Зритель, {1:STRING} # Viewport strings STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index b234920381..b3dad8b805 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -960,7 +960,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit malasio STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Conducir por la izquierda STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Conducir por la derecha -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nombres de municipios +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nombres de municipios: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Selección del estilo del nombre de los municipios ############ start of townname region @@ -1998,6 +1998,8 @@ STR_FACE_TIE :Corbata: STR_FACE_EARRING :Pendientes: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Cambiar corbata o pendientes +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privado +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Público # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multijugador @@ -2061,6 +2063,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}La parti STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Establecer contraseña STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protege tu partida con una contraseña si no quieres que sea universalmente accesible +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilidad +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Establece si otras personas pueden ver el servidor en la lista de servidores públicos STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} cliente{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Número máximo de clientes: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Selecciona el número máximo de clientes. No es necesario ocupar todos los espacios @@ -2124,12 +2128,45 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Empresa protegida. Introduce la contraseña # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clientes +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jugadores en línea STR_NETWORK_COMPANY_LIST_SPECTATE :Observar # Network client list - - +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijugador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nombre +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nombre del servidor en el que estás jugando +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Modifica el nombre de tu servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nombre del servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilidad +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Establece si otras personas pueden ver el servidor en la lista de servidores públicos +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nombre +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Tu nombre de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Modifica tu nombre de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Tu nombre de jugador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Acciones de administrador a realizar para este cliente +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Acciones de administrador a realizar para esta compañía +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Unirse a esta compañía +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Manda un mensaje a este jugador +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Manda un mensaje a todos los jugadores de esta compañía +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Manda un mensaje a todos los observadores +STR_NETWORK_CLIENT_LIST_SPECTATORS :Observadores +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nueva compañía) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crea una nueva companía y te une a ella +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Éste eres tú +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Éste es el servidor de la partida + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Expulsar +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Prohibir el acceso +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Eliminar +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Eliminar contraseña + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Acción de administrador +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}¿Estás seguro de que deseas expulsar al jugador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}¿Estás seguro de que deseas prohibir el acceso al jugador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}¿Estás seguro de que quieres eliminar la compañía '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}¿Estás seguro de que quieres eliminar la contraseña de la compañía '{COMPANY}'? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Cliente @@ -2174,6 +2211,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}No se ha STR_NETWORK_ERROR_CLIENT_START :{WHITE}No se pudo conectar STR_NETWORK_ERROR_TIMEOUT :{WHITE}Tiempo de espera agotado en conexión #{NUM} STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Se ha producido un error de protocolo y la conexión ha sido cerrada +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}No se ha establecido tu nombre de jugador. El nombre se puede establecer en la parte superior de la ventana de Multijugador STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}La versión de este cliente no corresponde con la versión del servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Contraseña incorrecta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}El servidor está completo @@ -2186,6 +2224,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Has tard STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Su ordenador es demasiado lento para seguir la velocidad del servidor STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Su ordenador necesitó demasiado tiempo para descargar el mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Su ordenador necesitó demasiado tiempo para conectar al servidor +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Tu nombre de jugador no es válido ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :error general @@ -2208,6 +2247,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :no se ha recibi STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :tiempo agotado en general STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :la descarga del mapa ha necesitado demasiado tiempo STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :el procesado del mapa ha necesitado demasiado tiempo +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nombre de cliente inválido ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Posible pérdida de conexión @@ -3051,6 +3091,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Atención: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Error Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Ha ocurrido un error fatal de NewGRF:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ha ocurrido un error de NewGRF:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} no funcionará con la con la versión de TTDPatch informada por OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} es para la versión {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} está diseñado para ser usado con {STRING} diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt index 8c4d8eb24c..656692732e 100644 --- a/src/lang/spanish_MX.txt +++ b/src/lang/spanish_MX.txt @@ -960,7 +960,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit malasio STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Manejar por la izquierda STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Manejar por la derecha -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nombres de pueblos +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nombres de pueblos: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Elegir el estilo de nombres para pueblos ############ start of townname region @@ -1998,6 +1998,8 @@ STR_FACE_TIE :Corbata: STR_FACE_EARRING :Aretes: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Cambiar corbata o aretes +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privado +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Público # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multijugador @@ -2061,6 +2063,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}La parti STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Establecer contraseña STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Proteger la partida con una contraseña para prevenir el acceso a otras personas +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilidad +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Quién puede ver tu servidor en la lista pública STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} cliente{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Número máximo de clientes: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Elegir el número máximo de clientes. No es necesario que se conecten todos @@ -2124,12 +2128,45 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Empresa protegida. Introducir contraseña # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clientes +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jugadores conectados STR_NETWORK_COMPANY_LIST_SPECTATE :Observar # Network client list - - +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijugador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nombre +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nombre del servidor en el que estás jugando +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Modificar nombre del servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nombre del servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilidad +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Quién puede ver tu servidor en la lista pública +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nombre +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Tu nombre de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Modificar nombre de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Tu nombre de jugador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Acciones administrativas para este cliente +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Acciones administrativas para esta empresa +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Unirse a esta empresa +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Enviar mensaje a este jugador +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Enviar mensaje a todos los jugadores de la empresa +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Enviar mensaje a los espectadores +STR_NETWORK_CLIENT_LIST_SPECTATORS :Espectadores +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nueva empresa) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crear nueva empresa y unirse a ella +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Este eres tú +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Este es el host del juego + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Expulsar +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Bloquear acceso +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Eliminar +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Restablecer contraseña + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Acción de aministrador +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}¿Sacar al jugador "{STRING}"? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}¿Bloquear acceso al jugador "{STRING}"? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}¿Eliminar la empresa "{COMPANY}"? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}¿Restablecer contraseña de la empresa "{COMPANY}"? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Cliente @@ -2188,6 +2225,7 @@ STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Tu compu STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Tu computadora tardó demasiado en descargar el mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Tu computadora tardó demasiado en conectarse al servidor STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Tu nombre de jugador no es válido +STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}El servidor es demasiado viejo para este cliente ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :error general @@ -3054,6 +3092,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Atención: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Error fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Ocurrió un error fatal de NewGRF:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ocurrió un error de NewGRF:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} no funcionará con la con la versión de TTDPatch reportada por OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} es la para la versión {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} está diseñado para usarse con {STRING} diff --git a/src/network/core/CMakeLists.txt b/src/network/core/CMakeLists.txt index 37cc3e1954..bf713be99c 100644 --- a/src/network/core/CMakeLists.txt +++ b/src/network/core/CMakeLists.txt @@ -8,6 +8,7 @@ add_files( game_info.h host.cpp host.h + os_abstraction.cpp os_abstraction.h packet.cpp packet.h diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 673619c2eb..3b0e76edd9 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -94,6 +94,18 @@ void NetworkAddress::GetAddressAsString(char *buffer, const char *last, bool wit } } + /** + * Get the address as a string, e.g. 127.0.0.1:12345. + * @param with_family whether to add the family (e.g. IPvX). + * @return the address + */ +std::string NetworkAddress::GetAddressAsString(bool with_family) +{ + char buf[NETWORK_HOSTNAME_LENGTH + 6 + 7]; + this->GetAddressAsString(buf, lastof(buf), with_family); + return buf; +} + /** * Get the address as a string, e.g. 127.0.0.1:12345. * @param with_family whether to add the family (e.g. IPvX). @@ -311,12 +323,11 @@ static SOCKET ConnectLoopProc(addrinfo *runp) { const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype); const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family); - char address[NETWORK_HOSTNAME_LENGTH + 6 + 7]; - NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(address, lastof(address)); + std::string address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(); SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { - DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, NetworkGetLastErrorString()); + DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, NetworkError::GetLast().AsString()); return INVALID_SOCKET; } @@ -325,8 +336,8 @@ static SOCKET ConnectLoopProc(addrinfo *runp) if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed", type); int err = connect(sock, runp->ai_addr, (int)runp->ai_addrlen); - if (err != 0 && NetworkGetLastError() != EINPROGRESS) { - DEBUG(net, 1, "[%s] could not connect to %s over %s: %s", type, address, family, NetworkGetLastErrorString()); + if (err != 0 && !NetworkError::GetLast().IsConnectInProgress()) { + DEBUG(net, 1, "[%s] could not connect to %s over %s: %s", type, address.c_str(), family, NetworkError::GetLast().AsString()); closesocket(sock); return INVALID_SOCKET; } @@ -342,28 +353,28 @@ static SOCKET ConnectLoopProc(addrinfo *runp) tv.tv_sec = DEFAULT_CONNECT_TIMEOUT_SECONDS; int n = select(FD_SETSIZE, NULL, &write_fd, NULL, &tv); if (n < 0) { - DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address, NetworkGetLastErrorString()); + DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address.c_str(), NetworkError::GetLast().AsString()); closesocket(sock); return INVALID_SOCKET; } /* If no fd is selected, the timeout has been reached. */ if (n == 0) { - DEBUG(net, 1, "[%s] timed out while connecting to %s", type, address); + DEBUG(net, 1, "[%s] timed out while connecting to %s", type, address.c_str()); closesocket(sock); return INVALID_SOCKET; } /* Retrieve last error, if any, on the socket. */ - err = GetSocketError(sock); - if (err != 0) { - DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address, NetworkGetErrorString(err)); + NetworkError socket_error = GetSocketError(sock); + if (socket_error.HasError()) { + DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address.c_str(), socket_error.AsString()); closesocket(sock); return INVALID_SOCKET; } /* Connection succeeded. */ - DEBUG(net, 1, "[%s] connected to %s", type, address); + DEBUG(net, 1, "[%s] connected to %s", type, address.c_str()); return sock; } @@ -388,48 +399,47 @@ static SOCKET ListenLoopProc(addrinfo *runp) { const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype); const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family); - char address[NETWORK_HOSTNAME_LENGTH + 6 + 7]; - NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(address, lastof(address)); + std::string address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(); SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { - DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address, NetworkGetLastErrorString()); + DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString()); return INVALID_SOCKET; } if (runp->ai_socktype == SOCK_STREAM && !SetNoDelay(sock)) { - DEBUG(net, 3, "[%s] setting TCP_NODELAY failed for port %s", type, address); + DEBUG(net, 3, "[%s] setting TCP_NODELAY failed for port %s", type, address.c_str()); } int on = 1; /* The (const char*) cast is needed for windows!! */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) { - DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address, NetworkGetLastErrorString()); + DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString()); } #ifndef __OS2__ if (runp->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) == -1) { - DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address, NetworkGetLastErrorString()); + DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address.c_str(), NetworkError::GetLast().AsString()); } #endif if (bind(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) { - DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address, NetworkGetLastErrorString()); + DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString()); closesocket(sock); return INVALID_SOCKET; } if (runp->ai_socktype != SOCK_DGRAM && listen(sock, 1) != 0) { - DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address, NetworkGetLastErrorString()); + DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString()); closesocket(sock); return INVALID_SOCKET; } /* Connection succeeded */ - if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed for %s port %s", type, family, address); + if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed for %s port %s", type, family, address.c_str()); - DEBUG(net, 1, "[%s] listening on %s port %s", type, family, address); + DEBUG(net, 1, "[%s] listening on %s port %s", type, family, address.c_str()); return sock; } diff --git a/src/network/core/address.h b/src/network/core/address.h index f27ba2003f..622566fe06 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -190,8 +190,8 @@ struct NetworkAddressDumper { const char *GetAddressAsString(NetworkAddress *addr, bool with_family = true); private: - /* 6 = for the : and 5 for the decimal port number */ - char buf[NETWORK_HOSTNAME_LENGTH + 6 + 7]; + /* 7 extra are for with_family, which adds " (IPvX)". */ + char buf[NETWORK_HOSTNAME_PORT_LENGTH + 7]; }; #endif /* NETWORK_CORE_ADDRESS_H */ diff --git a/src/network/core/config.h b/src/network/core/config.h index 3ec2656acc..5cc28a9c3c 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -57,6 +57,7 @@ static const byte NETWORK_MASTER_SERVER_VERSION = 2; ///< What vers 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' static const uint NETWORK_HOSTNAME_LENGTH = 80; ///< The maximum length of the host name, in bytes including '\0' +static const uint NETWORK_HOSTNAME_PORT_LENGTH = 80 + 6; ///< The maximum length of the host name + port, in bytes including '\0'. The extra six is ":" + port number (with a max of 65536) static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0' static const uint NETWORK_REVISION_LENGTH = 33; ///< The maximum length of the revision, in bytes including '\0' static const uint NETWORK_LONG_REVISION_LENGTH = 64; ///< The maximum length of the revision, in bytes including '\0' diff --git a/src/network/core/core.cpp b/src/network/core/core.cpp index 5c12cb2242..563deae963 100644 --- a/src/network/core/core.cpp +++ b/src/network/core/core.cpp @@ -13,7 +13,6 @@ #include "../../debug.h" #include "os_abstraction.h" #include "packet.h" -#include "../../string_func.h" #include "../../safeguards.h" @@ -48,20 +47,3 @@ void NetworkCoreShutdown() WSACleanup(); #endif } - -#if defined(_WIN32) -/** - * Return the string representation of the given error from the OS's network functions. - * @param error The error number (from \c NetworkGetLastError()). - * @return The error message, potentially an empty string but never \c nullptr. - */ -const char *NetworkGetErrorString(int error) -{ - static char buffer[512]; - if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), NULL) == 0) { - seprintf(buffer, lastof(buffer), "Unknown error %d", error); - } - return buffer; -} -#endif /* defined(_WIN32) */ diff --git a/src/network/core/game_info.h b/src/network/core/game_info.h index 4a93bb485d..988835e3c5 100644 --- a/src/network/core/game_info.h +++ b/src/network/core/game_info.h @@ -74,7 +74,6 @@ struct NetworkGameInfo : NetworkServerGameInfo { uint32 map_width; ///< Map width uint32 map_height; ///< Map height char server_name[NETWORK_NAME_LENGTH]; ///< Server name - char hostname[NETWORK_HOSTNAME_LENGTH]; ///< Hostname of the server (if any) char short_server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) (truncated) char server_revision[NETWORK_LONG_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) bool dedicated; ///< Is this a dedicated server? diff --git a/src/network/core/os_abstraction.cpp b/src/network/core/os_abstraction.cpp new file mode 100644 index 0000000000..e43775a5a5 --- /dev/null +++ b/src/network/core/os_abstraction.cpp @@ -0,0 +1,217 @@ +/* + * 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 os_abstraction.cpp OS specific implementations of functions of the OS abstraction layer for network stuff. + * + * The general idea is to have simple abstracting functions for things that + * require different implementations for different environments. + * In here the functions, and their documentation, are defined only once + * and the implementation contains the #ifdefs to change the implementation. + * Since Windows is usually different that is usually the first case, after + * that the behaviour is usually Unix/BSD-like with occasional variation. + */ + +#include "stdafx.h" +#include "os_abstraction.h" +#include "../../string_func.h" +#include + +#include "../../safeguards.h" + +/** + * Construct the network error with the given error code. + * @param error The error code. + */ +NetworkError::NetworkError(int error) : error(error) +{ +} + +/** + * Check whether this error describes that the operation would block. + * @return True iff the operation would block. + */ +bool NetworkError::WouldBlock() const +{ +#if defined(_WIN32) + return this->error == WSAEWOULDBLOCK; +#else + /* Usually EWOULDBLOCK and EAGAIN are the same, but sometimes they are not + * and the POSIX.1 specification states that either should be checked. */ + return this->error == EWOULDBLOCK || this->error == EAGAIN; +#endif +} + +/** + * Check whether this error describes a connection reset. + * @return True iff the connection is reset. + */ +bool NetworkError::IsConnectionReset() const +{ +#if defined(_WIN32) + return this->error == WSAECONNRESET; +#else + return this->error == ECONNRESET; +#endif +} + +/** + * Check whether this error describes a connect is in progress. + * @return True iff the connect is already in progress. + */ +bool NetworkError::IsConnectInProgress() const +{ +#if defined(_WIN32) + return this->error == WSAEWOULDBLOCK; +#else + return this->error == EINPROGRESS; +#endif +} + +/** + * Get the string representation of the error message. + * @return The string representation that will get overwritten by next calls. + */ +const char *NetworkError::AsString() const +{ + if (this->message.empty()) { +#if defined(_WIN32) + char buffer[512]; + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, this->error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), NULL) == 0) { + seprintf(buffer, lastof(buffer), "Unknown error %d", this->error); + } + this->message.assign(buffer); +#else + /* Make strerror thread safe by locking access to it. There is a thread safe strerror_r, however + * the non-POSIX variant is available due to defining _GNU_SOURCE meaning it is not portable. + * The problem with the non-POSIX variant is that it does not necessarily fill the buffer with + * the error message but can also return a pointer to a static bit of memory, whereas the POSIX + * variant always fills the buffer. This makes the behaviour too erratic to work with. */ + static std::mutex mutex; + std::lock_guard guard(mutex); + this->message.assign(strerror(this->error)); +#endif + } + return this->message.c_str(); +} + +/** + * Check whether an error was actually set. + * @return True iff an error was set. + */ +bool NetworkError::HasError() const +{ + return this->error != 0; +} + +/** + * Get the last network error. + * @return The network error. + */ +/* static */ NetworkError NetworkError::GetLast() +{ +#if defined(_WIN32) + return NetworkError(WSAGetLastError()); +#elif defined(__OS2__) + return NetworkError(sock_errno()); +#else + return NetworkError(errno); +#endif +} + + +/** + * Try to set the socket into non-blocking mode. + * @param d The socket to set the non-blocking more for. + * @return True if setting the non-blocking mode succeeded, otherwise false. + */ +bool SetNonBlocking(SOCKET d) +{ +#if defined(_WIN32) + u_long nonblocking = 1; + return ioctlsocket(d, FIONBIO, &nonblocking) == 0; +#elif defined __EMSCRIPTEN__ + return true; +#else + int nonblocking = 1; + return ioctl(d, FIONBIO, &nonblocking) == 0; +#endif +} + +/** + * Try to set the socket into blocking mode. + * @param d The socket to set the blocking more for. + * @return True if setting the blocking mode succeeded, otherwise false. + */ +bool SetBlocking(SOCKET d) +{ +#if defined(_WIN32) + u_long nonblocking = 0; + return ioctlsocket(d, FIONBIO, &nonblocking) == 0; +#elif defined __EMSCRIPTEN__ + return true; +#else + int nonblocking = 0; + return ioctl(d, FIONBIO, &nonblocking) == 0; +#endif +} + +/** + * Try to set the socket to not delay sending. + * @param d The socket to disable the delaying for. + * @return True if disabling the delaying succeeded, otherwise false. + */ +bool SetNoDelay(SOCKET d) +{ +#ifdef __EMSCRIPTEN__ + return true; +#else + int flags = 1; + /* The (const char*) cast is needed for windows */ + return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char *)&flags, sizeof(flags)) == 0; +#endif +} + +/** + * Try to shutdown the socket in one or both directions. + * @param d The socket to disable the delaying for. + * @param read Whether to shutdown the read direction. + * @param write Whether to shutdown the write direction. + * @param linger_timeout The socket linger timeout. + * @return True if successful + */ +bool ShutdownSocket(SOCKET d, bool read, bool write, uint linger_timeout) +{ + if (!read && !write) return true; +#ifdef _WIN32 + LINGER ln = { 1U, (uint16) linger_timeout }; +#else + struct linger ln = { 1, (int) linger_timeout }; +#endif + + setsockopt(d, SOL_SOCKET, SO_LINGER, (const char*)&ln, sizeof(ln)); + + int how = SD_BOTH; + if (!read) how = SD_SEND; + if (!write) how = SD_RECEIVE; + return shutdown(d, how) == 0; +} + +/** + * Get the error from a socket, if any. + * @param d The socket to get the error from. + * @return The errno on the socket. + */ +NetworkError GetSocketError(SOCKET d) +{ + int err; + socklen_t len = sizeof(err); + getsockopt(d, SOL_SOCKET, SO_ERROR, (char *)&err, &len); + + return NetworkError(err); +} diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h index 658088497d..ecbc6f3240 100644 --- a/src/network/core/os_abstraction.h +++ b/src/network/core/os_abstraction.h @@ -14,6 +14,26 @@ #ifndef NETWORK_CORE_OS_ABSTRACTION_H #define NETWORK_CORE_OS_ABSTRACTION_H +/** + * Abstraction of a network error where all implementation details of the + * error codes are encapsulated in this class and the abstraction layer. + */ +class NetworkError { +private: + int error; ///< The underlying error number from errno or WSAGetLastError. + mutable std::string message; ///< The string representation of the error (set on first call to #AsString). +public: + NetworkError(int error); + + bool HasError() const; + bool WouldBlock() const; + bool IsConnectionReset() const; + bool IsConnectInProgress() const; + const char *AsString() const; + + static NetworkError GetLast(); +}; + /* Include standard stuff per OS */ /* Windows stuff */ @@ -23,21 +43,6 @@ #include #include -/** - * Get the last error code from any of the OS's network functions. - * What it returns and when it is reset, is implementation defined. - * @return The last error code. - */ -#define NetworkGetLastError() WSAGetLastError() -#undef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#undef ECONNRESET -#define ECONNRESET WSAECONNRESET -#undef EINPROGRESS -#define EINPROGRESS WSAEWOULDBLOCK - -const char *NetworkGetErrorString(int error); - /* Windows has some different names for some types */ typedef unsigned long in_addr_t; @@ -74,10 +79,7 @@ typedef unsigned long in_addr_t; # endif # define SOCKET int # define INVALID_SOCKET -1 -# define ioctlsocket ioctl # define closesocket close -# define NetworkGetLastError() (errno) -# define NetworkGetErrorString(error) (strerror(error)) # define SD_RECEIVE SHUT_RD # define SD_SEND SHUT_WR # define SD_BOTH SHUT_RDWR @@ -128,10 +130,7 @@ typedef unsigned long in_addr_t; #if defined(__OS2__) # define SOCKET int # define INVALID_SOCKET -1 -# define ioctlsocket ioctl # define closesocket close -# define NetworkGetLastError() (sock_errno()) -# define NetworkGetErrorString(error) (strerror(error)) # define SD_RECEIVE SHUT_RD # define SD_SEND SHUT_WR # define SD_BOTH SHUT_RDWR @@ -206,105 +205,11 @@ static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address } #endif -/** - * Return the string representation of the last error from the OS's network functions. - * @return The error message, potentially an empty string but never \c nullptr. - */ -static inline const char *NetworkGetLastErrorString() -{ - return NetworkGetErrorString(NetworkGetLastError()); -} - -/** - * Try to set the socket into non-blocking mode. - * @param d The socket to set the non-blocking more for. - * @return True if setting the non-blocking mode succeeded, otherwise false. - */ -static inline bool SetNonBlocking(SOCKET d) -{ -#ifdef __EMSCRIPTEN__ - return true; -#else -# ifdef _WIN32 - u_long nonblocking = 1; -# else - int nonblocking = 1; -# endif - return ioctlsocket(d, FIONBIO, &nonblocking) == 0; -#endif -} - -/** - * Try to set the socket into blocking mode. - * @param d The socket to set the blocking more for. - * @return True if setting the blocking mode succeeded, otherwise false. - */ -static inline bool SetBlocking(SOCKET d) -{ -#ifdef _WIN32 - u_long nonblocking = 0; -#else - int nonblocking = 0; -#endif - return ioctlsocket(d, FIONBIO, &nonblocking) == 0; -} - -/** - * Try to set the socket to not delay sending. - * @param d The socket to disable the delaying for. - * @return True if disabling the delaying succeeded, otherwise false. - */ -static inline bool SetNoDelay(SOCKET d) -{ -#ifdef __EMSCRIPTEN__ - return true; -#else - /* XXX should this be done at all? */ - int b = 1; - /* The (const char*) cast is needed for windows */ - return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0; -#endif -} - - -/** - * Try to shutdown the socket in one or both directions. - * @param d The socket to disable the delaying for. - * @param read Whether to shutdown the read direction. - * @param write Whether to shutdown the write direction. - * @param linger_timeout The socket linger timeout. - * @return True if successful - */ -static inline bool ShutdownSocket(SOCKET d, bool read, bool write, uint linger_timeout) -{ - if (!read && !write) return true; -#ifdef _WIN32 - LINGER ln = { 1U, (uint16) linger_timeout }; -#else - struct linger ln = { 1, (int) linger_timeout }; -#endif - - setsockopt(d, SOL_SOCKET, SO_LINGER, (const char*)&ln, sizeof(ln)); - - int how = SD_BOTH; - if (!read) how = SD_SEND; - if (!write) how = SD_RECEIVE; - return shutdown(d, how) == 0; -} - -/** - * Get the error from a socket, if any. - * @param d The socket to get the error from. - * @return The errno on the socket. - */ -static inline int GetSocketError(SOCKET d) -{ - int err; - socklen_t len = sizeof(err); - getsockopt(d, SOL_SOCKET, SO_ERROR, (char *)&err, &len); - - return err; -} +bool SetNonBlocking(SOCKET d); +bool SetBlocking(SOCKET d); +bool SetNoDelay(SOCKET d); +bool ShutdownSocket(SOCKET d, bool read, bool write, uint linger_timeout); +NetworkError GetSocketError(SOCKET d); /* Make sure these structures have the size we expect them to be */ static_assert(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes. diff --git a/src/network/core/tcp.cpp b/src/network/core/tcp.cpp index 62f4e7c75a..322631190d 100644 --- a/src/network/core/tcp.cpp +++ b/src/network/core/tcp.cpp @@ -114,11 +114,11 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down) Packet *p = this->packet_queue.front().get(); res = p->TransferOut(send, this->sock, 0); if (res == -1) { - int err = NetworkGetLastError(); - if (err != EWOULDBLOCK) { + NetworkError err = NetworkError::GetLast(); + if (!err.WouldBlock()) { /* Something went wrong.. close client! */ if (!closing_down) { - DEBUG(net, 0, "send failed with error %s", NetworkGetErrorString(err)); + DEBUG(net, 0, "send failed with error %s", err.AsString()); this->CloseConnection(); } return SPS_CLOSED; @@ -165,10 +165,10 @@ std::unique_ptr NetworkTCPSocketHandler::ReceivePacket() while (p->RemainingBytesToTransfer() != 0) { res = p->TransferIn(recv, this->sock, 0); if (res == -1) { - int err = NetworkGetLastError(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (ECONNRESET is connection reset by peer) */ - if (err != ECONNRESET) DEBUG(net, 0, "recv failed with error %s", NetworkGetErrorString(err)); + NetworkError err = NetworkError::GetLast(); + if (!err.WouldBlock()) { + /* Something went wrong... */ + if (!err.IsConnectionReset()) DEBUG(net, 0, "recv failed with error %s", err.AsString()); this->CloseConnection(); return nullptr; } @@ -194,10 +194,10 @@ std::unique_ptr NetworkTCPSocketHandler::ReceivePacket() while (p->RemainingBytesToTransfer() != 0) { res = p->TransferIn(recv, this->sock, 0); if (res == -1) { - int err = NetworkGetLastError(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (ECONNRESET is connection reset by peer) */ - if (err != ECONNRESET) DEBUG(net, 0, "recv failed with error %s", NetworkGetErrorString(err)); + NetworkError err = NetworkError::GetLast(); + if (!err.WouldBlock()) { + /* Something went wrong... */ + if (!err.IsConnectionReset()) DEBUG(net, 0, "recv failed with error %s", err.AsString()); this->CloseConnection(); return nullptr; } diff --git a/src/network/core/tcp_game.cpp b/src/network/core/tcp_game.cpp index f31189fe9d..c4c911620e 100644 --- a/src/network/core/tcp_game.cpp +++ b/src/network/core/tcp_game.cpp @@ -27,8 +27,8 @@ static const char* _packet_game_type_names[] { "SERVER_ERROR", "CLIENT_COMPANY_INFO", "SERVER_COMPANY_INFO", - "CLIENT_GAME_INFO", "SERVER_GAME_INFO", + "CLIENT_GAME_INFO", "SERVER_GAME_INFO_EXTENDED", "SERVER_CHECK_NEWGRFS", "CLIENT_NEWGRFS_CHECKED", diff --git a/src/network/core/tcp_game.h b/src/network/core/tcp_game.h index 61dc5d31f9..8618574d3d 100644 --- a/src/network/core/tcp_game.h +++ b/src/network/core/tcp_game.h @@ -44,8 +44,8 @@ enum PacketGameType { PACKET_SERVER_COMPANY_INFO, ///< Information about a single company. /* Packets used to get the game info. */ - PACKET_CLIENT_GAME_INFO, ///< Request information about the server. PACKET_SERVER_GAME_INFO, ///< Information about the server. + PACKET_CLIENT_GAME_INFO, ///< Request information about the server. /* * Packets after here assume that the client diff --git a/src/network/core/tcp_http.cpp b/src/network/core/tcp_http.cpp index 39283ce407..8104512f44 100644 --- a/src/network/core/tcp_http.cpp +++ b/src/network/core/tcp_http.cpp @@ -12,7 +12,7 @@ #include "../../stdafx.h" #include "../../debug.h" #include "../../rev.h" -#include "../network_func.h" +#include "../network_internal.h" #include "game_info.h" #include "tcp_http.h" @@ -203,11 +203,7 @@ int NetworkHTTPSocketHandler::HandleHeader() *url = '\0'; - /* Fetch the hostname, and possible port number. */ - const char *port = nullptr; - ParseConnectionString(&port, hname); - - NetworkAddress address(hname, port == nullptr ? 80 : atoi(port)); + NetworkAddress address = ParseConnectionString(hname, 80); /* Restore the URL. */ *url = '/'; @@ -229,10 +225,10 @@ int NetworkHTTPSocketHandler::Receive() for (;;) { ssize_t res = recv(this->sock, (char *)this->recv_buffer + this->recv_pos, lengthof(this->recv_buffer) - this->recv_pos, 0); if (res == -1) { - int err = NetworkGetLastError(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (ECONNRESET is connection reset by peer) */ - if (err != ECONNRESET) DEBUG(net, 0, "recv failed with error %s", NetworkGetErrorString(err)); + NetworkError err = NetworkError::GetLast(); + if (!err.WouldBlock()) { + /* Something went wrong... */ + if (!err.IsConnectionReset()) DEBUG(net, 0, "recv failed with error %s", err.AsString()); return -1; } /* Connection would block, so stop for now */ diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h index 168f49f947..e23ecae707 100644 --- a/src/network/core/tcp_listen.h +++ b/src/network/core/tcp_listen.h @@ -64,7 +64,7 @@ public: DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), entry.c_str()); if (p.TransferOut(send, s, 0) < 0) { - DEBUG(net, 0, "send failed with error %s", NetworkGetLastErrorString()); + DEBUG(net, 0, "send failed with error %s", NetworkError::GetLast().AsString()); } closesocket(s); break; @@ -81,7 +81,7 @@ public: p.PrepareToSend(); if (p.TransferOut(send, s, 0) < 0) { - DEBUG(net, 0, "send failed with error %s", NetworkGetLastErrorString()); + DEBUG(net, 0, "send failed with error %s", NetworkError::GetLast().AsString()); } closesocket(s); @@ -151,7 +151,7 @@ public: if (sockets.size() == 0) { DEBUG(net, 0, "[server] could not start network: could not create listening socket"); - NetworkError(STR_NETWORK_ERROR_SERVER_START); + ShowNetworkError(STR_NETWORK_ERROR_SERVER_START); return false; } diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp index 646e28a654..8d54d59d30 100644 --- a/src/network/core/udp.cpp +++ b/src/network/core/udp.cpp @@ -127,7 +127,7 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a /* Enable broadcast */ unsigned long val = 1; if (setsockopt(s.second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { - DEBUG(net, 1, "[udp] setting broadcast failed with: %s", NetworkGetLastErrorString()); + DEBUG(net, 1, "[udp] setting broadcast failed with: %s", NetworkError::GetLast().AsString()); } } @@ -136,7 +136,7 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a DEBUG(net, 7, "[udp] sendto(%s)", NetworkAddressDumper().GetAddressAsString(&send)); /* Check for any errors, but ignore it otherwise */ - if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %s", NetworkAddressDumper().GetAddressAsString(&send), NetworkGetLastErrorString()); + if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %s", NetworkAddressDumper().GetAddressAsString(&send), NetworkError::GetLast().AsString()); if (!all) break; } diff --git a/src/network/network.cpp b/src/network/network.cpp index be4aec9ce0..e7b8972251 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -306,7 +306,7 @@ uint NetworkCalculateLag(const NetworkClientSocket *cs) /* There was a non-recoverable error, drop back to the main menu with a nice * error */ -void NetworkError(StringID error_string) +void ShowNetworkError(StringID error_string) { _switch_mode = SM_MENU; ShowErrorMessage(error_string, INVALID_STRING_ID, WL_CRITICAL); @@ -476,14 +476,14 @@ static void CheckPauseOnJoin() } /** - * Converts a string to ip/port - * Format: IP:port + * Converts a string to ip/port/company + * Format: IP:port#company * * connection_string will be re-terminated to separate out the hostname, port will * be set to the port strings given by the user, inside the memory area originally - * occupied by connection_string. + * occupied by connection_string. Similar for company, if set. */ -void ParseConnectionString(const char **port, char *connection_string) +void ParseFullConnectionString(const char **company, const char **port, char *connection_string) { bool ipv6 = (strchr(connection_string, ':') != strrchr(connection_string, ':')); for (char *p = connection_string; *p != '\0'; p++) { @@ -496,6 +496,12 @@ void ParseConnectionString(const char **port, char *connection_string) ipv6 = false; break; + case '#': + if (company == nullptr) continue; + *company = p + 1; + *p = '\0'; + break; + case ':': if (ipv6) break; *port = p + 1; @@ -506,38 +512,48 @@ void ParseConnectionString(const char **port, char *connection_string) } /** - * Converts a string to ip/port/company - * Format: IP:port#company + * Convert a string containing either "hostname" or "hostname:ip" to a + * NetworkAddress. * - * connection_string will be re-terminated to separate out the hostname, and company and port will - * be set to the company and port strings given by the user, inside the memory area originally - * occupied by connection_string. + * @param connection_string The string to parse. + * @param default_port The default port to set port to if not in connection_string. + * @return A valid NetworkAddress of the parsed information. */ -void ParseGameConnectionString(const char **company, const char **port, char *connection_string) +NetworkAddress ParseConnectionString(const std::string &connection_string, int default_port) { - bool ipv6 = (strchr(connection_string, ':') != strrchr(connection_string, ':')); - for (char *p = connection_string; *p != '\0'; p++) { - switch (*p) { - case '[': - ipv6 = true; - break; + char internal_connection_string[NETWORK_HOSTNAME_PORT_LENGTH]; + strecpy(internal_connection_string, connection_string.c_str(), lastof(internal_connection_string)); - case ']': - ipv6 = false; - break; + const char *port = nullptr; + ParseFullConnectionString(nullptr, &port, internal_connection_string); - case '#': - *company = p + 1; - *p = '\0'; - break; + int rport = port != nullptr ? atoi(port) : default_port; + return NetworkAddress(internal_connection_string, rport); +} - case ':': - if (ipv6) break; - *port = p + 1; - *p = '\0'; - break; - } - } +/** + * Convert a string containing either "hostname" or "hostname:ip" to a + * NetworkAddress, where the string can be postfixed with "#company" to + * indicate the requested company. + * + * @param company Pointer to the company variable to set iff indicted. + * @param connection_string The string to parse. + * @param default_port The default port to set port to if not in connection_string. + * @return A valid NetworkAddress of the parsed information. + */ +NetworkAddress ParseGameConnectionString(CompanyID *company, const std::string &connection_string, int default_port) +{ + char internal_connection_string[NETWORK_HOSTNAME_PORT_LENGTH + 4]; // 4 extra for the "#" and company + strecpy(internal_connection_string, connection_string.c_str(), lastof(internal_connection_string)); + + const char *port_s = nullptr; + const char *company_s = nullptr; + ParseFullConnectionString(&company_s, &port_s, internal_connection_string); + + if (company_s != nullptr) *company = (CompanyID)atoi(company_s); + + int port = port_s != nullptr ? atoi(port_s) : default_port; + return NetworkAddress(internal_connection_string, port); } /** @@ -619,8 +635,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 { @@ -630,45 +649,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 +/** + * 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. */ -void NetworkAddServer(const char *b) + * as manually added. + * @param connection_string The IP:port of the server to add. + * @return The entry on the game list. + */ +NetworkGameList *NetworkAddServer(const std::string &connection_string) { - if (*b != '\0') { - const char *port = nullptr; - char host[NETWORK_HOSTNAME_LENGTH]; - uint16 rport; + if (connection_string.empty()) return nullptr; - strecpy(host, b, lastof(host)); + NetworkAddress address = ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT); - strecpy(_settings_client.network.connect_to_ip, b, lastof(_settings_client.network.connect_to_ip)); - rport = 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; - ParseConnectionString(&port, host); - if (port != nullptr) rport = atoi(port); - - NetworkUDPQueryServer(NetworkAddress(host, rport), true); + NetworkRebuildHostList(); + UpdateNetworkGameWindow(); } + + NetworkTCPQueryServer(address); + + return item; } /** @@ -707,41 +734,99 @@ public: void OnFailure() override { - NetworkError(STR_NETWORK_ERROR_NOCONNECTION); + ShowNetworkError(STR_NETWORK_ERROR_NOCONNECTION); } void OnConnect(SOCKET s) override { _networking = true; - new ClientNetworkGameSocketHandler(s); + new ClientNetworkGameSocketHandler(s, this->address); IConsoleCmdExec("exec scripts/on_client.scr 0"); NetworkClient_Connected(); } }; - -/* Used by clients, to connect to a server */ -void NetworkClientConnectGame(const char *hostname, uint16 port, CompanyID join_as, const char *join_server_password, const char *join_company_password) +/** + * Join a client to the server at with the given connection string. + * The default for the passwords is \c nullptr. When the server or company needs a + * password and none is given, the user is asked to enter the password in the GUI. + * This function will return false whenever some information required to join is not + * correct such as the company number or the client's name, or when there is not + * networking avalabile at all. If the function returns false the connection with + * the existing server is not disconnected. + * It will return true when it starts the actual join process, i.e. when it + * actually shows the join status window. + * + * @param connection_string The IP address, port and company number to join as. + * @param default_company The company number to join as when none is given. + * @param join_server_password The password for the server. + * @param join_company_password The password for the company. + * @return Whether the join has started. + */ +bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const char *join_server_password, const char *join_company_password) { - if (!_network_available) return; + CompanyID join_as = default_company; + NetworkAddress address = ParseGameConnectionString(&join_as, connection_string, NETWORK_DEFAULT_PORT); - if (port == 0) return; + if (join_as != COMPANY_NEW_COMPANY && join_as != COMPANY_SPECTATOR) { + join_as--; + if (join_as >= MAX_COMPANIES) { + return false; + } + } - if (!NetworkValidateClientName()) return; + return NetworkClientConnectGame(address, join_as, join_server_password, join_company_password); +} + +/** + * Join a client to the server at the given address. + * See the overloaded NetworkClientConnectGame for more details. + * + * @param address The network address of the server to join to. + * @param join_as The company number to join as. + * @param join_server_password The password for the server. + * @param join_company_password The password for the company. + * @return Whether the join has started. + */ +bool NetworkClientConnectGame(NetworkAddress &address, CompanyID join_as, const char *join_server_password, const char *join_company_password) +{ + if (!_network_available) return false; + if (!NetworkValidateClientName()) return false; + + _network_join.address = address; + _network_join.company = join_as; + _network_join.server_password = join_server_password; + _network_join.company_password = join_company_password; - strecpy(_settings_client.network.last_host, hostname, lastof(_settings_client.network.last_host)); - _settings_client.network.last_port = port; - _network_join_as = join_as; - _network_join_server_password = join_server_password; - _network_join_company_password = join_company_password; + if (_game_mode == GM_MENU) { + /* From the menu we can immediately continue with the actual join. */ + NetworkClientJoinGame(); + } else { + /* When already playing a game, first go back to the main menu. This + * disconnects the user from the current game, meaning we can safely + * load in the new. After all, there is little point in continueing to + * play on a server if we are connecting to another one. + */ + _switch_mode = SM_JOIN_GAME; + } + return true; +} +/** + * Actually perform the joining to the server. Use #NetworkClientConnectGame + * when you want to connect to a specific server/company. This function + * assumes _network_join is already fully set up. + */ +void NetworkClientJoinGame() +{ NetworkDisconnect(); NetworkInitialize(); + strecpy(_settings_client.network.last_joined, _network_join.address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined)); _network_join_status = NETWORK_JOIN_STATUS_CONNECTING; ShowJoinStatusWindow(); - new TCPClientConnecter(NetworkAddress(hostname, port)); + new TCPClientConnecter(_network_join.address); } static void NetworkInitGameInfo() @@ -1126,13 +1211,14 @@ static void NetworkGenerateServerId() seprintf(_settings_client.network.network_id, lastof(_settings_client.network.network_id), "%s", hex_output); } -void NetworkStartDebugLog(const char *hostname, uint16 port) +void NetworkStartDebugLog(const std::string &connection_string) { extern SOCKET _debug_socket; // Comes from debug.c - DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", hostname, port); + NetworkAddress address = ParseConnectionString(connection_string, NETWORK_DEFAULT_DEBUGLOG_PORT); + + DEBUG(net, 0, "Redirecting DEBUG() to %s", address.GetAddressAsString().c_str()); - NetworkAddress address(hostname, port); SOCKET s = address.Connect(); if (s == INVALID_SOCKET) { DEBUG(net, 0, "Failed to open socket for redirection DEBUG()"); @@ -1180,9 +1266,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 fcd4e327c8..02dc58d36f 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -150,9 +150,9 @@ 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), token (0), status (STATUS_INACTIVE) +ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler (SOCKET s, NetworkAddress address) + : NetworkGameSocketHandler(s), + address(address), savegame(nullptr), token(0), status(STATUS_INACTIVE) { assert(ClientNetworkGameSocketHandler::my_client == nullptr); ClientNetworkGameSocketHandler::my_client = this; @@ -324,7 +324,7 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res) #endif if (_sync_state_checksum != _state_checksum.state) info.flags |= DesyncExtraInfo::DEIF_STATE; - NetworkError(STR_NETWORK_ERROR_DESYNC); + ShowNetworkError(STR_NETWORK_ERROR_DESYNC); DEBUG(desync, 1, "sync_err: date{%08x; %02x; %02x} {%x, " OTTD_PRINTFHEX64 "} != {%x, " OTTD_PRINTFHEX64 "}" , _date, _date_fract, _tick_skip_counter, _sync_seed_1, _sync_state_checksum, _random.state[0], _state_checksum.state); DEBUG(net, 0, "Sync error detected!"); @@ -389,13 +389,8 @@ static uint8 _network_server_max_companies; /** Maximum number of spectators of the currently joined server. */ static uint8 _network_server_max_spectators; -/** Who would we like to join as. */ -CompanyID _network_join_as; - -/** Login password from -p argument */ -const char *_network_join_server_password = nullptr; -/** Company password from -P argument */ -const char *_network_join_company_password = nullptr; +/** Information about the game to join to. */ +NetworkJoinInfo _network_join; /** Make sure the server ID length is the same as a md5 hash. */ static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1); @@ -408,11 +403,9 @@ 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; Packet *p = new Packet(PACKET_CLIENT_GAME_INFO); p->Send_uint32(FIND_SERVER_EXTENDED_TOKEN); @@ -421,7 +414,13 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendInformationQuery() p->Send_uint16(0); // version my_client->SendPacket(p); - 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; } @@ -437,7 +436,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendJoin() p->Send_string(_openttd_revision); p->Send_uint32(_openttd_newgrf_version); p->Send_string(_settings_client.network.client_name); // Client name - p->Send_uint8 (_network_join_as); // PlayAs + p->Send_uint8 (_network_join.company); // PlayAs p->Send_uint8 (0); // Used to be language my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; @@ -698,9 +697,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); @@ -711,6 +714,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. */ @@ -870,6 +875,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 */ @@ -933,7 +947,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSW p->Recv_string(_password_server_id, sizeof(_password_server_id)); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; - const char *password = _network_join_server_password; + const char *password = _network_join.server_password; if (!StrEmpty(password)) { return SendGamePassword(password); } @@ -952,7 +966,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA p->Recv_string(_password_server_id, sizeof(_password_server_id)); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; - const char *password = _network_join_company_password; + const char *password = _network_join.company_password; if (!StrEmpty(password)) { return SendCompanyPassword(password); } @@ -1077,10 +1091,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet /* New company/spectator (invalid company) or company we want to join is not active * Switch local company to spectator and await the server's judgement */ - if (_network_join_as == COMPANY_NEW_COMPANY || !Company::IsValidID(_network_join_as)) { + if (_network_join.company == COMPANY_NEW_COMPANY || !Company::IsValidID(_network_join.company)) { SetLocalCompany(COMPANY_SPECTATOR); - if (_network_join_as != COMPANY_SPECTATOR) { + if (_network_join.company != COMPANY_SPECTATOR) { /* We have arrived and ready to start playing; send a command to make a new company; * the server will give us a client-id and let us in */ _network_join_status = NETWORK_JOIN_STATUS_REGISTERING; @@ -1089,7 +1103,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet } } else { /* take control over an existing company */ - SetLocalCompany(_network_join_as); + SetLocalCompany(_network_join.company); } return NETWORK_RECV_STATUS_OKAY; @@ -1420,6 +1434,7 @@ const char *ClientNetworkGameSocketHandler::GetServerStatusName(ServerStatus sta { static const char* _server_status_names[] { "INACTIVE", + "GAME_INFO", "COMPANY_INFO", "JOIN", "NEWGRFS_CHECK", diff --git a/src/network/network_client.h b/src/network/network_client.h index fd1ad6a88a..d1898eb016 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 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. @@ -84,7 +86,7 @@ protected: static NetworkRecvStatus SendMapOk(); void CheckConnection(); public: - ClientNetworkGameSocketHandler(SOCKET s); + ClientNetworkGameSocketHandler(SOCKET s, NetworkAddress address); ~ClientNetworkGameSocketHandler(); NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override; @@ -92,7 +94,7 @@ public: std::string GetDebugInfo() const override; - static NetworkRecvStatus SendInformationQuery(); + static NetworkRecvStatus SendInformationQuery(bool request_company_info); static NetworkRecvStatus SendJoin(); static NetworkRecvStatus SendCommand(const CommandPacket *cp); @@ -127,9 +129,15 @@ typedef ClientNetworkGameSocketHandler MyClient; void NetworkClient_Connected(); void NetworkClientSetCompanyPassword(const char *password); -extern CompanyID _network_join_as; +/** Information required to join a server. */ +struct NetworkJoinInfo { + NetworkJoinInfo() : company(COMPANY_SPECTATOR), server_password(nullptr), company_password(nullptr) {} + NetworkAddress address; ///< The address of the server to join. + CompanyID company; ///< The company to join. + const char *server_password; ///< The password of the server to join. + const char *company_password; ///< The password of the company to join. +}; -extern const char *_network_join_server_password; -extern const char *_network_join_company_password; +extern NetworkJoinInfo _network_join; #endif /* NETWORK_CLIENT_H */ diff --git a/src/network/network_func.h b/src/network/network_func.h index 6e890cf289..aff5adfe97 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -45,14 +45,14 @@ void NetworkReboot(); void NetworkDisconnect(bool blocking = false, bool close_admins = true); void NetworkGameLoop(); void NetworkBackgroundLoop(); -void ParseConnectionString(const char **port, char *connection_string); -void ParseGameConnectionString(const char **company, const char **port, char *connection_string); -void NetworkStartDebugLog(const char *hostname, uint16 port); +void ParseFullConnectionString(const char **company, const char **port, char *connection_string); +void NetworkStartDebugLog(const std::string &connection_string); void NetworkPopulateCompanyStats(NetworkCompanyStats *stats); void NetworkUpdateClientInfo(ClientID client_id); void NetworkClientsToSpectators(CompanyID cid); -void NetworkClientConnectGame(const char *hostname, uint16 port, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr); +bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const char *join_server_password = nullptr, const char *join_company_password = nullptr); +void NetworkClientJoinGame(); void NetworkClientRequestMove(CompanyID company, const char *pass = ""); void NetworkClientSendRcon(const char *password, const char *command); void NetworkClientSendSettingsPassword(const char *password); diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index 7994b38400..f0e02994be 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -51,7 +51,6 @@ static void NetworkGameListHandleDelayedInsert() ClearGRFConfigList(&item->info.grfconfig); memset(&item->info, 0, sizeof(item->info)); strecpy(item->info.server_name, ins_item->info.server_name, lastof(item->info.server_name)); - strecpy(item->info.hostname, ins_item->info.hostname, lastof(item->info.hostname)); item->online = false; } item->manually |= ins_item->manually; @@ -70,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; @@ -96,7 +86,6 @@ NetworkGameList *NetworkGameListAddItem(NetworkAddress address) } else { prev_item->next = item; } - DEBUG(net, 4, "[gamelist] added server to list"); UpdateNetworkGameWindow(); @@ -152,7 +141,7 @@ void NetworkGameListRequery() /* item gets mostly zeroed by NetworkUDPQueryServer */ uint8 retries = item->retries; - NetworkUDPQueryServer(NetworkAddress(item->address)); + NetworkUDPQueryServer(item->address); item->retries = (retries >= REFRESH_GAMEINFO_X_REQUERIES) ? 0 : retries; } } diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index fcb38929a9..af4b699200 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -489,9 +489,8 @@ public: EM_ASM(if (window["openttd_server_list"]) openttd_server_list()); #endif - this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_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); @@ -662,9 +661,8 @@ public: DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version y += FONT_HEIGHT_NORMAL; - char network_addr_buffer[NETWORK_HOSTNAME_LENGTH + 6 + 7]; - sel->address.GetAddressAsString(network_addr_buffer, lastof(network_addr_buffer)); - SetDParamStr(0, network_addr_buffer); + std::string address = sel->address.GetAddressAsString(); + SetDParamStr(0, address.c_str()); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address y += FONT_HEIGHT_NORMAL; @@ -753,7 +751,7 @@ public: ShowQueryString( STR_JUST_RAW_STRING, STR_NETWORK_SERVER_LIST_ENTER_IP, - NETWORK_HOSTNAME_LENGTH, // maximum number of characters including '\0' + NETWORK_HOSTNAME_PORT_LENGTH, // maximum number of characters including '\0' this, CS_ALPHANUMERAL, QSF_ACCEPT_UNCHANGED); break; @@ -763,14 +761,12 @@ public: case WID_NG_JOIN: // Join Game if (this->server != nullptr) { - seprintf(_settings_client.network.last_host, lastof(_settings_client.network.last_host), "%s", this->server->address.GetHostname()); - _settings_client.network.last_port = this->server->address.GetPort(); ShowNetworkLobbyWindow(this->server); } 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 @@ -845,7 +841,10 @@ public: void OnQueryTextFinished(char *str) override { - if (!StrEmpty(str)) NetworkAddServer(str); + if (!StrEmpty(str)) { + strecpy(_settings_client.network.connect_to_ip, str, lastof(_settings_client.network.connect_to_ip)); + NetworkAddServer(str); + } } void OnResize() override @@ -988,7 +987,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); } } @@ -1487,22 +1486,22 @@ struct NetworkLobbyWindow : public Window { case WID_NL_JOIN: // Join company /* Button can be clicked only when it is enabled. */ - NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, this->company); + NetworkClientConnectGame(this->server->address, this->company); break; case WID_NL_NEW: // New company - NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, COMPANY_NEW_COMPANY); + NetworkClientConnectGame(this->server->address, COMPANY_NEW_COMPANY); break; case WID_NL_SPECTATE: // Spectate game - NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, COMPANY_SPECTATOR); + NetworkClientConnectGame(this->server->address, COMPANY_SPECTATOR); break; case WID_NL_REFRESH: // Refresh /* Clear the information so removed companies don't remain */ for (auto &company : this->company_info) company = {}; - NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); + NetworkTCPQueryServer(this->server->address, true); break; } } @@ -1570,7 +1569,9 @@ static void ShowNetworkLobbyWindow(NetworkGameList *ngl) DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START); DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); - NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); + strecpy(_settings_client.network.last_joined, ngl->address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined)); + + 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 f1c591ff40..c7a5eb7402 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -94,10 +94,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(); @@ -119,11 +119,15 @@ void NetworkExecuteLocalCommandQueue(); void NetworkFreeLocalCommandQueue(); void NetworkSyncCommandQueue(NetworkClientSocket *cs); -void NetworkError(StringID error_string); +void ShowNetworkError(StringID error_string); void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const char *name, const char *str = "", NetworkTextMessageData data = NetworkTextMessageData()); uint NetworkCalculateLag(const NetworkClientSocket *cs); StringID GetNetworkErrorMsg(NetworkErrorCode err); bool NetworkFindName(char *new_name, const char *last); const char *GenerateCompanyPasswordHash(const char *password, const char *password_server_id, uint32 password_game_seed); +bool NetworkClientConnectGame(NetworkAddress &address, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr); +NetworkAddress ParseConnectionString(const std::string &connection_string, int default_port); +NetworkAddress ParseGameConnectionString(CompanyID *company, const std::string &connection_string, int default_port); + #endif /* NETWORK_INTERNAL_H */ diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index cc223323c9..23e95412a1 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -111,7 +111,6 @@ static void DoNetworkUDPQueryServer(NetworkAddress &address, bool needs_mutex, b /* Clear item in gamelist */ NetworkGameList *item = CallocT(1); address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name)); - strecpy(item->info.hostname, address.GetHostname(), lastof(item->info.hostname)); item->address = address; item->manually = manually; NetworkGameListAddItemDelayed(item); @@ -453,10 +452,6 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE_Common(Packet *p, Ne if (in_request_count > 0) flush_request(); } - if (item->info.hostname[0] == '\0') { - seprintf(item->info.hostname, lastof(item->info.hostname), "%s", client_addr->GetHostname()); - } - if (client_addr->GetAddress()->ss_family == AF_INET6) { strecat(item->info.server_name, " (IPv6)", lastof(item->info.server_name)); } diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index a374264859..c0898f1936 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -31,62 +31,29 @@ bool _sprite_group_resolve_check_veh_check = false; bool _sprite_group_resolve_check_veh_curvature_check = false; -struct WagonOverride { - EngineID *train_id; - uint trains; - CargoID cargo; - const SpriteGroup *group; -}; - void SetWagonOverrideSprites(EngineID engine, CargoID cargo, const SpriteGroup *group, EngineID *train_id, uint trains) { Engine *e = Engine::Get(engine); - WagonOverride *wo; assert(cargo < NUM_CARGO + 2); // Include CT_DEFAULT and CT_PURCHASE pseudo cargoes. - e->overrides_count++; - e->overrides = ReallocT(e->overrides, e->overrides_count); - - wo = &e->overrides[e->overrides_count - 1]; + WagonOverride *wo = &e->overrides.emplace_back(); wo->group = group; wo->cargo = cargo; - wo->trains = trains; - wo->train_id = MallocT(trains); - memcpy(wo->train_id, train_id, trains * sizeof *train_id); + wo->engines.assign(train_id, train_id + trains); } const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, EngineID overriding_engine) { const Engine *e = Engine::Get(engine); - for (uint i = 0; i < e->overrides_count; i++) { - const WagonOverride *wo = &e->overrides[i]; - - if (wo->cargo != cargo && wo->cargo != CT_DEFAULT) continue; - - for (uint j = 0; j < wo->trains; j++) { - if (wo->train_id[j] == overriding_engine) return wo->group; - } + for (const WagonOverride &wo : e->overrides) { + if (wo.cargo != cargo && wo.cargo != CT_DEFAULT) continue; + if (std::find(wo.engines.begin(), wo.engines.end(), overriding_engine) != wo.engines.end()) return wo.group; } return nullptr; } -/** - * Unload all wagon override sprite groups. - */ -void UnloadWagonOverrides(Engine *e) -{ - for (uint i = 0; i < e->overrides_count; i++) { - WagonOverride *wo = &e->overrides[i]; - free(wo->train_id); - } - free(e->overrides); - e->overrides_count = 0; - e->overrides = nullptr; -} - - void SetCustomEngineSprites(EngineID engine, byte cargo, const SpriteGroup *group) { Engine *e = Engine::Get(engine); @@ -1623,8 +1590,8 @@ void AnalyseEngineCallbacks() for (uint i = 0; i < NUM_CARGO + 2; i++) { process_sg(e->grf_prop.spritegroup[i]); } - for (uint i = 0; i < e->overrides_count; i++) { - process_sg(e->overrides[i].group); + for (const WagonOverride &wo : e->overrides) { + process_sg(wo.group); } e->callbacks_used = callbacks_used; e->cb36_properties_used = cb36_properties_used; diff --git a/src/newgrf_engine.h b/src/newgrf_engine.h index 3442f98875..2ded4aea5f 100644 --- a/src/newgrf_engine.h +++ b/src/newgrf_engine.h @@ -116,8 +116,6 @@ enum VehicleTrigger { }; void TriggerVehicle(Vehicle *veh, VehicleTrigger trigger); -void UnloadWagonOverrides(Engine *e); - void AlterVehicleListOrder(EngineID engine, uint target); void CommitVehicleListOrderChanges(); diff --git a/src/openttd.cpp b/src/openttd.cpp index 690e5efe43..426b3f3db3 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -623,29 +623,10 @@ struct AfterNewGRFScan : NewGRFScanCallback { if (_switch_mode != SM_NONE) MakeNewgameSettingsLive(); if (_network_available && network_conn != nullptr) { - const char *port = nullptr; - const char *company = nullptr; - uint16 rport = NETWORK_DEFAULT_PORT; - CompanyID join_as = COMPANY_NEW_COMPANY; - - ParseGameConnectionString(&company, &port, network_conn); - - if (company != nullptr) { - join_as = (CompanyID)atoi(company); - - if (join_as != COMPANY_SPECTATOR) { - join_as--; - if (join_as >= MAX_COMPANIES) { - delete this; - return; - } - } - } - if (port != nullptr) rport = atoi(port); - LoadIntroGame(); _switch_mode = SM_NONE; - NetworkClientConnectGame(network_conn, rport, join_as, join_server_password, join_company_password); + + NetworkClientConnectGame(network_conn, COMPANY_NEW_COMPANY, join_server_password, join_company_password); } /* After the scan we're not used anymore. */ @@ -740,7 +721,7 @@ int openttd_main(int argc, char *argv[]) SetDebugString("net=3"); if (mgo.opt != nullptr) { const char *port = nullptr; - ParseConnectionString(&port, mgo.opt); + ParseFullConnectionString(nullptr, &port, mgo.opt); if (!StrEmpty(mgo.opt)) scanner->dedicated_host = mgo.opt; if (port != nullptr) scanner->dedicated_port = atoi(port); } @@ -939,15 +920,7 @@ int openttd_main(int argc, char *argv[]) NetworkStartUp(); // initialize network-core if (debuglog_conn != nullptr && _network_available) { - const char *port = nullptr; - uint16 rport; - - rport = NETWORK_DEFAULT_DEBUGLOG_PORT; - - ParseConnectionString(&port, debuglog_conn); - if (port != nullptr) rport = atoi(port); - - NetworkStartDebugLog(debuglog_conn, rport); + NetworkStartDebugLog(debuglog_conn); } if (!HandleBootstrap()) { @@ -1298,6 +1271,11 @@ void SwitchToMode(SwitchMode new_mode) break; } + case SM_JOIN_GAME: // Join a multiplayer game + LoadIntroGame(); + NetworkClientJoinGame(); + break; + case SM_MENU: // Switch to game intro menu LoadIntroGame(); if (BaseSounds::ini_set.empty() && BaseSounds::GetUsedSet()->fallback && SoundDriver::GetInstance()->HasOutput()) { @@ -1975,7 +1953,7 @@ void GameLoop() if (_network_reconnect > 0 && --_network_reconnect == 0) { /* This means that we want to reconnect to the last host * We do this here, because it means that the network is really closed */ - NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, COMPANY_SPECTATOR); + NetworkClientConnectGame(_settings_client.network.last_joined, COMPANY_SPECTATOR); } /* Singleplayer */ StateGameLoop(); diff --git a/src/openttd.h b/src/openttd.h index 61296d2ca1..cdabc6279f 100644 --- a/src/openttd.h +++ b/src/openttd.h @@ -36,6 +36,7 @@ enum SwitchMode { SM_START_HEIGHTMAP, ///< Load a heightmap and start a new game from it. SM_LOAD_HEIGHTMAP, ///< Load heightmap from scenario editor. SM_RESTART_HEIGHTMAP, ///< Load a heightmap and start a new game from it with current settings. + SM_JOIN_GAME, ///< Join a network game. }; /** Display Options */ diff --git a/src/safeguards.h b/src/safeguards.h index e3d6c4a3e4..aca461175f 100644 --- a/src/safeguards.h +++ b/src/safeguards.h @@ -70,15 +70,15 @@ #endif #if defined(NETWORK_CORE_OS_ABSTRACTION_H) && defined(_WIN32) -/* Use NetworkGetLastError() instead of errno, or do not (indirectly) include network/core/os_abstraction.h. - * Winsock does not set errno, but one should rather call WSAGetLastError. NetworkGetLastError abstracts that away. */ +/* Use NetworkError::GetLast() instead of errno, or do not (indirectly) include network/core/os_abstraction.h. + * Winsock does not set errno, but one should rather call WSAGetLastError. NetworkError::GetLast abstracts that away. */ #ifdef errno #undef errno #endif #define errno SAFEGUARD_DO_NOT_USE_THIS_METHOD -/* Use NetworkGetLastErrorString() instead of strerror, or do not (indirectly) include network/core/os_abstraction.h. - * Winsock errors are not handled by strerror, but one should rather call FormatMessage. NetworkGetLastErrorString abstracts that away. */ +/* Use NetworkError::AsString() instead of strerror, or do not (indirectly) include network/core/os_abstraction.h. + * Winsock errors are not handled by strerror, but one should rather call FormatMessage. NetworkError::AsString abstracts that away. */ #define strerror SAFEGUARD_DO_NOT_USE_THIS_METHOD #endif /* defined(NETWORK_CORE_OS_ABSTRACTION_H) && defined(_WIN32) */ diff --git a/src/script/api/script_date.cpp b/src/script/api/script_date.cpp index 78a30bcca1..56fe20428e 100644 --- a/src/script/api/script_date.cpp +++ b/src/script/api/script_date.cpp @@ -14,6 +14,8 @@ #include +#include + #include "../../safeguards.h" /* static */ bool ScriptDate::IsValidDate(Date date) diff --git a/src/settings_type.h b/src/settings_type.h index 5cb9cfd3f7..a0ae416ee8 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -337,7 +337,7 @@ struct NetworkSettings { bool server_advertise; ///< advertise the server to the masterserver char client_name[NETWORK_CLIENT_NAME_LENGTH]; ///< name of the player (as client) char default_company_pass[NETWORK_PASSWORD_LENGTH]; ///< default password for new companies in encrypted form - char connect_to_ip[NETWORK_HOSTNAME_LENGTH]; ///< default for the "Add server" query + char connect_to_ip[NETWORK_HOSTNAME_PORT_LENGTH]; ///< default for the "Add server" query char network_id[NETWORK_SERVER_ID_LENGTH]; ///< network ID for servers bool autoclean_companies; ///< automatically remove companies that are not in use uint8 autoclean_unprotected; ///< remove passwordless companies after this many months @@ -349,8 +349,7 @@ struct NetworkSettings { Year restart_game_year; ///< year the server restarts uint8 min_active_clients; ///< minimum amount of active clients to unpause the game bool reload_cfg; ///< reload the config file before restarting - char last_host[NETWORK_HOSTNAME_LENGTH]; ///< IP address of the last joined server - uint16 last_port; ///< port of the last joined server + char last_joined[NETWORK_HOSTNAME_PORT_LENGTH]; ///< Last joined server bool no_http_content_downloads; ///< do not do content downloads over HTTP }; diff --git a/src/stdafx.h b/src/stdafx.h index 42e8cac096..e7a74608df 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -144,6 +144,12 @@ # endif #endif /* __GNUC__ || __clang__ */ +#if __GNUC__ > 11 || (__GNUC__ == 11 && __GNUC_MINOR__ >= 1) +# define NOACCESS(args) __attribute__ ((access (none, args))) +#else +# define NOACCESS(args) +#endif + #if defined(__WATCOMC__) # define NORETURN # define CDECL diff --git a/src/string_func.h b/src/string_func.h index c022155c1a..8fb25f0917 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -30,30 +30,30 @@ #include "core/bitmath_func.hpp" #include "string_type.h" -char *strecat(char *dst, const char *src, const char *last); -char *strecpy(char *dst, const char *src, const char *last, bool quiet_mode = false); -char *stredup(const char *src, const char *last = nullptr); +char *strecat(char *dst, const char *src, const char *last) NOACCESS(3); +char *strecpy(char *dst, const char *src, const char *last, bool quiet_mode = false) NOACCESS(3); +char *stredup(const char *src, const char *last = nullptr) NOACCESS(2); -int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FORMAT(3, 4); -int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap) WARN_FORMAT(3, 0); +int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FORMAT(3, 4) NOACCESS(2); +int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap) WARN_FORMAT(3, 0) NOACCESS(2); char *CDECL str_fmt(const char *str, ...) WARN_FORMAT(1, 2); char *str_vfmt(const char *str, va_list ap) WARN_FORMAT(1, 0); std::string CDECL stdstr_fmt(const char *str, ...) WARN_FORMAT(1, 2); std::string stdstr_vfmt(const char *str, va_list va) WARN_FORMAT(1, 0); -char *str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); +char *str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK) NOACCESS(2); std::string str_validate(const std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); void ValidateString(const char *str); -const char *str_fix_scc_encoded(char *str, const char *last); +const char *str_fix_scc_encoded(char *str, const char *last) NOACCESS(2); void str_strip_colours(char *str); std::string str_strip_all_scc(const char *str); char *str_replace_wchar(char *str, const char *last, WChar find, WChar replace); bool strtolower(char *str); bool strtolower(std::string &str, std::string::size_type offs = 0); -bool StrValid(const char *str, const char *last); +bool StrValid(const char *str, const char *last) NOACCESS(2); void StrTrimInPlace(char *str); /** diff --git a/src/table/settings.ini b/src/table/settings.ini index 659d22134d..0a865c7189 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -6340,21 +6340,12 @@ def = false cat = SC_EXPERT [SDTC_STR] -var = network.last_host +var = network.last_joined type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = """" cat = SC_EXPERT -[SDTC_VAR] -var = network.last_port -type = SLE_UINT16 -flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = 0 -min = 0 -max = UINT16_MAX -cat = SC_EXPERT - [SDTC_BOOL] var = network.no_http_content_downloads flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC