Merge commit 'f1dfa661a1898cde06a38ab4cb230c95912b245b' into jgrpp-beta

# Conflicts:
#	src/lang/estonian.txt
#	src/lang/hungarian.txt
#	src/network/core/game_info.cpp
#	src/network/core/game_info.h
#	src/network/core/packet.h
#	src/network/network.cpp
#	src/network/network_client.cpp
#	src/network/network_server.cpp
#	src/network/network_udp.cpp
#	src/openttd.cpp
#	src/string_func.h
pull/332/head
Jonathan G Rennison 3 years ago
commit da1ac73c02

@ -392,7 +392,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c
fios->mtime = 0;
strecpy(fios->name, d_name, lastof(fios->name));
std::string dirname = std::string(d_name) + PATHSEP;
SetDParamStr(0, dirname.c_str());
SetDParamStr(0, dirname);
GetString(fios->title, STR_SAVELOAD_DIRECTORY, lastof(fios->title));
str_validate(fios->title, lastof(fios->title));
}

@ -553,7 +553,7 @@ public:
const CompanyProperties &c = *pair.second;
if (!c.name.empty()) {
SetDParam(1, STR_JUST_RAW_STRING);
SetDParamStr(2, c.name.c_str());
SetDParamStr(2, c.name);
} else {
SetDParam(1, c.name_1);
SetDParam(2, c.name_2);

@ -675,6 +675,28 @@ int DrawString(int left, int right, int top, const char *str, TextColour colour,
return DrawLayoutLine(*layout.front(), top, left, right, align, underline, true);
}
/**
* Draw string, possibly truncated to make it fit in its allocated space
*
* @param left The left most position to draw on.
* @param right The right most position to draw on.
* @param top The top most position to draw on.
* @param str String to draw.
* @param colour Colour used for drawing the string, for details see _string_colourmap in
* table/palettes.h or docs/ottd-colourtext-palette.png or the enum TextColour in gfx_type.h
* @param align The alignment of the string when drawing left-to-right. In the
* case a right-to-left language is chosen this is inverted so it
* will be drawn in the right direction.
* @param underline Whether to underline what has been drawn or not.
* @param fontsize The size of the initial characters.
* @return In case of left or center alignment the right most pixel we have drawn to.
* In case of right alignment the left most pixel we have drawn to.
*/
int DrawString(int left, int right, int top, const std::string &str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
{
return DrawString(left, right, top, str.c_str(), colour, align, underline, fontsize);
}
/**
* Draw string, possibly truncated to make it fit in its allocated space
*
@ -825,6 +847,28 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, const char *st
return ((align & SA_VERT_MASK) == SA_BOTTOM) ? first_line : last_line;
}
/**
* Draw string, possibly over multiple lines.
*
* @param left The left most position to draw on.
* @param right The right most position to draw on.
* @param top The top most position to draw on.
* @param bottom The bottom most position to draw on.
* @param str String to draw.
* @param colour Colour used for drawing the string, for details see _string_colourmap in
* table/palettes.h or docs/ottd-colourtext-palette.png or the enum TextColour in gfx_type.h
* @param align The horizontal and vertical alignment of the string.
* @param underline Whether to underline all strings
* @param fontsize The size of the initial characters.
*
* @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written.
*/
int DrawStringMultiLine(int left, int right, int top, int bottom, const std::string &str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
{
return DrawStringMultiLine(left, right, top, bottom, str.c_str(), colour, align, underline, fontsize);
}
/**
* Draw string, possibly over multiple lines.
*

@ -93,8 +93,10 @@ void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSpri
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI);
int DrawString(int left, int right, int top, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawString(int left, int right, int top, const std::string &str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawString(int left, int right, int top, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawStringMultiLine(int left, int right, int top, int bottom, const std::string &str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL);
void DrawCharCentered(WChar c, const Rect &r, TextColour colour);

@ -572,12 +572,12 @@ public:
/* Draw the accepted cargoes, if any. Otherwise, will print "Nothing". */
GetAllCargoSuffixes(CARGOSUFFIX_IN, CST_FUND, nullptr, this->selected_type, indsp, indsp->accepts_cargo, cargo_suffix);
std::string cargostring = this->MakeCargoListString(indsp->accepts_cargo, cargo_suffix, lengthof(indsp->accepts_cargo), STR_INDUSTRY_VIEW_REQUIRES_N_CARGO);
y = DrawStringMultiLine(left, right, y, bottom, cargostring.c_str());
y = DrawStringMultiLine(left, right, y, bottom, cargostring);
/* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */
GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_FUND, nullptr, this->selected_type, indsp, indsp->produced_cargo, cargo_suffix);
cargostring = this->MakeCargoListString(indsp->produced_cargo, cargo_suffix, lengthof(indsp->produced_cargo), STR_INDUSTRY_VIEW_PRODUCES_N_CARGO);
y = DrawStringMultiLine(left, right, y, bottom, cargostring.c_str());
y = DrawStringMultiLine(left, right, y, bottom, cargostring);
/* Get the additional purchase info text, if it has not already been queried. */
if (HasBit(indsp->callback_mask, CBM_IND_FUND_MORE_TEXT)) {
@ -972,7 +972,7 @@ public:
}
if (!i->text.empty()) {
SetDParamStr(0, i->text.c_str());
SetDParamStr(0, i->text);
y += WD_PAR_VSEP_WIDE;
y = DrawStringMultiLine(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK);
}

@ -2248,6 +2248,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
@ -2299,7 +2300,7 @@ STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} ha
STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} has joined spectators
STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} has started a new company (#{2:NUM})
STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} has left the game ({2:STRING})
STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} has changed his/her name to {STRING}
STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} has changed their name to {STRING}
STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} gave {2:CURRENCY_LONG} to {1:STRING}
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}The server closed the session
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}The server is restarting...{}Please wait...

@ -1056,6 +1056,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :12 kuud
STR_GAME_OPTIONS_LANGUAGE :{BLACK}Keel
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Valib kasutajaliideses kasutatava keele
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% valmis)
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Täisekraan
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Märgi see kast, et OpenTTD täisekraanirežiimis mängida
@ -1069,6 +1070,8 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Riistvar
STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Märkides selle ruudu, lubad OpenTTD-l üritada kasutada riistvarakiirendust. Muudetud seade omab mõju pärast mängu taaskäivitust
STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Seade omab mõju alles pärast mängu taaskäivitust
STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync
STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Märgi, et ekraani v-sync sisse lülitada. Seade kohaldub alles pärast mängu taaskäivitust. Töötab vaid, kui riistvarakiirendus on peal
STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Liidese suurus
STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Vali kasutatav liideseelementide suurus
@ -1202,6 +1205,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Seaded
STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Märksõna:
STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Ava kõik
STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Sulge kõik
STR_CONFIG_SETTING_RESET_ALL :{BLACK}Nulli kõik väärtused
STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(seletus puudub)
STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Vaikeväärtus: {ORANGE}{STRING}
STR_CONFIG_SETTING_TYPE :{LTBLUE}Seade liik: {ORANGE}{STRING}
@ -1210,6 +1214,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Mängu seade (s
STR_CONFIG_SETTING_TYPE_GAME_INGAME :Mängu seaded (hoitakse salvestuses; mõjutab ainult praegust mängu)
STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Ettevõtte seaded (hoitakse salvestuses; mõjutab ainult uusi mänge)
STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Ettevõtte seaded (hoitakse salvestuses; mõjutab ainult praegust ettevõtet)
STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Ettevaatust!
STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}See toiming nullib kõik mänguseaded.{}Oled sa kindel, et jätkata?
STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Jagu:
STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Liik:
@ -2048,6 +2054,8 @@ STR_FACE_TIE :Lips:
STR_FACE_EARRING :Kõrvarõngas:
STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Vaheta kraed või kõrvarõngast
STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privaatne
STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Avalik
# Network server list
STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Mitmikmäng
@ -2111,6 +2119,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Serveril
STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Määra salasõna
STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Et server ei oleks avalik, kaitse oma mäng salasõnaga
STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Nähtavus
STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Kas sinu server on kõikidele teistele avalikult nähtav
STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" i}
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Kliente kuni:
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS.in :sees
@ -2175,12 +2185,45 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server o
STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Ettevõte on kaitstud. Sisesta salasõna
# Network company list added strings
STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Klientide nimekiri
STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Ühendatud mängijad
STR_NETWORK_COMPANY_LIST_SPECTATE :Jälgi
# Network client list
STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Mitmikmäng
STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Server
STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nimi
STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Serveri nimi, kus sa mängid
STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Muuda oma serveri nime
STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Serveri nimi
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Nähtavus
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Kas sinu server on kõikidele teistele avalikult nähtav
STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Mängija
STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nimi
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Sinu mängija nimi
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Muuda oma mängija nime
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Sinu mängija nimi
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Haldustegevused, mida teha selle ettevõtte peal
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Haldustegevused, mida teha selle ettevõtte peal
STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Liitu selle ettevõttega
STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Saada sellele mängijale sõnum
STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Saada sõnum igale selle ettevõtte mängijale
STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Saada sõnum igale vaatlejale
STR_NETWORK_CLIENT_LIST_SPECTATORS :Vaatlejad
STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Uus ettevõte)
STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Loo uus ettevõte ja liitu sellega
STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Tema oled sina
STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Tema on mängu korraldaja
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Viska välja
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Keela
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Kustuta
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Salasõnaga avamine
STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Haldustoiming
STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Kas oled kindel, et välja visata mängija '{STRING}'?
STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Kas oled kindel, et sa tahad keelata mängija '{STRING}'?
STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Kas oled kindel, et tahad kustutada ettevõtte '{COMPANY}'?
STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Kas oled kindel, et soovid nullida ettevõtte '{COMPANY}' salasõna?
STR_NETWORK_SERVER :Server
STR_NETWORK_CLIENT :Klient
@ -2225,6 +2268,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Ei saa u
STR_NETWORK_ERROR_CLIENT_START :{WHITE}Ei õnnestu ühendada
STR_NETWORK_ERROR_TIMEOUT :{WHITE}Ühendus nr {NUM} aegus
STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Tekkis protokolliviga ja ühendus katkes
STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Sinu mängijale ei ole nime määratud. Nime saab määrata mitmikmägu akna ülaosas
STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Kliendi osa ei vasta serveri osaga
STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Vale salasõna
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Server on täis
@ -2237,6 +2281,8 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Sisestas
STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Arvutil võttis liitumisega liiga kaua aega
STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Kaardi allalaadimine võttis liiga kaua aega
STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Serveriga liitumine võttis liiga kaua aega
STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Sinu mängija nimi ei vasta nõuetele
STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}Päritud server kasutab liiga vana versiooni
############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :üldine viga
@ -2259,6 +2305,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :ei saanud õige
STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :üldine aegumine
STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :kaardi laadimine võttis liiga kaua aega
STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :kaardi töötlemine võttis liiga kaua aega
STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :kliendinimi ei vasta nõuetele
############ End of leave-in-this-order
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Võimalik ühenduse katkemine
@ -3102,6 +3149,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Hoiatus: {
STR_NEWGRF_ERROR_MSG_ERROR :{RED}Viga: {SILVER}{STRING}
STR_NEWGRF_ERROR_MSG_FATAL :{RED}Saatuslik viga: {SILVER}{STRING}
STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Esines raske NewGRF-i tõrge:{}{STRING}
STR_NEWGRF_ERROR_POPUP :{WHITE}Esines viga NewGRF-iga:{}{STRING}
STR_NEWGRF_ERROR_VERSION_NUMBER :OpenTTD väitel {1:STRING} ei tööta selle TTDPatch versiooniga.
STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} on {STRING} TTD osa jaoks.
STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} on mõeldud kasutamiseks {STRING}

@ -1176,9 +1176,9 @@ STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Pelin asetukset
STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Pelin asetukset (tallennetaan pelitallenteeseen; vaikuttavat vain nykyiseen peliin)
STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Yhtiön asetukset (tallennetaan pelitallenteisiin; vaikuttavat vain uusiin peleihin)
STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Yhtiön asetukset (tallennetaan pelitallenteeseen; vaikuttavat ainoastaan nykyiseen yhtiöön)
STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Näytä kaikki tulokset muuttamalla{}{SILVER}Kategoriaksi {WHITE}{STRING}
STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Näytä kaikki tulokset muuttamalla{}{SILVER}kategoriaksi {WHITE}{STRING}
STR_CONFIG_SETTING_TYPE_HIDES :{BLACK}Näytä kaikki hakutulokset muuttamalla{}{SILVER}Tyypiksi {WHITE}Kaikki asetustyypit
STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Näytä kaikki tulokset muuttamalla{}{SILVER}Kategoriaksi {WHITE}{STRING} {BLACK}ja {SILVER}Tyypiksi {WHITE}Kaikki asetustyypit
STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Näytä kaikki tulokset muuttamalla{}{SILVER}kategoriaksi {WHITE}{STRING} {BLACK}ja {SILVER}tyypiksi {WHITE}kaikki asetustyypit
STR_CONFIG_SETTINGS_NONE :{WHITE}- Ei mitään -
STR_CONFIG_SETTING_OFF :pois
@ -1340,7 +1340,7 @@ STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Suhteellinen ik
STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} kuukau{P 0 si tta} ennen kulkuneuvon käyttöiän loppua
STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} kuukau{P 0 si tta} jälkeen kulkuneuvon käyttöiän lopun
STR_CONFIG_SETTING_AUTORENEW_MONEY :Vähimmäisrahamäärä kulkuneuvon automaattiseen uudistukseen: {STRING}
STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Pienin rahamäärä, joka on oltava pankissa ennen kulkuneuvojen automaattista uudistamista
STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Vähimmäisrahamäärä, jonka on jäätävä pankkiin kulkuneuvoja automaattisesti uudistettaessa
STR_CONFIG_SETTING_ERRMSG_DURATION :Virheilmoitusten näyttöaika: {STRING}
STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Aika virheilmoitusten näyttämiseen punaisessa ikkunassa. Huomaa, että jotkut (kriittiset) virheilmoitukset eivät sulkeudu automaattisesti tämän ajan jälkeen, vaan ne on suljettava käsin
STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} sekunti{P 0 "" a}
@ -1464,7 +1464,7 @@ STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Mikäli käytö
STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :Salli pelin ollessa pysäytettynä: {STRING}
STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Valitse käytössä olevat toiminnot pelin ollessa pysäytettynä
STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :Ei mitään toimintoja
STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :Kaikki ei-rakennustoiminnot
STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :Kaikki paitsi rakennustoiminnot
STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :Kaikki paitsi maastonmuokkaustoiminnot
STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :Kaikki toiminnot
STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Käytä ryhmiä kulkuneuvolistassa: {STRING}
@ -1601,7 +1601,7 @@ STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Tiivistelmä
STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Täysi
STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Värilliset uutiset ilmestyvät: {STRING}
STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Vuosi, jonka jälkeen sanomalehdet ovat värillisiä. Ennen tätä vuotta sanomalehdet käyttävät mustavalkoisia kuvia
STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Vuosi, josta alkaen sanomalehdet painetaan värillisinä. Ennen tätä vuotta lehdet ovat mustavalkoiset.
STR_CONFIG_SETTING_STARTING_YEAR :Aloitusvuosi: {STRING}
STR_CONFIG_SETTING_ENDING_YEAR :Pistelaskun päättymisvuosi: {STRING}
STR_CONFIG_SETTING_ENDING_YEAR_HELPTEXT :Pelin päättymisvuosi pisteiden laskemista varten. Tämän vuoden lopussa talletetaan yhtiön pistemäärä ja näytetään ennätysluettelo; pelaajat voivat jatkaa pelaamista tämän jälkeenkin.{}Jos päättymisvuosi on ennen alkamisvuotta, ennätyksiä ei näytetä koskaan.
@ -1717,13 +1717,13 @@ STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manuaalinen
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :epäsymmetrinen
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :symmetrinen
STR_CONFIG_SETTING_DISTRIBUTION_PAX :Matkustajien jakautuminen: {STRING}
STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :"symmetrinen" tarkoittaa, että suunnilleen sama määrä matkustajia kulkee asemalta A asemalle B kuin asemalta B asemalle A. "epäsymmetrinen" tarkoittaa, että eri suuntiin voi kulkea eriävä määrä matkustajia. "manuaalinen" tarkoittaa, että automaattinen rahdin jakautuminen on pois käytöstä matkustajilla.
STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :”Symmetrinen” tarkoittaa, että suunnilleen sama määrä matkustajia kulkee asemalta A asemalle B kuin asemalta B asemalle A. ”Epäsymmetrinen” tarkoittaa, että eri suuntiin voi kulkea eriävä määrä matkustajia. ”Manuaalinen” tarkoittaa, että automaattinen rahdin jakautuminen on pois käytöstä matkustajilla.
STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Postin jakautuminen: {STRING}
STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"symmetrinen" tarkoittaa, että suunnilleen sama määrä postia lähetetään asemalta A asemalle B kuin asemalta B asemalle A. "epäsymmetrinen" tarkoittaa, että eri suuntiin voidaan lähettää eriävä määrä postia. "manuaalinen" tarkoittaa, että automaattinen rahdin jakautuminen on pois käytöstä postilla.
STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :”Symmetrinen” tarkoittaa, että suunnilleen sama määrä postia lähetetään asemalta A asemalle B kuin asemalta B asemalle A. ”Epäsymmetrinen” tarkoittaa, että eri suuntiin voidaan lähettää eriävä määrä postia. ”Manuaalinen” tarkoittaa, että automaattinen rahdin jakautuminen on pois käytöstä postilla.
STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Arvokuljetusten jakautuminen: {STRING}
STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :Arvokuljetuksiin kuuluvat arvotavarat lauhkeassa ilmastossa, timantit subtrooppisessa ilmastossa ja kulta pohjoisessa ilmastossa. NewGRF:t voivat kuitenkin muuttaa näitä rahteja. "symmetrinen" tarkoittaa, että suunnilleen sama määrä rahtia lähetetään asemalta A asemalle B kuin asemalta B asemalle A. "epäsymmetrinen" tarkoittaa, että eri suuntiin voidaan lähettää eriävä määrä rahtia. "manuaalinen" tarkoittaa, että automaattinen rahdin jakautuminen on poistettu käytöstä rahdilta. Suositeltavia asetuksia ovat "epäsymmetrinen" tai "manuaalinen" pelattaessa pohjoisessa ilmastossa, sillä pankit eivät lähetä kultaa takaisin kaivoksille. Lauhkeassa ja subtrooppisessa ilmastossa pelatessa voidaan myös valita "symmetrinen", sillä pankit lähettävät arvotavaroita takaisin alkuperäiselle pankille.
STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :Arvokuljetuksiin kuuluvat arvotavarat lauhkeassa ilmastossa, timantit subtrooppisessa ilmastossa ja kulta pohjoisessa ilmastossa. NewGRF:t voivat kuitenkin muuttaa näitä rahteja. ”Symmetrinen” tarkoittaa, että suunnilleen sama määrä rahtia lähetetään asemalta A asemalle B kuin asemalta B asemalle A. ”Epäsymmetrinen” tarkoittaa, että eri suuntiin voidaan lähettää eriävä määrä rahtia. ”Manuaalinen” tarkoittaa, että automaattinen rahdin jakautuminen on poistettu käytöstä rahdilta. Suositeltavia asetuksia ovat ”epäsymmetrinen” tai ”manuaalinen” pelattaessa pohjoisessa ilmastossa, sillä pankit eivät lähetä kultaa takaisin kaivoksille. Lauhkeassa ja subtrooppisessa ilmastossa pelatessa voidaan myös valita ”symmetrinen”, sillä pankit lähettävät arvotavaroita takaisin alkuperäiselle pankille.
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Muiden rahtityyppien jakautuminen: {STRING}
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"epäsymmetrinen" tarkoittaa, että eri suuntiin voidaan lähettää eriäviä määriä rahtia. "manuaalinen" tarkoittaa, että automaattinen jakautuminen ei ole käytössä rahdille.
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :”Epäsymmetrinen” tarkoittaa, että eri suuntiin voidaan lähettää eriäviä määriä rahtia. ”Manuaalinen” tarkoittaa, että automaattinen jakautuminen ei ole käytössä rahdille.
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Jakautumisen tarkkuus: {STRING}
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Mitä suuremmaksi tämä asetus on määritetty, sitä enemmän prosessoriaikaa yhteyskuvaajan laskemiseen kuluu. Mikäli tähän kuluu liian paljon aikaa, saatat havaita pelin nykimistä. Jos arvo on määritetty liian pieneksi, jakauman laskeminen ei ole tarkka ja rahtia ei välttämättä lähetetä odotetuille asemille.
STR_CONFIG_SETTING_DEMAND_DISTANCE :Välimatkan vaikutus kysyntään: {STRING}
@ -1777,7 +1777,7 @@ STR_CONFIG_SETTING_INTERFACE :{ORANGE}Käytt
STR_CONFIG_SETTING_INTERFACE_GENERAL :{ORANGE}Yleinen
STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :{ORANGE}Näkymät
STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}Rakentaminen
STR_CONFIG_SETTING_ADVISORS :{ORANGE}Uutiset / Neuvonantajat
STR_CONFIG_SETTING_ADVISORS :{ORANGE}Uutiset ja neuvonantajat
STR_CONFIG_SETTING_COMPANY :{ORANGE}Yhtiö
STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Talous
STR_CONFIG_SETTING_VEHICLES :{ORANGE}Kulkuneuvot
@ -1882,7 +1882,7 @@ STR_QUIT_NO :{BLACK}Ei
# Abandon game
STR_ABANDON_GAME_CAPTION :{WHITE}Pelin lopetus
STR_ABANDON_GAME_QUERY :{YELLOW}Lopetetaanko peli?
STR_ABANDON_SCENARIO_QUERY :{YELLOW}Lopetetaanko skenaario?
STR_ABANDON_SCENARIO_QUERY :{YELLOW}Haluatko varmasti hylätä tämän skenaarion?
# Cheat window
STR_CHEATS :{WHITE}Huijaukset
@ -2214,7 +2214,7 @@ STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Et ole a
STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Tämän asiakkaan versio ei vastaa palvelimen versiota
STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Väärä salasana
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Palvelin on täynnä
STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Sinut on kielletty palvelimelta
STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Sinut on estetty palvelimelta
STR_NETWORK_ERROR_KICKED :{WHITE}Sinut potkittiin pihalle palvelimelta
STR_NETWORK_ERROR_KICK_MESSAGE :{WHITE}Syy: {STRING}
STR_NETWORK_ERROR_CHEATER :{WHITE}Huijaaminen ei ole sallittua tällä palvelimella
@ -2224,6 +2224,7 @@ STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Tietokon
STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Kartan lataus kesti liian kauan
STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Palvelimelle liittyminen kesti liian kauan
STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Pelaajanimesi ei kelpaa
STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}Kysytty palvelin on liian vanha tälle asiakkaalle
############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :yleinen virhe
@ -2807,7 +2808,7 @@ STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Yhtiön omistam
STR_ABOUT_OPENTTD :{WHITE}Tietoja OpenTTD:stä
STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Alkuperäiset oikeudet {COPYRIGHT} 1995 Chris Sawyer, kaikki oikeudet pidätetään
STR_ABOUT_VERSION :{BLACK}OpenTTD-versio {REV}
STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-{STRING} The OpenTTD team
STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002{STRING} The OpenTTD team
# Framerate display window
STR_FRAMERATE_CAPTION :{WHITE}Kuvataajuus
@ -3513,8 +3514,8 @@ STR_INDUSTRY_VIEW_REQUIRES :{BLACK}Tarvitse
STR_INDUSTRY_VIEW_ACCEPT_CARGO :{YELLOW}{STRING}{BLACK}{3:STRING}
STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT :{YELLOW}{STRING}{BLACK}: {CARGO_SHORT} odottamassa{STRING}
STR_CONFIG_GAME_PRODUCTION :{WHITE}Muokkaa tuotantoa (8:n kerroin, 2040 asti)
STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Muuta tuotantotasoa (prosentteina, 800{NBSP}% asti)
STR_CONFIG_GAME_PRODUCTION :{WHITE}Muokkaa tuotantoa (8:n kerroin, 2040:een asti)
STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Muuta tuotantotasoa (prosentteina, 800{NBSP}%:iin asti)
# Vehicle lists
STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING} {COMMA} juna{P "" a}

@ -1023,7 +1023,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Maláj ringgit
STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Balra hajtás
STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Jobbra hajtás
STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Városnevek
STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Városnevek:
STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}A városnevek stílusának kiválasztása
############ start of townname region
@ -1063,6 +1063,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :12 havonta
STR_GAME_OPTIONS_LANGUAGE :{BLACK}Nyelv
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Válassz nyelvet
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% teljesítve)
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Teljes képernyő
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Jelöld be ezt, ha teljes képernyős módban szeretnél játszani az OpenTTD-vel
@ -2060,6 +2061,8 @@ STR_FACE_TIE :Nyakkendő:
STR_FACE_EARRING :Fülbevaló:
STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Nyakkendő vagy fülbevaló cseréje
STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privát
STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Nyilvános
# Network server list
STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Hálózati játék
@ -2123,6 +2126,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}A játé
STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Jelszó beállítása
STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Védd le a játékodat jelszóval, ha nem akarod hogy illetéktelenek csatlakozzanak
STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Láthatóság
STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Mások láthassák-e a szerveredet a publikus listában
STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} kliens
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Játékosok max. száma:
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}A maximálisan felcsatlakozható kliensek számának kiválasztása. Nem szükséges pont ennyi embernek éppen kapcsolódva lennie
@ -2186,12 +2191,45 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}A szerve
STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}A vállalat jelszóval van védve. Írd be
# Network company list added strings
STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Kliens lista
STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Online játékosok
STR_NETWORK_COMPANY_LIST_SPECTATE :Megfigyelés
# Network client list
STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Többjátékos
STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Szerver
STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Név
STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}A szerver neve amin játszol
STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}A szervered nevének szerkesztése
STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Szerver neve
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Láthatóság
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Mások láthassák-e a szerveredet a publikus listában
STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Játékos
STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Név
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}A játékos neved
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}A játékos neved szerkesztése
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Játékos neve
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Adminisztrátori műveletek ehhez a vállalathoz
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Adminisztrátori műveletek ehhez a vállalathoz
STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :Csatlakozz ehhez a vállalathoz
STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Üzenet küldése ennek a játékosnak
STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Üzenet küldése az összes játékosnak ebben a vállalatban
STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Üzenet küldése az összes megfigyelőnek
STR_NETWORK_CLIENT_LIST_SPECTATORS :Megfigyelők
STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Új vállalat)
STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Hozz létre egy új vállalatot és csatlakozz
STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Ez vagy te
STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Ez a játék elindítója
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Kirúgás
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Tiltás
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Törlés
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Jelszó feloldása
STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Adminisztrátori művelet
STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Biztos ki akarod rúgni ezt a játékost: '{STRING}'?
STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Biztos ki akarod tiltani ezt a játékost: '{STRING}'?
STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Biztos ki akarod törölni a '{COMPANY}' vállalatot?
STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Biztos vissza akarod állítani a '{COMPANY}' vállalat jelszavát?
STR_NETWORK_SERVER :Szerver
STR_NETWORK_CLIENT :Kliens
@ -2236,6 +2274,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Nem tudt
STR_NETWORK_ERROR_CLIENT_START :{WHITE}Nem tudtam kapcsolódni
STR_NETWORK_ERROR_TIMEOUT :{WHITE}A(z) {NUM}. játékos kapcsolata elveszett
STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Protokoll-hiba keletkezett és megszakadt a kapcsolat
STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}A játékos neved nem lett megadva. A nevet a többjátékos ablak tetején tudod beállítani.
STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}A gépeden és a szerveren lévő programnak nem egyezik meg a verziója
STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Rossz jelszó
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}A szerver tele van
@ -2248,6 +2287,8 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Túl sok
STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}A számítógéped túl lassú, hogy tartsa a szerver sebességét
STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Túl sokáig tartott a térkép letöltése a számítógépednek
STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Túl sokáig tartott a szerverhez való csatlakozása a számítógépednek
STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}A játékos neved nem megfelelő
STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}A lekérdezett szerver túl régi ehhez a klienshez
############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :általános hiba
@ -2270,6 +2311,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :nem érkezett j
STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :általános időtúllépés
STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :térkép letöltés túl sokáig tartott
STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :térkép feldolgozás túl sokáig tartott
STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :Érvénytelen kliens név
############ End of leave-in-this-order
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Lehetséges, hogy elveszett a kapcsolat
@ -3113,6 +3155,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Figyelmezt
STR_NEWGRF_ERROR_MSG_ERROR :{RED}Hiba: {SILVER}{STRING}
STR_NEWGRF_ERROR_MSG_FATAL :{RED}Végzetes hiba: {SILVER}{STRING}
STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Egy végzetes NewGRF hiba történt:{}{STRING}
STR_NEWGRF_ERROR_POPUP :{WHITE}NewGRF hiba történt:{}{STRING}
STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} nem fog működni az OpenTTD által jelentett TTDPatch verzióval
STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} a TTD {STRING} verziójához van
STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} úgy lett tervezve, hogy együtt lesz használva ezzel: {STRING}

@ -409,7 +409,7 @@ STR_SETTINGS_MENU_SIGNS_DISPLAYED :팻말을 표
STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :경쟁사의 팻말과 역 이름을 표시
STR_SETTINGS_MENU_FULL_ANIMATION :완전한 애니메이션
STR_SETTINGS_MENU_FULL_DETAIL :그래픽을 아주 상세하게
STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :건물 숨기
STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :건물 감추
STR_SETTINGS_MENU_TRANSPARENT_SIGNS :역명판 감추기
STR_SETTINGS_MENU_MONEY_TEXT_EFFECTS :수입/지출 표시
############ range ends here

@ -2277,7 +2277,7 @@ STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} en
STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} entrou como espectador
STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} iniciou uma nova empresa (#{2:NUM})
STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} deixou o jogo ({2:STRING})
STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} mudou o seu nome para {STRING}
STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} mudou o nome para {STRING}
STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} deu {2:CURRENCY_LONG} a {1:STRING}
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}O servidor fechou a sessão
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}O servidor está a reiniciar...{}Por favor espere...

@ -2430,7 +2430,7 @@ STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {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}
STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} сменил(а) имя на {STRING}
STR_NETWORK_MESSAGE_GIVE_MONEY :*** Компания «{STRING}» передала «{STRING}» {CURRENCY_LONG}
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Сервер закрыл сессию
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Сервер перезапускается...{}Пожалуйста, подождите...

@ -2225,6 +2225,7 @@ STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Su orden
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
STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}El servidor es demasiado antiguo para este cliente.
############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :error general

@ -462,7 +462,7 @@ struct MusicTrackSelectionWindow : public Window {
SetDParam(0, STR_MUSIC_PLAYLIST_ALL + _settings_client.music.playlist);
break;
case WID_MTS_CAPTION:
SetDParamStr(0, BaseMusic::GetUsedSet()->name.c_str());
SetDParamStr(0, BaseMusic::GetUsedSet()->name);
break;
}
}

@ -23,11 +23,13 @@ static const int DEFAULT_CONNECT_TIMEOUT_SECONDS = 3; ///< Allow connect() three
*/
const char *NetworkAddress::GetHostname()
{
if (StrEmpty(this->hostname) && this->address.ss_family != AF_UNSPEC) {
if (this->hostname.empty() && this->address.ss_family != AF_UNSPEC) {
assert(this->address_length != 0);
getnameinfo((struct sockaddr *)&this->address, this->address_length, this->hostname, sizeof(this->hostname), nullptr, 0, NI_NUMERICHOST);
char buffer[NETWORK_HOSTNAME_LENGTH];
getnameinfo((struct sockaddr *)&this->address, this->address_length, buffer, sizeof(buffer), nullptr, 0, NI_NUMERICHOST);
this->hostname = buffer;
}
return this->hostname;
return this->hostname.c_str();
}
/**
@ -244,32 +246,32 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
/* Setting both hostname to nullptr and port to 0 is not allowed.
* As port 0 means bind to any port, the other must mean that
* we want to bind to 'all' IPs. */
if (StrEmpty(this->hostname) && this->address_length == 0 && this->GetPort() == 0) {
if (this->hostname.empty() && this->address_length == 0 && this->GetPort() == 0) {
reset_hostname = true;
int fam = this->address.ss_family;
if (fam == AF_UNSPEC) fam = family;
strecpy(this->hostname, fam == AF_INET ? "0.0.0.0" : "::", lastof(this->hostname));
this->hostname = fam == AF_INET ? "0.0.0.0" : "::";
}
static bool _resolve_timeout_error_message_shown = false;
auto start = std::chrono::steady_clock::now();
int e = getaddrinfo(StrEmpty(this->hostname) ? nullptr : this->hostname, port_name, &hints, &ai);
int e = getaddrinfo(this->hostname.empty() ? nullptr : this->hostname.c_str(), port_name, &hints, &ai);
auto end = std::chrono::steady_clock::now();
std::chrono::seconds duration = std::chrono::duration_cast<std::chrono::seconds>(end - start);
if (!_resolve_timeout_error_message_shown && duration >= std::chrono::seconds(5)) {
DEBUG(net, 0, "getaddrinfo for hostname \"%s\", port %s, address family %s and socket type %s took %i seconds",
this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), (int)duration.count());
this->hostname.c_str(), port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), (int)duration.count());
DEBUG(net, 0, " this is likely an issue in the DNS name resolver's configuration causing it to time out");
_resolve_timeout_error_message_shown = true;
}
if (reset_hostname) strecpy(this->hostname, "", lastof(this->hostname));
if (reset_hostname) this->hostname.clear();
if (e != 0) {
if (func != ResolveLoopProc) {
DEBUG(net, 0, "getaddrinfo for hostname \"%s\", port %s, address family %s and socket type %s failed: %s",
this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), FS2OTTD(gai_strerror(e)).c_str());
this->hostname.c_str(), port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), FS2OTTD(gai_strerror(e)).c_str());
}
return INVALID_SOCKET;
}
@ -452,11 +454,11 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets)
{
assert(sockets != nullptr);
/* Setting both hostname to nullptr and port to 0 is not allowed.
/* Setting both hostname to "" and port to 0 is not allowed.
* As port 0 means bind to any port, the other must mean that
* we want to bind to 'all' IPs. */
if (this->address_length == 0 && this->address.ss_family == AF_UNSPEC &&
StrEmpty(this->hostname) && this->GetPort() == 0) {
this->hostname.empty() && this->GetPort() == 0) {
this->Resolve(AF_INET, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc);
this->Resolve(AF_INET6, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc);
} else {

@ -28,10 +28,10 @@ typedef SmallMap<NetworkAddress, SOCKET> SocketList; ///< Type for a mapping
*/
class NetworkAddress {
private:
char hostname[NETWORK_HOSTNAME_LENGTH]; ///< The hostname
int address_length; ///< The length of the resolved address
sockaddr_storage address; ///< The resolved address
bool resolved; ///< Whether the address has been (tried to be) resolved
std::string hostname; ///< The hostname
int address_length; ///< The length of the resolved address
sockaddr_storage address; ///< The resolved address
bool resolved; ///< Whether the address has been (tried to be) resolved
/**
* Helper function to resolve something to a socket.
@ -52,7 +52,6 @@ public:
address(address),
resolved(address_length != 0)
{
*this->hostname = '\0';
}
/**
@ -64,7 +63,6 @@ public:
address_length(address_length),
resolved(address_length != 0)
{
*this->hostname = '\0';
memset(&this->address, 0, sizeof(this->address));
memcpy(&this->address, address, address_length);
}
@ -75,16 +73,15 @@ public:
* @param port the port
* @param family the address family
*/
NetworkAddress(const char *hostname = "", uint16 port = 0, int family = AF_UNSPEC) :
NetworkAddress(std::string_view hostname = "", uint16 port = 0, int family = AF_UNSPEC) :
address_length(0),
resolved(false)
{
/* Also handle IPv6 bracket enclosed hostnames */
if (StrEmpty(hostname)) hostname = "";
if (*hostname == '[') hostname++;
strecpy(this->hostname, StrEmpty(hostname) ? "" : hostname, lastof(this->hostname));
char *tmp = strrchr(this->hostname, ']');
if (tmp != nullptr) *tmp = '\0';
if (!hostname.empty() && hostname.front() == '[' && hostname.back() == ']') {
hostname.remove_prefix(1);
hostname.remove_suffix(1);
}
this->hostname = hostname;
memset(&this->address, 0, sizeof(this->address));
this->address.ss_family = family;

@ -113,7 +113,7 @@ bool IsNetworkCompatibleVersion(const char *other, bool extended)
void CheckGameCompatibility(NetworkGameInfo &ngi, bool extended)
{
/* Check if we are allowed on this server based on the revision-check. */
ngi.version_compatible = IsNetworkCompatibleVersion(ngi.server_revision, extended);
ngi.version_compatible = IsNetworkCompatibleVersion(ngi.server_revision.c_str(), extended);
ngi.compatible = ngi.version_compatible;
/* Check if we have all the GRFs on the client-system too. */
@ -123,31 +123,37 @@ void CheckGameCompatibility(NetworkGameInfo &ngi, bool extended)
}
/**
* Fill a NetworkGameInfo structure with the latest information of the server.
* @param ngi the NetworkGameInfo struct to fill with data.
* Fill a NetworkServerGameInfo structure with the static content, or things
* that are so static they can be updated on request from a settings change.
*/
void FillNetworkGameInfo(NetworkGameInfo &ngi)
void FillStaticNetworkServerGameInfo()
{
/* Update some game_info */
ngi.clients_on = _network_game_info.clients_on;
ngi.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
ngi.use_password = !StrEmpty(_settings_client.network.server_password);
ngi.clients_max = _settings_client.network.max_clients;
ngi.companies_on = (byte)Company::GetNumItems();
ngi.companies_max = _settings_client.network.max_companies;
ngi.spectators_on = NetworkSpectatorCount();
ngi.spectators_max = _settings_client.network.max_spectators;
ngi.game_date = _date;
ngi.map_width = MapSizeX();
ngi.map_height = MapSizeY();
ngi.map_set = _settings_game.game_creation.landscape;
ngi.dedicated = _network_dedicated;
ngi.grfconfig = _grfconfig;
strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name));
strecpy(ngi.server_revision, GetNetworkRevisionString(), lastof(ngi.server_revision));
strecpy(ngi.short_server_revision, _openttd_revision, lastof(ngi.short_server_revision));
_network_game_info.use_password = !StrEmpty(_settings_client.network.server_password);
_network_game_info.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
_network_game_info.clients_max = _settings_client.network.max_clients;
_network_game_info.companies_max = _settings_client.network.max_companies;
_network_game_info.spectators_max = _settings_client.network.max_spectators;
_network_game_info.map_width = MapSizeX();
_network_game_info.map_height = MapSizeY();
_network_game_info.landscape = _settings_game.game_creation.landscape;
_network_game_info.dedicated = _network_dedicated;
_network_game_info.grfconfig = _grfconfig;
_network_game_info.server_name = _settings_client.network.server_name;
_network_game_info.server_revision = GetNetworkRevisionString();
}
/**
* Get the NetworkServerGameInfo structure with the latest information of the server.
* @return The current NetworkServerGameInfo.
*/
const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo()
{
/* Client_on is used as global variable to keep track on the number of clients. */
_network_game_info.companies_on = (byte)Company::GetNumItems();
_network_game_info.spectators_on = NetworkSpectatorCount();
_network_game_info.game_date = _date;
return &_network_game_info;
}
/**
@ -181,7 +187,7 @@ static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)
* @param p the packet to write the data to.
* @param info the NetworkGameInfo struct to serialize from.
*/
void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info)
{
p->Send_uint8 (NETWORK_GAME_INFO_VERSION);
@ -247,7 +253,7 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
p->Send_string(""); // Used to be map-name.
p->Send_uint16(info->map_width);
p->Send_uint16(info->map_height);
p->Send_uint8 (info->map_set);
p->Send_uint8 (info->landscape);
p->Send_bool (info->dedicated);
}
@ -256,7 +262,7 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
* @param p the packet to write the data to
* @param info the NetworkGameInfo struct to serialize
*/
void SerializeNetworkGameInfoExtended(Packet *p, const NetworkGameInfo *info, uint16 flags, uint16 version)
void SerializeNetworkGameInfoExtended(Packet *p, const NetworkServerGameInfo *info, uint16 flags, uint16 version)
{
p->Send_uint8(0); // version num
@ -275,7 +281,7 @@ void SerializeNetworkGameInfoExtended(Packet *p, const NetworkGameInfo *info, ui
p->Send_string(""); // Used to be map-name.
p->Send_uint32(info->map_width);
p->Send_uint32(info->map_height);
p->Send_uint8 (info->map_set);
p->Send_uint8 (info->landscape);
p->Send_bool (info->dedicated);
{
@ -310,7 +316,7 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
{
static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
info->game_info_version = p->Recv_uint8();
byte game_info_version = p->Recv_uint8();
/*
* Please observe the order.
@ -320,7 +326,7 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
/* Update the documentation in game_info.h on changes
* to the NetworkGameInfo wire-protocol! */
switch (info->game_info_version) {
switch (game_info_version) {
case 4: {
GRFConfig **dst = &info->grfconfig;
uint i;
@ -353,24 +359,24 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
FALLTHROUGH;
case 1:
p->Recv_string(info->server_name, sizeof(info->server_name));
p->Recv_string(info->server_revision, sizeof(info->server_revision));
info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);
info->server_revision = p->Recv_string(NETWORK_REVISION_LENGTH);
p->Recv_uint8 (); // Used to contain server-lang.
info->use_password = p->Recv_bool ();
info->clients_max = p->Recv_uint8 ();
info->clients_on = p->Recv_uint8 ();
info->spectators_on = p->Recv_uint8 ();
if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
if (game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
info->game_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
info->start_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
}
while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
info->map_width = p->Recv_uint16();
info->map_height = p->Recv_uint16();
info->map_set = p->Recv_uint8 ();
info->landscape = p->Recv_uint8 ();
info->dedicated = p->Recv_bool ();
if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
if (info->landscape >= NETWORK_NUM_LANDSCAPES) info->landscape = 0;
}
}
@ -386,15 +392,13 @@ void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info)
const uint8 version = p->Recv_uint8();
if (version > 0) return; // Unknown version
info->game_info_version = 255;
info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
info->companies_max = p->Recv_uint8 ();
info->companies_on = p->Recv_uint8 ();
info->spectators_max = p->Recv_uint8 ();
p->Recv_string(info->server_name, sizeof(info->server_name));
p->Recv_string(info->server_revision, sizeof(info->server_revision));
info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);
info->server_revision = p->Recv_string(NETWORK_LONG_REVISION_LENGTH);
p->Recv_uint8 (); // Used to contain server-lang.
info->use_password = p->Recv_bool ();
info->clients_max = p->Recv_uint8 ();
@ -403,7 +407,7 @@ void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info)
while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
info->map_width = p->Recv_uint32();
info->map_height = p->Recv_uint32();
info->map_set = p->Recv_uint8 ();
info->landscape = p->Recv_uint8 ();
info->dedicated = p->Recv_bool ();
{
@ -425,7 +429,7 @@ void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info)
}
}
if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
if (info->landscape >= NETWORK_NUM_LANDSCAPES) info->landscape = 0;
}
/**

@ -57,36 +57,34 @@
*/
/**
* The game information that is not generated on-the-fly and has to
* be sent to the clients.
* The game information that is sent from the server to the client.
*/
struct NetworkServerGameInfo {
byte clients_on; ///< Current count of clients on server
GRFConfig *grfconfig; ///< List of NewGRF files used
Date start_date; ///< When the game started
Date game_date; ///< Current date
uint32 map_width; ///< Map width
uint32 map_height; ///< Map height
std::string server_name; ///< Server name
std::string server_revision; ///< The version number the server is using (e.g.: 'r304' or 0.5.0)
bool dedicated; ///< Is this a dedicated server?
bool use_password; ///< Is this server passworded?
byte clients_on; ///< Current count of clients on server
byte clients_max; ///< Max clients allowed on server
byte companies_on; ///< How many started companies do we have
byte companies_max; ///< Max companies allowed on server
byte spectators_on; ///< How many spectators do we have?
byte spectators_max; ///< Max spectators allowed on server
byte landscape; ///< The used landscape
};
/**
* The game information that is sent from the server to the clients.
* The game information that is sent from the server to the clients
* with extra information only required at the client side.
*/
struct NetworkGameInfo : NetworkServerGameInfo {
GRFConfig *grfconfig; ///< List of NewGRF files used
Date start_date; ///< When the game started
Date game_date; ///< Current date
uint32 map_width; ///< Map width
uint32 map_height; ///< Map height
char server_name[NETWORK_NAME_LENGTH]; ///< Server name
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?
bool version_compatible; ///< Can we connect to this server or not? (based on server_revision)
bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match
bool use_password; ///< Is this server passworded?
byte game_info_version; ///< Version of the game info
byte clients_max; ///< Max clients allowed on server
byte companies_on; ///< How many started companies do we have
byte companies_max; ///< Max companies allowed on server
byte spectators_on; ///< How many spectators do we have?
byte spectators_max; ///< Max spectators allowed on server
byte map_set; ///< Graphical set
};
extern NetworkServerGameInfo _network_game_info;
@ -95,14 +93,15 @@ const char *GetNetworkRevisionString();
bool IsNetworkCompatibleVersion(const char *other, bool extended = false);
void CheckGameCompatibility(NetworkGameInfo &ngi, bool extended = false);
void FillNetworkGameInfo(NetworkGameInfo &ngi);
void FillStaticNetworkServerGameInfo();
const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo();
void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf);
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf);
void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info);
void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info);
void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info);
void SerializeNetworkGameInfoExtended(Packet *p, const NetworkGameInfo *info, uint16 flags, uint16 version);
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info);
void SerializeNetworkGameInfoExtended(Packet *p, const NetworkServerGameInfo *info, uint16 flags, uint16 version);
#endif /* NETWORK_CORE_GAME_INFO_H */

@ -168,12 +168,11 @@ void Packet::Send_uint64(uint64 data)
* the string + '\0'. No size-byte or something.
* @param data The string to send
*/
void Packet::Send_string(const char *data)
void Packet::Send_string(const std::string_view data)
{
assert(data != nullptr);
/* Length of the string + 1 for the '\0' termination. */
assert(this->CanWriteToPacket(strlen(data) + 1));
while (this->buffer.emplace_back(*data++) != '\0') {}
assert(this->CanWriteToPacket(data.size() + 1));
this->buffer.insert(this->buffer.end(), data.begin(), data.end());
this->buffer.emplace_back('\0');
}
/**
@ -404,6 +403,35 @@ void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings set
str_validate(bufp, last, settings);
}
/**
* Reads characters (bytes) from the packet until it finds a '\0', or reaches a
* maximum of \c length characters.
* When the '\0' has not been reached in the first \c length read characters,
* more characters are read from the packet until '\0' has been reached. However,
* these characters will not end up in the returned string.
* The length of the returned string will be at most \c length - 1 characters.
* @param length The maximum length of the string including '\0'.
* @param settings The string validation settings.
* @return The validated string.
*/
std::string Packet::Recv_string(size_t length, StringValidationSettings settings)
{
assert(length > 1);
/* Both loops with Recv_uint8 terminate when reading past the end of the
* packet as Recv_uint8 then closes the connection and returns 0. */
std::string str;
char character;
while (--length > 0 && (character = this->Recv_uint8()) != '\0') str.push_back(character);
if (length == 0) {
/* The string in the packet was longer. Read until the termination. */
while (this->Recv_uint8() != '\0') {}
}
return str_validate(str, settings);
}
/**
* Get the amount of bytes that are still available for the Transfer functions.
* @return The number of bytes that still have to be transfered.

@ -69,7 +69,7 @@ public:
void Send_uint16(uint16 data);
void Send_uint32(uint32 data);
void Send_uint64(uint64 data);
void Send_string(const char *data);
void Send_string(const std::string_view data);
size_t Send_bytes (const byte *begin, const byte *end);
void Send_binary(const char *data, const size_t size);
@ -88,6 +88,7 @@ public:
uint32 Recv_uint32();
uint64 Recv_uint64();
void Recv_string(char *buffer, size_t size, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
std::string Recv_string(size_t length, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
void Recv_string(std::string &buffer, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
void Recv_binary(char *buffer, size_t size);
void Recv_binary(std::string &buffer, size_t size);

@ -87,7 +87,7 @@ protected:
NetworkAddress address;
public:
TCPConnecter(const NetworkAddress &address);
TCPConnecter(const std::string &connection_string, uint16 default_port);
/** Silence the warnings */
virtual ~TCPConnecter() {}

@ -13,6 +13,7 @@
#include "../../thread.h"
#include "tcp.h"
#include "../network_internal.h"
#include "../../safeguards.h"
@ -21,15 +22,16 @@ static std::vector<TCPConnecter *> _tcp_connecters;
/**
* Create a new connecter for the given address
* @param address the (un)resolved address to connect to
* @param connection_string the address to connect to
*/
TCPConnecter::TCPConnecter(const NetworkAddress &address) :
TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port) :
connected(false),
aborted(false),
killed(false),
sock(INVALID_SOCKET),
address(address)
sock(INVALID_SOCKET)
{
this->address = ParseConnectionString(connection_string, default_port);
_tcp_connecters.push_back(this);
if (!StartNewThread(nullptr, "ottd:tcp", &TCPConnecter::ThreadEntry, this)) {
this->Connect();

@ -203,11 +203,9 @@ int NetworkHTTPSocketHandler::HandleHeader()
*url = '\0';
NetworkAddress address = ParseConnectionString(hname, 80);
/* Restore the URL. */
*url = '/';
new NetworkHTTPContentConnecter(address, callback, url, data, depth);
new NetworkHTTPContentConnecter(hname, callback, url, data, depth);
return 0;
}

@ -81,16 +81,14 @@ class NetworkHTTPContentConnecter : TCPConnecter {
public:
/**
* Start the connecting.
* @param address the address to connect to
* @param callback the callback for HTTP retrieval
* @param url the url at the server
* @param data the data to send
* @param depth the depth (redirect recursion) of the queries
* @param connection_string The address to connect to.
* @param callback The callback for HTTP retrieval.
* @param url The url at the server.
* @param data The data to send.
* @param depth The depth (redirect recursion) of the queries.
*/
NetworkHTTPContentConnecter(const NetworkAddress &address,
HTTPCallback *callback, const char *url,
const char *data = nullptr, int depth = 0) :
TCPConnecter(address),
NetworkHTTPContentConnecter(const std::string &connection_string, HTTPCallback *callback, const char *url, const char *data = nullptr, int depth = 0) :
TCPConnecter(connection_string, 80),
callback(callback),
url(stredup(url)),
data(data),

@ -28,11 +28,11 @@ NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind)
this->bind.push_back(addr);
}
} else {
/* As hostname nullptr and port 0/nullptr don't go well when
/* As an empty hostname and port 0 don't go well when
* resolving it we need to add an address for each of
* the address families we support. */
this->bind.emplace_back(nullptr, 0, AF_INET);
this->bind.emplace_back(nullptr, 0, AF_INET6);
this->bind.emplace_back("", 0, AF_INET);
this->bind.emplace_back("", 0, AF_INET6);
}
this->fragment_token = ((uint64) InteractiveRandom()) | (((uint64) InteractiveRandom()) << 32);

@ -34,6 +34,7 @@
#include "../gfx_func.h"
#include "../error.h"
#include "../core/checksum_func.hpp"
#include <charconv>
#include "../safeguards.h"
@ -479,36 +480,51 @@ static void CheckPauseOnJoin()
* 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. Similar for company, if set.
* Returns the IP part as a string view into the passed string. This view is
* valid as long the passed connection string is valid. If there is no port
* present in the connection string, the port reference will not be touched.
* When there is no company ID present in the connection string or company_id
* is nullptr, then company ID will not be touched.
*
* @param connection_string The string with the connection data.
* @param port The port reference to set.
* @param company_id The company ID to set, if available.
* @return A std::string_view into the connection string with the (IP) address part.
*/
void ParseFullConnectionString(const char **company, const char **port, char *connection_string)
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16 &port, CompanyID *company_id)
{
bool ipv6 = (strchr(connection_string, ':') != strrchr(connection_string, ':'));
for (char *p = connection_string; *p != '\0'; p++) {
switch (*p) {
case '[':
ipv6 = true;
break;
case ']':
ipv6 = false;
break;
case '#':
if (company == nullptr) continue;
*company = p + 1;
*p = '\0';
break;
case ':':
if (ipv6) break;
*port = p + 1;
*p = '\0';
break;
std::string_view ip = connection_string;
if (company_id != nullptr) {
size_t offset = ip.find_last_of('#');
if (offset != std::string::npos) {
std::string_view company_string = ip.substr(offset + 1);
ip = ip.substr(0, offset);
uint8 company_value;
auto [_, err] = std::from_chars(company_string.data(), company_string.data() + company_string.size(), company_value);
if (err == std::errc()) {
if (company_value != COMPANY_NEW_COMPANY && company_value != COMPANY_SPECTATOR) {
if (company_value > MAX_COMPANIES || company_value == 0) {
*company_id = COMPANY_SPECTATOR;
} else {
/* "#1" means the first company, which has index 0. */
*company_id = (CompanyID)(company_value - 1);
}
} else {
*company_id = (CompanyID)company_value;
}
}
}
}
size_t port_offset = ip.find_last_of(':');
size_t ipv6_close = ip.find_last_of(']');
if (port_offset != std::string::npos && (ipv6_close == std::string::npos || ipv6_close < port_offset)) {
std::string_view port_string = ip.substr(port_offset + 1);
ip = ip.substr(0, port_offset);
std::from_chars(port_string.data(), port_string.data() + port_string.size(), port);
}
return ip;
}
/**
@ -519,16 +535,11 @@ void ParseFullConnectionString(const char **company, const char **port, char *co
* @param default_port The default port to set port to if not in connection_string.
* @return A valid NetworkAddress of the parsed information.
*/
NetworkAddress ParseConnectionString(const std::string &connection_string, int default_port)
NetworkAddress ParseConnectionString(const std::string &connection_string, uint16 default_port)
{
char internal_connection_string[NETWORK_HOSTNAME_PORT_LENGTH];
strecpy(internal_connection_string, connection_string.c_str(), lastof(internal_connection_string));
const char *port = nullptr;
ParseFullConnectionString(nullptr, &port, internal_connection_string);
int rport = port != nullptr ? atoi(port) : default_port;
return NetworkAddress(internal_connection_string, rport);
uint16 port = default_port;
std::string_view ip = ParseFullConnectionString(connection_string, port);
return NetworkAddress(ip, port);
}
/**
@ -536,24 +547,16 @@ NetworkAddress ParseConnectionString(const std::string &connection_string, int d
* 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.
* @param company Pointer to the company variable to set iff indicted.
* @return A valid NetworkAddress of the parsed information.
*/
NetworkAddress ParseGameConnectionString(CompanyID *company, const std::string &connection_string, int default_port)
static NetworkAddress ParseGameConnectionString(const std::string &connection_string, uint16 default_port, CompanyID *company)
{
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);
uint16 port = default_port;
std::string_view ip = ParseFullConnectionString(connection_string, port, company);
return NetworkAddress(ip, port);
}
/**
@ -637,9 +640,10 @@ static void NetworkInitialize(bool close_admins = true)
class TCPQueryConnecter : TCPConnecter {
private:
bool request_company_info;
std::string connection_string;
public:
TCPQueryConnecter(const NetworkAddress &address, bool request_company_info) : TCPConnecter(address), request_company_info(request_company_info) {}
TCPQueryConnecter(const std::string &connection_string, bool request_company_info) : TCPConnecter(connection_string, NETWORK_DEFAULT_PORT), request_company_info(request_company_info), connection_string(connection_string) {}
void OnFailure() override
{
@ -649,24 +653,24 @@ public:
void OnConnect(SOCKET s) override
{
_networking = true;
new ClientNetworkGameSocketHandler(s, address);
new ClientNetworkGameSocketHandler(s, this->connection_string);
MyClient::SendInformationQuery(request_company_info);
}
};
/**
* Query a server to fetch his game-info.
* @param address the address to query.
* @param connection_string the address to query.
* @param request_company_info Whether to request company info too.
*/
void NetworkTCPQueryServer(NetworkAddress address, bool request_company_info)
void NetworkTCPQueryServer(const std::string &connection_string, bool request_company_info)
{
if (!_network_available) return;
NetworkDisconnect();
NetworkInitialize();
new TCPQueryConnecter(address, request_company_info);
new TCPQueryConnecter(connection_string, request_company_info);
}
/**
@ -680,20 +684,18 @@ NetworkGameList *NetworkAddServer(const std::string &connection_string)
{
if (connection_string.empty()) return nullptr;
NetworkAddress address = ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT);
/* Ensure the item already exists in the list */
NetworkGameList *item = NetworkGameListAddItem(address);
if (StrEmpty(item->info.server_name)) {
NetworkGameList *item = NetworkGameListAddItem(connection_string);
if (item->info.server_name.empty()) {
ClearGRFConfigList(&item->info.grfconfig);
address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name));
item->info.server_name = connection_string;
item->manually = true;
NetworkRebuildHostList();
UpdateNetworkGameWindow();
}
NetworkTCPQueryServer(address);
NetworkTCPQueryServer(connection_string);
return item;
}
@ -723,14 +725,17 @@ void NetworkRebuildHostList()
_network_host_list.clear();
for (NetworkGameList *item = _network_game_list; item != nullptr; item = item->next) {
if (item->manually) _network_host_list.emplace_back(NetworkAddressDumper().GetAddressAsString(&(item->address), false));
if (item->manually) _network_host_list.emplace_back(item->connection_string);
}
}
/** Non blocking connection create to actually connect to servers */
class TCPClientConnecter : TCPConnecter {
private:
std::string connection_string;
public:
TCPClientConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
TCPClientConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_DEFAULT_PORT), connection_string(connection_string) {}
void OnFailure() override
{
@ -740,7 +745,7 @@ public:
void OnConnect(SOCKET s) override
{
_networking = true;
new ClientNetworkGameSocketHandler(s, this->address);
new ClientNetworkGameSocketHandler(s, this->connection_string);
IConsoleCmdExec("exec scripts/on_client.scr 0");
NetworkClient_Connected();
}
@ -766,34 +771,12 @@ public:
bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const char *join_server_password, const char *join_company_password)
{
CompanyID join_as = default_company;
NetworkAddress address = ParseGameConnectionString(&join_as, connection_string, NETWORK_DEFAULT_PORT);
if (join_as != COMPANY_NEW_COMPANY && join_as != COMPANY_SPECTATOR) {
join_as--;
if (join_as >= MAX_COMPANIES) {
return false;
}
}
return NetworkClientConnectGame(address, join_as, join_server_password, join_company_password);
}
std::string resolved_connection_string = ParseGameConnectionString(connection_string, NETWORK_DEFAULT_PORT, &join_as).GetAddressAsString(false);
/**
* 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.connection_string = resolved_connection_string;
_network_join.company = join_as;
_network_join.server_password = join_server_password;
_network_join.company_password = join_company_password;
@ -822,11 +805,11 @@ void NetworkClientJoinGame()
NetworkDisconnect();
NetworkInitialize();
strecpy(_settings_client.network.last_joined, _network_join.address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined));
strecpy(_settings_client.network.last_joined, _network_join.connection_string.c_str(), lastof(_settings_client.network.last_joined));
_network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
ShowJoinStatusWindow();
new TCPClientConnecter(_network_join.address);
new TCPClientConnecter(_network_join.connection_string);
}
static void NetworkInitGameInfo()
@ -835,6 +818,7 @@ static void NetworkInitGameInfo()
strecpy(_settings_client.network.server_name, "Unnamed Server", lastof(_settings_client.network.server_name));
}
FillStaticNetworkServerGameInfo();
/* The server is a client too */
_network_game_info.clients_on = _network_dedicated ? 0 : 1;
@ -1243,7 +1227,7 @@ void NetworkStartUp()
/* Generate an server id when there is none yet */
if (StrEmpty(_settings_client.network.network_id)) NetworkGenerateServerId();
memset(&_network_game_info, 0, sizeof(_network_game_info));
_network_game_info = {};
NetworkInitialize();
DEBUG(net, 3, "[core] network online, multiplayer available");

@ -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, NetworkAddress address)
ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler (SOCKET s, std::string connection_string)
: NetworkGameSocketHandler(s),
address(address), savegame(nullptr), token(0), status(STATUS_INACTIVE)
connection_string(std::move(connection_string)), savegame(nullptr), token(0), status(STATUS_INACTIVE)
{
assert(ClientNetworkGameSocketHandler::my_client == nullptr);
ClientNetworkGameSocketHandler::my_client = this;
@ -702,7 +702,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packe
NetworkGameList *item = GetLobbyGameInfo();
if (item == nullptr) {
/* This is not the lobby, so add it to the game list. */
item = NetworkGameListAddItem(this->address);
item = NetworkGameListAddItem(this->connection_string);
}
/* Clear any existing GRFConfig chain. */

@ -15,7 +15,7 @@
/** Class for handling the client side of the game connection. */
class ClientNetworkGameSocketHandler : public NetworkGameSocketHandler {
private:
NetworkAddress address; ///< Address we are connected to.
std::string connection_string; ///< 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.
@ -86,7 +86,7 @@ protected:
static NetworkRecvStatus SendMapOk();
void CheckConnection();
public:
ClientNetworkGameSocketHandler(SOCKET s, NetworkAddress address);
ClientNetworkGameSocketHandler(SOCKET s, std::string connection_string);
~ClientNetworkGameSocketHandler();
NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override;
@ -132,10 +132,10 @@ void NetworkClientSetCompanyPassword(const char *password);
/** 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.
std::string connection_string; ///< 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 NetworkJoinInfo _network_join;

@ -367,8 +367,7 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const Conten
this->http_response_index = -1;
NetworkAddress address(NETWORK_CONTENT_MIRROR_HOST, NETWORK_CONTENT_MIRROR_PORT);
new NetworkHTTPContentConnecter(address, this, NETWORK_CONTENT_MIRROR_URL, content_request);
new NetworkHTTPContentConnecter(NETWORK_CONTENT_MIRROR_HOST, this, NETWORK_CONTENT_MIRROR_URL, content_request);
/* NetworkHTTPContentConnecter takes over freeing of content_request! */
}
@ -774,7 +773,7 @@ public:
* Initiate the connecting.
* @param address The address of the server.
*/
NetworkContentConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
NetworkContentConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_CONTENT_SERVER_PORT) {}
void OnFailure() override
{
@ -800,7 +799,7 @@ void ClientNetworkContentSocketHandler::Connect()
{
if (this->sock != INVALID_SOCKET || this->isConnecting) return;
this->isConnecting = true;
new NetworkContentConnecter(NetworkAddress(NETWORK_CONTENT_SERVER_HOST, NETWORK_CONTENT_SERVER_PORT, AF_UNSPEC));
new NetworkContentConnecter(NETWORK_CONTENT_SERVER_HOST);
}
/**

@ -45,7 +45,7 @@ void NetworkReboot();
void NetworkDisconnect(bool blocking = false, bool close_admins = true);
void NetworkGameLoop();
void NetworkBackgroundLoop();
void ParseFullConnectionString(const char **company, const char **port, char *connection_string);
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16 &port, CompanyID *company_id = nullptr);
void NetworkStartDebugLog(const std::string &connection_string);
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
@ -70,6 +70,7 @@ void NetworkServerDailyLoop();
void NetworkServerMonthlyLoop();
void NetworkServerYearlyLoop();
void NetworkServerSendConfigUpdate();
void NetworkServerUpdateGameInfo();
void NetworkServerShowStatusToConsole();
bool NetworkServerStart();
void NetworkServerNewCompany(const Company *company, NetworkClientInfo *ci);

@ -44,20 +44,20 @@ static void NetworkGameListHandleDelayedInsert()
while (ins_item != nullptr && !_network_game_delayed_insertion_list.compare_exchange_weak(ins_item, ins_item->next, std::memory_order_acq_rel)) {}
if (ins_item == nullptr) break; // No item left.
NetworkGameList *item = NetworkGameListAddItem(ins_item->address);
NetworkGameList *item = NetworkGameListAddItem(ins_item->connection_string);
if (item != nullptr) {
if (StrEmpty(item->info.server_name)) {
if (item->info.server_name.empty()) {
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));
item->info = {};
item->info.server_name = ins_item->info.server_name;
item->online = false;
}
item->manually |= ins_item->manually;
if (item->manually) NetworkRebuildHostList();
UpdateNetworkGameWindow();
}
free(ins_item);
delete ins_item;
}
}
@ -67,19 +67,20 @@ static void NetworkGameListHandleDelayedInsert()
* @param address the address of the to-be added item
* @return a point to the newly added or already existing item
*/
NetworkGameList *NetworkGameListAddItem(NetworkAddress address)
NetworkGameList *NetworkGameListAddItem(const std::string &connection_string)
{
NetworkGameList *item, *prev_item;
/* Parse the connection string to ensure the default port is there. */
const std::string resolved_connection_string = ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT).GetAddressAsString(false);
prev_item = nullptr;
for (item = _network_game_list; item != nullptr; item = item->next) {
if (item->address == address) return item;
if (item->connection_string == resolved_connection_string) return item;
prev_item = item;
}
item = CallocT<NetworkGameList>(1);
item->next = nullptr;
item->address = address;
item = new NetworkGameList(resolved_connection_string);
if (prev_item == nullptr) {
_network_game_list = item;
@ -109,8 +110,7 @@ void NetworkGameListRemoveItem(NetworkGameList *remove)
/* Remove GRFConfig information */
ClearGRFConfigList(&remove->info.grfconfig);
free(remove);
remove = nullptr;
delete remove;
DEBUG(net, 4, "[gamelist] removed server from list");
NetworkRebuildHostList();
@ -141,7 +141,7 @@ void NetworkGameListRequery()
/* item gets mostly zeroed by NetworkUDPQueryServer */
uint8 retries = item->retries;
NetworkUDPQueryServer(item->address);
NetworkUDPQueryServer(item->connection_string);
item->retries = (retries >= REFRESH_GAMEINFO_X_REQUERIES) ? 0 : retries;
}
}

@ -16,19 +16,24 @@
/** Structure with information shown in the game list (GUI) */
struct NetworkGameList {
NetworkGameInfo info; ///< The game information of this server
NetworkAddress address; ///< The connection info of the game server
bool online; ///< False if the server did not respond (default status)
bool manually; ///< True if the server was added manually
uint8 retries; ///< Number of retries (to stop requerying)
NetworkGameList *next; ///< Next pointer to make a linked game list
NetworkGameList(const std::string &connection_string, bool manually = false) :
connection_string(connection_string), manually(manually)
{
}
NetworkGameInfo info = {}; ///< The game information of this server
std::string connection_string; ///< Address of the server
bool online = false; ///< False if the server did not respond (default status)
bool manually = false; ///< True if the server was added manually
uint8 retries = 0; ///< Number of retries (to stop requerying)
NetworkGameList *next = nullptr; ///< Next pointer to make a linked game list
};
/** Game list of this client */
extern NetworkGameList *_network_game_list;
void NetworkGameListAddItemDelayed(NetworkGameList *item);
NetworkGameList *NetworkGameListAddItem(NetworkAddress address);
NetworkGameList *NetworkGameListAddItem(const std::string &connection_string);
void NetworkGameListRemoveItem(NetworkGameList *remove);
void NetworkGameListRequery();

@ -286,8 +286,10 @@ protected:
/** Sort servers by name. */
static bool NGameNameSorter(NetworkGameList * const &a, NetworkGameList * const &b)
{
int r = strnatcmp(a->info.server_name, b->info.server_name, true); // Sort by name (natural sorting).
return r == 0 ? a->address.CompareTo(b->address) < 0: r < 0;
int r = strnatcmp(a->info.server_name.c_str(), b->info.server_name.c_str(), true); // Sort by name (natural sorting).
if (r == 0) r = a->connection_string.compare(b->connection_string);
return r < 0;
}
/**
@ -337,7 +339,7 @@ protected:
static bool NGameAllowedSorter(NetworkGameList * const &a, NetworkGameList * const &b)
{
/* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
int r = StrEmpty(a->info.server_revision) - StrEmpty(b->info.server_revision);
int r = a->info.server_revision.empty() - b->info.server_revision.empty();
/* Reverse default as we are interested in version-compatible clients first */
if (r == 0) r = b->info.version_compatible - a->info.version_compatible;
@ -374,7 +376,7 @@ protected:
assert((*item) != nullptr);
sf.ResetState();
sf.AddLine((*item)->info.server_name);
sf.AddLine((*item)->info.server_name.c_str());
return sf.GetState();
}
@ -648,7 +650,7 @@ public:
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
y += FONT_HEIGHT_NORMAL;
SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + sel->info.map_set);
SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + sel->info.landscape);
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE); // landscape
y += FONT_HEIGHT_NORMAL;
@ -661,8 +663,7 @@ 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;
std::string address = sel->address.GetAddressAsString();
SetDParamStr(0, address.c_str());
SetDParamStr(0, sel->connection_string.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;
@ -766,7 +767,7 @@ public:
break;
case WID_NG_REFRESH: // Refresh
if (this->server != nullptr) NetworkTCPQueryServer(this->server->address);
if (this->server != nullptr) NetworkTCPQueryServer(this->server->connection_string);
break;
case WID_NG_NEWGRF: // NewGRF Settings
@ -1486,22 +1487,22 @@ struct NetworkLobbyWindow : public Window {
case WID_NL_JOIN: // Join company
/* Button can be clicked only when it is enabled. */
NetworkClientConnectGame(this->server->address, this->company);
NetworkClientConnectGame(this->server->connection_string, this->company);
break;
case WID_NL_NEW: // New company
NetworkClientConnectGame(this->server->address, COMPANY_NEW_COMPANY);
NetworkClientConnectGame(this->server->connection_string, COMPANY_NEW_COMPANY);
break;
case WID_NL_SPECTATE: // Spectate game
NetworkClientConnectGame(this->server->address, COMPANY_SPECTATOR);
NetworkClientConnectGame(this->server->connection_string, 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(this->server->address, true);
NetworkTCPQueryServer(this->server->connection_string, true);
break;
}
}
@ -1569,9 +1570,9 @@ static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START);
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
strecpy(_settings_client.network.last_joined, ngl->address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined));
strecpy(_settings_client.network.last_joined, ngl->connection_string.c_str(), lastof(_settings_client.network.last_joined));
NetworkTCPQueryServer(ngl->address, true);
NetworkTCPQueryServer(ngl->connection_string, true);
new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
}

@ -94,7 +94,7 @@ extern uint8 _network_reconnect;
extern CompanyMask _network_company_passworded;
void NetworkTCPQueryServer(NetworkAddress address, bool request_company_info = false);
void NetworkTCPQueryServer(const std::string &connection_string, bool request_company_info = false);
void GetBindAddresses(NetworkAddressList *addresses, uint16 port);
struct NetworkGameList *NetworkAddServer(const std::string &connection_string);
@ -126,8 +126,6 @@ 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);
NetworkAddress ParseConnectionString(const std::string &connection_string, uint16 default_port);
#endif /* NETWORK_INTERNAL_H */

@ -360,11 +360,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientIn
/** Send the client information about the server. */
NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo()
{
NetworkGameInfo ngi;
FillNetworkGameInfo(ngi);
Packet *p = new Packet(PACKET_SERVER_GAME_INFO, SHRT_MAX);
SerializeNetworkGameInfo(p, &ngi);
SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo());
this->SendPacket(p);
@ -373,11 +370,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo()
NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfoExtended(PacketGameType reply_type, uint16 flags, uint16 version)
{
NetworkGameInfo ngi;
FillNetworkGameInfo(ngi);
Packet *p = new Packet(reply_type, SHRT_MAX);
SerializeNetworkGameInfoExtended(p, &ngi, flags, version);
SerializeNetworkGameInfoExtended(p, GetCurrentNetworkServerGameInfo(), flags, version);
this->SendPacket(p);
@ -2166,6 +2160,12 @@ void NetworkServerSendConfigUpdate()
}
}
/** Update the server's NetworkServerGameInfo due to changes in settings. */
void NetworkServerUpdateGameInfo()
{
if (_network_server) FillStaticNetworkServerGameInfo();
}
/**
* Tell that a particular company is (not) passworded.
* @param company_id The company that got/removed the password.

@ -102,35 +102,34 @@ static Packet PrepareUdpClientFindServerPacket()
/**
* Helper function doing the actual work for querying the server.
* @param address The address of the server.
* @param connection_string The address of the server.
* @param needs_mutex Whether we need to acquire locks when sending the packet or not.
* @param manually Whether the address was entered manually.
*/
static void DoNetworkUDPQueryServer(NetworkAddress &address, bool needs_mutex, bool manually)
static void DoNetworkUDPQueryServer(const std::string &connection_string, bool needs_mutex, bool manually)
{
/* Clear item in gamelist */
NetworkGameList *item = CallocT<NetworkGameList>(1);
address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name));
item->address = address;
item->manually = manually;
NetworkGameList *item = new NetworkGameList(connection_string, manually);
item->info.server_name = connection_string;
NetworkGameListAddItemDelayed(item);
std::unique_lock<std::mutex> lock(_udp_client.mutex, std::defer_lock);
if (needs_mutex) lock.lock();
/* Init the packet */
NetworkAddress address = NetworkAddress(ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT));
Packet p = PrepareUdpClientFindServerPacket();
if (_udp_client.socket != nullptr) _udp_client.socket->SendPacket(&p, &address);
}
/**
* Query a specific server.
* @param address The address of the server.
* @param connection_string The address of the server.
* @param manually Whether the address was entered manually.
*/
void NetworkUDPQueryServer(NetworkAddress address, bool manually)
void NetworkUDPQueryServer(const std::string &connection_string, bool manually)
{
if (address.IsResolved() || !StartNewThread(nullptr, "ottd:udp-query", &DoNetworkUDPQueryServer, std::move(address), true, std::move(manually))) {
DoNetworkUDPQueryServer(address, true, manually);
if (!StartNewThread(nullptr, "ottd:udp-query", &DoNetworkUDPQueryServer, std::move(connection_string), true, std::move(manually))) {
DoNetworkUDPQueryServer(connection_string, true, manually);
}
}
@ -173,7 +172,7 @@ protected:
void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) override;
void Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) override;
void Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr) override;
void Reply_CLIENT_FIND_SERVER_extended(Packet *p, NetworkAddress *client_addr, NetworkGameInfo *ngi);
void Reply_CLIENT_FIND_SERVER_extended(Packet *p, NetworkAddress *client_addr, const NetworkServerGameInfo *ngi);
public:
/**
* Create the socket.
@ -190,16 +189,13 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, Networ
return;
}
NetworkGameInfo ngi;
FillNetworkGameInfo(ngi);
if (p->CanReadFromPacket(8) && p->Recv_uint32() == FIND_SERVER_EXTENDED_TOKEN) {
this->Reply_CLIENT_FIND_SERVER_extended(p, client_addr, &ngi);
this->Reply_CLIENT_FIND_SERVER_extended(p, client_addr, GetCurrentNetworkServerGameInfo());
return;
}
Packet packet(PACKET_UDP_SERVER_RESPONSE);
SerializeNetworkGameInfo(&packet, &ngi);
SerializeNetworkGameInfo(&packet, GetCurrentNetworkServerGameInfo());
/* Let the client know that we are here */
this->SendPacket(&packet, client_addr);
@ -207,7 +203,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, Networ
DEBUG(net, 2, "[udp] queried from %s", client_addr->GetHostname());
}
void ServerNetworkUDPSocketHandler::Reply_CLIENT_FIND_SERVER_extended(Packet *p, NetworkAddress *client_addr, NetworkGameInfo *ngi)
void ServerNetworkUDPSocketHandler::Reply_CLIENT_FIND_SERVER_extended(Packet *p, NetworkAddress *client_addr, const NetworkServerGameInfo *ngi)
{
uint16 flags = p->Recv_uint16();
uint16 version = p->Recv_uint16();
@ -396,7 +392,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE_Common(Packet *p, Ne
DEBUG(net, 4, "[udp]%s server response from %s", extended ? " extended" : "", NetworkAddressDumper().GetAddressAsString(client_addr));
/* Find next item */
item = NetworkGameListAddItem(*client_addr);
item = NetworkGameListAddItem(client_addr->GetAddressAsString(false));
/* Clear any existing GRFConfig chain. */
ClearGRFConfigList(&item->info.grfconfig);
@ -434,7 +430,8 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE_Common(Packet *p, Ne
SerializeGRFIdentifier(&packet, &in_request[i]->ident);
}
this->SendPacket(&packet, &item->address);
NetworkAddress address = NetworkAddress(ParseConnectionString(item->connection_string, NETWORK_DEFAULT_PORT));
this->SendPacket(&packet, &address);
DEBUG(net, 4, "[udp] sent newgrf data request (%u) to %s", in_request_count, NetworkAddressDumper().GetAddressAsString(client_addr));
@ -453,7 +450,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE_Common(Packet *p, Ne
}
if (client_addr->GetAddress()->ss_family == AF_INET6) {
strecat(item->info.server_name, " (IPv6)", lastof(item->info.server_name));
item->info.server_name.append(" (IPv6)");
}
UpdateNetworkGameWindow();
@ -489,7 +486,7 @@ void ClientNetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, Netw
/* Somehow we reached the end of the packet */
if (this->HasClientQuit()) return;
DoNetworkUDPQueryServer(addr, false, false);
DoNetworkUDPQueryServer(addr.GetAddressAsString(false), false, false);
}
}
}

@ -15,7 +15,7 @@
void NetworkUDPInitialize();
void NetworkUDPSearchGame();
void NetworkUDPQueryMasterServer();
void NetworkUDPQueryServer(NetworkAddress address, bool manually = false);
void NetworkUDPQueryServer(const std::string &connection_string, bool manually = false);
void NetworkUDPAdvertise();
void NetworkUDPRemoveAdvertise(bool blocking);
void NetworkUDPClose();

@ -51,9 +51,9 @@ void ShowNewGRFError()
if (c->error == nullptr || (c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL && c->error->severity != STR_NEWGRF_ERROR_MSG_ERROR)) continue;
SetDParam (0, c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING);
SetDParamStr(1, c->error->custom_message.c_str());
SetDParamStr(1, c->error->custom_message);
SetDParamStr(2, c->filename);
SetDParamStr(3, c->error->data.c_str());
SetDParamStr(3, c->error->data);
for (uint i = 0; i < lengthof(c->error->param_value); i++) {
SetDParam(4 + i, c->error->param_value[i]);
}
@ -70,9 +70,9 @@ static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint right, uint
{
if (c->error != nullptr) {
char message[512];
SetDParamStr(0, c->error->custom_message.c_str()); // is skipped by built-in messages
SetDParamStr(0, c->error->custom_message); // is skipped by built-in messages
SetDParamStr(1, c->filename);
SetDParamStr(2, c->error->data.c_str());
SetDParamStr(2, c->error->data);
for (uint i = 0; i < lengthof(c->error->param_value); i++) {
SetDParam(3 + i, c->error->param_value[i]);
}
@ -752,7 +752,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
case WID_NS_PRESET_LIST: {
Dimension d = GetStringBoundingBox(STR_NUM_CUSTOM);
for (const auto &i : this->grf_presets) {
SetDParamStr(0, i.c_str());
SetDParamStr(0, i);
d = maxdim(d, GetStringBoundingBox(STR_JUST_RAW_STRING));
}
d.width += padding.width;
@ -785,7 +785,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
SetDParam(0, STR_NUM_CUSTOM);
} else {
SetDParam(0, STR_JUST_RAW_STRING);
SetDParamStr(1, this->grf_presets[this->preset].c_str());
SetDParamStr(1, this->grf_presets[this->preset]);
}
break;
}

@ -555,7 +555,7 @@ void OpenBrowser(const char *url)
struct AfterNewGRFScan : NewGRFScanCallback {
Year startyear; ///< The start year.
uint32 generation_seed; ///< Seed for the new game.
char *dedicated_host; ///< Hostname for the dedicated server.
std::string dedicated_host; ///< Hostname for the dedicated server.
uint16 dedicated_port; ///< Port for the dedicated server.
char *network_conn; ///< Information about the server to connect to, or nullptr.
const char *join_server_password; ///< The password to join the server with.
@ -567,7 +567,7 @@ struct AfterNewGRFScan : NewGRFScanCallback {
*/
AfterNewGRFScan() :
startyear(INVALID_YEAR), generation_seed(GENERATE_NEW_SEED),
dedicated_host(nullptr), dedicated_port(0), network_conn(nullptr),
dedicated_port(0), network_conn(nullptr),
join_server_password(nullptr), join_company_password(nullptr),
save_config(true)
{
@ -608,7 +608,7 @@ struct AfterNewGRFScan : NewGRFScanCallback {
if (startyear != INVALID_YEAR) IConsoleSetSetting("game_creation.starting_year", startyear);
if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed;
if (dedicated_host != nullptr) {
if (!dedicated_host.empty()) {
_network_bind_list.clear();
_network_bind_list.emplace_back(dedicated_host);
}
@ -720,10 +720,7 @@ int openttd_main(int argc, char *argv[])
dedicated = true;
SetDebugString("net=3");
if (mgo.opt != nullptr) {
const char *port = nullptr;
ParseFullConnectionString(nullptr, &port, mgo.opt);
if (!StrEmpty(mgo.opt)) scanner->dedicated_host = mgo.opt;
if (port != nullptr) scanner->dedicated_port = atoi(port);
scanner->dedicated_host = ParseFullConnectionString(mgo.opt, scanner->dedicated_port);
}
break;
case 'f': _dedicated_forks = true; break;
@ -1000,6 +997,28 @@ void HandleExitGameRequest()
}
}
/**
* Triggers everything that should be triggered when starting a game.
* @param dedicated_server Whether this is a dedicated server or not.
*/
static void OnStartGame(bool dedicated_server)
{
/* Update the local company for a loaded game. It is either always
* a company or in the case of a dedicated server a spectator */
if (_network_server && !dedicated_server) {
NetworkServerDoMove(CLIENT_ID_SERVER, GetDefaultLocalCompany());
} else {
SetLocalCompany(dedicated_server ? COMPANY_SPECTATOR : GetDefaultLocalCompany());
}
if (_ctrl_pressed && !dedicated_server) {
DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);
}
/* Update the static game info to set the values from the new game. */
NetworkServerUpdateGameInfo();
/* Execute the game-start script */
IConsoleCmdExec("exec scripts/game_start.scr 0");
}
static void MakeNewGameDone()
{
SettingsDisableElrail(_settings_game.vehicle.disable_elrails);
@ -1009,9 +1028,8 @@ static void MakeNewGameDone()
/* In a dedicated server, the server does not play */
if (!VideoDriver::GetInstance()->HasGUI()) {
SetLocalCompany(COMPANY_SPECTATOR);
OnStartGame(true);
if (_settings_client.gui.pause_on_newgame) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);
IConsoleCmdExec("exec scripts/game_start.scr 0");
return;
}
@ -1030,9 +1048,7 @@ static void MakeNewGameDone()
BuildOwnerLegend();
}
IConsoleCmdExec("exec scripts/game_start.scr 0");
SetLocalCompany(COMPANY_FIRST);
OnStartGame(false);
InitializeRailGUI();
InitializeRoadGUI();
@ -1227,18 +1243,7 @@ void SwitchToMode(SwitchMode new_mode)
/* Reset engine pool to simplify changing engine NewGRFs in scenario editor. */
EngineOverrideManager::ResetToCurrentNewGRFConfig();
}
/* Update the local company for a loaded game. It is either always
* a company or in the case of a dedicated server a spectator */
if (_network_server && !_network_dedicated) {
NetworkServerDoMove(CLIENT_ID_SERVER, GetDefaultLocalCompany());
} else {
SetLocalCompany(_network_dedicated ? COMPANY_SPECTATOR : GetDefaultLocalCompany());
}
if (_ctrl_pressed && !_network_dedicated) {
DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);
}
/* Execute the game-start script */
IConsoleCmdExec("exec scripts/game_start.scr 0");
OnStartGame(_network_dedicated);
/* Decrease pause counter (was increased from opening load dialog) */
DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE);
}

@ -1825,6 +1825,7 @@ static bool UpdateServerPassword(int32 p1)
_settings_client.network.server_password[0] = '\0';
}
NetworkServerUpdateGameInfo();
return true;
}
@ -1848,6 +1849,7 @@ static bool UpdateSettingsPassword(int32 p1)
static bool UpdateClientConfigValues(int32 p1)
{
NetworkServerUpdateGameInfo();
if (_network_server) NetworkServerSendConfigUpdate();
return true;
@ -2071,7 +2073,7 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN);
}
SetDParamStr(0, StrEmpty(filename) ? item->name.c_str() : filename);
SetDParamStr(0, StrEmpty(filename) ? item->name : filename);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL);
delete c;
continue;

@ -127,7 +127,7 @@ struct BaseSetTextfileWindow : public TextfileWindow {
{
if (widget == WID_TF_CAPTION) {
SetDParam(0, content_type);
SetDParamStr(1, this->baseset->name.c_str());
SetDParamStr(1, this->baseset->name);
}
}
};
@ -308,10 +308,10 @@ struct GameOptionsWindow : Window {
case WID_GO_LANG_DROPDOWN: SetDParamStr(0, _current_language->own_name); break;
case WID_GO_GUI_ZOOM_DROPDOWN: SetDParam(0, _gui_zoom_dropdown[_gui_zoom_cfg != ZOOM_LVL_CFG_AUTO ? ZOOM_LVL_OUT_4X - _gui_zoom_cfg + 1 : 0]); break;
case WID_GO_FONT_ZOOM_DROPDOWN: SetDParam(0, _font_zoom_dropdown[_font_zoom_cfg != ZOOM_LVL_CFG_AUTO ? ZOOM_LVL_OUT_4X - _font_zoom_cfg + 1 : 0]); break;
case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name.c_str()); break;
case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break;
case WID_GO_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumInvalid()); break;
case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name.c_str()); break;
case WID_GO_BASE_MUSIC_DROPDOWN: SetDParamStr(0, BaseMusic::GetUsedSet()->name.c_str()); break;
case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break;
case WID_GO_BASE_MUSIC_DROPDOWN: SetDParamStr(0, BaseMusic::GetUsedSet()->name); break;
case WID_GO_BASE_MUSIC_STATUS: SetDParam(0, BaseMusic::GetUsedSet()->GetNumInvalid()); break;
case WID_GO_REFRESH_RATE_DROPDOWN: SetDParam(0, _settings_client.gui.refresh_rate); break;
case WID_GO_RESOLUTION_DROPDOWN: {

@ -43,7 +43,7 @@ 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) NOACCESS(2);
std::string str_validate(const std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
[[nodiscard]] 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) NOACCESS(2);

@ -300,6 +300,17 @@ void SetDParamStr(uint n, const char *str)
SetDParam(n, (uint64)(size_t)str);
}
/**
* This function is used to "bind" the C string of a std::string to a OpenTTD dparam slot.
* The caller has to ensure that the std::string reference remains valid while the string is shown.
* @param n slot of the string
* @param str string to bind
*/
void SetDParamStr(uint n, const std::string &str)
{
SetDParamStr(n, str.c_str());
}
/**
* Shift the string parameters in the global string parameter array by \a amount positions, making room at the beginning.
* @param amount Number of positions to shift.

@ -208,6 +208,7 @@ void SetDParamMaxValue(uint n, uint64 max_value, uint min_count = 0, FontSize si
void SetDParamMaxDigits(uint n, uint count, FontSize size = FS_NORMAL);
void SetDParamStr(uint n, const char *str);
void SetDParamStr(uint n, const std::string &str);
void CopyInDParam(int offs, const uint64 *src, int num);
void CopyOutDParam(uint64 *dst, int offs, int num);

@ -6233,6 +6233,7 @@ type = SLE_STRB
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
guiflags = SGF_NETWORK_ONLY
def = nullptr
proc = UpdateClientConfigValues
cat = SC_BASIC
[SDTC_STR]
@ -6300,6 +6301,7 @@ guiflags = SGF_NETWORK_ONLY
def = 25
min = 2
max = MAX_CLIENTS
proc = UpdateClientConfigValues
cat = SC_BASIC
[SDTC_VAR]

@ -442,7 +442,7 @@ public:
}
if (!this->town->text.empty()) {
SetDParamStr(0, this->town->text.c_str());
SetDParamStr(0, this->town->text);
DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y += FONT_HEIGHT_NORMAL, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK);
}
}
@ -524,7 +524,7 @@ public:
if (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL;
if (!this->town->text.empty()) {
SetDParamStr(0, this->town->text.c_str());
SetDParamStr(0, this->town->text);
aimed_height += GetStringHeight(STR_JUST_RAW_STRING, width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT);
}

@ -65,7 +65,7 @@ StringID DropDownListParamStringItem::String() const
StringID DropDownListCharStringItem::String() const
{
SetDParamStr(0, this->raw_string.c_str());
SetDParamStr(0, this->raw_string);
return this->string;
}

Loading…
Cancel
Save