diff options
| author | 2025-11-15 20:24:41 +0000 | |
|---|---|---|
| committer | 2025-11-15 20:24:41 +0000 | |
| commit | c15101df02685a5d26f4b130f7b559eb7ed7f74f (patch) | |
| tree | 5803259d20a291278c9cc7dfd6bc346198f0edb0 | |
| parent | 650bb761d3e5af3f8fa19ac8d22864cc0360d085 (diff) | |
| download | sst-c15101df02685a5d26f4b130f7b559eb7ed7f74f.tar.gz sst-c15101df02685a5d26f4b130f7b559eb7ed7f74f.zip | |
Deal with CON_HIDDEN not existing in OE
Pretty hacky for now, but not the worst thing in the world. Can always
be tidied up later.
| -rw-r--r-- | src/build/gluegen.c | 3 | ||||
| -rw-r--r-- | src/con_.c | 18 | ||||
| -rw-r--r-- | src/con_.h | 52 | ||||
| -rw-r--r-- | src/fixes.c | 129 | ||||
| -rw-r--r-- | src/fov.c | 9 | ||||
| -rw-r--r-- | src/nomute.c | 4 | ||||
| -rw-r--r-- | src/nosleep.c | 4 | ||||
| -rw-r--r-- | src/rinput.c | 8 | ||||
| -rw-r--r-- | src/sst.c | 2 |
9 files changed, 140 insertions, 89 deletions
diff --git a/src/build/gluegen.c b/src/build/gluegen.c index 5d02f48..6a859d3 100644 --- a/src/build/gluegen.c +++ b/src/build/gluegen.c @@ -749,6 +749,7 @@ F( " feats.preinit_%.*s = _feat_preinit_%.*s();", _( "}") _( "") _( "static inline void initfeatures() {") +_( " int _hiddenflag = GAMETYPE_MATCHES(OE) ? 0 : _CON_NE_HIDDEN;") for (int i = 0; i < nfeatures; ++i) { // N.B.: this *should* be 0-indexed! const char *else_ = ""; s16 mod = feat_initorder[i]; @@ -813,7 +814,7 @@ F( " if (status_%.*s != FEAT_SKIP) {", modname.len, modname.s) F( " con_regvar(%.*s);", cvar_names[i].len, cvar_names[i].s) -F( " if (status_%.*s != FEAT_OK) %.*s->base.flags |= CON_HIDDEN;", +F( " if (status_%.*s != FEAT_OK) %.*s->base.flags |= _hiddenflag;", modname.len, modname.s, cvar_names[i].len, cvar_names[i].s) _( " }") } @@ -432,7 +432,14 @@ struct con_var_common *con_getvarcommon(const struct con_var *v) { return mem_offset(v, off_cvar_common); } +static inline void fudgeflags(struct con_cmdbase *b) { + if_hot (!GAMETYPE_MATCHES(OE)) if (b->flags & CON_INIT_HIDDEN) { + b->flags = (b->flags & ~CON_INIT_HIDDEN) | _CON_NE_HIDDEN; + } +} + void con_regvar(struct con_var *v) { + fudgeflags(&v->base); struct con_var_common *c = con_getvarcommon(v); c->strval = extmalloc(c->strlen); // note: _DEF_CVAR() sets strlen member memcpy(c->strval, c->defaultval, c->strlen); @@ -440,9 +447,20 @@ void con_regvar(struct con_var *v) { } void con_regcmd(struct con_cmd *c) { + fudgeflags(&c->base); + if_hot (!GAMETYPE_MATCHES(OE)) if (c->base.flags & CON_INIT_HIDDEN) { + c->base.flags = (c->base.flags & ~CON_INIT_HIDDEN) | _CON_NE_HIDDEN; + } RegisterConCommand(coniface, c); } +void con_hide(struct con_cmdbase *b) { + if_hot (!GAMETYPE_MATCHES(OE)) b->flags |= _CON_NE_HIDDEN; +} +void con_unhide(struct con_cmdbase *b) { + if_hot (!GAMETYPE_MATCHES(OE)) b->flags &= ~_CON_NE_HIDDEN; +} + // XXX: these should use vcall/gamedata stuff as they're only used for the // setter API after everything is brought up. however that will require some // kind of windows/linux conditionals in the gamedata system! this solution is @@ -41,29 +41,35 @@ struct con_cmdargs { #define CON_CMD_MAXCOMPLETE 64 #define CON_CMD_MAXCOMPLLEN 64 -/* ConVar/ConCommand flag bits - undocumented ones are probably not useful... */ +/* ConVar/ConCommand flag bits stable across engines */ enum { - CON_UNREG = 1, - CON_DEVONLY = 1 << 1, /* hide unless developer 1 is set */ + _CON_NE_DEVONLY = 1 << 1, /* hide entirely and disallow usage. NE only. */ CON_SERVERSIDE = 1 << 2, /* set con_cmdclient and run on server side */ - CON_CLIENTDLL = 1 << 3, - CON_HIDDEN = 1 << 4, /* hide completely, often useful to remove! */ + _CON_NE_HIDDEN = 1 << 4, /* don't autocomplete. NE only; use con_hide() */ CON_PROTECTED = 1 << 5, /* don't send to clients (example: password) */ - CON_SPONLY = 1 << 6, - CON_ARCHIVE = 1 << 7, /* save in config - plugin would need a VDF! */ + CON_ARCHIVE = 1 << 7, /* save in config.cfg. needs VDF autoload. */ CON_NOTIFY = 1 << 8, /* announce changes in game chat */ - CON_USERINFO = 1 << 9, - CON_PRINTABLE = 1 << 10, /* do not allow non-printable values */ - CON_UNLOGGED = 1 << 11, - CON_NOPRINT = 1 << 12, /* do not attempt to print, contains junk! */ - CON_REPLICATE = 1 << 13, /* client will use server's value */ - CON_CHEAT = 1 << 14, /* require sv_cheats 1 to change from default */ - CON_DEMO = 1 << 16, /* record value at the start of a demo */ + CON_PRINTABLE = 1 << 10, /* do not allow non-printable characters */ + CON_NOPRINT = 1 << 12, /* contains junk; do not attempt to print */ + CON_REPLICATE = 1 << 13, /* client will value from server */ + CON_CHEAT = 1 << 14, /* require sv_cheats 1 to change (or run) */ + CON_DEMO = 1 << 16, /* record cvar value at the start of a demo */ CON_NORECORD = 1 << 17, /* don't record the command to a demo, ever */ - CON_NOTCONN = 1 << 22, /* cannot be changed while in-game */ - CON_SRVEXEC = 1 << 28, /* server can make clients run the command */ - CON_NOSRVQUERY = 1 << 29, /* server cannot query the clientside value */ - CON_CCMDEXEC = 1 << 30 /* ClientCmd() function may run the command */ + CON_NOTCONN = 1 << 22, /* cannot be changed while in a server */ + _CON_NE_CCMDEXEC = 1 << 30 /* ClientCmd() can run on client. NE only. */ +}; + +/* + * Placeholder flags for DEF_* usage. Mapped to correct runtime flags at + * registration time (see con_regvar(), con_regcmd()). + */ +enum { + /* + * Causes a command or variable to be registered as hidden on NE. Currently + * does nothing on OE. Cannot be used to hide/unhide something after + * registration. Use con_hide() or con_unhide() for that. + */ + CON_INIT_HIDDEN = 1 << 29 }; /* A callback function invoked by SST to execute its own commands. */ @@ -446,6 +452,16 @@ extern struct _con_vtab_iconvar_wrap { void con_regvar(struct con_var *v); void con_regcmd(struct con_cmd *c); +/* + * These functions cause a command or variable to be hidden or unhidden from + * autocompletion and command listing results, on engine branches which support + * doing so. In practice this means anything that's not OE. On OE, these + * functions currently just do nothing, although it would be possible in theory + * to patch in command-hiding support if deemed important enough. + */ +void con_hide(struct con_cmdbase *b); +void con_unhide(struct con_cmdbase *b); + #endif // vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/fixes.c b/src/fixes.c index 733616b..6a34c43 100644 --- a/src/fixes.c +++ b/src/fixes.c @@ -30,8 +30,11 @@ #include "ppmagic.h" #include "sst.h" -static void chflags(const char *name, int unset, int set) { +static inline void chflags(const char *name, int unset, int unset_ne, int set) { struct con_var *v = con_findvar(name); + if_hot (!GAMETYPE_MATCHES(OE)) { + unset |= unset_ne; + } if (v) { struct con_var *p = con_getvarcommon(v)->parent; p->base.flags = p->base.flags & ~unset | set; @@ -39,18 +42,21 @@ static void chflags(const char *name, int unset, int set) { } static inline void unhide(const char *name) { - chflags(name, CON_HIDDEN | CON_DEVONLY, 0); + chflags(name, 0, _CON_NE_HIDDEN | _CON_NE_DEVONLY, 0); } -static void chcmdflags(const char *name, int unset, int set) { +static inline void chcmdflags(const char *name, int unset, int unset_ne, + int set) { struct con_cmd *v = con_findcmd(name); if (v) v->base.flags = v->base.flags & ~unset | set; } static inline void unhidecmd(const char *name) { - chcmdflags(name, CON_HIDDEN | CON_DEVONLY, 0); + chcmdflags(name, 0, _CON_NE_HIDDEN | _CON_NE_DEVONLY, 0); } +// TOOD(opt): had to hack this up badly for OE compat. think of a nicer way? + static void generalfixes() { // Expose all the demo stuff, for games like L4D that hide it for some // reason. @@ -75,47 +81,74 @@ static void generalfixes() { // things that could conceivably cause issues with speedrun verification // and/or pedantic following of rules; throw on cheat flag. this could be // relaxed with the Eventual Fancy Demo Verification Stuff. - chflags("director_afk_timeout", CON_HIDDEN | CON_DEVONLY, CON_CHEAT); - chflags("mp_restartgame", CON_HIDDEN | CON_DEVONLY, CON_CHEAT); + chflags("mp_restartgame", 0, _CON_NE_HIDDEN | _CON_NE_DEVONLY, CON_CHEAT); // also, ensure the initial state of sv_cheats goes into demos so you can't // start a demo with cheats already on and then do something subtle - chflags("sv_cheats", 0, CON_DEMO); + chflags("sv_cheats", 0, 0, CON_DEMO); // also, let people use developer, it's pretty handy. ensure it goes in the // demo though. even though it's obvious looking at a video, maybe some day // a game will want to require demos only (probably not till demos are more // robust anyway... whatever) - chflags("developer", CON_HIDDEN | CON_DEVONLY, CON_DEMO); + chflags("developer", 0, _CON_NE_HIDDEN | _CON_NE_DEVONLY, CON_DEMO); +} + +static void l4dspecific() { + // NOTE: using unconditional dev-only flags here since we know it's NE. + chflags("director_afk_timeout", _CON_NE_HIDDEN | _CON_NE_DEVONLY, 0, + CON_CHEAT); // fps_max policy varies a bit between speedgames and their communities! // in theory we might wanna remove CON_NOTCONN on Portal 1 in a future // release, but for now people haven't fully talked themselves into it. - if (GAMETYPE_MATCHES(L4Dx)) { - struct con_var *v = con_findvar("fps_max"); - // for L4D games, generally changing anything above normal limits is - // disallowed, but externally capping FPS will always be possible so we - // might as well allow lowering it ingame for convenience. - struct con_var *p = con_getvarcommon(v)->parent; - struct con_var_common *c = con_getvarcommon(p); - if (p->base.flags & (CON_HIDDEN | CON_DEVONLY)) { - p->base.flags &= ~(CON_HIDDEN | CON_DEVONLY); - c->hasmax = true; c->maxval = 300; - } - else if (!c->hasmax) { - // in TLS, this was made changeable, but still limit to 1000 to - // prevent breaking the engine - c->hasmax = true; c->maxval = 1000; - } - // also show the lower limit in help, and prevent 0 (which is unlimited) - c->hasmin = true; c->minval = 30; - con_setvarf(v, con_getvarf(v)); // hack: reapply limit if we loaded late + struct con_var *v = con_findvar("fps_max"); + // for L4D games, generally changing anything above normal limits is + // disallowed, but externally capping FPS will always be possible so we + // might as well allow lowering it in-game for convenience. + struct con_var *p = con_getvarcommon(v)->parent; + struct con_var_common *c = con_getvarcommon(p); + if (p->base.flags & (_CON_NE_HIDDEN | _CON_NE_DEVONLY)) { + p->base.flags &= ~(_CON_NE_HIDDEN | _CON_NE_DEVONLY); + c->hasmax = true; c->maxval = 300; } + else if (!c->hasmax) { + // in TLS, this was made changeable, but still limit to 1000 to + // prevent breaking the engine + c->hasmax = true; c->maxval = 1000; + } + // also show the lower limit in help, and prevent 0 (which is unlimited) + c->hasmin = true; c->minval = 30; + con_setvarf(v, con_getvarf(v)); // hack: reapply limit if we loaded late +} + +static void l4d1specific() { + // For some reason, L4D1 hides mat_monitorgamma and doesn't archive it. + // This means on every startup it's necessary to manually set non-default + // values via the menu. This change here brings it in line with pretty much + // all other Source games for convenience. + chflags("mat_monitorgamma", _CON_NE_HIDDEN | _CON_NE_DEVONLY, 0, + CON_ARCHIVE); + + // Very early versions of L4D1 have a bunch of useless console spam. Setting + // these hidden variables to 0 gets rid of it. + struct con_var *v = con_findvar("ui_l4d_debug"); + if (v) con_setvari(v, 0); + v = con_findvar("mm_l4d_debug"); + if (v) con_setvari(v, 0); + + // same thing as above, seemed easier to just dupe :) + chcmdflags("cl_fullupdate", CON_CHEAT, 0, 0); + + // These commands lack CLIENTCMD_CAN_EXECUTE, so enabling/disabling addons + // doesn't work without manually running these in the console afterwards. + chcmdflags("mission_reload", 0, 0, _CON_NE_CCMDEXEC); + chcmdflags("update_addon_paths", 0, 0, _CON_NE_CCMDEXEC); } static void l4d2specific() { // L4D2 doesn't let you set sv_cheats in lobbies, but turns out it skips all - // the lobby checks if this random command is developer-only, presumably + // the lobby checks if this random command is not developer-only, presumably // because that flag is compiled out in debug builds and devs want to be // able to use cheats. Took literally hours of staring at Ghidra to find // this out. Good meme 8/10. @@ -137,13 +170,13 @@ static void l4d2specific() { if_hot (v && !(p->base.flags & CON_ARCHIVE)) { // not already fixed struct con_var_common *c = con_getvarcommon(p); p->base.flags = p->base.flags & - ~(CON_HIDDEN | CON_DEVONLY) | CON_ARCHIVE; + ~(_CON_NE_HIDDEN | _CON_NE_DEVONLY) | CON_ARCHIVE; c->hasmin = true; c->minval = -1; c->hasmax = true; c->maxval = 0; } #ifdef _WIN32 - // L4D2 has broken (dark) rendering on Intel iGPUs unless + // L4D2 has broken (overly dark) rendering on Intel iGPUs unless // mat_tonemapping_occlusion_use_stencil is enabled. Supposedly Valve used // to detect device IDs to enable it on, but new devices are still broken, // so just blanket enable it if the primary adapter is Intel, since it @@ -171,30 +204,7 @@ e: // We're preemptively removing its cheat flag here, so if it turns out to be // absolutely necessary, people can use it. If it doesn't work, or some // other workaround is found, this might get reverted. - chcmdflags("cl_fullupdate", CON_CHEAT, 0); -} - -static void l4d1specific() { - // For some reason, L4D1 hides mat_monitorgamma and doesn't archive it. - // This means on every startup it's necessary to manually set non-default - // values via the menu. This change here brings it in line with pretty much - // all other Source games for convenience. - chflags("mat_monitorgamma", CON_HIDDEN | CON_DEVONLY, CON_ARCHIVE); - - // Very early versions of L4D1 have a bunch of useless console spam. Setting - // these hidden variables to 0 gets rid of it. - struct con_var *v = con_findvar("ui_l4d_debug"); - if (v) con_setvari(v, 0); - v = con_findvar("mm_l4d_debug"); - if (v) con_setvari(v, 0); - - // same thing as above, seemed easier to just dupe :) - chcmdflags("cl_fullupdate", CON_CHEAT, 0); - - // These commands lack CLIENTCMD_CAN_EXECUTE, so enabling/disabling addons - // doesn't work without manually running these in the console afterwards. - chcmdflags("mission_reload", 0, CON_CCMDEXEC); - chcmdflags("update_addon_paths", 0, CON_CCMDEXEC); + chcmdflags("cl_fullupdate", CON_CHEAT, 0, 0); } static void portal1specific() { @@ -223,9 +233,14 @@ static void portal1specific() { void fixes_apply() { generalfixes(); - if (GAMETYPE_MATCHES(L4D1)) l4d1specific(); - else if (GAMETYPE_MATCHES(L4D2x)) l4d2specific(); - else if (GAMETYPE_MATCHES(Portal1)) portal1specific(); + if (GAMETYPE_MATCHES(L4Dx)) { + l4dspecific(); + if (GAMETYPE_MATCHES(L4D1)) l4d1specific(); + else if (GAMETYPE_MATCHES(L4D2x)) l4d2specific(); + } + else if (GAMETYPE_MATCHES(Portal1)) { + portal1specific(); + } } // vi: sw=4 ts=4 noet tw=80 cc=80 @@ -42,7 +42,7 @@ REQUEST(ent) DEF_CVAR_MINMAX_UNREG(fov_desired, "Set the base field of view (SST reimplementation)", 75, 75, 120, - CON_HIDDEN | CON_ARCHIVE) + CON_INIT_HIDDEN | CON_ARCHIVE) static struct con_var *real_fov_desired; // engine's if it has it, or ours typedef void (*VCALLCONV SetDefaultFOV_func)(void *, int); @@ -111,9 +111,10 @@ INIT { // we might not be using our cvar but simpler to do this unconditionally fov_desired->cb = &fovcb; - fov_desired->base.flags &= ~CON_HIDDEN; + con_unhide(&fov_desired->base); // hide the original fov command since we've effectively broken it anyway :) - cmd_fov->base.flags |= CON_DEVONLY; + // NOTE: assumes NE. fine for now because we're GAMESPECIFIC. + cmd_fov->base.flags |= _CON_NE_DEVONLY; return FEAT_OK; } @@ -130,7 +131,7 @@ END { if (player) orig_SetDefaultFOV(player, 75); } unhook_inline((void *)orig_SetDefaultFOV); - cmd_fov->base.flags &= ~CON_DEVONLY; + cmd_fov->base.flags &= ~_CON_NE_DEVONLY; } // vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/nomute.c b/src/nomute.c index 8cdb823..9b69dad 100644 --- a/src/nomute.c +++ b/src/nomute.c @@ -34,7 +34,7 @@ FEATURE("inactive window audio control") DEF_CVAR_UNREG(snd_mute_losefocus, "Keep playing audio while tabbed out (SST reimplementation)", 1, - CON_ARCHIVE | CON_HIDDEN) + CON_ARCHIVE | CON_INIT_HIDDEN) static IDirectSoundVtbl *ds_vt = 0; static typeof(ds_vt->CreateSoundBuffer) orig_CreateSoundBuffer; @@ -81,7 +81,7 @@ INIT { orig_CreateSoundBuffer = ds_vt->CreateSoundBuffer; ds_vt->CreateSoundBuffer = &hook_CreateSoundBuffer; - snd_mute_losefocus->base.flags &= ~CON_HIDDEN; + con_unhide(&snd_mute_losefocus->base); struct con_cmd *snd_restart = con_findcmd("snd_restart"); if_hot (snd_restart) { snd_restart_cb = con_getcmdcbv1(snd_restart); diff --git a/src/nosleep.c b/src/nosleep.c index b440bf3..3ac4069 100644 --- a/src/nosleep.c +++ b/src/nosleep.c @@ -31,7 +31,7 @@ REQUIRE_GLOBAL(inputsystem) DEF_CVAR_UNREG(engine_no_focus_sleep, "Delay while tabbed out (SST reimplementation)", 50, - CON_ARCHIVE | CON_HIDDEN) + CON_ARCHIVE | CON_INIT_HIDDEN) static void **vtable; @@ -56,7 +56,7 @@ INIT { } orig_SleepUntilInput = (SleepUntilInput_func)hook_vtable(vtable, vtidx_SleepUntilInput, (void *)&hook_SleepUntilInput); - engine_no_focus_sleep->base.flags &= ~CON_HIDDEN; + con_unhide(&engine_no_focus_sleep->base); return FEAT_OK; } diff --git a/src/rinput.c b/src/rinput.c index 1e957b0..554577c 100644 --- a/src/rinput.c +++ b/src/rinput.c @@ -61,10 +61,10 @@ static union { // space saving #define vtable_insys U.vtable_insys DEF_CVAR_UNREG(m_rawinput, "Use Raw Input for mouse input (SST reimplementation)", - 0, CON_ARCHIVE | CON_HIDDEN) + 0, CON_ARCHIVE | CON_INIT_HIDDEN) DEF_CVAR_MINMAX(sst_mouse_factor, "Number of hardware mouse counts per step", - 1, 1, 100, /*CON_ARCHIVE |*/ CON_HIDDEN) + 1, 1, 100, /*CON_ARCHIVE |*/ CON_INIT_HIDDEN) static ssize __stdcall inproc(void *wnd, uint msg, usize wp, ssize lp) { switch (msg) { @@ -205,8 +205,8 @@ INIT { hook_inline_commit(h1.prologue, (void *)&hook_GetCursorPos); hook_inline_commit(h2.prologue, (void *)&hook_SetCursorPos); -ok: m_rawinput->base.flags &= ~CON_HIDDEN; - sst_mouse_factor->base.flags &= ~CON_HIDDEN; +ok: con_unhide(&m_rawinput->base); + con_unhide(&sst_mouse_factor->base); return FEAT_OK; e1: DestroyWindow(inwin); @@ -245,7 +245,7 @@ DEF_CCMD_HERE(sst_printversion, "Display plugin version information", 0) { #error Need to change this manually, since gluegen requires it to be spelled \ out in DEF_CVAR - better yet, can we get rid of this yet? #endif -DEF_CVAR(__sst_0_15_beta, "", 0, CON_HIDDEN | CON_DEMO) +DEF_CVAR(__sst_0_15_beta, "", 0, CON_INIT_HIDDEN | CON_DEMO) // most plugin callbacks are unused - define dummy functions for each signature static void VCALLCONV nop_v_v(void *this) {} |
