/* * Cvar_FixCheatVars * * All cheat variables with be reset to default unless cheats are allowed */ void Cvar_FixCheatVars( void ) { struct trie_dump_s *dump; unsigned int i; cvar_flag_t flags = CVAR_CHEAT; if( Cvar_CheatsAllowed() ) return; assert( cvar_trie ); Trie_DumpIf( cvar_trie, "", TRIE_DUMP_VALUES, Cvar_HasFlags, &flags, &dump ); for( i = 0; i < dump->size; ++i ) { cvar_t *const var = (cvar_t *) dump->key_value_vector[i].value; Mem_ZoneFree( var->string ); var->string = ZoneCopyString( var->dvalue ); var->value = atof( var->string ); var->integer = Q_rint( var->value ); } Trie_FreeDump( dump ); }
/* * Key_SetBinding */ void Key_SetBinding( int keynum, const char *binding ) { if( keynum == -1 ) return; // free old bindings if( keybindings[keynum] ) { if( !Q_stricmp( keybindings[keynum], "toggleconsole" ) ) consolebinded--; Mem_ZoneFree( keybindings[keynum] ); keybindings[keynum] = NULL; } if( !binding ) return; // allocate memory for new binding keybindings[keynum] = ZoneCopyString( binding ); if( !Q_stricmp( keybindings[keynum], "toggleconsole" ) ) consolebinded++; }
/* * CL_ParseServerData */ static void CL_ParseServerData( msg_t *msg ) { const char *str, *gamedir; int i, sv_bitflags, numpure; int http_portnum; Com_DPrintf( "Serverdata packet received.\n" ); // wipe the client_state_t struct CL_ClearState(); CL_SetClientState( CA_CONNECTED ); // parse protocol version number i = MSG_ReadLong( msg ); if( i != APP_PROTOCOL_VERSION ) Com_Error( ERR_DROP, "Server returned version %i, not %i", i, APP_PROTOCOL_VERSION ); cl.servercount = MSG_ReadLong( msg ); cl.snapFrameTime = (unsigned int)MSG_ReadShort( msg ); // set extrapolation time to half snapshot time Cvar_ForceSet( "cl_extrapolationTime", va( "%i", (unsigned int)( cl.snapFrameTime * 0.5 ) ) ); cl_extrapolationTime->modified = qfalse; // base game directory str = MSG_ReadString( msg ); if( !str || !str[0] ) Com_Error( ERR_DROP, "Server sent an empty base game directory" ); if( !COM_ValidateRelativeFilename( str ) || strchr( str, '/' ) ) Com_Error( ERR_DROP, "Server sent an invalid base game directory: %s", str ); if( strcmp( FS_BaseGameDirectory(), str ) ) { Com_Error( ERR_DROP, "Server has different base game directory (%s) than the client (%s)", str, FS_BaseGameDirectory() ); } // game directory str = MSG_ReadString( msg ); if( !str || !str[0] ) Com_Error( ERR_DROP, "Server sent an empty game directory" ); if( !COM_ValidateRelativeFilename( str ) || strchr( str, '/' ) ) Com_Error( ERR_DROP, "Server sent an invalid game directory: %s", str ); gamedir = FS_GameDirectory(); if( strcmp( str, gamedir ) ) { // shutdown the cgame module first in case it is running for whatever reason // (happens on wswtv in lobby), otherwise precaches that are going to follow // will probably f**k up (like models trying to load before the world model) CL_GameModule_Shutdown(); if( !FS_SetGameDirectory( str, qtrue ) ) Com_Error( ERR_DROP, "Failed to load game directory set by server: %s", str ); ML_Restart( qtrue ); } // parse player entity number cl.playernum = MSG_ReadShort( msg ); // get the full level name Q_strncpyz( cl.servermessage, MSG_ReadString( msg ), sizeof( cl.servermessage ) ); sv_bitflags = MSG_ReadByte( msg ); if( cls.demo.playing ) { cls.reliable = ( sv_bitflags & SV_BITFLAGS_RELIABLE ); } else { if( cls.reliable != ( ( sv_bitflags & SV_BITFLAGS_RELIABLE ) != 0 ) ) Com_Error( ERR_DROP, "Server and client disagree about connection reliability" ); } // builting HTTP server port if( cls.httpbaseurl ) { Mem_Free( cls.httpbaseurl ); cls.httpbaseurl = NULL; } if( ( sv_bitflags & SV_BITFLAGS_HTTP ) != 0 ) { if( ( sv_bitflags & SV_BITFLAGS_HTTP_BASEURL ) != 0 ) { // read base upstream url cls.httpbaseurl = ZoneCopyString( MSG_ReadString( msg ) ); } else { http_portnum = MSG_ReadShort( msg ) & 0xffff; cls.httpaddress = cls.serveraddress; if( cls.httpaddress.type == NA_IP6 ) { cls.httpaddress.address.ipv6.port = BigShort( http_portnum ); } else { cls.httpaddress.address.ipv4.port = BigShort( http_portnum ); } if( http_portnum ) { if( cls.httpaddress.type == NA_LOOPBACK ) { cls.httpbaseurl = ZoneCopyString( va( "http://localhost:%hu/", http_portnum ) ); } else { cls.httpbaseurl = ZoneCopyString( va( "http://%s/", NET_AddressToString( &cls.httpaddress ) ) ); } } } } // pure list // clean old, if necessary Com_FreePureList( &cls.purelist ); // add new numpure = MSG_ReadShort( msg ); while( numpure > 0 ) { const char *pakname = MSG_ReadString( msg ); const unsigned checksum = MSG_ReadLong( msg ); Com_AddPakToPureList( &cls.purelist, pakname, checksum, NULL ); numpure--; } //assert( numpure == 0 ); // get the configstrings request CL_AddReliableCommand( va( "configstrings %i 0", cl.servercount ) ); cls.sv_pure = ( sv_bitflags & SV_BITFLAGS_PURE ) != 0; cls.sv_tv = ( sv_bitflags & SV_BITFLAGS_TVSERVER ) != 0; #ifdef PURE_CHEAT cls.sv_pure = qfalse; #endif // separate the printfs so the server message can have a color Com_Printf( S_COLOR_WHITE "\n" "=====================================\n" ); Com_Printf( S_COLOR_WHITE "%s\n\n", cl.servermessage ); }
/* * CL_InitDownload_f * * Hanldles server's initdownload message, starts web or server download if possible */ static void CL_InitDownload_f( void ) { const char *filename; const char *url; int size, alloc_size; unsigned checksum; qboolean allow_localhttpdownload; download_list_t *dl; // ignore download commands coming from demo files if( cls.demo.playing ) return; // read the data filename = Cmd_Argv( 1 ); size = atoi( Cmd_Argv( 2 ) ); checksum = strtoul( Cmd_Argv( 3 ), NULL, 10 ); allow_localhttpdownload = ( atoi( Cmd_Argv( 4 ) ) != 0 ) && cls.httpbaseurl != NULL; url = Cmd_Argv( 5 ); if( !cls.download.requestname ) { Com_Printf( "Got init download message without request\n" ); return; } if( cls.download.filenum || cls.download.web ) { Com_Printf( "Got init download message while already downloading\n" ); return; } if( size == -1 ) { // means that download was refused Com_Printf( "Server refused download request: %s\n", url ); // if it's refused, url field holds the reason CL_DownloadDone(); return; } if( size <= 0 ) { Com_Printf( "Server gave invalid size, not downloading\n" ); CL_DownloadDone(); return; } if( checksum == 0 ) { Com_Printf( "Server didn't provide checksum, not downloading\n" ); CL_DownloadDone(); return; } if( !COM_ValidateRelativeFilename( filename ) ) { Com_Printf( "Not downloading, invalid filename: %s\n", filename ); CL_DownloadDone(); return; } if( FS_CheckPakExtension( filename ) && !cls.download.requestpak ) { Com_Printf( "Got a pak file when requesting normal one, not downloading\n" ); CL_DownloadDone(); return; } if( !FS_CheckPakExtension( filename ) && cls.download.requestpak ) { Com_Printf( "Got a non pak file when requesting pak, not downloading\n" ); CL_DownloadDone(); return; } if( !strchr( filename, '/' ) ) { Com_Printf( "Refusing to download file with no gamedir: %s\n", filename ); CL_DownloadDone(); return; } // check that it is in game or basegame dir if( strlen( filename ) < strlen( FS_GameDirectory() )+1 || strncmp( filename, FS_GameDirectory(), strlen( FS_GameDirectory() ) ) || filename[strlen( FS_GameDirectory() )] != '/' ) { if( strlen( filename ) < strlen( FS_BaseGameDirectory() )+1 || strncmp( filename, FS_BaseGameDirectory(), strlen( FS_BaseGameDirectory() ) ) || filename[strlen( FS_BaseGameDirectory() )] != '/' ) { Com_Printf( "Can't download, invalid game directory: %s\n", filename ); CL_DownloadDone(); return; } } if( FS_CheckPakExtension( filename ) ) { if( strchr( strchr( filename, '/' ) + 1, '/' ) ) { Com_Printf( "Refusing to download pack file to subdirectory: %s\n", filename ); CL_DownloadDone(); return; } if( !Q_strnicmp( COM_FileBase( filename ), "modules", strlen( "modules" ) ) ) { if( !CL_CanDownloadModules() ) { CL_DownloadDone(); return; } } if( FS_FOpenBaseFile( filename, NULL, FS_READ ) != -1 ) { Com_Printf( "Can't download, file already exists: %s\n", filename ); CL_DownloadDone(); return; } } else { if( strcmp( cls.download.requestname, strchr( filename, '/' ) + 1 ) ) { Com_Printf( "Can't download, got different file than requested: %s\n", filename ); CL_DownloadDone(); return; } } if( cls.download.requestnext ) { dl = cls.download.list; while( dl != NULL ) { if( !Q_stricmp( dl->filename, filename ) ) { Com_Printf( "Skipping, already tried downloading: %s\n", filename ); CL_DownloadDone(); return; } dl = dl->next; } } cls.download.name = ZoneCopyString( filename ); alloc_size = strlen( filename ) + strlen( ".tmp" ) + 1; cls.download.tempname = Mem_ZoneMalloc( alloc_size ); Q_snprintfz( cls.download.tempname, alloc_size, "%s.tmp", filename ); cls.download.web = qfalse; cls.download.cancelled = qfalse; cls.download.disconnect = qfalse; cls.download.size = size; cls.download.checksum = checksum; cls.download.percent = 0; cls.download.timeout = 0; cls.download.retries = 0; cls.download.timestart = Sys_Milliseconds(); cls.download.offset = 0; cls.download.baseoffset = 0; cls.download.pending_reconnect = qfalse; Cvar_ForceSet( "cl_download_name", COM_FileBase( cls.download.name ) ); Cvar_ForceSet( "cl_download_percent", "0" ); if( cls.download.requestnext ) { dl = Mem_ZoneMalloc( sizeof( download_list_t ) ); dl->filename = ZoneCopyString( cls.download.name ); dl->next = cls.download.list; cls.download.list = dl; } if( cl_downloads_from_web->integer && allow_localhttpdownload && url && url[0] != 0 ) { cls.download.web = qtrue; Com_Printf( "Web download: %s from %s%s\n", cls.download.tempname, cls.httpbaseurl, url ); } else if( cl_downloads_from_web->integer && url && url[0] != 0 ) { cls.download.web = qtrue; Com_Printf( "Web download: %s from %s\n", cls.download.tempname, url ); } else { Com_Printf( "Server download: %s\n", cls.download.tempname ); } cls.download.baseoffset = cls.download.offset = FS_FOpenBaseFile( cls.download.tempname, &cls.download.filenum, FS_APPEND ); if( !cls.download.filenum ) { Com_Printf( "Can't download, couldn't open %s for writing\n", cls.download.tempname ); Mem_ZoneFree( cls.download.name ); cls.download.name = NULL; Mem_ZoneFree( cls.download.tempname ); cls.download.tempname = NULL; cls.download.filenum = 0; cls.download.offset = 0; cls.download.size = 0; CL_DownloadDone(); return; } if( cls.download.web ) { char *referer, *fullurl; const char *headers[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; alloc_size = strlen( APP_URI_SCHEME ) + strlen( NET_AddressToString( &cls.serveraddress ) ) + 1; referer = Mem_ZoneMalloc( alloc_size ); Q_snprintfz( referer, alloc_size, APP_URI_SCHEME "%s", NET_AddressToString( &cls.serveraddress ) ); Q_strlwr( referer ); if( allow_localhttpdownload ) { alloc_size = strlen( cls.httpbaseurl ) + 1 + strlen( url ) + 1; fullurl = Mem_ZoneMalloc( alloc_size ); Q_snprintfz( fullurl, alloc_size, "%s/%s", cls.httpbaseurl, url ); } else { size_t url_len = strlen( url ); alloc_size = url_len + 1 + strlen( filename ) * 3 + 1; fullurl = Mem_ZoneMalloc( alloc_size ); Q_snprintfz( fullurl, alloc_size, "%s/", url ); Q_urlencode_unsafechars( filename, fullurl + url_len + 1, alloc_size - url_len - 1 ); } headers[0] = "Referer"; headers[1] = referer; CL_AddSessionHttpRequestHeaders( fullurl, &headers[2] ); CL_AsyncStreamRequest( fullurl, headers, cl_downloads_from_web_timeout->integer / 100, cls.download.offset, CL_WebDownloadReadCb, CL_WebDownloadDoneCb, NULL, NULL, qfalse ); Mem_ZoneFree( fullurl ); Mem_ZoneFree( referer ); return; } // have to use Sys_Milliseconds because cls.realtime might be old from Web_Get cls.download.timeout = Sys_Milliseconds() + 3000; cls.download.retries = 0; CL_AddReliableCommand( va( "nextdl \"%s\" %i", cls.download.name, cls.download.offset ) ); }
/* * Cvar_Get * Creates the variable if it doesn't exist. * If the variable already exists, the value will not be set * The flags will be or'ed and default value overwritten in if the variable exists. */ cvar_t *Cvar_Get( const char *var_name, const char *var_value, cvar_flag_t flags ) { cvar_t *var; if( !var_name || !var_name[0] ) return NULL; if( Cvar_FlagIsSet( flags, CVAR_USERINFO ) || Cvar_FlagIsSet( flags, CVAR_SERVERINFO ) ) { if( !Cvar_InfoValidate( var_name, qtrue ) ) { Com_Printf( "invalid info cvar name\n" ); return NULL; } } assert( cvar_trie ); Trie_Find( cvar_trie, var_name, TRIE_EXACT_MATCH, (void **)&var ); if( var ) { assert( var_value ); if( !var->dvalue || strcmp( var->dvalue, var_value ) ) { if( var->dvalue ) Mem_ZoneFree( var->dvalue ); // free the old default value string var->dvalue = ZoneCopyString( (char *) var_value ); } #ifdef PUBLIC_BUILD if( Cvar_FlagIsSet( flags, CVAR_READONLY ) || Cvar_FlagIsSet( flags, CVAR_DEVELOPER ) ) { #else if( Cvar_FlagIsSet( flags, CVAR_READONLY ) ) { #endif if( !var->string || strcmp( var->string, var_value ) ) { if( var->string ) Mem_ZoneFree( var->string ); var->string = ZoneCopyString( (char *) var_value ); var->value = atof( var->string ); var->integer = Q_rint( var->value ); } var->flags = flags; } if( Cvar_FlagIsSet( flags, CVAR_USERINFO ) && !Cvar_FlagIsSet( var->flags, CVAR_USERINFO ) ) userinfo_modified = qtrue; // transmit at next oportunity Cvar_FlagSet( &var->flags, flags ); return var; } if( !var_value ) return NULL; if( Cvar_FlagIsSet( flags, CVAR_USERINFO ) || Cvar_FlagIsSet( flags, CVAR_SERVERINFO ) ) { if( !Cvar_InfoValidate( var_value, qfalse ) ) { Com_Printf( "invalid info cvar value\n" ); return NULL; } } var = Mem_ZoneMalloc( (int)( sizeof( *var ) + strlen( var_name ) + 1 ) ); var->name = (char *)( (qbyte *)var + sizeof( *var ) ); strcpy( var->name, var_name ); var->dvalue = ZoneCopyString( (char *) var_value ); var->string = ZoneCopyString( (char *) var_value ); Cvar_SetModified( var ); var->value = atof( var->string ); var->integer = Q_rint( var->value ); var->flags = flags; Trie_Insert( cvar_trie, var_name, var ); return var; } /* * Cvar_Set2 */ static cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) { cvar_t *var = Cvar_Find( var_name ); if( !var ) { // create it return Cvar_Get( var_name, value, 0 ); } if( Cvar_FlagIsSet( var->flags, CVAR_USERINFO ) || Cvar_FlagIsSet( var->flags, CVAR_SERVERINFO ) ) { if( !Cvar_InfoValidate( value, qfalse ) ) { Com_Printf( "invalid info cvar value\n" ); return var; } } if( !force ) { #ifdef PUBLIC_BUILD if( Cvar_FlagIsSet( var->flags, CVAR_NOSET ) || Cvar_FlagIsSet( var->flags, CVAR_READONLY ) || Cvar_FlagIsSet( var->flags, CVAR_DEVELOPER ) ) { #else if( Cvar_FlagIsSet( var->flags, CVAR_NOSET ) || Cvar_FlagIsSet( var->flags, CVAR_READONLY ) ) { #endif Com_Printf( "%s is write protected.\n", var_name ); return var; } if( Cvar_FlagIsSet( var->flags, CVAR_CHEAT ) && strcmp( value, var->dvalue ) ) { if( !Cvar_CheatsAllowed() ) { Com_Printf( "%s is cheat protected.\n", var_name ); return var; } } if( Cvar_FlagIsSet( var->flags, CVAR_LATCH ) || Cvar_FlagIsSet( var->flags, CVAR_LATCH_VIDEO ) || Cvar_FlagIsSet( var->flags, CVAR_LATCH_SOUND ) ) { if( var->latched_string ) { if( !strcmp( value, var->latched_string ) ) return var; Mem_ZoneFree( var->latched_string ); } else { if( !strcmp( value, var->string ) ) return var; } if( Com_ServerState() ) { Com_Printf( "%s will be changed upon restarting.\n", var->name ); var->latched_string = ZoneCopyString( (char *) value ); } else { if( Cvar_FlagIsSet( var->flags, CVAR_LATCH_VIDEO ) ) { Com_Printf( "%s will be changed upon restarting video.\n", var->name ); var->latched_string = ZoneCopyString( (char *) value ); } else if( Cvar_FlagIsSet( var->flags, CVAR_LATCH_SOUND ) ) { Com_Printf( "%s will be changed upon restarting sound.\n", var->name ); var->latched_string = ZoneCopyString( (char *) value ); } else { if( !strcmp( var->name, "fs_game" ) ) { FS_SetGameDirectory( value, qfalse ); return var; } Mem_ZoneFree( var->string ); // free the old value string var->string = ZoneCopyString( value ); var->value = atof( var->string ); var->integer = Q_rint( var->value ); Cvar_SetModified( var ); } } return var; } } else { if( var->latched_string ) { Mem_ZoneFree( var->latched_string ); var->latched_string = NULL; } } if( !strcmp( value, var->string ) ) return var; // not changed Cvar_SetModified( var ); if( Cvar_FlagIsSet( var->flags, CVAR_USERINFO ) ) userinfo_modified = qtrue; // transmit at next oportunity Mem_ZoneFree( var->string ); // free the old value string var->string = ZoneCopyString( (char *) value ); var->value = atof( var->string ); var->integer = Q_rint( var->value ); return var; } /* * Cvar_ForceSet * Set the variable even if NOSET or LATCH */ cvar_t *Cvar_ForceSet( const char *var_name, const char *value ) { return Cvar_Set2( var_name, value, qtrue ); } /* * Cvar_Set * Create the variable if it doesn't exist */ cvar_t *Cvar_Set( const char *var_name, const char *value ) { return Cvar_Set2( var_name, value, qfalse ); } /* * Cvar_FullSet */ cvar_t *Cvar_FullSet( const char *var_name, const char *value, cvar_flag_t flags, qboolean overwrite_flags ) { cvar_t *var; var = Cvar_Find( var_name ); if( !var ) return Cvar_Get( var_name, value, flags ); if( overwrite_flags ) { var->flags = flags; } else { Cvar_FlagSet( &var->flags, flags ); } // if we overwrite the flags, we will also force the value return Cvar_Set2( var_name, value, overwrite_flags ); }