From 3912e78a6047f2c45b3ff4967df7a68ad4e1b994 Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Tue, 24 Jan 2023 10:11:40 +1000 Subject: [PATCH] Reimplement the ability to override engine commands with QC commands This was working in div0-stable and was removed in 46acef5491629d06eddb8e78ed01e50b175d2bd8 Due to previous improvements by LH & Cloudwalk, the behaviour is now better: the new QC command appears in the console in addition to the engine one, the new command takes priority and what's going on is clearer. When the CSQC VM shuts down, the registered command is removed. Also this time we can has documentation. Signed-off-by: bones_was_here --- clvm_cmds.c | 3 +-- cmd.c | 16 +++++++++++++++- cmd.h | 1 + dpdefs/dpextensions.qc | 8 ++++++-- mvm_cmds.c | 3 +-- svvm_cmds.c | 3 +-- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/clvm_cmds.c b/clvm_cmds.c index 1f394845..44e62aee 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -2407,8 +2407,7 @@ static void VM_CL_setlistener (prvm_prog_t *prog) static void VM_CL_registercmd (prvm_prog_t *prog) { VM_SAFEPARMCOUNT(1, VM_CL_registercmd); - if(!Cmd_Exists(cmd_local, PRVM_G_STRING(OFS_PARM0))) - Cmd_AddCommand(CF_CLIENT, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC"); + Cmd_AddCommand(CF_CLIENT, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC"); } //#360 float() readbyte (EXT_CSQC) diff --git a/cmd.c b/cmd.c index a12fae8e..c9b2cd5d 100644 --- a/cmd.c +++ b/cmd.c @@ -1900,7 +1900,6 @@ void Cmd_AddCommand(int flags, const char *cmd_name, xcommand_t function, const } } - func = (cmd_function_t *)Mem_Alloc(cmd->mempool, sizeof(cmd_function_t)); func->flags = flags; func->name = cmd_name; @@ -1909,6 +1908,18 @@ void Cmd_AddCommand(int flags, const char *cmd_name, xcommand_t function, const func->qcfunc = true; //[515]: csqc func->next = cmd->userdefined->qc_functions; + // bones_was_here: if this QC command overrides an engine command, store its pointer + // to avoid doing this search at invocation if QC declines to handle this command. + for (cmd_function_t *f = cmd->engine_functions; f; f = f->next) + { + if (!strcmp(cmd_name, f->name)) + { + Con_DPrintf("Adding QC override of engine command %s\n", cmd_name); + func->overridden = f; + break; + } + } + // insert it at the right alphanumeric position for (prev = NULL, current = cmd->userdefined->qc_functions; current && strcmp(current->name, func->name) < 0; prev = current, current = current->next) ; @@ -2192,6 +2203,9 @@ qbool Cmd_CL_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, if(((func->flags & CF_CLIENT) && CL_VM_ConsoleCommand(text)) || ((func->flags & CF_SERVER) && SV_VM_ConsoleCommand(text))) return true; + + if (func->overridden) // If this QC command overrides an engine command, + func = func->overridden; // fall back to that command. } if (func->flags & CF_SERVER_FROM_CLIENT) { diff --git a/cmd.h b/cmd.h index c80fdf90..bee0a1f3 100644 --- a/cmd.h +++ b/cmd.h @@ -90,6 +90,7 @@ typedef struct cmd_function_s const char *description; xcommand_t function; qbool qcfunc; + struct cmd_function_s *overridden; // the engine cmd overriden by this QC cmd, if applicable qbool autofunc; qbool initstate; // indicates this command existed at init } cmd_function_t; diff --git a/dpdefs/dpextensions.qc b/dpdefs/dpextensions.qc index 48045a20..32c5e7c5 100644 --- a/dpdefs/dpextensions.qc +++ b/dpdefs/dpextensions.qc @@ -2633,12 +2633,16 @@ float(string pattern, float caseinsensitive, float quiet, string packfile) searc //extension to search_begin (DP_QC_FS_SEARCH), performs a filename search with the specified pattern (for example "maps/*.bsp") and stores the results in a search slot (minimum of 128 supported by any engine with this extension), the other functions take this returned search slot number, be sure to search_free when done (they are also freed on progs reload). //only searches for files within the specified packfile, which is expected to match the results of whichpack(). -//EXT_CSQC (registercommand for SSQC) +//EXT_CSQC (registercommand for CSQC, now also available in SVQC) //idea: probably Spoike //darkplaces implementation: Cloudwalk //builtin definitions: void(string cmdname) registercommand = #352; +//engine-called QC prototypes: +//float CSQC_ConsoleCommand(string command); +//float ConsoleCmd(string command); //description: -//the registercommand builtin but the server can use it +//Adds a new console command which will take priority over a previous command of the same name (including engine commands) and in CSQC is removed when the VM shuts down. This will call CSQC_ConsoleCommand(string command) or ConsoleCmd(string command) in SVQC. Return value should be true if QC handled the command, otherwise return false to have the engine handle it. + float(float dividend, float divisor) mod = #245; diff --git a/mvm_cmds.c b/mvm_cmds.c index 69801a04..3faf9a1f 100644 --- a/mvm_cmds.c +++ b/mvm_cmds.c @@ -1058,8 +1058,7 @@ void VM_cin_restart(prvm_prog_t *prog) static void VM_M_registercommand(prvm_prog_t *prog) { VM_SAFEPARMCOUNT(1, VM_M_registercommand); - if(!Cmd_Exists(cmd_local, PRVM_G_STRING(OFS_PARM0))) - Cmd_AddCommand(CF_CLIENT, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC"); + Cmd_AddCommand(CF_CLIENT, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC"); } prvm_builtin_t vm_m_builtins[] = { diff --git a/svvm_cmds.c b/svvm_cmds.c index a884d0f1..e77f9650 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -2865,8 +2865,7 @@ qbool SV_VM_ConsoleCommand (const char *text) static void VM_SV_registercommand (prvm_prog_t *prog) { VM_SAFEPARMCOUNT(1, VM_SV_registercmd); - if(!Cmd_Exists(cmd_local, PRVM_G_STRING(OFS_PARM0))) - Cmd_AddCommand(CF_SERVER, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC"); + Cmd_AddCommand(CF_SERVER, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC"); } //PF_setpause, // void(float pause) setpause = #531; -- 2.39.2