X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=cmd.c;h=ea0b608eecfab77ade1a7bca311d3ce0ca4e85dc;hb=9b260c644ab630a054c579117f72c0635488825a;hp=651d08e2269eb6b7cedcfba78e7707f51369ee14;hpb=23cf09777969ae0150ffd414ee8fc576526a77fa;p=xonotic%2Fdarkplaces.git diff --git a/cmd.c b/cmd.c index 651d08e2..ea0b608e 100644 --- a/cmd.c +++ b/cmd.c @@ -22,26 +22,42 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "thread.h" -typedef struct cmdalias_s -{ - struct cmdalias_s *next; - char name[MAX_ALIAS_NAME]; - char *value; - qboolean initstate; // indicates this command existed at init - char *initialvalue; // backup copy of value at init -} cmdalias_t; +cmd_state_t cmd_client; +cmd_state_t cmd_server; +cmd_state_t cmd_serverfromclient; -static cmdalias_t *cmd_alias; +cmd_userdefined_t cmd_userdefined_all; +cmd_userdefined_t cmd_userdefined_null; -static qboolean cmd_wait; +typedef struct cmd_iter_s { + cmd_state_t *cmd; +} +cmd_iter_t; -static mempool_t *cmd_mempool; +static cmd_iter_t cmd_iter_all[] = { + {&cmd_client}, + {&cmd_server}, + {&cmd_serverfromclient}, + {NULL}, +}; -static char cmd_tokenizebuffer[CMD_TOKENIZELENGTH]; -static int cmd_tokenizebufferpos = 0; + +// we only run the +whatever commandline arguments once +qboolean host_stuffcmdsrun = false; //============================================================================= +void Cbuf_Lock(cmd_state_t *cmd) +{ + Thread_AtomicLock(&cmd->text_lock); +} + +void Cbuf_Unlock(cmd_state_t *cmd) +{ + Thread_AtomicUnlock(&cmd->text_lock); +} + + /* ============ Cmd_Wait_f @@ -51,20 +67,11 @@ next frame. This allows commands like: bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" ============ */ -static void Cmd_Wait_f (void) +static void Cmd_Wait_f (cmd_state_t *cmd) { - cmd_wait = true; + cmd->wait = true; } -typedef struct cmddeferred_s -{ - struct cmddeferred_s *next; - char *value; - double delay; -} cmddeferred_t; - -static cmddeferred_t *cmd_deferred_list = NULL; - /* ============ Cmd_Defer_f @@ -72,11 +79,11 @@ Cmd_Defer_f Cause a command to be executed after a delay. ============ */ -static void Cmd_Defer_f (void) +static void Cmd_Defer_f (cmd_state_t *cmd) { - if(Cmd_Argc() == 1) + if(Cmd_Argc(cmd) == 1) { - cmddeferred_t *next = cmd_deferred_list; + cmddeferred_t *next = cmd->deferred_list; if(!next) Con_Printf("No commands are pending.\n"); while(next) @@ -84,34 +91,34 @@ static void Cmd_Defer_f (void) Con_Printf("-> In %9.2f: %s\n", next->delay, next->value); next = next->next; } - } else if(Cmd_Argc() == 2 && !strcasecmp("clear", Cmd_Argv(1))) + } else if(Cmd_Argc(cmd) == 2 && !strcasecmp("clear", Cmd_Argv(cmd, 1))) { - while(cmd_deferred_list) + while(cmd->deferred_list) { - cmddeferred_t *cmd = cmd_deferred_list; - cmd_deferred_list = cmd->next; - Mem_Free(cmd->value); - Mem_Free(cmd); + cmddeferred_t *defcmd = cmd->deferred_list; + cmd->deferred_list = defcmd->next; + Mem_Free(defcmd->value); + Mem_Free(defcmd); } - } else if(Cmd_Argc() == 3) + } else if(Cmd_Argc(cmd) == 3) { - const char *value = Cmd_Argv(2); + const char *value = Cmd_Argv(cmd, 2); cmddeferred_t *defcmd = (cmddeferred_t*)Mem_Alloc(tempmempool, sizeof(*defcmd)); size_t len = strlen(value); - defcmd->delay = atof(Cmd_Argv(1)); + defcmd->delay = atof(Cmd_Argv(cmd, 1)); defcmd->value = (char*)Mem_Alloc(tempmempool, len+1); memcpy(defcmd->value, value, len+1); defcmd->next = NULL; - if(cmd_deferred_list) + if(cmd->deferred_list) { - cmddeferred_t *next = cmd_deferred_list; + cmddeferred_t *next = cmd->deferred_list; while(next->next) next = next->next; next->next = defcmd; } else - cmd_deferred_list = defcmd; + cmd->deferred_list = defcmd; /* Stupid me... this changes the order... so commands with the same delay go blub :S defcmd->next = cmd_deferred_list; cmd_deferred_list = defcmd;*/ @@ -129,20 +136,20 @@ Cmd_Centerprint_f Print something to the center of the screen using SCR_Centerprint ============ */ -static void Cmd_Centerprint_f (void) +static void Cmd_Centerprint_f (cmd_state_t *cmd) { char msg[MAX_INPUTLINE]; unsigned int i, c, p; - c = Cmd_Argc(); + c = Cmd_Argc(cmd); if(c >= 2) { - strlcpy(msg, Cmd_Argv(1), sizeof(msg)); + strlcpy(msg, Cmd_Argv(cmd,1), sizeof(msg)); for(i = 2; i < c; ++i) { strlcat(msg, " ", sizeof(msg)); - strlcat(msg, Cmd_Argv(i), sizeof(msg)); + strlcat(msg, Cmd_Argv(cmd, i), sizeof(msg)); } - c = strlen(msg); + c = (unsigned int)strlen(msg); for(p = 0, i = 0; i < c; ++i) { if(msg[i] == '\\') @@ -173,13 +180,6 @@ static void Cmd_Centerprint_f (void) ============================================================================= */ -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 @@ -187,18 +187,18 @@ Cbuf_AddText Adds command text at the end of the buffer ============ */ -void Cbuf_AddText (const char *text) +void Cbuf_AddText (cmd_state_t *cmd, const char *text) { int l; l = (int)strlen(text); - Cbuf_LockThreadMutex(); - if (cmd_text.cursize + l >= cmd_text.maxsize) + Cbuf_Lock(cmd); + if (cmd->text.maxsize - cmd->text.cursize <= l) Con_Print("Cbuf_AddText: overflow\n"); else - SZ_Write(&cmd_text, (const unsigned char *)text, l); - Cbuf_UnlockThreadMutex(); + SZ_Write(&cmd->text, (const unsigned char *)text, l); + Cbuf_Unlock(cmd); } @@ -211,21 +211,21 @@ Adds a \n to the text FIXME: actually change the command buffer to do less copying ============ */ -void Cbuf_InsertText (const char *text) +void Cbuf_InsertText (cmd_state_t *cmd, const char *text) { size_t l = strlen(text); - Cbuf_LockThreadMutex(); + Cbuf_Lock(cmd); // we need to memmove the existing text and stuff this in before it... - if (cmd_text.cursize + l >= (size_t)cmd_text.maxsize) + if (cmd->text.cursize + l >= (size_t)cmd->text.maxsize) Con_Print("Cbuf_InsertText: overflow\n"); else { // we don't have a SZ_Prepend, so... - memmove(cmd_text.data + l, cmd_text.data, cmd_text.cursize); - cmd_text.cursize += l; - memcpy(cmd_text.data, text, l); + memmove(cmd->text.data + l, cmd->text.data, cmd->text.cursize); + cmd->text.cursize += (int)l; + memcpy(cmd->text.data, text, l); } - Cbuf_UnlockThreadMutex(); + Cbuf_Unlock(cmd); } /* @@ -233,40 +233,39 @@ void Cbuf_InsertText (const char *text) Cbuf_Execute_Deferred --blub ============ */ -static void Cbuf_Execute_Deferred (void) +static void Cbuf_Execute_Deferred (cmd_state_t *cmd) { - static double oldrealtime = 0; - cmddeferred_t *cmd, *prev; + cmddeferred_t *defcmd, *prev; double eat; - if (realtime - oldrealtime < 0 || realtime - oldrealtime > 1800) oldrealtime = realtime; - eat = realtime - oldrealtime; + if (host.realtime - cmd->deferred_oldrealtime < 0 || host.realtime - cmd->deferred_oldrealtime > 1800) cmd->deferred_oldrealtime = host.realtime; + eat = host.realtime - cmd->deferred_oldrealtime; if (eat < (1.0 / 120.0)) return; - oldrealtime = realtime; + cmd->deferred_oldrealtime = host.realtime; prev = NULL; - cmd = cmd_deferred_list; - while(cmd) + defcmd = cmd->deferred_list; + while(defcmd) { - cmd->delay -= eat; - if(cmd->delay <= 0) + defcmd->delay -= eat; + if(defcmd->delay <= 0) { - Cbuf_AddText(cmd->value); - Cbuf_AddText(";\n"); - Mem_Free(cmd->value); + Cbuf_AddText(cmd, defcmd->value); + Cbuf_AddText(cmd, ";\n"); + Mem_Free(defcmd->value); if(prev) { - prev->next = cmd->next; - Mem_Free(cmd); - cmd = prev->next; + prev->next = defcmd->next; + Mem_Free(defcmd); + defcmd = prev->next; } else { - cmd_deferred_list = cmd->next; - Mem_Free(cmd); - cmd = cmd_deferred_list; + cmd->deferred_list = defcmd->next; + Mem_Free(defcmd); + defcmd = cmd->deferred_list; } continue; } - prev = cmd; - cmd = cmd->next; + prev = defcmd; + defcmd = defcmd->next; } } @@ -275,8 +274,8 @@ static void Cbuf_Execute_Deferred (void) Cbuf_Execute ============ */ -static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ); -void Cbuf_Execute (void) +static qboolean Cmd_PreprocessString(cmd_state_t *cmd, const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ); +void Cbuf_Execute (cmd_state_t *cmd) { int i; char *text; @@ -286,17 +285,17 @@ void Cbuf_Execute (void) qboolean quotes; char *comment; - // LordHavoc: making sure the tokenizebuffer doesn't get filled up by repeated crashes - cmd_tokenizebufferpos = 0; + // LadyHavoc: making sure the tokenizebuffer doesn't get filled up by repeated crashes + cmd->tokenizebufferpos = 0; - while (cmd_text.cursize) + while (cmd->text.cursize) { // find a \n or ; line break - text = (char *)cmd_text.data; + text = (char *)cmd->text.data; quotes = false; comment = NULL; - for (i=0 ; i < cmd_text.cursize ; i++) + for (i=0 ; i < cmd->text.cursize ; i++) { if(!comment) { @@ -307,7 +306,7 @@ void Cbuf_Execute (void) { // make sure i doesn't get > cursize which causes a negative // size in memmove, which is fatal --blub - if (i < (cmd_text.cursize-1) && (text[i] == '\\' && (text[i+1] == '"' || text[i+1] == '\\'))) + if (i < (cmd->text.cursize-1) && (text[i] == '\\' && (text[i+1] == '"' || text[i+1] == '\\'))) i++; } else @@ -326,7 +325,7 @@ void Cbuf_Execute (void) // better than CRASHING on overlong input lines that may SOMEHOW enter the buffer if(i >= MAX_INPUTLINE) { - Con_Printf("Warning: console input buffer had an overlong line. Ignored.\n"); + Con_Warnf("Warning: console input buffer had an overlong line. Ignored.\n"); line[0] = 0; } else @@ -339,13 +338,13 @@ void Cbuf_Execute (void) // this is necessary because commands (exec, alias) can insert data at the // beginning of the text buffer - if (i == cmd_text.cursize) - cmd_text.cursize = 0; + if (i == cmd->text.cursize) + cmd->text.cursize = 0; else { i++; - cmd_text.cursize -= i; - memmove (cmd_text.data, text+i, cmd_text.cursize); + cmd->text.cursize -= i; + memmove (cmd->text.data, text+i, cmd->text.cursize); } // execute the command line @@ -360,30 +359,30 @@ void Cbuf_Execute (void) (strncmp(firstchar, "in_bind", 7) || !ISWHITESPACE(firstchar[7])) ) { - if(Cmd_PreprocessString( line, preprocessed, sizeof(preprocessed), NULL )) - Cmd_ExecuteString (preprocessed, src_command, false); + if(Cmd_PreprocessString( cmd, line, preprocessed, sizeof(preprocessed), NULL )) + Cmd_ExecuteString (cmd, preprocessed, src_command, false); } else { - Cmd_ExecuteString (line, src_command, false); + Cmd_ExecuteString (cmd, line, src_command, false); } - if (cmd_wait) + if (cmd->wait) { // skip out while text still remains in buffer, leaving it // for next frame - cmd_wait = false; + cmd->wait = false; break; } } } -void Cbuf_Frame(void) +void Cbuf_Frame(cmd_state_t *cmd) { - Cbuf_Execute_Deferred(); - if (cmd_text.cursize) + Cbuf_Execute_Deferred(cmd); + if (cmd->text.cursize) { SV_LockThreadMutex(); - Cbuf_Execute(); + Cbuf_Execute(cmd); SV_UnlockThreadMutex(); } } @@ -406,14 +405,17 @@ quake +prog jctest.qp +cmd amlev1 quake -nosound +cmd amlev1 =============== */ -qboolean host_stuffcmdsrun = false; -static void Cmd_StuffCmds_f (void) +static void Cmd_StuffCmds_f (cmd_state_t *cmd) { int i, j, l; // this is for all commandline options combined (and is bounds checked) char build[MAX_INPUTLINE]; + + // come back later so we don't crash + if(host.state == host_init) + return; - if (Cmd_Argc () != 1) + if (Cmd_Argc (cmd) != 1) { Con_Print("stuffcmds : execute command line parameters\n"); return; @@ -426,28 +428,28 @@ static void Cmd_StuffCmds_f (void) host_stuffcmdsrun = true; build[0] = 0; l = 0; - for (i = 0;i < com_argc;i++) + for (i = 0;i < sys.argc;i++) { - if (com_argv[i] && com_argv[i][0] == '+' && (com_argv[i][1] < '0' || com_argv[i][1] > '9') && l + strlen(com_argv[i]) - 1 <= sizeof(build) - 1) + if (sys.argv[i] && sys.argv[i][0] == '+' && (sys.argv[i][1] < '0' || sys.argv[i][1] > '9') && l + strlen(sys.argv[i]) - 1 <= sizeof(build) - 1) { j = 1; - while (com_argv[i][j]) - build[l++] = com_argv[i][j++]; + while (sys.argv[i][j]) + build[l++] = sys.argv[i][j++]; i++; - for (;i < com_argc;i++) + for (;i < sys.argc;i++) { - if (!com_argv[i]) + if (!sys.argv[i]) continue; - if ((com_argv[i][0] == '+' || com_argv[i][0] == '-') && (com_argv[i][1] < '0' || com_argv[i][1] > '9')) + if ((sys.argv[i][0] == '+' || sys.argv[i][0] == '-') && (sys.argv[i][1] < '0' || sys.argv[i][1] > '9')) break; - if (l + strlen(com_argv[i]) + 4 > sizeof(build) - 1) + if (l + strlen(sys.argv[i]) + 4 > sizeof(build) - 1) break; build[l++] = ' '; - if (strchr(com_argv[i], ' ')) + if (strchr(sys.argv[i], ' ')) build[l++] = '\"'; - for (j = 0;com_argv[i][j];j++) - build[l++] = com_argv[i][j]; - if (strchr(com_argv[i], ' ')) + for (j = 0;sys.argv[i][j];j++) + build[l++] = sys.argv[i][j]; + if (strchr(sys.argv[i], ' ')) build[l++] = '\"'; } build[l++] = '\n'; @@ -457,13 +459,16 @@ static void Cmd_StuffCmds_f (void) // now terminate the combined string and prepend it to the command buffer // we already reserved space for the terminator build[l++] = 0; - Cbuf_InsertText (build); + Cbuf_InsertText (cmd, build); } -static void Cmd_Exec(const char *filename) +static void Cmd_Exec(cmd_state_t *cmd, const char *filename) { char *f; - qboolean isdefaultcfg = strlen(filename) >= 11 && !strcmp(filename + strlen(filename) - 11, "default.cfg"); + size_t filenameLen = strlen(filename); + qboolean isdefaultcfg = + !strcmp(filename, "default.cfg") || + (filenameLen >= 12 && !strcmp(filename + filenameLen - 12, "/default.cfg")); if (!strcmp(filename, "config.cfg")) { @@ -484,12 +489,12 @@ static void Cmd_Exec(const char *filename) // it may seem backwards to insert this text BEFORE the default.cfg // but Cbuf_InsertText inserts before, so this actually ends up after it. if (isdefaultcfg) - Cbuf_InsertText("\ncvar_lockdefaults\n"); + Cbuf_InsertText(cmd, "\ncvar_lockdefaults\n"); // insert newline after the text to make sure the last line is terminated (some text editors omit the trailing newline) // (note: insertion order here is backwards from execution order, so this adds it after the text, by calling it before...) - Cbuf_InsertText ("\n"); - Cbuf_InsertText (f); + Cbuf_InsertText (cmd, "\n"); + Cbuf_InsertText (cmd, f); Mem_Free(f); if (isdefaultcfg) @@ -497,23 +502,222 @@ 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(cmd, "\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" +"csqc_polygons_defaultmaterial_nocullface 0\n" + ); + break; + case GAME_NEHAHRA: + Cbuf_InsertText(cmd, "\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" +"csqc_polygons_defaultmaterial_nocullface 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(cmd, "\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" +"csqc_polygons_defaultmaterial_nocullface 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(cmd, "\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" +"csqc_polygons_defaultmaterial_nocullface 0\n" + ); + break; + case GAME_TENEBRAE: + Cbuf_InsertText(cmd, "\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" +"csqc_polygons_defaultmaterial_nocullface 0\n" + ); + break; + case GAME_NEXUIZ: + Cbuf_InsertText(cmd, "\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" +"csqc_polygons_defaultmaterial_nocullface 1\n" +"con_chatsound_team_mask 13\n" + ); + break; + case GAME_XONOTIC: + case GAME_VORETOURNAMENT: + // compatibility for versions prior to 2020-05-25, this can be overridden in newer versions to get the default behavior and be consistent with FTEQW engine + Cbuf_InsertText(cmd, "\n" +"csqc_polygons_defaultmaterial_nocullface 1\n" +"con_chatsound_team_mask 13\n" +"sv_gameplayfix_customstats 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(cmd, "\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" +"csqc_polygons_defaultmaterial_nocullface 1\n" + ); + break; + default: + Cbuf_InsertText(cmd, "\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" +"csqc_polygons_defaultmaterial_nocullface 0\n" + ); + break; + } } } @@ -522,26 +726,26 @@ static void Cmd_Exec(const char *filename) Cmd_Exec_f =============== */ -static void Cmd_Exec_f (void) +static void Cmd_Exec_f (cmd_state_t *cmd) { fssearch_t *s; int i; - if (Cmd_Argc () != 2) + if (Cmd_Argc(cmd) != 2) { Con_Print("exec : execute a script file\n"); return; } - s = FS_Search(Cmd_Argv(1), true, true); + s = FS_Search(Cmd_Argv(cmd, 1), true, true); if(!s || !s->numfilenames) { - Con_Printf("couldn't exec %s\n",Cmd_Argv(1)); + Con_Printf("couldn't exec %s\n",Cmd_Argv(cmd, 1)); return; } for(i = 0; i < s->numfilenames; ++i) - Cmd_Exec(s->filenames[i]); + Cmd_Exec(cmd, s->filenames[i]); FS_FreeSearch(s); } @@ -554,12 +758,12 @@ Cmd_Echo_f Just prints the rest of the line to the console =============== */ -static void Cmd_Echo_f (void) +static void Cmd_Echo_f (cmd_state_t *cmd) { int i; - for (i=1 ; icvars, Cmd_Argv(cmd, 1), cmd->cvars_flagsmask); if(cvCVar != NULL) { // Valid CVar @@ -597,13 +801,13 @@ static void Cmd_Toggle_f(void) else if(nNumArgs == 3) { // 0 and Specified Usage - if(cvCVar->integer == atoi(Cmd_Argv(2) ) ) + if(cvCVar->integer == atoi(Cmd_Argv(cmd, 2) ) ) // CVar is Specified Value; // Reset to 0 Cvar_SetValueQuick(cvCVar, 0); else if(cvCVar->integer == 0) // CVar is 0; Specify Value - Cvar_SetQuick(cvCVar, Cmd_Argv(2) ); + Cvar_SetQuick(cvCVar, Cmd_Argv(cmd, 2) ); else // CVar does not match; Reset to 0 Cvar_SetValueQuick(cvCVar, 0); @@ -615,14 +819,14 @@ static void Cmd_Toggle_f(void) for(nCnt = 2; nCnt < nNumArgs; nCnt++) { // Cycle through Values - if( strcmp(cvCVar->string, Cmd_Argv(nCnt) ) == 0) + if( strcmp(cvCVar->string, Cmd_Argv(cmd, nCnt) ) == 0) { // Current Value Located; Increment to Next if( (nCnt + 1) == nNumArgs) // Max Value Reached; Reset - Cvar_SetQuick(cvCVar, Cmd_Argv(2) ); + Cvar_SetQuick(cvCVar, Cmd_Argv(cmd, 2) ); else // Next Value - Cvar_SetQuick(cvCVar, Cmd_Argv(nCnt + 1) ); + Cvar_SetQuick(cvCVar, Cmd_Argv(cmd, nCnt + 1) ); // End Loop nCnt = nNumArgs; @@ -632,13 +836,13 @@ static void Cmd_Toggle_f(void) } if(!bFound) // Value not Found; Reset to Original - Cvar_SetQuick(cvCVar, Cmd_Argv(2) ); + Cvar_SetQuick(cvCVar, Cmd_Argv(cmd, 2) ); } } else { // Invalid CVar - Con_Printf("ERROR : CVar '%s' not found\n", Cmd_Argv(1) ); + Con_Printf("ERROR : CVar '%s' not found\n", Cmd_Argv(cmd, 1) ); } } } @@ -650,23 +854,23 @@ Cmd_Alias_f Creates a new command that executes a command string (possibly ; seperated) =============== */ -static void Cmd_Alias_f (void) +static void Cmd_Alias_f (cmd_state_t *cmd) { cmdalias_t *a; - char cmd[MAX_INPUTLINE]; + char line[MAX_INPUTLINE]; int i, c; const char *s; size_t alloclen; - if (Cmd_Argc() == 1) + if (Cmd_Argc(cmd) == 1) { Con_Print("Current alias commands:\n"); - for (a = cmd_alias ; a ; a=a->next) + for (a = cmd->userdefined->alias ; a ; a=a->next) Con_Printf("%s : %s", a->name, a->value); return; } - s = Cmd_Argv(1); + s = Cmd_Argv(cmd, 1); if (strlen(s) >= MAX_ALIAS_NAME) { Con_Print("Alias name is too long\n"); @@ -674,7 +878,7 @@ static void Cmd_Alias_f (void) } // if the alias already exists, reuse it - for (a = cmd_alias ; a ; a=a->next) + for (a = cmd->userdefined->alias ; a ; a=a->next) { if (!strcmp(s, a->name)) { @@ -690,33 +894,33 @@ static void Cmd_Alias_f (void) a = (cmdalias_t *)Z_Malloc (sizeof(cmdalias_t)); strlcpy (a->name, s, sizeof (a->name)); // insert it at the right alphanumeric position - for( prev = NULL, current = cmd_alias ; current && strcmp( current->name, a->name ) < 0 ; prev = current, current = current->next ) + for( prev = NULL, current = cmd->userdefined->alias ; current && strcmp( current->name, a->name ) < 0 ; prev = current, current = current->next ) ; if( prev ) { prev->next = a; } else { - cmd_alias = a; + cmd->userdefined->alias = a; } a->next = current; } // copy the rest of the command line - cmd[0] = 0; // start out with a null string - c = Cmd_Argc(); + line[0] = 0; // start out with a null string + c = Cmd_Argc(cmd); for (i=2 ; i < c ; i++) { if (i != 2) - strlcat (cmd, " ", sizeof (cmd)); - strlcat (cmd, Cmd_Argv(i), sizeof (cmd)); + strlcat (line, " ", sizeof (line)); + strlcat (line, Cmd_Argv(cmd, i), sizeof (line)); } - strlcat (cmd, "\n", sizeof (cmd)); + strlcat (line, "\n", sizeof (line)); - alloclen = strlen (cmd) + 1; + alloclen = strlen (line) + 1; if(alloclen >= 2) - cmd[alloclen - 2] = '\n'; // to make sure a newline is appended even if too long + line[alloclen - 2] = '\n'; // to make sure a newline is appended even if too long a->value = (char *)Z_Malloc (alloclen); - memcpy (a->value, cmd, alloclen); + memcpy (a->value, line, alloclen); } /* @@ -726,30 +930,30 @@ Cmd_UnAlias_f Remove existing aliases. =============== */ -static void Cmd_UnAlias_f (void) +static void Cmd_UnAlias_f (cmd_state_t *cmd) { cmdalias_t *a, *p; int i; const char *s; - if(Cmd_Argc() == 1) + if(Cmd_Argc(cmd) == 1) { Con_Print("unalias: Usage: unalias alias1 [alias2 ...]\n"); return; } - for(i = 1; i < Cmd_Argc(); ++i) + for(i = 1; i < Cmd_Argc(cmd); ++i) { - s = Cmd_Argv(i); + s = Cmd_Argv(cmd, i); p = NULL; - for(a = cmd_alias; a; p = a, a = a->next) + for(a = cmd->userdefined->alias; a; p = a, a = a->next) { if(!strcmp(s, a->name)) { if (a->initstate) // we can not remove init aliases continue; - if(a == cmd_alias) - cmd_alias = a->next; + if(a == cmd->userdefined->alias) + cmd->userdefined->alias = a->next; if(p) p->next = a->next; Z_Free(a->value); @@ -770,32 +974,12 @@ static void Cmd_UnAlias_f (void) ============================================================================= */ -typedef struct cmd_function_s -{ - struct cmd_function_s *next; - const char *name; - const char *description; - xcommand_t consolefunction; - xcommand_t clientfunction; - qboolean csqcfunc; - qboolean initstate; // indicates this command existed at init -} cmd_function_t; - -static int cmd_argc; -static const char *cmd_argv[MAX_ARGS]; -static const char *cmd_null_string = ""; -static const char *cmd_args; -cmd_source_t cmd_source; - - -static cmd_function_t *cmd_functions; // possible commands to execute - -static const char *Cmd_GetDirectCvarValue(const char *varname, cmdalias_t *alias, qboolean *is_multiple) +static const char *Cmd_GetDirectCvarValue(cmd_state_t *cmd, const char *varname, cmdalias_t *alias, qboolean *is_multiple) { cvar_t *cvar; long argno; char *endptr; - char vabuf[1024]; + static char vabuf[1024]; // cmd_mutex if(is_multiple) *is_multiple = false; @@ -809,11 +993,11 @@ static const char *Cmd_GetDirectCvarValue(const char *varname, cmdalias_t *alias { if(is_multiple) *is_multiple = true; - return Cmd_Args(); + return Cmd_Args(cmd); } else if(!strcmp(varname, "#")) { - return va(vabuf, sizeof(vabuf), "%d", Cmd_Argc()); + return va(vabuf, sizeof(vabuf), "%d", Cmd_Argc(cmd)); } else if(varname[strlen(varname) - 1] == '-') { @@ -821,7 +1005,7 @@ static const char *Cmd_GetDirectCvarValue(const char *varname, cmdalias_t *alias if(endptr == varname + strlen(varname) - 1) { // whole string is a number, apart from the - - const char *p = Cmd_Args(); + const char *p = Cmd_Args(cmd); for(; argno > 1; --argno) if(!COM_ParseToken_Console(&p)) break; @@ -845,13 +1029,13 @@ static const char *Cmd_GetDirectCvarValue(const char *varname, cmdalias_t *alias { // whole string is a number // NOTE: we already made sure we don't have an empty cvar name! - if(argno >= 0 && argno < Cmd_Argc()) - return Cmd_Argv(argno); + if(argno >= 0 && argno < Cmd_Argc(cmd)) + return Cmd_Argv(cmd, argno); } } } - if((cvar = Cvar_FindVar(varname)) && !(cvar->flags & CVAR_PRIVATE)) + if((cvar = Cvar_FindVar(cmd->cvars, varname, cmd->cvars_flagsmask)) && !(cvar->flags & CVAR_PRIVATE)) return cvar->string; return NULL; @@ -916,7 +1100,7 @@ fail: return false; } -static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t *alias) +static const char *Cmd_GetCvarValue(cmd_state_t *cmd, const char *var, size_t varlen, cmdalias_t *alias) { static char varname[MAX_INPUTLINE]; // cmd_mutex static char varval[MAX_INPUTLINE]; // cmd_mutex @@ -942,9 +1126,9 @@ static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t * { // empty cvar name? if(alias) - Con_Printf("Warning: Could not expand $ in alias %s\n", alias->name); + Con_Warnf("Warning: Could not expand $ in alias %s\n", alias->name); else - Con_Printf("Warning: Could not expand $\n"); + Con_Warnf("Warning: Could not expand $\n"); return "$"; } @@ -974,12 +1158,12 @@ static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t * } if(varname[0] == '$') - varstr = Cmd_GetDirectCvarValue(Cmd_GetDirectCvarValue(varname + 1, alias, NULL), alias, NULL); + varstr = Cmd_GetDirectCvarValue(cmd, Cmd_GetDirectCvarValue(cmd, varname + 1, alias, NULL), alias, NULL); else { qboolean is_multiple = false; // Exception: $* and $n- don't use the quoted form by default - varstr = Cmd_GetDirectCvarValue(varname, alias, &is_multiple); + varstr = Cmd_GetDirectCvarValue(cmd, varname, alias, &is_multiple); if(is_multiple) if(!varfunc) varfunc = asis; @@ -990,9 +1174,9 @@ static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t * if(required) { if(alias) - Con_Printf("Error: Could not expand $%s in alias %s\n", varname, alias->name); + Con_Errorf("Error: Could not expand $%s in alias %s\n", varname, alias->name); else - Con_Printf("Error: Could not expand $%s\n", varname); + Con_Errorf("Error: Could not expand $%s\n", varname); return NULL; } else if(optional) @@ -1002,9 +1186,9 @@ static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t * else { if(alias) - Con_Printf("Warning: Could not expand $%s in alias %s\n", varname, alias->name); + Con_Warnf("Warning: Could not expand $%s in alias %s\n", varname, alias->name); else - Con_Printf("Warning: Could not expand $%s\n", varname); + Con_Warnf("Warning: Could not expand $%s\n", varname); dpsnprintf(varval, sizeof(varval), "$%s", varname); return varval; } @@ -1032,7 +1216,7 @@ Cmd_PreprocessString Preprocesses strings and replaces $*, $param#, $cvar accordingly. Also strips comments. */ -static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ) { +static qboolean Cmd_PreprocessString(cmd_state_t *cmd, const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ) { const char *in; size_t eat, varlen; unsigned outlen; @@ -1111,7 +1295,7 @@ static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigne varlen = strcspn(in + 1, "}"); if(in[varlen + 1] == '}') { - val = Cmd_GetCvarValue(in + 1, varlen, alias); + val = Cmd_GetCvarValue(cmd, in + 1, varlen, alias); if(!val) return false; eat = varlen + 2; @@ -1124,7 +1308,7 @@ static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigne } } else { varlen = strspn(in, "#*0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"); - val = Cmd_GetCvarValue(in, varlen, alias); + val = Cmd_GetCvarValue(cmd, in, varlen, alias); if(!val) return false; eat = varlen; @@ -1161,11 +1345,11 @@ Cmd_ExecuteAlias Called for aliases and fills in the alias into the cbuffer ============ */ -static void Cmd_ExecuteAlias (cmdalias_t *alias) +static void Cmd_ExecuteAlias (cmd_state_t *cmd, cmdalias_t *alias) { static char buffer[ MAX_INPUTLINE ]; // cmd_mutex static char buffer2[ MAX_INPUTLINE ]; // cmd_mutex - qboolean ret = Cmd_PreprocessString( alias->value, buffer, sizeof(buffer) - 2, alias ); + qboolean ret = Cmd_PreprocessString( cmd, alias->value, buffer, sizeof(buffer) - 2, alias ); if(!ret) return; // insert at start of command buffer, so that aliases execute in order @@ -1175,7 +1359,7 @@ static void Cmd_ExecuteAlias (cmdalias_t *alias) // have to make sure that no second variable expansion takes place, otherwise // alias parameters containing dollar signs can have bad effects. Cmd_QuoteString(buffer2, sizeof(buffer2), buffer, "$", false); - Cbuf_InsertText( buffer2 ); + Cbuf_InsertText(cmd, buffer2); } /* @@ -1187,33 +1371,40 @@ Cmd_List ======== */ -static void Cmd_List_f (void) +static void Cmd_List_f (cmd_state_t *cmd) { - cmd_function_t *cmd; + cmd_function_t *func; const char *partial; size_t len; int count; qboolean ispattern; - if (Cmd_Argc() > 1) + if (Cmd_Argc(cmd) > 1) { - partial = Cmd_Argv (1); + partial = Cmd_Argv(cmd, 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) + for (func = cmd->userdefined->csqc_functions; func; func = func->next) { - if (partial && (ispattern ? !matchpattern_with_separator(cmd->name, partial, false, "", false) : strncmp(partial, cmd->name, len))) + if (partial && (ispattern ? !matchpattern_with_separator(func->name, partial, false, "", false) : strncmp(partial, func->name, len))) continue; - Con_Printf("%s : %s\n", cmd->name, cmd->description); + Con_Printf("%s : %s\n", func->name, func->description); + count++; + } + for (func = cmd->engine_functions; func; func = func->next) + { + if (partial && (ispattern ? !matchpattern_with_separator(func->name, partial, false, "", false) : strncmp(partial, func->name, len))) + continue; + Con_Printf("%s : %s\n", func->name, func->description); count++; } @@ -1228,9 +1419,9 @@ static void Cmd_List_f (void) Con_Printf("%i Command%s\n\n", count, (count > 1) ? "s" : ""); } -static void Cmd_Apropos_f(void) +static void Cmd_Apropos_f(cmd_state_t *cmd) { - cmd_function_t *cmd; + cmd_function_t *func; cvar_t *cvar; cmdalias_t *alias; const char *partial; @@ -1238,11 +1429,11 @@ static void Cmd_Apropos_f(void) qboolean ispattern; char vabuf[1024]; - if (Cmd_Argc() > 1) - partial = Cmd_Args(); + if (Cmd_Argc(cmd) > 1) + partial = Cmd_Args(cmd); else { - Con_Printf("usage: apropos \n"); + Con_Printf("usage: %s \n",Cmd_Argv(cmd, 0)); return; } @@ -1251,23 +1442,42 @@ static void Cmd_Apropos_f(void) partial = va(vabuf, sizeof(vabuf), "*%s*", partial); count = 0; - for (cvar = cvar_vars; cvar; cvar = cvar->next) + for (cvar = cmd->cvars->vars; cvar; cvar = cvar->next) { - if (!matchpattern_with_separator(cvar->name, partial, true, "", false)) - if (!matchpattern_with_separator(cvar->description, partial, true, "", false)) - continue; - Con_Printf ("cvar ^3%s^7 is \"%s\" [\"%s\"] %s\n", cvar->name, cvar->string, cvar->defstring, cvar->description); + if (matchpattern_with_separator(cvar->name, partial, true, "", false) || + matchpattern_with_separator(cvar->description, partial, true, "", false)) + { + Con_Printf ("cvar "); + Cvar_PrintHelp(cvar, cvar->name, true); + count++; + } + for (int i = 0; i < cvar->aliasindex; i++) + { + if (matchpattern_with_separator(cvar->aliases[i], partial, true, "", false)) + { + Con_Printf ("cvar "); + Cvar_PrintHelp(cvar, cvar->aliases[i], true); + count++; + } + } + } + for (func = cmd->userdefined->csqc_functions; func; func = func->next) + { + if (!matchpattern_with_separator(func->name, partial, true, "", false)) + if (!matchpattern_with_separator(func->description, partial, true, "", false)) + continue; + Con_Printf("command ^2%s^7: %s\n", func->name, func->description); count++; } - for (cmd = cmd_functions; cmd; cmd = cmd->next) + for (func = cmd->engine_functions; func; func = func->next) { - if (!matchpattern_with_separator(cmd->name, partial, true, "", false)) - if (!matchpattern_with_separator(cmd->description, partial, true, "", false)) + if (!matchpattern_with_separator(func->name, partial, true, "", false)) + if (!matchpattern_with_separator(func->description, partial, true, "", false)) continue; - Con_Printf("command ^2%s^7: %s\n", cmd->name, cmd->description); + Con_Printf("command ^2%s^7: %s\n", func->name, func->description); count++; } - for (alias = cmd_alias; alias; alias = alias->next) + for (alias = cmd->userdefined->alias; alias; alias = alias->next) { // procede here a bit differently as an alias value always got a final \n if (!matchpattern_with_separator(alias->name, partial, true, "", false)) @@ -1284,54 +1494,75 @@ static void Cmd_Apropos_f(void) Cmd_Init ============ */ -void Cmd_Init (void) +void Cmd_Init(void) { - cmd_mempool = Mem_AllocPool("commands", 0, NULL); - // space for commands and script files - cmd_text.data = cmd_text_buf; - cmd_text.maxsize = sizeof(cmd_text_buf); - cmd_text.cursize = 0; - - if (Thread_HasThreads()) - cmd_text_mutex = Thread_CreateMutex(); -} + cmd_iter_t *cmd_iter; + for (cmd_iter = cmd_iter_all; cmd_iter->cmd; cmd_iter++) + { + cmd_state_t *cmd = cmd_iter->cmd; + cmd->mempool = Mem_AllocPool("commands", 0, NULL); + // space for commands and script files + cmd->text.data = cmd->text_buf; + cmd->text.maxsize = sizeof(cmd->text_buf); + cmd->text.cursize = 0; + cmd->null_string = ""; + } + // client console can see server cvars because the user may start a server + cmd_client.cvars = &cvars_all; + cmd_client.cvars_flagsmask = CVAR_CLIENT | CVAR_SERVER; + cmd_client.cmd_flags = CMD_CLIENT | CMD_CLIENT_FROM_SERVER | CMD_SERVER_FROM_CLIENT; + cmd_client.userdefined = &cmd_userdefined_all; + // dedicated server console can only see server cvars, there is no client + cmd_server.cvars = &cvars_all; + cmd_server.cvars_flagsmask = CVAR_SERVER; + cmd_server.cmd_flags = CMD_SERVER; + cmd_server.userdefined = &cmd_userdefined_all; + // server commands received from clients have no reason to access cvars, cvar expansion seems perilous. + cmd_serverfromclient.cvars = &cvars_null; + cmd_serverfromclient.cvars_flagsmask = 0; + cmd_serverfromclient.cmd_flags = CMD_SERVER_FROM_CLIENT | CMD_USERINFO; + cmd_serverfromclient.userdefined = &cmd_userdefined_null; -void Cmd_Init_Commands (void) -{ // // register our commands // - Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f, "execute commandline parameters (must be present in quake.rc script)"); - Cmd_AddCommand ("exec",Cmd_Exec_f, "execute a script file"); - Cmd_AddCommand ("echo",Cmd_Echo_f, "print a message to the console (useful in scripts)"); - Cmd_AddCommand ("alias",Cmd_Alias_f, "create a script function (parameters are passed in as $X (being X a number), $* for all parameters, $X- for all parameters starting from $X). Without arguments show the list of all alias"); - Cmd_AddCommand ("unalias",Cmd_UnAlias_f, "remove an alias"); - Cmd_AddCommand ("cmd", Cmd_ForwardToServer, "send a console commandline to the server (used by some mods)"); - Cmd_AddCommand ("wait", Cmd_Wait_f, "make script execution wait for next rendered frame"); - Cmd_AddCommand ("set", Cvar_Set_f, "create or change the value of a console variable"); - Cmd_AddCommand ("seta", Cvar_SetA_f, "create or change the value of a console variable that will be saved to config.cfg"); - Cmd_AddCommand ("unset", Cvar_Del_f, "delete a cvar (does not work for static ones like _cl_name, or read-only ones)"); + // client-only commands + Cmd_AddCommand(CMD_CLIENT | CMD_CLIENT_FROM_SERVER, "cmd", Cmd_ForwardToServer_f, "send a console commandline to the server (used by some mods)"); + Cmd_AddCommand(CMD_SHARED, "wait", Cmd_Wait_f, "make script execution wait for next rendered frame"); + Cmd_AddCommand(CMD_CLIENT, "cprint", Cmd_Centerprint_f, "print something at the screen center"); + + // maintenance commands used for upkeep of cvars and saved configs + Cmd_AddCommand(CMD_SHARED, "stuffcmds", Cmd_StuffCmds_f, "execute commandline parameters (must be present in quake.rc script)"); + Cmd_AddCommand(CMD_SHARED, "cvar_lockdefaults", Cvar_LockDefaults_f, "stores the current values of all cvars into their default values, only used once during startup after parsing default.cfg"); + Cmd_AddCommand(CMD_SHARED, "cvar_resettodefaults_all", Cvar_ResetToDefaults_All_f, "sets all cvars to their locked default values"); + Cmd_AddCommand(CMD_SHARED, "cvar_resettodefaults_nosaveonly", Cvar_ResetToDefaults_NoSaveOnly_f, "sets all non-saved cvars to their locked default values (variables that will not be saved to config.cfg)"); + Cmd_AddCommand(CMD_SHARED, "cvar_resettodefaults_saveonly", Cvar_ResetToDefaults_SaveOnly_f, "sets all saved cvars to their locked default values (variables that will be saved to config.cfg)"); + + // general console commands used in multiple environments + Cmd_AddCommand(CMD_SHARED, "exec", Cmd_Exec_f, "execute a script file"); + Cmd_AddCommand(CMD_SHARED, "echo",Cmd_Echo_f, "print a message to the console (useful in scripts)"); + Cmd_AddCommand(CMD_SHARED, "alias",Cmd_Alias_f, "create a script function (parameters are passed in as $X (being X a number), $* for all parameters, $X- for all parameters starting from $X). Without arguments show the list of all alias"); + Cmd_AddCommand(CMD_SHARED, "unalias",Cmd_UnAlias_f, "remove an alias"); + Cmd_AddCommand(CMD_SHARED, "set", Cvar_Set_f, "create or change the value of a console variable"); + Cmd_AddCommand(CMD_SHARED, "seta", Cvar_SetA_f, "create or change the value of a console variable that will be saved to config.cfg"); + Cmd_AddCommand(CMD_SHARED, "unset", Cvar_Del_f, "delete a cvar (does not work for static ones like _cl_name, or read-only ones)"); + #ifdef FILLALLCVARSWITHRUBBISH - Cmd_AddCommand ("fillallcvarswithrubbish", Cvar_FillAll_f, "fill all cvars with a specified number of characters to provoke buffer overruns"); + Cmd_AddCommand(CMD_SHARED, "fillallcvarswithrubbish", Cvar_FillAll_f, "fill all cvars with a specified number of characters to provoke buffer overruns"); #endif /* FILLALLCVARSWITHRUBBISH */ // 2000-01-09 CmdList, CvarList commands By Matthias "Maddes" Buecher // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com - Cmd_AddCommand ("cmdlist", Cmd_List_f, "lists all console commands beginning with the specified prefix or matching the specified wildcard pattern"); - Cmd_AddCommand ("cvarlist", Cvar_List_f, "lists all console variables beginning with the specified prefix or matching the specified wildcard pattern"); - Cmd_AddCommand ("apropos", Cmd_Apropos_f, "lists all console variables/commands/aliases containing the specified string in the name or description"); - - Cmd_AddCommand ("cvar_lockdefaults", Cvar_LockDefaults_f, "stores the current values of all cvars into their default values, only used once during startup after parsing default.cfg"); - Cmd_AddCommand ("cvar_resettodefaults_all", Cvar_ResetToDefaults_All_f, "sets all cvars to their locked default values"); - Cmd_AddCommand ("cvar_resettodefaults_nosaveonly", Cvar_ResetToDefaults_NoSaveOnly_f, "sets all non-saved cvars to their locked default values (variables that will not be saved to config.cfg)"); - Cmd_AddCommand ("cvar_resettodefaults_saveonly", Cvar_ResetToDefaults_SaveOnly_f, "sets all saved cvars to their locked default values (variables that will be saved to config.cfg)"); + Cmd_AddCommand(CMD_SHARED, "cmdlist", Cmd_List_f, "lists all console commands beginning with the specified prefix or matching the specified wildcard pattern"); + Cmd_AddCommand(CMD_SHARED, "cvarlist", Cvar_List_f, "lists all console variables beginning with the specified prefix or matching the specified wildcard pattern"); + Cmd_AddCommand(CMD_SHARED, "apropos", Cmd_Apropos_f, "lists all console variables/commands/aliases containing the specified string in the name or description"); + Cmd_AddCommand(CMD_SHARED, "find", Cmd_Apropos_f, "lists all console variables/commands/aliases containing the specified string in the name or description"); - Cmd_AddCommand ("cprint", Cmd_Centerprint_f, "print something at the screen center"); - Cmd_AddCommand ("defer", Cmd_Defer_f, "execute a command in the future"); + Cmd_AddCommand(CMD_SHARED, "defer", Cmd_Defer_f, "execute a command in the future"); // DRESK - 5/14/06 // Support Doom3-style Toggle Command - Cmd_AddCommand( "toggle", Cmd_Toggle_f, "toggles a console variable's values (use for more info)"); + Cmd_AddCommand(CMD_SHARED | CMD_CLIENT_FROM_SERVER, "toggle", Cmd_Toggle_f, "toggles a console variable's values (use for more info)"); } /* @@ -1341,15 +1572,19 @@ Cmd_Shutdown */ void Cmd_Shutdown(void) { - if (cmd_text_mutex) + cmd_iter_t *cmd_iter; + for (cmd_iter = cmd_iter_all; cmd_iter->cmd; cmd_iter++) { - // we usually have this locked when we get here from Host_Quit_f - Cbuf_UnlockThreadMutex(); - Thread_DestroyMutex(cmd_text_mutex); - } - cmd_text_mutex = NULL; + cmd_state_t *cmd = cmd_iter->cmd; - Mem_FreePool(&cmd_mempool); + if (cmd->text_lock) + { + // we usually have this locked when we get here from Host_Quit_f + Cbuf_Unlock(cmd); + } + + Mem_FreePool(&cmd->mempool); + } } /* @@ -1357,9 +1592,9 @@ void Cmd_Shutdown(void) Cmd_Argc ============ */ -int Cmd_Argc (void) +int Cmd_Argc (cmd_state_t *cmd) { - return cmd_argc; + return cmd->argc; } /* @@ -1367,11 +1602,11 @@ int Cmd_Argc (void) Cmd_Argv ============ */ -const char *Cmd_Argv (int arg) +const char *Cmd_Argv(cmd_state_t *cmd, int arg) { - if (arg >= cmd_argc ) - return cmd_null_string; - return cmd_argv[arg]; + if (arg >= cmd->argc ) + return cmd->null_string; + return cmd->argv[arg]; } /* @@ -1379,9 +1614,9 @@ const char *Cmd_Argv (int arg) Cmd_Args ============ */ -const char *Cmd_Args (void) +const char *Cmd_Args (cmd_state_t *cmd) { - return cmd_args; + return cmd->args; } @@ -1393,12 +1628,12 @@ Parses the given string into command line tokens. ============ */ // AK: This function should only be called from ExcuteString because the current design is a bit of an hack -static void Cmd_TokenizeString (const char *text) +static void Cmd_TokenizeString (cmd_state_t *cmd, const char *text) { int l; - cmd_argc = 0; - cmd_args = NULL; + cmd->argc = 0; + cmd->args = NULL; while (1) { @@ -1422,24 +1657,24 @@ static void Cmd_TokenizeString (const char *text) if (!*text) return; - if (cmd_argc == 1) - cmd_args = text; + if (cmd->argc == 1) + cmd->args = text; if (!COM_ParseToken_Console(&text)) return; - if (cmd_argc < MAX_ARGS) + if (cmd->argc < MAX_ARGS) { l = (int)strlen(com_token) + 1; - if (cmd_tokenizebufferpos + l > CMD_TOKENIZELENGTH) + if (cmd->tokenizebufferpos + l > CMD_TOKENIZELENGTH) { - Con_Printf("Cmd_TokenizeString: ran out of %i character buffer space for command arguements\n", CMD_TOKENIZELENGTH); + Con_Printf("Cmd_TokenizeString: ran out of %i character buffer space for command arguments\n", CMD_TOKENIZELENGTH); break; } - memcpy (cmd_tokenizebuffer + cmd_tokenizebufferpos, com_token, l); - cmd_argv[cmd_argc] = cmd_tokenizebuffer + cmd_tokenizebufferpos; - cmd_tokenizebufferpos += l; - cmd_argc++; + memcpy (cmd->tokenizebuffer + cmd->tokenizebufferpos, com_token, l); + cmd->argv[cmd->argc] = cmd->tokenizebuffer + cmd->tokenizebufferpos; + cmd->tokenizebufferpos += l; + cmd->argc++; } } } @@ -1450,59 +1685,98 @@ static void Cmd_TokenizeString (const char *text) Cmd_AddCommand ============ */ -void Cmd_AddCommand_WithClientCommand (const char *cmd_name, xcommand_t consolefunction, xcommand_t clientfunction, const char *description) +void Cmd_AddCommand(int flags, const char *cmd_name, xcommand_t function, const char *description) { - cmd_function_t *cmd; + cmd_function_t *func; cmd_function_t *prev, *current; + cmd_state_t *cmd; + xcommand_t save = NULL; + int i; -// fail if the command is a variable name - if (Cvar_FindVar( cmd_name )) - { - Con_Printf("Cmd_AddCommand: %s already defined as a var\n", cmd_name); - return; - } - -// fail if the command already exists - for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + for (i = 0; i < 3; i++) { - if (!strcmp (cmd_name, cmd->name)) + cmd = cmd_iter_all[i].cmd; + if (flags & cmd->cmd_flags) { - if (consolefunction || clientfunction) + if(cmd == &cmd_client && (flags & CMD_SERVER_FROM_CLIENT) && !(flags & CMD_CLIENT)) { - Con_Printf("Cmd_AddCommand: %s already defined\n", cmd_name); - return; + save = function; + function = Cmd_ForwardToServer_f; } - else //[515]: csqc + // fail if the command is a variable name + if (Cvar_FindVar(cmd->cvars, cmd_name, ~0)) { - cmd->csqcfunc = true; + Con_Printf("Cmd_AddCommand: %s already defined as a var\n", cmd_name); return; } - } - } - cmd = (cmd_function_t *)Mem_Alloc(cmd_mempool, sizeof(cmd_function_t)); - cmd->name = cmd_name; - cmd->consolefunction = consolefunction; - cmd->clientfunction = clientfunction; - cmd->description = description; - if(!consolefunction && !clientfunction) //[515]: csqc - cmd->csqcfunc = true; - cmd->next = cmd_functions; - -// insert it at the right alphanumeric position - for( prev = NULL, current = cmd_functions ; current && strcmp( current->name, cmd->name ) < 0 ; prev = current, current = current->next ) - ; - if( prev ) { - prev->next = cmd; - } else { - cmd_functions = cmd; - } - cmd->next = current; -} + if (function) + { + // fail if the command already exists in this interpreter + for (func = cmd->engine_functions; func; func = func->next) + { + if (!strcmp(cmd_name, func->name)) + { + Con_Printf("Cmd_AddCommand: %s already defined\n", cmd_name); + goto next; + } + } -void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *description) -{ - Cmd_AddCommand_WithClientCommand (cmd_name, function, NULL, description); + func = (cmd_function_t *)Mem_Alloc(cmd->mempool, sizeof(cmd_function_t)); + func->flags = flags; + func->name = cmd_name; + func->function = function; + func->description = description; + func->next = cmd->engine_functions; + + // insert it at the right alphanumeric position + for (prev = NULL, current = cmd->engine_functions; current && strcmp(current->name, func->name) < 0; prev = current, current = current->next) + ; + if (prev) { + prev->next = func; + } + else { + cmd->engine_functions = func; + } + func->next = current; + } + else + { + // mark csqcfunc if the function already exists in the csqc_functions list + for (func = cmd->userdefined->csqc_functions; func; func = func->next) + { + if (!strcmp(cmd_name, func->name)) + { + func->csqcfunc = true; //[515]: csqc + continue; + } + } + + + func = (cmd_function_t *)Mem_Alloc(cmd->mempool, sizeof(cmd_function_t)); + func->name = cmd_name; + func->function = function; + func->description = description; + func->csqcfunc = true; //[515]: csqc + func->next = cmd->userdefined->csqc_functions; + + // insert it at the right alphanumeric position + for (prev = NULL, current = cmd->userdefined->csqc_functions; current && strcmp(current->name, func->name) < 0; prev = current, current = current->next) + ; + if (prev) { + prev->next = func; + } + else { + cmd->userdefined->csqc_functions = func; + } + func->next = current; + } + if (save) + function = save; + } +next: + continue; + } } /* @@ -1510,12 +1784,16 @@ void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *desc Cmd_Exists ============ */ -qboolean Cmd_Exists (const char *cmd_name) +qboolean Cmd_Exists (cmd_state_t *cmd, const char *cmd_name) { - cmd_function_t *cmd; + cmd_function_t *func; - for (cmd=cmd_functions ; cmd ; cmd=cmd->next) - if (!strcmp (cmd_name,cmd->name)) + for (func = cmd->userdefined->csqc_functions; func; func = func->next) + if (!strcmp(cmd_name, func->name)) + return true; + + for (func=cmd->engine_functions ; func ; func=func->next) + if (!strcmp (cmd_name,func->name)) return true; return false; @@ -1527,9 +1805,9 @@ qboolean Cmd_Exists (const char *cmd_name) Cmd_CompleteCommand ============ */ -const char *Cmd_CompleteCommand (const char *partial) +const char *Cmd_CompleteCommand (cmd_state_t *cmd, const char *partial) { - cmd_function_t *cmd; + cmd_function_t *func; size_t len; len = strlen(partial); @@ -1538,9 +1816,13 @@ const char *Cmd_CompleteCommand (const char *partial) return NULL; // check functions - for (cmd = cmd_functions; cmd; cmd = cmd->next) - if (!strncasecmp(partial, cmd->name, len)) - return cmd->name; + for (func = cmd->userdefined->csqc_functions; func; func = func->next) + if (!strncasecmp(partial, func->name, len)) + return func->name; + + for (func = cmd->engine_functions; func; func = func->next) + if (!strncasecmp(partial, func->name, len)) + return func->name; return NULL; } @@ -1554,9 +1836,9 @@ const char *Cmd_CompleteCommand (const char *partial) Thanks to taniwha */ -int Cmd_CompleteCountPossible (const char *partial) +int Cmd_CompleteCountPossible (cmd_state_t *cmd, const char *partial) { - cmd_function_t *cmd; + cmd_function_t *func; size_t len; int h; @@ -1567,8 +1849,12 @@ int Cmd_CompleteCountPossible (const char *partial) return 0; // Loop through the command list and count all partial matches - for (cmd = cmd_functions; cmd; cmd = cmd->next) - if (!strncasecmp(partial, cmd->name, len)) + for (func = cmd->userdefined->csqc_functions; func; func = func->next) + if (!strncasecmp(partial, func->name, len)) + h++; + + for (func = cmd->engine_functions; func; func = func->next) + if (!strncasecmp(partial, func->name, len)) h++; return h; @@ -1583,34 +1869,40 @@ int Cmd_CompleteCountPossible (const char *partial) Thanks to taniwha */ -const char **Cmd_CompleteBuildList (const char *partial) +const char **Cmd_CompleteBuildList (cmd_state_t *cmd, const char *partial) { - cmd_function_t *cmd; + cmd_function_t *func; size_t len = 0; size_t bpos = 0; - size_t sizeofbuf = (Cmd_CompleteCountPossible (partial) + 1) * sizeof (const char *); + size_t sizeofbuf = (Cmd_CompleteCountPossible (cmd, partial) + 1) * sizeof (const char *); const char **buf; len = strlen(partial); buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *)); - // Loop through the alias list and print all matches - for (cmd = cmd_functions; cmd; cmd = cmd->next) - if (!strncasecmp(partial, cmd->name, len)) - buf[bpos++] = cmd->name; + // Loop through the functions lists and print all matches + for (func = cmd->userdefined->csqc_functions; func; func = func->next) + if (!strncasecmp(partial, func->name, len)) + buf[bpos++] = func->name; + for (func = cmd->engine_functions; func; func = func->next) + if (!strncasecmp(partial, func->name, len)) + buf[bpos++] = func->name; buf[bpos] = NULL; return buf; } -// written by LordHavoc -void Cmd_CompleteCommandPrint (const char *partial) +// written by LadyHavoc +void Cmd_CompleteCommandPrint (cmd_state_t *cmd, const char *partial) { - cmd_function_t *cmd; + cmd_function_t *func; size_t len = strlen(partial); // Loop through the command list and print all matches - for (cmd = cmd_functions; cmd; cmd = cmd->next) - if (!strncasecmp(partial, cmd->name, len)) - Con_Printf("^2%s^7: %s\n", cmd->name, cmd->description); + for (func = cmd->userdefined->csqc_functions; func; func = func->next) + if (!strncasecmp(partial, func->name, len)) + Con_Printf("^2%s^7: %s\n", func->name, func->description); + for (func = cmd->engine_functions; func; func = func->next) + if (!strncasecmp(partial, func->name, len)) + Con_Printf("^2%s^7: %s\n", func->name, func->description); } /* @@ -1622,7 +1914,7 @@ void Cmd_CompleteCommandPrint (const char *partial) Thanks to taniwha */ -const char *Cmd_CompleteAlias (const char *partial) +const char *Cmd_CompleteAlias (cmd_state_t *cmd, const char *partial) { cmdalias_t *alias; size_t len; @@ -1633,20 +1925,20 @@ const char *Cmd_CompleteAlias (const char *partial) return NULL; // Check functions - for (alias = cmd_alias; alias; alias = alias->next) + for (alias = cmd->userdefined->alias; alias; alias = alias->next) if (!strncasecmp(partial, alias->name, len)) return alias->name; return NULL; } -// written by LordHavoc -void Cmd_CompleteAliasPrint (const char *partial) +// written by LadyHavoc +void Cmd_CompleteAliasPrint (cmd_state_t *cmd, const char *partial) { cmdalias_t *alias; size_t len = strlen(partial); // Loop through the alias list and print all matches - for (alias = cmd_alias; alias; alias = alias->next) + for (alias = cmd->userdefined->alias; alias; alias = alias->next) if (!strncasecmp(partial, alias->name, len)) Con_Printf("^5%s^7: %s", alias->name, alias->value); } @@ -1661,7 +1953,7 @@ void Cmd_CompleteAliasPrint (const char *partial) Thanks to taniwha */ -int Cmd_CompleteAliasCountPossible (const char *partial) +int Cmd_CompleteAliasCountPossible (cmd_state_t *cmd, const char *partial) { cmdalias_t *alias; size_t len; @@ -1675,7 +1967,7 @@ int Cmd_CompleteAliasCountPossible (const char *partial) return 0; // Loop through the command list and count all partial matches - for (alias = cmd_alias; alias; alias = alias->next) + for (alias = cmd->userdefined->alias; alias; alias = alias->next) if (!strncasecmp(partial, alias->name, len)) h++; @@ -1691,18 +1983,18 @@ int Cmd_CompleteAliasCountPossible (const char *partial) Thanks to taniwha */ -const char **Cmd_CompleteAliasBuildList (const char *partial) +const char **Cmd_CompleteAliasBuildList (cmd_state_t *cmd, const char *partial) { cmdalias_t *alias; size_t len = 0; size_t bpos = 0; - size_t sizeofbuf = (Cmd_CompleteAliasCountPossible (partial) + 1) * sizeof (const char *); + size_t sizeofbuf = (Cmd_CompleteAliasCountPossible (cmd, partial) + 1) * sizeof (const char *); const char **buf; len = strlen(partial); buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *)); // Loop through the alias list and print all matches - for (alias = cmd_alias; alias; alias = alias->next) + for (alias = cmd->userdefined->alias; alias; alias = alias->next) if (!strncasecmp(partial, alias->name, len)) buf[bpos++] = alias->name; @@ -1710,13 +2002,22 @@ const char **Cmd_CompleteAliasBuildList (const char *partial) return buf; } -void Cmd_ClearCsqcFuncs (void) +// TODO: Make this more generic? +void Cmd_ClearCSQCCommands (cmd_state_t *cmd) { - cmd_function_t *cmd; - for (cmd=cmd_functions ; cmd ; cmd=cmd->next) - cmd->csqcfunc = false; + cmd_function_t *func; + cmd_function_t **next = &cmd->userdefined->csqc_functions; + + while(*next) + { + func = *next; + *next = func->next; + Z_Free(func); + } } +extern cvar_t sv_cheats; + /* ============ Cmd_ExecuteString @@ -1725,88 +2026,83 @@ A complete command line has been parsed, so try to execute it FIXME: lookupnoadd the token to speed search? ============ */ -void Cmd_ExecuteString (const char *text, cmd_source_t src, qboolean lockmutex) +void Cmd_ExecuteString (cmd_state_t *cmd, const char *text, cmd_source_t src, qboolean lockmutex) { int oldpos; - int found; - cmd_function_t *cmd; + cmd_function_t *func; cmdalias_t *a; + if (lockmutex) + Cbuf_Lock(cmd); + oldpos = cmd->tokenizebufferpos; + cmd->source = src; - oldpos = cmd_tokenizebufferpos; - cmd_source = src; - found = false; - - Cmd_TokenizeString (text); + Cmd_TokenizeString (cmd, text); // execute the command line - if (!Cmd_Argc()) + if (!Cmd_Argc(cmd)) goto done; // no tokens // check functions - for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + for (func = cmd->userdefined->csqc_functions; func; func = func->next) { - if (!strcasecmp (cmd_argv[0],cmd->name)) + if (!strcasecmp(cmd->argv[0], func->name)) { - if (cmd->csqcfunc && CL_VM_ConsoleCommand (text)) //[515]: csqc + if (func->csqcfunc && CL_VM_ConsoleCommand(text)) //[515]: csqc goto done; + break; + } + } + + for (func = cmd->engine_functions; func; func=func->next) + { + if (!strcasecmp (cmd->argv[0], func->name)) + { switch (src) { case src_command: - if (cmd->consolefunction) - cmd->consolefunction (); - else if (cmd->clientfunction) - { - if (cls.state == ca_connected) - { - // forward remote commands to the server for execution - Cmd_ForwardToServer(); - } - else - Con_Printf("Can not send command \"%s\", not connected.\n", Cmd_Argv(0)); - } + if (func->function) + func->function(cmd); else - Con_Printf("Command \"%s\" can not be executed\n", Cmd_Argv(0)); - found = true; - goto command_found; + Con_Printf("Command \"%s\" can not be executed\n", Cmd_Argv(cmd, 0)); + goto done; case src_client: - if (cmd->clientfunction) + if (func->function) { - cmd->clientfunction (); + if((func->flags & CMD_CHEAT) && !sv_cheats.integer) + SV_ClientPrintf("No cheats allowed. The server must have sv_cheats set to 1\n"); + else + func->function(cmd); goto done; } - break; } break; } } -command_found: // if it's a client command and no command was found, say so. - if (cmd_source == src_client) + if (cmd->source == src_client) { - Con_Printf("player \"%s\" tried to %s\n", host_client->name, text); + Con_Printf("Client \"%s\" tried to execute \"%s\"\n", host_client->name, text); goto done; } // check alias - for (a=cmd_alias ; a ; a=a->next) + for (a=cmd->userdefined->alias ; a ; a=a->next) { - if (!strcasecmp (cmd_argv[0], a->name)) + if (!strcasecmp (cmd->argv[0], a->name)) { - Cmd_ExecuteAlias(a); + Cmd_ExecuteAlias(cmd, a); goto done; } } - if(found) // if the command was hooked and found, all is good - goto done; - // check cvars - if (!Cvar_Command () && host_framecount > 0) - Con_Printf("Unknown command \"%s\"\n", Cmd_Argv(0)); - + if (!Cvar_Command(cmd) && host.framecount > 0) + Con_Printf("Unknown command \"%s\"\n", Cmd_Argv(cmd, 0)); done: - cmd_tokenizebufferpos = oldpos; + cmd->tokenizebufferpos = oldpos; + if (lockmutex) + Cbuf_Unlock(cmd); } @@ -1829,7 +2125,7 @@ void Cmd_ForwardStringToServer (const char *s) if (!cls.netcon) return; - // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my + // LadyHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my // attention, it has been eradicated from here, its only (former) use in // all of darkplaces. if (cls.protocol == PROTOCOL_QUAKEWORLD) @@ -1924,7 +2220,7 @@ void Cmd_ForwardStringToServer (const char *s) break; } // write the resulting text - SZ_Write(&cls.netcon->message, (unsigned char *)temp, strlen(temp)); + SZ_Write(&cls.netcon->message, (unsigned char *)temp, (int)strlen(temp)); s += 2; continue; } @@ -1944,19 +2240,19 @@ Cmd_ForwardToServer Sends the entire command line over to the server =================== */ -void Cmd_ForwardToServer (void) +void Cmd_ForwardToServer_f (cmd_state_t *cmd) { const char *s; char vabuf[1024]; - if (!strcasecmp(Cmd_Argv(0), "cmd")) + if (!strcasecmp(Cmd_Argv(cmd, 0), "cmd")) { // we want to strip off "cmd", so just send the args - s = Cmd_Argc() > 1 ? Cmd_Args() : ""; + s = Cmd_Argc(cmd) > 1 ? Cmd_Args(cmd) : ""; } else { - // we need to keep the command name, so send Cmd_Argv(0), a space and then Cmd_Args() - s = va(vabuf, sizeof(vabuf), "%s %s", Cmd_Argv(0), Cmd_Argc() > 1 ? Cmd_Args() : ""); + // we need to keep the command name, so send Cmd_Argv(cmd, 0), a space and then Cmd_Args(cmd) + s = va(vabuf, sizeof(vabuf), "%s %s", Cmd_Argv(cmd, 0), Cmd_Argc(cmd) > 1 ? Cmd_Args(cmd) : ""); } // don't send an empty forward message if the user tries "cmd" by itself if (!s || !*s) @@ -1974,7 +2270,7 @@ where the given parameter apears, or 0 if not present ================ */ -int Cmd_CheckParm (const char *parm) +int Cmd_CheckParm (cmd_state_t *cmd, const char *parm) { int i; @@ -1984,8 +2280,8 @@ int Cmd_CheckParm (const char *parm) return 0; } - for (i = 1; i < Cmd_Argc (); i++) - if (!strcasecmp (parm, Cmd_Argv (i))) + for (i = 1; i < Cmd_Argc (cmd); i++) + if (!strcasecmp (parm, Cmd_Argv(cmd, i))) return i; return 0; @@ -1995,57 +2291,81 @@ int Cmd_CheckParm (const char *parm) void Cmd_SaveInitState(void) { - cmd_function_t *f; - cmdalias_t *a; - for (f = cmd_functions;f;f = f->next) - f->initstate = true; - for (a = cmd_alias;a;a = a->next) + cmd_iter_t *cmd_iter; + for (cmd_iter = cmd_iter_all; cmd_iter->cmd; cmd_iter++) { - a->initstate = true; - a->initialvalue = Mem_strdup(zonemempool, a->value); + cmd_state_t *cmd = cmd_iter->cmd; + cmd_function_t *f; + cmdalias_t *a; + for (f = cmd->userdefined->csqc_functions; f; f = f->next) + f->initstate = true; + for (f = cmd->engine_functions; f; f = f->next) + f->initstate = true; + for (a = cmd->userdefined->alias; a; a = a->next) + { + a->initstate = true; + a->initialvalue = Mem_strdup(zonemempool, a->value); + } } - Cvar_SaveInitState(); + Cvar_SaveInitState(&cvars_all); } void Cmd_RestoreInitState(void) { - cmd_function_t *f, **fp; - cmdalias_t *a, **ap; - for (fp = &cmd_functions;(f = *fp);) + cmd_iter_t *cmd_iter; + for (cmd_iter = cmd_iter_all; cmd_iter->cmd; cmd_iter++) { - if (f->initstate) - fp = &f->next; - else + cmd_state_t *cmd = cmd_iter->cmd; + cmd_function_t *f, **fp; + cmdalias_t *a, **ap; + for (fp = &cmd->userdefined->csqc_functions; (f = *fp);) { - // destroy this command, it didn't exist at init - Con_DPrintf("Cmd_RestoreInitState: Destroying command %s\n", f->name); - *fp = f->next; - Z_Free(f); + if (f->initstate) + fp = &f->next; + else + { + // destroy this command, it didn't exist at init + Con_DPrintf("Cmd_RestoreInitState: Destroying command %s\n", f->name); + *fp = f->next; + Z_Free(f); + } } - } - for (ap = &cmd_alias;(a = *ap);) - { - if (a->initstate) + for (fp = &cmd->engine_functions; (f = *fp);) { - // restore this alias, it existed at init - if (strcmp(a->value ? a->value : "", a->initialvalue ? a->initialvalue : "")) + if (f->initstate) + fp = &f->next; + else { - Con_DPrintf("Cmd_RestoreInitState: Restoring alias %s\n", a->name); - if (a->value) - Z_Free(a->value); - a->value = Mem_strdup(zonemempool, a->initialvalue); + // destroy this command, it didn't exist at init + Con_DPrintf("Cmd_RestoreInitState: Destroying command %s\n", f->name); + *fp = f->next; + Z_Free(f); } - ap = &a->next; } - else + for (ap = &cmd->userdefined->alias; (a = *ap);) { - // free this alias, it didn't exist at init... - Con_DPrintf("Cmd_RestoreInitState: Destroying alias %s\n", a->name); - *ap = a->next; - if (a->value) - Z_Free(a->value); - Z_Free(a); + if (a->initstate) + { + // restore this alias, it existed at init + if (strcmp(a->value ? a->value : "", a->initialvalue ? a->initialvalue : "")) + { + Con_DPrintf("Cmd_RestoreInitState: Restoring alias %s\n", a->name); + if (a->value) + Z_Free(a->value); + a->value = Mem_strdup(zonemempool, a->initialvalue); + } + ap = &a->next; + } + else + { + // free this alias, it didn't exist at init... + Con_DPrintf("Cmd_RestoreInitState: Destroying alias %s\n", a->name); + *ap = a->next; + if (a->value) + Z_Free(a->value); + Z_Free(a); + } } } - Cvar_RestoreInitState(); + Cvar_RestoreInitState(&cvars_all); }