diff --git a/src/include/net_message.h b/src/include/net_message.h
index c75326d41..1baef5a7f 100644
--- a/src/include/net_message.h
+++ b/src/include/net_message.h
@@ -336,6 +336,13 @@ public:
 	void Deserialize(const unsigned char *p);
 	static size_t Size() { return 2 + 2 + 2 + 2; }
 
+	bool operator == (const CNetworkCommand &rhs) const
+	{
+		return Unit == rhs.Unit && X == rhs.X && Y == rhs.Y && Dest == rhs.Dest;
+	}
+	bool operator != (const CNetworkCommand &rhs) const { return !(*this == rhs); }
+
+public:
 	uint16_t Unit;         /// Command for unit
 	uint16_t X;            /// Map position X
 	uint16_t Y;            /// Map position Y
diff --git a/src/network/network.cpp b/src/network/network.cpp
index 2a1857b71..5bada2a58 100644
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -50,7 +50,7 @@
 ** broadcasting messages.
 **
 ** TCP, on the other hand, provides a connection-based, reliable data
-** stream.  TCP guarantees delivery of data and also guarantees that
+** stream. TCP guarantees delivery of data and also guarantees that
 ** packets will be delivered in the same order in which they were sent.
 **
 ** TCP is a simple and effective way of transmitting data. For making sure
@@ -90,8 +90,8 @@
 ** p2p has the advantage of a smaller lag, but needs a higher bandwidth
 ** by the clients.
 **
-** I have choosen p2p. Additional support for a server to client protocol
-** is welcome.
+** p2p has been choosen for in-game.
+** s/c for the preparing room.
 **
 ** @subsection bandwidth bandwidth
 **
@@ -103,7 +103,7 @@
 ** you just need to divide 28800 bits/second by 10 and end up with 2880
 ** bytes per second.
 **
-** We want to send many packets, more updated pro second and big packets,
+** We want to send many packets, more updated per second and big packets,
 ** less protocol overhead.
 **
 ** If we do an update 6 times per second, leaving approximately 480 bytes
@@ -113,18 +113,26 @@
 ** IP  Header 20 bytes
 ** UDP Header 8  bytes
 **
-** With 10 bytes per command and 4 commands this are 68 (20+8+4*10) bytes
-** pro packet.  Sending it to 7 other players, gives 476 bytes pro update.
-** This means we could do 6 updates (each 166ms) pro second.
+** With 9 bytes per command and N(=9) commands there are 20+8+1+9*N(=120) bytes
+** per packet. Sending it to 7 other players, gives 840 bytes per update.
+** This means we could do 6 updates (each 166ms) per second (6*840=5040 bytes/s).
 **
 ** @subsection a_packet Network packet
 **
 ** @li [IP  Header - 20 bytes]
 ** @li [UDP Header -  8 bytes]
-** @li [Type 1 byte][Cycle 1 byte][Data 8 bytes] - Slot 0
-** @li [Type 1 byte][Cycle 1 byte][Data 8 bytes] - Slot 1
-** @li [Type 1 byte][Cycle 1 byte][Data 8 bytes] - Slot 2
-** @li [Type 1 byte][Cycle 1 byte][Data 8 bytes] - Slot 3
+** @li [Header Data:Type - 1 byte]
+** if Type is one of the InitConfigMessage
+** @li [Header Data:SubType - 1 byte]
+** @li [Data - depend of subtype (may be 0 byte)]
+** if Type is Chat
+** [..]
+** if Type is Selection
+** [..]
+** else
+** @li [Header Data:Types - N-1 bytes] (for N commands)
+** @li [Header Data:Cycle - 1 byte]
+** @li [Data:Commands - 8 bytes * N]
 **
 ** @subsection internals Putting it together
 **
@@ -148,8 +156,7 @@
 ** @li The UDP protocol isn't good for firewalls, we need also support
 ** for the TCP protocol.
 **
-** @li Add a server / client protocol, which allows more players pro
-** game.
+** @li Add a server / client protocol, which allows more players per game.
 **
 ** @li Lag (latency) and bandwidth are set over the commandline. This
 ** should be automatic detected during game setup and later during
@@ -164,17 +171,13 @@
 ** @li Proxy and relays should be supported, to improve the playable
 ** over the internet.
 **
-** @li The game cycles is transfered for each slot, this is not needed. We
-** can save some bytes if we compress this.
-**
 ** @li We can sort the command by importants, currently all commands are
 ** send in order, only chat messages are send if there are free slots.
 **
 ** @li password protection the login process (optional), to prevent that
 ** the wrong player join an open network game.
 **
-** @li add meta server support, i have planned to use bnetd and its
-** protocol.
+** @li add meta server support, i have planned to use bnetd and its protocol.
 **
 ** @section api API How should it be used.
 **
@@ -248,9 +251,15 @@ public:
 	CNetworkCommandQueue() : Time(0), Type(0) {}
 	void Clear() { this->Time = this->Type = 0; Data.Clear(); }
 
-	unsigned long Time;     /// time to execute
-	unsigned char Type;     /// Command Type
-	CNetworkCommand Data;   /// command content
+	bool operator == (const CNetworkCommandQueue &rhs) const
+	{
+		return Time == rhs.Time && Type == rhs.Type && Data == rhs.Data;
+	}
+	bool operator != (const CNetworkCommandQueue &rhs) const { return !(*this == rhs); }
+public:
+	unsigned long Time;    /// time to execute
+	unsigned char Type;    /// Command Type
+	CNetworkCommand Data;  /// command content
 };
 
 
@@ -332,7 +341,7 @@ static void NetworkBroadcast(const CNetworkPacket &packet, int numcommands)
 **
 **  @param ncq  Outgoing network queue start.
 */
-static void NetworkSendPacket(const CNetworkCommandQueue ncq[])
+static void NetworkSendPacket(const CNetworkCommandQueue (&ncq)[MaxNetworkCommands])
 {
 	CNetworkPacket packet;
 
@@ -340,9 +349,7 @@ static void NetworkSendPacket(const CNetworkCommandQueue ncq[])
 	++NetworkSendPackets;
 #endif
 
-	//
 	// Build packet of up to MaxNetworkCommands messages.
-	//
 	int numcommands = 0;
 	packet.Header.Cycle = ncq[0].Time & 0xFF;
 	int i;
@@ -351,11 +358,9 @@ static void NetworkSendPacket(const CNetworkCommandQueue ncq[])
 		packet.Command[i] = ncq[i].Data;
 		++numcommands;
 	}
-
 	for (; i < MaxNetworkCommands; ++i) {
 		packet.Header.Type[i] = MessageNone;
 	}
-
 	NetworkBroadcast(packet, numcommands);
 }
 
@@ -368,6 +373,10 @@ static void NetworkSendPacket(const CNetworkCommandQueue ncq[])
 */
 void InitNetwork1()
 {
+	CommandsIn.clear();
+	MsgCommandsIn.clear();
+	NumNCQs = 0;
+
 	NetworkFildes.Close();
 	NetworkInSync = 1;
 
@@ -376,10 +385,7 @@ void InitNetwork1()
 	for (int i = 0; i < PlayerMax; ++i) {
 		NetMsgBufLen[i] = 0;
 	}
-
-	if (NetworkUpdates <= 0) {
-		NetworkUpdates = 1;
-	}
+	NetworkUpdates = std::max(NetworkUpdates, 1);
 	// Lag must be multiple of updates
 	NetworkLag = (NetworkLag / NetworkUpdates) * NetworkUpdates;
 
@@ -397,6 +403,16 @@ void InitNetwork1()
 		NetExit(); // machine dependent network exit
 		return;
 	}
+#ifdef DEBUG
+	{
+		char buf[128];
+
+		gethostname(buf, sizeof(buf));
+		DebugPrint("%s\n" _C_ buf);
+		const std::string hostStr = CHost(buf, port).toString();
+		DebugPrint("My host:port %s\n" _C_ hostStr.c_str());
+	}
+#endif
 
 #if 0 // FIXME: need a working interface check
 	unsigned long ips[10];
@@ -412,22 +428,6 @@ void InitNetwork1()
 		return;
 	}
 #endif
-
-#ifdef DEBUG
-	{
-		char buf[128];
-
-		gethostname(buf, sizeof(buf));
-		DebugPrint("%s\n" _C_ buf);
-		const std::string hostStr = CHost(buf, port).toString();
-		DebugPrint("My host:port %s\n" _C_ hostStr.c_str());
-	}
-#endif
-
-	CommandsIn.clear();
-	MsgCommandsIn.clear();
-
-	NumNCQs = 0;
 }
 
 /**
@@ -443,8 +443,7 @@ void ExitNetwork1()
 	DebugPrint("Received: %d packets, %d early, %d late, %d dups, %d lost.\n" _C_
 			   NetworkReceivedPackets _C_ NetworkReceivedEarly _C_ NetworkReceivedLate _C_
 			   NetworkReceivedDups _C_ NetworkReceivedLost);
-	DebugPrint("Send: %d packets, %d resend\n" _C_
-			   NetworkSendPackets _C_ NetworkSendResend);
+	DebugPrint("Send: %d packets, %d resend\n" _C_ NetworkSendPackets _C_ NetworkSendResend);
 #endif
 
 	NetworkFildes.Close();
@@ -464,12 +463,8 @@ void InitNetwork2()
 	for (int i = 0; i < HostsCount; ++i) {
 		Players[Hosts[i].PlyNr].SetName(Hosts[i].PlyName);
 	}
-
 	DebugPrint("Lag %d, Updates %d, Hosts %d\n" _C_ NetworkLag _C_ NetworkUpdates _C_ HostsCount);
-
-	//
 	// Prepare first time without syncs.
-	//
 	memset(NetworkIn, 0, sizeof(NetworkIn));
 	for (int i = 0; i <= NetworkLag; i += NetworkUpdates) {
 		for (int n = 0; n < HostsCount; ++n) {
@@ -479,7 +474,6 @@ void InitNetwork2()
 			}
 		}
 	}
-
 	memset(NetworkSyncSeeds, 0, sizeof(NetworkSyncSeeds));
 	memset(NetworkSyncHashs, 0, sizeof(NetworkSyncHashs));
 	memset(PlayerQuit, 0, sizeof(PlayerQuit));
@@ -535,44 +529,34 @@ static void FreeNCQ(CNetworkCommandQueue *ncq)
 void NetworkSendCommand(int command, const CUnit &unit, int x, int y,
 						const CUnit *dest, const CUnitType *type, int status)
 {
-	std::list<CNetworkCommandQueue *>::iterator it;
+	CNetworkCommandQueue ncq;
 
+	ncq.Time = GameCycle;
+	ncq.Type = command;
+	if (status) {
+		ncq.Type |= 0x80;
+	}
+	ncq.Data.Unit = htons(UnitNumber(unit));
+	ncq.Data.X = htons(x);
+	ncq.Data.Y = htons(y);
+	Assert(!dest || !type); // Both together isn't allowed
+	if (dest) {
+		ncq.Data.Dest = htons(UnitNumber(*dest));
+	} else if (type) {
+		ncq.Data.Dest = htons(type->Slot);
+	} else {
+		ncq.Data.Dest = htons(0xFFFF); // -1
+	}
 	// Check for duplicate command in queue
+	std::list<CNetworkCommandQueue *>::iterator it;
 	for (it = CommandsIn.begin(); it != CommandsIn.end(); ++it) {
-		CNetworkCommandQueue *ncq = *it;
-		if ((ncq->Type & 0x7F) == command
-			&& ncq->Data.Unit == htons(UnitNumber(unit))
-			&& ncq->Data.X == htons(x)
-			&& ncq->Data.Y == htons(y)) {
-			if (dest && ncq->Data.Dest == htons(UnitNumber(*dest))) {
-				return;
-			} else if (type && ncq->Data.Dest == htons(type->Slot)) {
-				return;
-			} else if (ncq->Data.Dest == 0xFFFF) {
-				return;
-			}
+		if (**it == ncq) {
+			return;
 		}
 	}
-
-	CNetworkCommandQueue *ncq = AllocNCQ();
-	CommandsIn.push_back(ncq);
-
-	ncq->Time = GameCycle;
-	ncq->Type = command;
-	if (status) {
-		ncq->Type |= 0x80;
-	}
-	ncq->Data.Unit = htons(UnitNumber(unit));
-	ncq->Data.X = htons(x);
-	ncq->Data.Y = htons(y);
-	Assert(!dest || !type);  // Both together isn't allowed
-	if (dest) {
-		ncq->Data.Dest = htons(UnitNumber(*dest));
-	} else if (type) {
-		ncq->Data.Dest = htons(type->Slot);
-	} else {
-		ncq->Data.Dest = htons(0xFFFF); // -1
-	}
+	CNetworkCommandQueue *pncq = AllocNCQ();
+	*pncq = ncq;
+	CommandsIn.push_back(pncq);
 }
 
 /**
@@ -627,8 +611,7 @@ void NetworkSendSelection(CUnit **units, int count)
 	if (!numteammates) {
 		return;
 	}
-
-	//  Build and send packets to cover all units.
+	// Build and send packets to cover all units.
 	CNetworkPacket packet;
 	int unitcount = 0;
 	while (unitcount < count) {
@@ -650,18 +633,15 @@ void NetworkSendSelection(CUnit **units, int count)
 				++nosent;
 			}
 		}
-
 		if (unitcount >= count) {
 			// This is the last command
 			header.NumberSent = nosent;
 		} else {
 			header.NumberSent = MaxNetworkCommands * 4;
 		}
-
 		for (; i < MaxNetworkCommands; ++i) {
 			packet.Header.Type[i] = MessageNone;
 		}
-
 		// Send the Constructed packet to team members
 		const int numcommands = (nosent + 3) / 4;
 		unsigned char *buf = new unsigned char [CNetworkPacket::Size(numcommands)];
@@ -723,6 +703,151 @@ static void NetworkRemovePlayer(int player)
 	}
 }
 
+static bool IsNetworkCommandReady(unsigned long gameCycle)
+{
+	// Check if all next messages are available.
+	const CNetworkCommandQueue (&ncqs)[PlayerMax][MaxNetworkCommands] = NetworkIn[gameCycle & 0xFF];
+	for (int i = 0; i < HostsCount; ++i) {
+		const CNetworkCommandQueue *ncq = ncqs[Hosts[i].PlyNr];
+
+		if (ncq[0].Time != gameCycle) {
+			return false;
+		}
+	}
+	return true;
+}
+
+static void NetworkParseInGameEvent(unsigned char *buf, int len, const CHost &host)
+{
+	CNetworkPacket packet;
+	int commands = packet.Deserialize(buf, len);
+	if (commands < 0) {
+		DebugPrint("Bad packet read\n");
+		return;
+	}
+	const int index = FindHostIndexBy(host);
+	if (index == -1 || PlayerQuit[Hosts[index].PlyNr]) {
+#ifdef DEBUG
+		const std::string hostStr = host.toString();
+		DebugPrint("Not a host in play: %s\n" _C_ hostStr.c_str());
+#endif
+		return;
+	}
+	const int player = Hosts[index].PlyNr;
+
+	// In a normal packet there is a least sync, selection may not have that
+	if (packet.Header.Type[0] == MessageSelection || commands == 0) {
+		NetworkProcessSelection(packet, player);
+		return;
+	}
+	// Parse the packet commands.
+	for (int i = 0; i != commands; ++i) {
+		const CNetworkCommand &nc = packet.Command[i];
+		bool validCommand = false;
+
+		// Handle some messages.
+		if (packet.Header.Type[i] == MessageQuit) {
+			const int playerNum = ntohs(nc.X);
+
+			if (playerNum >= 0 && playerNum < NumPlayers) {
+				PlayerQuit[playerNum] = 1;
+				validCommand = true;
+			}
+		}
+		if (packet.Header.Type[i] == MessageResend) {
+			// Destination cycle (time to execute).
+			unsigned long n = ((GameCycle + 128) & ~0xFF) | packet.Header.Cycle;
+			if (n > GameCycle + 128) {
+				n -= 0x100;
+			}
+			// FIXME: not necessary to send this packet multiple times!!!!
+			// other side sends re-send until it gets an answer.
+			if (n != NetworkIn[n & 0xFF][ThisPlayer->Index][0].Time) {
+				// Asking for a cycle we haven't gotten to yet, ignore for now
+				return;
+			}
+			NetworkSendPacket(NetworkIn[n & 0xFF][ThisPlayer->Index]);
+			// Check if a player quit this cycle
+			for (int j = 0; j < HostsCount; ++j) {
+				for (int c = 0; c < MaxNetworkCommands; ++c) {
+					const CNetworkCommandQueue *ncq;
+					ncq = &NetworkIn[n & 0xFF][Hosts[j].PlyNr][c];
+					if (ncq->Time && ncq->Type == MessageQuit) {
+						CNetworkPacket np;
+						np.Header.Cycle = ncq->Time & 0xFF;
+						np.Header.Type[0] = ncq->Type;
+						np.Command[0] = ncq->Data;
+						for (int k = 1; k < MaxNetworkCommands; ++k) {
+							np.Header.Type[k] = MessageNone;
+						}
+						NetworkBroadcast(np, 1);
+					}
+				}
+			}
+			return;
+		}
+		// Destination cycle (time to execute).
+		unsigned long n = ((GameCycle + 128) & ~0xFF) | packet.Header.Cycle;
+		if (n > GameCycle + 128) {
+			n -= 0x100;
+		}
+		// Receive statistic
+		NetworkLastFrame[player] = FrameCounter;
+
+		// Place in network in
+		switch (packet.Header.Type[i] & 0x7F) {
+			case MessageExtendedCommand:
+				// FIXME: ensure the sender is part of the command
+				validCommand = true;
+				break;
+			case MessageSync:
+				// Sync does not matter
+				validCommand = true;
+				break;
+			case MessageQuit:
+			case MessageQuitAck:
+			case MessageResend:
+			case MessageChat:
+			case MessageChatTerm:
+				// FIXME: ensure it's from the right player
+				validCommand = true;
+				break;
+			case MessageCommandDismiss: // Fall through!
+			default: {
+				const unsigned int slot = ntohs(nc.Unit);
+				const CUnit *unit = slot < UnitManager.GetUsedSlotCount() ? &UnitManager.GetSlotUnit(slot) : NULL;
+
+				if (unit && (unit->Player->Index == player
+							 || Players[player].IsTeamed(*unit))) {
+					validCommand = true;
+				} else {
+					validCommand = false;
+				}
+			}
+		}
+		// FIXME: not all values in nc have been validated
+		if (validCommand) {
+			NetworkIn[packet.Header.Cycle][player][i].Time = n;
+			NetworkIn[packet.Header.Cycle][player][i].Type = packet.Header.Type[i];
+			NetworkIn[packet.Header.Cycle][player][i].Data = nc;
+		} else {
+			SetMessage(_("%s sent bad command"), Players[player].Name.c_str());
+			DebugPrint("%s sent bad command: 0x%x\n" _C_ Players[player].Name.c_str()
+					   _C_ packet.Header.Type[i] & 0x7F);
+		}
+	}
+	for (int i = commands; i != MaxNetworkCommands; ++i) {
+		NetworkIn[packet.Header.Cycle][player][i].Time = 0;
+	}
+	// Waiting for this time slot
+	if (!NetworkInSync) {
+		unsigned long n = (GameCycle / NetworkUpdates) * NetworkUpdates + NetworkUpdates;
+		if (IsNetworkCommandReady(n) == true) {
+			NetworkInSync = 1;
+		}
+	}
+}
+
 /**
 **  Called if message for the network is ready.
 **  (by WaitEventsOneFrame)
@@ -747,163 +872,16 @@ void NetworkEvent()
 		NetworkInSync = 0;
 		return;
 	}
-
 #ifdef DEBUG
 	++NetworkReceivedPackets;
 #endif
-
 	// Setup messages
 	if (NetConnectRunning) {
 		if (NetworkParseSetupEvent(buf, len, host)) {
 			return;
 		}
 	}
-
-	CNetworkPacket packet;
-	int commands = packet.Deserialize(buf, len);
-	if (commands < 0) {
-		DebugPrint("Bad packet read\n");
-		return;
-	}
-
-	const int index = FindHostIndexBy(host);
-	if (index == -1 || PlayerQuit[Hosts[index].PlyNr]) {
-#ifdef DEBUG
-		const std::string hostStr = host.toString();
-		DebugPrint("Not a host in play: %s\n" _C_ hostStr.c_str());
-#endif
-		return;
-	}
-	const int player = Hosts[index].PlyNr;
-
-	// In a normal packet there is a least sync, selection may not have that
-	if (packet.Header.Type[0] == MessageSelection || commands == 0) {
-		NetworkProcessSelection(packet, player);
-		return;
-	}
-
-	// Parse the packet commands.
-	for (int i = 0; i != commands; ++i) {
-		const CNetworkCommand &nc = packet.Command[i];
-		bool validCommand = false;
-
-		// Handle some messages.
-		if (packet.Header.Type[i] == MessageQuit) {
-			int playerNum = ntohs(nc.X);
-
-			if (playerNum >= 0 && playerNum < NumPlayers) {
-				PlayerQuit[playerNum] = 1;
-				validCommand = true;
-			}
-		}
-
-		if (packet.Header.Type[i] == MessageResend) {
-			// Destination cycle (time to execute).
-			unsigned long n = ((GameCycle + 128) & ~0xFF) | packet.Header.Cycle;
-			if (n > GameCycle + 128) {
-				n -= 0x100;
-			}
-
-			// FIXME: not necessary to send this packet multiple times!!!!
-			// other side sends re-send until it gets an answer.
-
-			if (n != NetworkIn[n & 0xFF][ThisPlayer->Index][0].Time) {
-				// Asking for a cycle we haven't gotten to yet, ignore for now
-				return;
-			}
-
-			NetworkSendPacket(NetworkIn[n & 0xFF][ThisPlayer->Index]);
-
-			// Check if a player quit this cycle
-			for (int j = 0; j < HostsCount; ++j) {
-				for (int c = 0; c < MaxNetworkCommands; ++c) {
-					CNetworkCommandQueue *ncq;
-					ncq = &NetworkIn[n & 0xFF][Hosts[j].PlyNr][c];
-					if (ncq->Time && ncq->Type == MessageQuit) {
-						CNetworkPacket np;
-						np.Header.Cycle = ncq->Time & 0xFF;
-						np.Header.Type[0] = ncq->Type;
-						np.Command[0] = ncq->Data;
-						for (int k = 1; k < MaxNetworkCommands; ++k) {
-							np.Header.Type[k] = MessageNone;
-						}
-
-						NetworkBroadcast(np, 1);
-					}
-				}
-			}
-			return;
-		}
-
-		// Destination cycle (time to execute).
-		unsigned long n = ((GameCycle + 128) & ~0xFF) | packet.Header.Cycle;
-		if (n > GameCycle + 128) {
-			n -= 0x100;
-		}
-
-		// Receive statistic
-		NetworkLastFrame[player] = FrameCounter;
-
-		// Place in network in
-		switch (packet.Header.Type[i] & 0x7F) {
-			case MessageExtendedCommand:
-				// FIXME: ensure the sender is part of the command
-				validCommand = true;
-				break;
-			case MessageSync:
-				// Sync does not matter
-				validCommand = true;
-				break;
-			case MessageQuit:
-			case MessageQuitAck:
-			case MessageResend:
-			case MessageChat:
-			case MessageChatTerm:
-				// FIXME: ensure it's from the right player
-				validCommand = true;
-				break;
-			case MessageCommandDismiss:
-				// Fall through!
-			default: {
-				const unsigned int slot = ntohs(nc.Unit);
-				const CUnit *unit = slot < UnitManager.GetUsedSlotCount() ? &UnitManager.GetSlotUnit(slot) : NULL;
-
-				if (unit && (unit->Player->Index == player
-							 || Players[player].IsTeamed(*unit))) {
-					validCommand = true;
-				} else {
-					validCommand = false;
-				}
-			}
-		}
-
-		// FIXME: not all values in nc have been validated
-		if (validCommand) {
-			NetworkIn[packet.Header.Cycle][player][i].Time = n;
-			NetworkIn[packet.Header.Cycle][player][i].Type = packet.Header.Type[i];
-			NetworkIn[packet.Header.Cycle][player][i].Data = nc;
-		} else {
-			SetMessage(_("%s sent bad command"), Players[player].Name.c_str());
-			DebugPrint("%s sent bad command: 0x%x\n" _C_ Players[player].Name.c_str()
-					   _C_ packet.Header.Type[i] & 0x7F);
-		}
-	}
-
-	for (int i = commands; i != MaxNetworkCommands; ++i) {
-		NetworkIn[packet.Header.Cycle][player][i].Time = 0;
-	}
-
-	// Waiting for this time slot
-	if (!NetworkInSync) {
-		NetworkInSync = 1;
-		unsigned long n = (GameCycle / NetworkUpdates) * NetworkUpdates + NetworkUpdates;
-		for (int player = 0; player < HostsCount; ++player) {
-			if (NetworkIn[n & 0xFF][Hosts[player].PlyNr][0].Time != n) {
-				NetworkInSync = 0;
-				break;
-			}
-		}
-	}
+	NetworkParseInGameEvent(buf, len, host);
 }
 
 /**
@@ -914,16 +892,15 @@ void NetworkQuit()
 	if (!ThisPlayer) {
 		return;
 	}
-
-	int n = (GameCycle + NetworkUpdates) / NetworkUpdates * NetworkUpdates + NetworkLag;
-	NetworkIn[n & 0xFF][ThisPlayer->Index][0].Type = MessageQuit;
-	NetworkIn[n & 0xFF][ThisPlayer->Index][0].Time = n;
-	NetworkIn[n & 0xFF][ThisPlayer->Index][0].Data.X = ThisPlayer->Index;
-
+	const int n = (GameCycle + NetworkUpdates) / NetworkUpdates * NetworkUpdates + NetworkLag;
+	CNetworkCommandQueue (&ncqs)[MaxNetworkCommands] = NetworkIn[n & 0xFF][ThisPlayer->Index];
+	ncqs[0].Type = MessageQuit;
+	ncqs[0].Time = n;
+	ncqs[0].Data.X = ThisPlayer->Index;
 	for (int i = 1; i < MaxNetworkCommands; ++i) {
-		NetworkIn[n & 0xFF][ThisPlayer->Index][i].Type = MessageNone;
+		ncqs[i].Type = MessageNone;
 	}
-	NetworkSendPacket(NetworkIn[n & 0xFF][ThisPlayer->Index]);
+	NetworkSendPacket(ncqs);
 }
 
 /**
@@ -933,27 +910,28 @@ void NetworkQuit()
 */
 void NetworkChatMessage(const std::string &msg)
 {
-	if (IsNetworkGame()) {
-		const char *cp = msg.c_str();
-		size_t n = msg.size();
-		CNetworkChat *ncm = NULL;
-		while (n >= sizeof(ncm->Text)) {
-			CNetworkCommandQueue *ncq = AllocNCQ();
-			MsgCommandsIn.push_back(ncq);
-			ncq->Type = MessageChat;
-			ncm = (CNetworkChat *)(&ncq->Data);
-			ncm->Player = ThisPlayer->Index;
-			memcpy(ncm->Text, cp, sizeof(ncm->Text));
-			cp += sizeof(ncm->Text);
-			n -= sizeof(ncm->Text);
-		}
+	if (!IsNetworkGame()) {
+		return;
+	}
+	const char *cp = msg.c_str();
+	size_t n = msg.size();
+	CNetworkChat *ncm = NULL;
+	while (n >= sizeof(ncm->Text)) {
 		CNetworkCommandQueue *ncq = AllocNCQ();
 		MsgCommandsIn.push_back(ncq);
-		ncq->Type = MessageChatTerm;
+		ncq->Type = MessageChat;
 		ncm = (CNetworkChat *)(&ncq->Data);
 		ncm->Player = ThisPlayer->Index;
-		memcpy(ncm->Text, cp, n + 1); // see >= above :)
+		memcpy(ncm->Text, cp, sizeof(ncm->Text));
+		cp += sizeof(ncm->Text);
+		n -= sizeof(ncm->Text);
 	}
+	CNetworkCommandQueue *ncq = AllocNCQ();
+	MsgCommandsIn.push_back(ncq);
+	ncq->Type = MessageChatTerm;
+	ncm = (CNetworkChat *)(&ncq->Data);
+	ncm->Player = ThisPlayer->Index;
+	memcpy(ncm->Text, cp, n + 1); // see >= above :)
 }
 
 static void ParseNetworkCommand_Sync(const CNetworkCommandQueue &ncq)
@@ -964,7 +942,6 @@ static void ParseNetworkCommand_Sync(const CNetworkCommandQueue &ncq)
 	ply |= ntohs(ncq.Data.Y);
 	if (ply != NetworkSyncSeeds[GameCycle & 0xFF]
 		|| ntohs(ncq.Data.Unit) != NetworkSyncHashs[GameCycle & 0xFF]) {
-
 		SetMessage("%s", _("Network out of sync"));
 		DebugPrint("\nNetwork out of sync %x!=%x! %d!=%d! Cycle %lu\n\n" _C_
 				   ply _C_ NetworkSyncSeeds[GameCycle & 0xFF] _C_
@@ -975,7 +952,7 @@ static void ParseNetworkCommand_Sync(const CNetworkCommandQueue &ncq)
 static void ParseNetworkCommand_Chat(const CNetworkCommandQueue &ncq)
 {
 	const CNetworkChat &ncm = reinterpret_cast<const CNetworkChat &>(ncq.Data);
-	int ply = ncm.Player;
+	const int ply = ncm.Player;
 
 	if (NetMsgBufLen[ply] + sizeof(ncm.Text) < 128) {
 		memcpy(NetMsgBuf[ply] + NetMsgBufLen[ply], ncm.Text, sizeof(ncm.Text));
@@ -1025,102 +1002,79 @@ static void ParseNetworkCommand(const CNetworkCommandQueue &ncq)
 	}
 }
 
-/**
-**  Network resend commands, we have a missing packet send to all clients
-**  what packet we are missing.
-**
-**  @todo
-**  We need only send to the clients, that have not delivered the packet.
-*/
-static void NetworkResendCommands()
-{
-	CNetworkPacket packet;
-
-#ifdef DEBUG
-	++NetworkSendResend;
-#endif
-
-	// Build packet
-	packet.Header.Type[0] = MessageResend;
-	packet.Header.Type[1] = MessageNone;
-	packet.Header.Cycle =
-		(uint8_t)((GameCycle / NetworkUpdates) * NetworkUpdates + NetworkUpdates);
-
-	NetworkBroadcast(packet, 1);
-}
-
 /**
 **  Network send commands.
 */
-static void NetworkSendCommands()
+static void NetworkSendCommands(unsigned long gameCycle)
 {
 	// No command available, send sync.
 	int numcommands = 0;
-	CNetworkCommandQueue *incommand = NULL;
-	CNetworkCommandQueue *ncq = NetworkIn[(GameCycle + NetworkLag) & 0xFF][ThisPlayer->Index];
+	CNetworkCommandQueue (&ncq)[MaxNetworkCommands] = NetworkIn[gameCycle & 0xFF][ThisPlayer->Index];
 	ncq->Clear();
 	if (CommandsIn.empty() && MsgCommandsIn.empty()) {
 		ncq[0].Type = MessageSync;
 		ncq[0].Data.Unit = htons(SyncHash & 0xFFFF);
 		ncq[0].Data.X = htons(SyncRandSeed >> 16);
 		ncq[0].Data.Y = htons(SyncRandSeed & 0xFFFF);
-		ncq[0].Time = GameCycle + NetworkLag;
+		ncq[0].Time = gameCycle;
 		numcommands = 1;
 	} else {
-		while ((!CommandsIn.empty() || !MsgCommandsIn.empty()) && numcommands < MaxNetworkCommands) {
-			if (!CommandsIn.empty()) {
-				incommand = CommandsIn.front();
+		while (!CommandsIn.empty() && numcommands < MaxNetworkCommands) {
+			CNetworkCommandQueue *incommand = CommandsIn.front();
 #ifdef DEBUG
-				if (incommand->Type != MessageExtendedCommand) {
-					CUnit &unit = UnitManager.GetSlotUnit(ntohs(ncq->Data.Unit));
-					// FIXME: we can send destoyed units over network :(
-					if (unit.Destroyed) {
-						DebugPrint("Sending destroyed unit %d over network!!!!!!\n" _C_
-								   ntohs(incommand->Data.Unit));
-					}
+			if (incommand->Type != MessageExtendedCommand) {
+				CUnit &unit = UnitManager.GetSlotUnit(ntohs(ncq->Data.Unit));
+				// FIXME: we can send destoyed units over network :(
+				if (unit.Destroyed) {
+					DebugPrint("Sending destroyed unit %d over network!!!!!!\n" _C_
+							   ntohs(incommand->Data.Unit));
 				}
-#endif
-				CommandsIn.pop_front();
-			} else {
-				incommand = MsgCommandsIn.front();
-				MsgCommandsIn.pop_front();
 			}
+#endif
 			ncq[numcommands] = *incommand;
-			ncq[numcommands].Time = GameCycle + NetworkLag;
+			ncq[numcommands].Time = gameCycle;
+			++numcommands;
+			CommandsIn.pop_front();
+			FreeNCQ(incommand);
+		}
+		while (!MsgCommandsIn.empty() && numcommands < MaxNetworkCommands) {
+			CNetworkCommandQueue *incommand = MsgCommandsIn.front();
+			MsgCommandsIn.pop_front();
+			ncq[numcommands] = *incommand;
+			ncq[numcommands].Time = gameCycle;
 			++numcommands;
 			FreeNCQ(incommand);
 		}
 	}
-
 	if (numcommands != MaxNetworkCommands) {
 		ncq[numcommands].Type = MessageNone;
 	}
-
 	NetworkSendPacket(ncq);
 
-	NetworkSyncSeeds[(GameCycle + NetworkLag) & 0xFF] = SyncRandSeed;
-	NetworkSyncHashs[(GameCycle + NetworkLag) & 0xFF] = SyncHash & 0xFFFF; // FIXME: 32bit later
+	NetworkSyncSeeds[gameCycle & 0xFF] = SyncRandSeed;
+	NetworkSyncHashs[gameCycle & 0xFF] = SyncHash & 0xFFFF; // FIXME: 32bit later
 }
 
 /**
 **  Network excecute commands.
 */
-static void NetworkExecCommands()
+static void NetworkExecCommands(unsigned long gameCycle)
 {
 	// Must execute commands on all computers in the same order.
 	for (int i = 0; i < NumPlayers; ++i) {
 		// Remove commands.
+		const CNetworkCommandQueue *ncqs = NetworkIn[gameCycle & 0xFF][i];
 		for (int c = 0; c < MaxNetworkCommands; ++c) {
-			const CNetworkCommandQueue &ncq = NetworkIn[GameCycle & 0xFF][i][c];
+			const CNetworkCommandQueue &ncq = ncqs[c];
 			if (ncq.Type == MessageNone) {
 				break;
 			}
 			if (ncq.Time) {
 #ifdef DEBUG
-				if (ncq.Time != GameCycle) {
+				if (ncq.Time != gameCycle) {
 					DebugPrint("cycle %lu idx %lu time %lu\n" _C_
-							   GameCycle _C_ GameCycle & 0xFF _C_ ncq.Time);
-					Assert(ncq.Time == GameCycle);
+							   gameCycle _C_ gameCycle & 0xFF _C_ ncq.Time);
+					Assert(ncq.Time == gameCycle);
 				}
 #endif
 				ParseNetworkCommand(ncq);
@@ -1129,41 +1083,49 @@ static void NetworkExecCommands()
 	}
 }
 
-/**
-**  Network synchronize commands.
-*/
-static void NetworkSyncCommands()
-{
-	// Check if all next messages are available.
-	NetworkInSync = 1;
-	unsigned long n = GameCycle + NetworkUpdates;
-	for (int i = 0; i < HostsCount; ++i) {
-		const CNetworkCommandQueue *ncq = NetworkIn[n & 0xFF][Hosts[i].PlyNr];
-
-		if (ncq[0].Time != n) {
-			NetworkInSync = 0;
-			NetworkDelay = FrameCounter + NetworkUpdates;
-			// FIXME: should send a resend request.
-			break;
-		}
-	}
-}
-
 /**
 **  Handle network commands.
 */
 void NetworkCommands()
 {
-	if (IsNetworkGame()) {
-		if (!(GameCycle % NetworkUpdates)) {
-			// Send messages to all clients (other players)
-			NetworkSendCommands();
-			NetworkExecCommands();
-			NetworkSyncCommands();
-		}
+	if (!IsNetworkGame()) {
+		return;
+	}
+	if ((GameCycle % NetworkUpdates) != 0) {
+		return;
+	}
+	// Send messages to all clients (other players)
+	NetworkSendCommands(GameCycle + NetworkLag);
+	NetworkExecCommands(GameCycle);
+	if (IsNetworkCommandReady(GameCycle + NetworkUpdates) == false) {
+		NetworkInSync = 0;
+		NetworkDelay = FrameCounter + NetworkUpdates;
+		// FIXME: should send a resend request.
 	}
 }
 
+/**
+**  Network resend commands, we have a missing packet send to all clients
+**  what packet we are missing.
+**
+**  @todo
+**  We need only send to the clients, that have not delivered the packet.
+*/
+static void NetworkResendCommands()
+{
+#ifdef DEBUG
+	++NetworkSendResend;
+#endif
+
+	// Build packet
+	CNetworkPacket packet;
+	packet.Header.Type[0] = MessageResend;
+	packet.Header.Type[1] = MessageNone;
+	packet.Header.Cycle =
+		(uint8_t)((GameCycle / NetworkUpdates) * NetworkUpdates + NetworkUpdates);
+
+	NetworkBroadcast(packet, 1);
+}
 
 /**
 **  Recover network.
@@ -1174,50 +1136,53 @@ void NetworkRecover()
 		NetworkInSync = 1;
 		return;
 	}
+	if (FrameCounter <= NetworkDelay) {
+		return;
+	}
+	NetworkDelay += NetworkUpdates;
 
-	if (FrameCounter > NetworkDelay) {
-		NetworkDelay += NetworkUpdates;
-
-		// Check for players that timed out
-		for (int i = 0; i < HostsCount; ++i) {
-			if (!NetworkLastFrame[Hosts[i].PlyNr]) {
-				continue;
-			}
-			int secs = (FrameCounter - NetworkLastFrame[Hosts[i].PlyNr]) /
-					   (FRAMES_PER_SECOND * VideoSyncSpeed / 100);
-			// FIXME: display a menu while we wait
-			if (secs >= 3 && secs < NetworkTimeout) {
-				if (FrameCounter % FRAMES_PER_SECOND < (unsigned long)NetworkUpdates) {
-					SetMessage(_("Waiting for player \"%s\": %d:%02d"), Hosts[i].PlyName,
-							   (NetworkTimeout - secs) / 60, (NetworkTimeout - secs) % 60);
-				}
-			}
-			if (secs >= NetworkTimeout) {
-				CNetworkCommand nc;
-				CNetworkPacket np;
-
-				unsigned long n = GameCycle + NetworkUpdates;
-				nc.X = Hosts[i].PlyNr;
-				NetworkIn[n & 0xFF][Hosts[i].PlyNr][0].Time = n;
-				NetworkIn[n & 0xFF][Hosts[i].PlyNr][0].Type = MessageQuit;
-				NetworkIn[n & 0xFF][Hosts[i].PlyNr][0].Data = nc;
-				PlayerQuit[Hosts[i].PlyNr] = 1;
-				SetMessage("%s", _("Timed out"));
-
-				const CNetworkCommandQueue *ncq = &NetworkIn[n & 0xFF][Hosts[i].PlyNr][0];
-				np.Header.Cycle = ncq->Time & 0xFF;
-				np.Header.Type[0] = ncq->Type;
-				np.Header.Type[1] = MessageNone;
-
-				NetworkBroadcast(np, 1);
-
-				NetworkSyncCommands();
+	// Check for players that timed out
+	for (int i = 0; i < HostsCount; ++i) {
+		if (!NetworkLastFrame[Hosts[i].PlyNr]) {
+			continue;
+		}
+		int secs = (FrameCounter - NetworkLastFrame[Hosts[i].PlyNr]) /
+				   (FRAMES_PER_SECOND * VideoSyncSpeed / 100);
+		// FIXME: display a menu while we wait
+		if (secs >= 3 && secs < NetworkTimeout) {
+			if (FrameCounter % FRAMES_PER_SECOND < (unsigned long)NetworkUpdates) {
+				SetMessage(_("Waiting for player \"%s\": %d:%02d"), Hosts[i].PlyName,
+						   (NetworkTimeout - secs) / 60, (NetworkTimeout - secs) % 60);
 			}
 		}
+		if (secs >= NetworkTimeout) {
+			CNetworkCommand nc;
+			CNetworkPacket np;
 
-		// Resend old commands
-		NetworkResendCommands();
+			unsigned long n = GameCycle + NetworkUpdates;
+			nc.X = Hosts[i].PlyNr;
+			NetworkIn[n & 0xFF][Hosts[i].PlyNr][0].Time = n;
+			NetworkIn[n & 0xFF][Hosts[i].PlyNr][0].Type = MessageQuit;
+			NetworkIn[n & 0xFF][Hosts[i].PlyNr][0].Data = nc;
+			PlayerQuit[Hosts[i].PlyNr] = 1;
+			SetMessage("%s", _("Timed out"));
+
+			const CNetworkCommandQueue *ncq = &NetworkIn[n & 0xFF][Hosts[i].PlyNr][0];
+			np.Header.Cycle = ncq->Time & 0xFF;
+			np.Header.Type[0] = ncq->Type;
+			np.Header.Type[1] = MessageNone;
+
+			NetworkBroadcast(np, 1);
+
+			if (IsNetworkCommandReady(GameCycle + NetworkUpdates) == false) {
+				NetworkInSync = 0;
+				NetworkDelay = FrameCounter + NetworkUpdates;
+				// FIXME: should send a resend request.
+			}
+		}
 	}
+	// Resend old commands
+	NetworkResendCommands();
 }
 
 //@}