From c0d4714cb304394f19cac5b71d704aa6b2c27dd5 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Sun, 20 Mar 2022 20:05:42 +0000 Subject: Support deferring cvar registration This allows stuff to be registered conditionally. Unfortunately cmeta is now truly the worst thing of all time, but cleaning it up isn't a huge priority. On the plus side, codegen actually got simpler. --- src/build/cmeta.c | 31 ++++++++++++++++++++++++----- src/build/cmeta.h | 2 +- src/build/codegen.c | 57 ++++++++++++++++++++++++++--------------------------- src/con_.c | 37 +++++++++++++++++++--------------- src/con_.h | 18 +++++++++++++++++ 5 files changed, 94 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/build/cmeta.c b/src/build/cmeta.c index 7b7a767..4e1eb4a 100644 --- a/src/build/cmeta.c +++ b/src/build/cmeta.c @@ -204,16 +204,37 @@ void cmeta_includes(const struct cmeta *cm, // AGAIN, NOTE: this doesn't *perfectly* match top level decls only in the event // that someone writes something weird, but we just don't really care because // we're not writing something weird. Don't write something weird! -void cmeta_conmacros(const struct cmeta *cm, void (*cb)(const char *, bool)) { +void cmeta_conmacros(const struct cmeta *cm, + void (*cb)(const char *, bool, bool)) { Token *tp = (Token *)cm; if (!tp || !tp->next || !tp->next->next) return; // DEF_xyz, (, name while (tp) { bool isplusminus = false, isvar = false; - if (equal(tp, "DEF_CCMD_PLUSMINUS")) isplusminus = true; + bool unreg = false; + // this is like the worst thing ever, but oh well it's just build time + // XXX: tidy this up some day, though, probably + if (equal(tp, "DEF_CCMD_PLUSMINUS")) { + isplusminus = true; + } + else if (equal(tp, "DEF_CCMD_PLUSMINUS_UNREG")) { + isplusminus = true; + unreg = true; + } else if (equal(tp, "DEF_CVAR") || equal(tp, "DEF_CVAR_MIN") || equal(tp, "DEF_CVAR_MAX") || equal(tp, "DEF_CVAR_MINMAX")) { isvar = true; } + else if (equal(tp, "DEF_CVAR_UNREG") || + equal(tp, "DEF_CVAR_MIN_UNREG") || + equal(tp, "DEF_CVAR_MAX_UNREG") || + equal(tp, "DEF_CVAR_MINMAX_UNREG")) { + isvar = true; + unreg = true; + } + else if (equal(tp, "DEF_CCMD_UNREG") || + equal(tp, "DEF_CCMD_HERE_UNREG")) { + unreg = true; + } else if (!equal(tp, "DEF_CCMD") && !equal(tp, "DEF_CCMD_HERE")) { tp = tp->next; continue; } @@ -226,20 +247,20 @@ void cmeta_conmacros(const struct cmeta *cm, void (*cb)(const char *, bool)) { memcpy(plusname, "PLUS_", 5); memcpy(plusname + sizeof("PLUS_") - 1, tp->loc, tp->len); plusname[sizeof("PLUS_") - 1 + tp->len] = '\0'; - cb(plusname, false); + cb(plusname, false, unreg); char *minusname = malloc(sizeof("MINUS_") + tp->len); if (!minusname) die1("couldn't allocate memory"); memcpy(minusname, "MINUS_", 5); memcpy(minusname + sizeof("MINUS_") - 1, tp->loc, tp->len); minusname[sizeof("MINUS_") - 1 + tp->len] = '\0'; - cb(minusname, false); + cb(minusname, false, unreg); } else { char *name = malloc(tp->len + 1); if (!name) die1("couldn't allocate memory"); memcpy(name, tp->loc, tp->len); name[tp->len] = '\0'; - cb(name, isvar); + cb(name, isvar, unreg); } tp = tp->next; } diff --git a/src/build/cmeta.h b/src/build/cmeta.h index 3319e3a..18ff62c 100644 --- a/src/build/cmeta.h +++ b/src/build/cmeta.h @@ -37,7 +37,7 @@ void cmeta_includes(const struct cmeta *cm, * con_.h, passing each one in turn to the callback cb. */ void cmeta_conmacros(const struct cmeta *cm, - void (*cb)(const char *name, bool isvar)); + void (*cb)(const char *name, bool isvar, bool unreg)); #endif diff --git a/src/build/codegen.c b/src/build/codegen.c index c9be0ef..38645e5 100644 --- a/src/build/codegen.c +++ b/src/build/codegen.c @@ -21,26 +21,30 @@ #include "../os.h" #include "cmeta.h" -static const char *cmdnames[4096]; // arbitrary limit! -static int ncmdnames = 0; -static const char *varnames[4096]; // arbitrary limit! -static int nvarnames = 0; +#define MAXENT 65536 // arbitrary limit! +static struct ent { + const char *name; + bool unreg; + bool isvar; // false for cmd +} ents[MAXENT]; +static int nents; static void die(const char *s) { fprintf(stderr, "codegen: %s\n", s); exit(100); } -#define PUT(array, ent) do { \ - if (n##array == sizeof(array) / sizeof(*array)) { \ - fprintf(stderr, "codegen: out of space; make " #array " bigger!\n"); \ +#define PUT(name_, isvar_, unreg_) do { \ + if (nents == sizeof(ents) / sizeof(*ents)) { \ + fprintf(stderr, "codegen: out of space; make ents bigger!\n"); \ exit(1); \ } \ - array[n##array++] = ent; \ + ents[nents].name = name_; \ + ents[nents].isvar = isvar_; ents[nents++].unreg = unreg_; \ } while (0) -static void oncondef(const char *name, bool isvar) { - if (isvar) PUT(varnames, name); else PUT(cmdnames, name); +static void oncondef(const char *name, bool isvar, bool unreg) { + PUT(name, isvar, unreg); } #define _(x) \ @@ -60,31 +64,26 @@ int OS_MAIN(int argc, os_char *argv[]) { FILE *out = fopen(".build/include/cmdinit.gen.h", "wb"); if (!out) die("couldn't open cmdinit.gen.h"); H(); - for (const char *const *pp = cmdnames; - pp - cmdnames < ncmdnames; ++pp) { -F( "extern struct con_cmd *%s;", *pp) - } - for (const char *const *pp = varnames; - pp - varnames < nvarnames; ++pp) { -F( "extern struct con_var *%s;", *pp) + for (const struct ent *p = ents; p - ents < nents; ++p) { +F( "extern struct con_%s *%s;", p->isvar ? "var" : "cmd", p->name) } _( "") -_( "static void regcmds(void (*VCALLCONV f)(void *, void *)) {") - for (const char *const *pp = cmdnames; - pp - cmdnames < ncmdnames; ++pp) { -F( " f(_con_iface, %s);", *pp) - } - for (const char *const *pp = varnames; - pp - varnames < nvarnames; ++pp) { -F( " initval(%s);", *pp) -F( " f(_con_iface, %s);", *pp) +_( "static void regcmds(void) {") + for (const struct ent *p = ents; p - ents < nents; ++p) { + if (p->isvar) { +F( " initval(%s);", p->name) + } + if (!p->unreg) { +F( " con_reg(%s);", p->name) + } } _( "}") _( "") _( "static void freevars(void) {") - for (const char *const *pp = varnames; - pp - varnames < nvarnames; ++pp) { -F( " extfree(%s->strval);", *pp) + for (const struct ent *p = ents; p - ents < nents; ++p) { + if (p->isvar) { +F( " extfree(%s->strval);", p->name); + } } _( "}") if (fflush(out) == EOF) die("couldn't fully write cmdinit.gen.h"); diff --git a/src/con_.c b/src/con_.c index e58c040..ab1cd1e 100644 --- a/src/con_.c +++ b/src/con_.c @@ -396,6 +396,15 @@ static void fillvts(void) { *pi++ = (void *)&GetSplitScreenPlayerSlot; } +void con_reg(void *cmd_or_var) { + if (GAMETYPE_MATCHES(Portal2)) { + VCALL(_con_iface, RegisterConCommand_p2, cmd_or_var); + } + else { + VCALL(_con_iface, RegisterConCommand, cmd_or_var); + } +} + bool con_init(void *(*f)(const char *, int *), int plugin_ver) { int ifacever; // for error messages if (_con_iface = f("VEngineCvar007", 0)) { @@ -409,11 +418,8 @@ bool con_init(void *(*f)(const char *, int *), int plugin_ver) { _con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_p2); dllid = VCALL0(_con_iface, AllocateDLLIdentifier_p2); _gametype_tag |= _gametype_tag_Portal2; - fillvts(); - regcmds(VFUNC(_con_iface, RegisterConCommand_p2)); - return true; } - if (VCALL(_con_iface, FindCommand, "l4d2_snd_adrenaline")) { + else if (VCALL(_con_iface, FindCommand, "l4d2_snd_adrenaline")) { _con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_l4d); dllid = VCALL0(_con_iface, AllocateDLLIdentifier); // while we're here, also distinguish Survivors, the stupid Japanese @@ -428,22 +434,21 @@ bool con_init(void *(*f)(const char *, int *), int plugin_ver) { else { _gametype_tag |= _gametype_tag_L4D2; } - fillvts(); - regcmds(VFUNC(_con_iface, RegisterConCommand)); - return true; } - if (VCALL(_con_iface, FindVar, "z_difficulty")) { + else if (VCALL(_con_iface, FindVar, "z_difficulty")) { _con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_l4d); dllid = VCALL0(_con_iface, AllocateDLLIdentifier); _gametype_tag |= _gametype_tag_L4D1; - fillvts(); // XXX: is this all kinda dupey? maybe rearrange one day. - regcmds(VFUNC(_con_iface, RegisterConCommand)); - return true; } - con_warn("sst: error: game \"%s\" is unsupported (using " - "VEngineCvar007)\n", gameinfo_title); - ifacever = 7; - goto e; + else { + con_warn("sst: error: game \"%s\" is unsupported (using " + "VEngineCvar007)\n", gameinfo_title); + ifacever = 7; + goto e; + } + fillvts(); + regcmds(); + return true; } if (_con_iface = f("VEngineCvar004", 0)) { // TODO(compat): are there any cases where 004 is incompatible? could @@ -455,7 +460,7 @@ bool con_init(void *(*f)(const char *, int *), int plugin_ver) { if (plugin_ver == 3) _gametype_tag |= _gametype_tag_2013; else _gametype_tag |= _gametype_tag_OrangeBox; fillvts(); - regcmds(VFUNC(_con_iface, RegisterConCommand)); + regcmds(); return true; } if (f("VEngineCvar003", 0)) { diff --git a/src/con_.h b/src/con_.h index ff4241f..c0c37f1 100644 --- a/src/con_.h +++ b/src/con_.h @@ -293,6 +293,24 @@ extern void *_con_vtab_iconvar[]; static void _cmdf_##name(const struct con_cmdargs *cmd) \ /* { body here } */ +/* + * These are exactly the same as the above macros, but they don't cause the + * commands or variables to be registered on plugin load. + */ +#define DEF_CVAR_UNREG DEF_CVAR +#define DEF_CVAR_MIN_UNREG DEF_CVAR_MIN +#define DEF_CVAR_MAX_UNREG DEF_CVAR_MAX +#define DEF_CVAR_MINMAX_UNREG DEF_CVAR_MINMAX +#define DEF_CCMD_UNREG DEF_CCMD +#define DEF_CCMD_HERE_UNREG DEF_CCMD_HERE +#define DEF_CCMD_PLUSMINUS_UNREG DEF_CCMD_PLUSMINUS + +/* + * Registers a command or variable defined with the _UNREG variants of the above + * macros. Can be used to conditionally register things. + */ +void con_reg(void *cmd_or_var); + #endif // vi: sw=4 ts=4 noet tw=80 cc=80 -- cgit v1.2.3