mirror of
https://github.com/ReactionQuake3/reaction.git
synced 2024-11-29 15:31:51 +00:00
IOQ3 commit 2073
This commit is contained in:
parent
52151b3d1a
commit
d08fd5549d
6 changed files with 150 additions and 78 deletions
|
@ -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).
|
||||||
|
|
|
@ -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);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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);
|
NET_Sleep(0);
|
||||||
else
|
else
|
||||||
NET_Sleep(timeVal - 1);
|
NET_Sleep(timeVal - 1);
|
||||||
|
}
|
||||||
|
|
||||||
msec = Sys_Milliseconds() - com_frameTime;
|
msec = Sys_Milliseconds() - com_frameTime;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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,54 +1013,18 @@ 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
|
|
||||||
// normal rate / snapshotMsec calculation
|
|
||||||
rate = cl->rate;
|
|
||||||
if ( sv_maxRate->integer ) {
|
|
||||||
if ( sv_maxRate->integer < 1000 ) {
|
|
||||||
Cvar_Set( "sv_MaxRate", "1000" );
|
|
||||||
}
|
|
||||||
if ( sv_maxRate->integer < rate ) {
|
|
||||||
rate = sv_maxRate->integer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
blockspersnap = 1;
|
|
||||||
} else {
|
|
||||||
blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) /
|
|
||||||
MAX_DOWNLOAD_BLKSIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockspersnap < 0)
|
|
||||||
blockspersnap = 1;
|
|
||||||
|
|
||||||
while (blockspersnap--) {
|
|
||||||
|
|
||||||
// Write out the next section of the file, if we have already reached our window,
|
// Write out the next section of the file, if we have already reached our window,
|
||||||
// automatically start retransmitting
|
// automatically start retransmitting
|
||||||
|
if (cl->downloadXmitBlock == cl->downloadCurrentBlock)
|
||||||
if (cl->downloadClientBlock == cl->downloadCurrentBlock)
|
{
|
||||||
return; // Nothing to transmit
|
|
||||||
|
|
||||||
if (cl->downloadXmitBlock == cl->downloadCurrentBlock) {
|
|
||||||
// We have transmitted the complete window, should we start resending?
|
// 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 > 1000)
|
||||||
cl->downloadXmitBlock = cl->downloadClientBlock;
|
cl->downloadXmitBlock = cl->downloadClientBlock;
|
||||||
else
|
else
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send current block
|
// Send current block
|
||||||
|
@ -1078,18 +1040,58 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
|
||||||
MSG_WriteShort( msg, cl->downloadBlockSize[curindex] );
|
MSG_WriteShort( msg, cl->downloadBlockSize[curindex] );
|
||||||
|
|
||||||
// Write the block
|
// Write the block
|
||||||
if ( cl->downloadBlockSize[curindex] ) {
|
if(cl->downloadBlockSize[curindex])
|
||||||
MSG_WriteData(msg, cl->downloadBlocks[curindex], 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 );
|
Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock );
|
||||||
|
|
||||||
// Move on to the next block
|
// Move on to the next block
|
||||||
// It will get sent with next snap shot. The rate will keep us in line.
|
// It will get sent with next snap shot. The rate will keep us in line.
|
||||||
cl->downloadXmitBlock++;
|
cl->downloadXmitBlock++;
|
||||||
|
|
||||||
cl->downloadSendTime = svs.time;
|
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
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return numDLs;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_VOIP
|
#ifdef USE_VOIP
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue