IOQ3 commit 2073

This commit is contained in:
Richard Allen 2011-07-18 15:59:55 +00:00
parent 52151b3d1a
commit d08fd5549d
6 changed files with 150 additions and 78 deletions

View file

@ -170,6 +170,8 @@ New cvars
backend backend
s_muteWhenMinimized - mute sound when minimized s_muteWhenMinimized - mute sound when minimized
s_muteWhenUnfocused - mute sound when window is unfocused s_muteWhenUnfocused - mute sound when window is unfocused
sv_dlRate - bandwidth allotted to PK3 file downloads
via UDP, in kbyte/s
com_ansiColor - enable use of ANSI escape codes in the tty com_ansiColor - enable use of ANSI escape codes in the tty
com_altivec - enable use of altivec on PowerPC systems com_altivec - enable use of altivec on PowerPC systems
@ -498,6 +500,11 @@ Using HTTP/FTP Download Support (Server)
that ioquake3 sets which is "ioQ3://{SERVER_IP}:{SERVER_PORT}". For, that ioquake3 sets which is "ioQ3://{SERVER_IP}:{SERVER_PORT}". For,
example, Apache's mod_rewrite can restrict access based on HTTP_REFERER. example, Apache's mod_rewrite can restrict access based on HTTP_REFERER.
On a sidenote, downloading via UDP has been improved and yields higher data
rates now. You can configure the maximum bandwidth for UDP downloads via the
cvar sv_dlRate. Due to system-specific limits the download rate is capped
at about 1 Mbyte/s per client, so curl downloading may still be faster.
Using HTTP/FTP Download Support (Client) Using HTTP/FTP Download Support (Client)
Simply setting cl_allowDownload to 1 will enable HTTP/FTP downloads Simply setting cl_allowDownload to 1 will enable HTTP/FTP downloads
assuming ioquake3 was compiled with USE_CURL=1 (the default). assuming ioquake3 was compiled with USE_CURL=1 (the default).

View file

@ -77,6 +77,7 @@ cvar_t *cl_paused;
cvar_t *sv_paused; cvar_t *sv_paused;
cvar_t *cl_packetdelay; cvar_t *cl_packetdelay;
cvar_t *sv_packetdelay; cvar_t *sv_packetdelay;
cvar_t *sv_dlRate;
cvar_t *com_cameraMode; cvar_t *com_cameraMode;
cvar_t *com_ansiColor; cvar_t *com_ansiColor;
cvar_t *com_unfocused; cvar_t *com_unfocused;
@ -2777,6 +2778,7 @@ void Com_Init( char *commandLine ) {
sv_paused = Cvar_Get ("sv_paused", "0", CVAR_ROM); sv_paused = Cvar_Get ("sv_paused", "0", CVAR_ROM);
cl_packetdelay = Cvar_Get ("cl_packetdelay", "0", CVAR_CHEAT); cl_packetdelay = Cvar_Get ("cl_packetdelay", "0", CVAR_CHEAT);
sv_packetdelay = Cvar_Get ("sv_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_sv_running = Cvar_Get ("sv_running", "0", CVAR_ROM);
com_cl_running = Cvar_Get ("cl_running", "0", CVAR_ROM); com_cl_running = Cvar_Get ("cl_running", "0", CVAR_ROM);
com_buildScript = Cvar_Get( "com_buildScript", "0", 0 ); com_buildScript = Cvar_Get( "com_buildScript", "0", 0 );
@ -3024,6 +3026,9 @@ void Com_Frame( void ) {
int msec, minMsec; int msec, minMsec;
int timeVal; int timeVal;
int numBlocks = 1;
int dlStart, deltaT, delayT;
static int dlNextRound = 0;
static int lastTime = 0, bias = 0; static int lastTime = 0, bias = 0;
int timeBeforeFirstEvents; int timeBeforeFirstEvents;
@ -3084,13 +3089,70 @@ void Com_Frame( void ) {
minMsec = 1; minMsec = 1;
timeVal = 0; timeVal = 0;
do do
{ {
// Busy sleep the last millisecond for better timeout precision // Busy sleep the last millisecond for better timeout precision
if(com_busyWait->integer || timeVal < 2) if(timeVal < 2)
NET_Sleep(0); NET_Sleep(0);
else 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; msec = Sys_Milliseconds() - com_frameTime;

View file

@ -192,8 +192,9 @@ void NET_Sleep(int msec);
#define MAX_MSGLEN 16384 // max length of a message, which may #define MAX_MSGLEN 16384 // max length of a message, which may
// be fragmented into multiple packets // be fragmented into multiple packets
#define MAX_DOWNLOAD_WINDOW 8 // max of eight download frames #define MAX_DOWNLOAD_WINDOW 48 // ACK window of 48 download chunks. Cannot set this higher, or clients
#define MAX_DOWNLOAD_BLKSIZE 2048 // 2048 byte block chunks // will overflow the reliable commands buffer
#define MAX_DOWNLOAD_BLKSIZE 1024 // 896 byte block chunks
/* /*
@ -1029,6 +1030,7 @@ void SV_Frame( int msec );
void SV_PacketEvent( netadr_t from, msg_t *msg ); void SV_PacketEvent( netadr_t from, msg_t *msg );
int SV_FrameMsec(void); int SV_FrameMsec(void);
qboolean SV_GameCommand( void ); qboolean SV_GameCommand( void );
int SV_SendDownloadMessages(void);
// //

View file

@ -345,7 +345,7 @@ void SV_DropClient( client_t *drop, const char *reason );
void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ); void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK );
void SV_ClientThink (client_t *cl, usercmd_t *cmd); void SV_ClientThink (client_t *cl, usercmd_t *cmd);
void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ); int SV_WriteDownloadToClient(client_t *cl , msg_t *msg);
#ifdef USE_VOIP #ifdef USE_VOIP
void SV_WriteVoipToClient( client_t *cl, msg_t *msg ); void SV_WriteVoipToClient( client_t *cl, msg_t *msg );

View file

@ -852,21 +852,19 @@ static void SV_BeginDownload_f( client_t *cl ) {
SV_WriteDownloadToClient SV_WriteDownloadToClient
Check to see if the client wants a file, open it if needed and start pumping the client Check to see if the client wants a file, open it if needed and start pumping the client
Fill up msg with data Fill up msg with data, return number of download blocks added
================== ==================
*/ */
void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) int SV_WriteDownloadToClient(client_t *cl, msg_t *msg)
{ {
int curindex; int curindex;
int rate;
int blockspersnap;
int unreferenced = 1; int unreferenced = 1;
char errorMessage[1024]; char errorMessage[1024];
char pakbuf[MAX_QPATH], *pakptr; char pakbuf[MAX_QPATH], *pakptr;
int numRefPaks; int numRefPaks;
if (!*cl->downloadName) if (!*cl->downloadName)
return; // Nothing being downloaded return 0; // Nothing being downloaded
if(!cl->download) if(!cl->download)
{ {
@ -970,7 +968,7 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
if(cl->download) if(cl->download)
FS_FCloseFile(cl->download); FS_FCloseFile(cl->download);
return; return 0;
} }
Com_Printf( "clientDownload: %d : beginning \"%s\"\n", (int) (cl - svs.clients), cl->downloadName ); Com_Printf( "clientDownload: %d : beginning \"%s\"\n", (int) (cl - svs.clients), cl->downloadName );
@ -1015,81 +1013,85 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
cl->downloadEOF = qtrue; // We have added the EOF block cl->downloadEOF = qtrue; // We have added the EOF block
} }
// Loop up to window size times based on how many blocks we can fit in the if (cl->downloadClientBlock == cl->downloadCurrentBlock)
// client snapMsec and rate return 0; // Nothing to transmit
// based on the rate, how many bytes can we fit in the snapMsec time of the client // Write out the next section of the file, if we have already reached our window,
// normal rate / snapshotMsec calculation // automatically start retransmitting
rate = cl->rate; if (cl->downloadXmitBlock == cl->downloadCurrentBlock)
if ( sv_maxRate->integer ) { {
if ( sv_maxRate->integer < 1000 ) { // We have transmitted the complete window, should we start resending?
Cvar_Set( "sv_MaxRate", "1000" ); if (svs.time - cl->downloadSendTime > 1000)
} cl->downloadXmitBlock = cl->downloadClientBlock;
if ( sv_maxRate->integer < rate ) { else
rate = sv_maxRate->integer; return 0;
}
}
if ( sv_minRate->integer ) {
if ( sv_minRate->integer < 1000 )
Cvar_Set( "sv_minRate", "1000" );
if ( sv_minRate->integer > rate )
rate = sv_minRate->integer;
} }
if (!rate) { // Send current block
blockspersnap = 1; curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW);
} else {
blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) /
MAX_DOWNLOAD_BLKSIZE;
}
if (blockspersnap < 0) MSG_WriteByte( msg, svc_download );
blockspersnap = 1; MSG_WriteShort( msg, cl->downloadXmitBlock );
while (blockspersnap--) { // block zero is special, contains file size
if ( cl->downloadXmitBlock == 0 )
MSG_WriteLong( msg, cl->downloadSize );
// Write out the next section of the file, if we have already reached our window, MSG_WriteShort( msg, cl->downloadBlockSize[curindex] );
// automatically start retransmitting
if (cl->downloadClientBlock == cl->downloadCurrentBlock) // Write the block
return; // Nothing to transmit if(cl->downloadBlockSize[curindex])
MSG_WriteData(msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex]);
if (cl->downloadXmitBlock == cl->downloadCurrentBlock) { Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock );
// We have transmitted the complete window, should we start resending?
//FIXME: This uses a hardcoded one second timeout for lost blocks // Move on to the next block
//the timeout should be based on client rate somehow // It will get sent with next snap shot. The rate will keep us in line.
if (svs.time - cl->downloadSendTime > 1000) cl->downloadXmitBlock++;
cl->downloadXmitBlock = cl->downloadClientBlock; cl->downloadSendTime = svs.time;
return 1;
}
/*
==================
SV_SendDownloadMessages
Send download messages to all clients
==================
*/
int SV_SendDownloadMessages(void)
{
int i, numDLs = 0, retval;
client_t *cl;
msg_t msg;
byte msgBuffer[MAX_MSGLEN];
for(i=0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++)
{
if(cl->state && *cl->downloadName)
{
if(cl->netchan.unsentFragments)
SV_Netchan_TransmitNextFragment(cl);
else else
return; {
MSG_Init(&msg, msgBuffer, sizeof(msgBuffer));
MSG_WriteLong(&msg, cl->lastClientCommand);
retval = SV_WriteDownloadToClient(cl, &msg);
if(retval)
{
MSG_WriteByte(&msg, svc_EOF);
SV_Netchan_Transmit(cl, &msg);
numDLs += retval;
}
}
} }
// Send current block
curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW);
MSG_WriteByte( msg, svc_download );
MSG_WriteShort( msg, cl->downloadXmitBlock );
// block zero is special, contains file size
if ( cl->downloadXmitBlock == 0 )
MSG_WriteLong( msg, cl->downloadSize );
MSG_WriteShort( msg, cl->downloadBlockSize[curindex] );
// Write the block
if ( cl->downloadBlockSize[curindex] ) {
MSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] );
}
Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock );
// Move on to the next block
// It will get sent with next snap shot. The rate will keep us in line.
cl->downloadXmitBlock++;
cl->downloadSendTime = svs.time;
} }
return numDLs;
} }
#ifdef USE_VOIP #ifdef USE_VOIP

View file

@ -647,9 +647,6 @@ void SV_SendClientSnapshot( client_t *client ) {
// and the playerState_t // and the playerState_t
SV_WriteSnapshotToClient( client, &msg ); SV_WriteSnapshotToClient( client, &msg );
// Add any download data if the client is downloading
SV_WriteDownloadToClient( client, &msg );
#ifdef USE_VOIP #ifdef USE_VOIP
SV_WriteVoipToClient( client, &msg ); SV_WriteVoipToClient( client, &msg );
#endif #endif
@ -683,6 +680,9 @@ void SV_SendClientMessages( void ) {
continue; // not time yet continue; // not time yet
} }
if(*c->downloadName)
continue; // Client is downloading, don't send snapshots
// send additional message fragments if the last message // send additional message fragments if the last message
// was too large to send at once // was too large to send at once
if ( c->netchan.unsentFragments ) { if ( c->netchan.unsentFragments ) {
@ -696,4 +696,3 @@ void SV_SendClientMessages( void ) {
SV_SendClientSnapshot( c ); SV_SendClientSnapshot( c );
} }
} }