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; fios->mtime = 0;
strecpy(fios->name, d_name, lastof(fios->name)); strecpy(fios->name, d_name, lastof(fios->name));
std::string dirname = std::string(d_name) + PATHSEP; 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)); GetString(fios->title, STR_SAVELOAD_DIRECTORY, lastof(fios->title));
str_validate(fios->title, lastof(fios->title)); str_validate(fios->title, lastof(fios->title));
} }

@ -553,7 +553,7 @@ public:
const CompanyProperties &c = *pair.second; const CompanyProperties &c = *pair.second;
if (!c.name.empty()) { if (!c.name.empty()) {
SetDParam(1, STR_JUST_RAW_STRING); SetDParam(1, STR_JUST_RAW_STRING);
SetDParamStr(2, c.name.c_str()); SetDParamStr(2, c.name);
} else { } else {
SetDParam(1, c.name_1); SetDParam(1, c.name_1);
SetDParam(2, c.name_2); 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); 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 * 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; 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. * 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); 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 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 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 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); 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); void DrawCharCentered(WChar c, const Rect &r, TextColour colour);

@ -572,12 +572,12 @@ public:
/* Draw the accepted cargoes, if any. Otherwise, will print "Nothing". */ /* 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); 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); 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". */ /* 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); 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); 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. */ /* Get the additional purchase info text, if it has not already been queried. */
if (HasBit(indsp->callback_mask, CBM_IND_FUND_MORE_TEXT)) { if (HasBit(indsp->callback_mask, CBM_IND_FUND_MORE_TEXT)) {
@ -972,7 +972,7 @@ public:
} }
if (!i->text.empty()) { if (!i->text.empty()) {
SetDParamStr(0, i->text.c_str()); SetDParamStr(0, i->text);
y += WD_PAR_VSEP_WIDE; y += WD_PAR_VSEP_WIDE;
y = DrawStringMultiLine(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK); 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_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_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_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!! ############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :general error 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_SPECTATE :*** {STRING} has joined spectators
STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} has started a new company (#{2:NUM}) 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_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_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_SHUTDOWN :{WHITE}The server closed the session
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}The server is restarting...{}Please wait... 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 :{BLACK}Keel
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Valib kasutajaliideses kasutatava keele 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 :{BLACK}Täisekraan
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Märgi see kast, et OpenTTD täisekraanirežiimis mängida 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_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_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_FRAME :{BLACK}Liidese suurus
STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Vali kasutatav liideseelementide 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_FILTER_TITLE :{BLACK}Märksõna:
STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Ava kõik STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Ava kõik
STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Sulge 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_NO_EXPLANATION_AVAILABLE_HELPTEXT :(seletus puudub)
STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Vaikeväärtus: {ORANGE}{STRING} STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Vaikeväärtus: {ORANGE}{STRING}
STR_CONFIG_SETTING_TYPE :{LTBLUE}Seade liik: {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_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_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_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_CATEGORY :{BLACK}Jagu:
STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Liik: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Liik:
@ -2048,6 +2054,8 @@ STR_FACE_TIE :Lips:
STR_FACE_EARRING :Kõrvarõngas: STR_FACE_EARRING :Kõrvarõngas:
STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Vaheta kraed või kõrvarõngast 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 # Network server list
STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Mitmikmäng 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_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_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_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" i}
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Kliente kuni: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Kliente kuni:
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS.in :sees 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 STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Ettevõte on kaitstud. Sisesta salasõna
# Network company list added strings # 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 STR_NETWORK_COMPANY_LIST_SPECTATE :Jälgi
# Network client list # 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_SERVER :Server
STR_NETWORK_CLIENT :Klient 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_CLIENT_START :{WHITE}Ei õnnestu ühendada
STR_NETWORK_ERROR_TIMEOUT :{WHITE}Ühendus nr {NUM} aegus STR_NETWORK_ERROR_TIMEOUT :{WHITE}Ühendus nr {NUM} aegus
STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Tekkis protokolliviga ja ühendus katkes 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_REVISION :{WHITE}Kliendi osa ei vasta serveri osaga
STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Vale salasõna STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Vale salasõna
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Server on täis 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_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_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_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!! ############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :üldine viga 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_COMPUTER :üldine aegumine
STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :kaardi laadimine võttis liiga kaua aega 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_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 ############ End of leave-in-this-order
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Võimalik ühenduse katkemine 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_ERROR :{RED}Viga: {SILVER}{STRING}
STR_NEWGRF_ERROR_MSG_FATAL :{RED}Saatuslik 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_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_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_DOS_OR_WINDOWS :{1:STRING} on {STRING} TTD osa jaoks.
STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} on mõeldud kasutamiseks {STRING} 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_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_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_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_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_SETTINGS_NONE :{WHITE}- Ei mitään -
STR_CONFIG_SETTING_OFF :pois 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_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_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 :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 :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_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} 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 :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_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_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_NON_LANDSCAPING :Kaikki paitsi maastonmuokkaustoiminnot
STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :Kaikki toiminnot STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :Kaikki toiminnot
STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Käytä ryhmiä kulkuneuvolistassa: {STRING} 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_NEWS_MESSAGES_FULL :Täysi
STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Värilliset uutiset ilmestyvät: {STRING} 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_STARTING_YEAR :Aloitusvuosi: {STRING}
STR_CONFIG_SETTING_ENDING_YEAR :Pistelaskun päättymisvuosi: {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. 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_ASYMMETRIC :epäsymmetrinen
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :symmetrinen STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :symmetrinen
STR_CONFIG_SETTING_DISTRIBUTION_PAX :Matkustajien jakautuminen: {STRING} 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 :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 :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 :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 :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_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} 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_GENERAL :{ORANGE}Yleinen
STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :{ORANGE}Näkymät STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :{ORANGE}Näkymät
STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}Rakentaminen 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_COMPANY :{ORANGE}Yhtiö
STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Talous STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Talous
STR_CONFIG_SETTING_VEHICLES :{ORANGE}Kulkuneuvot STR_CONFIG_SETTING_VEHICLES :{ORANGE}Kulkuneuvot
@ -1882,7 +1882,7 @@ STR_QUIT_NO :{BLACK}Ei
# Abandon game # Abandon game
STR_ABANDON_GAME_CAPTION :{WHITE}Pelin lopetus STR_ABANDON_GAME_CAPTION :{WHITE}Pelin lopetus
STR_ABANDON_GAME_QUERY :{YELLOW}Lopetetaanko peli? 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 # Cheat window
STR_CHEATS :{WHITE}Huijaukset 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_REVISION :{WHITE}Tämän asiakkaan versio ei vastaa palvelimen versiota
STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Väärä salasana STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Väärä salasana
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Palvelin on täynnä 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_KICKED :{WHITE}Sinut potkittiin pihalle palvelimelta
STR_NETWORK_ERROR_KICK_MESSAGE :{WHITE}Syy: {STRING} STR_NETWORK_ERROR_KICK_MESSAGE :{WHITE}Syy: {STRING}
STR_NETWORK_ERROR_CHEATER :{WHITE}Huijaaminen ei ole sallittua tällä palvelimella 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_MAP :{WHITE}Kartan lataus kesti liian kauan
STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Palvelimelle liittyminen 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_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!! ############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :yleinen virhe 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_OPENTTD :{WHITE}Tietoja OpenTTD:stä
STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Alkuperäiset oikeudet {COPYRIGHT} 1995 Chris Sawyer, kaikki oikeudet pidätetään 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_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 # Framerate display window
STR_FRAMERATE_CAPTION :{WHITE}Kuvataajuus 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 :{YELLOW}{STRING}{BLACK}{3:STRING}
STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT :{YELLOW}{STRING}{BLACK}: {CARGO_SHORT} odottamassa{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 :{WHITE}Muokkaa tuotantoa (8:n kerroin, 2040:een asti)
STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Muuta tuotantotasoa (prosentteina, 800{NBSP}% asti) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Muuta tuotantotasoa (prosentteina, 800{NBSP}%:iin asti)
# Vehicle lists # Vehicle lists
STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING} {COMMA} juna{P "" a} 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_LEFT :Balra hajtás
STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Jobbra 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 STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}A városnevek stílusának kiválasztása
############ start of townname region ############ 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 :{BLACK}Nyelv
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Válassz nyelvet 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 :{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 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_EARRING :Fülbevaló:
STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Nyakkendő vagy fülbevaló cseréje 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 # Network server list
STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Hálózati játék 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_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_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_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 :{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 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 STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}A vállalat jelszóval van védve. Írd be
# Network company list added strings # 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 STR_NETWORK_COMPANY_LIST_SPECTATE :Megfigyelés
# Network client list # 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_SERVER :Szerver
STR_NETWORK_CLIENT :Kliens 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_CLIENT_START :{WHITE}Nem tudtam kapcsolódni
STR_NETWORK_ERROR_TIMEOUT :{WHITE}A(z) {NUM}. játékos kapcsolata elveszett 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_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_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_WRONG_PASSWORD :{WHITE}Rossz jelszó
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}A szerver tele van 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_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_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_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!! ############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :általános hiba 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_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_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_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 ############ End of leave-in-this-order
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Lehetséges, hogy elveszett a kapcsolat 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_ERROR :{RED}Hiba: {SILVER}{STRING}
STR_NEWGRF_ERROR_MSG_FATAL :{RED}Végzetes 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_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_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_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} 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_SHOW_COMPETITOR_SIGNS :경쟁사의 팻말과 역 이름을 표시
STR_SETTINGS_MENU_FULL_ANIMATION :완전한 애니메이션 STR_SETTINGS_MENU_FULL_ANIMATION :완전한 애니메이션
STR_SETTINGS_MENU_FULL_DETAIL :그래픽을 아주 상세하게 STR_SETTINGS_MENU_FULL_DETAIL :그래픽을 아주 상세하게
STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :건물 숨기 STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :건물 감추
STR_SETTINGS_MENU_TRANSPARENT_SIGNS :역명판 감추기 STR_SETTINGS_MENU_TRANSPARENT_SIGNS :역명판 감추기
STR_SETTINGS_MENU_MONEY_TEXT_EFFECTS :수입/지출 표시 STR_SETTINGS_MENU_MONEY_TEXT_EFFECTS :수입/지출 표시
############ range ends here ############ 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_SPECTATE :*** {STRING} entrou como espectador
STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} iniciou uma nova empresa (#{2:NUM}) 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_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_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_SHUTDOWN :{WHITE}O servidor fechou a sessão
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}O servidor está a reiniciar...{}Por favor espere... 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_SPECTATE :*** {STRING} подключился в качестве зрителя
STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} основал новую компанию (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} основал новую компанию (#{2:NUM})
STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} покинул игру ({2:STRING}) 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_GIVE_MONEY :*** Компания «{STRING}» передала «{STRING}» {CURRENCY_LONG}
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Сервер закрыл сессию STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Сервер закрыл сессию
STR_NETWORK_MESSAGE_SERVER_REBOOT :{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_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_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_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!! ############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :error general 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); SetDParam(0, STR_MUSIC_PLAYLIST_ALL + _settings_client.music.playlist);
break; break;
case WID_MTS_CAPTION: case WID_MTS_CAPTION:
SetDParamStr(0, BaseMusic::GetUsedSet()->name.c_str()); SetDParamStr(0, BaseMusic::GetUsedSet()->name);
break; break;
} }
} }

@ -23,11 +23,13 @@ static const int DEFAULT_CONNECT_TIMEOUT_SECONDS = 3; ///< Allow connect() three
*/ */
const char *NetworkAddress::GetHostname() 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); 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. /* 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 * As port 0 means bind to any port, the other must mean that
* we want to bind to 'all' IPs. */ * 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; reset_hostname = true;
int fam = this->address.ss_family; int fam = this->address.ss_family;
if (fam == AF_UNSPEC) fam = 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; static bool _resolve_timeout_error_message_shown = false;
auto start = std::chrono::steady_clock::now(); 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(); auto end = std::chrono::steady_clock::now();
std::chrono::seconds duration = std::chrono::duration_cast<std::chrono::seconds>(end - start); std::chrono::seconds duration = std::chrono::duration_cast<std::chrono::seconds>(end - start);
if (!_resolve_timeout_error_message_shown && duration >= std::chrono::seconds(5)) { 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", 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"); 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; _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 (e != 0) {
if (func != ResolveLoopProc) { if (func != ResolveLoopProc) {
DEBUG(net, 0, "getaddrinfo for hostname \"%s\", port %s, address family %s and socket type %s failed: %s", 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; return INVALID_SOCKET;
} }
@ -452,11 +454,11 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets)
{ {
assert(sockets != nullptr); 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 * As port 0 means bind to any port, the other must mean that
* we want to bind to 'all' IPs. */ * we want to bind to 'all' IPs. */
if (this->address_length == 0 && this->address.ss_family == AF_UNSPEC && 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_INET, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc);
this->Resolve(AF_INET6, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc); this->Resolve(AF_INET6, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc);
} else { } else {

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

@ -113,7 +113,7 @@ bool IsNetworkCompatibleVersion(const char *other, bool extended)
void CheckGameCompatibility(NetworkGameInfo &ngi, bool extended) void CheckGameCompatibility(NetworkGameInfo &ngi, bool extended)
{ {
/* Check if we are allowed on this server based on the revision-check. */ /* 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; ngi.compatible = ngi.version_compatible;
/* Check if we have all the GRFs on the client-system too. */ /* 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. * Fill a NetworkServerGameInfo structure with the static content, or things
* @param ngi the NetworkGameInfo struct to fill with data. * that are so static they can be updated on request from a settings change.
*/ */
void FillNetworkGameInfo(NetworkGameInfo &ngi) void FillStaticNetworkServerGameInfo()
{ {
/* Update some game_info */ _network_game_info.use_password = !StrEmpty(_settings_client.network.server_password);
ngi.clients_on = _network_game_info.clients_on; _network_game_info.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
ngi.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;
ngi.use_password = !StrEmpty(_settings_client.network.server_password); _network_game_info.spectators_max = _settings_client.network.max_spectators;
ngi.clients_max = _settings_client.network.max_clients; _network_game_info.map_width = MapSizeX();
ngi.companies_on = (byte)Company::GetNumItems(); _network_game_info.map_height = MapSizeY();
ngi.companies_max = _settings_client.network.max_companies; _network_game_info.landscape = _settings_game.game_creation.landscape;
ngi.spectators_on = NetworkSpectatorCount(); _network_game_info.dedicated = _network_dedicated;
ngi.spectators_max = _settings_client.network.max_spectators; _network_game_info.grfconfig = _grfconfig;
ngi.game_date = _date;
ngi.map_width = MapSizeX(); _network_game_info.server_name = _settings_client.network.server_name;
ngi.map_height = MapSizeY(); _network_game_info.server_revision = GetNetworkRevisionString();
ngi.map_set = _settings_game.game_creation.landscape; }
ngi.dedicated = _network_dedicated;
ngi.grfconfig = _grfconfig; /**
* Get the NetworkServerGameInfo structure with the latest information of the server.
strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name)); * @return The current NetworkServerGameInfo.
strecpy(ngi.server_revision, GetNetworkRevisionString(), lastof(ngi.server_revision)); */
strecpy(ngi.short_server_revision, _openttd_revision, lastof(ngi.short_server_revision)); 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 p the packet to write the data to.
* @param info the NetworkGameInfo struct to serialize from. * @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); 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_string(""); // Used to be map-name.
p->Send_uint16(info->map_width); p->Send_uint16(info->map_width);
p->Send_uint16(info->map_height); p->Send_uint16(info->map_height);
p->Send_uint8 (info->map_set); p->Send_uint8 (info->landscape);
p->Send_bool (info->dedicated); 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 p the packet to write the data to
* @param info the NetworkGameInfo struct to serialize * @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 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_string(""); // Used to be map-name.
p->Send_uint32(info->map_width); p->Send_uint32(info->map_width);
p->Send_uint32(info->map_height); p->Send_uint32(info->map_height);
p->Send_uint8 (info->map_set); p->Send_uint8 (info->landscape);
p->Send_bool (info->dedicated); 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 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. * Please observe the order.
@ -320,7 +326,7 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
/* Update the documentation in game_info.h on changes /* Update the documentation in game_info.h on changes
* to the NetworkGameInfo wire-protocol! */ * to the NetworkGameInfo wire-protocol! */
switch (info->game_info_version) { switch (game_info_version) {
case 4: { case 4: {
GRFConfig **dst = &info->grfconfig; GRFConfig **dst = &info->grfconfig;
uint i; uint i;
@ -353,24 +359,24 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
FALLTHROUGH; FALLTHROUGH;
case 1: case 1:
p->Recv_string(info->server_name, sizeof(info->server_name)); info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);
p->Recv_string(info->server_revision, sizeof(info->server_revision)); info->server_revision = p->Recv_string(NETWORK_REVISION_LENGTH);
p->Recv_uint8 (); // Used to contain server-lang. p->Recv_uint8 (); // Used to contain server-lang.
info->use_password = p->Recv_bool (); info->use_password = p->Recv_bool ();
info->clients_max = p->Recv_uint8 (); info->clients_max = p->Recv_uint8 ();
info->clients_on = p->Recv_uint8 (); info->clients_on = p->Recv_uint8 ();
info->spectators_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->game_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
info->start_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. while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
info->map_width = p->Recv_uint16(); info->map_width = p->Recv_uint16();
info->map_height = 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 (); 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(); const uint8 version = p->Recv_uint8();
if (version > 0) return; // Unknown version if (version > 0) return; // Unknown version
info->game_info_version = 255;
info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
info->start_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_max = p->Recv_uint8 ();
info->companies_on = p->Recv_uint8 (); info->companies_on = p->Recv_uint8 ();
info->spectators_max = p->Recv_uint8 (); info->spectators_max = p->Recv_uint8 ();
p->Recv_string(info->server_name, sizeof(info->server_name)); info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);
p->Recv_string(info->server_revision, sizeof(info->server_revision)); info->server_revision = p->Recv_string(NETWORK_LONG_REVISION_LENGTH);
p->Recv_uint8 (); // Used to contain server-lang. p->Recv_uint8 (); // Used to contain server-lang.
info->use_password = p->Recv_bool (); info->use_password = p->Recv_bool ();
info->clients_max = p->Recv_uint8 (); 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. while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
info->map_width = p->Recv_uint32(); info->map_width = p->Recv_uint32();
info->map_height = 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 (); 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 * The game information that is sent from the server to the client.
* be sent to the clients.
*/ */
struct NetworkServerGameInfo { 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 { 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 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 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; extern NetworkServerGameInfo _network_game_info;
@ -95,14 +93,15 @@ const char *GetNetworkRevisionString();
bool IsNetworkCompatibleVersion(const char *other, bool extended = false); bool IsNetworkCompatibleVersion(const char *other, bool extended = false);
void CheckGameCompatibility(NetworkGameInfo &ngi, 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 DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf);
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf); void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf);
void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info); void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info);
void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info); void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info);
void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info); void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info);
void SerializeNetworkGameInfoExtended(Packet *p, const NetworkGameInfo *info, uint16 flags, uint16 version); void SerializeNetworkGameInfoExtended(Packet *p, const NetworkServerGameInfo *info, uint16 flags, uint16 version);
#endif /* NETWORK_CORE_GAME_INFO_H */ #endif /* NETWORK_CORE_GAME_INFO_H */

@ -168,12 +168,11 @@ void Packet::Send_uint64(uint64 data)
* the string + '\0'. No size-byte or something. * the string + '\0'. No size-byte or something.
* @param data The string to send * @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); assert(this->CanWriteToPacket(data.size() + 1));
/* Length of the string + 1 for the '\0' termination. */ this->buffer.insert(this->buffer.end(), data.begin(), data.end());
assert(this->CanWriteToPacket(strlen(data) + 1)); this->buffer.emplace_back('\0');
while (this->buffer.emplace_back(*data++) != '\0') {}
} }
/** /**
@ -404,6 +403,35 @@ void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings set
str_validate(bufp, last, settings); 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. * Get the amount of bytes that are still available for the Transfer functions.
* @return The number of bytes that still have to be transfered. * @return The number of bytes that still have to be transfered.

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

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

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

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

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

@ -28,11 +28,11 @@ NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind)
this->bind.push_back(addr); this->bind.push_back(addr);
} }
} else { } 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 * resolving it we need to add an address for each of
* the address families we support. */ * the address families we support. */
this->bind.emplace_back(nullptr, 0, AF_INET); this->bind.emplace_back("", 0, AF_INET);
this->bind.emplace_back(nullptr, 0, AF_INET6); this->bind.emplace_back("", 0, AF_INET6);
} }
this->fragment_token = ((uint64) InteractiveRandom()) | (((uint64) InteractiveRandom()) << 32); this->fragment_token = ((uint64) InteractiveRandom()) | (((uint64) InteractiveRandom()) << 32);

@ -34,6 +34,7 @@
#include "../gfx_func.h" #include "../gfx_func.h"
#include "../error.h" #include "../error.h"
#include "../core/checksum_func.hpp" #include "../core/checksum_func.hpp"
#include <charconv>
#include "../safeguards.h" #include "../safeguards.h"
@ -479,36 +480,51 @@ static void CheckPauseOnJoin()
* Converts a string to ip/port/company * Converts a string to ip/port/company
* Format: IP:port#company * Format: IP:port#company
* *
* connection_string will be re-terminated to separate out the hostname, port will * Returns the IP part as a string view into the passed string. This view is
* be set to the port strings given by the user, inside the memory area originally * valid as long the passed connection string is valid. If there is no port
* occupied by connection_string. Similar for company, if set. * 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, ':')); std::string_view ip = connection_string;
for (char *p = connection_string; *p != '\0'; p++) { if (company_id != nullptr) {
switch (*p) { size_t offset = ip.find_last_of('#');
case '[': if (offset != std::string::npos) {
ipv6 = true; std::string_view company_string = ip.substr(offset + 1);
break; ip = ip.substr(0, offset);
case ']': uint8 company_value;
ipv6 = false; auto [_, err] = std::from_chars(company_string.data(), company_string.data() + company_string.size(), company_value);
break; if (err == std::errc()) {
if (company_value != COMPANY_NEW_COMPANY && company_value != COMPANY_SPECTATOR) {
case '#': if (company_value > MAX_COMPANIES || company_value == 0) {
if (company == nullptr) continue; *company_id = COMPANY_SPECTATOR;
*company = p + 1; } else {
*p = '\0'; /* "#1" means the first company, which has index 0. */
break; *company_id = (CompanyID)(company_value - 1);
}
case ':': } else {
if (ipv6) break; *company_id = (CompanyID)company_value;
*port = p + 1; }
*p = '\0'; }
break;
} }
} }
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. * @param default_port The default port to set port to if not in connection_string.
* @return A valid NetworkAddress of the parsed information. * @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]; uint16 port = default_port;
strecpy(internal_connection_string, connection_string.c_str(), lastof(internal_connection_string)); std::string_view ip = ParseFullConnectionString(connection_string, port);
return NetworkAddress(ip, port);
const char *port = nullptr;
ParseFullConnectionString(nullptr, &port, internal_connection_string);
int rport = port != nullptr ? atoi(port) : default_port;
return NetworkAddress(internal_connection_string, rport);
} }
/** /**
@ -536,24 +547,16 @@ NetworkAddress ParseConnectionString(const std::string &connection_string, int d
* NetworkAddress, where the string can be postfixed with "#company" to * NetworkAddress, where the string can be postfixed with "#company" to
* indicate the requested company. * indicate the requested company.
* *
* @param company Pointer to the company variable to set iff indicted.
* @param connection_string The string to parse. * @param connection_string The string to parse.
* @param default_port The default port to set port to if not in connection_string. * @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. * @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 uint16 port = default_port;
strecpy(internal_connection_string, connection_string.c_str(), lastof(internal_connection_string)); std::string_view ip = ParseFullConnectionString(connection_string, port, company);
return NetworkAddress(ip, port);
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);
} }
/** /**
@ -637,9 +640,10 @@ static void NetworkInitialize(bool close_admins = true)
class TCPQueryConnecter : TCPConnecter { class TCPQueryConnecter : TCPConnecter {
private: private:
bool request_company_info; bool request_company_info;
std::string connection_string;
public: 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 void OnFailure() override
{ {
@ -649,24 +653,24 @@ public:
void OnConnect(SOCKET s) override void OnConnect(SOCKET s) override
{ {
_networking = true; _networking = true;
new ClientNetworkGameSocketHandler(s, address); new ClientNetworkGameSocketHandler(s, this->connection_string);
MyClient::SendInformationQuery(request_company_info); MyClient::SendInformationQuery(request_company_info);
} }
}; };
/** /**
* Query a server to fetch his game-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. * @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; if (!_network_available) return;
NetworkDisconnect(); NetworkDisconnect();
NetworkInitialize(); 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; if (connection_string.empty()) return nullptr;
NetworkAddress address = ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT);
/* Ensure the item already exists in the list */ /* Ensure the item already exists in the list */
NetworkGameList *item = NetworkGameListAddItem(address); NetworkGameList *item = NetworkGameListAddItem(connection_string);
if (StrEmpty(item->info.server_name)) { if (item->info.server_name.empty()) {
ClearGRFConfigList(&item->info.grfconfig); ClearGRFConfigList(&item->info.grfconfig);
address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name)); item->info.server_name = connection_string;
item->manually = true; item->manually = true;
NetworkRebuildHostList(); NetworkRebuildHostList();
UpdateNetworkGameWindow(); UpdateNetworkGameWindow();
} }
NetworkTCPQueryServer(address); NetworkTCPQueryServer(connection_string);
return item; return item;
} }
@ -723,14 +725,17 @@ void NetworkRebuildHostList()
_network_host_list.clear(); _network_host_list.clear();
for (NetworkGameList *item = _network_game_list; item != nullptr; item = item->next) { 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 */ /** Non blocking connection create to actually connect to servers */
class TCPClientConnecter : TCPConnecter { class TCPClientConnecter : TCPConnecter {
private:
std::string connection_string;
public: 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 void OnFailure() override
{ {
@ -740,7 +745,7 @@ public:
void OnConnect(SOCKET s) override void OnConnect(SOCKET s) override
{ {
_networking = true; _networking = true;
new ClientNetworkGameSocketHandler(s, this->address); new ClientNetworkGameSocketHandler(s, this->connection_string);
IConsoleCmdExec("exec scripts/on_client.scr 0"); IConsoleCmdExec("exec scripts/on_client.scr 0");
NetworkClient_Connected(); 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) 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; CompanyID join_as = default_company;
NetworkAddress address = ParseGameConnectionString(&join_as, connection_string, NETWORK_DEFAULT_PORT); std::string resolved_connection_string = ParseGameConnectionString(connection_string, NETWORK_DEFAULT_PORT, &join_as).GetAddressAsString(false);
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);
}
/**
* 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 (!_network_available) return false;
if (!NetworkValidateClientName()) return false; if (!NetworkValidateClientName()) return false;
_network_join.address = address; _network_join.connection_string = resolved_connection_string;
_network_join.company = join_as; _network_join.company = join_as;
_network_join.server_password = join_server_password; _network_join.server_password = join_server_password;
_network_join.company_password = join_company_password; _network_join.company_password = join_company_password;
@ -822,11 +805,11 @@ void NetworkClientJoinGame()
NetworkDisconnect(); NetworkDisconnect();
NetworkInitialize(); 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; _network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
ShowJoinStatusWindow(); ShowJoinStatusWindow();
new TCPClientConnecter(_network_join.address); new TCPClientConnecter(_network_join.connection_string);
} }
static void NetworkInitGameInfo() static void NetworkInitGameInfo()
@ -835,6 +818,7 @@ static void NetworkInitGameInfo()
strecpy(_settings_client.network.server_name, "Unnamed Server", lastof(_settings_client.network.server_name)); strecpy(_settings_client.network.server_name, "Unnamed Server", lastof(_settings_client.network.server_name));
} }
FillStaticNetworkServerGameInfo();
/* The server is a client too */ /* The server is a client too */
_network_game_info.clients_on = _network_dedicated ? 0 : 1; _network_game_info.clients_on = _network_dedicated ? 0 : 1;
@ -1243,7 +1227,7 @@ void NetworkStartUp()
/* Generate an server id when there is none yet */ /* Generate an server id when there is none yet */
if (StrEmpty(_settings_client.network.network_id)) NetworkGenerateServerId(); if (StrEmpty(_settings_client.network.network_id)) NetworkGenerateServerId();
memset(&_network_game_info, 0, sizeof(_network_game_info)); _network_game_info = {};
NetworkInitialize(); NetworkInitialize();
DEBUG(net, 3, "[core] network online, multiplayer available"); 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. * Create a new socket for the client side of the game connection.
* @param s The socket to connect with. * @param s The socket to connect with.
*/ */
ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler (SOCKET s, NetworkAddress address) ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler (SOCKET s, std::string connection_string)
: NetworkGameSocketHandler(s), : 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); assert(ClientNetworkGameSocketHandler::my_client == nullptr);
ClientNetworkGameSocketHandler::my_client = this; ClientNetworkGameSocketHandler::my_client = this;
@ -702,7 +702,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packe
NetworkGameList *item = GetLobbyGameInfo(); NetworkGameList *item = GetLobbyGameInfo();
if (item == nullptr) { if (item == nullptr) {
/* This is not the lobby, so add it to the game list. */ /* 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. */ /* Clear any existing GRFConfig chain. */

@ -15,7 +15,7 @@
/** Class for handling the client side of the game connection. */ /** Class for handling the client side of the game connection. */
class ClientNetworkGameSocketHandler : public NetworkGameSocketHandler { class ClientNetworkGameSocketHandler : public NetworkGameSocketHandler {
private: 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. 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. 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(); static NetworkRecvStatus SendMapOk();
void CheckConnection(); void CheckConnection();
public: public:
ClientNetworkGameSocketHandler(SOCKET s, NetworkAddress address); ClientNetworkGameSocketHandler(SOCKET s, std::string connection_string);
~ClientNetworkGameSocketHandler(); ~ClientNetworkGameSocketHandler();
NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override; NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override;
@ -132,10 +132,10 @@ void NetworkClientSetCompanyPassword(const char *password);
/** Information required to join a server. */ /** Information required to join a server. */
struct NetworkJoinInfo { struct NetworkJoinInfo {
NetworkJoinInfo() : company(COMPANY_SPECTATOR), server_password(nullptr), company_password(nullptr) {} NetworkJoinInfo() : company(COMPANY_SPECTATOR), server_password(nullptr), company_password(nullptr) {}
NetworkAddress address; ///< The address of the server to join. std::string connection_string; ///< The address of the server to join.
CompanyID company; ///< The company to join. CompanyID company; ///< The company to join.
const char *server_password; ///< The password of the server to join. const char *server_password; ///< The password of the server to join.
const char *company_password; ///< The password of the company to join. const char *company_password; ///< The password of the company to join.
}; };
extern NetworkJoinInfo _network_join; extern NetworkJoinInfo _network_join;

@ -367,8 +367,7 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const Conten
this->http_response_index = -1; this->http_response_index = -1;
NetworkAddress address(NETWORK_CONTENT_MIRROR_HOST, NETWORK_CONTENT_MIRROR_PORT); new NetworkHTTPContentConnecter(NETWORK_CONTENT_MIRROR_HOST, this, NETWORK_CONTENT_MIRROR_URL, content_request);
new NetworkHTTPContentConnecter(address, this, NETWORK_CONTENT_MIRROR_URL, content_request);
/* NetworkHTTPContentConnecter takes over freeing of content_request! */ /* NetworkHTTPContentConnecter takes over freeing of content_request! */
} }
@ -774,7 +773,7 @@ public:
* Initiate the connecting. * Initiate the connecting.
* @param address The address of the server. * @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 void OnFailure() override
{ {
@ -800,7 +799,7 @@ void ClientNetworkContentSocketHandler::Connect()
{ {
if (this->sock != INVALID_SOCKET || this->isConnecting) return; if (this->sock != INVALID_SOCKET || this->isConnecting) return;
this->isConnecting = true; 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 NetworkDisconnect(bool blocking = false, bool close_admins = true);
void NetworkGameLoop(); void NetworkGameLoop();
void NetworkBackgroundLoop(); 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 NetworkStartDebugLog(const std::string &connection_string);
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats); void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
@ -70,6 +70,7 @@ void NetworkServerDailyLoop();
void NetworkServerMonthlyLoop(); void NetworkServerMonthlyLoop();
void NetworkServerYearlyLoop(); void NetworkServerYearlyLoop();
void NetworkServerSendConfigUpdate(); void NetworkServerSendConfigUpdate();
void NetworkServerUpdateGameInfo();
void NetworkServerShowStatusToConsole(); void NetworkServerShowStatusToConsole();
bool NetworkServerStart(); bool NetworkServerStart();
void NetworkServerNewCompany(const Company *company, NetworkClientInfo *ci); 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)) {} 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. 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 (item != nullptr) {
if (StrEmpty(item->info.server_name)) { if (item->info.server_name.empty()) {
ClearGRFConfigList(&item->info.grfconfig); ClearGRFConfigList(&item->info.grfconfig);
memset(&item->info, 0, sizeof(item->info)); item->info = {};
strecpy(item->info.server_name, ins_item->info.server_name, lastof(item->info.server_name)); item->info.server_name = ins_item->info.server_name;
item->online = false; item->online = false;
} }
item->manually |= ins_item->manually; item->manually |= ins_item->manually;
if (item->manually) NetworkRebuildHostList(); if (item->manually) NetworkRebuildHostList();
UpdateNetworkGameWindow(); UpdateNetworkGameWindow();
} }
free(ins_item); delete ins_item;
} }
} }
@ -67,19 +67,20 @@ static void NetworkGameListHandleDelayedInsert()
* @param address the address of the to-be added item * @param address the address of the to-be added item
* @return a point to the newly added or already existing 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; 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; prev_item = nullptr;
for (item = _network_game_list; item != nullptr; item = item->next) { 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; prev_item = item;
} }
item = CallocT<NetworkGameList>(1); item = new NetworkGameList(resolved_connection_string);
item->next = nullptr;
item->address = address;
if (prev_item == nullptr) { if (prev_item == nullptr) {
_network_game_list = item; _network_game_list = item;
@ -109,8 +110,7 @@ void NetworkGameListRemoveItem(NetworkGameList *remove)
/* Remove GRFConfig information */ /* Remove GRFConfig information */
ClearGRFConfigList(&remove->info.grfconfig); ClearGRFConfigList(&remove->info.grfconfig);
free(remove); delete remove;
remove = nullptr;
DEBUG(net, 4, "[gamelist] removed server from list"); DEBUG(net, 4, "[gamelist] removed server from list");
NetworkRebuildHostList(); NetworkRebuildHostList();
@ -141,7 +141,7 @@ void NetworkGameListRequery()
/* item gets mostly zeroed by NetworkUDPQueryServer */ /* item gets mostly zeroed by NetworkUDPQueryServer */
uint8 retries = item->retries; uint8 retries = item->retries;
NetworkUDPQueryServer(item->address); NetworkUDPQueryServer(item->connection_string);
item->retries = (retries >= REFRESH_GAMEINFO_X_REQUERIES) ? 0 : retries; item->retries = (retries >= REFRESH_GAMEINFO_X_REQUERIES) ? 0 : retries;
} }
} }

@ -16,19 +16,24 @@
/** Structure with information shown in the game list (GUI) */ /** Structure with information shown in the game list (GUI) */
struct NetworkGameList { struct NetworkGameList {
NetworkGameInfo info; ///< The game information of this server NetworkGameList(const std::string &connection_string, bool manually = false) :
NetworkAddress address; ///< The connection info of the game server connection_string(connection_string), manually(manually)
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 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 */ /** Game list of this client */
extern NetworkGameList *_network_game_list; extern NetworkGameList *_network_game_list;
void NetworkGameListAddItemDelayed(NetworkGameList *item); void NetworkGameListAddItemDelayed(NetworkGameList *item);
NetworkGameList *NetworkGameListAddItem(NetworkAddress address); NetworkGameList *NetworkGameListAddItem(const std::string &connection_string);
void NetworkGameListRemoveItem(NetworkGameList *remove); void NetworkGameListRemoveItem(NetworkGameList *remove);
void NetworkGameListRequery(); void NetworkGameListRequery();

@ -286,8 +286,10 @@ protected:
/** Sort servers by name. */ /** Sort servers by name. */
static bool NGameNameSorter(NetworkGameList * const &a, NetworkGameList * const &b) 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). int r = strnatcmp(a->info.server_name.c_str(), b->info.server_name.c_str(), true); // Sort by name (natural sorting).
return r == 0 ? a->address.CompareTo(b->address) < 0: r < 0; 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) 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) */ /* 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 */ /* Reverse default as we are interested in version-compatible clients first */
if (r == 0) r = b->info.version_compatible - a->info.version_compatible; if (r == 0) r = b->info.version_compatible - a->info.version_compatible;
@ -374,7 +376,7 @@ protected:
assert((*item) != nullptr); assert((*item) != nullptr);
sf.ResetState(); sf.ResetState();
sf.AddLine((*item)->info.server_name); sf.AddLine((*item)->info.server_name.c_str());
return sf.GetState(); 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); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
y += FONT_HEIGHT_NORMAL; 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 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE); // landscape
y += FONT_HEIGHT_NORMAL; 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 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version
y += FONT_HEIGHT_NORMAL; y += FONT_HEIGHT_NORMAL;
std::string address = sel->address.GetAddressAsString(); SetDParamStr(0, sel->connection_string.c_str());
SetDParamStr(0, address.c_str());
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address
y += FONT_HEIGHT_NORMAL; y += FONT_HEIGHT_NORMAL;
@ -766,7 +767,7 @@ public:
break; break;
case WID_NG_REFRESH: // Refresh case WID_NG_REFRESH: // Refresh
if (this->server != nullptr) NetworkTCPQueryServer(this->server->address); if (this->server != nullptr) NetworkTCPQueryServer(this->server->connection_string);
break; break;
case WID_NG_NEWGRF: // NewGRF Settings case WID_NG_NEWGRF: // NewGRF Settings
@ -1486,22 +1487,22 @@ struct NetworkLobbyWindow : public Window {
case WID_NL_JOIN: // Join company case WID_NL_JOIN: // Join company
/* Button can be clicked only when it is enabled. */ /* Button can be clicked only when it is enabled. */
NetworkClientConnectGame(this->server->address, this->company); NetworkClientConnectGame(this->server->connection_string, this->company);
break; break;
case WID_NL_NEW: // New company case WID_NL_NEW: // New company
NetworkClientConnectGame(this->server->address, COMPANY_NEW_COMPANY); NetworkClientConnectGame(this->server->connection_string, COMPANY_NEW_COMPANY);
break; break;
case WID_NL_SPECTATE: // Spectate game case WID_NL_SPECTATE: // Spectate game
NetworkClientConnectGame(this->server->address, COMPANY_SPECTATOR); NetworkClientConnectGame(this->server->connection_string, COMPANY_SPECTATOR);
break; break;
case WID_NL_REFRESH: // Refresh case WID_NL_REFRESH: // Refresh
/* Clear the information so removed companies don't remain */ /* Clear the information so removed companies don't remain */
for (auto &company : this->company_info) company = {}; for (auto &company : this->company_info) company = {};
NetworkTCPQueryServer(this->server->address, true); NetworkTCPQueryServer(this->server->connection_string, true);
break; 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_START);
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); 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); new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
} }

@ -94,7 +94,7 @@ extern uint8 _network_reconnect;
extern CompanyMask _network_company_passworded; 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); void GetBindAddresses(NetworkAddressList *addresses, uint16 port);
struct NetworkGameList *NetworkAddServer(const std::string &connection_string); struct NetworkGameList *NetworkAddServer(const std::string &connection_string);
@ -126,8 +126,6 @@ StringID GetNetworkErrorMsg(NetworkErrorCode err);
bool NetworkFindName(char *new_name, const char *last); bool NetworkFindName(char *new_name, const char *last);
const char *GenerateCompanyPasswordHash(const char *password, const char *password_server_id, uint32 password_game_seed); 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, uint16 default_port);
NetworkAddress ParseConnectionString(const std::string &connection_string, int default_port);
NetworkAddress ParseGameConnectionString(CompanyID *company, const std::string &connection_string, int default_port);
#endif /* NETWORK_INTERNAL_H */ #endif /* NETWORK_INTERNAL_H */

@ -360,11 +360,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientIn
/** Send the client information about the server. */ /** Send the client information about the server. */
NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo() NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo()
{ {
NetworkGameInfo ngi;
FillNetworkGameInfo(ngi);
Packet *p = new Packet(PACKET_SERVER_GAME_INFO, SHRT_MAX); Packet *p = new Packet(PACKET_SERVER_GAME_INFO, SHRT_MAX);
SerializeNetworkGameInfo(p, &ngi); SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo());
this->SendPacket(p); this->SendPacket(p);
@ -373,11 +370,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo()
NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfoExtended(PacketGameType reply_type, uint16 flags, uint16 version) NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfoExtended(PacketGameType reply_type, uint16 flags, uint16 version)
{ {
NetworkGameInfo ngi;
FillNetworkGameInfo(ngi);
Packet *p = new Packet(reply_type, SHRT_MAX); Packet *p = new Packet(reply_type, SHRT_MAX);
SerializeNetworkGameInfoExtended(p, &ngi, flags, version); SerializeNetworkGameInfoExtended(p, GetCurrentNetworkServerGameInfo(), flags, version);
this->SendPacket(p); 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. * Tell that a particular company is (not) passworded.
* @param company_id The company that got/removed the password. * @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. * 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 needs_mutex Whether we need to acquire locks when sending the packet or not.
* @param manually Whether the address was entered manually. * @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 */ /* Clear item in gamelist */
NetworkGameList *item = CallocT<NetworkGameList>(1); NetworkGameList *item = new NetworkGameList(connection_string, manually);
address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name)); item->info.server_name = connection_string;
item->address = address;
item->manually = manually;
NetworkGameListAddItemDelayed(item); NetworkGameListAddItemDelayed(item);
std::unique_lock<std::mutex> lock(_udp_client.mutex, std::defer_lock); std::unique_lock<std::mutex> lock(_udp_client.mutex, std::defer_lock);
if (needs_mutex) lock.lock(); if (needs_mutex) lock.lock();
/* Init the packet */ /* Init the packet */
NetworkAddress address = NetworkAddress(ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT));
Packet p = PrepareUdpClientFindServerPacket(); Packet p = PrepareUdpClientFindServerPacket();
if (_udp_client.socket != nullptr) _udp_client.socket->SendPacket(&p, &address); if (_udp_client.socket != nullptr) _udp_client.socket->SendPacket(&p, &address);
} }
/** /**
* Query a specific server. * 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. * @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))) { if (!StartNewThread(nullptr, "ottd:udp-query", &DoNetworkUDPQueryServer, std::move(connection_string), true, std::move(manually))) {
DoNetworkUDPQueryServer(address, true, 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_FIND_SERVER(Packet *p, NetworkAddress *client_addr) override;
void Receive_CLIENT_DETAIL_INFO(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 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: public:
/** /**
* Create the socket. * Create the socket.
@ -190,16 +189,13 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, Networ
return; return;
} }
NetworkGameInfo ngi;
FillNetworkGameInfo(ngi);
if (p->CanReadFromPacket(8) && p->Recv_uint32() == FIND_SERVER_EXTENDED_TOKEN) { 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; return;
} }
Packet packet(PACKET_UDP_SERVER_RESPONSE); Packet packet(PACKET_UDP_SERVER_RESPONSE);
SerializeNetworkGameInfo(&packet, &ngi); SerializeNetworkGameInfo(&packet, GetCurrentNetworkServerGameInfo());
/* Let the client know that we are here */ /* Let the client know that we are here */
this->SendPacket(&packet, client_addr); 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()); 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 flags = p->Recv_uint16();
uint16 version = 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)); DEBUG(net, 4, "[udp]%s server response from %s", extended ? " extended" : "", NetworkAddressDumper().GetAddressAsString(client_addr));
/* Find next item */ /* Find next item */
item = NetworkGameListAddItem(*client_addr); item = NetworkGameListAddItem(client_addr->GetAddressAsString(false));
/* Clear any existing GRFConfig chain. */ /* Clear any existing GRFConfig chain. */
ClearGRFConfigList(&item->info.grfconfig); ClearGRFConfigList(&item->info.grfconfig);
@ -434,7 +430,8 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE_Common(Packet *p, Ne
SerializeGRFIdentifier(&packet, &in_request[i]->ident); 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)); 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) { 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(); UpdateNetworkGameWindow();
@ -489,7 +486,7 @@ void ClientNetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, Netw
/* Somehow we reached the end of the packet */ /* Somehow we reached the end of the packet */
if (this->HasClientQuit()) return; if (this->HasClientQuit()) return;
DoNetworkUDPQueryServer(addr, false, false); DoNetworkUDPQueryServer(addr.GetAddressAsString(false), false, false);
} }
} }
} }

@ -15,7 +15,7 @@
void NetworkUDPInitialize(); void NetworkUDPInitialize();
void NetworkUDPSearchGame(); void NetworkUDPSearchGame();
void NetworkUDPQueryMasterServer(); void NetworkUDPQueryMasterServer();
void NetworkUDPQueryServer(NetworkAddress address, bool manually = false); void NetworkUDPQueryServer(const std::string &connection_string, bool manually = false);
void NetworkUDPAdvertise(); void NetworkUDPAdvertise();
void NetworkUDPRemoveAdvertise(bool blocking); void NetworkUDPRemoveAdvertise(bool blocking);
void NetworkUDPClose(); 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; 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); 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(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++) { for (uint i = 0; i < lengthof(c->error->param_value); i++) {
SetDParam(4 + i, 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) { if (c->error != nullptr) {
char message[512]; 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(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++) { for (uint i = 0; i < lengthof(c->error->param_value); i++) {
SetDParam(3 + i, 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: { case WID_NS_PRESET_LIST: {
Dimension d = GetStringBoundingBox(STR_NUM_CUSTOM); Dimension d = GetStringBoundingBox(STR_NUM_CUSTOM);
for (const auto &i : this->grf_presets) { for (const auto &i : this->grf_presets) {
SetDParamStr(0, i.c_str()); SetDParamStr(0, i);
d = maxdim(d, GetStringBoundingBox(STR_JUST_RAW_STRING)); d = maxdim(d, GetStringBoundingBox(STR_JUST_RAW_STRING));
} }
d.width += padding.width; d.width += padding.width;
@ -785,7 +785,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
SetDParam(0, STR_NUM_CUSTOM); SetDParam(0, STR_NUM_CUSTOM);
} else { } else {
SetDParam(0, STR_JUST_RAW_STRING); SetDParam(0, STR_JUST_RAW_STRING);
SetDParamStr(1, this->grf_presets[this->preset].c_str()); SetDParamStr(1, this->grf_presets[this->preset]);
} }
break; break;
} }

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

@ -1825,6 +1825,7 @@ static bool UpdateServerPassword(int32 p1)
_settings_client.network.server_password[0] = '\0'; _settings_client.network.server_password[0] = '\0';
} }
NetworkServerUpdateGameInfo();
return true; return true;
} }
@ -1848,6 +1849,7 @@ static bool UpdateSettingsPassword(int32 p1)
static bool UpdateClientConfigValues(int32 p1) static bool UpdateClientConfigValues(int32 p1)
{ {
NetworkServerUpdateGameInfo();
if (_network_server) NetworkServerSendConfigUpdate(); if (_network_server) NetworkServerSendConfigUpdate();
return true; 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); 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); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL);
delete c; delete c;
continue; continue;

@ -127,7 +127,7 @@ struct BaseSetTextfileWindow : public TextfileWindow {
{ {
if (widget == WID_TF_CAPTION) { if (widget == WID_TF_CAPTION) {
SetDParam(0, content_type); 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_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_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_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_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_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break;
case WID_GO_BASE_MUSIC_DROPDOWN: SetDParamStr(0, BaseMusic::GetUsedSet()->name.c_str()); 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_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_REFRESH_RATE_DROPDOWN: SetDParam(0, _settings_client.gui.refresh_rate); break;
case WID_GO_RESOLUTION_DROPDOWN: { 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); 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); 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); void ValidateString(const char *str);
const char *str_fix_scc_encoded(char *str, const char *last) NOACCESS(2); 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); 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. * 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. * @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 SetDParamMaxDigits(uint n, uint count, FontSize size = FS_NORMAL);
void SetDParamStr(uint n, const char *str); 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 CopyInDParam(int offs, const uint64 *src, int num);
void CopyOutDParam(uint64 *dst, int offs, 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 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
guiflags = SGF_NETWORK_ONLY guiflags = SGF_NETWORK_ONLY
def = nullptr def = nullptr
proc = UpdateClientConfigValues
cat = SC_BASIC cat = SC_BASIC
[SDTC_STR] [SDTC_STR]
@ -6300,6 +6301,7 @@ guiflags = SGF_NETWORK_ONLY
def = 25 def = 25
min = 2 min = 2
max = MAX_CLIENTS max = MAX_CLIENTS
proc = UpdateClientConfigValues
cat = SC_BASIC cat = SC_BASIC
[SDTC_VAR] [SDTC_VAR]

@ -442,7 +442,7 @@ public:
} }
if (!this->town->text.empty()) { 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); 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 (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL;
if (!this->town->text.empty()) { 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); 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 StringID DropDownListCharStringItem::String() const
{ {
SetDParamStr(0, this->raw_string.c_str()); SetDParamStr(0, this->raw_string);
return this->string; return this->string;
} }

Loading…
Cancel
Save