(svn r13341) -Codechange: make most of the network settings configurable via the patch command.
authorrubidium
Fri, 30 May 2008 09:23:05 +0000
changeset 10790 9f507561b6a5
parent 10789 ea0c9cdc607b
child 10791 0f3e94733e65
(svn r13341) -Codechange: make most of the network settings configurable via the patch command.
src/console_cmds.cpp
src/console_func.h
src/console_internal.h
src/settings.cpp
src/settings_func.h
src/settings_internal.h
--- a/src/console_cmds.cpp	Thu May 29 23:33:37 2008 +0000
+++ b/src/console_cmds.cpp	Fri May 30 09:23:05 2008 +0000
@@ -597,43 +597,6 @@
 	return true;
 }
 
-DEF_CONSOLE_HOOK(ConHookValidateMaxClientsCount)
-{
-	if (_network_game_info.clients_max > MAX_CLIENTS) {
-		_network_game_info.clients_max = MAX_CLIENTS;
-		IConsoleError("Maximum clients out of bounds, truncating to limit.");
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookValidateMaxCompaniesCount)
-{
-	if (_network_game_info.companies_max > MAX_PLAYERS) {
-		_network_game_info.companies_max = MAX_PLAYERS;
-		IConsoleError("Maximum companies out of bounds, truncating to limit.");
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookValidateMaxSpectatorsCount)
-{
-	/* XXX see ConHookValidateMaxClientsCount */
-	if (_network_game_info.spectators_max > 10) {
-		_network_game_info.spectators_max = 10;
-		IConsoleError("Maximum spectators out of bounds, truncating to limit.");
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookCheckMinPlayers)
-{
-	CheckMinPlayers();
-	return true;
-}
-
 DEF_CONSOLE_CMD(ConKick)
 {
 	NetworkClientInfo *ci;
@@ -1305,30 +1268,6 @@
 	return true;
 }
 
-DEF_CONSOLE_HOOK(ConHookServerPW)
-{
-	if (strcmp(_settings_client.network.server_password, "*") == 0) {
-		_settings_client.network.server_password[0] = '\0';
-		_network_game_info.use_password = false;
-	} else {
-		ttd_strlcpy(_network_game_info.server_password, _settings_client.network.server_password, sizeof(_network_game_info.server_password));
-		_network_game_info.use_password = true;
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookRconPW)
-{
-	if (strcmp(_settings_client.network.rcon_password, "*") == 0) {
-		_settings_client.network.rcon_password[0] = '\0';
-	}
-
-	ttd_strlcpy(_network_game_info.rcon_password, _settings_client.network.rcon_password, sizeof(_network_game_info.rcon_password));
-
-	return true;
-}
-
 extern void HashCurrentCompanyPassword();
 
 /* Also use from within player_gui to change the password graphically */
@@ -1362,56 +1301,6 @@
 	return true;
 }
 
-DEF_CONSOLE_HOOK(ConProcPlayerName)
-{
-	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
-
-	if (ci == NULL) return false;
-
-	/* Don't change the name if it is the same as the old name */
-	if (strcmp(ci->client_name, _settings_client.network.player_name) != 0) {
-		if (!_network_server) {
-			SEND_COMMAND(PACKET_CLIENT_SET_NAME)(_settings_client.network.player_name);
-		} else {
-			if (NetworkFindName(_settings_client.network.player_name)) {
-				NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, "%s", _settings_client.network.player_name);
-				ttd_strlcpy(ci->client_name, _settings_client.network.player_name, sizeof(ci->client_name));
-				NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
-			}
-		}
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookServerName)
-{
-	ttd_strlcpy(_network_game_info.server_name, _settings_client.network.server_name, sizeof(_network_game_info.server_name));
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookServerAdvertise)
-{
-	if (!_network_advertise) // remove us from advertising
-		NetworkUDPRemoveAdvertise();
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConProcServerIP)
-{
-	if (argc == 0) {
-		IConsolePrintF(CC_WARNING, "Current value for 'server_ip': %s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
-		return true;
-	}
-
-	if (argc != 1) return false;
-
-	_network_server_bind_ip = (strcmp(argv[0], "all") == 0) ? inet_addr("0.0.0.0") : inet_addr(argv[0]);
-	snprintf(_settings_client.network.server_bind_ip, sizeof(_settings_client.network.server_bind_ip), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
-	IConsolePrintF(CC_WARNING, "'server_ip' changed to:  %s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
-	return true;
-}
 #endif /* ENABLE_NETWORK */
 
 DEF_CONSOLE_CMD(ConPatch)
@@ -1427,17 +1316,7 @@
 	if (argc == 2) {
 		IConsoleGetPatchSetting(argv[1]);
 	} else {
-		uint32 val;
-
-		if (GetArgumentInteger(&val, argv[2])) {
-			if (!IConsoleSetPatchSetting(argv[1], val)) {
-				if (_network_server) {
-					IConsoleError("This command/variable is not available during network games.");
-				} else {
-					IConsoleError("This command/variable is only available to a network server.");
-				}
-			}
-		}
+		IConsoleSetPatchSetting(argv[1], argv[2]);
 	}
 
 	return true;
@@ -1595,71 +1474,36 @@
 	IConsoleCmdHookAdd("unpause",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
 
 	/*** Networking variables ***/
-	IConsoleVarRegister("net_frame_freq",        &_settings_client.network.frame_freq, ICONSOLE_VAR_BYTE, "The amount of frames before a command will be (visibly) executed. Default value: 1");
-	IConsoleVarHookAdd("net_frame_freq",         ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarRegister("net_sync_freq",         &_settings_client.network.sync_freq,  ICONSOLE_VAR_UINT16, "The amount of frames to check if the game is still in sync. Default value: 100");
-	IConsoleVarHookAdd("net_sync_freq",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-
-	IConsoleVarStringRegister("server_pw",       &_settings_client.network.server_password, sizeof(_settings_client.network.server_password), "Set the server password to protect your server. Use '*' to clear the password");
-	IConsoleVarHookAdd("server_pw",              ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("server_pw",              ICONSOLE_HOOK_POST_ACTION, ConHookServerPW);
-	IConsoleAliasRegister("server_password",     "server_pw %+");
-	IConsoleVarStringRegister("rcon_pw",         &_settings_client.network.rcon_password, sizeof(_settings_client.network.rcon_password), "Set the rcon-password to change server behaviour. Use '*' to disable rcon");
-	IConsoleVarHookAdd("rcon_pw",                ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("rcon_pw",                ICONSOLE_HOOK_POST_ACTION, ConHookRconPW);
-	IConsoleAliasRegister("rcon_password",       "rcon_pw %+");
 	IConsoleVarStringRegister("company_pw",      NULL, 0, "Set a password for your company, so no one without the correct password can join. Use '*' to clear the password");
 	IConsoleVarHookAdd("company_pw",             ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
 	IConsoleVarProcAdd("company_pw",             NetworkChangeCompanyPassword);
 	IConsoleAliasRegister("company_password",    "company_pw %+");
 
-	IConsoleVarStringRegister("name",            &_settings_client.network.player_name, sizeof(_settings_client.network.player_name), "Set your name for multiplayer");
-	IConsoleVarHookAdd("name",                   ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
-	IConsoleVarHookAdd("name",                   ICONSOLE_HOOK_POST_ACTION, ConProcPlayerName);
-	IConsoleVarStringRegister("server_name",     &_settings_client.network.server_name, sizeof(_settings_client.network.server_name), "Set the name of the server for multiplayer");
-	IConsoleVarHookAdd("server_name",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("server_name",            ICONSOLE_HOOK_POST_ACTION, ConHookServerName);
-
-	IConsoleVarRegister("server_port",           &_settings_client.network.server_port, ICONSOLE_VAR_UINT32, "Set the server port. Changes take effect the next time you start a server");
-	IConsoleVarRegister("server_ip",             &_network_server_bind_ip, ICONSOLE_VAR_UINT32, "Set the IP the server binds to. Changes take effect the next time you start a server. Use 'all' to bind to any IP.");
-	IConsoleVarProcAdd("server_ip",              ConProcServerIP);
-	IConsoleAliasRegister("server_bind_ip",      "server_ip %+");
-	IConsoleAliasRegister("server_ip_bind",      "server_ip %+");
-	IConsoleAliasRegister("server_bind",         "server_ip %+");
-	IConsoleVarRegister("server_advertise",      &_settings_client.network.server_advertise, ICONSOLE_VAR_BOOLEAN, "Set if the server will advertise to the master server and show up there");
-	IConsoleVarHookAdd("server_advertise",       ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("server_advertise",       ICONSOLE_HOOK_POST_ACTION, ConHookServerAdvertise);
-
-	IConsoleVarRegister("max_clients",           &_network_game_info.clients_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of connected players during runtime. Default value: 10");
-	IConsoleVarHookAdd("max_clients",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("max_clients",            ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxClientsCount);
-	IConsoleVarRegister("max_companies",         &_network_game_info.companies_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of active companies during runtime. Default value: 8");
-	IConsoleVarHookAdd("max_companies",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("max_companies",          ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxCompaniesCount);
-	IConsoleVarRegister("max_spectators",        &_network_game_info.spectators_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of active spectators during runtime. Default value: 9");
-	IConsoleVarHookAdd("max_spectators",         ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("max_spectators",         ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxSpectatorsCount);
-
-	IConsoleVarRegister("max_join_time",         &_settings_client.network.max_join_time, ICONSOLE_VAR_UINT16, "Set the maximum amount of time (ticks) a client is allowed to join. Default value: 500");
-
-	IConsoleVarRegister("pause_on_join",         &_settings_client.network.pause_on_join, ICONSOLE_VAR_BOOLEAN, "Set if the server should pause gameplay while a client is joining. This might help slow users");
-	IConsoleVarHookAdd("pause_on_join",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-
-	IConsoleVarRegister("autoclean_companies",   &_settings_client.network.autoclean_companies, ICONSOLE_VAR_BOOLEAN, "Automatically shut down inactive companies to free them up for other players. Customize with 'autoclean_(un)protected'");
-	IConsoleVarHookAdd("autoclean_companies",    ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarRegister("autoclean_protected",   &_settings_client.network.autoclean_protected, ICONSOLE_VAR_BYTE, "Automatically remove the password from an inactive company after the given amount of months");
-	IConsoleVarHookAdd("autoclean_protected",    ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarRegister("autoclean_unprotected", &_settings_client.network.autoclean_unprotected, ICONSOLE_VAR_BYTE, "Automatically shut down inactive companies after the given amount of months");
-	IConsoleVarHookAdd("autoclean_unprotected",  ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarRegister("restart_game_year",     &_settings_client.network.restart_game_year, ICONSOLE_VAR_UINT16, "Auto-restart the server when Jan 1st of the set year is reached. Use '0' to disable this");
-	IConsoleVarHookAdd("restart_game_year",      ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-
-	IConsoleVarRegister("min_players",           &_settings_client.network.min_players, ICONSOLE_VAR_BYTE, "Automatically pause the game when the number of active players passes below the given amount");
-	IConsoleVarHookAdd("min_players",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("min_players",            ICONSOLE_HOOK_POST_ACTION, ConHookCheckMinPlayers);
-	IConsoleVarRegister("reload_cfg",            &_settings_client.network.reload_cfg, ICONSOLE_VAR_BOOLEAN, "reload the entire config file between the end of this game, and starting the next new game - dedicated servers");
-	IConsoleVarHookAdd("reload_cfg",             ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-
+	IConsoleAliasRegister("net_frame_freq",        "patch frame_freq %+");
+	IConsoleAliasRegister("net_sync_freq",         "patch sync_freq %+");
+	IConsoleAliasRegister("server_pw",             "patch server_password %+");
+	IConsoleAliasRegister("server_password",       "patch server_password %+");
+	IConsoleAliasRegister("rcon_pw",               "patch rcon_password %+");
+	IConsoleAliasRegister("rcon_password",         "patch rcon_password %+");
+	IConsoleAliasRegister("name",                  "patch player_name %+");
+	IConsoleAliasRegister("server_name",           "patch server_name %+");
+	IConsoleAliasRegister("server_port",           "patch server_port %+");
+	IConsoleAliasRegister("server_ip",             "patch server_bind_ip %+");
+	IConsoleAliasRegister("server_bind_ip",        "patch server_bind_ip %+");
+	IConsoleAliasRegister("server_ip_bind",        "patch server_bind_ip %+");
+	IConsoleAliasRegister("server_bind",           "patch server_bind_ip %+");
+	IConsoleAliasRegister("server_advertise",      "patch server_advertise %+");
+	IConsoleAliasRegister("max_clients",           "patch max_clients %+");
+	IConsoleAliasRegister("max_companies",         "patch max_companies %+");
+	IConsoleAliasRegister("max_spectators",        "patch max_spectators %+");
+	IConsoleAliasRegister("max_join_time",         "patch max_join_time %+");
+	IConsoleAliasRegister("pause_on_join",         "patch pause_on_join %+");
+	IConsoleAliasRegister("autoclean_companies",   "patch autoclean_companies %+");
+	IConsoleAliasRegister("autoclean_protected",   "patch autoclean_protected %+");
+	IConsoleAliasRegister("autoclean_unprotected", "patch autoclean_unprotected %+");
+	IConsoleAliasRegister("restart_game_year",     "patch restart_game_year %+");
+	IConsoleAliasRegister("min_players",           "patch min_players %+");
+	IConsoleAliasRegister("reload_cfg",            "patch reload_cfg %+");
 #endif /* ENABLE_NETWORK */
 
 	// debugging stuff
--- a/src/console_func.h	Thu May 29 23:33:37 2008 +0000
+++ b/src/console_func.h	Fri May 30 09:23:05 2008 +0000
@@ -19,6 +19,8 @@
 void IConsolePrint(ConsoleColour color_code, const char *string);
 void CDECL IConsolePrintF(ConsoleColour color_code, const char *s, ...);
 void IConsoleDebug(const char *dbg, const char *string);
+void IConsoleWarning(const char *string);
+void IConsoleError(const char *string);
 
 /* Parser */
 void IConsoleCmdExec(const char *cmdstr);
--- a/src/console_internal.h	Thu May 29 23:33:37 2008 +0000
+++ b/src/console_internal.h	Fri May 30 09:23:05 2008 +0000
@@ -105,10 +105,6 @@
 void IConsoleClearBuffer();
 void IConsoleOpen();
 
-/* console output */
-void IConsoleWarning(const char *string);
-void IConsoleError(const char *string);
-
 /* Commands */
 void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc);
 void IConsoleAliasRegister(const char *name, const char *cmd);
--- a/src/settings.cpp	Thu May 29 23:33:37 2008 +0000
+++ b/src/settings.cpp	Fri May 30 09:23:05 2008 +0000
@@ -25,7 +25,10 @@
 #include "screenshot.h"
 #include "variables.h"
 #include "network/network.h"
-#include "network/network_internal.h"
+#include "network/network_data.h"
+#include "network/network_client.h"
+#include "network/network_server.h"
+#include "network/network_udp.h"
 #include "settings_internal.h"
 #include "command_func.h"
 #include "console_func.h"
@@ -1135,12 +1138,12 @@
 #define SDTC_CONDLIST(var, type, length, flags, guiflags, def, str, proc, from, to)\
 	SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, length, def, 0, 0, 0, NULL, str, proc, from, to)
 #define SDTC_LIST(var, type, flags, guiflags, def, str, proc)\
-	SDTG_GENERAL(var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
+	SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
 
 #define SDTC_CONDSTR(var, type, length, flags, guiflags, def, str, proc, from, to)\
 	SDTG_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, length, def, 0, 0, 0, NULL, str, proc, from, to)
 #define SDTC_STR(var, type, flags, guiflags, def, str, proc)\
-	SDTG_GENERAL(var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
+	SDTG_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
 
 #define SDTC_CONDOMANY(var, type, from, to, flags, guiflags, def, max, full, str, proc)\
 	SDTG_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, 0, max, 0, full, str, proc, from, to)
@@ -1433,6 +1436,69 @@
 	return 0;
 }
 
+#ifdef ENABLE_NETWORK
+
+static int32 UpdateMinPlayers(int32 p1)
+{
+	CheckMinPlayers();
+	return 0;
+}
+
+static int32 UpdatePlayerName(int32 p1)
+{
+	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
+
+	if (ci == NULL) return 0;
+
+	/* Don't change the name if it is the same as the old name */
+	if (strcmp(ci->client_name, _settings_client.network.player_name) != 0) {
+		if (!_network_server) {
+			SEND_COMMAND(PACKET_CLIENT_SET_NAME)(_settings_client.network.player_name);
+		} else {
+			if (NetworkFindName(_settings_client.network.player_name)) {
+				NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, "%s", _settings_client.network.player_name);
+				ttd_strlcpy(ci->client_name, _settings_client.network.player_name, sizeof(ci->client_name));
+				NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int32 UpdateServerName(int32 p1)
+{
+	ttd_strlcpy(_network_game_info.server_name, _settings_client.network.server_name, sizeof(_network_game_info.server_name));
+	return 0;
+}
+
+static int32 UpdateServerPassword(int32 p1)
+{
+	if (strcmp(_settings_client.network.server_password, "*") == 0) {
+		_settings_client.network.server_password[0] = '\0';
+		_network_game_info.use_password = false;
+	} else {
+		ttd_strlcpy(_network_game_info.server_password, _settings_client.network.server_password, sizeof(_network_game_info.server_password));
+		_network_game_info.use_password = true;
+	}
+
+	return 0;
+}
+
+static int32 UpdateRconPassword(int32 p1)
+{
+	if (strcmp(_settings_client.network.rcon_password, "*") == 0) {
+		_settings_client.network.rcon_password[0] = '\0';
+	}
+
+	ttd_strlcpy(_network_game_info.rcon_password, _settings_client.network.rcon_password, sizeof(_network_game_info.rcon_password));
+
+	return 0;
+}
+
+#endif /* ENABLE_NETWORK */
+
+
 /* End - Callback Functions */
 
 #ifndef EXTERNAL_PLAYER
@@ -1499,39 +1565,6 @@
 	  SDTG_END()
 };
 
-#ifdef ENABLE_NETWORK
-static const SettingDescGlobVarList _network_settings[] = {
-	  SDTG_VAR("sync_freq",           SLE_UINT16,C|S,0, _settings_client.network.sync_freq,            100, 0,   100,   0, STR_NULL, NULL),
-	  SDTG_VAR("frame_freq",           SLE_UINT8,C|S,0, _settings_client.network.frame_freq,             0, 0,   100,   0, STR_NULL, NULL),
-	  SDTG_VAR("max_join_time",       SLE_UINT16, S, 0, _settings_client.network.max_join_time,        500, 0, 32000,   0, STR_NULL, NULL),
-	 SDTG_BOOL("pause_on_join",                   S, 0, _settings_client.network.pause_on_join,        true,               STR_NULL, NULL),
-	  SDTG_STR("server_bind_ip",        SLE_STRB, S, 0, _settings_client.network.server_bind_ip,       "0.0.0.0",          STR_NULL, NULL),
-	  SDTG_VAR("server_port",         SLE_UINT16, S, 0, _settings_client.network.server_port,          NETWORK_DEFAULT_PORT, 0, 65535, 0, STR_NULL, NULL),
-	 SDTG_BOOL("server_advertise",                S, 0, _settings_client.network.server_advertise,     false,              STR_NULL, NULL),
-	  SDTG_VAR("lan_internet",         SLE_UINT8, S, 0, _settings_client.network.lan_internet,           0, 0,     1,   0, STR_NULL, NULL),
-	  SDTG_STR("player_name",           SLE_STRB, S, 0, _settings_client.network.player_name,          NULL,               STR_NULL, NULL),
-	  SDTG_STR("server_password",       SLE_STRB, S, 0, _settings_client.network.server_password,      NULL,               STR_NULL, NULL),
-	  SDTG_STR("rcon_password",         SLE_STRB, S, 0, _settings_client.network.rcon_password,        NULL,               STR_NULL, NULL),
-	  SDTG_STR("default_company_pass",  SLE_STRB, S, 0, _settings_client.network.default_company_pass, NULL,               STR_NULL, NULL),
-	  SDTG_STR("server_name",           SLE_STRB, S, 0, _settings_client.network.server_name,          NULL,               STR_NULL, NULL),
-	  SDTG_STR("connect_to_ip",         SLE_STRB, S, 0, _settings_client.network.connect_to_ip,        NULL,               STR_NULL, NULL),
-	  SDTG_STR("network_id",            SLE_STRB, S, 0, _settings_client.network.network_id,           NULL,               STR_NULL, NULL),
-	 SDTG_BOOL("autoclean_companies",             S, 0, _settings_client.network.autoclean_companies,  false,              STR_NULL, NULL),
-	  SDTG_VAR("autoclean_unprotected",SLE_UINT8, S, 0, _settings_client.network.autoclean_unprotected,12, 0,     60,   0, STR_NULL, NULL),
-	  SDTG_VAR("autoclean_protected",  SLE_UINT8, S, 0, _settings_client.network.autoclean_protected,  36, 0,    180,   0, STR_NULL, NULL),
-	  SDTG_VAR("max_companies",        SLE_UINT8, S, 0, _settings_client.network.max_companies,      8, 1, MAX_PLAYERS, 0, STR_NULL, NULL),
-	  SDTG_VAR("max_clients",          SLE_UINT8, S, 0, _settings_client.network.max_clients,       10, 2, MAX_CLIENTS, 0, STR_NULL, NULL),
-	  SDTG_VAR("max_spectators",       SLE_UINT8, S, 0, _settings_client.network.max_spectators,    10, 0, MAX_CLIENTS, 0, STR_NULL, NULL),
-	  SDTG_VAR("restart_game_year",    SLE_INT32, S,D0, _settings_client.network.restart_game_year,  0, MIN_YEAR, MAX_YEAR, 1, STR_NULL, NULL),
-	  SDTG_VAR("min_players",          SLE_UINT8, S, 0, _settings_client.network.min_players,               0, 0, 10,   0, STR_NULL, NULL),
-	SDTG_OMANY("server_lang",          SLE_UINT8, S, 0, _settings_client.network.server_lang,     0, 35, "ANY|ENGLISH|GERMAN|FRENCH|BRAZILIAN|BULGARIAN|CHINESE|CZECH|DANISH|DUTCH|ESPERANTO|FINNISH|HUNGARIAN|ICELANDIC|ITALIAN|JAPANESE|KOREAN|LITHUANIAN|NORWEGIAN|POLISH|PORTUGUESE|ROMANIAN|RUSSIAN|SLOVAK|SLOVENIAN|SPANISH|SWEDISH|TURKISH|UKRAINIAN|AFRIKAANS|CROATIAN|CATALAN|ESTONIAN|GALICIAN|GREEK|LATVIAN", STR_NULL, NULL),
-	 SDTG_BOOL("reload_cfg",                      S, 0, _settings_client.network.reload_cfg,           false,              STR_NULL, NULL),
-	  SDTG_STR("last_host",             SLE_STRB, S, 0, _settings_client.network.last_host,            "0.0.0.0",          STR_NULL, NULL),
-	  SDTG_VAR("last_port",           SLE_UINT16, S, 0, _settings_client.network.last_port,            0, 0, UINT16_MAX, 0, STR_NULL ,NULL),
-	  SDTG_END()
-};
-#endif /* ENABLE_NETWORK */
-
 static const uint GAME_DIFFICULTY_NUM = 18;
 uint16 _old_diff_custom[GAME_DIFFICULTY_NUM];
 
@@ -1746,45 +1779,75 @@
 
 	/***************************************************************************/
 	/* Unsaved patch variables. */
-	SDTC_OMANY(gui.autosave,               SLE_UINT8, S, 0, 1, 4, "off|monthly|quarterly|half year|yearly", STR_NULL,                     NULL),
-	 SDTC_BOOL(gui.vehicle_speed,                     S, 0,  true,                        STR_CONFIG_PATCHES_VEHICLESPEED,                NULL),
-	 SDTC_BOOL(gui.status_long_date,                  S, 0,  true,                        STR_CONFIG_PATCHES_LONGDATE,                    NULL),
-	 SDTC_BOOL(gui.show_finances,                     S, 0,  true,                        STR_CONFIG_PATCHES_SHOWFINANCES,                NULL),
-	 SDTC_BOOL(gui.autoscroll,                        S, 0, false,                        STR_CONFIG_PATCHES_AUTOSCROLL,                  NULL),
-	 SDTC_BOOL(gui.reverse_scroll,                    S, 0, false,                        STR_CONFIG_PATCHES_REVERSE_SCROLLING,           NULL),
-	 SDTC_BOOL(gui.smooth_scroll,                     S, 0, false,                        STR_CONFIG_PATCHES_SMOOTH_SCROLLING,            NULL),
-	 SDTC_BOOL(gui.measure_tooltip,                   S, 0, false,                        STR_CONFIG_PATCHES_MEASURE_TOOLTIP,             NULL),
-	  SDTC_VAR(gui.errmsg_duration,        SLE_UINT8, S, 0,     5,        0,       20, 0, STR_CONFIG_PATCHES_ERRMSG_DURATION,             NULL),
-	  SDTC_VAR(gui.toolbar_pos,            SLE_UINT8, S,MS,     0,        0,        2, 0, STR_CONFIG_PATCHES_TOOLBAR_POS,                 v_PositionMainToolbar),
-	  SDTC_VAR(gui.window_snap_radius,     SLE_UINT8, S,D0,    10,        1,       32, 0, STR_CONFIG_PATCHES_SNAP_RADIUS,                 NULL),
-	 SDTC_BOOL(gui.population_in_label,               S, 0,  true,                        STR_CONFIG_PATCHES_POPULATION_IN_LABEL,         PopulationInLabelActive),
-	 SDTC_BOOL(gui.link_terraform_toolbar,            S, 0, false,                        STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR,      NULL),
-	  SDTC_VAR(gui.liveries,               SLE_UINT8, S,MS,     2,        0,        2, 0, STR_CONFIG_PATCHES_LIVERIES,                    RedrawScreen),
-	 SDTC_BOOL(gui.prefer_teamchat,                   S, 0, false,                        STR_CONFIG_PATCHES_PREFER_TEAMCHAT,             NULL),
-	  SDTC_VAR(gui.scrollwheel_scrolling,  SLE_UINT8, S,MS,     0,        0,        2, 0, STR_CONFIG_PATCHES_SCROLLWHEEL_SCROLLING,       NULL),
-	  SDTC_VAR(gui.scrollwheel_multiplier, SLE_UINT8, S, 0,     5,        1,       15, 1, STR_CONFIG_PATCHES_SCROLLWHEEL_MULTIPLIER,      NULL),
-	 SDTC_BOOL(gui.pause_on_newgame,                  S, 0, false,                        STR_CONFIG_PATCHES_PAUSE_ON_NEW_GAME,           NULL),
-	  SDTC_VAR(gui.advanced_vehicle_list,  SLE_UINT8, S,MS,     1,        0,        2, 0, STR_CONFIG_PATCHES_ADVANCED_VEHICLE_LISTS,      NULL),
-	 SDTC_BOOL(gui.timetable_in_ticks,                S, 0, false,                        STR_CONFIG_PATCHES_TIMETABLE_IN_TICKS,          NULL),
-	  SDTC_VAR(gui.loading_indicators,     SLE_UINT8, S,MS,     1,        0,        2, 0, STR_CONFIG_PATCHES_LOADING_INDICATORS,          RedrawScreen),
-	  SDTC_VAR(gui.default_rail_type,      SLE_UINT8, S,MS,     4,        0,        6, 0, STR_CONFIG_PATCHES_DEFAULT_RAIL_TYPE,           NULL),
-	 SDTC_BOOL(gui.enable_signal_gui,                 S, 0, false,                        STR_CONFIG_PATCHES_ENABLE_SIGNAL_GUI,           CloseSignalGUI),
-	  SDTC_VAR(gui.drag_signals_density,   SLE_UINT8, S, 0,     4,        1,       20, 0, STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY,        DragSignalsDensityChanged),
-	  SDTC_VAR(gui.semaphore_build_before, SLE_INT32, S, NC, 1975, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_SEMAPHORE_BUILD_BEFORE_DATE, ResetSignalVariant),
-	 SDTC_BOOL(gui.train_income_warn,                 S, 0,  true,                        STR_CONFIG_PATCHES_WARN_INCOME_LESS,            NULL),
-	  SDTC_VAR(gui.order_review_system,    SLE_UINT8, S,MS,     2,        0,        2, 0, STR_CONFIG_PATCHES_ORDER_REVIEW,                NULL),
-	 SDTC_BOOL(gui.lost_train_warn,                   S, 0,  true,                        STR_CONFIG_PATCHES_WARN_LOST_TRAIN,             NULL),
-	 SDTC_BOOL(gui.autorenew,                         S, 0, false,                        STR_CONFIG_PATCHES_AUTORENEW_VEHICLE,           EngineRenewUpdate),
-	  SDTC_VAR(gui.autorenew_months,       SLE_INT16, S, 0,     6,      -12,       12, 0, STR_CONFIG_PATCHES_AUTORENEW_MONTHS,            EngineRenewMonthsUpdate),
-	  SDTC_VAR(gui.autorenew_money,         SLE_UINT, S,CR,100000,        0,  2000000, 0, STR_CONFIG_PATCHES_AUTORENEW_MONEY,             EngineRenewMoneyUpdate),
-	 SDTC_BOOL(gui.always_build_infrastructure,       S, 0, false,                        STR_CONFIG_PATCHES_ALWAYS_BUILD_INFRASTRUCTURE, RedrawScreen),
-	 SDTC_BOOL(gui.new_nonstop,                       S, 0, false,                        STR_CONFIG_PATCHES_NEW_NONSTOP,                 NULL),
-	 SDTC_BOOL(gui.keep_all_autosave,                 S, 0, false,                        STR_NULL,                                       NULL),
-	 SDTC_BOOL(gui.autosave_on_exit,                  S, 0, false,                        STR_NULL,                                       NULL),
-	  SDTC_VAR(gui.max_num_autosaves,      SLE_UINT8, S, 0,    16,        0,      255, 0, STR_NULL,                                       NULL),
-	 SDTC_BOOL(gui.bridge_pillars,                    S, 0,  true,                        STR_NULL,                                       NULL),
-	 SDTC_BOOL(gui.auto_euro,                         S, 0,  true,                        STR_NULL,                                       NULL),
-	  SDTC_VAR(gui.news_message_timeout,   SLE_UINT8, S, 0,     2,        1,      255, 0, STR_NULL,                                       NULL),
+	SDTC_OMANY(gui.autosave,                  SLE_UINT8, S,  0, 1, 4, "off|monthly|quarterly|half year|yearly", STR_NULL,                     NULL),
+	 SDTC_BOOL(gui.vehicle_speed,                        S,  0,  true,                        STR_CONFIG_PATCHES_VEHICLESPEED,                NULL),
+	 SDTC_BOOL(gui.status_long_date,                     S,  0,  true,                        STR_CONFIG_PATCHES_LONGDATE,                    NULL),
+	 SDTC_BOOL(gui.show_finances,                        S,  0,  true,                        STR_CONFIG_PATCHES_SHOWFINANCES,                NULL),
+	 SDTC_BOOL(gui.autoscroll,                           S,  0, false,                        STR_CONFIG_PATCHES_AUTOSCROLL,                  NULL),
+	 SDTC_BOOL(gui.reverse_scroll,                       S,  0, false,                        STR_CONFIG_PATCHES_REVERSE_SCROLLING,           NULL),
+	 SDTC_BOOL(gui.smooth_scroll,                        S,  0, false,                        STR_CONFIG_PATCHES_SMOOTH_SCROLLING,            NULL),
+	 SDTC_BOOL(gui.measure_tooltip,                      S,  0, false,                        STR_CONFIG_PATCHES_MEASURE_TOOLTIP,             NULL),
+	  SDTC_VAR(gui.errmsg_duration,           SLE_UINT8, S,  0,     5,        0,       20, 0, STR_CONFIG_PATCHES_ERRMSG_DURATION,             NULL),
+	  SDTC_VAR(gui.toolbar_pos,               SLE_UINT8, S, MS,     0,        0,        2, 0, STR_CONFIG_PATCHES_TOOLBAR_POS,                 v_PositionMainToolbar),
+	  SDTC_VAR(gui.window_snap_radius,        SLE_UINT8, S, D0,    10,        1,       32, 0, STR_CONFIG_PATCHES_SNAP_RADIUS,                 NULL),
+	 SDTC_BOOL(gui.population_in_label,                  S,  0,  true,                        STR_CONFIG_PATCHES_POPULATION_IN_LABEL,         PopulationInLabelActive),
+	 SDTC_BOOL(gui.link_terraform_toolbar,               S,  0, false,                        STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR,      NULL),
+	  SDTC_VAR(gui.liveries,                  SLE_UINT8, S, MS,     2,        0,        2, 0, STR_CONFIG_PATCHES_LIVERIES,                    RedrawScreen),
+	 SDTC_BOOL(gui.prefer_teamchat,                      S,  0, false,                        STR_CONFIG_PATCHES_PREFER_TEAMCHAT,             NULL),
+	  SDTC_VAR(gui.scrollwheel_scrolling,     SLE_UINT8, S, MS,     0,        0,        2, 0, STR_CONFIG_PATCHES_SCROLLWHEEL_SCROLLING,       NULL),
+	  SDTC_VAR(gui.scrollwheel_multiplier,    SLE_UINT8, S,  0,     5,        1,       15, 1, STR_CONFIG_PATCHES_SCROLLWHEEL_MULTIPLIER,      NULL),
+	 SDTC_BOOL(gui.pause_on_newgame,                     S,  0, false,                        STR_CONFIG_PATCHES_PAUSE_ON_NEW_GAME,           NULL),
+	  SDTC_VAR(gui.advanced_vehicle_list,     SLE_UINT8, S, MS,     1,        0,        2, 0, STR_CONFIG_PATCHES_ADVANCED_VEHICLE_LISTS,      NULL),
+	 SDTC_BOOL(gui.timetable_in_ticks,                   S,  0, false,                        STR_CONFIG_PATCHES_TIMETABLE_IN_TICKS,          NULL),
+	  SDTC_VAR(gui.loading_indicators,        SLE_UINT8, S, MS,     1,        0,        2, 0, STR_CONFIG_PATCHES_LOADING_INDICATORS,          RedrawScreen),
+	  SDTC_VAR(gui.default_rail_type,         SLE_UINT8, S, MS,     4,        0,        6, 0, STR_CONFIG_PATCHES_DEFAULT_RAIL_TYPE,           NULL),
+	 SDTC_BOOL(gui.enable_signal_gui,                    S,  0, false,                        STR_CONFIG_PATCHES_ENABLE_SIGNAL_GUI,           CloseSignalGUI),
+	  SDTC_VAR(gui.drag_signals_density,      SLE_UINT8, S,  0,     4,        1,       20, 0, STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY,        DragSignalsDensityChanged),
+	  SDTC_VAR(gui.semaphore_build_before,    SLE_INT32, S, NC,  1975, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_SEMAPHORE_BUILD_BEFORE_DATE, ResetSignalVariant),
+	 SDTC_BOOL(gui.train_income_warn,                    S,  0,  true,                        STR_CONFIG_PATCHES_WARN_INCOME_LESS,            NULL),
+	  SDTC_VAR(gui.order_review_system,       SLE_UINT8, S, MS,     2,        0,        2, 0, STR_CONFIG_PATCHES_ORDER_REVIEW,                NULL),
+	 SDTC_BOOL(gui.lost_train_warn,                      S,  0,  true,                        STR_CONFIG_PATCHES_WARN_LOST_TRAIN,             NULL),
+	 SDTC_BOOL(gui.autorenew,                            S,  0, false,                        STR_CONFIG_PATCHES_AUTORENEW_VEHICLE,           EngineRenewUpdate),
+	  SDTC_VAR(gui.autorenew_months,          SLE_INT16, S,  0,     6,      -12,       12, 0, STR_CONFIG_PATCHES_AUTORENEW_MONTHS,            EngineRenewMonthsUpdate),
+	  SDTC_VAR(gui.autorenew_money,            SLE_UINT, S, CR,100000,        0,  2000000, 0, STR_CONFIG_PATCHES_AUTORENEW_MONEY,             EngineRenewMoneyUpdate),
+	 SDTC_BOOL(gui.always_build_infrastructure,          S,  0, false,                        STR_CONFIG_PATCHES_ALWAYS_BUILD_INFRASTRUCTURE, RedrawScreen),
+	 SDTC_BOOL(gui.new_nonstop,                          S,  0, false,                        STR_CONFIG_PATCHES_NEW_NONSTOP,                 NULL),
+	 SDTC_BOOL(gui.keep_all_autosave,                    S,  0, false,                        STR_NULL,                                       NULL),
+	 SDTC_BOOL(gui.autosave_on_exit,                     S,  0, false,                        STR_NULL,                                       NULL),
+	  SDTC_VAR(gui.max_num_autosaves,         SLE_UINT8, S,  0,    16,        0,      255, 0, STR_NULL,                                       NULL),
+	 SDTC_BOOL(gui.bridge_pillars,                       S,  0,  true,                        STR_NULL,                                       NULL),
+	 SDTC_BOOL(gui.auto_euro,                            S,  0,  true,                        STR_NULL,                                       NULL),
+	  SDTC_VAR(gui.news_message_timeout,      SLE_UINT8, S,  0,     2,        1,      255, 0, STR_NULL,                                       NULL),
+
+#ifdef ENABLE_NETWORK
+	  SDTC_VAR(network.sync_freq,            SLE_UINT16,C|S,NO,   100,        0,      100, 0, STR_NULL,                                       NULL),
+	  SDTC_VAR(network.frame_freq,            SLE_UINT8,C|S,NO,     0,        0,      100, 0, STR_NULL,                                       NULL),
+	  SDTC_VAR(network.max_join_time,        SLE_UINT16, S, NO,   500,        0,    32000, 0, STR_NULL,                                       NULL),
+	 SDTC_BOOL(network.pause_on_join,                    S, NO,  true,                        STR_NULL,                                       NULL),
+	  SDTC_STR(network.server_bind_ip,         SLE_STRB, S, NO, "0.0.0.0",                    STR_NULL,                                       NULL),
+	  SDTC_VAR(network.server_port,          SLE_UINT16, S, NO,NETWORK_DEFAULT_PORT,0,65535,0,STR_NULL,                                       NULL),
+	 SDTC_BOOL(network.server_advertise,                 S, NO, false,                        STR_NULL,                                       NULL),
+	  SDTC_VAR(network.lan_internet,          SLE_UINT8, S, NO,     0,        0,        1, 0, STR_NULL,                                       NULL),
+	  SDTC_STR(network.player_name,            SLE_STRB, S,  0,  NULL,                        STR_NULL,                                       UpdatePlayerName),
+	  SDTC_STR(network.server_password,        SLE_STRB, S, NO,  NULL,                        STR_NULL,                                       UpdateServerPassword),
+	  SDTC_STR(network.rcon_password,          SLE_STRB, S, NO,  NULL,                        STR_NULL,                                       UpdateRconPassword),
+	  SDTC_STR(network.default_company_pass,   SLE_STRB, S,  0,  NULL,                        STR_NULL,                                       NULL),
+	  SDTC_STR(network.server_name,            SLE_STRB, S, NO,  NULL,                        STR_NULL,                                       UpdateServerName),
+	  SDTC_STR(network.connect_to_ip,          SLE_STRB, S,  0,  NULL,                        STR_NULL,                                       NULL),
+	  SDTC_STR(network.network_id,             SLE_STRB, S, NO,  NULL,                        STR_NULL,                                       NULL),
+	 SDTC_BOOL(network.autoclean_companies,              S, NO, false,                        STR_NULL,                                       NULL),
+	  SDTC_VAR(network.autoclean_unprotected, SLE_UINT8, S, NO,    12,     0,          60, 0, STR_NULL,                                       NULL),
+	  SDTC_VAR(network.autoclean_protected,   SLE_UINT8, S, NO,    36,     0,         180, 0, STR_NULL,                                       NULL),
+	  SDTC_VAR(network.max_companies,         SLE_UINT8, S, NO,     8,     1, MAX_PLAYERS, 0, STR_NULL,                                       NULL),
+	  SDTC_VAR(network.max_clients,           SLE_UINT8, S, NO,    10,     2, MAX_CLIENTS, 0, STR_NULL,                                       NULL),
+	  SDTC_VAR(network.max_spectators,        SLE_UINT8, S, NO,    10,     0, MAX_CLIENTS, 0, STR_NULL,                                       NULL),
+	  SDTC_VAR(network.restart_game_year,     SLE_INT32, S,D0|NO|NC,0, MIN_YEAR, MAX_YEAR, 1, STR_NULL,                                       NULL),
+	  SDTC_VAR(network.min_players,           SLE_UINT8, S, NO,     0,     0,        10,   0, STR_NULL,                                       UpdateMinPlayers),
+	SDTC_OMANY(network.server_lang,           SLE_UINT8, S, NO,     0,    35, "ANY|ENGLISH|GERMAN|FRENCH|BRAZILIAN|BULGARIAN|CHINESE|CZECH|DANISH|DUTCH|ESPERANTO|FINNISH|HUNGARIAN|ICELANDIC|ITALIAN|JAPANESE|KOREAN|LITHUANIAN|NORWEGIAN|POLISH|PORTUGUESE|ROMANIAN|RUSSIAN|SLOVAK|SLOVENIAN|SPANISH|SWEDISH|TURKISH|UKRAINIAN|AFRIKAANS|CROATIAN|CATALAN|ESTONIAN|GALICIAN|GREEK|LATVIAN", STR_NULL, NULL),
+	 SDTC_BOOL(network.reload_cfg,                       S, NO, false,                        STR_NULL,                                       NULL),
+	  SDTC_STR(network.last_host,              SLE_STRB, S,  0, "0.0.0.0",                    STR_NULL,                                       NULL),
+	  SDTC_VAR(network.last_port,            SLE_UINT16, S,  0,     0,     0,  UINT16_MAX, 0, STR_NULL,                                       NULL),
+#endif /* ENABLE_NETWORK */
 
 	/*
 	 * Since the network code (CmdChangePatchSetting and friends) use the index in this array to decide
@@ -2026,7 +2089,6 @@
 	proc(ini, _currency_settings,"currency", &_custom_currency);
 
 #ifdef ENABLE_NETWORK
-	proc(ini, (const SettingDesc*)_network_settings, "network", NULL);
 	proc_list(ini, "servers", _network_host_list, lengthof(_network_host_list), NULL);
 	proc_list(ini, "bans",    _network_ban_list,  lengthof(_network_ban_list), NULL);
 #endif /* ENABLE_NETWORK */
@@ -2090,7 +2152,7 @@
 	if (sd == NULL) return CMD_ERROR;
 	if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR;
 
-	if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return CMD_ERROR;
+	if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return CMD_ERROR;
 	if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return CMD_ERROR;
 	if ((sd->desc.flags & SGF_NEWGAME_ONLY) && _game_mode != GM_MENU) return CMD_ERROR;
 
@@ -2140,6 +2202,23 @@
 	return false;
 }
 
+/**
+ * Set a patch value with a string.
+ * @param index the patch settings index.
+ * @param value the value to write
+ * @note CANNOT BE SAVED IN THE SAVEGAME.
+ */
+bool SetPatchValue(uint index, const char *value)
+{
+	const SettingDesc *sd = &_patch_settings[index];
+	assert(sd->save.conv & SLF_NETWORK_NO);
+
+	char *var = (char*)GetVariableAddress(NULL, &sd->save);
+	ttd_strlcpy(var, value, sd->save.length);
+
+	return true;
+}
+
 const SettingDesc *GetPatchFromName(const char *name, uint *i)
 {
 	const SettingDesc *sd;
@@ -2165,23 +2244,40 @@
 
 /* Those 2 functions need to be here, else we have to make some stuff non-static
  * and besides, it is also better to keep stuff like this at the same place */
-bool IConsoleSetPatchSetting(const char *name, int32 value)
+void IConsoleSetPatchSetting(const char *name, const char *value)
 {
-	bool success;
 	uint index;
 	const SettingDesc *sd = GetPatchFromName(name, &index);
-	void *ptr;
 
 	if (sd == NULL) {
 		IConsolePrintF(CC_WARNING, "'%s' is an unknown patch setting.", name);
-		return true;
 	}
 
-	GameSettings *s = (_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game;
-	ptr = GetVariableAddress(s, &sd->save);
+	bool success;
+	if (sd->desc.cmd == SDT_STRING) {
+		success = SetPatchValue(index, value);
+	} else {
+		uint32 val;
+		extern bool GetArgumentInteger(uint32 *value, const char *arg);
+		success = GetArgumentInteger(&val, value);
+		if (success) success = SetPatchValue(index, val);
+	}
 
-	success = SetPatchValue(index, value);
-	return success;
+	if (!success) {
+		if (_network_server) {
+			IConsoleError("This command/variable is not available during network games.");
+		} else {
+			IConsoleError("This command/variable is only available to a network server.");
+		}
+	}
+}
+
+void IConsoleSetPatchSetting(const char *name, int value)
+{
+	uint index;
+	const SettingDesc *sd = GetPatchFromName(name, &index);
+	assert(sd != NULL);
+	SetPatchValue(index, value);
 }
 
 void IConsoleGetPatchSetting(const char *name)
@@ -2198,14 +2294,18 @@
 
 	ptr = GetVariableAddress((_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game, &sd->save);
 
-	if (sd->desc.cmd == SDT_BOOLX) {
-		snprintf(value, sizeof(value), (*(bool*)ptr == 1) ? "on" : "off");
+	if (sd->desc.cmd == SDT_STRING) {
+		IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, (const char *)ptr);
 	} else {
-		snprintf(value, sizeof(value), "%d", (int32)ReadValue(ptr, sd->save.conv));
+		if (sd->desc.cmd == SDT_BOOLX) {
+			snprintf(value, sizeof(value), (*(bool*)ptr == 1) ? "on" : "off");
+		} else {
+			snprintf(value, sizeof(value), "%d", (int32)ReadValue(ptr, sd->save.conv));
+		}
+
+		IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
+			name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
 	}
-
-	IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
-		name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
 }
 
 void IConsoleListPatches()
@@ -2218,6 +2318,8 @@
 
 		if (sd->desc.cmd == SDT_BOOLX) {
 			snprintf(value, lengthof(value), (*(bool*)ptr == 1) ? "on" : "off");
+		} else if (sd->desc.cmd == SDT_STRING) {
+			snprintf(value, sizeof(value), "%s", (const char *)ptr);
 		} else {
 			snprintf(value, lengthof(value), "%d", (uint32)ReadValue(ptr, sd->save.conv));
 		}
--- a/src/settings_func.h	Thu May 29 23:33:37 2008 +0000
+++ b/src/settings_func.h	Fri May 30 09:23:05 2008 +0000
@@ -5,7 +5,8 @@
 #ifndef SETTINGS_FUNC_H
 #define SETTINGS_FUNC_H
 
-bool IConsoleSetPatchSetting(const char *name, int32 value);
+void IConsoleSetPatchSetting(const char *name, const char *value);
+void IConsoleSetPatchSetting(const char *name, int32 value);
 void IConsoleGetPatchSetting(const char *name);
 void IConsoleListPatches();
 
--- a/src/settings_internal.h	Thu May 29 23:33:37 2008 +0000
+++ b/src/settings_internal.h	Fri May 30 09:23:05 2008 +0000
@@ -85,5 +85,6 @@
 
 const SettingDesc *GetPatchFromName(const char *name, uint *i);
 bool SetPatchValue(uint index, int32 value);
+bool SetPatchValue(uint index, const char *value);
 
 #endif /* SETTINGS_H */