aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Michael Smith <mikesmiffy128@gmail.com> 2025-06-21 14:46:10 +0100
committerGravatar Michael Smith <mikesmiffy128@gmail.com> 2025-06-21 14:50:00 +0100
commitf38fc784ffab00c11b9818d18f55be34cc8aa130 (patch)
treea6370ebb95506003ae6b984f724d42369efae366
parentac7e7d0f21978afc70fe3ef76db69d575742b974 (diff)
downloadsst-f38fc784ffab00c11b9818d18f55be34cc8aa130.tar.gz
sst-f38fc784ffab00c11b9818d18f55be34cc8aa130.zip
Abstract over con_var layout changes from OE to NE
This doesn't allow us to support OE in and of itself but is part of the groundwork necessary to do so in the future.
-rw-r--r--src/autojump.c2
-rw-r--r--src/build/gluegen.c3
-rw-r--r--src/con_.c55
-rw-r--r--src/con_.h52
-rw-r--r--src/fixes.c29
-rw-r--r--src/fov.c17
-rw-r--r--src/inputhud.c14
7 files changed, 108 insertions, 64 deletions
diff --git a/src/autojump.c b/src/autojump.c
index 2656796..eb0e34f 100644
--- a/src/autojump.c
+++ b/src/autojump.c
@@ -78,7 +78,7 @@ static bool unprot(struct CGameMovement *gm) {
// reimplementing cheats check for dumb and bad reasons, see below
static struct con_var *sv_cheats;
static void cheatcb(struct con_var *this) {
- if (this->ival) if_cold (!con_getvari(sv_cheats)) {
+ if (con_getvari(this)) if_cold (!con_getvari(sv_cheats)) {
con_warn("Can't use cheat cvar sst_autojump, unless server has "
"sv_cheats set to 1.\n");
con_setvari(this, 0);
diff --git a/src/build/gluegen.c b/src/build/gluegen.c
index bc973fb..e2bc2f3 100644
--- a/src/build/gluegen.c
+++ b/src/build/gluegen.c
@@ -869,7 +869,8 @@ _( "}")
_( "")
_( "static inline void freevars() {")
for (int i = 1; i < ncvars; ++i) {
-F( " extfree(%.*s->strval);", cvar_names[i].len, cvar_names[i].s)
+F( " extfree(con_getvarcommon(%.*s)->strval);",
+ cvar_names[i].len, cvar_names[i].s)
}
_( "}")
for (int i = 1; i < nevents; ++i) {
diff --git a/src/con_.c b/src/con_.c
index b2d7e29..d0ad7ce 100644
--- a/src/con_.c
+++ b/src/con_.c
@@ -65,8 +65,8 @@ struct ICvar *_con_iface;
ConsoleColorPrintf_func _con_colourmsgf;
static inline void initval(struct con_var *v) {
- v->strval = extmalloc(v->strlen); // note: strlen is preset in _DEF_CVAR()
- memcpy(v->strval, v->defaultval, v->strlen);
+ v->v2.strval = extmalloc(v->v2.strlen); // note: _DEF_CVAR() sets strlen
+ memcpy(v->v2.strval, v->v2.defaultval, v->v2.strlen);
}
static void VCALLCONV dtor(void *_) {} // we don't use constructors/destructors
@@ -122,8 +122,14 @@ static void VCALLCONV Create_base(struct con_cmdbase *this, const char *name,
static void VCALLCONV Init(struct con_cmdbase *this) {} // ""
static bool VCALLCONV ClampValue(struct con_var *this, float *f) {
- if (this->hasmin && this->minval > *f) { *f = this->minval; return true; }
- if (this->hasmax && this->maxval < *f) { *f = this->maxval; return true; }
+ if (this->v2.hasmin && this->v2.minval > *f) {
+ *f = this->v2.minval;
+ return true;
+ }
+ if (this->v2.hasmax && this->v2.maxval < *f) {
+ *f = this->v2.maxval;
+ return true;
+ }
return false;
}
@@ -141,14 +147,14 @@ void VCALLCONV Dispatch(struct con_cmd *this, const struct con_cmdargs *args) {
static void VCALLCONV ChangeStringValue(struct con_var *this, const char *s,
float oldf) {
- char *old = alloca(this->strlen);
- memcpy(old, this->strval, this->strlen);
+ char *old = alloca(this->v2.strlen);
+ memcpy(old, this->v2.strval, this->v2.strlen);
int len = strlen(s) + 1;
- if (len > this->strlen) {
- this->strval = extrealloc(this->strval, len);
- this->strlen = len;
+ if (len > this->v2.strlen) {
+ this->v2.strval = extrealloc(this->v2.strval, len);
+ this->v2.strlen = len;
}
- memcpy(this->strval, s, len);
+ memcpy(this->v2.strval, s, len);
// callbacks don't matter as far as ABI compat goes (and thank goodness
// because e.g. portal2 randomly adds a *list* of callbacks!?). however we
// do need callbacks for at least one feature, so do our own minimal thing
@@ -163,41 +169,39 @@ static void VCALLCONV ChangeStringValue(struct con_var *this, const char *s,
// *should* be calling these internal things anyway.
static void VCALLCONV InternalSetValue(struct con_var *this, const char *v) {
- float oldf = this->fval;
+ float oldf = this->v2.fval;
float newf = atof(v);
char tmp[32];
- // NOTE: calling our own ClampValue and ChangeString, not bothering with
- // vtable (it's internal anyway, so we're never calling into engine code)
if (ClampValue(this, &newf)) {
snprintf(tmp, sizeof(tmp), "%f", newf);
v = tmp;
}
- this->fval = newf;
- this->ival = (int)newf;
+ this->v2.fval = newf;
+ this->v2.ival = (int)newf;
if (!(this->base.flags & CON_NOPRINT)) ChangeStringValue(this, v, oldf);
}
static void VCALLCONV InternalSetFloatValue(struct con_var *this, float v) {
- if (v == this->fval) return;
+ if (v == this->v2.fval) return;
ClampValue(this, &v);
- float old = this->fval;
- this->fval = v; this->ival = (int)this->fval;
+ float old = this->v2.fval;
+ this->v2.fval = v; this->v2.ival = (int)this->v2.fval;
if (!(this->base.flags & CON_NOPRINT)) {
char tmp[32];
- snprintf(tmp, sizeof(tmp), "%f", this->fval);
+ snprintf(tmp, sizeof(tmp), "%f", this->v2.fval);
ChangeStringValue(this, tmp, old);
}
}
static void VCALLCONV InternalSetIntValue(struct con_var *this, int v) {
- if (v == this->ival) return;
+ if (v == this->v2.ival) return;
float f = (float)v;
if (ClampValue(this, &f)) v = (int)f;
- float old = this->fval;
- this->fval = f; this->ival = v;
+ float old = this->v2.fval;
+ this->v2.fval = f; this->v2.ival = v;
if (!(this->base.flags & CON_NOPRINT)) {
char tmp[32];
- snprintf(tmp, sizeof(tmp), "%f", this->fval);
+ snprintf(tmp, sizeof(tmp), "%f", this->v2.fval);
ChangeStringValue(this, tmp, old);
}
}
@@ -465,7 +469,10 @@ struct con_cmd *con_findcmd(const char *name) {
// NOTE: getters here still go through the parent pointer although we stopped
// doing that internally, just in case we run into parented cvars in the actual
// engine. a little less efficient, but safest and simplest for now.
-#define GETTER(T, N, M) T N(const struct con_var *v) { return v->parent->M; }
+#define GETTER(T, N, M) \
+ T N(const struct con_var *v) { \
+ return v->v2.parent->v2.M; \
+ }
GETTER(const char *, con_getvarstr, strval)
GETTER(float, con_getvarf, fval)
GETTER(int, con_getvari, ival)
diff --git a/src/con_.h b/src/con_.h
index b491aad..c2c0cce 100644
--- a/src/con_.h
+++ b/src/con_.h
@@ -117,9 +117,7 @@ struct con_cmd { // ConCommand in engine
bool has_complcb : 1, use_newcb : 1, use_newcmdiface : 1;
};
-struct con_var { // ConVar in engine
- struct con_cmdbase base;
- void **vtable_iconvar; // IConVar in engine (pure virtual)
+struct con_var_common {
struct con_var *parent;
const char *defaultval;
char *strval;
@@ -131,8 +129,19 @@ struct con_var { // ConVar in engine
float minval;
bool hasmax; // just sticking to sdk position
float maxval;
+};
+
+struct con_var { // ConVar in engine
+ struct con_cmdbase base;
+ union {
+ struct con_var_common v1;
+ struct {
+ void **vtable_iconvar; // IConVar in engine (pure virtual)
+ struct con_var_common v2;
+ };
+ };
/*
- * Our quickly-chucked-in optional callback - doesn't match the engine!!
+ * Our quickly-chucked-in optional callback - doesn't match the engine ABI!
* Also has to be manually set in code, although that's probably fine anyway
* as it's common to only want a cvar to do something if the feature
* succesfully init-ed.
@@ -143,13 +152,27 @@ struct con_var { // ConVar in engine
/* The change callback used in most branches of Source. Takes an IConVar :) */
typedef void (*con_varcb)(void *v, const char *, float);
+
+/* Returns a registered variable with the given name, or null if not found. */
+struct con_var *con_findvar(const char *name);
+
+/* Returns a registered command with the given name, or null if not found. */
+struct con_cmd *con_findcmd(const char *name);
+
+/*
+ * Returns a pointer to the common (i.e. middle) part of a ConVar struct, the
+ * offset of which varies by engine version. This sub-struct contains
+ * essentially all the actual cvar-specific data.
+ */
+static inline struct con_var_common *con_getvarcommon(struct con_var *v) {
+ return &v->v2;
+}
+
/*
* These functions get and set the values of console variables in a
* neatly-abstracted manner. Note: cvar values are always strings internally -
* numerical values are just interpretations of the underlying value.
*/
-struct con_var *con_findvar(const char *name);
-struct con_cmd *con_findcmd(const char *name);
const char *con_getvarstr(const struct con_var *v);
float con_getvarf(const struct con_var *v);
int con_getvari(const struct con_var *v);
@@ -236,13 +259,16 @@ extern struct _con_vtab_iconvar_wrap {
.name = "" #name_, .help = "" desc, .flags = (flags_) \
}, \
.vtable_iconvar = _con_vtab_iconvar, \
- .parent = &_cvar_##name_, /* bizarre, but how the engine does it */ \
- .defaultval = _Generic(value, char *: value, int: #value, \
- double: #value), \
- .strlen = sizeof(_Generic(value, char *: value, default: #value)), \
- .fval = _Generic(value, char *: 0, int: value, double: value), \
- .ival = _Generic(value, char *: 0, int: value, double: (int)value), \
- .hasmin = hasmin_, .minval = (min), .hasmax = hasmax_, .maxval = (max) \
+ .v2 = { \
+ .parent = &_cvar_##name_, /* bizarre, but how the engine does it */ \
+ .defaultval = _Generic(value, char *: value, int: #value, \
+ double: #value), \
+ .strlen = sizeof(_Generic(value, char *: value, default: #value)), \
+ .fval = _Generic(value, char *: 0, int: value, double: value), \
+ .ival = _Generic(value, char *: 0, int: value, double: (int)value), \
+ .hasmin = hasmin_, .minval = (min), \
+ .hasmax = hasmax_, .maxval = (max) \
+ } \
}; \
struct con_var *name_ = &_cvar_##name_;
diff --git a/src/fixes.c b/src/fixes.c
index ea008e5..d4b5330 100644
--- a/src/fixes.c
+++ b/src/fixes.c
@@ -32,7 +32,10 @@
static void chflags(const char *name, int unset, int set) {
struct con_var *v = con_findvar(name);
- if (v) v->parent->base.flags = v->parent->base.flags & ~unset | set;
+ if (v) {
+ struct con_var *p = con_getvarcommon(v)->parent;
+ p->base.flags = p->base.flags & ~unset | set;
+ }
}
static inline void unhide(const char *name) {
@@ -93,17 +96,19 @@ static void generalfixes() {
// 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.
- if (v->parent->base.flags & (CON_HIDDEN | CON_DEVONLY)) {
- v->parent->base.flags &= ~(CON_HIDDEN | CON_DEVONLY);
- v->parent->hasmax = true; v->parent->maxval = 300;
+ 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 (!v->parent->hasmax) {
+ else if (!c->hasmax) {
// in TLS, this was made changeable, but still limit to 1000 to
// prevent breaking the engine
- v->parent->hasmax = true; v->parent->maxval = 1000;
+ c->hasmax = true; c->maxval = 1000;
}
// also show the lower limit in help, and prevent 0 (which is unlimited)
- v->parent->hasmin = true; v->parent->minval = 30;
+ c->hasmin = true; c->minval = 30;
con_setvarf(v, con_getvarf(v)); // hack: reapply limit if we loaded late
}
}
@@ -128,11 +133,13 @@ static void l4d2specific() {
// possible on these earlier versions (who knows if that breaks
// something...).
struct con_var *v = con_findvar("mat_queue_mode");
- if_hot (v && !(v->parent->base.flags & CON_ARCHIVE)) { // not already fixed
- v->parent->base.flags = v->parent->base.flags &
+ struct con_var *p = con_getvarcommon(v)->parent;
+ 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;
- v->parent->hasmin = true; v->parent->minval = -1;
- v->parent->hasmax = true; v->parent->maxval = 0;
+ c->hasmin = true; c->minval = -1;
+ c->hasmax = true; c->maxval = 0;
}
#ifdef _WIN32
diff --git a/src/fov.c b/src/fov.c
index bfef858..2ef13e9 100644
--- a/src/fov.c
+++ b/src/fov.c
@@ -24,7 +24,6 @@
#include "ent.h"
#include "event.h"
#include "feature.h"
-#include "gametype.h"
#include "hook.h"
#include "intdefs.h"
#include "langext.h"
@@ -88,8 +87,10 @@ INIT {
if_cold (!cmd_fov) return FEAT_INCOMPAT; // shouldn't happen, but who knows!
if (real_fov_desired = con_findvar("fov_desired")) {
// latest steampipe already goes up to 120 fov
- if (real_fov_desired->parent->maxval == 120) return FEAT_SKIP;
- real_fov_desired->parent->maxval = 120;
+ struct con_var *p = con_getvarcommon(real_fov_desired)->parent;
+ struct con_var_common *c = con_getvarcommon(p);
+ if (c->maxval == 120) return FEAT_SKIP;
+ c->maxval = 120;
}
else {
if (!has_ent) return FEAT_INCOMPAT;
@@ -109,7 +110,7 @@ INIT {
// we might not be using our cvar but simpler to do this unconditionally
fov_desired->cb = &fovcb;
- fov_desired->parent->base.flags &= ~CON_HIDDEN;
+ fov_desired->base.flags &= ~CON_HIDDEN;
// hide the original fov command since we've effectively broken it anyway :)
cmd_fov->base.flags |= CON_DEVONLY;
return FEAT_OK;
@@ -118,10 +119,10 @@ INIT {
END {
if_hot (!sst_userunloaded) return;
if (real_fov_desired && real_fov_desired != fov_desired) {
- real_fov_desired->parent->maxval = 90;
- if (con_getvarf(real_fov_desired) > 90) {
- con_setvarf(real_fov_desired, 90); // blegh.
- }
+ struct con_var *p = con_getvarcommon(real_fov_desired)->parent;
+ struct con_var_common *c = con_getvarcommon(p);
+ c->maxval = 90;
+ if (c->fval > 90) con_setvarf(real_fov_desired, 90); // blegh.
}
else {
void *player = ent_get(1); // also singleplayer only
diff --git a/src/inputhud.c b/src/inputhud.c
index fdefe6a..b93e9d8 100644
--- a/src/inputhud.c
+++ b/src/inputhud.c
@@ -432,14 +432,16 @@ INIT {
// HL2 sprint HUD, so move it up. This is a bit yucky, but at least we don't
// have to go through all the virtual setter crap twice...
if (GAMETYPE_MATCHES(L4D)) {
- sst_inputhud_y->defaultval = "0.82";
- sst_inputhud_y->fval = 0.82f;
- sst_inputhud_y->ival = 0;
+ struct con_var_common *c = con_getvarcommon(sst_inputhud_y);
+ c->defaultval = "0.82";
+ c->fval = 0.82f;
+ c->ival = 0;
}
else if (GAMETYPE_MATCHES(HL2series)) {
- sst_inputhud_y->defaultval = "0.75";
- sst_inputhud_y->fval = 0.75f;
- sst_inputhud_y->ival = 0;
+ struct con_var_common *c = con_getvarcommon(sst_inputhud_y);
+ c->defaultval = "0.75";
+ c->fval = 0.75f;
+ c->ival = 0;
}
return FEAT_OK;