summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/ac.c110
-rw-r--r--src/alias.c6
-rw-r--r--src/autojump.c15
-rw-r--r--src/bind.c5
-rw-r--r--src/bitbuf.h7
-rw-r--r--src/build/codegen.c9
-rw-r--r--src/build/mkentprops.c4
-rw-r--r--src/build/mkgamedata.c2
-rw-r--r--src/chunklets/msg.c6
-rw-r--r--src/democustom.c3
-rw-r--r--src/demorec.c15
-rw-r--r--src/engineapi.c5
-rw-r--r--src/ent.c16
-rw-r--r--src/extmalloc.c9
-rw-r--r--src/fastfwd.c46
-rw-r--r--src/fixes.c14
-rw-r--r--src/fov.c11
-rw-r--r--src/gameinfo.c9
-rw-r--r--src/gameserver.c5
-rw-r--r--src/hook.c5
-rw-r--r--src/hud.c19
-rw-r--r--src/kv.c4
-rw-r--r--src/kvsys.c5
-rw-r--r--src/l4dmm.c27
-rw-r--r--src/l4dreset.c34
-rw-r--r--src/l4dwarp.c5
-rw-r--r--src/langext.h64
-rw-r--r--src/nomute.c10
-rw-r--r--src/noreturn.h11
-rw-r--r--src/nosleep.c5
-rw-r--r--src/os.c13
-rw-r--r--src/os.h10
-rw-r--r--src/portalcolours.c7
-rw-r--r--src/rinput.c31
-rw-r--r--src/sst.c79
-rw-r--r--src/unreachable.h14
-rw-r--r--src/x86util.h7
-rw-r--r--test/kv.test.c2
38 files changed, 356 insertions, 293 deletions
diff --git a/src/ac.c b/src/ac.c
index 8c98cfb..7f3157c 100644
--- a/src/ac.c
+++ b/src/ac.c
@@ -40,6 +40,7 @@
#include "gamedata.h"
#include "gametype.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "ppmagic.h"
@@ -102,34 +103,37 @@ static ulong inhooktid;
static ssize __stdcall kproc(int code, usize wp, ssize lp) {
KBDLLHOOKSTRUCT *data = (KBDLLHOOKSTRUCT *)lp;
- if (enabled && data->flags & LLKHF_INJECTED &&
- GetForegroundWindow() == gamewin) {
- // maybe this input is reasonable, but log it for closer inspection
- // TODO(rta): figure out what to do with this stuff
- // something like the following, but with a proper abstraction...
- //uchar buf[28 + 16], *p = buf;
- //msg_putasz4(p, 2); p += 1;
- // msg_putssz5(p, 8); memcpy(p + 1, "FakeKey", 7); p += 8;
- // msg_putmsz4(p, 2); p += 1;
- // msg_putssz5(p, 3); memcpy(p + 1, "vk", 2); p += 3;
- // p += msg_putu32(p, data->vkCode);
- // msg_putssz5(p, 3); memcpy(p + 1, "scan", 4); p += 5;
- // p += msg_putu32(p, data->scanCode);
- //++keybox->nonce;
- //// append mac at end of message
- //crypto_aead_lock_djb(buf, p, keybox->shr, keybox->nonce_bytes, 0, 0,
- // buf, p - buf);
- //democustom_write(buf, p - buf + 16);
+ if_cold (enabled && data->flags & LLKHF_INJECTED) {
+ // fast-path the next branch because alt-tabbed speed is irrelevant
+ if_hot (GetForegroundWindow() == gamewin) {
+ // maybe this input is reasonable, but log it for closer inspection
+ // TODO(rta): figure out what to do with this stuff
+ // something like the following, but with a proper abstraction...
+ //uchar buf[28 + 16], *p = buf;
+ //msg_putasz4(p, 2); p += 1;
+ // msg_putssz5(p, 8); memcpy(p + 1, "FakeKey", 7); p += 8;
+ // msg_putmsz4(p, 2); p += 1;
+ // msg_putssz5(p, 3); memcpy(p + 1, "vk", 2); p += 3;
+ // p += msg_putu32(p, data->vkCode);
+ // msg_putssz5(p, 3); memcpy(p + 1, "scan", 4); p += 5;
+ // p += msg_putu32(p, data->scanCode);
+ //++keybox->nonce;
+ //// append mac at end of message
+ //crypto_aead_lock_djb(buf, p, keybox->shr, keybox->nonce_bytes, 0,
+ // 0, buf, p - buf);
+ //democustom_write(buf, p - buf + 16);
+ }
}
return CallNextHookEx(0, code, wp, lp);
}
static ssize __stdcall mproc(int code, usize wp, ssize lp) {
MSLLHOOKSTRUCT *data = (MSLLHOOKSTRUCT *)lp;
- if (enabled && data->flags & LLMHF_INJECTED &&
- GetForegroundWindow() == gamewin) {
- // no way this input would ever be reasonable. just discard it
- return 1;
+ if_cold (enabled && data->flags & LLMHF_INJECTED) {
+ if_hot (GetForegroundWindow() == gamewin) {
+ // no way this input would ever be reasonable. just discard it
+ return 1;
+ }
}
return CallNextHookEx(0, code, wp, lp);
}
@@ -138,7 +142,7 @@ static ssize __stdcall mproc(int code, usize wp, ssize lp) {
// hook gets silently removed. plus, we don't wanna incur latency anyway.
static ulong __stdcall inhookthrmain(void *param) {
volatile int *sig = param;
- if (!SetWindowsHookExW(WH_KEYBOARD_LL, (HOOKPROC)&kproc, 0, 0) ||
+ if_cold (!SetWindowsHookExW(WH_KEYBOARD_LL, (HOOKPROC)&kproc, 0, 0) ||
!SetWindowsHookExW(WH_MOUSE_LL, (HOOKPROC)&mproc, 0, 0)) {
fastspin_raise(sig, 2);
return -1;
@@ -151,29 +155,31 @@ static ulong __stdcall inhookthrmain(void *param) {
static ssize orig_wndproc;
static ssize __stdcall hook_wndproc(void *wnd, uint msg, usize wp, ssize lp) {
- if (msg == WM_COPYDATA && enabled) return DefWindowProcW(wnd, msg, wp, lp);
+ if_cold (msg == WM_COPYDATA && enabled) {
+ return DefWindowProcW(wnd, msg, wp, lp);
+ }
return CallWindowProcA((WNDPROC)orig_wndproc, wnd, msg, wp, lp);
}
-static bool win32_init(void) {
+static inline bool win32_init(void) {
// note: using A instead of W to avoid some weirdness with handles...
gamewin = FindWindowA("Valve001", 0);
// note: error messages here are a bit cryptic on purpose, but easy to find
// in the code. in other words, we're hiding in plain sight :-)
- if (!gamewin) {
+ if_cold (!gamewin) {
errmsg_errorsys("failed to find window");
return false;
}
orig_wndproc = SetWindowLongPtrA(gamewin, GWLP_WNDPROC,
(ssize)&hook_wndproc);
- if (!orig_wndproc) { // XXX: assuming 0 won't be legitimately returned
+ if_cold (!orig_wndproc) { // XXX: assuming 0 won't be legitimately returned
errmsg_errorsys("failed to attach message handler");
return false;
}
return true;
}
-static void win32_end(void) {
+static inline void win32_end(void) {
// no error handling here because we'd crash either way. good luck!
SetWindowLongPtrA(gamewin, GWLP_WNDPROC, orig_wndproc);
}
@@ -188,7 +194,7 @@ static void inhook_check(void) {
if (WaitForSingleObject(inhookthr, 0) == WAIT_OBJECT_0) {
ulong status;
GetExitCodeThread(inhookthr, &status);
- if (status) {
+ if_cold (status) {
// XXX: if this ever happens, it's a disaster! users might not
// notice their run just dying all of a sudden. with any luck it
// won't matter in practice but... this kind of sucks.
@@ -209,7 +215,7 @@ static void inhook_stop(void) {
// assume WAIT_OBJECT_0
ulong status;
GetExitCodeThread(inhookthr, &status);
- if (status) {
+ if_cold (status) {
// not much else we can do now!
errmsg_errorx("message loop didn't shut down cleanly\n");
}
@@ -224,17 +230,18 @@ static void inhook_stop(void) {
#endif
bool ac_enable(void) {
- if (enabled) return true;
+ if (!enabled) {
#ifdef _WIN32
- volatile int sig = 0;
- inhook_start(&sig);
- fastspin_wait(&sig);
- if (sig == 2) { // else 1 for success
- con_warn("** sst: ERROR starting message loop, can't continue! **");
- CloseHandle(inhookthr);
- return false;
- }
+ volatile int sig = 0;
+ inhook_start(&sig);
+ fastspin_wait(&sig);
+ if_cold (sig == 2) { // else 1 for success
+ con_warn("** sst: ERROR starting message loop, can't continue! **");
+ CloseHandle(inhookthr);
+ return false;
+ }
#endif
+ }
enabled = true;
return true;
}
@@ -248,10 +255,11 @@ HANDLE_EVENT(Tick, bool simulating) {
}
void ac_disable(void) {
- if (!enabled) return;
+ if (enabled) {
#ifdef _WIN32
- inhook_stop();
+ inhook_stop();
#endif
+ }
enabled = false;
}
@@ -308,7 +316,7 @@ static bool find_Key_Event(void) {
// -> CGame::DispatchAllStoredGameMessages vfunc
// -> First call instruction (either DispatchInputEvent or Key_Event)
void *gameuifuncs = factory_engine("VENGINE_GAMEUIFUNCS_VERSION005", 0);
- if (!gameuifuncs) {
+ if_cold (!gameuifuncs) {
errmsg_errorx("couldn't get engine game UI interface");
return false;
}
@@ -355,7 +363,7 @@ ok2:
}
HANDLE_EVENT(AllowPluginLoading, bool loading) {
- if (enabled && demorec_demonum() != -1) {
+ if_cold(enabled) if_hot(demorec_demonum() != -1) {
con_warn("sst: plugins cannot be %s while recording a run\n",
loading ? "loaded" : "unloaded");
return false;
@@ -375,39 +383,39 @@ PREINIT {
}
INIT {
- if (!find_Key_Event()) return false;
+ if_cold (!find_Key_Event()) return false;
orig_Key_Event = (Key_Event_func)hook_inline((void *)orig_Key_Event,
(void *)&hook_Key_Event);
- if (!orig_Key_Event) {
+ if_cold (!orig_Key_Event) {
errmsg_errorsys("couldn't hook Key_Event function");
return false;
}
#ifdef _WIN32
keybox = VirtualAlloc(0, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
- if (!keybox) {
+ if_cold (!keybox) {
errmsg_errorsys("couldn't allocate memory for session state");
return false;
}
- if (!VirtualLock(keybox, 4096)) {
+ if_cold (!VirtualLock(keybox, 4096)) {
errmsg_errorsys("couldn't secure session state");
goto e2;
}
- if (WerRegisterExcludedMemoryBlock(keybox, 4096) != S_OK) {
+ if_cold (WerRegisterExcludedMemoryBlock(keybox, 4096) != S_OK) {
// FIXME: stringify errors properly here
errmsg_errorx("couldn't secure session state");
goto e2;
}
- if (!win32_init()) goto e;
+ if_cold (!win32_init()) goto e;
#else
keybox = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
- if (keybox == MAP_FAILED) {
+ if_cold (keybox == MAP_FAILED) {
errmsg_errorstd("couldn't allocate memory for session state");
return false;
}
// linux-specific madvise stuff (there are some equivalents in OpenBSD and
// FreeBSD, if anyone's wondering, but we don't need to worry about those)
- if (madvise(keybox, 4096, MADV_DONTFORK) == -1 ||
+ if_cold (madvise(keybox, 4096, MADV_DONTFORK) == -1 ||
madvise(keybox, 4096, MADV_DONTDUMP) == - 1 ||
mlock(keybox, 4096) == -1) {
errmsg_errorstd("couldn't secure session state");
diff --git a/src/alias.c b/src/alias.c
index 6af7467..e6f5f7e 100644
--- a/src/alias.c
+++ b/src/alias.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -94,10 +94,10 @@ INIT {
if (GAMETYPE_MATCHES(Portal2)) return false;
struct con_cmd *cmd_alias = con_findcmd("alias");
- if (!find_alias_head(con_getcmdcb(cmd_alias))) {
+ if_cold (!find_alias_head(con_getcmdcb(cmd_alias))) {
errmsg_warnx("couldn't find alias list");
return false;
- };
+ }
con_reg(sst_alias_clear);
con_reg(sst_alias_remove);
return true;
diff --git a/src/autojump.c b/src/autojump.c
index 1bfc170..cc44573 100644
--- a/src/autojump.c
+++ b/src/autojump.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -20,8 +20,9 @@
#include "feature.h"
#include "gamedata.h"
#include "gametype.h"
-#include "intdefs.h"
#include "hook.h"
+#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "vcall.h"
@@ -76,7 +77,7 @@ static bool unprot(void *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 && !con_getvari(sv_cheats)) {
+ if (this->ival) 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);
@@ -85,17 +86,17 @@ static void cheatcb(struct con_var *this) {
INIT {
gmsv = factory_server("GameMovement001", 0);
- if (!gmsv) {
+ if_cold (!gmsv) {
errmsg_errorx("couldn't get server-side game movement interface");
return false;
}
- if (!unprot(gmsv)) return false;
+ if_cold (!unprot(gmsv)) return false;
gmcl = factory_client("GameMovement001", 0);
- if (!gmcl) {
+ if_cold (!gmcl) {
errmsg_errorx("couldn't get client-side game movement interface");
return false;
}
- if (!unprot(gmcl)) return false;
+ if_cold (!unprot(gmcl)) return false;
origsv = (CheckJumpButton_func)hook_vtable(*(void ***)gmsv,
vtidx_CheckJumpButton, (void *)&hooksv);
origcl = (CheckJumpButton_func)hook_vtable(*(void ***)gmcl,
diff --git a/src/bind.c b/src/bind.c
index deb943e..327d0c2 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -20,6 +20,7 @@
#include "feature.h"
#include "hook.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "x86.h"
#include "x86util.h"
@@ -57,7 +58,7 @@ static bool find_keyinfo(con_cmdcb klbc_cb) {
INIT {
struct con_cmd *cmd_key_listboundkeys = con_findcmd("key_listboundkeys");
con_cmdcb cb = con_getcmdcb(cmd_key_listboundkeys);
- if (!find_keyinfo(cb)) {
+ if_cold (!find_keyinfo(cb)) {
errmsg_warnx("couldn't find key binding list");
return false;
}
diff --git a/src/bitbuf.h b/src/bitbuf.h
index 404dc9d..9e0fe19 100644
--- a/src/bitbuf.h
+++ b/src/bitbuf.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -77,11 +77,12 @@ static inline void bitbuf_appendbuf(struct bitbuf *bb, const char *buf,
// shift the stored value (if it were big endian, the shift would have
// to be the other way, or something)
_bitbuf_append(bb, *p >> (unalign << 3), (bitbuf_align - unalign) << 3);
- buf += sizeof(bitbuf_cell) - unalign;
+ buf += (int)sizeof(bitbuf_cell) - unalign;
len -= unalign;
}
bitbuf_cell *aligned = (bitbuf_cell *)buf;
- for (; len >= sizeof(bitbuf_cell); len -= sizeof(bitbuf_cell), ++aligned) {
+ for (; len >= (int)sizeof(bitbuf_cell); len -= (int)sizeof(bitbuf_cell),
+ ++aligned) {
_bitbuf_append(bb, *aligned, bitbuf_cell_bits);
}
// unaligned end bytes
diff --git a/src/build/codegen.c b/src/build/codegen.c
index 3cf4d8b..70b5e12 100644
--- a/src/build/codegen.c
+++ b/src/build/codegen.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -20,6 +20,7 @@
#include <string.h>
#include "../intdefs.h"
+#include "../langext.h"
#include "../os.h"
#include "cmeta.h"
#include "skiplist.h"
@@ -45,8 +46,8 @@ static struct conent {
static int nconents;
#define PUT(name_, isvar_, unreg_) do { \
- if (nconents == sizeof(conents) / sizeof(*conents)) { \
- fprintf(stderr, "codegen: out of space; make ents bigger!\n"); \
+ if (nconents == countof(conents)) { \
+ fprintf(stderr, "codegen: out of space; make conents bigger!\n"); \
exit(1); \
} \
conents[nconents].name = name_; \
@@ -116,7 +117,7 @@ static struct skiplist_hdr_feature_bydesc features_bydesc = {0};
static void onfeatinfo(enum cmeta_featmacro type, const char *param,
void *ctxt) {
struct feature *f = ctxt;
- switch (type) {
+ switch_exhaust_enum (cmeta_featmacro, type) {
case CMETA_FEAT_REQUIRE:; bool optional = false; goto dep;
case CMETA_FEAT_REQUEST: optional = true;
dep:; struct feature *dep = skiplist_get_feature(&features, param);
diff --git a/src/build/mkentprops.c b/src/build/mkentprops.c
index 2043a9b..fdbb8af 100644
--- a/src/build/mkentprops.c
+++ b/src/build/mkentprops.c
@@ -20,7 +20,7 @@
#include "../intdefs.h"
#include "../kv.h"
-#include "../noreturn.h"
+#include "../langext.h"
#include "../os.h"
#include "skiplist.h"
#include "vec.h"
@@ -73,7 +73,7 @@ static noreturn badparse(struct parsestate *state, const char *e) {
static void kv_cb(enum kv_token type, const char *p, uint len, void *ctxt) {
struct parsestate *state = ctxt;
- switch (type) {
+ switch_exhaust_enum (kv_token, type) {
case KV_IDENT: case KV_IDENT_QUOTED:
state->lastvar = malloc(len + 1);
if (!state->lastvar) die("couldn't allocate memory");
diff --git a/src/build/mkgamedata.c b/src/build/mkgamedata.c
index bf359b2..266a411 100644
--- a/src/build/mkgamedata.c
+++ b/src/build/mkgamedata.c
@@ -20,7 +20,7 @@
#include "../intdefs.h"
#include "../kv.h"
-#include "../noreturn.h"
+#include "../langext.h"
#include "../os.h"
#include "vec.h"
diff --git a/src/chunklets/msg.c b/src/chunklets/msg.c
index d99edc1..5b688cb 100644
--- a/src/chunklets/msg.c
+++ b/src/chunklets/msg.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -155,9 +155,7 @@ int msg_putu32(unsigned char *out, unsigned int val) {
}
int msg_puts(unsigned char *out, long long val) {
- if (val >= -2147483648 && val <= 2147483647) {
- return msg_puts32(out, val);
- }
+ if (val >= -2147483648 && val <= 2147483647) return msg_puts32(out, val);
out[0] = 0xD3;
doput64(out, val);
return 9;
diff --git a/src/democustom.c b/src/democustom.c
index 4c1baf2..30fc4ee 100644
--- a/src/democustom.c
+++ b/src/democustom.c
@@ -24,6 +24,7 @@
#include "feature.h"
#include "gamedata.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "ppmagic.h"
#include "vcall.h"
@@ -46,7 +47,7 @@ static union {
bitbuf_cell _align; // just in case...
} bb_buf;
static struct bitbuf bb = {
- {bb_buf.x}, sizeof(bb_buf), sizeof(bb_buf) * 8, 0, false, false, "SST"
+ {bb_buf.x}, ssizeof(bb_buf), ssizeof(bb_buf) * 8, 0, false, false, "SST"
};
static const void *createhdr(struct bitbuf *msg, int len, bool last) {
diff --git a/src/demorec.c b/src/demorec.c
index 8abba77..4a8efb5 100644
--- a/src/demorec.c
+++ b/src/demorec.c
@@ -26,6 +26,7 @@
#include "gameinfo.h"
#include "hook.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "ppmagic.h"
@@ -99,7 +100,7 @@ static struct con_cmd *cmd_record, *cmd_stop;
static con_cmdcb orig_record_cb, orig_stop_cb;
static void hook_record_cb(const struct con_cmdargs *args) {
- if (!CHECK_DemoControlAllowed()) return;
+ if_cold (!CHECK_DemoControlAllowed()) return;
bool was = *recording;
if (!was && args->argc == 2 || args->argc == 3) {
// safety check: make sure a directory exists, otherwise recording
@@ -162,7 +163,7 @@ static void hook_record_cb(const struct con_cmdargs *args) {
}
static void hook_stop_cb(const struct con_cmdargs *args) {
- if (!CHECK_DemoControlAllowed()) return;
+ if_cold (!CHECK_DemoControlAllowed()) return;
wantstop = true;
orig_stop_cb(args);
wantstop = false;
@@ -258,21 +259,21 @@ INIT {
orig_record_cb = con_getcmdcb(cmd_record);
cmd_stop = con_findcmd("stop");
orig_stop_cb = con_getcmdcb(cmd_stop);
- if (!find_demorecorder()) {
+ if_cold (!find_demorecorder()) {
errmsg_errorx("couldn't find demo recorder instance");
return false;
}
void **vtable = mem_loadptr(demorecorder);
// XXX: 16 is totally arbitrary here! figure out proper bounds later
- if (!os_mprot(vtable, 16 * sizeof(void *), PAGE_READWRITE)) {
+ if_cold (!os_mprot(vtable, 16 * sizeof(void *), PAGE_READWRITE)) {
errmsg_errorsys("couldn't make virtual table writable");
return false;
}
- if (!find_recmembers(vtable[vtidx_StopRecording])) {
+ if_cold (!find_recmembers(vtable[vtidx_StopRecording])) {
errmsg_errorx("couldn't find recording state variables");
return false;
}
- if (!find_demoname(vtable[vtidx_StartRecording])) {
+ if_cold (!find_demoname(vtable[vtidx_StartRecording])) {
errmsg_errorx("couldn't find demo basename variable");
return false;
}
@@ -290,7 +291,7 @@ INIT {
}
END {
- if (!sst_userunloaded) return;
+ if_hot (!sst_userunloaded) return;
// avoid dumb edge case if someone somehow records and immediately unloads
if (*recording && *demonum == 0) *demonum = 1;
void **vtable = *(void ***)demorecorder;
diff --git a/src/engineapi.c b/src/engineapi.c
index f3c8c6d..04e6a8c 100644
--- a/src/engineapi.c
+++ b/src/engineapi.c
@@ -24,6 +24,7 @@
#include "gameinfo.h"
#include "gametype.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h" // "
#include "os.h"
#include "vcall.h"
@@ -50,7 +51,7 @@ DECL_VFUNC_DYN(void *, GetAllServerClasses)
#include <entpropsinit.gen.h> // generated by build/mkentprops.c
bool engineapi_init(int pluginver) {
- if (!con_detect(pluginver)) return false;
+ if_cold (!con_detect(pluginver)) return false;
pluginhandler = factory_engine("ISERVERPLUGINHELPERS001", 0);
if (engclient = factory_engine("VEngineClient015", 0)) {
@@ -104,7 +105,7 @@ bool engineapi_init(int pluginver) {
gamedata_init();
con_init();
- if (!gameinfo_init()) { con_disconnect(); return false; }
+ if_cold (!gameinfo_init()) { con_disconnect(); return false; }
return true;
}
diff --git a/src/ent.c b/src/ent.c
index a1ad08f..1845b1f 100644
--- a/src/ent.c
+++ b/src/ent.c
@@ -22,6 +22,7 @@
#include "gamedata.h"
#include "gametype.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "vcall.h"
#include "x86.h"
@@ -35,8 +36,8 @@ static struct edict **edicts = 0;
struct edict *ent_getedict(int idx) {
if (edicts) {
// globalvars->edicts seems to be null when disconnected
- if (!*edicts) return 0;
- return mem_offset(*edicts, sz_edict * idx);
+ if_hot (*edicts) return mem_offset(*edicts, sz_edict * idx);
+ return 0;
}
else {
return PEntityOfEntIndex(engserver, idx);
@@ -45,8 +46,8 @@ struct edict *ent_getedict(int idx) {
void *ent_get(int idx) {
struct edict *e = ent_getedict(idx);
- if (!e) return 0;
- return e->ent_unknown;
+ if_hot(e) return e->ent_unknown;
+ return 0;
}
struct CEntityFactory {
@@ -143,14 +144,14 @@ void **ent_findvtable(const struct CEntityFactory *factory,
const char *classname) {
#ifdef _WIN32
ctor_func ctor = findctor(factory, classname);
- if (!ctor) return 0;
+ if_cold (!ctor) return 0;
const uchar *insns = (const uchar *)ctor;
// the constructor itself should do *(void**)this = &vtable; almost right
// away, so look for the first immediate load into indirect register
for (const uchar *p = insns; p - insns < 32;) {
if (p[0] == X86_MOVMIW && (p[1] & 0xF8) == 0) return mem_loadptr(p + 2);
int len = x86_len(p);
- if (len == -1) {
+ if_cold (len == -1) {
errmsg_errorx("unknown or invalid instruction looking for %s "
"vtable pointer", classname);
return 0;
@@ -166,7 +167,8 @@ void **ent_findvtable(const struct CEntityFactory *factory,
INIT {
#ifdef _WIN32 // TODO(linux): above
struct con_cmd *dumpentityfactories = con_findcmd("dumpentityfactories");
- if (!dumpentityfactories || !find_entfactorydict(dumpentityfactories->cb)) {
+ if_cold (!dumpentityfactories ||
+ !find_entfactorydict(dumpentityfactories->cb)) {
errmsg_warnx("server entity factories unavailable");
}
#endif
diff --git a/src/extmalloc.c b/src/extmalloc.c
index a23dc2a..d80ab8d 100644
--- a/src/extmalloc.c
+++ b/src/extmalloc.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -41,6 +41,8 @@ void extfree(void *mem) { Free(g_pMemAlloc, mem); }
#else
+#include "langext.h"
+
void Error(const char *fmt, ...); // stub left out of con_.h (not that useful)
// Linux Source doesn't seem to bother with the custom allocator stuff at all.
@@ -48,15 +50,16 @@ void Error(const char *fmt, ...); // stub left out of con_.h (not that useful)
// right, not a privilege. Like func_vehicle.
void *extmalloc(usize sz) {
void *ret = malloc(sz);
- if (!ret) Error("sst: out of memory");
+ if_cold (!ret) Error("sst: out of memory");
return ret;
}
void *extrealloc(void *mem, usize sz) {
void *ret = realloc(mem, sz);
- if (!ret) Error("sst: out of memory");
+ if_cold (!ret) Error("sst: out of memory");
return ret;
}
// note: extfree is #defined to free in the header
+
#endif
// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/fastfwd.c b/src/fastfwd.c
index 92d7623..e287770 100644
--- a/src/fastfwd.c
+++ b/src/fastfwd.c
@@ -26,6 +26,7 @@
#include "feature.h"
#include "hook.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "ppmagic.h"
@@ -46,19 +47,14 @@ static float *realtime, *host_frametime;
static float skiptime = 0.0, skiprate;
static void hook_Host_AccumulateTime(float dt) {
float skipinc = skiprate * dt;
- if (skiptime > skipinc) {
- skiptime -= skipinc;
- *realtime += skipinc;
- *host_frametime = skipinc;
- }
- else if (skiptime > 0) {
- *realtime += skiptime;
- *host_frametime = skiptime;
- skiptime = 0;
- }
- else {
+ if_hot (!skiptime) {
orig_Host_AccumulateTime(dt);
+ return;
}
+ if_random (skiptime <= skipinc) skipinc = skiptime; // should become fcmovbe
+ skiptime -= skipinc;
+ *realtime += skipinc;
+ *host_frametime = skipinc;
}
void fastfwd(float seconds, float timescale) {
@@ -194,67 +190,67 @@ PREINIT {
INIT {
void *hldsapi = factory_engine("VENGINE_HLDS_API_VERSION002", 0);
- if (!hldsapi) {
+ if_cold (!hldsapi) {
errmsg_errorx("couldn't find HLDS API interface");
return false;
}
void *enginetool = factory_engine("VENGINETOOL003", 0);
- if (!enginetool) {
+ if_cold (!enginetool) {
errmsg_errorx("missing engine tool interface");
return false;
}
// behold: the greatest pointer chase of all time
realtime = find_float((*(void ***)enginetool)[vtidx_GetRealTime]);
- if (!realtime) {
+ if_cold (!realtime) {
errmsg_errorx("couldn't find realtime variable");
return false;
}
host_frametime = find_float((*(void ***)enginetool)[vtidx_HostFrameTime]);
- if (!host_frametime) {
+ if_cold (!host_frametime) {
errmsg_errorx("couldn't find host_frametime variable");
return false;
}
void *eng = find_eng((*(void ***)hldsapi)[vtidx_RunFrame]);
- if (!eng) {
+ if_cold (!eng) {
errmsg_errorx("couldn't find eng global object");
return false;
}
void *func;
- if (!(func = find_HostState_Frame((*(void ***)eng)[vtidx_Frame]))) {
+ if_cold (!(func = find_HostState_Frame((*(void ***)eng)[vtidx_Frame]))) {
errmsg_errorx("couldn't find HostState_Frame function");
return false;
}
- if (!(func = find_FrameUpdate(func))) {
+ if_cold (!(func = find_FrameUpdate(func))) {
errmsg_errorx("couldn't find FrameUpdate function");
return false;
}
- if (!(func = find_floatcall(func, GAMETYPE_MATCHES(L4D2_2147plus) ? 2 : 1,
- "CHostState::State_Run"))) {
+ if_cold (!(func = find_floatcall(func, GAMETYPE_MATCHES(L4D2_2147plus) ?
+ 2 : 1, "CHostState::State_Run"))) {
errmsg_errorx("couldn't find State_Run function");
return false;
}
- if (!(func = find_floatcall(func, 1, "Host_RunFrame"))) {
+ if_cold (!(func = find_floatcall(func, 1, "Host_RunFrame"))) {
errmsg_errorx("couldn't find Host_RunFrame function");
return false;
}
- if (!(func = find_floatcall(func, 1, "_Host_RunFrame"))) {
+ if_cold (!(func = find_floatcall(func, 1, "_Host_RunFrame"))) {
errmsg_errorx("couldn't find _Host_RunFrame");
return false;
}
- if (!find_Host_AccumulateTime(func)) {
+ if_cold (!find_Host_AccumulateTime(func)) {
errmsg_errorx("couldn't find Host_AccumulateTime");
return false;
}
orig_Host_AccumulateTime = (Host_AccumulateTime_func)hook_inline(
(void *)orig_Host_AccumulateTime, (void *)hook_Host_AccumulateTime);
- if (!orig_Host_AccumulateTime) {
+ if_cold (!orig_Host_AccumulateTime) {
errmsg_errorsys("couldn't hook Host_AccumulateTime function");
}
return true;
}
END {
- if (!sst_userunloaded) return;
+ if_hot (!sst_userunloaded) return;
unhook_inline((void *)orig_Host_AccumulateTime);
}
diff --git a/src/fixes.c b/src/fixes.c
index 79f4e3d..226c5a9 100644
--- a/src/fixes.c
+++ b/src/fixes.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 Michael Smith <mikesmiffy128@gmail.com>
* Copyright © 2023 Hayden K <imaciidz@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -24,6 +24,7 @@
#include "con_.h"
#include "gametype.h"
+#include "langext.h"
static void chflags(const char *name, int unset, int set) {
struct con_var *v = con_findvar(name);
@@ -118,7 +119,7 @@ static void l4d2specific(void) {
// possible on these earlier versions (who knows if that breaks
// something...).
struct con_var *v = con_findvar("mat_queue_mode");
- if (v && !(v->parent->base.flags & CON_ARCHIVE)) { // not already fixed
+ if_hot (v && !(v->parent->base.flags & CON_ARCHIVE)) { // not already fixed
v->parent->base.flags = v->parent->base.flags &
~(CON_HIDDEN | CON_DEVONLY) | CON_ARCHIVE;
v->parent->hasmin = true; v->parent->minval = -1;
@@ -132,15 +133,14 @@ static void l4d2specific(void) {
// so just blanket enable it if the primary adapter is Intel, since it
// doesn't seem to break anything else anyway.
v = con_findvar("mat_tonemapping_occlusion_use_stencil");
- if (!v || con_getvari(v)) goto e;
+ if_cold (!v || con_getvari(v)) goto e;
// considered getting d3d9 object from actual game, but it's way easier
// to just create another one
IDirect3D9 *d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
- if (!d3d9) goto e;
+ if_cold (!d3d9) goto e;
D3DADAPTER_IDENTIFIER9 ident;
- if (IDirect3D9_GetAdapterIdentifier(d3d9, 0, 0, &ident) == D3D_OK &&
- ident.VendorId == 0x8086) { // neat vendor id, btw!
- con_setvari(v, 1);
+ if_hot (IDirect3D9_GetAdapterIdentifier(d3d9, 0, 0, &ident) == D3D_OK) {
+ if (ident.VendorId == 0x8086) con_setvari(v, 1); // neat vendor id, btw!
}
IDirect3D9_Release(d3d9);
e:;
diff --git a/src/fov.c b/src/fov.c
index 73cd17e..f4b8575 100644
--- a/src/fov.c
+++ b/src/fov.c
@@ -27,6 +27,7 @@
#include "gametype.h"
#include "hook.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "sst.h"
#include "vcall.h"
@@ -67,7 +68,7 @@ static bool find_SetDefaultFOV(struct con_cmd *fov) {
// replacement cvar needs to actively set player fov if in a map
static void fovcb(struct con_var *v) {
void *player = ent_get(1); // NOTE: singleplayer only!
- if (player) orig_SetDefaultFOV(player, con_getvari(v));
+ if_hot (player) orig_SetDefaultFOV(player, con_getvari(v));
}
// ensure FOV is applied on load, if the engine wouldn't do that itself
@@ -87,7 +88,7 @@ PREINIT {
INIT {
cmd_fov = con_findcmd("fov");
- if (!cmd_fov) return false; // shouldn't really happen but just in case!
+ if_cold (!cmd_fov) return false; // shouldn't happen but just in case!
if (real_fov_desired = con_findvar("fov_desired")) {
// latest steampipe already goes up to 120 fov
if (real_fov_desired->parent->maxval == 120) return false;
@@ -98,13 +99,13 @@ INIT {
con_reg(fov_desired);
real_fov_desired = fov_desired;
}
- if (!find_SetDefaultFOV(cmd_fov)) {
+ if_cold (!find_SetDefaultFOV(cmd_fov)) {
errmsg_errorx("couldn't find SetDefaultFOV function");
return false;
}
orig_SetDefaultFOV = (SetDefaultFOV_func)hook_inline(
(void *)orig_SetDefaultFOV, (void *)&hook_SetDefaultFOV);
- if (!orig_SetDefaultFOV) {
+ if_cold (!orig_SetDefaultFOV) {
errmsg_errorsys("couldn't hook SetDefaultFOV function");
return false;
}
@@ -118,7 +119,7 @@ INIT {
}
END {
- if (!sst_userunloaded) return;
+ 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) {
diff --git a/src/gameinfo.c b/src/gameinfo.c
index d535a44..21205b7 100644
--- a/src/gameinfo.c
+++ b/src/gameinfo.c
@@ -23,6 +23,7 @@
#include "errmsg.h"
#include "gamedata.h"
#include "gametype.h"
+#include "langext.h"
#include "os.h"
#include "vcall.h"
@@ -41,7 +42,7 @@ const char *gameinfo_title = title;
DECL_VFUNC_DYN(const char *, GetGameDirectory)
bool gameinfo_init(void) {
- if (!has_vtidx_GetGameDirectory) {
+ if_cold (!has_vtidx_GetGameDirectory) {
errmsg_errorx("unsupported VEngineClient interface");
return false;
}
@@ -53,8 +54,8 @@ bool gameinfo_init(void) {
// using e.g. Cyrillic folder names and successfully loading their
// speedgames won't be able to load SST. Thanks Windows!
const char *lcpgamedir = GetGameDirectory(engclient);
- if (!MultiByteToWideChar(CP_ACP, 0, lcpgamedir, strlen(lcpgamedir), gamedir,
- sizeof(gamedir) / sizeof(*gamedir))) {
+ if_cold (!MultiByteToWideChar(CP_ACP, 0, lcpgamedir, strlen(lcpgamedir),
+ gamedir, countof(gamedir))) {
errmsg_errorsys("couldn't convert game directory path character set");
return false;
}
@@ -73,7 +74,7 @@ bool gameinfo_init(void) {
// XXX: this same FindWindow call happens in ac.c - maybe factor out?
void *gamewin = FindWindowW(L"Valve001", 0);
// assuming: all games/mods use narrow chars only; this won't fail.
- int len = GetWindowTextA(gamewin, title, sizeof(title));
+ int len = GetWindowTextA(gamewin, title, ssizeof(title));
// argh, why did they start doing this, it's so pointless!
// hopefully nobody included these suffixes in their mod names, lol
if (len > 13 && !memcmp(title + len - 13, " - Direct3D 9", 13)) {
diff --git a/src/gameserver.c b/src/gameserver.c
index 5a76027..9e046ee 100644
--- a/src/gameserver.c
+++ b/src/gameserver.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -19,6 +19,7 @@
#include "feature.h"
#include "gamedata.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "x86.h"
#include "vcall.h"
@@ -66,7 +67,7 @@ static bool find_sv(con_cmdcb pause_cb) {
INIT {
struct con_cmd *pause = con_findcmd("pause");
- if (!find_sv(pause->cb)) {
+ if_cold (!find_sv(pause->cb)) {
errmsg_errorx("couldn't find game server object\n");
return false;
}
diff --git a/src/hook.c b/src/hook.c
index fe311cc..9e5d694 100644
--- a/src/hook.c
+++ b/src/hook.c
@@ -19,6 +19,7 @@
#include "con_.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "x86.h"
@@ -67,7 +68,7 @@ void *hook_inline(void *func_, void *target) {
// 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_loads32(func + 1) + 5;
- if (!os_mprot(func, 5, PAGE_EXECUTE_READWRITE)) return 0;
+ if_cold (!os_mprot(func, 5, PAGE_EXECUTE_READWRITE)) return 0;
int len = 0;
for (;;) {
// FIXME: these cases may result in somewhat dodgy error messaging. They
@@ -91,7 +92,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) {
+ if_cold (nexttrampoline - trampolines > sizeof(trampolines) - len - 6) {
con_warn("hook_inline: out of trampoline space\n");
return 0;
}
diff --git a/src/hud.c b/src/hud.c
index 24d8563..b1cbb56 100644
--- a/src/hud.c
+++ b/src/hud.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2022 Matthew Wozniak <sirtomato999@gmail.com>
+ * Copyright © 2024 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
@@ -23,6 +24,7 @@
#include "hook.h"
#include "hud.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "sst.h"
@@ -92,7 +94,10 @@ static void *matsurf, *toolspanel, *scheme;
typedef void (*VCALLCONV Paint_func)(void *);
static Paint_func orig_Paint;
void VCALLCONV hook_Paint(void *this) {
- if (this == toolspanel) EMIT_HudPaint();
+ // hopefully a smart branch predictor can figure this out - but we still
+ // want it to be the "slow" path, so that every other path does *not* need a
+ // prediction record. or.. I dunno, in theory that does make sense. shrug.
+ if_cold (this == toolspanel) EMIT_HudPaint();
orig_Paint(this);
}
@@ -156,21 +161,21 @@ static bool find_toolspanel(void *enginevgui) {
INIT {
matsurf = factory_engine("MatSystemSurface006", 0);
- if (!matsurf) {
+ if_cold (!matsurf) {
errmsg_errorx("couldn't get MatSystemSurface006 interface");
return false;
}
void *schememgr = factory_engine("VGUI_Scheme010", 0);
- if (!schememgr) {
+ if_cold (!schememgr) {
errmsg_errorx("couldn't get VGUI_Scheme010 interface");
return false;
}
- if (!find_toolspanel(vgui)) {
+ if_cold (!find_toolspanel(vgui)) {
errmsg_errorx("couldn't find engine tools panel");
return false;
}
void **vtable = *(void ***)toolspanel;
- if (!os_mprot(vtable + vtidx_Paint, sizeof(void *),
+ if_cold (!os_mprot(vtable + vtidx_Paint, sizeof(void *),
PAGE_READWRITE)) {
errmsg_errorsys("couldn't make virtual table writable");
return false;
@@ -184,8 +189,8 @@ INIT {
}
END {
- // don't unhook toolspanel if exiting, it's already long gone!
- if (sst_userunloaded) {
+ // don't unhook toolspanel if exiting: it's already long gone!
+ if_cold (sst_userunloaded) {
unhook_vtable(*(void ***)toolspanel, vtidx_Paint, (void *)orig_Paint);
SetPaintEnabled(toolspanel, false);
}
diff --git a/src/kv.c b/src/kv.c
index 019d017..698aa8e 100644
--- a/src/kv.c
+++ b/src/kv.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -16,7 +16,7 @@
#include "intdefs.h"
#include "kv.h"
-#include "unreachable.h"
+#include "langext.h"
#define EOF -1
diff --git a/src/kvsys.c b/src/kvsys.c
index fc10b93..31652f3 100644
--- a/src/kvsys.c
+++ b/src/kvsys.c
@@ -24,6 +24,7 @@
#include "gametype.h"
#include "hook.h"
#include "kvsys.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "vcall.h"
@@ -31,7 +32,7 @@
FEATURE()
-IMPORT void *KeyValuesSystem(void); // vstlib symbol
+void *KeyValuesSystem(void); // vstlib symbol
static void *kvs;
static int vtidx_GetSymbolForString = 3, vtidx_GetStringForSymbol = 4;
static bool iskvv2 = false;
@@ -101,7 +102,7 @@ INIT {
if (GAMETYPE_MATCHES(L4D2x)) {
void **kvsvt = mem_loadptr(kvs);
detectabichange(kvsvt);
- if (!os_mprot(kvsvt + vtidx_GetStringForSymbol, sizeof(void *),
+ if_cold (!os_mprot(kvsvt + vtidx_GetStringForSymbol, sizeof(void *),
PAGE_READWRITE)) {
errmsg_warnx("couldn't make KeyValuesSystem vtable writable");
errmsg_note("won't be able to prevent any nag messages");
diff --git a/src/l4dmm.c b/src/l4dmm.c
index 2439d6b..05a03a7 100644
--- a/src/l4dmm.c
+++ b/src/l4dmm.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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,6 +22,7 @@
#include "gamedata.h"
#include "gametype.h"
#include "kvsys.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "vcall.h"
@@ -62,7 +63,7 @@ const char *l4dmm_curcampaign(void) {
if (!matchfwk) { // we must have oldmmiface, then
struct contextval *ctxt = unknown_contextlookup(oldmmiface,
"CONTEXT_L4D_CAMPAIGN");
- if (!ctxt) return 0;
+ if_cold (!ctxt) return 0;
// HACK: since this context symbol stuff was the best that was found for
// this old MM interface, just map things back to their names manually.
// bit stupid, but it gets the (rather difficult) job done
@@ -76,18 +77,18 @@ const char *l4dmm_curcampaign(void) {
#endif
void *ctrlr = GetMatchNetworkMsgController(matchfwk);
struct KeyValues *kv = GetActiveGameServerDetails(ctrlr, 0);
- if (!kv) return 0; // not in server, probably
+ if_cold (!kv) return 0; // not in server, probably
const char *ret = 0;
struct KeyValues *subkey = kvsys_getsubkey(kv, sym_game);
- if (subkey) subkey = kvsys_getsubkey(subkey, sym_campaign);
- if (subkey) ret = kvsys_getstrval(subkey);
- if (ret) {
+ if_hot (subkey) subkey = kvsys_getsubkey(subkey, sym_campaign);
+ if_hot (subkey) ret = kvsys_getstrval(subkey);
+ if_hot (ret) {
// ugh, we have to free all the memory allocated by the engine, so copy
// this glorified global state to a buffer so the caller doesn't have to
// deal with freeing. this necessitates a length cap but it's hopefully
// reasonable...
- int len = strlen(ret);
- if (len > sizeof(campaignbuf) - 1) ret = 0;
+ usize len = strlen(ret);
+ if_cold (len > sizeof(campaignbuf) - 1) ret = 0;
else ret = memcpy(campaignbuf, ret, len + 1);
}
kvsys_free(kv);
@@ -112,8 +113,8 @@ bool l4dmm_firstmap(void) {
if (!kv) return false;
int chapter = 0;
struct KeyValues *subkey = kvsys_getsubkey(kv, sym_game);
- if (subkey) subkey = kvsys_getsubkey(subkey, sym_chapter);
- if (subkey) chapter = subkey->ival;
+ if_hot (subkey) subkey = kvsys_getsubkey(subkey, sym_chapter);
+ if_hot (subkey) chapter = subkey->ival;
kvsys_free(kv);
return chapter == 1;
}
@@ -122,12 +123,12 @@ INIT {
void *mmlib = os_dlhandle(OS_LIT("matchmaking") OS_LIT(OS_DLSUFFIX));
if (mmlib) {
ifacefactory factory = (ifacefactory)os_dlsym(mmlib, "CreateInterface");
- if (!factory) {
+ if_cold (!factory) {
errmsg_errordl("couldn't get matchmaking interface factory");
return false;
}
matchfwk = factory("MATCHFRAMEWORK_001", 0);
- if (!matchfwk) {
+ if_cold (!matchfwk) {
errmsg_errorx("couldn't get IMatchFramework interface");
return false;
}
@@ -138,7 +139,7 @@ INIT {
#ifdef _WIN32 // L4D1 has no Linux build, btw!
else {
oldmmiface = factory_engine("VENGINE_MATCHMAKING_VERSION001", 0);
- if (!oldmmiface) {
+ if_cold (!oldmmiface) {
errmsg_errorx("couldn't get IMatchmaking interface");
return false;
}
diff --git a/src/l4dreset.c b/src/l4dreset.c
index 4a8792e..a53b987 100644
--- a/src/l4dreset.c
+++ b/src/l4dreset.c
@@ -31,6 +31,7 @@
#include "gameserver.h"
#include "hook.h"
#include "intdefs.h"
+#include "langext.h"
#include "l4dmm.h"
#include "mem.h"
#include "sst.h"
@@ -84,14 +85,13 @@ static struct CVoteIssue *getissue(const char *textkey) {
static inline 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) {
- // 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;
- }
+ // versions >2045 and on map 1, but it's easiest to do unconditionally.
+ // the way this is written will *hopefully* produce a nice neat lea+cmovne.
+ struct CUtlVector *recordvector = mem_offset(*votecontroller,
+ off_callerrecords);
+ // This is equivalent to CUtlVector::RemoveAll() as there's no
+ // destructors to call. The result as is if nobody had ever voted.
+ if_random (off_callerrecords != -1) recordvector->sz = 0;
ExecuteCommand(getissue("#L4D_vote_restart_game"));
}
@@ -503,24 +503,24 @@ ok: // Director::Update calls UnfreezeTeam after the first jmp instruction
INIT {
struct con_cmd *cmd_listissues = con_findcmd("listissues");
- if (!cmd_listissues) {
+ if_cold (!cmd_listissues) {
errmsg_errorx("couldn't find \"listissues\" command");
return false;
}
con_cmdcbv1 listissues_cb = con_getcmdcbv1(cmd_listissues);
const uchar *nextinsns = find_votecontroller(listissues_cb);
- if (!nextinsns) {
+ if_cold (!nextinsns) {
errmsg_errorx("couldn't find vote controller variable");
return false;
}
- if (!find_voteissues(nextinsns)) {
+ if_cold (!find_voteissues(nextinsns)) {
errmsg_errorx("couldn't find vote issues list offset\n");
return false;
}
void **vtable;
#ifdef _WIN32
void *GameShutdown = (*(void ***)srvdll)[vtidx_GameShutdown];
- if (!find_TheDirector(GameShutdown)) {
+ if_cold (!find_TheDirector(GameShutdown)) {
errmsg_errorx("couldn't find TheDirector variable");
return false;
}
@@ -532,7 +532,7 @@ INIT {
if (GAMETYPE_MATCHES(L4D2)) {
#endif
vtable = mem_loadptr(director);
- if (!os_mprot(vtable + vtidx_OnGameplayStart, sizeof(*vtable),
+ if_cold (!os_mprot(vtable + vtidx_OnGameplayStart, sizeof(*vtable),
PAGE_READWRITE)) {
errmsg_errorsys("couldn't make virtual table writable");
return false;
@@ -543,7 +543,7 @@ INIT {
}
else /* L4D1 */ {
void *GameFrame = (*(void ***)srvdll)[vtidx_GameFrame];
- if (!find_UnfreezeTeam(GameFrame)) {
+ if_cold (!find_UnfreezeTeam(GameFrame)) {
errmsg_errorx("couldn't find UnfreezeTeam function");
return false;
}
@@ -556,16 +556,16 @@ INIT {
// 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) {
+ if_cold (!factory) {
errmsg_errorx("couldn't find vote controller entity factory");
goto nocd;
}
vtable = ent_findvtable(factory, "CVoteController");
- if (!vtable) {
+ if_cold (!vtable) {
errmsg_errorx("couldn't find CVoteController vtable");
goto nocd;
}
- if (!find_votecallers(vtable[vtidx_Spawn])) {
+ if_cold (!find_votecallers(vtable[vtidx_Spawn])) {
errmsg_errorx("couldn't find vote callers list offset");
nocd: errmsg_note("resetting a first map will not clear vote cooldowns");
}
diff --git a/src/l4dwarp.c b/src/l4dwarp.c
index 24c3873..d24e39c 100644
--- a/src/l4dwarp.c
+++ b/src/l4dwarp.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -25,6 +25,7 @@
#include "gamedata.h"
#include "gametype.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "vcall.h"
@@ -41,7 +42,7 @@ DECL_VFUNC_DYN(void, Teleport, const struct vec3f */*pos*/,
DEF_CCMD_HERE_UNREG(sst_l4d_testwarp, "Simulate a bot warping to you",
CON_SERVERSIDE | CON_CHEAT) {
struct edict *ed = ent_getedict(con_cmdclient + 1);
- if (!ed) { errmsg_errorx("couldn't access player entity"); return; }
+ if_cold (!ed) { errmsg_errorx("couldn't access player entity"); return; }
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);
diff --git a/src/langext.h b/src/langext.h
new file mode 100644
index 0000000..ef0f18d
--- /dev/null
+++ b/src/langext.h
@@ -0,0 +1,64 @@
+/* This file is dedicated to the public domain. */
+
+#ifndef INC_LANGEXT_H
+#define INC_LANGEXT_H
+
+#include "intdefs.h"
+
+#define ssizeof(x) ((ssize)sizeof(x))
+#define countof(x) (ssizeof(x) / ssizeof(*x))
+
+#if defined(__GNUC__) || defined(__clang__)
+#define if_hot(x) if (__builtin_expect(!!(x), 1))
+#define if_cold(x) if (__builtin_expect(!!(x), 0))
+#define if_random(x) if (__builtin_expect_with_probability(!!(x), 1, 0.5))
+#define unreachable __builtin_unreachable()
+#define assume(x) ((void)(!!(x) || (unreachable, 0)))
+#define cold __attribute__((__cold__, __noinline__))
+#else
+#define if_hot(x) if (x)
+#define if_cold(x) if (x)
+#define if_random(x) if (x)
+#ifdef _MSC_VER
+#define unreachable __assume(0)
+#define assume(x) ((void)(__assume(x), 0))
+#define cold __declspec(noinline)
+#else
+#define unreachable ((void)(0)) // might still give some warnings, but too bad
+#define assume(x) ((void)0)
+#define cold
+#endif
+#endif
+
+#define switch_exhaust(x) switch (x) if (0) default: unreachable; else
+#if defined(__GNUC__) || defined(__clang__)
+#define switch_exhaust_enum(E, x) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic error \"-Wswitch-enum\"") \
+ switch_exhaust ((enum E)(x)) \
+ _Pragma("GCC diagnostic pop")
+#else
+// NOTE: pragma trick doesn't work in MSVC (the pop seems to happen before the
+// switch is evaluated, so nothing happens) but you can still get errors using
+// -we4061. This doesn't matter for sst but might come in handy elsewhere...
+#define switch_exhaust_enum(E, x) switch_exhaust ((enum E)(x))
+#endif
+
+#define noreturn _Noreturn void
+
+#ifdef _WIN32
+#define import __declspec(dllimport) // only needed for variables
+#define export __declspec(dllexport)
+#else
+#define import
+#ifdef __GNUC__
+// N.B. we assume -fvisibility=hidden
+#define export __attribute__((visibility("default"))
+#else
+#define export int exp[-!!"compiler needs a way to export symbols!"];
+#endif
+#endif
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/nomute.c b/src/nomute.c
index 6a42d46..4e5bcc4 100644
--- a/src/nomute.c
+++ b/src/nomute.c
@@ -26,6 +26,7 @@
#include "con_.h"
#include "errmsg.h"
#include "feature.h"
+#include "langext.h"
#include "os.h"
#include "sst.h"
@@ -44,7 +45,7 @@ static con_cmdcbv1 snd_restart_cb = 0;
// 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();
+ if_hot (!skiprestart) snd_restart_cb();
skiprestart = false;
}
@@ -65,14 +66,15 @@ PREINIT {
INIT {
skiprestart = sst_earlyloaded; // see above
IDirectSound *ds_obj = 0;
- if (DirectSoundCreate(0, &ds_obj, 0) != DS_OK) {
+ if_cold (DirectSoundCreate(0, &ds_obj, 0) != DS_OK) {
// XXX: can this error be usefully stringified?
errmsg_errorx("couldn't create IDirectSound instance");
return false;
}
ds_vt = ds_obj->lpVtbl;
ds_obj->lpVtbl->Release(ds_obj);
- if (!os_mprot(&ds_vt->CreateSoundBuffer, sizeof(void *), PAGE_READWRITE)) {
+ if_cold (!os_mprot(&ds_vt->CreateSoundBuffer, sizeof(void *),
+ PAGE_READWRITE)) {
errmsg_errorsys("couldn't make virtual table writable");
return false;
}
@@ -81,7 +83,7 @@ INIT {
snd_mute_losefocus->base.flags &= ~CON_HIDDEN;
struct con_cmd *snd_restart = con_findcmd("snd_restart");
- if (snd_restart) {
+ if_hot (snd_restart) {
snd_restart_cb = con_getcmdcbv1(snd_restart);
snd_mute_losefocus->cb = &losefocuscb;
}
diff --git a/src/noreturn.h b/src/noreturn.h
deleted file mode 100644
index 81b2bae..0000000
--- a/src/noreturn.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* This file is dedicated to the public domain. */
-
-#ifndef INC_NORETURN_H
-#define INC_NORETURN_H
-
-#undef noreturn
-#define noreturn _Noreturn void
-
-#endif
-
-// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/nosleep.c b/src/nosleep.c
index e75c6e6..52c88a9 100644
--- a/src/nosleep.c
+++ b/src/nosleep.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -20,6 +20,7 @@
#include "feature.h"
#include "gamedata.h"
#include "hook.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "vcall.h"
@@ -48,7 +49,7 @@ PREINIT {
INIT {
vtable = mem_loadptr(inputsystem);
- if (!os_mprot(vtable + vtidx_SleepUntilInput, sizeof(void *),
+ if_cold (!os_mprot(vtable + vtidx_SleepUntilInput, sizeof(void *),
PAGE_READWRITE)) {
errmsg_errorx("couldn't make virtual table writable");
return false;
diff --git a/src/os.c b/src/os.c
index 49cab63..cf5c262 100644
--- a/src/os.c
+++ b/src/os.c
@@ -31,6 +31,7 @@
#endif
#include "intdefs.h"
+#include "langext.h"
#ifdef _WIN32
@@ -65,7 +66,7 @@ int os_write(int f, const void *buf, int len) {
vlong os_fsize(int f) {
vlong ret;
- if (!GetFileSizeEx((void *)(ssize)f, (LARGE_INTEGER *)&ret)) return -1;
+ if_cold (!GetFileSizeEx((void *)(ssize)f, (LARGE_INTEGER *)&ret)) return -1;
return ret;
}
@@ -90,13 +91,13 @@ void *os_dlsym(void *restrict lib, const char *restrict s) {
}
int os_dlfile(void *lib, ushort *buf, int sz) {
unsigned int n = GetModuleFileNameW(lib, buf, sz);
- if (n == 0 || n == sz) return -1;
+ if_cold (n == 0 || n == sz) return -1;
// get the canonical capitalisation, as for some reason GetModuleFileName()
// returns all lowercase. this doesn't really matter except it looks nicer
GetLongPathNameW(buf, buf, n + 1);
// the drive letter will also be lower case, if it is an actual drive letter
// of course. it should be; I'm not gonna lose sleep over UNC paths and such
- if (buf[0] >= L'a' && buf[0] <= L'z' && buf[1] == L':') buf[0] &= ~32u;
+ if_hot (buf[0] >= L'a' && buf[0] <= L'z' && buf[1] == L':') buf[0] &= ~32u;
return n;
}
@@ -124,7 +125,7 @@ void os_close(int f) { close(f); }
vlong os_fsize(int f) {
struct stat s;
- if (stat(f, &s) == -1) return -1;
+ if_cold (stat(f, &s) == -1) return -1;
return s.st_size;
}
@@ -166,7 +167,7 @@ static struct link_map *lmbase = 0;
void *os_dlhandle(const char *name) {
extern struct link_map *lmbase; // note: defined in sst.c for now
- if (!lmbase) { // IMPORTANT: not thread safe. don't forget later!
+ if_cold (!lmbase) { // IMPORTANT: not thread safe. don't forget later!
lmbase = (struct link_map *)dlopen("libc.so.6", RTLD_LAZY | RTLD_NOLOAD);
dlclose(lmbase); // assume success
while (lmbase->l_prev) lmbase = lmbase->l_prev;
@@ -195,7 +196,7 @@ void *os_dlhandle(const char *name) {
int os_dlfile(void *lib, char *buf, int sz) {
struct link_map *lm = lib;
int ssz = strlen(lm->l_name) + 1;
- if (ssz > sz) { errno = ENAMETOOLONG; return -1; }
+ if_cold (ssz > sz) { errno = ENAMETOOLONG; return -1; }
memcpy(buf, lm->l_name, ssz);
return ssz;
}
diff --git a/src/os.h b/src/os.h
index b599523..cbecf2c 100644
--- a/src/os.h
+++ b/src/os.h
@@ -24,9 +24,6 @@
#include <wchar.h> // XXX: there's kind of a lot of junk in this header!
-#define IMPORT __declspec(dllimport) // only needed for variables
-#define EXPORT __declspec(dllexport)
-
typedef unsigned short os_char;
#define _OS_CAT(x, y) x##y
#define OS_LIT(x) _OS_CAT(L, x)
@@ -75,13 +72,6 @@ typedef unsigned short os_char;
#include <errno.h> // meh
-#define IMPORT
-#ifdef __GNUC__
-#define EXPORT __attribute__((visibility("default"))
-#else
-#define EXPORT int exp[-!!"compiler needs a way to export symbols!"];
-#endif
-
// trying to avoid pulling in unnecessary headers as much as possible: define
// our own constants for os_mprot() / mprotect()
#if defined(__linux__) // apparently linux is pretty much the sole oddball here!
diff --git a/src/portalcolours.c b/src/portalcolours.c
index 3167c0b..61d9cc7 100644
--- a/src/portalcolours.c
+++ b/src/portalcolours.c
@@ -24,6 +24,7 @@
#include "hexcolour.h"
#include "hook.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "os.h"
#include "ppmagic.h"
@@ -102,13 +103,13 @@ PREINIT {
INIT {
#ifdef _WIN32
- if (!find_UTIL_Portal_Color(clientlib)) {
+ if_cold (!find_UTIL_Portal_Color(clientlib)) {
errmsg_errorx("couldn't find UTIL_Portal_Color");
return false;
}
orig_UTIL_Portal_Color = (UTIL_Portal_Color_func)hook_inline(
(void *)orig_UTIL_Portal_Color, (void *)&hook_UTIL_Portal_Color);
- if (!orig_UTIL_Portal_Color) {
+ if_cold (!orig_UTIL_Portal_Color) {
errmsg_errorsys("couldn't hook UTIL_Portal_Color");
return false;
}
@@ -126,7 +127,7 @@ INIT {
}
END {
- if (!sst_userunloaded) return;
+ if_hot (!sst_userunloaded) return;
unhook_inline((void *)orig_UTIL_Portal_Color);
}
diff --git a/src/rinput.c b/src/rinput.c
index 6b61bff..5464957 100644
--- a/src/rinput.c
+++ b/src/rinput.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -28,6 +28,7 @@
#include "gamedata.h"
#include "hook.h"
#include "intdefs.h"
+#include "langext.h"
#include "mem.h"
#include "sst.h"
#include "vcall.h"
@@ -68,12 +69,12 @@ DEF_CVAR_MINMAX(sst_mouse_factor, "Number of hardware mouse counts per step",
static ssize __stdcall inproc(void *wnd, uint msg, usize wp, ssize lp) {
switch (msg) {
case WM_INPUT:;
- char buf[sizeof(RAWINPUTHEADER) + sizeof(RAWMOUSE) /* = 40 */];
+ char buf[ssizeof(RAWINPUTHEADER) + ssizeof(RAWMOUSE) /* = 40 */];
uint sz = sizeof(buf);
- if (GetRawInputData((void *)lp, RID_INPUT, buf, &sz,
+ if_hot (GetRawInputData((void *)lp, RID_INPUT, buf, &sz,
sizeof(RAWINPUTHEADER)) != -1) {
RAWINPUT *ri = (RAWINPUT *)buf;
- if (ri->header.dwType == RIM_TYPEMOUSE) {
+ if_hot (ri->header.dwType == RIM_TYPEMOUSE) {
int d = con_getvari(sst_mouse_factor);
int dx = rx + ri->data.mouse.lLastX;
int dy = ry + ri->data.mouse.lLastY;
@@ -129,8 +130,8 @@ INIT {
if (!inputsystem) return false;
vtable_insys = mem_loadptr(inputsystem);
// XXX: this is kind of duping nosleep, but that won't always init...
- if (!os_mprot(vtable_insys + vtidx_GetRawMouseAccumulators,
- sizeof(void *), PAGE_READWRITE)) {
+ if_cold (!os_mprot(vtable_insys + vtidx_GetRawMouseAccumulators,
+ ssizeof(void *), PAGE_READWRITE)) {
errmsg_errorx("couldn't make virtual table writable");
return false;
}
@@ -149,7 +150,7 @@ INIT {
.lpfnWndProc = (WNDPROC)&inproc,
.lpszClassName = L"RInput"
};
- if (!RegisterClassExW(&wc)) {
+ if_cold (!RegisterClassExW(&wc)) {
struct rgba gold = {255, 210, 0, 255};
struct rgba blue = {45, 190, 190, 255};
struct rgba white = {200, 200, 200, 255};
@@ -158,7 +159,7 @@ INIT {
"Consider launching without that and using ");
con_colourmsg(&gold, "m_rawinput 1");
con_colourmsg(&blue, " instead!\n");
- if (has_rawinput) {
+ if_cold (has_rawinput) { // slow path because this'd be kinda weird!
con_colourmsg(&white, "This is built into this version of game, and"
" will also get provided by SST in older versions. ");
}
@@ -181,18 +182,18 @@ INIT {
orig_GetCursorPos = (GetCursorPos_func)hook_inline((void *)&GetCursorPos,
(void *)&hook_GetCursorPos);
- if (!orig_GetCursorPos) {
+ if_cold (!orig_GetCursorPos) {
errmsg_errorsys("couldn't hook %s", "GetCursorPos");
goto e0;
}
orig_SetCursorPos = (SetCursorPos_func)hook_inline((void *)&SetCursorPos,
(void *)&hook_SetCursorPos);
- if (!orig_SetCursorPos) {
+ if_cold (!orig_SetCursorPos) {
errmsg_errorsys("couldn't hook %s", "SetCursorPos");
goto e1;
}
inwin = CreateWindowExW(0, L"RInput", L"RInput", 0, 0, 0, 0, 0, 0, 0, 0, 0);
- if (!inwin) {
+ if_cold (!inwin) {
errmsg_errorsys("couldn't create input window");
goto e2;
}
@@ -201,7 +202,7 @@ INIT {
.usUsagePage = USAGEPAGE_MOUSE,
.usUsage = USAGE_MOUSE
};
- if (!RegisterRawInputDevices(&rd, 1, sizeof(rd))) {
+ if_cold (!RegisterRawInputDevices(&rd, 1, sizeof(rd))) {
errmsg_errorsys("couldn't create raw mouse device");
goto e3;
}
@@ -218,8 +219,8 @@ e0: UnregisterClassW(L"RInput", 0);
}
END {
- if (!sst_userunloaded) return;
- if (orig_SetCursorPos) { // if null, we didn't init our own implementation
+ if_hot (!sst_userunloaded) return;
+ if_hot (orig_SetCursorPos) { // we inited our own implementation
RAWINPUTDEVICE rd = {
.dwFlags = RIDEV_REMOVE,
.hwndTarget = 0,
@@ -232,7 +233,7 @@ END {
unhook_inline((void *)orig_GetCursorPos);
unhook_inline((void *)orig_SetCursorPos);
}
- else {
+ else { // we must have hooked the *existing* implementation
unhook_vtable(vtable_insys, vtidx_GetRawMouseAccumulators,
(void *)orig_GetRawMouseAccumulators);
}
diff --git a/src/sst.c b/src/sst.c
index ce80032..3f42327 100644
--- a/src/sst.c
+++ b/src/sst.c
@@ -33,6 +33,7 @@
#include "gameinfo.h"
#include "gametype.h"
#include "hook.h"
+#include "langext.h"
#include "os.h"
#include "sst.h"
#include "vcall.h"
@@ -70,7 +71,7 @@ int dladdr1(const void *addr, Dl_info *info, void **extra_info, int flags);
static void *ownhandle(void) {
static void *cached = 0;
Dl_info dontcare;
- if (!cached) {
+ if_cold (!cached) {
dladdr1((void *)&ownhandle, &dontcare, &cached, /*RTLD_DL_LINKMAP*/ 2);
}
return cached;
@@ -82,14 +83,14 @@ static void *ownhandle(void) {
static inline bool checksamedrive(const ushort *restrict path1,
const ushort *restrict path2) {
bool ret = (path1[0] | 32) == (path2[0] | 32);
- if (!ret) errmsg_errorx("game and plugin must be on the same drive\n");
+ if_cold (!ret) errmsg_errorx("game and plugin must be on the same drive\n");
return ret;
}
#endif
DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) {
os_char path[PATH_MAX];
- if (os_dlfile(ownhandle(), path, sizeof(path) / sizeof(*path)) == -1) {
+ if_cold (os_dlfile(ownhandle(), path, countof(path)) == -1) {
// hopefully by this point this won't happen, but, like, never know
errmsg_errordl("failed to get path to plugin");
return;
@@ -104,10 +105,10 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) {
// since old builds allow absolute plugin_load paths but since it's less
// reliable if e.g. a disk is removed, and also doesn't work for all
// games, just rule it out entirely to keep things simple.
- if (!checksamedrive(path, startdir)) return;
+ if_cold (!checksamedrive(path, startdir)) return;
#endif
int len = os_strlen(startdir);
- if (len + sizeof("/bin") >= PATH_MAX) {
+ if_cold (len + ssizeof("/bin") >= PATH_MAX) {
errmsg_errorx("path to game is too long");
return;
}
@@ -128,7 +129,7 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) {
// obscure gameinfo.txt arrangement could technically allow that to work
startdir = gameinfo_gamedir;
#ifdef _WIN32
- if (!checksamedrive(path, startdir)) return;
+ if_cold (!checksamedrive(path, startdir)) return;
#endif
}
os_char relpath[PATH_MAX];
@@ -136,7 +137,7 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) {
// note: dll isn't actually in gamedir if it's in a base mod directory
// note: gamedir doesn't account for if the dll is in a base mod's
// directory, although it will yield a valid/working relative path anyway.
- if (!PathRelativePathToW(relpath, startdir, FILE_ATTRIBUTE_DIRECTORY,
+ if_cold (!PathRelativePathToW(relpath, startdir, FILE_ATTRIBUTE_DIRECTORY,
path, 0)) {
errmsg_errorsys("couldn't compute a relative path");
return;
@@ -145,12 +146,12 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) {
// also make sure there's no unicode in there, just in case...
int rellen = 0;
for (ushort *p = relpath; *p; ++p, ++rellen) {
- if (*p > 127) {
+ if_cold (*p > 127) {
errmsg_errorx("mod dir contains Unicode characters which Source "
"doesn't handle well - autoload file not created");
return;
}
- if (*p == L'\\') *p = L'/';
+ if_random (*p == L'\\') *p = L'/';
}
#else
const char *p = path, *q = startdir;
@@ -179,35 +180,34 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) {
c: memcpy(r, p + slash + 1, rellen);
#endif
int len = os_strlen(gameinfo_gamedir);
- if (len + sizeof("/addons/" VDFBASENAME ".vdf") >
- sizeof(path) / sizeof(*path)) {
+ if (len + ssizeof("/addons/" VDFBASENAME ".vdf") > countof(path)) {
errmsg_errorx("path to VDF is too long");
return;
}
os_spancopy(path, gameinfo_gamedir, len);
os_spancopy(path + len, OS_LIT("/addons"), 8);
- if (!os_mkdir(path) && os_lasterror() != OS_EEXIST) {
+ if (!os_mkdir(path)) if_cold (os_lasterror() != OS_EEXIST) {
errmsg_errorsys("couldn't create %" fS, path);
return;
}
- os_spancopy(path + len + sizeof("/addons") - 1,
+ os_spancopy(path + len + ssizeof("/addons") - 1,
OS_LIT("/") OS_LIT(VDFBASENAME) OS_LIT(".vdf"),
- sizeof("/" VDFBASENAME ".vdf"));
+ ssizeof("/" VDFBASENAME ".vdf"));
int f = os_open_write(path);
- if (f == -1) { errmsg_errorsys("couldn't open %" fS, path); return; }
+ if_cold (f == -1) { errmsg_errorsys("couldn't open %" fS, path); return; }
#ifdef _WIN32
char buf[19 + PATH_MAX];
memcpy(buf, "Plugin { file \"", 15);
for (int i = 0; i < rellen; ++i) buf[i + 15] = relpath[i];
memcpy(buf + 15 + rellen, "\" }\n", 4);
- if (os_write(f, buf, rellen + 19) == -1) { // blegh
+ if_cold (os_write(f, buf, rellen + 19) == -1) { // blegh
#else
struct iovec iov[3] = {
{"Plugin { file \"", 15},
{relpath, rellen},
{"\" }\n", 4}
};
- if (writev(fd, &iov, 3) == -1) {
+ if_cold (writev(fd, &iov, 3) == -1) {
#endif
errmsg_errorsys("couldn't write to %" fS, path);
}
@@ -217,15 +217,14 @@ c: memcpy(r, p + slash + 1, rellen);
DEF_CCMD_HERE(sst_autoload_disable, "Stop loading SST on game startup", 0) {
os_char path[PATH_MAX];
int len = os_strlen(gameinfo_gamedir);
- if (len + sizeof("/addons/" VDFBASENAME ".vdf") >
- sizeof(path) / sizeof(*path)) {
+ if_cold (len + ssizeof("/addons/" VDFBASENAME ".vdf") > countof(path)) {
errmsg_errorx("path to VDF is too long");
return;
}
os_spancopy(path, gameinfo_gamedir, len);
os_spancopy(path + len, OS_LIT("/addons/") OS_LIT(VDFBASENAME) OS_LIT(".vdf"),
- sizeof("/addons/" VDFBASENAME ".vdf"));
- if (!os_unlink(path) && os_lasterror() != OS_ENOENT) {
+ ssizeof("/addons/" VDFBASENAME ".vdf"));
+ if (!os_unlink(path)) if_cold (os_lasterror() != OS_ENOENT) {
errmsg_warnsys("couldn't delete %" fS, path);
}
}
@@ -277,23 +276,24 @@ static void do_featureinit(void) {
engineapi_lateinit();
// load libs that might not be there early (...at least on Linux???)
clientlib = os_dlhandle(OS_LIT("client") OS_LIT(OS_DLSUFFIX));
- if (!clientlib) {
+ if_cold (!clientlib) {
errmsg_warndl("couldn't get the game's client library");
}
- else if (!(factory_client = (ifacefactory)os_dlsym(clientlib,
+ else if_cold (!(factory_client = (ifacefactory)os_dlsym(clientlib,
"CreateInterface"))) {
errmsg_warndl("couldn't get client's CreateInterface");
}
void *inputsystemlib = os_dlhandle(OS_LIT("bin/") OS_LIT("inputsystem")
OS_LIT(OS_DLSUFFIX));
- if (!inputsystemlib) {
+ if_cold (!inputsystemlib) {
errmsg_warndl("couldn't get the input system library");
}
- else if (!(factory_inputsystem = (ifacefactory)os_dlsym(inputsystemlib,
+ else if_cold (!(factory_inputsystem = (ifacefactory)os_dlsym(inputsystemlib,
"CreateInterface"))) {
errmsg_warndl("couldn't get input system's CreateInterface");
}
- else if (!(inputsystem = factory_inputsystem("InputSystemVersion001", 0))) {
+ else if_cold (!(inputsystem = factory_inputsystem(
+ "InputSystemVersion001", 0))) {
errmsg_warnx("missing input system interface");
}
// ... and now for the real magic!
@@ -301,7 +301,7 @@ static void do_featureinit(void) {
// if we're autoloaded and the external autoupdate script downloaded a new
// version, let the user know about the cool new stuff!
- if (getenv("SST_UPDATED")) {
+ if_cold (getenv("SST_UPDATED")) {
// avoid displaying again if we're unloaded and reloaded in one session
#ifdef _WIN32
SetEnvironmentVariableA("SST_UPDATED", 0);
@@ -338,7 +338,7 @@ DECL_VFUNC_DYN(bool, VGuiIsInitialized)
//
// Route credit to bill for helping figure a lot of this out - mike
static bool deferinit(void) {
- if (!vgui) {
+ if_cold (!vgui) {
errmsg_warnx("can't use VEngineVGui for deferred feature setup");
goto e;
}
@@ -348,7 +348,7 @@ static bool deferinit(void) {
// CEngineVGui::IsInitialized() which works everywhere.
if (VGuiIsInitialized(vgui)) return false;
sst_earlyloaded = true; // let other code know
- if (!os_mprot(*(void ***)vgui + vtidx_VGuiConnect, sizeof(void *),
+ if_cold (!os_mprot(*(void ***)vgui + vtidx_VGuiConnect, ssizeof(void *),
PAGE_READWRITE)) {
errmsg_warnsys("couldn't make CEngineVGui vtable writable for deferred "
"feature setup");
@@ -392,7 +392,7 @@ static void hook_plugin_unload_cb(const struct con_cmdargs *args) {
if (!CHECK_AllowPluginLoading(false)) return;
int idx = atoi(args->argv[1]);
struct CPlugin **plugins = pluginhandler->plugins.m.mem;
- if (idx >= 0 && idx < pluginhandler->plugins.sz) {
+ if_hot (idx >= 0 && idx < pluginhandler->plugins.sz) {
const struct CPlugin *plugin = plugins[idx];
// XXX: *could* memoise the ispluginv1 call, but... meh. effort.
const struct CPlugin_common *common = ispluginv1(plugin) ?
@@ -417,12 +417,12 @@ static void hook_plugin_unload_cb(const struct con_cmdargs *args) {
}
static bool do_load(ifacefactory enginef, ifacefactory serverf) {
- if (!hook_init()) {
+ if_cold (!hook_init()) {
errmsg_warnsys("couldn't set up memory for function hooking");
return false;
}
factory_engine = enginef; factory_server = serverf;
- if (!engineapi_init(ifacever)) return false;
+ if_cold (!engineapi_init(ifacever)) return false;
const void **p = vtable_firstdiff;
if (GAMETYPE_MATCHES(Portal2)) *p++ = (void *)&nop_p_v; // ClientFullyConnect
*p++ = (void *)&nop_p_v; // ClientDisconnect
@@ -437,7 +437,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(); fixes_apply(); }
- if (pluginhandler) {
+ if_hot (pluginhandler) {
cmd_plugin_load = con_findcmd("plugin_load");
orig_plugin_load_cb = cmd_plugin_load->cb;
cmd_plugin_load->cb = &hook_plugin_load_cb;
@@ -449,7 +449,8 @@ static bool do_load(ifacefactory enginef, ifacefactory serverf) {
}
static void do_unload(void) {
- if (sst_userunloaded) { // note: pluginhandler must also be set here
+ // slow path: reloading shouldn't happen all the time, prioritise fast exit
+ if_cold (sst_userunloaded) { // note: if we're here, pluginhandler is set
cmd_plugin_load->cb = orig_plugin_load_cb;
cmd_plugin_unload->cb = orig_plugin_unload_cb;
#ifdef _WIN32 // this bit is only relevant in builds that predate linux support
@@ -470,7 +471,7 @@ static void do_unload(void) {
static bool VCALLCONV Load(void *this, ifacefactory enginef,
ifacefactory serverf) {
- if (already_loaded) {
+ if_cold (already_loaded) {
con_warn("Already loaded! Doing nothing!\n");
skip_unload = true;
return false;
@@ -482,7 +483,7 @@ static bool VCALLCONV Load(void *this, ifacefactory enginef,
static void VCALLCONV Unload(void *this) {
// the game tries to unload on a failed load, for some reason
- if (skip_unload) { skip_unload = false; return; }
+ if_cold (skip_unload) { skip_unload = false; return; }
do_unload();
}
@@ -535,9 +536,9 @@ static const void **vtable_firstdiff = vtable + 10;
// this is equivalent to a class with no members!
static const void *const *const plugin_obj = vtable;
-EXPORT const void *CreateInterface(const char *name, int *ret) {
- if (!strncmp(name, "ISERVERPLUGINCALLBACKS00", 24)) {
- if (name[24] >= '1' && name[24] <= '3' && name[25] == '\0') {
+export const void *CreateInterface(const char *name, int *ret) {
+ if_hot (!strncmp(name, "ISERVERPLUGINCALLBACKS00", 24)) {
+ if_hot (name[24] >= '1' && name[24] <= '3' && name[25] == '\0') {
if (ret) *ret = 0;
ifacever = name[24] - '0';
return &plugin_obj;
diff --git a/src/unreachable.h b/src/unreachable.h
deleted file mode 100644
index 99c82b5..0000000
--- a/src/unreachable.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* This file is dedicated to the public domain. */
-
-#ifndef INC_UNREACHABLE_H
-#define INC_UNREACHABLE_H
-
-#if defined(__GNUC__) || defined(__clang__)
-#define unreachable __builtin_unreachable()
-#else
-#define unreachable do; while (0)
-#endif
-
-#endif
-
-// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/x86util.h b/src/x86util.h
index 85a824e..9fcdfff 100644
--- a/src/x86util.h
+++ b/src/x86util.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 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
@@ -18,14 +18,15 @@
#define INC_X86UTIL_H
#include "errmsg.h"
+#include "langext.h"
#include "x86.h"
// XXX: don't know where else to put this, or how else to design this, so this
-// is very much a plonk-it-here-for-now scenario.
+// is very much a plonk-it-here-for-now scenario (and has been for years!)
#define NEXT_INSN(p, tgt) do { \
int _len = x86_len(p); \
- if (_len == -1) { \
+ if_cold (_len == -1) { \
errmsg_errorx("unknown or invalid instruction looking for %s", tgt); \
return false; \
} \
diff --git a/test/kv.test.c b/test/kv.test.c
index 7f82b8a..1bd1784 100644
--- a/test/kv.test.c
+++ b/test/kv.test.c
@@ -9,7 +9,7 @@
#include "../src/kv.c"
#include "../src/intdefs.h"
-#include "../src/noreturn.h"
+#include "../src/langext.h"
static noreturn die(const struct kv_parser *kvp) {
fprintf(stderr, "parse error: %d:%d: %s\n", kvp->line, kvp->col,