X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=cmd.c;h=ba6aec5bd6c19385818b05310e795041f83058a3;hb=fa69b3e45b5cf486826fcb9d5865159706c6f0e9;hp=8efe3dc9a0e69290ebf36383366b94ed89130b1f;hpb=66a10ad8f7213d8969fc53f69f1ff712f3aea004;p=xonotic%2Fdarkplaces.git diff --git a/cmd.c b/cmd.c index 8efe3dc9..ba6aec5b 100644 --- a/cmd.c +++ b/cmd.c @@ -177,9 +177,6 @@ static sizebuf_t cmd_text; static unsigned char cmd_text_buf[CMDBUFSIZE]; void *cmd_text_mutex = NULL; -#define Cbuf_LockThreadMutex() (cmd_text_mutex ? Thread_LockMutex(cmd_text_mutex),1 : 0) -#define Cbuf_UnlockThreadMutex() (cmd_text_mutex ? Thread_UnlockMutex(cmd_text_mutex),1 : 0) - /* ============ Cbuf_AddText @@ -275,7 +272,7 @@ static void Cbuf_Execute_Deferred (void) Cbuf_Execute ============ */ -static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ); +static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ); void Cbuf_Execute (void) { int i; @@ -289,7 +286,6 @@ void Cbuf_Execute (void) // LordHavoc: making sure the tokenizebuffer doesn't get filled up by repeated crashes cmd_tokenizebufferpos = 0; - Cbuf_Execute_Deferred(); while (cmd_text.cursize) { // find a \n or ; line break @@ -361,8 +357,8 @@ void Cbuf_Execute (void) (strncmp(firstchar, "in_bind", 7) || !ISWHITESPACE(firstchar[7])) ) { - Cmd_PreprocessString( line, preprocessed, sizeof(preprocessed), NULL ); - Cmd_ExecuteString (preprocessed, src_command, false); + if(Cmd_PreprocessString( line, preprocessed, sizeof(preprocessed), NULL )) + Cmd_ExecuteString (preprocessed, src_command, false); } else { @@ -378,6 +374,17 @@ void Cbuf_Execute (void) } } +void Cbuf_Frame(void) +{ + Cbuf_Execute_Deferred(); + if (cmd_text.cursize) + { + SV_LockThreadMutex(); + Cbuf_Execute(); + SV_UnlockThreadMutex(); + } +} + /* ============================================================================== @@ -453,7 +460,8 @@ static void Cmd_StuffCmds_f (void) static void Cmd_Exec(const char *filename) { char *f; - qboolean isdefaultcfg = strlen(filename) >= 11 && !strcmp(filename + strlen(filename) - 11, "default.cfg"); + size_t filenameLen = strlen(filename); + qboolean isdefaultcfg = filenameLen >= 11 && !strcmp(filename + filenameLen - 11, "default.cfg"); if (!strcmp(filename, "config.cfg")) { @@ -487,23 +495,204 @@ static void Cmd_Exec(const char *filename) // special defaults for specific games go here, these execute before default.cfg // Nehahra pushable crates malfunction in some levels if this is on // Nehahra NPC AI is confused by blowupfallenzombies - if (gamemode == GAME_NEHAHRA) - Cbuf_InsertText("\nsv_gameplayfix_upwardvelocityclearsongroundflag 0\nsv_gameplayfix_blowupfallenzombies 0\n\n"); + switch(gamemode) + { + case GAME_NORMAL: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.01388889\n" +"r_shadow_gloss 1\n" +"r_shadow_bumpscale_basetexture 0\n" + ); + break; + case GAME_NEHAHRA: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.01388889\n" +"r_shadow_gloss 1\n" +"r_shadow_bumpscale_basetexture 0\n" + ); + break; // hipnotic mission pack has issues in their 'friendly monster' ai, which seem to attempt to attack themselves for some reason when findradius() returns non-solid entities. // hipnotic mission pack has issues with bobbing water entities 'jittering' between different heights on alternate frames at the default 0.0138889 ticrate, 0.02 avoids this issue // hipnotic mission pack has issues in their proximity mine sticking code, which causes them to bounce off. - if (gamemode == GAME_HIPNOTIC) - Cbuf_InsertText("\nsv_gameplayfix_blowupfallenzombies 0\nsys_ticrate 0.02\nsv_gameplayfix_slidemoveprojectiles 0\n\n"); + case GAME_HIPNOTIC: + case GAME_QUOTH: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.02\n" +"r_shadow_gloss 1\n" +"r_shadow_bumpscale_basetexture 0\n" + ); + break; // rogue mission pack has a guardian boss that does not wake up if findradius returns one of the entities around its spawn area - if (gamemode == GAME_ROGUE) - Cbuf_InsertText("\nsv_gameplayfix_findradiusdistancetobox 0\n\n"); - if (gamemode == GAME_NEXUIZ) - Cbuf_InsertText("\nsv_gameplayfix_q2airaccelerate 1\nsv_gameplayfix_stepmultipletimes 1\n\n"); - if (gamemode == GAME_TENEBRAE) - Cbuf_InsertText("\nr_shadow_gloss 2\nr_shadow_bumpscale_basetexture 4\n\n"); + case GAME_ROGUE: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.01388889\n" +"r_shadow_gloss 1\n" +"r_shadow_bumpscale_basetexture 0\n" + ); + break; + case GAME_TENEBRAE: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.01388889\n" +"r_shadow_gloss 2\n" +"r_shadow_bumpscale_basetexture 4\n" + ); + break; + case GAME_NEXUIZ: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 1\n" +"sv_gameplayfix_findradiusdistancetobox 1\n" +"sv_gameplayfix_grenadebouncedownslopes 1\n" +"sv_gameplayfix_slidemoveprojectiles 1\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 1\n" +"sv_gameplayfix_setmodelrealbox 1\n" +"sv_gameplayfix_droptofloorstartsolid 1\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 1\n" +"sv_gameplayfix_noairborncorpse 1\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 1\n" +"sv_gameplayfix_easierwaterjump 1\n" +"sv_gameplayfix_delayprojectiles 1\n" +"sv_gameplayfix_multiplethinksperframe 1\n" +"sv_gameplayfix_fixedcheckwatertransition 1\n" +"sv_gameplayfix_q1bsptracelinereportstexture 1\n" +"sv_gameplayfix_swiminbmodels 1\n" +"sv_gameplayfix_downtracesupportsongroundflag 1\n" +"sys_ticrate 0.01388889\n" +"sv_gameplayfix_q2airaccelerate 1\n" +"sv_gameplayfix_stepmultipletimes 1\n" + ); + break; // Steel Storm: Burning Retribution csqc misinterprets CSQC_InputEvent if type is a value other than 0 or 1 - if (gamemode == GAME_STEELSTORM) - Cbuf_InsertText("\ncl_csqc_generatemousemoveevents 0\n\n"); + case GAME_STEELSTORM: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 1\n" +"sv_gameplayfix_findradiusdistancetobox 1\n" +"sv_gameplayfix_grenadebouncedownslopes 1\n" +"sv_gameplayfix_slidemoveprojectiles 1\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 1\n" +"sv_gameplayfix_setmodelrealbox 1\n" +"sv_gameplayfix_droptofloorstartsolid 1\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 1\n" +"sv_gameplayfix_noairborncorpse 1\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 1\n" +"sv_gameplayfix_easierwaterjump 1\n" +"sv_gameplayfix_delayprojectiles 1\n" +"sv_gameplayfix_multiplethinksperframe 1\n" +"sv_gameplayfix_fixedcheckwatertransition 1\n" +"sv_gameplayfix_q1bsptracelinereportstexture 1\n" +"sv_gameplayfix_swiminbmodels 1\n" +"sv_gameplayfix_downtracesupportsongroundflag 1\n" +"sys_ticrate 0.01388889\n" +"cl_csqc_generatemousemoveevents 0\n" + ); + break; + default: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 1\n" +"sv_gameplayfix_findradiusdistancetobox 1\n" +"sv_gameplayfix_grenadebouncedownslopes 1\n" +"sv_gameplayfix_slidemoveprojectiles 1\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 1\n" +"sv_gameplayfix_setmodelrealbox 1\n" +"sv_gameplayfix_droptofloorstartsolid 1\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 1\n" +"sv_gameplayfix_noairborncorpse 1\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 1\n" +"sv_gameplayfix_easierwaterjump 1\n" +"sv_gameplayfix_delayprojectiles 1\n" +"sv_gameplayfix_multiplethinksperframe 1\n" +"sv_gameplayfix_fixedcheckwatertransition 1\n" +"sv_gameplayfix_q1bsptracelinereportstexture 1\n" +"sv_gameplayfix_swiminbmodels 1\n" +"sv_gameplayfix_downtracesupportsongroundflag 1\n" +"sys_ticrate 0.01388889\n" + ); + break; + } } } @@ -910,9 +1099,11 @@ static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t * { static char varname[MAX_INPUTLINE]; // cmd_mutex static char varval[MAX_INPUTLINE]; // cmd_mutex - const char *varstr; + const char *varstr = NULL; char *varfunc; -static char asis[] = "asis"; // just to suppress const char warnings + qboolean required = false; + qboolean optional = false; + static char asis[] = "asis"; // just to suppress const char warnings if(varlen >= MAX_INPUTLINE) varlen = MAX_INPUTLINE - 1; @@ -929,10 +1120,37 @@ static char asis[] = "asis"; // just to suppress const char warnings if(*var == 0) { // empty cvar name? - return NULL; + if(alias) + Con_Printf("Warning: Could not expand $ in alias %s\n", alias->name); + else + Con_Printf("Warning: Could not expand $\n"); + return "$"; } - varstr = NULL; + if(varfunc) + { + char *p; + // ? means optional + while((p = strchr(varfunc, '?'))) + { + optional = true; + memmove(p, p+1, strlen(p)); // with final NUL + } + // ! means required + while((p = strchr(varfunc, '!'))) + { + required = true; + memmove(p, p+1, strlen(p)); // with final NUL + } + // kill spaces + while((p = strchr(varfunc, ' '))) + { + memmove(p, p+1, strlen(p)); // with final NUL + } + // if no function is left, NULL it + if(!*varfunc) + varfunc = NULL; + } if(varname[0] == '$') varstr = Cmd_GetDirectCvarValue(Cmd_GetDirectCvarValue(varname + 1, alias, NULL), alias, NULL); @@ -948,11 +1166,27 @@ static char asis[] = "asis"; // just to suppress const char warnings if(!varstr) { - if(alias) - Con_Printf("Warning: Could not expand $%s in alias %s\n", varname, alias->name); + if(required) + { + if(alias) + Con_Printf("Error: Could not expand $%s in alias %s\n", varname, alias->name); + else + Con_Printf("Error: Could not expand $%s\n", varname); + return NULL; + } + else if(optional) + { + return ""; + } else - Con_Printf("Warning: Could not expand $%s\n", varname); - return NULL; + { + if(alias) + Con_Printf("Warning: Could not expand $%s in alias %s\n", varname, alias->name); + else + Con_Printf("Warning: Could not expand $%s\n", varname); + dpsnprintf(varval, sizeof(varval), "$%s", varname); + return varval; + } } if(!varfunc || !strcmp(varfunc, "q")) // note: quoted form is default, use "asis" to override! @@ -977,7 +1211,7 @@ Cmd_PreprocessString Preprocesses strings and replaces $*, $param#, $cvar accordingly. Also strips comments. */ -static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ) { +static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ) { const char *in; size_t eat, varlen; unsigned outlen; @@ -985,7 +1219,7 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma // don't crash if there's no room in the outtext buffer if( maxoutlen == 0 ) { - return; + return false; } maxoutlen--; // because of \0 @@ -1006,6 +1240,10 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma // that way) // - ${var asis} inserts the cvar value as is, without doing this // quoting + // - ${var ?} silently expands to the empty string if + // $var does not exist + // - ${var !} fails expansion and executes nothing if + // $var does not exist // - prefix the cvar name with a dollar sign to do indirection; // for example, if $x has the value timelimit, ${$x} will return // the value of $timelimit @@ -1016,6 +1254,7 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma // parameters, without extra quoting, so one can use $* to just // pass all parameters around. All parameters starting from $n // can be referred to as $n- (so $* is equivalent to $1-). + // - ${* q} and ${n- q} force quoting anyway // // Note: when expanding an alias, cvar expansion is done in the SAME step // as alias expansion so that alias parameters or cvar values containing @@ -1052,6 +1291,8 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma if(in[varlen + 1] == '}') { val = Cmd_GetCvarValue(in + 1, varlen, alias); + if(!val) + return false; eat = varlen + 2; } else @@ -1063,6 +1304,8 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma } else { varlen = strspn(in, "#*0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"); val = Cmd_GetCvarValue(in, varlen, alias); + if(!val) + return false; eat = varlen; } if(val) @@ -1087,6 +1330,7 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma outtext[outlen++] = *in++; } outtext[outlen] = 0; + return true; } /* @@ -1100,7 +1344,9 @@ static void Cmd_ExecuteAlias (cmdalias_t *alias) { static char buffer[ MAX_INPUTLINE ]; // cmd_mutex static char buffer2[ MAX_INPUTLINE ]; // cmd_mutex - Cmd_PreprocessString( alias->value, buffer, sizeof(buffer) - 2, alias ); + qboolean ret = Cmd_PreprocessString( alias->value, buffer, sizeof(buffer) - 2, alias ); + if(!ret) + return; // insert at start of command buffer, so that aliases execute in order // (fixes bug introduced by Black on 20050705) @@ -1132,15 +1378,15 @@ static void Cmd_List_f (void) { partial = Cmd_Argv (1); len = strlen(partial); + ispattern = (strchr(partial, '*') || strchr(partial, '?')); } else { partial = NULL; len = 0; + ispattern = false; } - ispattern = partial && (strchr(partial, '*') || strchr(partial, '?')); - count = 0; for (cmd = cmd_functions; cmd; cmd = cmd->next) { @@ -1664,7 +1910,8 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src, qboolean lockmutex) int found; cmd_function_t *cmd; cmdalias_t *a; - + if (lockmutex) + Cbuf_LockThreadMutex(); oldpos = cmd_tokenizebufferpos; cmd_source = src; found = false; @@ -1740,6 +1987,8 @@ command_found: done: cmd_tokenizebufferpos = oldpos; + if (lockmutex) + Cbuf_UnlockThreadMutex(); }