aboutsummaryrefslogtreecommitdiff
path: root/src/l4dreset.c
diff options
context:
space:
mode:
authorGravatar Michael Smith <mikesmiffy128@gmail.com> 2025-03-10 02:37:19 +0000
committerGravatar Michael Smith <mikesmiffy128@gmail.com> 2025-04-06 16:41:13 +0100
commit244fea664121acf12871ab5858a5fe95a2606b52 (patch)
treee42b1990ef97adc0f0ab48b9be7e11de7fee0558 /src/l4dreset.c
parentd86b7b41453c69b3854baa7cdc05a79a3cdfe092 (diff)
downloadsst-244fea664121acf12871ab5858a5fe95a2606b52.tar.gz
sst-244fea664121acf12871ab5858a5fe95a2606b52.zip
Rewrite and redesign codegen and feature system
Also switch to somewhat proper C23 flags while we're at it. This is a huge change. It took me forever, in between being really busy. Sorry about that. But the good news is I'm now free to start integrating the various patches that have accumulated since last release. Well, at least in between still being really busy. Gotta manage expectations. The main benefit of introducing GAMESPECIFIC() is that features that don't apply to a particular game no longer show up *at all*, and less time is wasted on init. It also enables a cool optimisation wherein unnecessary REQUIRE_GAMEDATA() checks can elided at compile time whenever the gamedata is known up-front to always exist in supported games. The DEF_FEAT_CVAR macro family meanwhile makes it easier to manage the lifecycle of cvars/ccmds, with less manual registering, unhiding and such. Originally I was going to try and just hack these features into the existing codegen abomination, but it just got too terrible. This rewrite should make it easier to continue tweaking codegen behaviour in future. It also has slightly better error messages.
Diffstat (limited to 'src/l4dreset.c')
-rw-r--r--src/l4dreset.c45
1 files changed, 17 insertions, 28 deletions
diff --git a/src/l4dreset.c b/src/l4dreset.c
index 9e72f04..8333839 100644
--- a/src/l4dreset.c
+++ b/src/l4dreset.c
@@ -1,6 +1,6 @@
/*
* Copyright © 2023 Willian Henrique <wsimanbrazil@yahoo.com.br>
- * Copyright © 2024 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2025 Michael Smith <mikesmiffy128@gmail.com>
* Copyright © 2024 Hayden K <imaciidz@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -45,6 +45,7 @@
#endif
FEATURE("Left 4 Dead quick resetting")
+GAMESPECIFIC(L4D)
REQUIRE(ent)
REQUIRE(fastfwd)
REQUIRE(gameserver)
@@ -196,11 +197,11 @@ static short ffdelay = 0;
static float ffadj = 0;
static int nextmapnum = 0;
-DEF_CVAR_MINMAX_UNREG(sst_l4d_quickreset_peektime,
+DEF_FEAT_CVAR_MINMAX(sst_l4d_quickreset_peektime,
"Number of seconds to show each relevant item spot during fast-forward",
- 1.5, 0, 3, CON_ARCHIVE | CON_HIDDEN)
+ 1.5, 0, 3, CON_ARCHIVE)
-DEF_CCMD_HERE_UNREG(sst_l4d_quickreset_continue,
+DEF_FEAT_CCMD_HERE(sst_l4d_quickreset_continue,
"Get to the end of the current cutscene without further slowdowns", 0) {
if (!ffdelay) {
con_warn("not currently fast-forwarding a cutscene\n");
@@ -340,11 +341,10 @@ static int getffidx(const char *campaign) {
return -1; // if unknown, just don't fast-forward, I guess.
}
-DEF_CVAR_UNREG(sst_l4d_quickreset_fastfwd,
- "Fast-forward through cutscenes when quick-resetting", 1,
- CON_ARCHIVE | CON_HIDDEN)
+DEF_FEAT_CVAR(sst_l4d_quickreset_fastfwd,
+ "Fast-forward through cutscenes when quick-resetting", 1, CON_ARCHIVE)
-DEF_CCMD_HERE_UNREG(sst_l4d_quickreset,
+DEF_FEAT_CCMD_HERE(sst_l4d_quickreset,
"Reset (or switch) campaign and clear all vote cooldowns", 0) {
if (cmd->argc > 2) {
con_warn("usage: sst_l4d_quickreset [campaignid]\n");
@@ -376,13 +376,6 @@ DEF_CCMD_HERE_UNREG(sst_l4d_quickreset,
}
}
-PREINIT {
- if (!GAMETYPE_MATCHES(L4D)) return false;
- con_reg(sst_l4d_quickreset_fastfwd);
- con_reg(sst_l4d_quickreset_peektime);
- return true;
-}
-
// 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;
@@ -490,7 +483,7 @@ static inline bool find_UnfreezeTeam(void *GameFrame) { // note: L4D1 only
NEXT_INSN(p, "Director::Update call");
}
return false;
-ok: // Director::Update calls UnfreezeTeam after the first jmp instruction
+ok: // Director::Update calls UnfreezeTeam after the first jmp instruction
while (p - insns < 96) {
// jz XXX; mov ecx, <reg>; call Director::UnfreezeTeam
if (p[0] == X86_JZ && p[2] == X86_MOVRMW && (p[3] & 0xF8) == 0xC8 &&
@@ -508,28 +501,28 @@ INIT {
struct con_cmd *cmd_listissues = con_findcmd("listissues");
if_cold (!cmd_listissues) {
errmsg_errorx("couldn't find \"listissues\" command");
- return false;
+ return FEAT_INCOMPAT;
}
con_cmdcbv1 listissues_cb = con_getcmdcbv1(cmd_listissues);
const uchar *nextinsns = find_votecontroller(listissues_cb);
if_cold (!nextinsns) {
errmsg_errorx("couldn't find vote controller variable");
- return false;
+ return FEAT_INCOMPAT;
}
if_cold (!find_voteissues(nextinsns)) {
errmsg_errorx("couldn't find vote issues list offset\n");
- return false;
+ return FEAT_INCOMPAT;
}
void **vtable;
#ifdef _WIN32
void *GameShutdown = (*(void ***)srvdll)[vtidx_GameShutdown];
if_cold (!find_TheDirector(GameShutdown)) {
errmsg_errorx("couldn't find TheDirector variable");
- return false;
+ return FEAT_INCOMPAT;
}
#else
#warning TODO(linux): should be able to just dlsym(server, "TheDirector")
- return false;
+ return FEAT_INCOMPAT;
#endif
#ifdef _WIN32 // L4D1 has no Linux build, no need to check whether L4D2
if (GAMETYPE_MATCHES(L4D2)) {
@@ -538,7 +531,7 @@ INIT {
if_cold (!os_mprot(vtable + vtidx_OnGameplayStart, sizeof(*vtable),
PAGE_READWRITE)) {
errmsg_errorsys("couldn't make virtual table writable");
- return false;
+ return FEAT_FAIL;
}
orig_OnGameplayStart = (OnGameplayStart_func)hook_vtable(vtable,
vtidx_OnGameplayStart, (void *)&hook_OnGameplayStart);
@@ -548,7 +541,7 @@ INIT {
void *GameFrame = (*(void ***)srvdll)[vtidx_GameFrame];
if_cold (!find_UnfreezeTeam(GameFrame)) {
errmsg_errorx("couldn't find UnfreezeTeam function");
- return false;
+ return FEAT_INCOMPAT;
}
orig_UnfreezeTeam = (UnfreezeTeam_func)hook_inline(
(void *)orig_UnfreezeTeam, (void *)&hook_UnfreezeTeam);
@@ -573,11 +566,7 @@ INIT {
nocd: errmsg_note("resetting a first map will not clear vote cooldowns");
}
}
- con_reg(sst_l4d_quickreset);
- con_reg(sst_l4d_quickreset_continue);
- sst_l4d_quickreset_fastfwd->base.flags &= ~CON_HIDDEN;
- sst_l4d_quickreset_peektime->base.flags &= ~CON_HIDDEN;
- return true;
+ return FEAT_OK;
}
END {