[Server] Faster download

[Server] Faster download

diff --git a/src/engine/API/serverClient_api.hpp b/src/engine/API/serverClient_api.hpp
index 051ce73..9e284d7 100644
--- a/src/engine/API/serverClient_api.hpp
+++ b/src/engine/API/serverClient_api.hpp
@@ -47,6 +47,8 @@ public:
     virtual void DirectConnect( netadr_t from ) = 0;
     virtual void ExecuteClientMessage( client_t* cl, msg_t* msg ) = 0;
     virtual void AuthorizeIpPacket( netadr_t from ) = 0;
+    virtual sint SendQueuedMessages( void ) = 0;
+    virtual sint SendDownloadMessages( void ) = 0;
 };
 
 extern idServerClientSystem* serverClientSystem;
diff --git a/src/engine/API/serverMain_api.hpp b/src/engine/API/serverMain_api.hpp
index 4664526..d8c9720 100644
--- a/src/engine/API/serverMain_api.hpp
+++ b/src/engine/API/serverMain_api.hpp
@@ -58,6 +58,8 @@ public:
     virtual void PacketEvent( netadr_t from, msg_t* msg ) = 0;
     virtual void Frame( sint msec ) = 0;
     virtual sint LoadTag( pointer mod_name ) = 0;
+    virtual sint RateMsec( client_t* client ) = 0;
+    virtual sint SendQueuedPackets( void ) = 0;
 };
 
 extern idServerMainSystem* serverMainSystem;
diff --git a/src/engine/framework/NetworkChain.cpp b/src/engine/framework/NetworkChain.cpp
index 360e003..5979709 100644
--- a/src/engine/framework/NetworkChain.cpp
+++ b/src/engine/framework/NetworkChain.cpp
@@ -246,7 +246,6 @@ void idNetworkChainSystemLocal::Transmit( netchan_t* chan, sint length, const uc
     chan->lastSentTime = idsystem->Milliseconds();
     chan->lastSentSize = send.cursize;
     
-    
     if( showpackets->integer )
     {
         Com_Printf( "%s send %4i : s=%i ack=%i\n"
diff --git a/src/engine/server/server.hpp b/src/engine/server/server.hpp
index 3fcae9c..2b5ee7c 100644
--- a/src/engine/server/server.hpp
+++ b/src/engine/server/server.hpp
@@ -548,6 +548,7 @@ extern convar_t*  sv_mapname;
 extern convar_t*  sv_mapChecksum;
 extern convar_t*  sv_serverid;
 extern convar_t*  sv_maxRate;
+extern convar_t* sv_dlRate;
 extern convar_t*  sv_minPing;
 extern convar_t*  sv_maxPing;
 
diff --git a/src/engine/server/serverClient.cpp b/src/engine/server/serverClient.cpp
index 802fefb..4be3661 100644
--- a/src/engine/server/serverClient.cpp
+++ b/src/engine/server/serverClient.cpp
@@ -1558,10 +1558,7 @@ void idServerClientSystemLocal::WriteDownloadToClient( client_t* cl, msg_t* msg 
         if( cl->downloadXmitBlock == cl->downloadCurrentBlock )
         {
             // We have transmitted the complete window, should we start resending?
-            
-            //FIXME:  This uses a hardcoded one second timeout for lost blocks
-            //the timeout should be based on client rate somehow
-            if( svs.time - cl->downloadSendTime > 1000 )
+            if( svs.time - cl->downloadSendTime > MAX_DOWNLOAD_BLKSIZE * 1000 / rate )
             {
                 cl->downloadXmitBlock = cl->downloadClientBlock;
             }
@@ -1602,6 +1599,84 @@ void idServerClientSystemLocal::WriteDownloadToClient( client_t* cl, msg_t* msg 
 }
 
 /*
+==================
+idServerClientSystemLocal::SendQueuedMessages
+
+Send one round of fragments, or queued messages to all clients that have data pending.
+Return the shortest time interval for sending next packet to client
+==================
+*/
+sint idServerClientSystemLocal::SendQueuedMessages( void )
+{
+    sint i, retVal = -1, nextFragTime;
+    client_t* cl;
+    
+    for( i = 0; i < sv_maxclients->integer; i++ )
+    {
+        cl = &svs.clients[i];
+        
+        if( cl->state && cl->netchan.unsentFragments )
+        {
+            nextFragTime = serverMainSystem->RateMsec( cl );
+            
+            if( !nextFragTime )
+            {
+                networkChainSystem->TransmitNextFragment( &cl->netchan );
+                nextFragTime = serverMainSystem->RateMsec( cl );
+            }
+            
+            if( nextFragTime >= 0 && ( retVal == -1 || retVal > nextFragTime ) )
+            {
+                retVal = nextFragTime;
+            }
+        }
+    }
+    
+    return retVal;
+}
+
+
+/*
+==================
+idServerClientSystemLocal::SendDownloadMessages
+
+Send one round of download messages to all clients
+==================
+*/
+sint idServerClientSystemLocal::SendDownloadMessages( void )
+{
+    sint i, numDownloads = 0;
+    client_t* client;
+    msg_t message;
+    uchar8 messageBuffer[MAX_MSGLEN];
+    
+    for( i = 0; i < sv_maxclients->integer; i++ )
+    {
+        client = &svs.clients[i];
+        
+        if( client->state && *client->downloadName )
+        {
+            sint basesize;
+            
+            MSG_Init( &message, messageBuffer, sizeof( messageBuffer ) );
+            MSG_WriteLong( &message, client->lastClientCommand );
+            
+            basesize = message.cursize;
+            serverClientLocal.WriteDownloadToClient( client, &message );
+            
+            if( message.cursize != basesize )
+            {
+                serverSnapshotSystem->SendMessageToClient( &message, client );
+                numDownloads++;
+            }
+        }
+    }
+    
+    return numDownloads;
+}
+
+
+/*
 =================
 idServerClientSystemLocal::Disconnect_f
 
@@ -1613,9 +1688,12 @@ void idServerClientSystemLocal::Disconnect_f( client_t* cl )
     if( cmdSystem->Argc() > 1 )
     {
         valueType reason[MAX_STRING_CHARS] = { 0 };
+        
         Q_strncpyz( reason, cmdSystem->Argv( 1 ), sizeof( reason ) );
         Q_strstrip( reason, "\r\n;\"", nullptr );
+        
         serverClientLocal.DropClient( cl, "disconnected" );
+        
         ( cl, va( "disconnected: %s", reason ) );
     }
     else
diff --git a/src/engine/server/serverClient.hpp b/src/engine/server/serverClient.hpp
index cfe84f3..303e67f 100644
--- a/src/engine/server/serverClient.hpp
+++ b/src/engine/server/serverClient.hpp
@@ -58,6 +58,8 @@ public:
     virtual void DirectConnect( netadr_t from );
     virtual void ExecuteClientMessage( client_t* cl, msg_t* msg );
     virtual void AuthorizeIpPacket( netadr_t from );
+    virtual sint SendQueuedMessages( void );
+    virtual sint SendDownloadMessages( void );
     
 public:
     static valueType* isClientBanned( valueType* ip, valueType* password );
diff --git a/src/engine/server/serverInit.cpp b/src/engine/server/serverInit.cpp
index 0875893..9bba6f0 100644
--- a/src/engine/server/serverInit.cpp
+++ b/src/engine/server/serverInit.cpp
@@ -1069,6 +1069,7 @@ void idServerInitSystemLocal::Init( void )
     sv_maxRate = cvarSystem->Get( "sv_maxRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, "Option to force all clients to play with a max rate. This can be used to limit the advantage of low pings, or to cap bandwidth utilization for a server. Note that rate is ignored for clients that are on the same LAN." );
     sv_minPing = cvarSystem->Get( "sv_minPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, "Set the minimum ping aloud on the server to keep low pings out" );
     sv_maxPing = cvarSystem->Get( "sv_maxPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, "Set the maximum ping allowed on the server to keep high pings out" );
+    sv_dlRate = cvarSystem->Get( "sv_dlRate", "100", CVAR_ARCHIVE | CVAR_SERVERINFO, "Bandwidth allotted to PK3 file downloads via UDP, in kbyte / s" );
     sv_floodProtect = cvarSystem->Get( "sv_floodProtect", "1", CVAR_ARCHIVE | CVAR_SERVERINFO, "Whether or not to use flood protection, preventing clients from sending numerous consecutive commands to the server." );
     sv_allowAnonymous = cvarSystem->Get( "sv_allowAnonymous", "0", CVAR_SERVERINFO, "Allow anonymous connections in the server" );
     sv_friendlyFire = cvarSystem->Get( "g_friendlyFire", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, "Toggles wether players can damage their teammates" );	// NERVE - SMF
diff --git a/src/engine/server/serverMain.cpp b/src/engine/server/serverMain.cpp
index ea6adb6..8ef19dc 100644
--- a/src/engine/server/serverMain.cpp
+++ b/src/engine/server/serverMain.cpp
@@ -75,6 +75,7 @@ convar_t* sv_serverid;

[... diff too long, it was truncated ...]

GitHub
sha: ce552356