diff options
Diffstat (limited to 'source/sv_user.c')
-rw-r--r-- | source/sv_user.c | 1345 |
1 files changed, 676 insertions, 669 deletions
diff --git a/source/sv_user.c b/source/sv_user.c index 3e7c845..0c29983 100644 --- a/source/sv_user.c +++ b/source/sv_user.c @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sv_local.h" #include "mvd_local.h" -edict_t *sv_player; +edict_t *sv_player; /* ============================================================ @@ -43,85 +43,94 @@ baseline will be transmitted ================ */ static void create_baselines( void ) { - int i; - edict_t *ent; - entity_state_t *base, **chunk; - - // clear baselines from previous level - for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) { - base = sv_client->baselines[i]; - if( !base ) { - continue; - } - memset( base, 0, sizeof( *base ) * SV_BASELINES_PER_CHUNK ); - } - - for( i = 1; i < sv_client->pool->num_edicts; i++ ) { - ent = EDICT_POOL( sv_client, i ); - - if( ( g_features->integer & GMF_PROPERINUSE ) && !ent->inuse ) { + int i; + edict_t *ent; + entity_state_t *base, **chunk; + + // clear baselines from previous level + for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) { + base = sv_client->baselines[i]; + if( !base ) { + continue; + } + memset( base, 0, sizeof( *base ) * SV_BASELINES_PER_CHUNK ); + } + + for( i = 1; i < sv_client->pool->num_edicts; i++ ) { + ent = EDICT_POOL( sv_client, i ); + + if( ( svs.gameFeatures & GMF_PROPERINUSE ) && !ent->inuse ) { continue; } - if( !ES_INUSE( &ent->s ) ) { - continue; - } + if( !ES_INUSE( &ent->s ) ) { + continue; + } - ent->s.number = i; + ent->s.number = i; - chunk = &sv_client->baselines[i >> SV_BASELINES_SHIFT]; - if( *chunk == NULL ) { - *chunk = SV_Mallocz( sizeof( *base ) * SV_BASELINES_PER_CHUNK ); - } + chunk = &sv_client->baselines[i >> SV_BASELINES_SHIFT]; + if( *chunk == NULL ) { + *chunk = SV_Mallocz( sizeof( *base ) * SV_BASELINES_PER_CHUNK ); + } - base = *chunk + ( i & SV_BASELINES_MASK ); + base = *chunk + ( i & SV_BASELINES_MASK ); - *base = ent->s; - } + *base = ent->s; + } } static void write_plain_configstrings( void ) { - int i; - char *string; - size_t length; - - // write a packet full of data - string = sv_client->configstrings; - for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { - if( !string[0] ) { - continue; - } - length = strlen( string ); - if( length > MAX_QPATH ) { - length = MAX_QPATH; - } - // check if this configstring will overflow - if( msg_write.cursize + length + 64 > sv_client->netchan->maxpacketlen ) + int i; + char *string; + size_t length; + + // write a packet full of data + string = sv_client->configstrings; + for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { + if( !string[0] ) { + continue; + } + length = strlen( string ); + if( length > MAX_QPATH ) { + length = MAX_QPATH; + } + // check if this configstring will overflow + if( msg_write.cursize + length + 64 > sv_client->netchan->maxpacketlen ) { - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } - MSG_WriteByte( svc_configstring ); - MSG_WriteShort( i ); - MSG_WriteData( string, length ); - MSG_WriteByte( 0 ); - } + MSG_WriteByte( svc_configstring ); + MSG_WriteShort( i ); + MSG_WriteData( string, length ); + MSG_WriteByte( 0 ); + } - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); +} + +static void write_baseline( entity_state_t *base ) { + msgEsFlags_t flags = MSG_ES_FORCE; + + if( LONG_SOLID_SUPPORTED( sv_client->protocol, sv_client->version ) ) { + flags |= MSG_ES_LONGSOLID; + } + MSG_WriteDeltaEntity( NULL, base, flags ); } static void write_plain_baselines( void ) { - int i, j; - entity_state_t *base; + int i, j; + entity_state_t *base; - // write a packet full of data + // write a packet full of data for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) { - base = sv_client->baselines[i]; - if( !base ) { - continue; - } - for( j = 0; j < SV_BASELINES_PER_CHUNK; j++ ) { + base = sv_client->baselines[i]; + if( !base ) { + continue; + } + for( j = 0; j < SV_BASELINES_PER_CHUNK; j++ ) { if( base->number ) { // check if this baseline will overflow if( msg_write.cursize + 64 > sv_client->netchan->maxpacketlen ) @@ -130,71 +139,71 @@ static void write_plain_baselines( void ) { } MSG_WriteByte( svc_spawnbaseline ); - MSG_WriteDeltaEntity( NULL, base, MSG_ES_FORCE ); + write_baseline( base ); } base++; } - } + } - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } #if USE_ZLIB static void write_compressed_gamestate( void ) { - sizebuf_t *buf = &sv_client->netchan->message; - entity_state_t *base; - int i, j; - size_t length; + sizebuf_t *buf = &sv_client->netchan->message; + entity_state_t *base; + int i, j; + size_t length; uint8_t *patch; char *string; MSG_WriteByte( svc_gamestate ); - // write configstrings + // write configstrings string = sv_client->configstrings; - for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { - if( !string[0] ) { - continue; - } - length = strlen( string ); - if( length > MAX_QPATH ) { - length = MAX_QPATH; - } - - MSG_WriteShort( i ); - MSG_WriteData( string, length ); - MSG_WriteByte( 0 ); - } + for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { + if( !string[0] ) { + continue; + } + length = strlen( string ); + if( length > MAX_QPATH ) { + length = MAX_QPATH; + } + + MSG_WriteShort( i ); + MSG_WriteData( string, length ); + MSG_WriteByte( 0 ); + } MSG_WriteShort( MAX_CONFIGSTRINGS ); // end of configstrings // write baselines for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) { - base = sv_client->baselines[i]; - if( !base ) { - continue; - } - for( j = 0; j < SV_BASELINES_PER_CHUNK; j++ ) { + base = sv_client->baselines[i]; + if( !base ) { + continue; + } + for( j = 0; j < SV_BASELINES_PER_CHUNK; j++ ) { if( base->number ) { - MSG_WriteDeltaEntity( NULL, base, MSG_ES_FORCE ); + write_baseline( base ); } base++; } - } + } MSG_WriteShort( 0 ); // end of baselines - SZ_WriteByte( buf, svc_zpacket ); + SZ_WriteByte( buf, svc_zpacket ); patch = SZ_GetSpace( buf, 2 ); - SZ_WriteShort( buf, msg_write.cursize ); + SZ_WriteShort( buf, msg_write.cursize ); deflateReset( &svs.z ); svs.z.next_in = msg_write.data; svs.z.avail_in = ( uInt )msg_write.cursize; svs.z.next_out = buf->data + buf->cursize; svs.z.avail_out = ( uInt )( buf->maxsize - buf->cursize ); - SZ_Clear( &msg_write ); + SZ_Clear( &msg_write ); - if( deflate( &svs.z, Z_FINISH ) != Z_STREAM_END ) { + if( deflate( &svs.z, Z_FINISH ) != Z_STREAM_END ) { SV_DropClient( sv_client, "deflate() failed on gamestate" ); return; } @@ -213,23 +222,23 @@ static inline int z_flush( byte *buffer ) { int ret; ret = deflate( &svs.z, Z_FINISH ); - if( ret != Z_STREAM_END ) { - return ret; - } + if( ret != Z_STREAM_END ) { + return ret; + } if( sv_debug_send->integer ) { Com_Printf( S_COLOR_BLUE"%s: comp: %lu into %lu\n", sv_client->name, svs.z.total_in, svs.z.total_out ); } - MSG_WriteByte( svc_zpacket ); - MSG_WriteShort( svs.z.total_out ); - MSG_WriteShort( svs.z.total_in ); - MSG_WriteData( buffer, svs.z.total_out ); - - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + MSG_WriteByte( svc_zpacket ); + MSG_WriteShort( svs.z.total_out ); + MSG_WriteShort( svs.z.total_in ); + MSG_WriteData( buffer, svs.z.total_out ); + + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); - return ret; + return ret; } static inline void z_reset( byte *buffer ) { @@ -239,52 +248,52 @@ static inline void z_reset( byte *buffer ) { } static void write_compressed_configstrings( void ) { - int i; - size_t length; - byte buffer[MAX_PACKETLEN_WRITABLE]; - char *string; + int i; + size_t length; + byte buffer[MAX_PACKETLEN_WRITABLE]; + char *string; z_reset( buffer ); - // write a packet full of data + // write a packet full of data string = sv_client->configstrings; - for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { - if( !string[0] ) { - continue; - } - length = strlen( string ); - if( length > MAX_QPATH ) { - length = MAX_QPATH; - } - - // check if this configstring will overflow - if( svs.z.avail_out < length + 32 ) { - // then flush compressed data - if( z_flush( buffer ) != Z_STREAM_END ) { + for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { + if( !string[0] ) { + continue; + } + length = strlen( string ); + if( length > MAX_QPATH ) { + length = MAX_QPATH; + } + + // check if this configstring will overflow + if( svs.z.avail_out < length + 32 ) { + // then flush compressed data + if( z_flush( buffer ) != Z_STREAM_END ) { goto fail; - } + } z_reset( buffer ); - } + } - MSG_WriteByte( svc_configstring ); - MSG_WriteShort( i ); - MSG_WriteData( string, length ); - MSG_WriteByte( 0 ); + MSG_WriteByte( svc_configstring ); + MSG_WriteShort( i ); + MSG_WriteData( string, length ); + MSG_WriteByte( 0 ); svs.z.next_in = msg_write.data; svs.z.avail_in = ( uInt )msg_write.cursize; SZ_Clear( &msg_write ); - if( deflate( &svs.z, Z_SYNC_FLUSH ) != Z_OK ) { + if( deflate( &svs.z, Z_SYNC_FLUSH ) != Z_OK ) { goto fail; } - } + } - // finally flush all remaining compressed data - if( z_flush( buffer ) != Z_STREAM_END ) { + // finally flush all remaining compressed data + if( z_flush( buffer ) != Z_STREAM_END ) { fail: SV_DropClient( sv_client, "deflate() failed on configstrings" ); - } + } } #endif // USE_ZLIB @@ -297,7 +306,7 @@ static void stuff_cmds( list_t *list ) { MSG_WriteData( stuff->string, stuff->len ); MSG_WriteByte( '\n' ); MSG_WriteByte( 0 ); - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } } @@ -316,18 +325,18 @@ void SV_New_f( void ) { char junk[8][16]; int i, j, c; - Com_DPrintf( "New() from %s\n", sv_client->name ); + Com_DPrintf( "New() from %s\n", sv_client->name ); if( sv_client->state < cs_connected ) { - Com_DPrintf( "Going from cs_assigned to cs_connected for %s\n", + Com_DPrintf( "Going from cs_assigned to cs_connected for %s\n", sv_client->name ); sv_client->state = cs_connected; sv_client->lastmessage = svs.realtime; // don't timeout time( &sv_client->connect_time ); } else if( sv_client->state > cs_connected ) { - Com_DPrintf( "New not valid -- already primed\n" ); - return; - } + Com_DPrintf( "New not valid -- already primed\n" ); + return; + } if( sv_force_reconnect->string[0] && !sv_client->reconnect_var[0] && !NET_IsLocalAddress( &sv_client->netchan->remote_address ) ) @@ -363,89 +372,89 @@ void SV_New_f( void ) { return; } - SV_ClientCommand( sv_client, "\n" ); + SV_ClientCommand( sv_client, "\n" ); - // - // serverdata needs to go over for all types of servers - // to make sure the protocol is right, and to set the gamedir - // + // + // serverdata needs to go over for all types of servers + // to make sure the protocol is right, and to set the gamedir + // // create baselines for this client create_baselines(); - // send the serverdata - MSG_WriteByte( svc_serverdata ); - MSG_WriteLong( sv_client->protocol ); - MSG_WriteLong( sv.spawncount ); - MSG_WriteByte( 0 ); // no attract loop - MSG_WriteString( sv_client->gamedir ); - MSG_WriteShort( sv_client->slot ); - MSG_WriteString( &sv_client->configstrings[CS_NAME*MAX_QPATH] ); - - // send protocol specific stuff - switch( sv_client->protocol ) { - case PROTOCOL_VERSION_R1Q2: - MSG_WriteByte( 0 ); // not enhanced - MSG_WriteShort( sv_client->version ); - MSG_WriteByte( 0 ); // no advanced deltas - MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); - break; - case PROTOCOL_VERSION_Q2PRO: - MSG_WriteShort( sv_client->version ); - MSG_WriteByte( svs.gametype ); - MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); - MSG_WriteByte( sv_qwmod->integer ); - break; - default: - break; - } - - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); - - SV_ClientCommand( sv_client, "\n" ); - - // send version string request - if( !sv_client->versionString ) { - SV_ClientCommand( sv_client, "cmd \177c version $version\n" + // send the serverdata + MSG_WriteByte( svc_serverdata ); + MSG_WriteLong( sv_client->protocol ); + MSG_WriteLong( sv.spawncount ); + MSG_WriteByte( 0 ); // no attract loop + MSG_WriteString( sv_client->gamedir ); + MSG_WriteShort( sv_client->slot ); + MSG_WriteString( &sv_client->configstrings[CS_NAME*MAX_QPATH] ); + + // send protocol specific stuff + switch( sv_client->protocol ) { + case PROTOCOL_VERSION_R1Q2: + MSG_WriteByte( 0 ); // not enhanced + MSG_WriteShort( sv_client->version ); + MSG_WriteByte( 0 ); // no advanced deltas + MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); + break; + case PROTOCOL_VERSION_Q2PRO: + MSG_WriteShort( sv_client->version ); + MSG_WriteByte( 2 ); // used to be GT_DEATHMATCH + MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); + MSG_WriteByte( sv_qwmod->integer ); + break; + default: + break; + } + + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + + SV_ClientCommand( sv_client, "\n" ); + + // send version string request + if( !sv_client->versionString ) { + SV_ClientCommand( sv_client, "cmd \177c version $version\n" #if USE_ANTICHEAT & 2 "cmd \177c actoken $actoken\n" #endif ); stuff_cmds( &sv_cmdlist_connect ); - } + } // send reconnect var request if( sv_force_reconnect->string[0] && !( sv_client->flags & CF_RECONNECTED ) ) { - SV_ClientCommand( sv_client, "cmd \177c connect $%s\n", + SV_ClientCommand( sv_client, "cmd \177c connect $%s\n", sv_client->reconnect_var ); } - Com_DPrintf( "Going from cs_connected to cs_primed for %s\n", + Com_DPrintf( "Going from cs_connected to cs_primed for %s\n", sv_client->name ); - sv_client->state = cs_primed; + sv_client->state = cs_primed; - memset( &sv_client->lastcmd, 0, sizeof( sv_client->lastcmd ) ); + memset( &sv_client->lastcmd, 0, sizeof( sv_client->lastcmd ) ); #if USE_ZLIB if( !( sv_client->flags & CF_DEFLATE ) ) { - write_plain_configstrings(); - write_plain_baselines(); + write_plain_configstrings(); + write_plain_baselines(); } else { if( sv_client->netchan->type == NETCHAN_NEW ) { write_compressed_gamestate(); } else { // FIXME: Z_SYNC_FLUSH is not efficient for baselines write_compressed_configstrings(); - write_plain_baselines(); + write_plain_baselines(); } - } + } #else // USE_ZLIB - write_plain_configstrings(); - write_plain_baselines(); + write_plain_configstrings(); + write_plain_baselines(); #endif // !USE_ZLIB - // send next command - SV_ClientCommand( sv_client, "precache %i\n", sv.spawncount ); + // send next command + SV_ClientCommand( sv_client, "precache %i\n", sv.spawncount ); } /* @@ -454,18 +463,18 @@ SV_Begin_f ================== */ void SV_Begin_f( void ) { - Com_DPrintf( "Begin() from %s\n", sv_client->name ); - - // handle the case of a level changing while a client was connecting - if( sv_client->state < cs_primed ) { - Com_DPrintf( "Begin not valid -- not yet primed\n" ); - SV_New_f(); - return; - } - if( sv_client->state > cs_primed ) { - Com_DPrintf( "Begin not valid -- already spawned\n" ); - return; - } + Com_DPrintf( "Begin() from %s\n", sv_client->name ); + + // handle the case of a level changing while a client was connecting + if( sv_client->state < cs_primed ) { + Com_DPrintf( "Begin not valid -- not yet primed\n" ); + SV_New_f(); + return; + } + if( sv_client->state > cs_primed ) { + Com_DPrintf( "Begin not valid -- already spawned\n" ); + return; + } if( sv_force_reconnect->string[0] && !( sv_client->flags & CF_RECONNECTED ) ) { if( dedicated->integer ) { @@ -482,17 +491,17 @@ void SV_Begin_f( void ) { } #endif - Com_DPrintf( "Going from cs_primed to cs_spawned for %s\n", + Com_DPrintf( "Going from cs_primed to cs_spawned for %s\n", sv_client->name ); - sv_client->state = cs_spawned; - sv_client->send_delta = 0; - sv_client->commandMsec = 1800; + sv_client->state = cs_spawned; + sv_client->send_delta = 0; + sv_client->commandMsec = 1800; sv_client->surpressCount = 0; stuff_cmds( &sv_cmdlist_begin ); - - // call the game begin function - ge->ClientBegin( sv_player ); + + // call the game begin function + ge->ClientBegin( sv_player ); #if USE_ANTICHEAT & 2 AC_ClientAnnounce( sv_client ); @@ -501,7 +510,7 @@ void SV_Begin_f( void ) { //============================================================================= -#define MAX_DOWNLOAD_CHUNK 1024 +#define MAX_DOWNLOAD_CHUNK 1024 /* ================== @@ -509,42 +518,42 @@ SV_NextDownload_f ================== */ static void SV_NextDownload_f( void ) { - int r; - int percent; - int size; - - if ( !sv_client->download ) - return; - - r = sv_client->downloadsize - sv_client->downloadcount; - if ( r > MAX_DOWNLOAD_CHUNK ) - r = MAX_DOWNLOAD_CHUNK; - - MSG_WriteByte( svc_download ); - MSG_WriteShort( r ); - - sv_client->downloadcount += r; - size = sv_client->downloadsize; - if( !size ) - size = 1; - percent = sv_client->downloadcount*100/size; - MSG_WriteByte( percent ); - MSG_WriteData( sv_client->download + sv_client->downloadcount - r, r ); - - if( sv_client->downloadcount == sv_client->downloadsize ) { - Z_Free( sv_client->download ); - sv_client->download = NULL; - } - - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + int r; + int percent; + int size; + + if ( !sv_client->download ) + return; + + r = sv_client->downloadsize - sv_client->downloadcount; + if ( r > MAX_DOWNLOAD_CHUNK ) + r = MAX_DOWNLOAD_CHUNK; + + MSG_WriteByte( svc_download ); + MSG_WriteShort( r ); + + sv_client->downloadcount += r; + size = sv_client->downloadsize; + if( !size ) + size = 1; + percent = sv_client->downloadcount*100/size; + MSG_WriteByte( percent ); + MSG_WriteData( sv_client->download + sv_client->downloadcount - r, r ); + + if( sv_client->downloadcount == sv_client->downloadsize ) { + Z_Free( sv_client->download ); + sv_client->download = NULL; + } + + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } static void SV_DownloadFailed( void ) { - MSG_WriteByte( svc_download ); - MSG_WriteShort( -1 ); - MSG_WriteByte( 0 ); - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + MSG_WriteByte( svc_download ); + MSG_WriteShort( -1 ); + MSG_WriteByte( 0 ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } /* @@ -553,133 +562,133 @@ SV_BeginDownload_f ================== */ static void SV_BeginDownload_f( void ) { - char name[MAX_QPATH]; - int downloadsize; - int offset = 0; - cvar_t *allow; - int length; - char *filename; - - length = Q_ClearStr( name, Cmd_Argv( 1 ), sizeof( name ) ); - Q_strlwr( name ); - - if( Cmd_Argc() > 2 ) - offset = atoi( Cmd_Argv( 2 ) ); // downloaded offset - - // hacked by zoid to allow more conrol over download - // first off, no .. or global allow check - if( !allow_download->integer - // check for empty paths - || !length - // check for illegal negative offsets - || offset < 0 - // don't allow anything with .. path - || strstr( name, ".." ) - // leading dots, slashes, etc are no good - || !Q_ispath( name[0] ) - // trailing dots, slashes, etc are no good - || !Q_ispath( name[ length - 1 ] ) - // back slashes should be never sent - || strchr( name, '\\' ) - // colons are bad also - || strchr( name, ':' ) - // MUST be in a subdirectory - || !strchr( name, '/' ) ) - { - SV_DownloadFailed(); - return; - } - - if( strncmp( name, "players/", 8 ) == 0 ) { - allow = allow_download_players; - } else if( strncmp( name, "models/", 7 ) == 0 ) { - allow = allow_download_models; - } else if( strncmp( name, "sound/", 6 ) == 0 ) { - allow = allow_download_sounds; - } else if( strncmp( name, "maps/", 5 ) == 0 ) { - allow = allow_download_maps; - } else { - allow = allow_download_other; - } - - if( !allow->integer ) { - Com_DPrintf( "Refusing download of %s to %s\n", name, sv_client->name ); - SV_DownloadFailed(); - return; - } - - if( sv_client->download ) { - Com_DPrintf( "Closing existing download for %s (should not happen)\n", sv_client->name ); - FS_FreeFile( sv_client->download ); - sv_client->download = NULL; - } - - filename = name; - - downloadsize = FS_LoadFileEx( filename, NULL, 0, TAG_SERVER ); - - if( downloadsize == INVALID_LENGTH || downloadsize == 0 - // special check for maps, if it came from a pak file, don't allow - // download ZOID - || ( allow == allow_download_maps - && allow_download_maps->integer < 2 - && FS_LastFileFromPak() ) ) - { - Com_DPrintf( "Couldn't download %s to %s\n", name, sv_client->name ); - SV_DownloadFailed(); - return; - } - - if( offset > downloadsize ) { - Com_DPrintf( "Refusing download, %s has wrong version of %s (%d > %d)\n", - sv_client->name, name, offset, downloadsize ); - SV_ClientPrintf( sv_client, PRINT_HIGH, "File size differs from server.\n" - "Please delete the corresponding .tmp file from your system.\n" ); - SV_DownloadFailed(); - return; - } - - if( offset == downloadsize ) { - Com_DPrintf( "Refusing download, %s already has %s (%d bytes)\n", - sv_client->name, name, offset ); - MSG_WriteByte( svc_download ); - MSG_WriteShort( 0 ); - MSG_WriteByte( 100 ); - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); - return; - } - - sv_client->downloadsize = FS_LoadFileEx( filename, + char name[MAX_QPATH]; + int downloadsize; + int offset = 0; + cvar_t *allow; + int length; + char *filename; + + length = Q_ClearStr( name, Cmd_Argv( 1 ), sizeof( name ) ); + Q_strlwr( name ); + + if( Cmd_Argc() > 2 ) + offset = atoi( Cmd_Argv( 2 ) ); // downloaded offset + + // hacked by zoid to allow more conrol over download + // first off, no .. or global allow check + if( !allow_download->integer + // check for empty paths + || !length + // check for illegal negative offsets + || offset < 0 + // don't allow anything with .. path + || strstr( name, ".." ) + // leading dots, slashes, etc are no good + || !Q_ispath( name[0] ) + // trailing dots, slashes, etc are no good + || !Q_ispath( name[ length - 1 ] ) + // back slashes should be never sent + || strchr( name, '\\' ) + // colons are bad also + || strchr( name, ':' ) + // MUST be in a subdirectory + || !strchr( name, '/' ) ) + { + SV_DownloadFailed(); + return; + } + + if( strncmp( name, "players/", 8 ) == 0 ) { + allow = allow_download_players; + } else if( strncmp( name, "models/", 7 ) == 0 ) { + allow = allow_download_models; + } else if( strncmp( name, "sound/", 6 ) == 0 ) { + allow = allow_download_sounds; + } else if( strncmp( name, "maps/", 5 ) == 0 ) { + allow = allow_download_maps; + } else { + allow = allow_download_other; + } + + if( !allow->integer ) { + Com_DPrintf( "Refusing download of %s to %s\n", name, sv_client->name ); + SV_DownloadFailed(); + return; + } + + if( sv_client->download ) { + Com_DPrintf( "Closing existing download for %s (should not happen)\n", sv_client->name ); + FS_FreeFile( sv_client->download ); + sv_client->download = NULL; + } + + filename = name; + + downloadsize = FS_LoadFileEx( filename, NULL, 0, TAG_SERVER ); + + if( downloadsize == INVALID_LENGTH || downloadsize == 0 + // special check for maps, if it came from a pak file, don't allow + // download ZOID + || ( allow == allow_download_maps + && allow_download_maps->integer < 2 + && FS_LastFileFromPak() ) ) + { + Com_DPrintf( "Couldn't download %s to %s\n", name, sv_client->name ); + SV_DownloadFailed(); + return; + } + + if( offset > downloadsize ) { + Com_DPrintf( "Refusing download, %s has wrong version of %s (%d > %d)\n", + sv_client->name, name, offset, downloadsize ); + SV_ClientPrintf( sv_client, PRINT_HIGH, "File size differs from server.\n" + "Please delete the corresponding .tmp file from your system.\n" ); + SV_DownloadFailed(); + return; + } + + if( offset == downloadsize ) { + Com_DPrintf( "Refusing download, %s already has %s (%d bytes)\n", + sv_client->name, name, offset ); + MSG_WriteByte( svc_download ); + MSG_WriteShort( 0 ); + MSG_WriteByte( 100 ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + return; + } + + sv_client->downloadsize = FS_LoadFileEx( filename, ( void ** )&sv_client->download, 0, TAG_SERVER ); - sv_client->downloadcount = offset; + sv_client->downloadcount = offset; - Com_DPrintf( "Downloading %s to %s\n", name, sv_client->name ); + Com_DPrintf( "Downloading %s to %s\n", name, sv_client->name ); - SV_NextDownload_f(); + SV_NextDownload_f(); } static void SV_StopDownload_f( void ) { - int size, percent; - - if( !sv_client->download ) { - return; - } - - size = sv_client->downloadsize; - if( !size ) { - percent = 0; - } else { - percent = sv_client->downloadcount*100/size; - } - - MSG_WriteByte( svc_download ); - MSG_WriteShort( -1 ); - MSG_WriteByte( percent ); - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); - - Com_DPrintf( "Download for %s stopped by user request\n", sv_client->name ); - Z_Free( sv_client->download ); - sv_client->download = NULL; + int size, percent; + + if( !sv_client->download ) { + return; + } + + size = sv_client->downloadsize; + if( !size ) { + percent = 0; + } else { + percent = sv_client->downloadcount*100/size; + } + + MSG_WriteByte( svc_download ); + MSG_WriteShort( -1 ); + MSG_WriteByte( percent ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + + Com_DPrintf( "Download for %s stopped by user request\n", sv_client->name ); + Z_Free( sv_client->download ); + sv_client->download = NULL; } //============================================================================ @@ -697,7 +706,7 @@ static void SV_Disconnect_f( void ) { Com_Printf( "%s[%s] disconnected\n", sv_client->name, NET_AdrToString( &sv_client->netchan->remote_address ) ); } - SV_DropClient( sv_client, NULL ); + SV_DropClient( sv_client, NULL ); } @@ -713,21 +722,21 @@ static void SV_ShowServerinfo_f( void ) { Cvar_BitInfo( serverinfo, CVAR_SERVERINFO ); - SV_BeginRedirect( RD_CLIENT ); - Info_Print( serverinfo ); - Com_EndRedirect(); + SV_BeginRedirect( RD_CLIENT ); + Info_Print( serverinfo ); + Com_EndRedirect(); } static void SV_NoGameData_f( void ) { - sv_client->flags ^= CF_NODATA; + sv_client->flags ^= CF_NODATA; } static void SV_CvarResult_f( void ) { - char *c, *v; + char *c, *v; - c = Cmd_Argv( 1 ); - if( !strcmp( c, "version" ) ) { - if( !sv_client->versionString ) { + c = Cmd_Argv( 1 ); + if( !strcmp( c, "version" ) ) { + if( !sv_client->versionString ) { v = Cmd_RawArgsFrom( 2 ); if( dedicated->integer ) { Com_Printf( "%s[%s]: %s\n", sv_client->name, @@ -735,7 +744,7 @@ static void SV_CvarResult_f( void ) { } sv_client->versionString = SV_CopyString( v ); } - } else if( !strcmp( c, "connect" ) ) { + } else if( !strcmp( c, "connect" ) ) { if( sv_client->reconnect_var[0] ) { v = Cmd_Argv( 2 ); if( !strcmp( v, sv_client->reconnect_val ) ) { @@ -744,7 +753,7 @@ static void SV_CvarResult_f( void ) { } } #if USE_ANTICHEAT & 2 - else if( !strcmp( c, "actoken" ) ) { + else if( !strcmp( c, "actoken" ) ) { AC_ClientToken( sv_client, Cmd_Argv( 2 ) ); } #endif @@ -753,43 +762,43 @@ static void SV_CvarResult_f( void ) { #if USE_ANTICHEAT & 2 static void SV_AC_List_f( void ) { - SV_BeginRedirect( RD_CLIENT ); - AC_List_f(); - Com_EndRedirect(); + SV_BeginRedirect( RD_CLIENT ); + AC_List_f(); + Com_EndRedirect(); } static void SV_AC_Info_f( void ) { - SV_BeginRedirect( RD_CLIENT ); - AC_Info_f(); - Com_EndRedirect(); + SV_BeginRedirect( RD_CLIENT ); + AC_Info_f(); + Com_EndRedirect(); } #endif static const ucmd_t ucmds[] = { - // auto issued - { "new", SV_New_f }, - { "begin", SV_Begin_f }, - { "baselines", NULL }, - { "configstrings", NULL }, - { "nextserver", NULL }, - { "disconnect", SV_Disconnect_f }, - - // issued by hand at client consoles - { "info", SV_ShowServerinfo_f }, - - { "download", SV_BeginDownload_f }, - { "nextdl", SV_NextDownload_f }, - { "stopdl", SV_StopDownload_f }, - - { "\177c", SV_CvarResult_f }, - { "nogamedata", SV_NoGameData_f }, + // auto issued + { "new", SV_New_f }, + { "begin", SV_Begin_f }, + { "baselines", NULL }, + { "configstrings", NULL }, + { "nextserver", NULL }, + { "disconnect", SV_Disconnect_f }, + + // issued by hand at client consoles + { "info", SV_ShowServerinfo_f }, + + { "download", SV_BeginDownload_f }, + { "nextdl", SV_NextDownload_f }, + { "stopdl", SV_StopDownload_f }, + + { "\177c", SV_CvarResult_f }, + { "nogamedata", SV_NoGameData_f }, #if USE_ANTICHEAT & 2 - { "aclist", SV_AC_List_f }, - { "acinfo", SV_AC_Info_f }, + { "aclist", SV_AC_List_f }, + { "acinfo", SV_AC_Info_f }, #endif - { NULL, NULL } + { NULL, NULL } }; /* @@ -798,16 +807,16 @@ SV_ExecuteUserCommand ================== */ static void SV_ExecuteUserCommand( const char *s ) { - const ucmd_t *u; - char *c; - - Cmd_TokenizeString( s, qfalse ); - sv_player = sv_client->edict; + const ucmd_t *u; + char *c; + + Cmd_TokenizeString( s, qfalse ); + sv_player = sv_client->edict; - c = Cmd_Argv( 0 ); - if( !c[0] ) { - return; - } + c = Cmd_Argv( 0 ); + if( !c[0] ) { + return; + } if( ( u = Com_Find( ucmds, c ) ) != NULL ) { if( u->func ) { @@ -835,17 +844,17 @@ SV_ClientThink ================== */ static inline void SV_ClientThink( client_t *cl, usercmd_t *cmd ) { - cl->commandMsec -= cmd->msec; + cl->commandMsec -= cmd->msec; - if( cl->commandMsec < 0 && sv_enforcetime->integer ) { + if( cl->commandMsec < 0 && sv_enforcetime->integer ) { #ifdef _DEBUG - Com_DPrintf( "commandMsec underflow from %s: %d\n", - cl->name, cl->commandMsec ); + Com_DPrintf( "commandMsec underflow from %s: %d\n", + cl->name, cl->commandMsec ); #endif - return; - } + return; + } - ge->ClientThink( cl->edict, cmd ); + ge->ClientThink( cl->edict, cmd ); } static inline void SV_SetLastFrame( int lastframe ) { @@ -871,17 +880,17 @@ SV_OldClientExecuteMove ================== */ static void SV_OldClientExecuteMove( int net_drop ) { - usercmd_t oldest, oldcmd, newcmd; - int lastframe; + usercmd_t oldest, oldcmd, newcmd; + int lastframe; - if( sv_client->protocol == PROTOCOL_VERSION_DEFAULT ) { - MSG_ReadByte(); // skip over checksum - } - + if( sv_client->protocol == PROTOCOL_VERSION_DEFAULT ) { + MSG_ReadByte(); // skip over checksum + } + lastframe = MSG_ReadLong(); SV_SetLastFrame( lastframe ); - if( sv_client->protocol == PROTOCOL_VERSION_R1Q2 && + if( sv_client->protocol == PROTOCOL_VERSION_R1Q2 && sv_client->version >= PROTOCOL_VERSION_R1Q2_UCMD ) { MSG_ReadDeltaUsercmd_Hacked( NULL, &oldest ); @@ -893,31 +902,31 @@ static void SV_OldClientExecuteMove( int net_drop ) { MSG_ReadDeltaUsercmd( &oldcmd, &newcmd ); } - if( sv_client->state != cs_spawned ) { - sv_client->lastframe = -1; - return; - } + if( sv_client->state != cs_spawned ) { + sv_client->lastframe = -1; + return; + } - if( net_drop > 2 ) { + if( net_drop > 2 ) { sv_client->frameflags |= FF_CLIENTPRED; -// Com_DPrintf( "%s: net_drop %i\n", sv_client->name, net_drop ); - } - - if( net_drop < 20 ) { - while( net_drop > 2 ) { - SV_ClientThink( sv_client, &sv_client->lastcmd ); - net_drop--; - } - if( net_drop > 1 ) - SV_ClientThink( sv_client, &oldest ); - - if( net_drop > 0 ) - SV_ClientThink( sv_client, &oldcmd ); - - } - SV_ClientThink( sv_client, &newcmd ); - - sv_client->lastcmd = newcmd; +// Com_DPrintf( "%s: net_drop %i\n", sv_client->name, net_drop ); + } + + if( net_drop < 20 ) { + while( net_drop > 2 ) { + SV_ClientThink( sv_client, &sv_client->lastcmd ); + net_drop--; + } + if( net_drop > 1 ) + SV_ClientThink( sv_client, &oldest ); + + if( net_drop > 0 ) + SV_ClientThink( sv_client, &oldcmd ); + + } + SV_ClientThink( sv_client, &newcmd ); + + sv_client->lastcmd = newcmd; } @@ -928,91 +937,91 @@ SV_NewClientExecuteMove ================== */ static void SV_NewClientExecuteMove( int c, int net_drop ) { - usercmd_t cmds[MAX_PACKET_FRAMES][MAX_PACKET_USERCMDS]; - usercmd_t *lastcmd, *cmd; - int lastframe; - int numCmds[MAX_PACKET_FRAMES], numDups; - int i, j, lightlevel; - - numDups = c >> SVCMD_BITS; - c &= SVCMD_MASK; - - if( numDups >= MAX_PACKET_FRAMES ) { - SV_DropClient( sv_client, "too many frames in packet" ); - return; - } - - if( c == clc_move_nodelta ) { - lastframe = -1; - } else { - lastframe = MSG_ReadLong(); - } + usercmd_t cmds[MAX_PACKET_FRAMES][MAX_PACKET_USERCMDS]; + usercmd_t *lastcmd, *cmd; + int lastframe; + int numCmds[MAX_PACKET_FRAMES], numDups; + int i, j, lightlevel; + + numDups = c >> SVCMD_BITS; + c &= SVCMD_MASK; + + if( numDups >= MAX_PACKET_FRAMES ) { + SV_DropClient( sv_client, "too many frames in packet" ); + return; + } + + if( c == clc_move_nodelta ) { + lastframe = -1; + } else { + lastframe = MSG_ReadLong(); + } SV_SetLastFrame( lastframe ); - lightlevel = MSG_ReadByte(); - - // read all cmds - lastcmd = NULL; - for( i = 0; i <= numDups; i++ ) { - numCmds[i] = MSG_ReadBits( 5 ); - if( numCmds[i] == -1 ) { - SV_DropClient( sv_client, "read past end of message" ); - return; - } - if( numCmds[i] >= MAX_PACKET_USERCMDS ) { - SV_DropClient( sv_client, "too many usercmds in frame" ); - return; - } - for( j = 0; j < numCmds[i]; j++ ) { - if( msg_read.readcount > msg_read.cursize ) { - SV_DropClient( sv_client, "read past end of message" ); - return; - } - cmd = &cmds[i][j]; - MSG_ReadDeltaUsercmd_Enhanced( lastcmd, cmd, sv_client->version ); - cmd->lightlevel = lightlevel; - lastcmd = cmd; - } - } - if( sv_client->state != cs_spawned ) { - sv_client->lastframe = -1; - return; - } - - if( q_unlikely( !lastcmd ) ) { - return; // should never happen - } - - if( net_drop > numDups ) { + lightlevel = MSG_ReadByte(); + + // read all cmds + lastcmd = NULL; + for( i = 0; i <= numDups; i++ ) { + numCmds[i] = MSG_ReadBits( 5 ); + if( numCmds[i] == -1 ) { + SV_DropClient( sv_client, "read past end of message" ); + return; + } + if( numCmds[i] >= MAX_PACKET_USERCMDS ) { + SV_DropClient( sv_client, "too many usercmds in frame" ); + return; + } + for( j = 0; j < numCmds[i]; j++ ) { + if( msg_read.readcount > msg_read.cursize ) { + SV_DropClient( sv_client, "read past end of message" ); + return; + } + cmd = &cmds[i][j]; + MSG_ReadDeltaUsercmd_Enhanced( lastcmd, cmd, sv_client->version ); + cmd->lightlevel = lightlevel; + lastcmd = cmd; + } + } + if( sv_client->state != cs_spawned ) { + sv_client->lastframe = -1; + return; + } + + if( q_unlikely( !lastcmd ) ) { + return; // should never happen + } + + if( net_drop > numDups ) { sv_client->frameflags |= FF_CLIENTPRED; -// Com_DPrintf( "%s: net_drop %i\n", sv_client->name, net_drop ); - } - - if( net_drop < 20 ) { - // run lastcmd multiple times if no backups available - while( net_drop > numDups ) { - SV_ClientThink( sv_client, &sv_client->lastcmd ); - net_drop--; - } - - // run backup cmds, if any - while( net_drop > 0 ) { - i = numDups - net_drop; - for( j = 0; j < numCmds[i]; j++ ) { - SV_ClientThink( sv_client, &cmds[i][j] ); - } - net_drop--; - } - - } - - // run new cmds - for( j = 0; j < numCmds[numDups]; j++ ) { - SV_ClientThink( sv_client, &cmds[numDups][j] ); - } - - sv_client->lastcmd = *lastcmd; +// Com_DPrintf( "%s: net_drop %i\n", sv_client->name, net_drop ); + } + + if( net_drop < 20 ) { + // run lastcmd multiple times if no backups available + while( net_drop > numDups ) { + SV_ClientThink( sv_client, &sv_client->lastcmd ); + net_drop--; + } + + // run backup cmds, if any + while( net_drop > 0 ) { + i = numDups - net_drop; + for( j = 0; j < numCmds[i]; j++ ) { + SV_ClientThink( sv_client, &cmds[i][j] ); + } + net_drop--; + } + + } + + // run new cmds + for( j = 0; j < numCmds[numDups]; j++ ) { + SV_ClientThink( sv_client, &cmds[numDups][j] ); + } + + sv_client->lastcmd = *lastcmd; } /* @@ -1023,153 +1032,151 @@ The current net_message is parsed for the given client =================== */ void SV_ExecuteClientMessage( client_t *client ) { - int c; - char *s; - qboolean move_issued; - int stringCmdCount; - int userinfoUpdateCount; - int net_drop; - - sv_client = client; - sv_player = sv_client->edict; - - // only allow one move command - move_issued = qfalse; - stringCmdCount = 0; - userinfoUpdateCount = 0; - - net_drop = client->netchan->dropped; + int c; + char *s; + qboolean move_issued; + int stringCmdCount; + int userinfoUpdateCount; + int net_drop; + + sv_client = client; + sv_player = sv_client->edict; + + // only allow one move command + move_issued = qfalse; + stringCmdCount = 0; + userinfoUpdateCount = 0; + + net_drop = client->netchan->dropped; if( net_drop > 0 ) { client->frameflags |= FF_CLIENTDROP; } - while( 1 ) { - if( msg_read.readcount > msg_read.cursize ) { - SV_DropClient( client, "read past end of message" ); - break; - } - - c = MSG_ReadByte(); - if( c == -1 ) - break; - - switch( c & SVCMD_MASK ) { - default: - badbyte: - SV_DropClient( client, "unknown command byte" ); - break; - - case clc_nop: - break; - - case clc_userinfo: - s = MSG_ReadString(); - - // malicious users may try sending too many userinfo updates - if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { - Com_DPrintf( "Too many userinfos from %s\n", client->name ); - break; - } - - SV_UpdateUserinfo( s ); - userinfoUpdateCount++; - break; - - case clc_move: - if( move_issued ) { - SV_DropClient( client, "multiple clc_move commands in packet" ); - break; // someone is trying to cheat... - } - - move_issued = qtrue; - - SV_OldClientExecuteMove( net_drop ); - break; - - case clc_stringcmd: - s = MSG_ReadString(); - - Com_DPrintf( "ClientCommand( %s ): %s\n", client->name, s ); - - // malicious users may try using too many string commands - if( stringCmdCount == MAX_PACKET_STRINGCMDS ) { - Com_DPrintf( "Too many stringcmds from %s\n", client->name ); - break; - } - SV_ExecuteUserCommand( s ); - stringCmdCount++; - break; - - // r1q2 specific operations - case clc_setting: { - uint16_t idx, value; - - if( client->protocol < PROTOCOL_VERSION_R1Q2 ) { - goto badbyte; - } - - idx = MSG_ReadShort(); - value = MSG_ReadShort(); - if( idx < CLS_MAX ) { - client->settings[idx] = value; - } - } - break; - - - // q2pro specific operations - case clc_move_nodelta: - case clc_move_batched: - if( client->protocol != PROTOCOL_VERSION_Q2PRO ) { - goto badbyte; - } - - if( move_issued ) { - SV_DropClient( client, "multiple clc_move commands in packet" ); - break; // someone is trying to cheat... - } - - move_issued = qtrue; - SV_NewClientExecuteMove( c, net_drop ); - break; - - case clc_userinfo_delta: { - char *key, *value; - char buffer[MAX_INFO_STRING]; - - if( client->protocol != PROTOCOL_VERSION_Q2PRO ) { - goto badbyte; - } - - key = MSG_ReadString(); - value = MSG_ReadString(); - - // malicious users may try sending too many userinfo updates - if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { - Com_DPrintf( "Too many userinfos from %s\n", client->name ); - break; - } - userinfoUpdateCount++; - - strcpy( buffer, client->userinfo ); - if( !Info_SetValueForKey( buffer, key, value ) ) { - SV_DropClient( client, "malformed delta userinfo" ); - break; - } - - SV_UpdateUserinfo( buffer ); - } - break; - } - - if( client->state < cs_assigned ) { - break; // disconnect command - } - } - - sv_client = NULL; - sv_player = NULL; -} + while( 1 ) { + if( msg_read.readcount > msg_read.cursize ) { + SV_DropClient( client, "read past end of message" ); + break; + } + + c = MSG_ReadByte(); + if( c == -1 ) + break; + + switch( c & SVCMD_MASK ) { + default: + badbyte: + SV_DropClient( client, "unknown command byte" ); + break; + + case clc_nop: + break; + + case clc_userinfo: + s = MSG_ReadString(); + + // malicious users may try sending too many userinfo updates + if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { + Com_DPrintf( "Too many userinfos from %s\n", client->name ); + break; + } + + SV_UpdateUserinfo( s ); + userinfoUpdateCount++; + break; + + case clc_move: + if( move_issued ) { + SV_DropClient( client, "multiple clc_move commands in packet" ); + break; // someone is trying to cheat... + } + + move_issued = qtrue; + + SV_OldClientExecuteMove( net_drop ); + break; + + case clc_stringcmd: + s = MSG_ReadString(); + + Com_DPrintf( "ClientCommand( %s ): %s\n", client->name, s ); + + // malicious users may try using too many string commands + if( stringCmdCount == MAX_PACKET_STRINGCMDS ) { + Com_DPrintf( "Too many stringcmds from %s\n", client->name ); + break; + } + SV_ExecuteUserCommand( s ); + stringCmdCount++; + break; + + // r1q2 specific operations + case clc_setting: { + uint16_t idx, value; + + if( client->protocol < PROTOCOL_VERSION_R1Q2 ) { + goto badbyte; + } + idx = MSG_ReadShort(); + value = MSG_ReadShort(); + if( idx < CLS_MAX ) { + client->settings[idx] = value; + } + } + break; + + + // q2pro specific operations + case clc_move_nodelta: + case clc_move_batched: + if( client->protocol != PROTOCOL_VERSION_Q2PRO ) { + goto badbyte; + } + + if( move_issued ) { + SV_DropClient( client, "multiple clc_move commands in packet" ); + break; // someone is trying to cheat... + } + + move_issued = qtrue; + SV_NewClientExecuteMove( c, net_drop ); + break; + + case clc_userinfo_delta: { + char *key, *value; + char buffer[MAX_INFO_STRING]; + + if( client->protocol != PROTOCOL_VERSION_Q2PRO ) { + goto badbyte; + } + + key = MSG_ReadString(); + value = MSG_ReadString(); + // malicious users may try sending too many userinfo updates + if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { + Com_DPrintf( "Too many userinfos from %s\n", client->name ); + break; + } + userinfoUpdateCount++; + + strcpy( buffer, client->userinfo ); + if( !Info_SetValueForKey( buffer, key, value ) ) { + SV_DropClient( client, "malformed delta userinfo" ); + break; + } + + SV_UpdateUserinfo( buffer ); + } + break; + } + + if( client->state < cs_assigned ) { + break; // disconnect command + } + } + + sv_client = NULL; + sv_player = NULL; +} |