aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Michael Smith <mikesmiffy128@gmail.com> 2025-11-15 20:24:41 +0000
committerGravatar Michael Smith <mikesmiffy128@gmail.com> 2025-11-15 20:24:41 +0000
commitc15101df02685a5d26f4b130f7b559eb7ed7f74f (patch)
tree5803259d20a291278c9cc7dfd6bc346198f0edb0
parent650bb761d3e5af3f8fa19ac8d22864cc0360d085 (diff)
downloadsst-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.c3
-rw-r--r--src/con_.c18
-rw-r--r--src/con_.h52
-rw-r--r--src/fixes.c129
-rw-r--r--src/fov.c9
-rw-r--r--src/nomute.c4
-rw-r--r--src/nosleep.c4
-rw-r--r--src/rinput.c8
-rw-r--r--src/sst.c2
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)
_( " }")
}
diff --git a/src/con_.c b/src/con_.c
index c316318..7552816 100644
--- a/src/con_.c
+++ b/src/con_.c
@@ -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
diff --git a/src/con_.h b/src/con_.h
index 63e79c1..d75c2af 100644
--- a/src/con_.h
+++ b/src/con_.h
@@ -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
diff --git a/src/fov.c b/src/fov.c
index c822584..8bfa2ab 100644
--- a/src/fov.c
+++ b/src/fov.c
@@ -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);
diff --git a/src/sst.c b/src/sst.c
index fc35b53..e6737bb 100644
--- a/src/sst.c
+++ b/src/sst.c
@@ -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) {}