diff -r 8f7e778b0843 src/sv_main.cpp
--- a/src/sv_main.cpp	Mon Aug 05 20:53:11 2013 +0200
+++ b/src/sv_main.cpp	Mon Aug 05 21:42:25 2013 +0200
@@ -157,6 +157,7 @@
 static	bool	server_Puke( BYTESTREAM_s *pByteStream );
 static	bool	server_MorphCheat( BYTESTREAM_s *pByteStream );
 static	bool	server_CheckForClientMinorCommandFlood( ULONG ulClient );
+static	bool	server_ProcessMoveCommand( CLIENT_MOVE_COMMAND_s &ClientMoveCmd, const ULONG ulClient );
 
 // [RC]
 #ifdef CREATE_PACKET_LOG
@@ -559,6 +560,19 @@
 		// Recieve packets.
 		SERVER_GetPackets( );
 
+		// [BB] Process up to two movement commands for each client.
+		for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ )
+		{
+			if ( SERVER_IsValidClient( ulIdx ) == false )
+				continue;
+
+			for ( int i = 0; i < min ( g_aClients[ulIdx].MoveCMDs.Size(), 2 ); ++i )
+			{
+				server_ProcessMoveCommand( g_aClients[ulIdx].MoveCMDs[0], ulIdx );
+				g_aClients[ulIdx].MoveCMDs.Delete( 0 );
+			}
+		}
+
 		G_Ticker ();
 
 		// Update the scoreboard if we have a new second to display.
@@ -4535,25 +4549,14 @@
 //
 static bool server_ClientMove( BYTESTREAM_s *pByteStream )
 {
-	player_t		*pPlayer;
-	ticcmd_t		*pCmd;
-	angle_t			Angle;
-	angle_t			Pitch;
-	ULONG			ulGametic;
-	ULONG			ulBits;
-	USHORT			usActorNetworkIndex;
-	const PClass	*pType;
-	AInventory		*pInventory;
-//	ULONG			ulIdx;
-
-	pPlayer = &players[g_lCurrentClient];
-	pCmd = &pPlayer->cmd;
+	CLIENT_MOVE_COMMAND_s clientMoveCmd;
+	ticcmd_t *pCmd = &clientMoveCmd.cmd;
 
 	// Read in the client's gametic.
-	ulGametic = NETWORK_ReadLong( pByteStream );
+	clientMoveCmd.ulGametic = NETWORK_ReadLong( pByteStream );
 
 	// Read in the information the client is sending us.
-	ulBits = NETWORK_ReadByte( pByteStream );
+	const ULONG ulBits = NETWORK_ReadByte( pByteStream );
 
 	if ( ulBits & CLIENT_UPDATE_YAW )
 		pCmd->ucmd.yaw = NETWORK_ReadShort( pByteStream );
@@ -4591,8 +4594,8 @@
 		pCmd->ucmd.upmove = 0;
 
 	// Always read in the angle and pitch.
-	Angle = NETWORK_ReadLong( pByteStream );
-	Pitch = NETWORK_ReadLong( pByteStream );
+	clientMoveCmd.angle = NETWORK_ReadLong( pByteStream );
+	clientMoveCmd.pitch = NETWORK_ReadLong( pByteStream );
 
 	// [BB] Extra scope to create a local variable.
 	{
@@ -4612,15 +4615,35 @@
 		}
 #endif
 	}
-
 	// If the client is attacking, he always sends the name of the weapon he's using.
 	if ( pCmd->ucmd.buttons & BT_ATTACK )
-	{
-		usActorNetworkIndex = NETWORK_ReadShort( pByteStream );
+		clientMoveCmd.usWeaponNetworkIndex = NETWORK_ReadShort( pByteStream );
+	else
+		clientMoveCmd.usWeaponNetworkIndex = 0;
+
+	// Don't timeout.
+	g_aClients[g_lCurrentClient].ulLastCommandTic = gametic;
+
+	g_aClients[g_lCurrentClient].MoveCMDs.Push ( clientMoveCmd );
+
+	return false;
+}
+
+static bool server_ProcessMoveCommand( CLIENT_MOVE_COMMAND_s &ClientMoveCmd, const ULONG ulClient )
+{
+	player_t *pPlayer = &players[ulClient];
+	ticcmd_t *pCmd = &pPlayer->cmd;
+	memcpy( pCmd, &ClientMoveCmd.cmd, sizeof( ticcmd_t ));
+
+	g_aClients[ulClient].ulClientGameTic = ClientMoveCmd.ulGametic;
+
+	// If the client is attacking, he always sends the name of the weapon he's using.
+	if ( pCmd->ucmd.buttons & BT_ATTACK )
+	{
 		// If the name of the weapon the client is using doesn't match the name of the
 		// weapon we think he's using, do something to rectify the situation.
 		// [BB] Only do this if the client is fully spawned and authenticated.
-		if ( ( SERVER_GetClient( g_lCurrentClient )->State == CLS_SPAWNED ) && ( ( pPlayer->ReadyWeapon == NULL ) || ( pPlayer->ReadyWeapon->GetClass( )->getActorNetworkIndex() != usActorNetworkIndex ) ) )
+		if ( ( SERVER_GetClient( ulClient )->State == CLS_SPAWNED ) && ( ( pPlayer->ReadyWeapon == NULL ) || ( pPlayer->ReadyWeapon->GetClass( )->getActorNetworkIndex() != ClientMoveCmd.usWeaponNetworkIndex ) ) )
 		{
 			// [BB] Directly after a map change this workaround seems to do more harm than good,
 			// (client and server are possibly changing weapons and one of them is slightly ahead)
@@ -4628,14 +4651,14 @@
 			// on the clients after a map change most likely has to do with this slight sync issues.
 			// [BB] Do this anyway if the server thinks that the player doesn't have any weapon.
 			if ( ( level.maptime > 3*TICRATE )
-				|| ( ( SERVER_GetClient( g_lCurrentClient )->State == CLS_SPAWNED ) && ( pPlayer->ReadyWeapon == NULL ) && ( pPlayer->PendingWeapon == WP_NOCHANGE ) ) )
+				|| ( ( SERVER_GetClient( ulClient )->State == CLS_SPAWNED ) && ( pPlayer->ReadyWeapon == NULL ) && ( pPlayer->PendingWeapon == WP_NOCHANGE ) ) )
 			{
-				pType = NETWORK_GetClassFromIdentification( usActorNetworkIndex );
+				const PClass *pType = NETWORK_GetClassFromIdentification( ClientMoveCmd.usWeaponNetworkIndex );
 				if (( pType ) && ( pType->IsDescendantOf( RUNTIME_CLASS( AWeapon ))))
 				{
 					if ( pPlayer->mo )
 					{
-						pInventory = pPlayer->mo->FindInventory( pType );
+						AInventory *pInventory = pPlayer->mo->FindInventory( pType );
 						if ( pInventory )
 						{
 							pPlayer->PendingWeapon = static_cast<AWeapon *>( pInventory );
@@ -4644,27 +4667,27 @@
 							pPlayer->bClientSelectedWeapon = true;
 
 							// Update other spectators with this info.
-							SERVERCOMMANDS_SetPlayerPendingWeapon( g_lCurrentClient, g_lCurrentClient, SVCF_SKIPTHISCLIENT );
+							SERVERCOMMANDS_SetPlayerPendingWeapon( ulClient, ulClient, SVCF_SKIPTHISCLIENT );
 						}
 //						else if ( g_ulWeaponCheckGracePeriodTicks == 0 )
 //						{
-//							SERVER_KickPlayer( g_lCurrentClient, "Using unowned weapon." );
+//							SERVER_KickPlayer( ulClient, "Using unowned weapon." );
 //							return ( true );
 //						}
 					}
 				}
 				else
 				{
-					if( usActorNetworkIndex == 0 )
+					if( ClientMoveCmd.usWeaponNetworkIndex == 0 )
 					{
 						// [BB] For some reason the clients think he as no ready weapon, 
 						// but the server thinks he as one. Although this should not happen,
 						// we make a workaround for this here. Just tell the client to bring
 						// up the weapon, the server thinks he is using.
-						SERVERCOMMANDS_WeaponChange( g_lCurrentClient, g_lCurrentClient, SVCF_ONLYTHISCLIENT );
+						SERVERCOMMANDS_WeaponChange( ulClient, ulClient, SVCF_ONLYTHISCLIENT );
 					}
 					else{
-						SERVER_KickPlayer( g_lCurrentClient, "Using unknown weapon type." );
+						SERVER_KickPlayer( ulClient, "Using unknown weapon type." );
 						return ( true );
 					}
 				}
@@ -4672,15 +4695,11 @@
 		}
 	}
 
-	// Don't timeout.
-	g_aClients[g_lCurrentClient].ulLastCommandTic = gametic;
-	g_aClients[g_lCurrentClient].ulClientGameTic = ulGametic;
-
 	// [BB] Instead of kicking players that send too many movement commands, we just ignroe the excessive commands.
 	// Note: The kick code is still there, but isn't triggered anymore since we are reducing lOverMovementLevel here.
-	if ( g_aClients[g_lCurrentClient].lOverMovementLevel >= ( MAX_OVERMOVEMENT_LEVEL - 1 ) )
-	{
-		g_aClients[g_lCurrentClient].lOverMovementLevel--;
+	if ( g_aClients[ulClient].lOverMovementLevel >= ( MAX_OVERMOVEMENT_LEVEL - 1 ) )
+	{
+		g_aClients[ulClient].lOverMovementLevel--;
 		return false;
 	}
 
@@ -4690,9 +4709,9 @@
 		{
 			// [BB] Ignore the angle and pitch sent by the client if the client isn't authenticated yet.
 			// In this case the client still sends these values based on the previous map.
-			if ( SERVER_GetClient( g_lCurrentClient )->State == CLS_SPAWNED ) {
-				pPlayer->mo->angle = Angle;
-				pPlayer->mo->pitch = Pitch;
+			if ( SERVER_GetClient( ulClient )->State == CLS_SPAWNED ) {
+				pPlayer->mo->angle = ClientMoveCmd.angle;
+				pPlayer->mo->pitch = ClientMoveCmd.pitch;
 			}
 
 			// Makes sure the pitch is valid (should we kick them if it's not?)
@@ -4702,8 +4721,14 @@
 				pPlayer->mo->pitch = ( ANGLE_1 * 90 );
 
 			P_PlayerThink( pPlayer );
+
+			// [BB] The server blocks AActor::Tick() for non-bot player actors unless the player
+			// is the "current client". So we have to work around this.
+			const LONG savedCurrentClient = g_lCurrentClient;
+			g_lCurrentClient = ulClient;
 			if ( pPlayer->mo )
 				pPlayer->mo->Tick( );
+			g_lCurrentClient = savedCurrentClient;
 
 			// [BB] We possibly process more than one move of this client per tic,
 			// so we have to update oldbuttons (otherwise a door that just started to
@@ -4723,17 +4748,17 @@
 		( pCmd->ucmd.upmove != 0 ))
 	{
 		// [K6/BB] The client is pressing a button, so not afk.
-		g_aClients[g_lCurrentClient].lLastActionTic = gametic;
+		g_aClients[ulClient].lLastActionTic = gametic;
 		if ( pPlayer->bChatting )
 		{
 			pPlayer->bChatting = false;
-			SERVERCOMMANDS_SetPlayerChatStatus( g_lCurrentClient );
+			SERVERCOMMANDS_SetPlayerChatStatus( ulClient );
 		}
 
 		if ( pPlayer->bInConsole )
 		{
 			pPlayer->bInConsole = false;
-			SERVERCOMMANDS_SetPlayerConsoleStatus( g_lCurrentClient );
+			SERVERCOMMANDS_SetPlayerConsoleStatus( ulClient );
 		}
 	}
 
diff -r 8f7e778b0843 src/sv_main.h
--- a/src/sv_main.h	Mon Aug 05 20:53:11 2013 +0200
+++ b/src/sv_main.h	Mon Aug 05 21:42:25 2013 +0200
@@ -176,6 +176,16 @@
 //*****************************************************************************
 typedef struct
 {
+	ticcmd_t		cmd;
+	angle_t			angle;
+	angle_t			pitch;
+	USHORT			usWeaponNetworkIndex;
+	ULONG				ulGametic;
+} CLIENT_MOVE_COMMAND_s;
+
+//*****************************************************************************
+typedef struct
+{
 	// The network address of this client.
 	NETADDRESS_s	Address;
 
@@ -290,6 +300,9 @@
 	// [K6] Last tic we got some action from the client. Used to determine his presence.
 	LONG			lLastActionTic;
 
+	// [BB] Buffer storing all movement commands received from the client we haven't executed yet.
+	TArray<CLIENT_MOVE_COMMAND_s>	MoveCMDs;
+
 } CLIENT_s;
 
 //*****************************************************************************
