From 703ce809e76d66ac43e286cdee7477730769d84b Mon Sep 17 00:00:00 2001 From: Cloudwalk Date: Tue, 27 Oct 2020 10:49:25 -0400 Subject: [PATCH] cvar: Proof of concept for "internal variables" as a subset of cvar_t The idea is to create a dividing line between internal variables and their end-user configurability. This gives more control to the game dev, where they can decide which engine variables they want configurable with what ever name they choose. So far it works with sv_cheats. This allows the engine to be in a more barebones state, not imposing on the game dev as far as cvars are concerned. It makes cross-engine compatibility more feasible by allowing variables to adopt different names to satisfy MenuQC settings menus or what have you. --- cmd.c | 2 +- cvar.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ cvar.h | 48 +++++++++++++++++++++++++++++++++++++++++ sv_ccmds.c | 12 ++++++++--- 4 files changed, 121 insertions(+), 4 deletions(-) diff --git a/cmd.c b/cmd.c index c353b4c8..aeeb110c 100644 --- a/cmd.c +++ b/cmd.c @@ -2146,7 +2146,7 @@ void Cmd_ClearCSQCCommands (cmd_state_t *cmd) } } -extern cvar_t sv_cheats; +extern ivar_t sv_cheats; /* ============ diff --git a/cvar.c b/cvar.c index 1124494d..de837945 100644 --- a/cvar.c +++ b/cvar.c @@ -392,6 +392,22 @@ static void Cvar_SetQuick_Internal (cvar_t *var, const char *value) memcpy ((char *)var->string, value, valuelen + 1); var->value = atof (var->string); var->integer = (int) var->value; + + if(var->internal) + { + switch (var->internal->type) + { + case _bool: + case _int: + case _float: + var->internal->integer = var->integer; + break; + case _string: + var->internal->string = (char *)var->string; + break; + } + } + if ((var->flags & CF_NOTIFY) && sv.active && !sv_disablenotify.integer) SV_BroadcastPrintf("\003^3Server cvar \"%s\" changed to \"%s\"\n", var->name, var->string); #if 0 @@ -527,6 +543,51 @@ static void Cvar_Link(cvar_t *variable, cvar_state_t *cvars) cvars->hashtable[hashindex] = hash; } +void Cvar_RegisterInternal(ivar_t *variable, const char *name, const char *description, int flags) +{ + cvar_t *cvar = NULL; + char buf[256]; + int i; + + cvar = Cvar_FindVar(&cvars_all, name, ~0); + if(cvar) + return; + + cvar = (cvar_t *)Z_Malloc(sizeof(cvar_t)); + cvar->flags = flags; + cvar->name = (char *)Mem_strdup(zonemempool, name); + switch (variable->type) + { + case _bool: + case _int: + dpsnprintf(buf, sizeof(buf), "%i", variable->integer); + break; + case _float: + dpsnprintf(buf, sizeof(buf), "%.9g", variable->value); + break; + case _string: + dpsnprintf(buf, sizeof(buf), "%s", variable->string); + break; + } + + cvar->name = (char *)Mem_strdup(zonemempool, name); + cvar->string = (char *)Mem_strdup(zonemempool, buf); + cvar->defstring = (char *)Mem_strdup(zonemempool, buf); + cvar->description = (char *)Mem_strdup(zonemempool, description); + cvar->value = variable->value; + cvar->integer = variable->integer; + cvar->aliases = (char **)Z_Malloc(sizeof(char **)); + cvar->internal = variable; + memset(cvar->aliases, 0, sizeof(char *)); + + + // Mark it as not an autocvar. + for (i = 0;i < PRVM_PROG_MAX;i++) + cvar->globaldefindex[i] = -1; + + Cvar_Link(cvar, &cvars_all); +} + /* ============ Cvar_RegisterVariable @@ -617,6 +678,7 @@ void Cvar_RegisterVariable (cvar_t *variable) variable->defstring = (char *)Mem_strdup(zonemempool, variable->string); variable->value = atof (variable->string); variable->integer = (int) variable->value; + variable->internal = NULL; variable->aliasindex = 0; // Mark it as not an autocvar. @@ -685,6 +747,7 @@ cvar_t *Cvar_Get(cvar_state_t *cvars, const char *name, const char *value, int f cvar->value = atof (cvar->string); cvar->integer = (int) cvar->value; cvar->aliases = (char **)Z_Malloc(sizeof(char **)); + cvar->internal = NULL; memset(cvar->aliases, 0, sizeof(char *)); if(newdescription && *newdescription) diff --git a/cvar.h b/cvar.h index 1b01fc78..1e01a738 100644 --- a/cvar.h +++ b/cvar.h @@ -61,6 +61,50 @@ interface from being ambiguous. struct cmd_state_s; struct qfile_s; +// TODO +typedef enum ival_type_e +{ + _bool, + _int, + _float, + //_vector, + _string +} ival_type_t; + +typedef struct ivar_s +{ + union + { + qbool boolean; + int integer; + float value; + //float *vector; + const char *string; + }; + + ival_type_t type; + +} ivar_t; + +// Not used, just what the new cvar_t *might* look like. +typedef struct ncvar_s +{ + ivar_t var; + ivar_t init; + int flags; + const char *name; + const char *description; + const char *string; + const char *defstring; + void (*callback)(struct ncvar_s *var); + + int globaldefindex[3]; + int globaldefindex_stringno[3]; + + struct ncvar_s *next; + +} ncvar_t; + typedef struct cvar_s { int flags; @@ -94,6 +138,8 @@ typedef struct cvar_s int globaldefindex[3]; int globaldefindex_stringno[3]; + ivar_t *internal; + struct cvar_s *next; } cvar_t; @@ -117,6 +163,8 @@ void Cvar_RegisterAlias(cvar_t *variable, const char *alias ); void Cvar_RegisterCallback(cvar_t *variable, void (*callback)(cvar_t *)); +void Cvar_RegisterInternal(ivar_t *variable, const char *name, const char *description, int flags); + /// registers a cvar that already has the name, string, and optionally the /// archive elements set. void Cvar_RegisterVariable(cvar_t *variable); diff --git a/sv_ccmds.c b/sv_ccmds.c index 95796d5c..969fd46e 100644 --- a/sv_ccmds.c +++ b/sv_ccmds.c @@ -24,7 +24,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sv_demo.h" int current_skill; -cvar_t sv_cheats = {CF_SERVER | CF_NOTIFY, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"}; +// TODO: Convenience macros? Maybe IVAR_BOOL(sv_cheats, 1) or something +ivar_t sv_cheats = { .boolean = 0, _bool}; +//cvar_t sv_cheats = {CF_SERVER | CF_NOTIFY, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"}; cvar_t sv_adminnick = {CF_SERVER | CF_ARCHIVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"}; cvar_t sv_status_privacy = {CF_SERVER | CF_ARCHIVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"}; cvar_t sv_status_show_qcstatus = {CF_SERVER | CF_ARCHIVE, "sv_status_show_qcstatus", "0", "show the 'qcstatus' field in status replies, not the 'frags' field. Turn this on if your mod uses this field, and the 'frags' field on the other hand has no meaningful value."}; @@ -1609,8 +1611,12 @@ static void SV_Ent_Remove_All_f(cmd_state_t *cmd) void SV_InitOperatorCommands(void) { - Cvar_RegisterVariable(&sv_cheats); - Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c); + // TODO: By making cvar_t a superset of ivar_t, we can just cast sv_cheats + // to cvar_t and not have to do what ever this shit is. + cvar_t *cheats; + Cvar_RegisterInternal(&sv_cheats, "sv_cheats", "enables cheat commands in any game, and cheat impulses in dpmod", CF_SERVER | CF_NOTIFY); + cheats = Cvar_FindVar(&cvars_all, "sv_cheats", ~0); + Cvar_RegisterCallback(cheats, SV_DisableCheats_c); Cvar_RegisterVariable(&sv_adminnick); Cvar_RegisterVariable(&sv_status_privacy); Cvar_RegisterVariable(&sv_status_show_qcstatus); -- 2.39.2