(svn r2106) -Fix: improved the network-join algoritm, it is now a bit more stable
authortruelight
Tue, 29 Mar 2005 19:10:13 +0000
changeset 1602 08783e4287dc
parent 1601 9fd461d00287
child 1603 e67485272abc
(svn r2106) -Fix: improved the network-join algoritm, it is now a bit more stable
-Add: added 'pause_on_join' and 'max_join_time' for MP games, where you
can auto-pause the game when a client wants to join the game. This to
avoid connection losses because of big maps (200+ trains). (with tnx to
#openttdcoop for the ideas and testing)
console_cmds.c
network.c
network.h
network_server.c
settings.c
--- a/console_cmds.c	Tue Mar 29 11:19:10 2005 +0000
+++ b/console_cmds.c	Tue Mar 29 19:10:13 2005 +0000
@@ -436,6 +436,9 @@
 			case STATUS_AUTH:
 				status = "authorized";
 				break;
+			case STATUS_MAP_WAIT:
+				status = "waiting";
+				break;
 			case STATUS_MAP:
 				status = "loading map";
 				break;
@@ -1061,6 +1064,20 @@
 		return NULL;
 	}
 
+	// setting max-join-time
+	if (strcmp(argv[1],"max_join_time") == 0) {
+		if (argc == 3 && atoi(argv[2]) != 0) {
+			_network_max_join_time = atoi(argv[2]);
+			IConsolePrintF(_iconsole_color_warning, "Max-join-time changed to '%d'", _network_max_join_time);
+			IConsolePrintF(_iconsole_color_warning, "Changes will take effect immediatly.");
+		} else {
+			IConsolePrintF(_iconsole_color_default, "Current max-join-time is '%d'", _network_max_join_time);
+			IConsolePrint(_iconsole_color_warning, "Usage: set max_join_time <ticks> (default = 500).");
+		}
+		return NULL;
+	}
+
+
 	// setting the server advertising on/off
 	if (strcmp(argv[1],"server_advertise") == 0) {
 		if (!_network_server) {
@@ -1082,6 +1099,25 @@
 		return NULL;
 	}
 
+	// setting the server 'pause on client join' on/off
+	if (strcmp(argv[1],"pause_on_join") == 0) {
+		if (!_network_server) {
+			IConsolePrintF(_iconsole_color_error, "You are not the server");
+			return NULL;
+		}
+		if (argc == 3) {
+			if (strcmp(argv[2], "on") == 0 || atoi(argv[2]) == 1)
+				_network_pause_on_join = true;
+			else
+				_network_pause_on_join = false;
+			IConsolePrintF(_iconsole_color_warning, "Pause-on-join changed to '%s'", (_network_pause_on_join)?"on":"off");
+		} else {
+			IConsolePrintF(_iconsole_color_default, "Current pause-on-join is '%s'", (_network_pause_on_join)?"on":"off");
+			IConsolePrint(_iconsole_color_warning, "Usage: set pause_on_join on/off.");
+		}
+		return NULL;
+	}
+
 	// setting the server autoclean on/off
 	if (strcmp(argv[1],"autoclean_companies") == 0) {
 		if (!_network_server) {
@@ -1175,7 +1211,9 @@
 	IConsolePrint(_iconsole_color_error, " - autoclean_protected <months>");
 	IConsolePrint(_iconsole_color_error, " - autoclean_unprotected <months>");
 	IConsolePrint(_iconsole_color_error, " - company_pw \"<password>\"");
+	IConsolePrint(_iconsole_color_error, " - max_join_time <frames>");
 	IConsolePrint(_iconsole_color_error, " - name \"<playername>\"");
+	IConsolePrint(_iconsole_color_error, " - pause_on_join on/off");
 	IConsolePrint(_iconsole_color_error, " - rcon_pw \"<password>\"");
 	IConsolePrint(_iconsole_color_error, " - server_name \"<name>\"");
 	IConsolePrint(_iconsole_color_error, " - server_advertise on/off");
--- a/network.c	Tue Mar 29 11:19:10 2005 +0000
+++ b/network.c	Tue Mar 29 19:10:13 2005 +0000
@@ -4,6 +4,7 @@
 #include "strings.h"
 #include "map.h"
 #include "network_data.h"
+#include "command.h"
 
 #if defined(WITH_REV)
 	extern const char _openttd_revision[];
@@ -466,6 +467,9 @@
 	cs->last_frame = 0;
 	cs->quited = false;
 
+	cs->last_frame = _frame_counter;
+	cs->last_frame_server = _frame_counter;
+
 	if (_network_server) {
 		ci = DEREF_CLIENT_INFO(cs);
 		memset(ci, 0, sizeof(*ci));
@@ -511,6 +515,12 @@
 				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
 			}
 		}
+
+		/* When the client was PRE_ACTIVE, the server was in pause mode, so unpause */
+		if (cs->status == STATUS_PRE_ACTIVE && _network_pause_on_join) {
+			DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
+			NetworkServer_HandleChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, "Game unpaused", NETWORK_SERVER_INDEX);
+		}
 	}
 
 	closesocket(cs->socket);
--- a/network.h	Tue Mar 29 11:19:10 2005 +0000
+++ b/network.h	Tue Mar 29 19:10:13 2005 +0000
@@ -161,6 +161,9 @@
 VARDEF char _network_server_password[NETWORK_PASSWORD_LENGTH];
 VARDEF char _network_rcon_password[NETWORK_PASSWORD_LENGTH];
 
+VARDEF uint16 _network_max_join_time;             //! Time a client can max take to join
+VARDEF bool _network_pause_on_join;               //! Pause the game when a client tries to join (more chance of succeeding join)
+
 VARDEF uint16 _redirect_console_to_client;
 
 VARDEF uint16 _network_sync_freq;
--- a/network_server.c	Tue Mar 29 11:19:10 2005 +0000
+++ b/network_server.c	Tue Mar 29 19:10:13 2005 +0000
@@ -304,6 +304,9 @@
 		sent_packets = 4; // We start with trying 4 packets
 
 		cs->status = STATUS_MAP;
+		/* Mark the start of download */
+		cs->last_frame = _frame_counter;
+		cs->last_frame_server = _frame_counter;
 	}
 
 	if (cs->status == STATUS_MAP) {
@@ -759,6 +762,13 @@
 				SEND_COMMAND(PACKET_SERVER_JOIN)(new_cs, cs->index);
 			}
 		}
+
+		if (_network_pause_on_join) {
+			/* Now pause the game till the client is in sync */
+			DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
+
+			NetworkServer_HandleChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, "Game paused (incoming client)", NETWORK_SERVER_INDEX);
+		}
 	} else {
 		// Wrong status for this packet, give a warning to client, and close connection
 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
@@ -937,14 +947,27 @@
 
 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK)
 {
+	uint32 frame = NetworkRecv_uint32(cs, p);
+
+	/* The client is trying to catch up with the server */
+	if (cs->status == STATUS_PRE_ACTIVE) {
+		/* The client is not yet catched up? */
+		if (frame + DAY_TICKS < _frame_counter)
+			return;
+
+		/* Now he is! Unpause the game */
+		cs->status = STATUS_ACTIVE;
+
+		if (_network_pause_on_join) {
+			DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
+			NetworkServer_HandleChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, "Game unpaused", NETWORK_SERVER_INDEX);
+		}
+	}
+
 	// The client received the frame, make note of it
-	cs->last_frame = NetworkRecv_uint32(cs, p);
+	cs->last_frame = frame;
 	// With those 2 values we can calculate the lag realtime
 	cs->last_frame_server = _frame_counter;
-
-	// The client is now really active
-	if (cs->status == STATUS_PRE_ACTIVE)
-		cs->status = STATUS_ACTIVE;
 }
 
 
@@ -1527,6 +1550,12 @@
 			} else {
 				cs->lag_test = 0;
 			}
+		} else if (cs->status == STATUS_PRE_ACTIVE) {
+			int lag = NetworkCalculateLag(cs);
+			if (lag > _network_max_join_time) {
+				IConsolePrintF(_iconsole_color_error,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->index, _network_max_join_time);
+				NetworkCloseClient(cs);
+			}
 		}
 
 
@@ -1536,7 +1565,7 @@
 		}
 
 		// Do we need to send the new frame-packet?
-		if (send_frame && cs->status == STATUS_ACTIVE) {
+		if (send_frame && (cs->status == STATUS_ACTIVE || cs->status == STATUS_PRE_ACTIVE)) {
 			SEND_COMMAND(PACKET_SERVER_FRAME)(cs);
 		}
 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
--- a/settings.c	Tue Mar 29 11:19:10 2005 +0000
+++ b/settings.c	Tue Mar 29 19:10:13 2005 +0000
@@ -760,6 +760,8 @@
 static const SettingDesc network_settings[] = {
 	{"sync_freq",				SDT_UINT16 | SDT_NOSAVE,	(void*)100,			&_network_sync_freq,		NULL},
 	{"frame_freq",			SDT_UINT8 | SDT_NOSAVE,	(void*)0,			&_network_frame_freq,		NULL},
+	{"max_join_time",		SDT_UINT,	(void*)500,	&_network_max_join_time,	NULL},
+	{"pause_on_join",		SDT_BOOL, (void*)false, &_network_pause_on_join, NULL},
 	{"server_bind_ip",	SDT_STRINGBUF | (lengthof(_network_server_bind_ip_host) << 16),	"0.0.0.0",	&_network_server_bind_ip_host,	NULL},
 	{"server_port",			SDT_UINT,	(void*)NETWORK_DEFAULT_PORT,	&_network_server_port,	NULL},
 	{"server_advertise",SDT_BOOL, (void*)false, &_network_advertise, NULL},