(svn r207) -Codechange: randomizer handling
authorsignde
Sat, 11 Sep 2004 19:34:11 +0000
changeset 206 7f8c26d8526b
parent 205 49e96fd94d63
child 207 0f7f7a67bd1b
(svn r207) -Codechange: randomizer handling
-Fix: desync problem fixes
-Fix: server doesnt hang anymore when a client timed out
-Feature: low latency connection enhancements [*net_sync_freq, *net_ready_ahead]
economy.c
functions.h
intro_gui.c
main_gui.c
misc.c
network.c
network_gui.c
oldloader.c
players.c
ttd.c
unix.c
variables.h
win32.c
--- a/economy.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/economy.c	Sat Sep 11 19:34:11 2004 +0000
@@ -1305,6 +1305,8 @@
 	if (_patches.inflation)
 		AddInflation();
 	PlayersPayInterest();
+	// Reset the _current_player flag
+	_current_player = OWNER_NONE;
 	HandleEconomyFluctuations();
 	SubsidyMonthlyHandler();
 }
--- a/functions.h	Sat Sep 11 19:18:30 2004 +0000
+++ b/functions.h	Sat Sep 11 19:34:11 2004 +0000
@@ -95,6 +95,8 @@
 uint32 Random();
 uint RandomRange(uint max);
 
+void InitPlayerRandoms();
+
 uint32 InteractiveRandom(); /* Used for random sequences that are not the same on the other end of the multiplayer link */
 void SetDate(uint date);
 /* facedraw.c */
@@ -131,6 +133,8 @@
 void NetworkStartSync(bool fcreset);
 void NetworkClose(bool client);
 void NetworkSendReadyPacket();
+void NetworkSendSyncPackets();
+bool NetworkCheckClientReady();
 
 void NetworkIPListInit();
 
--- a/intro_gui.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/intro_gui.c	Sat Sep 11 19:34:11 2004 +0000
@@ -125,8 +125,8 @@
 	// this forces stuff into test mode.
 	_docommand_recursive = 0;
 
-	_random_seed_1 = p1;
-	_random_seed_2 = p2;
+	_random_seeds[0][0] = p1;
+	_random_seeds[0][1] = p2;
 
 	if (_networking) { NetworkStartSync(true); }
 
@@ -166,8 +166,8 @@
 	// this forces stuff into test mode.
 	_docommand_recursive = 0;
 
-	_random_seed_1 = p1;
-	_random_seed_2 = p2;
+	_random_seeds[0][0] = p1;
+	_random_seeds[0][1] = p2;
 
 	if (_networking) { NetworkStartSync(true); }
 
--- a/main_gui.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/main_gui.c	Sat Sep 11 19:34:11 2004 +0000
@@ -922,8 +922,8 @@
 
 void ResetLandscape()
 {
-	_random_seed_1 = InteractiveRandom();
-	_random_seed_2 = InteractiveRandom();
+	_random_seeds[0][0] = InteractiveRandom();
+	_random_seeds[0][1] = InteractiveRandom();
 
 	GenerateWorld(1);
 	MarkWholeScreenDirty();
--- a/misc.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/misc.c	Sat Sep 11 19:34:11 2004 +0000
@@ -8,8 +8,6 @@
 extern void StartupEconomy();
 extern void InitNewsItemStructs();
 
-static uint32 _random_seed_3, _random_seed_4;
-
 byte _name_array[512][32];
 
 static INLINE uint32 ROR(uint32 x, int n)
@@ -20,10 +18,17 @@
 
 uint32 Random()
 {
-	uint32 t = _random_seed_2;
-	uint32 s = _random_seed_1;
-	_random_seed_1 = s + ROR(t ^ 0x1234567F, 7);
-	return _random_seed_2 = ROR(s, 3);
+	if (_current_player>=MAX_PLAYERS) {
+		uint32 s = _random_seeds[0][0];
+		uint32 t = _random_seeds[0][1];
+		_random_seeds[0][0] = s + ROR(t ^ 0x1234567F, 7);
+		return _random_seeds[0][1] = ROR(s, 3);
+	} else {
+		uint32 s = _player_seeds[_current_player][0];
+		uint32 t = _player_seeds[_current_player][1];
+		_player_seeds[_current_player][0] = s + ROR(t ^ 0x1234567F, 7);
+		return _player_seeds[_current_player][1] = ROR(s, 3);
+	}
 }
 
 uint RandomRange(uint max)
@@ -33,10 +38,19 @@
 
 uint32 InteractiveRandom()
 {
-	uint32 t = _random_seed_4;
-	uint32 s = _random_seed_3;
-	_random_seed_3 = s + ROR(t ^ 0x1234567F, 7);
-	return _random_seed_4 = ROR(s, 3);
+	uint32 t = _random_seeds[1][1];
+	uint32 s = _random_seeds[1][0];
+	_random_seeds[1][0] = s + ROR(t ^ 0x1234567F, 7);
+	return _random_seeds[1][1] = ROR(s, 3);
+}
+
+void InitPlayerRandoms()
+{
+	int i;
+	for (i=0; i<MAX_PLAYERS; i++) {
+		_player_seeds[i][0]=InteractiveRandom();
+		_player_seeds[i][1]=InteractiveRandom();
+		}
 }
 
 void memswap(void *a, void *b, size_t size) {
@@ -561,7 +575,7 @@
 		return;
 	_cur_month = ymd.month;
 
-//	printf("Month %d, %X\n", ymd.month, _random_seed_1);
+//	printf("Month %d, %X\n", ymd.month, _random_seeds[0][0]);
 
 	/* yes, call various monthly loops */
 	if (_game_mode != GM_MENU) {
@@ -693,8 +707,8 @@
 	{&_cur_tileloop_tile, 			SLE_UINT16, 0, 255},
 	{&_disaster_delay, 					SLE_UINT16, 0, 255},
 	{&_station_tick_ctr, 				SLE_UINT16, 0, 255},
-	{&_random_seed_1, 					SLE_UINT32, 0, 255},
-	{&_random_seed_2, 					SLE_UINT32, 0, 255},
+	{&_random_seeds[0][0], 					SLE_UINT32, 0, 255},
+	{&_random_seeds[0][1], 					SLE_UINT32, 0, 255},
 	{&_cur_town_ctr, 						SLE_UINT8,	0, 255},
 	{&_cur_player_tick_index, 	SLE_FILE_U8 | SLE_VAR_UINT, 0, 255},
 	{&_next_competitor_start, 	SLE_FILE_U16 | SLE_VAR_UINT, 0, 255},
--- a/network.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/network.c	Sat Sep 11 19:34:11 2004 +0000
@@ -79,6 +79,15 @@
 
 #if defined(ENABLE_NETWORK)
 
+enum {
+	PACKET_TYPE_WELCOME = 0,
+	PACKET_TYPE_READY,
+	PACKET_TYPE_ACK,
+	PACKET_TYPE_SYNC,
+	PACKET_TYPE_XMIT,
+	PACKET_TYPE_COMMAND,
+};
+
 // sent from client -> server whenever the client wants to exec a command.
 // send from server -> client when another player execs a command.
 typedef struct CommandPacket {
@@ -92,8 +101,6 @@
 	uint32 dp[8];
 } CommandPacket;
 
-assert_compile(sizeof(CommandPacket) == 16 + 32);
-
 #define COMMAND_PACKET_BASE_SIZE (sizeof(CommandPacket) - 8 * sizeof(uint32))
 
 // sent from server -> client periodically to tell the client about the current tick in the server
@@ -107,13 +114,12 @@
 	uint32 random_seed_2;
 } SyncPacket;
 
-assert_compile(sizeof(SyncPacket) == 12);
-
 // 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;
 } AckPacket;
 
 typedef struct ReadyPacket {
@@ -124,16 +130,16 @@
 typedef struct FilePacketHdr {
 	byte packet_length;
 	byte packet_type;
-	byte unused[2];
 } FilePacketHdr;
 
-assert_compile(sizeof(FilePacketHdr) == 4);
-
 // sent from server to client when the client has joined.
 typedef struct WelcomePacket {
 	byte packet_length;
 	byte packet_type;
-	byte unused[2];
+	uint32 player_seeds[MAX_PLAYERS][2];
+	uint32 frames_max;
+	uint32 frames_srv;
+	uint32 frames_cnt;
 } WelcomePacket;
 
 typedef struct Packet Packet;
@@ -155,19 +161,17 @@
 	Packet *head, **last;
 
 	uint buflen;											// receive buffer len
-	byte buf[256];										// receive buffer
+	byte buf[1024];										// receive buffer
 } ClientState;
 
 
-static uint _not_packet;
-
 typedef struct QueuedCommand QueuedCommand;
 struct QueuedCommand {
 	QueuedCommand *next;
 	CommandPacket cp;
 	CommandCallback *callback;
 	uint32 cmd;
-	int32 frame;
+	uint32 frame;
 };
 
 typedef struct CommandQueue CommandQueue;
@@ -195,7 +199,7 @@
 static uint16 _network_client_timeout;
 
 typedef struct FutureSeeds {
-	int32 frame;
+	uint32 frame;
 	uint32 seed[2];
 } FutureSeeds;
 
@@ -223,6 +227,8 @@
 };
 
 void NetworkUDPSend(bool client, struct sockaddr_in recv,struct UDPPacket packet);
+static void CloseClient(ClientState *cs);
+void NetworkSendWelcome(ClientState *cs, bool direct);
 
 uint32 _network_ip_list[10]; // network ip list
 
@@ -340,6 +346,16 @@
 	return qp;
 }
 
+static void QueueClear(CommandQueue *nq) {
+	QueuedCommand *qp;
+	while ((qp=nq->head)) {
+		// unlink it.
+		if (!(nq->head = qp->next)) nq->last = &nq->head;
+		free(qp);
+		}
+	nq->last = &nq->head;
+}
+
 // 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()
@@ -416,6 +432,20 @@
 	} while (len -= n);
 }
 
+// send data direct to a client
+static void SendDirectBytes(ClientState *cs, void *bytes, uint len)
+{
+	char *buf = (char*)bytes;
+	uint n;
+
+	n = send(cs->socket, buf, len, 0);
+	if (n == -1) {
+				int err = GET_LAST_ERROR();
+				DEBUG(net, 0) ("[NET] send() failed with error %d", err);
+				CloseClient(cs);
+			}
+}
+
 // client:
 //   add it to the client's ack queue, and send the command to the server
 // server:
@@ -427,7 +457,7 @@
 	ClientState *cs;
 
 	qp = AllocQueuedCommand(_networking_server ? &_command_queue : &_ack_queue);
-	qp->cp.packet_type = 0;
+	qp->cp.packet_type = PACKET_TYPE_COMMAND;
 	qp->cp.tile = tile;
 	qp->cp.p1 = p1;
 	qp->cp.p2 = p2;
@@ -438,7 +468,7 @@
 	qp->callback = callback;
 
 	// so the server knows when to execute it.
-	qp->frame = _frame_counter_max;
+	qp->frame = _frame_counter + 5;
 
 	// calculate the amount of extra bytes.
 	nump = 8;
@@ -480,6 +510,7 @@
 	QueuedCommand *qp;
 	ClientState *c;
 	AckPacket ap;
+	int i;
 
 	DEBUG(net, 2) ("[NET] cmd size %d", np->packet_length);
 
@@ -489,21 +520,28 @@
 	qp = AllocQueuedCommand(&_command_queue);
 	qp->cp = *np;
 
-	qp->frame = _frame_counter_max;
+	i = _frame_counter_max - (_frame_counter + 3);
+	
+	if (i<0) {
+		qp->frame = _frame_counter_max ;
+	} else {
+		qp->frame = _frame_counter + 3;
+	}
 
 	qp->callback = NULL;
 
 	// extra params
 	memcpy(&qp->cp.dp, np->dp, np->packet_length - COMMAND_PACKET_BASE_SIZE);
 
-	ap.packet_type = 2;
-	ap.packet_length = 2;
+	ap.packet_type = PACKET_TYPE_ACK;
+	ap.when = _frame_counter_max-(qp->frame);
+	ap.packet_length = sizeof(AckPacket);
 
 	// send it to the peers
 	if (_networking_server) {
 		for(c=_clients; c->socket != INVALID_SOCKET; c++) {
 			if (c == cs) {
-				SendBytes(c, &ap, 2);
+				SendDirectBytes(c, &ap, ap.packet_length);
 			} else {
 				if (!cs->inactive) SendBytes(c, &qp->cp, qp->cp.packet_length);
 			}
@@ -540,7 +578,7 @@
 	s1 = TO_LE32(sp->random_seed_1);
 	s2 = TO_LE32(sp->random_seed_2);
 
-	DEBUG(net, 3) ("[NET] sync seeds: [1]=%i rnd[2]=%i", sp->random_seed_1, sp->random_seed_2);
+	DEBUG(net, 3) ("[NET] sync seeds: frame=%i 1=%i 2=%i",_frame_counter, sp->random_seed_1, sp->random_seed_2);
 
 	if (_frame_counter_srv <= _frame_counter) {
 		// we are ahead of the server check if the seed is in our list.
@@ -561,7 +599,7 @@
 
 // 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()
+static void HandleAckPacket(AckPacket * ap)
 {
 	QueuedCommand *q;
 	// move a packet from the ack queue to the end of this player's queue.
@@ -569,12 +607,12 @@
 	assert(q);
 	if (!(_ack_queue.head = q->next)) _ack_queue.last = &_ack_queue.head;
 	q->next = NULL;
-	q->frame = _frame_counter_max;
+	q->frame = (_frame_counter_max - (ap->when));
 
 	*_command_queue.last = q;
 	_command_queue.last = &q->next;
 
-	DEBUG(net, 2) ("[NET] ack");
+	DEBUG(net, 2) ("[NET] ack [frame=%i]",q->frame);
 }
 
 static void HandleFilePacket(FilePacketHdr *fp)
@@ -619,6 +657,28 @@
 	}
 }
 
+static void HandleWelcomePacket(WelcomePacket *wp) {
+	int i;
+	for (i=0; i<MAX_PLAYERS; i++) {
+		_player_seeds[i][0]=wp->player_seeds[i][0];
+		_player_seeds[i][1]=wp->player_seeds[i][1];
+		}
+	if (wp->frames_srv != 0) {
+		_frame_counter_max = wp->frames_max;
+		_frame_counter_srv = wp->frames_srv;
+	}
+	if (wp->frames_cnt != 0) {
+		_frame_counter = wp->frames_cnt;
+	}
+}
+
+static void HandleReadyPacket(ReadyPacket *rp, ClientState *cs)
+{
+	cs->ready=true;
+	cs->timeout=_network_client_timeout;
+}
+
+
 static void CloseClient(ClientState *cs)
 {
 	Packet *p, *next;
@@ -680,24 +740,26 @@
 			size -= packet[0];
 			pos += packet[0];
 			switch(packet[1]) {
-			case 0:
+			case PACKET_TYPE_WELCOME:
+				HandleWelcomePacket((WelcomePacket *)packet);
+				break;
+			case PACKET_TYPE_COMMAND:
 				HandleCommandPacket(cs, (CommandPacket*)packet);
 				break;
-			case 1:
+			case PACKET_TYPE_SYNC:
 				assert(_networking_sync || _networking_queuing);
 				assert(!_networking_server);
 				HandleSyncPacket((SyncPacket*)packet);
 				break;
-			case 2:
+			case PACKET_TYPE_ACK:
 				assert(!_networking_server);
-				HandleAckPacket();
+				HandleAckPacket((AckPacket*)packet);
 				break;
-			case 3:
+			case PACKET_TYPE_XMIT:
 				HandleFilePacket((FilePacketHdr*)packet);
 				break;
-			case 5:
-				cs->ready=true;
-				cs->timeout=_network_client_timeout;
+			case PACKET_TYPE_READY:
+				HandleReadyPacket((ReadyPacket*)packet, cs);
 				break;
 			default:
 				DEBUG (net,0) ("net: unknown packet type");
@@ -783,8 +845,7 @@
 		n = minu(_transmit_file_size - pos, 248);
 
 		hdr.packet_length = n + sizeof(hdr);
-		hdr.packet_type = 3;
-		hdr.unused[0] = hdr.unused[1] = 0;
+		hdr.packet_type = PACKET_TYPE_XMIT;
 		SendBytes(cs, &hdr, sizeof(hdr));
 
 		if (n == 0) {
@@ -797,6 +858,10 @@
 
 	cs->xmitpos = pos + 1;
 
+	if (cs->xmitpos == 0) {
+		NetworkSendWelcome(cs,false);
+	}
+
 	DEBUG(net, 2) ("[NET] client xmit at %d", pos + 1);
 }
 
@@ -819,17 +884,65 @@
 
 void NetworkSendReadyPacket()
 {
-	if (!_network_ready_sent) {
+	if ((!_network_ready_sent) && (_frame_counter + _network_ready_ahead >= _frame_counter_max)) {
 		ReadyPacket *rp	= malloc(sizeof(rp));
 		ClientState *c	= _clients;
 
-		rp->packet_type = 5;
+		rp->packet_type = PACKET_TYPE_READY;
 		rp->packet_length = sizeof(rp);
 		SendBytes(c, rp, sizeof(rp));
 		_network_ready_sent = true;
 	}
 }
 
+void NetworkSendSyncPackets()
+{
+	ClientState *cs;
+	uint32 new_max;
+	SyncPacket sp;
+
+	new_max = _frame_counter + (int)_network_sync_freq;
+
+	DEBUG(net,3) ("net: serv: sync frame=%i,max=%i, seed1=%i, seed2=%i",new_max,_sync_seed_1,_sync_seed_2);
+
+	sp.packet_length = sizeof(sp);
+	sp.packet_type = PACKET_TYPE_SYNC;
+	sp.frames = new_max - _frame_counter_max;
+	sp.server = _frame_counter_max - _frame_counter;
+	sp.random_seed_1 = TO_LE32(_sync_seed_1);
+	sp.random_seed_2 = TO_LE32(_sync_seed_2);
+	_frame_counter_max = new_max;
+
+	// 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));
+	}
+
+}
+
+void NetworkSendWelcome(ClientState *cs, bool direct) {
+	WelcomePacket wp;
+	int i;
+	wp.packet_type = PACKET_TYPE_WELCOME;
+	wp.packet_length = sizeof(WelcomePacket);
+	for (i=0; i<MAX_PLAYERS; i++) {
+		wp.player_seeds[i][0]=_player_seeds[i][0];
+		wp.player_seeds[i][1]=_player_seeds[i][1];
+		}
+	if (direct) {
+		wp.frames_max=0;
+		wp.frames_srv=0;
+		wp.frames_cnt=_frame_counter;
+		SendDirectBytes(cs,(void *)&wp,wp.packet_length);
+	} else {
+		wp.frames_max=_frame_counter_max;
+		wp.frames_srv=_frame_counter_srv;
+		wp.frames_cnt=0;
+		SendBytes(cs,(void *)&wp,wp.packet_length);
+	}
+}
+
 static void NetworkAcceptClients()
 {
 	struct sockaddr_in sin;
@@ -888,12 +1001,12 @@
 	// send the commands in the server queue to the new client.
 	QueuedCommand *qp;
 	SyncPacket sp;
-	int32 frame;
+	uint32 frame;
 
 	DEBUG(net, 2) ("[NET] sending queued commands to client");
 
 	sp.packet_length = sizeof(sp);
-	sp.packet_type = 1;
+	sp.packet_type = PACKET_TYPE_SYNC;
 	sp.random_seed_1 = sp.random_seed_2 = 0;
 	sp.server = 0;
 
@@ -918,6 +1031,25 @@
 
 }
 
+
+bool NetworkCheckClientReady() {
+	bool ready_all = true;
+	uint16 count = 0;
+	ClientState *cs;
+
+	for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
+		count++;
+		ready_all = ready_all && (cs->ready || cs->inactive || (cs->xmitpos>0));
+		if (!cs->ready) cs->timeout-=1;
+		if (cs->timeout == 0) {
+			SET_DPARAM16(0,count);
+			ShowErrorMessage(-1,STR_NETWORK_ERR_TIMEOUT,0,0);
+			CloseClient(cs);
+			}
+		}
+	return ready_all;
+}
+
 // ************************** //
 // * TCP Networking         * //
 // ************************** //
@@ -1077,6 +1209,8 @@
 
 				// send queue of commands to client.
 				SendQueuedCommandsToNewClient(cs);
+
+				NetworkSendWelcome(cs, true);
 			}
 		}
 	}
@@ -1086,61 +1220,6 @@
 {
 	ClientState *cs;
 	void *free_xmit;
-	uint16 count;
-	bool ready_all;
-
-	// send sync packets?
-	if (_networking_server && _networking_sync && !_pause) {
-
-		if (++_not_packet >= _network_sync_freq) {
-			SyncPacket sp;
-			uint new_max;
-
-			_network_ahead_frames = _network_sync_freq + 1;
-
-			ready_all=false;
-
-			while (!ready_all) {
-				// check wether all clients are ready
-				ready_all=true;
-				count=0;
-				for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
-					count++;
-					ready_all = ready_all && (cs->ready || cs->inactive || (cs->xmitpos>0));
-					if (!cs->ready) cs->timeout-=5;
-					if (cs->timeout == 0) {
-						SET_DPARAM16(0,count);
-						ShowErrorMessage(-1,STR_NETWORK_ERR_TIMEOUT,0,0);
-						CloseClient(cs);
-						}
-					}
-				if (!ready_all) {
-					NetworkReceive();
-					CSleep(5);
-					}
-			}
-
-			_not_packet = 0;
-
-			new_max = max(_frame_counter + (int)_network_ahead_frames, _frame_counter_max);
-
-			DEBUG(net,3) ("net: serv: sync max=%i, seed1=%i, seed2=%i",new_max,_sync_seed_1,_sync_seed_2);
-
-			sp.packet_length = sizeof(sp);
-			sp.packet_type = 1;
-			sp.frames = new_max - _frame_counter_max;
-			sp.server = _frame_counter_max - _frame_counter;
-			sp.random_seed_1 = TO_LE32(_sync_seed_1);
-			sp.random_seed_2 = TO_LE32(_sync_seed_2);
-			_frame_counter_max = new_max;
-
-			// 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));
-			}
-		}
-	}
 
 	free_xmit = _transmit_file;
 
@@ -1168,8 +1247,9 @@
 {
 	ClientState *cs;
 
+	QueueClear(&_command_queue);
+	QueueClear(&_ack_queue);
 	_command_queue.last = &_command_queue.head;
-	_ack_queue.last = &_ack_queue.head;
 
 	// invalidate all clients
 	for(cs=_clients; cs != &_clients[MAX_CLIENTS]; cs++)
@@ -1455,7 +1535,7 @@
 
 DEBUG(net, 3) ("[NET][Core] init()");
 _network_available=true;
-_network_client_timeout=3000;
+_network_client_timeout=300;
 
 // [win32] winsock startup
 
@@ -1631,19 +1711,12 @@
 
 	if (_networking) {
 		NetworkReceive();
-		NetworkProcessCommands(); // to check if we got any new commands belonging to the current frame before we increase it.
 		}
 
 	} else {
 
-	// outgoing
-
-	if ((_networking) && (!_networking_server) && (_frame_counter+_network_ready_ahead >= _frame_counter_max)) {
-			// send the "i" am ready message to the server
-			// [_network_ready_ahead] frames before "i" reach the frame-limit
-			NetworkSendReadyPacket();
-		}
-
+	if ( _udp_client_socket != INVALID_SOCKET ) NetworkUDPReceive(true);
+	if ( _udp_server_socket != INVALID_SOCKET ) NetworkUDPReceive(false);
 
 	if (_networking) {
 		NetworkSend();
--- a/network_gui.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/network_gui.c	Sat Sep 11 19:34:11 2004 +0000
@@ -31,10 +31,17 @@
 * we'll just use some dummy here
 */
 static byte _network_connection;
+static uint16 _network_game_count_last;
 
 static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
 {
 	switch(e->event) {
+	case WE_TICK: {
+		if (_network_game_count_last != _network_game_count) {
+			SetWindowDirty(w);
+			}
+		}
+		break;
 	case WE_PAINT: {
 
 		SET_DPARAM16(0, 0x00);
@@ -86,8 +93,18 @@
 
 	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
 		_network_connection = e->dropdown.index;
-
-		SetWindowDirty(w);
+		switch (_network_connection) {
+		case 0:
+			NetworkGameListFromLAN();
+			_network_game_count_last = _network_game_count;
+			SetWindowDirty(w);
+			break;
+		case 1:
+			NetworkGameListFromInternet();
+			_network_game_count_last = _network_game_count;
+			SetWindowDirty(w);
+			break;
+		}
 		break;
 
 	case WE_MOUSELOOP:
@@ -164,6 +181,7 @@
 	w = AllocateWindowDesc(&_network_game_window_desc);
 	strcpy(_edit_str_buf, "Your name");
 
+	_network_game_count_last = _network_game_count;
 
 	WP(w,querystr_d).caret = 1;
 	WP(w,querystr_d).maxlen = MAX_QUERYSTR_LEN;
--- a/oldloader.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/oldloader.c	Sat Sep 11 19:34:11 2004 +0000
@@ -1124,8 +1124,8 @@
 	_cur_tileloop_tile = m->cur_tileloop_tile;
 	_disaster_delay = m->disaster_delay;
 	_station_tick_ctr = m->station_tick_ctr;
-	_random_seed_1 = m->seed_1;
-	_random_seed_2 = m->seed_2;
+	_random_seeds[0][0] = m->seed_1;
+	_random_seeds[0][1] = m->seed_2;
 	_cur_town_ctr = REMAP_TOWN_IDX(m->cur_town_ptr);
 	_cur_player_tick_index = m->cur_player_tick_index;
 	_next_competitor_start = m->next_competitor_start;
--- a/players.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/players.c	Sat Sep 11 19:34:11 2004 +0000
@@ -548,7 +548,7 @@
 	_is_ai_player = true;
 
 	FOR_ALL_PLAYERS(p) {
-		if (p->is_active) {
+		if (p->is_active && p->is_ai) {
 			_current_player = p->index;
 			if (_patches.ainew_active)
 				AiNewDoGameLoop(p);
@@ -558,8 +558,7 @@
 	}
 
 	_is_ai_player = false;
-// XXX: is this needed?
-	_current_player = 0;
+	_current_player = OWNER_NONE;
 }
 
 // index is the next parameter in _decode_parameters to set up
--- a/ttd.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/ttd.c	Sat Sep 11 19:34:11 2004 +0000
@@ -533,7 +533,7 @@
 				_switch_mode = SM_NEWGAME;
 			break;
 		case 'G':
-			_random_seed_1 = atoi(mgo.opt);
+			_random_seeds[0][0] = atoi(mgo.opt);
 			break;
 		case 'p': {
 			int i = atoi(mgo.opt);
@@ -604,6 +604,7 @@
 
 	// initialize the ingame console
 	IConsoleInit();
+	InitPlayerRandoms();
 
 	while (_video_driver->main_loop() == ML_SWITCHDRIVER) {}
 
@@ -881,8 +882,8 @@
 	_frame_counter++;
 
 	// store the random seed to be able to detect out of sync errors
-	_sync_seed_1 = _random_seed_1;
-	_sync_seed_2 = _random_seed_2;
+	_sync_seed_1 = _random_seeds[0][0];
+	_sync_seed_2 = _random_seeds[0][1];
 	if (_networking) disable_computer=true;
 
 	if (_savedump_path[0] && (uint)_frame_counter >= _savedump_first && (uint)(_frame_counter -_savedump_first) % _savedump_freq == 0 ) {
@@ -899,6 +900,11 @@
 		CallWindowTickEvent();
 		NewsLoop();
 	} else {
+		// All these actions has to be done from OWNER_NONE
+		//  for multiplayer compatibility
+		uint p = _current_player;
+		_current_player = OWNER_NONE;
+
 		AnimateAnimatedTiles();
 		IncreaseDate();
 		RunTileLoop();
@@ -910,6 +916,7 @@
 
 		CallWindowTickEvent();
 		NewsLoop();
+		_current_player = p;
 	}
 	_in_state_game_loop = false;
 }
@@ -985,21 +992,36 @@
 	NetworkCoreLoop(true);
 
 	if (_networking_sync) {
-		// make sure client's time is synched to the server by running frames quickly up to where the server is.
+		// 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) {
 				StateGameLoop();
 				NetworkProcessCommands(); // need to process queue to make sure that packets get executed.
 			}
-		}
-		// don't exceed the max count told by the server
+		// client: don't exceed the max count told by the server
 		if (_frame_counter < _frame_counter_max) {
 			StateGameLoop();
 			NetworkProcessCommands();
 			}
+		// client: send the ready packet
+		NetworkSendReadyPacket();
+		} else {
+		// server: work on to the frame max
+		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.
+			}
+		// server: wait until all clients were ready for going on
+		if (_frame_counter == _frame_counter_max) {
+			if (NetworkCheckClientReady()) NetworkSendSyncPackets();
+			}
+		}
 	} else {
+		// server/client/standalone: not synced --> state game loop
 		if (!_pause)
 			StateGameLoop();
+		// server/client: process queued network commands
+		if (_networking) NetworkProcessCommands();
 	}
 
 	if (!_pause && _display_opt&DO_FULL_ANIMATION)
--- a/unix.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/unix.c	Sat Sep 11 19:34:11 2004 +0000
@@ -420,7 +420,7 @@
 	ChangeWorkingDirectory(argv[0]);
 #endif
 
-	_random_seed_2 = _random_seed_1 = time(NULL);
+	_random_seeds[0][1] = _random_seeds[0][0] = time(NULL);
 
 
 	return ttd_main(argc, argv);
--- a/variables.h	Sat Sep 11 19:18:30 2004 +0000
+++ b/variables.h	Sat Sep 11 19:34:11 2004 +0000
@@ -62,7 +62,9 @@
 //  tick handler.
 VARDEF uint16 _station_tick_ctr;
 
-VARDEF uint32 _random_seed_1, _random_seed_2;
+VARDEF uint32 _random_seeds[2][2];
+VARDEF uint32 _player_seeds[MAX_PLAYERS][2];
+
 // Iterator through all towns in OnTick_Town
 VARDEF byte _cur_town_ctr;
 
@@ -214,10 +216,10 @@
 VARDEF byte _player_colors[MAX_PLAYERS];
 
 VARDEF bool _in_state_game_loop;
-VARDEF int32 _frame_counter;
+VARDEF uint32 _frame_counter;
 
-VARDEF int32 _frame_counter_max; // for networking, this is the frame that we are not allowed to execute yet.
-VARDEF int32 _frame_counter_srv; // for networking, this is the last known framecounter of the server. it is always less than frame_counter_max.
+VARDEF uint32 _frame_counter_max; // for networking, this is the frame that we are not allowed to execute yet.
+VARDEF uint32 _frame_counter_srv; // for networking, this is the last known framecounter of the server. it is always less than frame_counter_max.
 
 // networking settings
 VARDEF bool _network_available;  // is network mode available?
--- a/win32.c	Sat Sep 11 19:18:30 2004 +0000
+++ b/win32.c	Sat Sep 11 19:34:11 2004 +0000
@@ -1951,12 +1951,12 @@
 #if defined(_MSC_VER)
 	{
 		uint64 seed = rdtsc();
-		_random_seed_1 = ((uint32*)&seed)[0];
-		_random_seed_2 = ((uint32*)&seed)[1];
+		_random_seeds[0][0] = ((uint32*)&seed)[0];
+		_random_seeds[0][1] = ((uint32*)&seed)[1];
 	}
 #else
-	_random_seed_1 = GetTickCount();
-	_random_seed_2 = _random_seed_1 * 0x1234567;
+	_random_seeds[0][0] = GetTickCount();
+	_random_seeds[0][1] = _random_seeds[0][0] * 0x1234567;
 #endif
 
 	argc = ParseCommandLine(GetCommandLine(), argv, lengthof(argv));