changeset 17544:09be4c66385a draft

(svn r22308) -Fix [FS#4574]: waiting on a server could kick the client, or rather the client would kick itself due to an unexpected packet
author rubidium <rubidium@openttd.org>
date Sat, 09 Apr 2011 21:52:38 +0000
parents 2576cb1b3f90
children 2bdf6a8c6631
files src/network/network_client.cpp src/network/network_server.cpp
diffstat 2 files changed, 34 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/src/network/network_client.cpp
+++ b/src/network/network_client.cpp
@@ -719,17 +719,14 @@
 
 DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_WAIT)
 {
-	if (this->status != STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
-	this->status = STATUS_MAP_WAIT;
+	/* We set the internal wait state when requesting the map. */
+	if (this->status != STATUS_MAP_WAIT) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 
+	/* But... only now we set the join status to waiting, instead of requesting. */
 	_network_join_status = NETWORK_JOIN_STATUS_WAITING;
 	_network_join_waiting = p->Recv_uint8();
 	SetWindowDirty(WC_NETWORK_STATUS_WINDOW, 0);
 
-	/* We are put on hold for receiving the map.. we need GUI for this ;) */
-	DEBUG(net, 1, "The server is currently busy sending the map to someone else, please wait..." );
-	DEBUG(net, 1, "There are %d clients in front of you", _network_join_waiting);
-
 	return NETWORK_RECV_STATUS_OKAY;
 }
 
--- a/src/network/network_server.cpp
+++ b/src/network/network_server.cpp
@@ -539,9 +539,11 @@
 	if (this->status == STATUS_MAP) {
 		if (this->savegame_mutex != NULL) this->savegame_mutex->BeginCritical();
 
+		bool last_packet = false;
+
 		for (uint i = 0; i < sent_packets && this->savegame_packets != NULL; i++) {
 			Packet *p = this->savegame_packets;
-			bool last_packet = p->buffer[2] == PACKET_SERVER_MAP_DONE;
+			last_packet = p->buffer[2] == PACKET_SERVER_MAP_DONE;
 
 			/* Remove the packet from the savegame queue and put it in the real queue. */
 			this->savegame_packets = p->next;
@@ -549,31 +551,6 @@
 			this->NetworkTCPSocketHandler::SendPacket(p);
 
 			if (last_packet) {
-				/* Done reading! */
-
-				/* Set the status to DONE_MAP, no we will wait for the client
-				 *  to send it is ready (maybe that happens like never ;)) */
-				this->status = STATUS_DONE_MAP;
-
-				NetworkClientSocket *new_cs;
-				bool new_map_client = false;
-				/* Check if there is a client waiting for receiving the map
-				 *  and start sending him the map */
-				FOR_ALL_CLIENT_SOCKETS(new_cs) {
-					if (new_cs->status == STATUS_MAP_WAIT) {
-						/* Check if we already have a new client to send the map to */
-						if (!new_map_client) {
-							/* If not, this client will get the map */
-							new_cs->status = STATUS_AUTHORIZED;
-							new_map_client = true;
-							new_cs->SendMap();
-						} else {
-							/* Else, send the other clients how many clients are in front of them */
-							new_cs->SendWait();
-						}
-					}
-				}
-
 				/* There is no more data, so break the for */
 				break;
 			}
@@ -581,6 +558,34 @@
 
 		if (this->savegame_mutex != NULL) this->savegame_mutex->EndCritical();
 
+		if (last_packet) {
+			/* Done reading, make sure saving is done as well */
+			WaitTillSaved();
+
+			/* Set the status to DONE_MAP, no we will wait for the client
+				*  to send it is ready (maybe that happens like never ;)) */
+			this->status = STATUS_DONE_MAP;
+
+			NetworkClientSocket *new_cs;
+			bool new_map_client = false;
+			/* Check if there is a client waiting for receiving the map
+				*  and start sending him the map */
+			FOR_ALL_CLIENT_SOCKETS(new_cs) {
+				if (new_cs->status == STATUS_MAP_WAIT) {
+					/* Check if we already have a new client to send the map to */
+					if (!new_map_client) {
+						/* If not, this client will get the map */
+						new_cs->status = STATUS_AUTHORIZED;
+						new_map_client = true;
+						new_cs->SendMap();
+					} else {
+						/* Else, send the other clients how many clients are in front of them */
+						new_cs->SendWait();
+					}
+				}
+			}
+		}
+
 		switch (this->SendPackets()) {
 			case SPS_CLOSED:
 				return NETWORK_RECV_STATUS_CONN_LOST;