summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMichael Smith <mikesmiffy128@gmail.com>2023-06-10 16:44:19 +0100
committerMichael Smith <mikesmiffy128@gmail.com>2023-06-10 16:51:02 +0100
commit1c4318331663b152b0b298bd2c9e5c971506a86b (patch)
treea402681cb84b491819ba5018525c16340110fd4d
parent602a18977d500ad068fd63fbedcafb630c29ee72 (diff)
Prune some comments and tidy up other minor things
-rw-r--r--compile.bat11
-rw-r--r--src/ac.c3
-rw-r--r--src/alias.c1
-rw-r--r--src/alias.h5
-rw-r--r--src/bind.c3
-rw-r--r--src/bitbuf.h5
-rw-r--r--src/con_.c50
-rw-r--r--src/con_.h5
-rw-r--r--src/democustom.c7
-rw-r--r--src/demorec.c32
-rw-r--r--src/dictmaptree.h2
-rw-r--r--src/engineapi.c9
-rw-r--r--src/ent.c8
-rw-r--r--src/fixes.c3
-rw-r--r--src/fov.c10
-rw-r--r--src/gamedata.c4
-rw-r--r--src/gamedata.h8
-rw-r--r--src/gameinfo.c5
-rw-r--r--src/hook.c6
-rw-r--r--src/kvsys.c3
-rw-r--r--src/l4dmm.c2
-rw-r--r--src/l4dreset.c39
-rw-r--r--src/l4dwarp.c6
-rw-r--r--src/mem.h12
-rw-r--r--src/nomute.c8
-rw-r--r--src/os-win32.h3
-rw-r--r--src/sst.c28
27 files changed, 113 insertions, 165 deletions
diff --git a/compile.bat b/compile.bat
index 660ebe7..17dd919 100644
--- a/compile.bat
+++ b/compile.bat
@@ -17,9 +17,12 @@ set warnings=-Wall -pedantic -Wno-parentheses -Wno-missing-braces ^
-Wno-gnu-zero-variadic-macro-arguments
set dbg=0
+:: XXX: -Og would be nice but apparently a bunch of stuff still gets inlined
+:: which can be somewhat annoying so -O0 it is. Still using -Og in the linux
+:: script; will need to investigate when linux is actually a thing later.
if "%dbg%"=="1" (
- set cflags=-Og -g
- set ldflags=-Og -g
+ set cflags=-O0 -g3
+ set ldflags=-O0 -g3
) else (
set cflags=-O2
set ldflags=-O2
@@ -99,8 +102,8 @@ llvm-rc /FO .build\dll.res src\dll.rc || exit /b
%CC% -shared -O0 -w -o .build/tier0.dll src/stubs/tier0.c
%CC% -shared -O0 -w -o .build/vstdlib.dll src/stubs/vstdlib.c
for %%b in (%src%) do ( call :cc %%b || exit /b )
+:: we need different library names for debugging because Microsoft.
if "%dbg%"=="1" (
- :: ugh, microsoft.
set clibs=-lmsvcrtd -lvcruntimed -lucrtd
) else (
set clibs=-lmsvcrt -lvcruntime -lucrt
@@ -113,6 +116,8 @@ del .build\sst.lib
%HOSTCC% -O2 -g -include test/test.h -o .build/bitbuf.test.exe test/bitbuf.test.c || exit /b
.build\bitbuf.test.exe || exit /b
+%HOSTCC% -O2 -g -include test/test.h -o .build/crc32.test.exe test/crc32.test.c || exit /b
+.build\crc32.test.exe || exit /b
:: special case: test must be 32-bit
%HOSTCC% -m32 -O2 -g -ladvapi32 -include test/test.h -o .build/hook.test.exe test/hook.test.c || exit /b
.build\hook.test.exe || exit /b
diff --git a/src/ac.c b/src/ac.c
index c379326..605a2be 100644
--- a/src/ac.c
+++ b/src/ac.c
@@ -230,8 +230,7 @@ static void VCALLCONV hook_DispatchInputEvent(void *this,
static bool find_DispatchInputEvent(void) {
#ifdef _WIN32
- // Crazy pointer-chasing path to get to DispatchInputEvent (to log keypresses
- // and their associated binds):
+ // Crazy pointer-chasing path to get to DispatchInputEvent:
// IGameUIFuncs interface
// -> CGameUIFuncs::GetDesktopResolution vfunc
// -> IGame/CGame (first mov into ECX)
diff --git a/src/alias.c b/src/alias.c
index e390cd1..c660367 100644
--- a/src/alias.c
+++ b/src/alias.c
@@ -76,7 +76,6 @@ static bool find_alias_head(con_cmdcb alias_cb) {
for (const uchar *p = insns; p - insns < 64;) {
// alias command with no args calls ConMsg() then loads the head pointer
// that asm looks like: call <reg>; mov <reg>, dword ptr [x]
- // (we don't care about the exact registers)
if (p[0] == X86_MISCMW && (p[1] & 0xF8) == 0xD0 &&
p[2] == X86_MOVRMW && (p[3] & 0xC7) == 0x05) {
_alias_head = mem_loadptr(p + 4);
diff --git a/src/alias.h b/src/alias.h
index bc125eb..c13f342 100644
--- a/src/alias.h
+++ b/src/alias.h
@@ -19,13 +19,16 @@
struct alias {
struct alias *next;
- char name[32]; // TIL this has a hard limit :^)
+ char name[32];
char *value;
};
extern struct alias **_alias_head;
#define alias_head (*_alias_head) // act as a global
+/* Clears all aliases from the engine's internal list. */
void alias_nuke(void);
+
+/* Removes a specific named alias from the engine's internal list. */
void alias_rm(const char *name);
#endif
diff --git a/src/bind.c b/src/bind.c
index 97864c8..37a34ea 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -39,8 +39,7 @@ static bool find_keyinfo(con_cmdcb klbc_cb) {
#ifdef _WIN32
const uchar *insns = (const uchar *)klbc_cb;
for (const uchar *p = insns; p - insns < 32;) {
- // key_listboundkeys command, in its loop through each possible index,
- // does a mov from that index into a register, something like:
+ // key_listboundkeys loops through each index, moving into a register:
// mov <reg>, dword ptr [<reg> * 8 + s_pKeyInfo]
if (p[0] == X86_MOVRMW && (p[1] & 0xC7) == 4 /* SIB + imm32 */ &&
(p[2] & 0xC7) == 0xC5 /* [immediate + reg * 8] */) {
diff --git a/src/bitbuf.h b/src/bitbuf.h
index 8700af3..a2ee60f 100644
--- a/src/bitbuf.h
+++ b/src/bitbuf.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -49,8 +49,7 @@ static inline void bitbuf_appendbits(struct bitbuf *bb, bitbuf_cell x,
// OR into the existing cell (lower bits were already set!)
bb->buf_as_cells[idx] |= x << shift;
// assign the next cell (that also clears the upper bits for the next OR)
- // note: if nbits fits in the first cell, this just 0s the next cell, which
- // is absolutely fine
+ // if nbits fits in the first cell, this zeros the next cell, which is fine
bb->buf_as_cells[idx + 1] = x >> (bitbuf_cell_bits - shift);
bb->curbit += nbits;
}
diff --git a/src/con_.c b/src/con_.c
index eafc242..6ae1738 100644
--- a/src/con_.c
+++ b/src/con_.c
@@ -38,24 +38,13 @@
* Don't get set on fire. *
\******************************************************************************/
-// given to us by the engine to unregister cvars in bulk on plugin unload
-static int dllid;
-
-// external spaghetti variable, exists only because valve are bad
+static int dllid; // from AllocateDLLIdentifier(), lets us unregister in bulk
int con_cmdclient;
-// these have to be extern because of varargs nonsense - they get wrapped in a
-// macro for the actual api (con_colourmsg)
-void *_con_iface;
-void (*_con_colourmsgf)(void *this, const struct rgba *c, const char *fmt,
- ...) _CON_PRINTF(3, 4);
-
-// bootstrap hackery, see "GENIUS HACK" comment below :)
DECL_VFUNC(void *, FindCommandBase_p2, 13, const char *)
DECL_VFUNC(void *, FindCommand_nonp2, 14, const char *)
DECL_VFUNC(void *, FindVar_nonp2, 12, const char *)
-// rest of these are figured out from gamedata after initial game detection
DECL_VFUNC_DYN(int, AllocateDLLIdentifier)
DECL_VFUNC_DYN(void, RegisterConCommand, /*ConCommandBase*/ void *)
DECL_VFUNC_DYN(void, UnregisterConCommands, int)
@@ -71,35 +60,31 @@ DECL_VFUNC_DYN(void, CallGlobalChangeCallbacks, struct con_var *, const char *,
typedef void (*ConsoleColorPrintf_func)(void *, const struct rgba *,
const char *, ...);
+// these have to be extern for con_colourmsg(), due to varargs nonsense
+void *_con_iface;
+ConsoleColorPrintf_func _con_colourmsgf;
+
static inline void initval(struct con_var *v) {
- // v->strlen is set to defaultval len in _DEF_CVAR so we don't need to call
- // strlen() on each string :)
- v->strval = extmalloc(v->strlen);
+ v->strval = extmalloc(v->strlen); // note: strlen is preset in _DEF_CVAR()
memcpy(v->strval, v->defaultval, v->strlen);
}
-// generated by build/codegen.c, defines regcmds() and freevars()
-#include <cmdinit.gen.h>
+#include <cmdinit.gen.h> // generated by build/codegen.c
-// to try and be like the engine even though it's probably not actually
-// required, we call the Internal* virtual functions by actual virtual lookup.
-// since the vtables are filled dynamically (below), we store this index; other
-// indices are just offset from this one since the 3-or-4 functions are all
-// right next to each other. the #defines allow us to still use the nice vcall
-// stuff.
+// to try and match the engine even though it's probably not strictly required,
+// we call the Internal* virtual functions via the actual vtable. since vtables
+// are built dynamically (below), we store this index; other indices are just
+// offset from it since these 3-or-4 functions are all right next to each other.
static int vtidx_InternalSetValue;
#define vtidx_InternalSetFloatValue (vtidx_InternalSetValue + 1)
#define vtidx_InternalSetIntValue (vtidx_InternalSetValue + 2)
#define vtidx_InternalSetColorValue (vtidx_InternalSetValue + 3)
-// implementation of virtual functions for our vars and commands below...
-
static void VCALLCONV dtor(void *_) {} // we don't use constructors/destructors
static bool VCALLCONV IsCommand_cmd(void *this) { return true; }
static bool VCALLCONV IsCommand_var(void *this) { return false; }
-// flag stuff
static bool VCALLCONV IsFlagSet_cmd(struct con_cmd *this, int flags) {
return !!(this->base.flags & flags);
}
@@ -125,7 +110,6 @@ static int VCALLCONV GetFlags_var(struct con_var *this) {
return this->parent->base.flags;
}
-// basic registration stuff
static const char *VCALLCONV GetName_cmd(struct con_cmd *this) {
return this->base.name;
}
@@ -154,9 +138,8 @@ static bool VCALLCONV ClampValue(struct con_var *this, float *f) {
return false;
}
-// command-specific stuff
int VCALLCONV AutoCompleteSuggest(void *this, const char *partial,
- /* CUtlVector */ void *commands) {
+ /*CUtlVector*/ void *commands) {
// TODO(autocomplete): implement this if needed later
return 0;
}
@@ -164,11 +147,10 @@ bool VCALLCONV CanAutoComplete(void *this) {
return false;
}
void VCALLCONV Dispatch(struct con_cmd *this, const struct con_cmdargs *args) {
- // only try cb, cbv1 and iface should never get used by us
+ // only try cb; cbv1 and iface should never get used by us
if (this->use_newcb && this->cb) this->cb(args);
}
-// var-specific stuff
static void VCALLCONV ChangeStringValue(struct con_var *this, const char *s,
float oldf) {
char *old = alloca(this->strlen);
@@ -232,8 +214,7 @@ DECL_VFUNC_DYN(void, InternalSetFloatValue, float)
DECL_VFUNC_DYN(void, InternalSetIntValue, int)
DECL_VFUNC_DYN(void, InternalSetColorValue, struct rgba)
-// Hack: IConVar things get this-adjusted pointers, we just reverse the offset
-// to get the top pointer.
+// IConVar calls get this-adjusted pointers, so just subtract the offset
static void VCALLCONV SetValue_str_thunk(void *thisoff, const char *v) {
struct con_var *this = mem_offset(thisoff,
-offsetof(struct con_var, vtable_iconvar));
@@ -379,8 +360,7 @@ void con_init(void) {
*pv++ = (void *)&InternalSetFloatValue_impl;
*pv++ = (void *)&InternalSetIntValue_impl;
if (GAMETYPE_MATCHES(L4D2x) || GAMETYPE_MATCHES(Portal2)) { // ugh, annoying
- // This is InternalSetColorValue, but that's basically the same thing,
- // when you think about it.
+ // InternalSetColorValue, literally the same machine instructions as int
*pv++ = (void *)&InternalSetIntValue_impl;
}
*pv++ = (void *)&ClampValue;;
diff --git a/src/con_.h b/src/con_.h
index dcba4d9..9e96741 100644
--- a/src/con_.h
+++ b/src/con_.h
@@ -79,10 +79,7 @@ typedef void (*con_cmdcbv1)(void);
typedef int (*con_complcb)(const char *part,
char cmds[CON_CMD_MAXCOMPLETE][CON_CMD_MAXCOMPLLEN]);
-/*
- * These are called by the plugin load/unload functions; they have no use
- * elsewhere.
- */
+/* These are called on plugin load/unload. They should not be used elsewhere. */
bool con_detect(int pluginver);
void con_init(void);
void con_disconnect(void);
diff --git a/src/democustom.c b/src/democustom.c
index c2c6ae1..0ecbaa3 100644
--- a/src/democustom.c
+++ b/src/democustom.c
@@ -76,11 +76,8 @@ void democustom_write(const void *buf, int len) {
bitbuf_reset(&bb);
}
-// This finds the CDemoRecorder::WriteMessages() function, which takes a raw
-// network packet, wraps it up in the appropriate demo framing format and writes
-// it out to the demo file being recorded.
static bool find_WriteMessages(void) {
- // TODO(compat): probably rewrite this to just scan for a call instruction!
+ // TODO(compat): rewrite this to just scan for a call instruction!
const uchar *insns = (*(uchar ***)demorecorder)[vtidx_RecordPacket];
// RecordPacket calls WriteMessages pretty much right away:
// 56 push esi
@@ -101,8 +98,6 @@ static bool find_WriteMessages(void) {
#endif
if (!memcmp(insns, bytes, sizeof(bytes))) {
ssize off = mem_loadoffset(insns + sizeof(bytes));
- // ... and then offset is relative to the address of whatever is _after_
- // the call instruction... because x86.
WriteMessages = (WriteMessages_func)(insns + sizeof(bytes) + 4 + off);
return true;
}
diff --git a/src/demorec.c b/src/demorec.c
index ee57c12..07e51d1 100644
--- a/src/demorec.c
+++ b/src/demorec.c
@@ -73,9 +73,6 @@ static void VCALLCONV hook_SetSignonState(void *this_, int state) {
typedef void (*VCALLCONV StopRecording_func)(void *);
static StopRecording_func orig_StopRecording;
static void VCALLCONV hook_StopRecording(void *this) {
- // This can be called any number of times in a row, generally twice per load
- // and once per explicit disconnect. Each time the engine sets demonum to 0
- // and recording to false.
bool wasrecording = *recording;
int lastnum = *demonum;
orig_StopRecording(this);
@@ -164,20 +161,17 @@ static void hook_stop_cb(const struct con_cmdargs *args) {
wantstop = false;
}
-// This finds the "demorecorder" global variable (the engine-wide CDemoRecorder
-// instance).
static inline bool find_demorecorder(void) {
#ifdef _WIN32
const uchar *insns = (const uchar *)orig_stop_cb;
- // The "stop" command calls the virtual function demorecorder.IsRecording(),
- // so just look for the load of the "this" pointer into ECX
+ // The stop command loads `demorecorder` into ECX to call IsRecording()
for (const uchar *p = insns; p - insns < 32;) {
if (p[0] == X86_MOVRMW && p[1] == X86_MODRM(0, 1, 5)) {
void **indirect = mem_loadptr(p + 2);
demorecorder = *indirect;
return true;
}
- NEXT_INSN(p, "demorecorder object");
+ NEXT_INSN(p, "global demorecorder object");
}
#else
#warning TODO(linux): implement linux equivalent (cdecl!)
@@ -185,11 +179,9 @@ static inline bool find_demorecorder(void) {
return false;
}
-// This finds "m_bRecording" and "m_nDemoNumber" using the pointer to the
-// original "StopRecording" demorecorder function.
-static inline bool find_recmembers(void *stoprecording) {
+static inline bool find_recmembers(void *StopRecording) {
#ifdef _WIN32
- const uchar *insns = (uchar *)stoprecording;
+ const uchar *insns = (uchar *)StopRecording;
for (const uchar *p = insns; p - insns < 128;) {
// m_nDemoNumber = 0 -> mov dword ptr [<reg> + off], 0
// XXX: might end up wanting constants for the MRM field masks?
@@ -210,15 +202,12 @@ static inline bool find_recmembers(void *stoprecording) {
return false;
}
-// This finds "m_szDemoBaseName" using the pointer to the original
-// "StartRecording" demorecorder function.
-static inline bool find_demoname(void *startrecording) {
+static inline bool find_demoname(void *StartRecording) {
#ifdef _WIN32
- const uchar *insns = (uchar *)startrecording;
+ const uchar *insns = (uchar *)StartRecording;
for (const uchar *p = insns; p - insns < 32;) {
- // the function immediately calls Q_strncpy and copies into a buffer
- // offset from `this` - look for a LEA instruction some time *before*
- // the first call takes place
+ // the function immediately does a Q_strncpy() into a buffer offset from
+ // `this` - look for a LEA some time *before* the first call instruction
if (p[0] == X86_CALL) return false;
if (p[0] == X86_LEA && (p[1] & 0xC0) == 0x80) {
demorec_basename = mem_offset(demorecorder, mem_load32(p + 2));
@@ -235,9 +224,8 @@ static inline bool find_demoname(void *startrecording) {
bool demorec_start(const char *name) {
bool was = *recording;
if (was) return false;
- // easiest way to do this, though dumb, is to just call the record command
- // callback that we already have a hold of. note: this args object is very
- // incomplete, but is enough to make the command work
+ // dumb but easy way to do this: call the record command callback. note:
+ // this args object is very incomplete by enough to make the command work
struct con_cmdargs args = {.argc = 2, .argv = {0, name, 0}};
orig_record_cb(&args);
if (!was && *recording) *demonum = 0; // same logic as in the hook
diff --git a/src/dictmaptree.h b/src/dictmaptree.h
index 8a354fe..190683c 100644
--- a/src/dictmaptree.h
+++ b/src/dictmaptree.h
@@ -22,7 +22,7 @@
/*
* Valve's dict/map/tree structures come in various shapes and sizes, so here we
- * do the generic macro thing for future proofing. For now we just define a
+ * do the generic macro thing for future-proofing. For now we just define a
* CUtlDict (map with string keys) of pointers, with ushort indices, which is
* sufficient for server entity factory lookup, and probably some other stuff.
* Functions for actually modifying the dicts/maps/trees aren't implemented.
diff --git a/src/engineapi.c b/src/engineapi.c
index d4ee742..831836b 100644
--- a/src/engineapi.c
+++ b/src/engineapi.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
* Copyright © 2023 Willian Henrique <wsimanbrazil@yahoo.com.br>
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -37,15 +37,14 @@ ifacefactory factory_client = 0, factory_server = 0, factory_engine = 0,
struct VEngineClient *engclient;
struct VEngineServer *engserver;
-// this seems to be very stable, thank goodness
-DECL_VFUNC(void *, GetGlobalVars, 1)
+DECL_VFUNC(void *, GetGlobalVars, 1) // seems to be very stable, thank goodness
void *globalvars;
void *inputsystem, *vgui;
DECL_VFUNC_DYN(void *, GetAllServerClasses)
-#include <entpropsinit.gen.h>
+#include <entpropsinit.gen.h> // generated by build/mkentprops.c
bool engineapi_init(int pluginver) {
if (!con_detect(pluginver)) return false;
@@ -101,8 +100,6 @@ bool engineapi_init(int pluginver) {
}
}
- // need to do this now; ServerClass network table iteration requires
- // SendProp offsets
gamedata_init();
con_init();
if (!gameinfo_init()) { con_disconnect(); return false; }
diff --git a/src/ent.c b/src/ent.c
index 8dcb1f1..6329152 100644
--- a/src/ent.c
+++ b/src/ent.c
@@ -69,10 +69,10 @@ static struct CEntityFactoryDictionary *entfactorydict = 0;
static inline bool find_entfactorydict(con_cmdcb dumpentityfactories_cb) {
const uchar *insns = (const uchar *)dumpentityfactories_cb;
for (const uchar *p = insns; p - insns < 64;) {
- // the call to EntityFactoryDictionary() is inlined. that returns a
- // static, which is lazy-inited (trivia: this was old MSVC, so it's not
- // threadsafe like C++ requires nowadays). for some reason the init flag
- // is set using OR, and then the instance is put in ECX to call the ctor
+ // EntityFactoryDictionary() is inlined, and returns a static, which is
+ // lazy-inited (trivia: this was old MSVC, so it's not thread-safe like
+ // C++ requires nowadays). for some reason the init flag is set using
+ // OR, and then the instance is put in ECX to call the ctor
if (p[0] == X86_ORMRW && p[6] == X86_MOVECXI && p[11] == X86_CALL) {
entfactorydict = mem_loadptr(p + 7);
return true;
diff --git a/src/fixes.c b/src/fixes.c
index 29d5ab3..b2eaf91 100644
--- a/src/fixes.c
+++ b/src/fixes.c
@@ -106,7 +106,7 @@ static void l4d2specific(void) {
// this out. Good meme 8/10.
unhide("sv_hosting_lobby");
- // Older versions of L4D2 reset mat_queue_mode to -1 (multicore rendering
+ // Older versions of L4D2 reset mat_queue_mode to 0 (multicore rendering
// off) all the time if gpu_level is 0 (low shader detail), causing lag that
// can only be fixed by manually fixing the setting in video settings. Newer
// versions work around this by marking it as ARCHIVE, *breaking* the code
@@ -169,6 +169,7 @@ static void l4d1specific(void) {
// these hidden variables to 0 gets rid of it.
struct con_var *v = con_findvar("ui_l4d_debug");
if (v) con_setvari(v, 0);
+ // FIXME: this is borked with deferred init. Does gameui load SUPER late?
v = con_findvar("mm_l4d_debug");
if (v) con_setvari(v, 0);
diff --git a/src/fov.c b/src/fov.c
index 236182a..1886c1f 100644
--- a/src/fov.c
+++ b/src/fov.c
@@ -44,8 +44,7 @@ static struct con_var *real_fov_desired; // engine's if it has it, or ours
typedef void (*VCALLCONV SetDefaultFOV_func)(void *, int);
static SetDefaultFOV_func orig_SetDefaultFOV;
static void VCALLCONV hook_SetDefaultFOV(void *this, int fov) {
- // the game normally clamps fov_desired on the server side, disregard
- // whatever it tries to set and force our own value instead
+ // disregard server-side clamped value and force our own value instead
orig_SetDefaultFOV(this, con_getvari(real_fov_desired));
}
@@ -53,15 +52,14 @@ static bool find_SetDefaultFOV(struct con_cmd *fov) {
const uchar *insns = (const uchar *)fov->cb;
int callcnt = 0;
for (const uchar *p = insns; p - insns < 96;) {
- // fov command source, and consequent asm, calls 4 functions, one of
- // them virtual (i.e. via register). of the 3 direct calls,
- // SetDefaultFOV is the third.
+ // The fov command calls 4 functions, one of them virtual. Of the 3
+ // direct calls, SetDefaultFOV() is the third.
if (p[0] == X86_CALL && ++callcnt == 3) {
orig_SetDefaultFOV = (SetDefaultFOV_func)(p + 5 +
mem_loadoffset(p + 1));
return true;
}
- NEXT_INSN(p, "SetDefaultFOV");
+ NEXT_INSN(p, "SetDefaultFOV function");
}
return false;
}
diff --git a/src/gamedata.c b/src/gamedata.c
index 639b2f8..78eb620 100644
--- a/src/gamedata.c
+++ b/src/gamedata.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -24,6 +24,6 @@
#define NVDTOR 2
#endif
-#include <gamedatainit.gen.h>
+#include <gamedatainit.gen.h> // generated by build/mkgamedata.c
// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/gamedata.h b/src/gamedata.h
index 471e5bb..2e58ef6 100644
--- a/src/gamedata.h
+++ b/src/gamedata.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -22,11 +22,11 @@
#else
#define NVDTOR 2
#endif
-#include <gamedata.gen.h>
-// entprops are built by a different tool, in a different header for simplicity
-#include <entprops.gen.h>
+#include <gamedata.gen.h> // generated by build/mkgamedata.c
+#include <entprops.gen.h> // generated by build/mkentprops.c
#undef NVDTOR
+/* Called as part of plugin init to set up various metadata about the game. */
void gamedata_init(void);
#endif
diff --git a/src/gameinfo.c b/src/gameinfo.c
index d04ae0f..71922a6 100644
--- a/src/gameinfo.c
+++ b/src/gameinfo.c
@@ -39,7 +39,10 @@
#define PATHSEP "/"
#endif
-// TODO(opt): get rid of the rest of the snprintf and strcpy, some day
+// ~~TODO(opt): get rid of the rest of the snprintf and strcpy, some day~~
+// TODO(opt): remove almost all this parsing nonsense, it's not needed any more!
+// We can simply GetWindowText (and do a little more work on Linux...) and do
+// away with absolute paths to DLLs which won't be required with deferred init.
static os_char bindir[PATH_MAX] = {0};
#ifdef _WIN32
diff --git a/src/hook.c b/src/hook.c
index ff7ac96..3d6c14d 100644
--- a/src/hook.c
+++ b/src/hook.c
@@ -47,9 +47,8 @@ bool hook_init(void) {
void *hook_inline(void *func_, void *target) {
uchar *func = func_;
- // dumb hack: rather than correcting jmp offsets and having to painstakingly
- // track them all, just look for the underlying thing being jmp-ed to and
- // hook _that_.
+ // dumb hack: if we hit some thunk that immediately jumps elsewhere (which
+ // seems common for win32 API functions), hook the underlying thing instead.
while (*func == X86_JMPIW) func += mem_loadoffset(func + 1) + 5;
if (!os_mprot(func, 5, PAGE_EXECUTE_READWRITE)) return false;
int len = 0;
@@ -76,6 +75,7 @@ void *hook_inline(void *func_, void *target) {
}
// for simplicity, just bump alloc the trampoline. no need to free anyway
if (nexttrampoline - trampolines > sizeof(trampolines) - len - 6) goto nosp;
+ // TODO(opt): stop pretending to be thread-safe, it's just slowing us down
uchar *trampoline = (uchar *)InterlockedExchangeAdd(
(volatile long *)&nexttrampoline, len + 6);
// avoid TOCTOU
diff --git a/src/kvsys.c b/src/kvsys.c
index 8bb140e..25344da 100644
--- a/src/kvsys.c
+++ b/src/kvsys.c
@@ -60,8 +60,7 @@ void kvsys_free(struct KeyValues *kv) {
// HACK: later versions of L4D2 show an annoying dialog on every plugin_load.
// We can suppress this by catching the message string that's passed from
// engine.dll to gameui.dll through KeyValuesSystem in vstdlib.dll and just
-// replacing it with some other arbitrary garbage string. This makes gameui fail
-// to match the message and thus do nothing. :)
+// replacing it with some other arbitrary string that gameui won't match.
static GetStringForSymbol_func orig_GetStringForSymbol = 0;
static const char *VCALLCONV hook_GetStringForSymbol(void *this, int s) {
const char *ret = orig_GetStringForSymbol(this, s);
diff --git a/src/l4dmm.c b/src/l4dmm.c
index 8394038..3c7a07c 100644
--- a/src/l4dmm.c
+++ b/src/l4dmm.c
@@ -95,7 +95,7 @@ const char *l4dmm_curcampaign(void) {
}
INIT {
- // ugh, we NEED to centralise the library stuff at some point, this sucks
+ // XXX: ugh, we NEED to centralise library stuff at some point, this sucks
#ifdef _WIN32
void *mmlib = GetModuleHandleW(L"matchmaking.dll");
#else
diff --git a/src/l4dreset.c b/src/l4dreset.c
index 4bffa3c..2245a16 100644
--- a/src/l4dreset.c
+++ b/src/l4dreset.c
@@ -44,7 +44,7 @@ static int off_callerrecords = -1;
static int off_voteissues;
// Note: the vote callers vector contains these as elements. We don't currently
-// do anything with the structure, but keeping it here for reference.
+// do anything with the structure, but we're keeping it here for reference.
/*struct CallerRecord {
u32 steamid_trunc;
float last_time;
@@ -78,8 +78,8 @@ static void reset(void) {
// reset the vote cooldowns if possible (will skip L4D1). only necessary on
// versions >2045 and on map 1, but it's easiest to do unconditionally
if (off_callerrecords != -1) {
- // Basically equivalent to CUtlVector::RemoveAll. The elements have no
- // destructors to call. The resulting state is as if nobody has voted.
+ // This is equivalent to CUtlVector::RemoveAll() as there's no
+ // destructors to call. The result as is if nobody had ever voted.
struct CUtlVector *recordvector = mem_offset(*votecontroller,
off_callerrecords);
recordvector->sz = 0;
@@ -116,8 +116,7 @@ DEF_CCMD_HERE_UNREG(sst_l4d_quickreset,
PREINIT { return GAMETYPE_MATCHES(L4D); }
-// This finds the g_voteController variable using the listissues callback, and
-// returns a pointer to the rest of the bytes for find_voteissues() below
+// Note: this returns a pointer to subsequent bytes for find_voteissues() below
static inline const uchar *find_votecontroller(con_cmdcbv1 listissues_cb) {
const uchar *insns = (const uchar *)listissues_cb;
#ifdef _WIN32
@@ -136,8 +135,6 @@ static inline const uchar *find_votecontroller(con_cmdcbv1 listissues_cb) {
return 0;
}
-// This finds ListIssues() using the instruction pointer returned by
-// find_votecontroller() above, and then uses that to find the vote issue list.
static inline bool find_voteissues(const uchar *insns) {
#ifdef _WIN32
for (const uchar *p = insns; p - insns < 16;) {
@@ -150,10 +147,9 @@ static inline bool find_voteissues(const uchar *insns) {
}
return false;
ok: for (const uchar *p = insns; p - insns < 96;) {
- // There's a virtual call on each actual CVoteIssue in the loop over the
- // list. That entails putting the issue pointer in ECX, which involves
- // loading that pointer from the vector, which exists at an offset from
- // `this`, meaning we can find the offset from the mov into ECX.
+ // The loop in ListIssues() calls a member function on each CVoteIssue.
+ // Each pointer is loaded from a CUtlVector at an offset from `this`, so
+ // we can find that offset from the mov into ECX.
if (p[0] == X86_MOVRMW && (p[1] & 0xF8) == 0x88) {
int off = mem_loadoffset(p + 2);
if (off > 800) { // sanity check: offset is always fairly high
@@ -161,9 +157,8 @@ ok: for (const uchar *p = insns; p - insns < 96;) {
return true;
}
}
- // Further complication: at least in 2045 there's a short jmp over some
- // invalid instruction bytes. I guess there's no reason to ever expect
- // something interesting after an unconditional jmp, so just follow it.
+ // Complication: at least 2045 has a short jmp over some garbage bytes.
+ // Follow that jmp since there's nothing interesting before the target.
if (p[0] == X86_JMPI8) {
p += 2 + ((s8 *)p)[1];
continue;
@@ -176,15 +171,12 @@ ok: for (const uchar *p = insns; p - insns < 96;) {
return false;
}
-// This finds the caller record vector using a pointer to the
-// CVoteController::Spawn function
static inline bool find_votecallers(void *votectrlspawn) {
#ifdef _WIN32
const uchar *insns = (const uchar *)votectrlspawn;
for (const uchar *p = insns; p - insns < 64;) {
- // Unsure what the member on this offset actually is (the game seems to
- // want it to be set to 0 to allow votes to happen), but the vector we
- // want seems to consistently be 8 bytes after whatever this is
+ // Unsure what this offset points at (it seems to have to be 0 for votes
+ // to happen), but the vector of interest always comes 8 bytes later.
// "mov dword ptr [<reg> + off], 0", mod == 0b11
if (p[0] == X86_MOVMIW && (p[1] & 0xC0) == 0x80 &&
mem_load32(p + 6) == 0) {
@@ -215,12 +207,11 @@ INIT {
errmsg_errorx("couldn't find vote issues list offset\n");
return false;
}
- // only bother with vote cooldown stuff for L4D2, since all versions of L4D1
- // have unlimited votes anyway. NOTE: assuming L4D2 always has Spawn in
- // gamedata (which has no reason to stop being true...)
+ // Only try cooldown stuff for L4D2, since L4D1 always had unlimited votes.
+ // NOTE: assuming L4D2 always has Spawn in gamedata (why wouldn't it?)
if (GAMETYPE_MATCHES(L4D2)) {
- // g_voteController may have not been initialized yet so we get the
- // vtable from the ent factory
+ // g_voteController is invalid if not running a server so get the
+ // vtable by inspecting the ent factory code instead
const struct CEntityFactory *factory = ent_getfactory("vote_controller");
if (!factory) {
errmsg_errorx("couldn't find vote controller entity factory");
diff --git a/src/l4dwarp.c b/src/l4dwarp.c
index 75c762c..24c3873 100644
--- a/src/l4dwarp.c
+++ b/src/l4dwarp.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -45,9 +45,7 @@ DEF_CCMD_HERE_UNREG(sst_l4d_testwarp, "Simulate a bot warping to you",
void *e = GetBaseEntity(ed->ent_unknown); // is this call required?
struct vec3f *org = mem_offset(e, off_entpos);
struct vec3f *ang = mem_offset(e, off_eyeang);
- // L4D idle warps go up to 10 units behind relative to whatever angle the
- // player is facing, lessening the distance based on pitch angle but never
- // displacing vertically
+ // L4D idle warps go up to 10 units behind yaw, lessening based on pitch.
float pitch = ang->x * M_PI / 180, yaw = ang->y * M_PI / 180;
float shift = -10 * cos(pitch);
Teleport(e, &(struct vec3f){org->x + shift * cos(yaw),
diff --git a/src/mem.h b/src/mem.h
index 97dfa91..367ed5b 100644
--- a/src/mem.h
+++ b/src/mem.h
@@ -19,7 +19,7 @@
#include "intdefs.h"
-/* retrieves a 32-bit integer from an unaligned pointer */
+/* Retrieves a 32-bit integer from an unaligned pointer. */
static inline u32 mem_load32(const void *p) {
// XXX: Turns out the pedantically-safe approach below causes most compilers
// to generate horribly braindead x86 output in at least some cases (and the
@@ -31,13 +31,13 @@ static inline u32 mem_load32(const void *p) {
//return (u32)cp[0] | (u32)cp[1] << 8 | (u32)cp[2] << 16 | (u32)cp[3] << 24;
}
-/* retrieves a 64-bit integer from an unaligned pointer */
+/* Retrieves a 64-bit integer from an unaligned pointer. */
static inline u64 mem_load64(const void *p) {
// this seems not to get butchered as badly in most cases?
return (u64)mem_load32(p) | (u64)mem_load32((uchar *)p + 4) << 32;
}
-/* retrieves a pointer from an unaligned pointer-to-pointer */
+/* Retrieves a pointer from an unaligned pointer-to-pointer. */
static inline void *mem_loadptr(const void *p) {
#if defined(_WIN64) || defined(__x86_64__)
return (void *)mem_load64(p);
@@ -46,15 +46,15 @@ static inline void *mem_loadptr(const void *p) {
#endif
}
-/* retreives a signed offset from an unaligned pointer */
+/* Retreives a signed offset from an unaligned pointer. */
static inline ssize mem_loadoffset(const void *p) {
return (ssize)mem_loadptr(p);
}
-/* adds a byte count to a pointer and returns a freely-assignable void pointer */
+/* Adds a byte count to a pointer and returns a freely-assignable pointer. */
static inline void *mem_offset(void *p, int off) { return (char *)p + off; }
-/* returns the offset in bytes from one pointer to another (p - q) */
+/* Returns the offset in bytes from one pointer to another (p - q). */
static inline ssize mem_diff(const void *p, const void *q) {
return (char *)p - (char *)q;
}
diff --git a/src/nomute.c b/src/nomute.c
index 30f93c3..93cfcd2 100644
--- a/src/nomute.c
+++ b/src/nomute.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2023 Willian Henrique <wsimanbrazil@yahoo.com.br>
+ * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -37,10 +38,9 @@ static IDirectSoundVtbl *ds_vt = 0;
static typeof(ds_vt->CreateSoundBuffer) orig_CreateSoundBuffer;
static con_cmdcbv1 snd_restart_cb = 0;
-// early init (via VDF) happens before config is loaded, and audio is set up
-// after that, so we don't want to run snd_restart the first time the cvar is
-// set, unless we were loaded later with plugin_load, in which case audio is
-// already up and running and we'll want to restart it every time
+// early init via VDF happens before config is loaded and audio is set up after
+// that, so we don't want to run snd_restart the first time the cvar is set,
+// unless we were loaded later with plugin_load in which case we actually do.
static bool skiprestart;
static void losefocuscb(struct con_var *v) {
if (!skiprestart) snd_restart_cb();
diff --git a/src/os-win32.h b/src/os-win32.h
index 365e2dc..fe61f84 100644
--- a/src/os-win32.h
+++ b/src/os-win32.h
@@ -98,6 +98,9 @@ static inline void os_randombytes(void *buf, int sz) {
#define fdopen _fdopen
#define dup _dup
#define dup2 _dup2
+#define strdup _strdup
+#define fstat _fstat64
+#define lseek _lseeki64
#define O_RDONLY _O_RDONLY
#define O_RDWR _O_RDWR
#define O_CLOEXEC _O_NOINHERIT // and why did they rename this!?
diff --git a/src/sst.c b/src/sst.c
index a0f926d..afe7eb3 100644
--- a/src/sst.c
+++ b/src/sst.c
@@ -170,11 +170,10 @@ static const char *updatenotes = "\
* various internal cleanup\n\
";
-#include <featureinit.gen.h>
+#include <featureinit.gen.h> // generated by build/codegen.c
static void do_featureinit(void) {
initfeatures();
- fixes_apply();
// if we're autoloaded and the external autoupdate script downloaded a new
// version, let the user know about the cool new stuff!
@@ -200,25 +199,20 @@ static VGuiConnect_func orig_VGuiConnect;
static void VCALLCONV hook_VGuiConnect(void *this) {
orig_VGuiConnect(this);
do_featureinit();
- unhook_vtable(*(void ***)vgui, vtidx_VGuiConnect,
- (void *)orig_VGuiConnect);
+ fixes_apply();
+ unhook_vtable(*(void ***)vgui, vtidx_VGuiConnect, (void *)orig_VGuiConnect);
}
DECL_VFUNC_DYN(bool, VGuiIsInitialized)
// --- Magical deferred load order hack nonsense! ---
-// The engine loads VDF plugins basically right after server.dll, but long
-// before most other stuff, which makes hooking certain other stuff a pain. We
-// still want to be able to load via VDF as it's the only reasonable way to get
-// in before config.cfg, which is needed for any kind of configuration to work
-// correctly.
-//
-// So here, we hook CEngineVGui::Connect() which is one the very last things
-// to get called on startup, and use that hook to defer feature init till after
-// most of the rest of the game is up and running. That allows us to touch
-// pretty much any engine stuff without worrying about load order nonsense.
+// VDF plugins load right after server.dll, but long before most other stuff. We
+// want to be able to load via VDF so archived cvars in config.cfg can get set,
+// but don't want to be so early that most of the game's interfaces haven't been
+// brought up yet. Hook CEngineVGui::Connect(), which is called very late in
+// startup, in order to init the features properly.
//
-// Route credit to Bill for helping figure a lot of this out - mike
+// Route credit to bill for helping figure a lot of this out - mike
static bool deferinit(void) {
if (!vgui) {
errmsg_warnx("can't use VEngineVGui for deferred feature setup");
@@ -300,7 +294,7 @@ static bool do_load(ifacefactory enginef, ifacefactory serverf) {
*p++ = (void *)&nop_p_v; // OnEdictAllocated
*p = (void *)&nop_p_v; // OnEdictFreed
- if (!deferinit()) do_featureinit();
+ if (!deferinit()) { do_featureinit(); fixes_apply(); }
return true;
}
@@ -428,6 +422,6 @@ EXPORT const void *CreateInterface(const char *name, int *ret) {
}
// no better place to put this lol
-#include <evglue.gen.h>
+#include <evglue.gen.h> // generated by src/build/codegen.c
// vi: sw=4 ts=4 noet tw=80 cc=80