From 3bd2ba9e590cb882b684b1eb4b2650b1a4c94f7f Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Tue, 12 Jul 2011 11:01:20 +0000 Subject: - Greatly improve UDP downloading speed for clients - Add download rate control cvar sv_dlRate - Don't send snapshots to downloading clients --- src/qcommon/common.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/qcommon/qcommon.h | 6 +++-- 2 files changed, 68 insertions(+), 4 deletions(-) (limited to 'src/qcommon') diff --git a/src/qcommon/common.c b/src/qcommon/common.c index 4a0e48ad..c9f9816d 100644 --- a/src/qcommon/common.c +++ b/src/qcommon/common.c @@ -77,6 +77,7 @@ cvar_t *cl_paused; cvar_t *sv_paused; cvar_t *cl_packetdelay; cvar_t *sv_packetdelay; +cvar_t *sv_dlRate; cvar_t *com_cameraMode; cvar_t *com_ansiColor; cvar_t *com_unfocused; @@ -2649,6 +2650,7 @@ void Com_Init( char *commandLine ) { sv_paused = Cvar_Get ("sv_paused", "0", CVAR_ROM); cl_packetdelay = Cvar_Get ("cl_packetdelay", "0", CVAR_CHEAT); sv_packetdelay = Cvar_Get ("sv_packetdelay", "0", CVAR_CHEAT); + sv_dlRate = Cvar_Get ("sv_dlRate", "1000", CVAR_ARCHIVE); com_sv_running = Cvar_Get ("sv_running", "0", CVAR_ROM); com_cl_running = Cvar_Get ("cl_running", "0", CVAR_ROM); com_buildScript = Cvar_Get( "com_buildScript", "0", 0 ); @@ -2873,6 +2875,9 @@ void Com_Frame( void ) { int msec, minMsec; int timeVal; + int numBlocks = 1; + int dlStart, deltaT, delayT; + static int dlNextRound = 0; static int lastTime = 0, bias = 0; int timeBeforeFirstEvents; @@ -2933,13 +2938,70 @@ void Com_Frame( void ) { minMsec = 1; timeVal = 0; + do { // Busy sleep the last millisecond for better timeout precision - if(com_busyWait->integer || timeVal < 2) + if(timeVal < 2) NET_Sleep(0); else - NET_Sleep(timeVal - 1); + { + if(com_sv_running->integer) + { + // Send out download messages now that we're idle + if(sv_dlRate->integer) + { + // Rate limiting. This is very imprecise for high + // download rates due to millisecond timedelta resolution + dlStart = Sys_Milliseconds(); + deltaT = dlNextRound - dlStart; + + if(deltaT > 0) + { + if(deltaT < timeVal) + timeVal = deltaT + 1; + } + else + { + numBlocks = SV_SendDownloadMessages(); + + if(numBlocks) + { + // There are active downloads + deltaT = Sys_Milliseconds() - dlStart; + + delayT = 1000 * numBlocks * MAX_DOWNLOAD_BLKSIZE; + delayT /= sv_dlRate->integer * 1024; + + if(delayT <= deltaT + 1) + { + // Sending the last round of download messages + // took too long for given rate, don't wait for + // next round, but always enforce a 1ms delay + // between DL message rounds so we don't hog + // all of the bandwidth. This will result in an + // effective maximum rate of 1MB/s per user, but the + // low download window size limits this anyways. + timeVal = 2; + dlNextRound = dlStart + deltaT + 1; + } + else + { + dlNextRound = dlStart + delayT; + timeVal = delayT - deltaT; + } + } + } + } + else + SV_SendDownloadMessages(); + } + + if(com_busyWait->integer) + NET_Sleep(0); + else + NET_Sleep(timeVal - 1); + } msec = Sys_Milliseconds() - com_frameTime; diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index 8a7dbe7f..165dccae 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -190,8 +190,9 @@ void NET_Sleep(int msec); #define MAX_MSGLEN 16384 // max length of a message, which may // be fragmented into multiple packets -#define MAX_DOWNLOAD_WINDOW 8 // max of eight download frames -#define MAX_DOWNLOAD_BLKSIZE 2048 // 2048 byte block chunks +#define MAX_DOWNLOAD_WINDOW 48 // ACK window of 48 download chunks. Cannot set this higher, or clients + // will overflow the reliable commands buffer +#define MAX_DOWNLOAD_BLKSIZE 1024 // 896 byte block chunks /* @@ -1008,6 +1009,7 @@ void SV_Frame( int msec ); void SV_PacketEvent( netadr_t from, msg_t *msg ); int SV_FrameMsec(void); qboolean SV_GameCommand( void ); +int SV_SendDownloadMessages(void); // -- cgit