(svn r209) -Fix: network code based desync
authorsignde
Sat, 11 Sep 2004 22:10:31 +0000
changeset 208 f3998d4089f0
parent 207 0f7f7a67bd1b
child 209 fd1ec5041eeb
(svn r209) -Fix: network code based desync
-Feature: framesync packets to hold the clients framecount near the servers
-Fix: command queue now aligns the commands to be processed right after an sync or framesync packet
-Fix: added stubs for compiling without network
functions.h
network.c
ttd.c
--- a/functions.h	Sat Sep 11 20:25:40 2004 +0000
+++ b/functions.h	Sat Sep 11 22:10:31 2004 +0000
@@ -134,6 +134,7 @@
 void NetworkClose(bool client);
 void NetworkSendReadyPacket();
 void NetworkSendSyncPackets();
+void NetworkSendFrameSyncPackets();
 bool NetworkCheckClientReady();
 
 void NetworkIPListInit();
--- a/network.c	Sat Sep 11 20:25:40 2004 +0000
+++ b/network.c	Sat Sep 11 22:10:31 2004 +0000
@@ -84,6 +84,7 @@
 	PACKET_TYPE_READY,
 	PACKET_TYPE_ACK,
 	PACKET_TYPE_SYNC,
+	PACKET_TYPE_FSYNC,
 	PACKET_TYPE_XMIT,
 	PACKET_TYPE_COMMAND,
 };
@@ -114,12 +115,18 @@
 	uint32 random_seed_2;
 } SyncPacket;
 
+typedef struct FrameSyncPacket {
+	byte packet_length;
+	byte packet_type;
+	byte frames; // where is the server currently executing? this is negatively relative to the old value of max.
+} FrameSyncPacket;
+
 // sent from server -> client as an acknowledgement that the server received the command.
 // the command will be executed at the current value of "max".
 typedef struct AckPacket {
 	byte packet_length;
 	byte packet_type;
-	byte when;
+	int16 when;
 } AckPacket;
 
 typedef struct ReadyPacket {
@@ -197,6 +204,7 @@
 static bool _network_ready_sent;
 static uint16 _network_ready_ahead = 1;
 static uint16 _network_client_timeout;
+static uint32 _frame_fsync_last;
 
 typedef struct FutureSeeds {
 	uint32 frame;
@@ -356,6 +364,16 @@
 	nq->last = &nq->head;
 }
 
+static int GetNextSyncFrame()
+{
+	uint32 newframe;
+	if (_frame_fsync_last == 0) return -1;
+	newframe = (_frame_fsync_last + 9);
+	if ( (newframe + 4) > _frame_counter_max) return -1;
+	return (_frame_counter_max - newframe);
+
+}
+
 // go through the player queues for each player and see if there are any pending commands
 // that should be executed this frame. if there are, execute them.
 void NetworkProcessCommands()
@@ -468,7 +486,7 @@
 	qp->callback = callback;
 
 	// so the server knows when to execute it.
-	qp->frame = _frame_counter + 5;
+	qp->frame = _frame_counter_max - GetNextSyncFrame();
 
 	// calculate the amount of extra bytes.
 	nump = 8;
@@ -510,7 +528,6 @@
 	QueuedCommand *qp;
 	ClientState *c;
 	AckPacket ap;
-	int i;
 
 	DEBUG(net, 2) ("[NET] cmd size %d", np->packet_length);
 
@@ -519,14 +536,8 @@
 	// put it into the command queue
 	qp = AllocQueuedCommand(&_command_queue);
 	qp->cp = *np;
-
-	i = _frame_counter_max - (_frame_counter + 3);
 	
-	if (i<0) {
-		qp->frame = _frame_counter_max ;
-	} else {
-		qp->frame = _frame_counter + 3;
-	}
+	qp->frame = _frame_counter_max - GetNextSyncFrame();
 
 	qp->callback = NULL;
 
@@ -534,8 +545,9 @@
 	memcpy(&qp->cp.dp, np->dp, np->packet_length - COMMAND_PACKET_BASE_SIZE);
 
 	ap.packet_type = PACKET_TYPE_ACK;
-	ap.when = _frame_counter_max-(qp->frame);
+	ap.when = GetNextSyncFrame();
 	ap.packet_length = sizeof(AckPacket);
+	DEBUG(net,4)("[NET] NewACK: frame=%i %i",ap.when,_frame_counter_max - GetNextSyncFrame());
 
 	// send it to the peers
 	if (_networking_server) {
@@ -597,6 +609,13 @@
 	}
 }
 
+static void HandleFSyncPacket(FrameSyncPacket *fsp)
+{
+	DEBUG(net,3)("[NET] FSYNC: srv=%i %i",fsp->frames,(_frame_counter_max - fsp->frames));
+	if (fsp->frames < 4) return;
+	_frame_fsync_last = _frame_counter_srv = _frame_counter_max - fsp->frames;
+}
+
 // sent from server -> client as an acknowledgement that the server received the command.
 // the command will be executed at the current value of "max".
 static void HandleAckPacket(AckPacket * ap)
@@ -751,6 +770,9 @@
 				assert(!_networking_server);
 				HandleSyncPacket((SyncPacket*)packet);
 				break;
+			case PACKET_TYPE_FSYNC:
+				HandleFSyncPacket((FrameSyncPacket *)packet);
+				break;
 			case PACKET_TYPE_ACK:
 				assert(!_networking_server);
 				HandleAckPacket((AckPacket*)packet);
@@ -916,7 +938,26 @@
 	// send it to all the clients and mark them unready
 	for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
 		cs->ready=false;
-		SendBytes(cs, &sp, sizeof(sp));
+		SendBytes(cs, &sp, sp.packet_length);
+	}
+
+}
+
+void NetworkSendFrameSyncPackets()
+{
+	ClientState *cs;
+	FrameSyncPacket fsp;
+	if ((_frame_counter + 4) < _frame_counter_max) if ((_frame_fsync_last + 4 < _frame_counter)) {
+		// this packet mantains some information about on which frame the server is
+		fsp.frames = _frame_counter_max - _frame_counter;
+		fsp.packet_type = PACKET_TYPE_FSYNC;
+		fsp.packet_length = sizeof (FrameSyncPacket);
+		// send it to all the clients and mark them unready
+		for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
+			cs->ready=false;
+			SendBytes(cs, &fsp, fsp.packet_length);
+		}
+		_frame_fsync_last = _frame_counter;
 	}
 
 }
@@ -1293,6 +1334,7 @@
 	if (fcreset) {
 		_frame_counter_max = 0;
 		_frame_counter_srv = 0;
+		_frame_fsync_last = 0;
 		}
 	_num_future_seed = 0;
 	_sync_seed_1 = _sync_seed_2 = 0;
@@ -1863,6 +1905,10 @@
 void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) {}
 void NetworkProcessCommands() {}
 void NetworkStartSync(bool fcreset) {}
+void NetworkSendReadyPacket() {}
+void NetworkSendSyncPackets() {}
+void NetworkSendFrameSyncPackets() {}
+bool NetworkCheckClientReady() { return true; }
 void NetworkCoreInit() { _network_available=false; };
 void NetworkCoreShutdown() {};
 void NetworkCoreDisconnect() {};
--- a/ttd.c	Sat Sep 11 20:25:40 2004 +0000
+++ b/ttd.c	Sat Sep 11 22:10:31 2004 +0000
@@ -995,8 +995,10 @@
 		// client: make sure client's time is synched to the server by running frames quickly up to where the server is.
 		if (!_networking_server) {
 			while (_frame_counter < _frame_counter_srv) {
+				NetworkCoreLoop(true);
 				StateGameLoop();
 				NetworkProcessCommands(); // need to process queue to make sure that packets get executed.
+				NetworkCoreLoop(false);
 			}
 		// client: don't exceed the max count told by the server
 		if (_frame_counter < _frame_counter_max) {
@@ -1010,6 +1012,7 @@
 		if (_frame_counter < _frame_counter_max) {
 			StateGameLoop();
 			NetworkProcessCommands(); // to check if we got any new commands belonging to the current frame before we increase it.
+			NetworkSendFrameSyncPackets();
 			}
 		// server: wait until all clients were ready for going on
 		if (_frame_counter == _frame_counter_max) {