- Add unset command for cvars created by the user

- Fix crash bug when maximum number of cvars has been reached
- Fix cvar_restart
- Add possibility to cleanly switch mods ingame (#2819)
This commit is contained in:
Thilo Schulz 2009-11-09 22:41:42 +00:00
parent 606ce66726
commit 258429efe7
8 changed files with 414 additions and 143 deletions

View file

@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "q_shared.h"
#include "qcommon.h"
cvar_t *cvar_vars;
cvar_t *cvar_vars = NULL;
cvar_t *cvar_cheats;
int cvar_modifiedFlags;
@ -33,7 +33,7 @@ cvar_t cvar_indexes[MAX_CVARS];
int cvar_numIndexes;
#define FILE_HASH_SIZE 256
static cvar_t* hashTable[FILE_HASH_SIZE];
static cvar_t *hashTable[FILE_HASH_SIZE];
cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force);
@ -181,11 +181,14 @@ int Cvar_Flags(const char *var_name)
Cvar_CommandCompletion
============
*/
void Cvar_CommandCompletion( void(*callback)(const char *s) ) {
void Cvar_CommandCompletion(void (*callback)(const char *s))
{
cvar_t *cvar;
for ( cvar = cvar_vars ; cvar ; cvar = cvar->next ) {
callback( cvar->name );
for(cvar = cvar_vars; cvar; cvar = cvar->next)
{
if(cvar->name)
callback(cvar->name);
}
}
@ -304,6 +307,7 @@ The flags will be or'ed in if the variable exists.
cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
cvar_t *var;
long hash;
int index;
if ( !var_name || ! var_value ) {
Com_Error( ERR_FATAL, "Cvar_Get: NULL parameter" );
@ -322,13 +326,15 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
#endif
var = Cvar_FindVar (var_name);
if ( var ) {
var_value = Cvar_Validate( var, var_value, qfalse );
if(var)
{
var_value = Cvar_Validate(var, var_value, qfalse);
// if the C code is now specifying a variable that the user already
// set a value for, take the new value as the reset value
if ( ( var->flags & CVAR_USER_CREATED ) && !( flags & CVAR_USER_CREATED )
&& var_value[0] ) {
if(var->flags & CVAR_USER_CREATED)
{
var->flags &= ~CVAR_USER_CREATED;
Z_Free( var->resetString );
var->resetString = CopyString( var_value );
@ -343,13 +349,22 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
var->latchedString = CopyString(var_value);
}
// ZOID--needs to be set so that cvars the game sets as
// SERVERINFO get sent to clients
cvar_modifiedFlags |= flags;
}
// Make sure the game code cannot mark engine-added variables as gamecode vars
if(var->flags & CVAR_VM_CREATED)
{
if(!(flags & CVAR_VM_CREATED))
var->flags &= ~CVAR_VM_CREATED;
}
else
{
if(flags & CVAR_VM_CREATED)
flags &= ~CVAR_VM_CREATED;
}
var->flags |= flags;
// only allow one non-empty reset string without a warning
if ( !var->resetString[0] ) {
// we don't have a reset string yet
@ -367,6 +382,10 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
var->latchedString = NULL; // otherwise cvar_set2 would free it
Cvar_Set2( var_name, s, qtrue );
Z_Free( s );
// ZOID--needs to be set so that cvars the game sets as
// SERVERINFO get sent to clients
cvar_modifiedFlags |= flags;
}
return var;
@ -375,11 +394,27 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
//
// allocate a new cvar
//
if ( cvar_numIndexes >= MAX_CVARS ) {
Com_Error( ERR_FATAL, "MAX_CVARS" );
// find a free cvar
for(index = 0; index < MAX_CVARS; index++)
{
if(!cvar_indexes[index].name)
break;
}
var = &cvar_indexes[cvar_numIndexes];
cvar_numIndexes++;
if(index >= MAX_CVARS)
{
if(!com_errorEntered)
Com_Error(ERR_FATAL, "Error: Too many cvars, cannot create a new one!");
return NULL;
}
var = &cvar_indexes[index];
if(index >= cvar_numIndexes)
cvar_numIndexes = index + 1;
var->name = CopyString (var_name);
var->string = CopyString (var_value);
var->modified = qtrue;
@ -391,6 +426,10 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
// link the variable in
var->next = cvar_vars;
if(cvar_vars)
cvar_vars->prev = var;
var->prev = NULL;
cvar_vars = var;
var->flags = flags;
@ -398,7 +437,13 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
cvar_modifiedFlags |= var->flags;
hash = generateHashValue(var_name);
var->hashIndex = hash;
var->hashNext = hashTable[hash];
if(hashTable[hash])
hashTable[hash]->hashPrev = var;
var->hashPrev = NULL;
hashTable[hash] = var;
return var;
@ -470,15 +515,23 @@ cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) {
value = var->resetString;
}
value = Cvar_Validate( var, value, qtrue );
value = Cvar_Validate(var, value, qtrue);
if((var->flags & CVAR_LATCH) && var->latchedString) {
if(!strcmp(value,var->latchedString))
if((var->flags & CVAR_LATCH) && var->latchedString)
{
if(!strcmp(value, var->string))
{
Z_Free(var->latchedString);
var->latchedString = NULL;
return var;
}
if(!strcmp(value, var->latchedString))
return var;
}
else if (!strcmp(value,var->string)) {
else if(!strcmp(value, var->string))
return var;
}
// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
cvar_modifiedFlags |= var->flags;
@ -609,12 +662,15 @@ Cvar_SetCheatState
Any testing variables will be reset to the safe values
============
*/
void Cvar_SetCheatState( void ) {
void Cvar_SetCheatState(void)
{
cvar_t *var;
// set all default vars to the safe value
for ( var = cvar_vars ; var ; var = var->next ) {
if ( var->flags & CVAR_CHEAT ) {
for(var = cvar_vars; var ; var = var->next)
{
if(var->flags & CVAR_CHEAT)
{
// the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
// because of a different var->latchedString
if (var->latchedString)
@ -622,9 +678,8 @@ void Cvar_SetCheatState( void ) {
Z_Free(var->latchedString);
var->latchedString = NULL;
}
if (strcmp(var->resetString,var->string)) {
Cvar_Set( var->name, var->resetString );
}
if (strcmp(var->resetString,var->string))
Cvar_Set(var->name, var->resetString);
}
}
}
@ -802,14 +857,16 @@ Appends lines containing "set variable value" for all variables
with the archive flag set to qtrue.
============
*/
void Cvar_WriteVariables( fileHandle_t f ) {
void Cvar_WriteVariables(fileHandle_t f)
{
cvar_t *var;
char buffer[1024];
for (var = cvar_vars ; var ; var = var->next) {
if( Q_stricmp( var->name, "cl_cdkey" ) == 0 ) {
for (var = cvar_vars; var; var = var->next)
{
if(!var->name || Q_stricmp( var->name, "cl_cdkey" ) == 0)
continue;
}
if( var->flags & CVAR_ARCHIVE ) {
// write the latched value, even if it hasn't taken effect yet
if ( var->latchedString ) {
@ -851,7 +908,8 @@ void Cvar_List_f( void ) {
i = 0;
for (var = cvar_vars ; var ; var = var->next, i++)
{
if (match && !Com_Filter(match, var->name, qfalse)) continue;
if(!var->name || (match && !Com_Filter(match, var->name, qfalse)))
continue;
if (var->flags & CVAR_SERVERINFO) {
Com_Printf("S");
@ -906,6 +964,113 @@ void Cvar_List_f( void ) {
Com_Printf ("%i cvar indexes\n", cvar_numIndexes);
}
/*
============
Cvar_Unset
Unsets a cvar
============
*/
cvar_t *Cvar_Unset(cvar_t *cv)
{
cvar_t *next = cv->next;
if(cv->name)
Z_Free(cv->name);
if(cv->string)
Z_Free(cv->string);
if(cv->latchedString)
Z_Free(cv->latchedString);
if(cv->resetString)
Z_Free(cv->resetString);
if(cv->prev)
cv->prev->next = cv->next;
else
cvar_vars = cv->next;
if(cv->next)
cv->next->prev = cv->prev;
if(cv->hashPrev)
cv->hashPrev->hashNext = cv->hashNext;
else
hashTable[cv->hashIndex] = cv->hashNext;
if(cv->hashNext)
cv->hashNext->hashPrev = cv->hashPrev;
Com_Memset(cv, '\0', sizeof(*cv));
return next;
}
/*
============
Cvar_Unset_f
Unsets a userdefined cvar
============
*/
void Cvar_Unset_f(void)
{
cvar_t *cv;
if(Cmd_Argc() != 2)
{
Com_Printf("Usage: %s <varname>\n", Cmd_Argv(0));
return;
}
cv = Cvar_FindVar(Cmd_Argv(1));
if(!cv)
return;
if(cv->flags & CVAR_USER_CREATED)
Cvar_Unset(cv);
else
Com_Printf("Error: %s: Variable %s is not user created.\n", Cmd_Argv(0), cv->name);
}
/*
============
Cvar_Restart
Resets all cvars to their hardcoded values and removes userdefined variables
and variables added via the VMs if requested.
============
*/
void Cvar_Restart(qboolean unsetVM)
{
cvar_t *curvar;
curvar = cvar_vars;
while(curvar)
{
if((curvar->flags & CVAR_USER_CREATED) ||
(unsetVM && (curvar->flags & CVAR_VM_CREATED)))
{
// throw out any variables the user/vm created
curvar = Cvar_Unset(curvar);
continue;
}
if(!(curvar->flags & (CVAR_ROM | CVAR_INIT | CVAR_NORESTART)))
{
// Just reset the rest to their default values.
Cvar_Set2(curvar->name, curvar->resetString, qfalse);
}
curvar = curvar->next;
}
}
/*
============
Cvar_Restart_f
@ -913,69 +1078,29 @@ Cvar_Restart_f
Resets all cvars to their hardcoded values
============
*/
void Cvar_Restart_f( void ) {
cvar_t *var;
cvar_t **prev;
prev = &cvar_vars;
while ( 1 ) {
var = *prev;
if ( !var ) {
break;
}
// don't mess with rom values, or some inter-module
// communication will get broken (com_cl_running, etc)
if ( var->flags & ( CVAR_ROM | CVAR_INIT | CVAR_NORESTART ) ) {
prev = &var->next;
continue;
}
// throw out any variables the user created
if ( var->flags & CVAR_USER_CREATED ) {
*prev = var->next;
if ( var->name ) {
Z_Free( var->name );
}
if ( var->string ) {
Z_Free( var->string );
}
if ( var->latchedString ) {
Z_Free( var->latchedString );
}
if ( var->resetString ) {
Z_Free( var->resetString );
}
// clear the var completely, since we
// can't remove the index from the list
Com_Memset( var, 0, sizeof( var ) );
continue;
}
Cvar_Set( var->name, var->resetString );
prev = &var->next;
}
void Cvar_Restart_f(void)
{
Cvar_Restart(qfalse);
}
/*
=====================
Cvar_InfoString
=====================
*/
char *Cvar_InfoString( int bit ) {
char *Cvar_InfoString(int bit)
{
static char info[MAX_INFO_STRING];
cvar_t *var;
info[0] = 0;
for (var = cvar_vars ; var ; var = var->next) {
if (var->flags & bit) {
for(var = cvar_vars; var; var = var->next)
{
if(var->name && (var->flags & bit))
Info_SetValueForKey (info, var->name, var->string);
}
}
return info;
}
@ -986,16 +1111,17 @@ Cvar_InfoString_Big
handles large info strings ( CS_SYSTEMINFO )
=====================
*/
char *Cvar_InfoString_Big( int bit ) {
char *Cvar_InfoString_Big(int bit)
{
static char info[BIG_INFO_STRING];
cvar_t *var;
info[0] = 0;
for (var = cvar_vars ; var ; var = var->next) {
if (var->flags & bit) {
for (var = cvar_vars; var; var = var->next)
{
if(var->name && (var->flags & bit))
Info_SetValueForKey_Big (info, var->name, var->string);
}
}
return info;
}
@ -1034,13 +1160,15 @@ Cvar_Register
basically a slightly modified Cvar_Get for the interpreted modules
=====================
*/
void Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {
void Cvar_Register(vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags)
{
cvar_t *cv;
cv = Cvar_Get( varName, defaultValue, flags );
if ( !vmCvar ) {
cv = Cvar_Get(varName, defaultValue, flags | CVAR_VM_CREATED);
if (!vmCvar)
return;
}
vmCvar->handle = cv - cvar_indexes;
vmCvar->modificationCount = -1;
Cvar_Update( vmCvar );
@ -1105,7 +1233,11 @@ Cvar_Init
Reads in all archived cvars
============
*/
void Cvar_Init (void) {
void Cvar_Init (void)
{
Com_Memset(cvar_indexes, '\0', sizeof(cvar_indexes));
Com_Memset(hashTable, '\0', sizeof(hashTable));
cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_ROM | CVAR_SYSTEMINFO );
Cmd_AddCommand ("print", Cvar_Print_f);
@ -1121,6 +1253,9 @@ void Cvar_Init (void) {
Cmd_SetCommandCompletionFunc( "seta", Cvar_CompleteCvarName );
Cmd_AddCommand ("reset", Cvar_Reset_f);
Cmd_SetCommandCompletionFunc( "reset", Cvar_CompleteCvarName );
Cmd_AddCommand ("unset", Cvar_Unset_f);
Cmd_SetCommandCompletionFunc("unset", Cvar_CompleteCvarName);
Cmd_AddCommand ("cvarlist", Cvar_List_f);
Cmd_AddCommand ("cvar_restart", Cvar_Restart_f);
}