diff options
| author | 2025-12-26 23:12:11 +0000 | |
|---|---|---|
| committer | 2026-02-16 19:11:24 +0000 | |
| commit | af370088fc178996a46ee508aaa1a2c46318bbf2 (patch) | |
| tree | cf1f6c01ad7c101d3fd4abb44835d9deb600e30d /src/l4daddon.c | |
| parent | 40f9d989df2c1ff2f567656ccbdbfc0d97e34a77 (diff) | |
| download | sst-af370088fc178996a46ee508aaa1a2c46318bbf2.tar.gz sst-af370088fc178996a46ee508aaa1a2c46318bbf2.zip | |
Move to static trampolines and type-safe hooks
For some reason the DLL got a tiny little bit bigger again but that's
fine. This will make orig_ calls more efficient in the inline case, and
also make it harder to screw up and hook the wrong thing by mistake.
Self-explanatory-ish, apart from the fact it's a fairly large API change
of course. And it relies on some more bonkers assembler directive
hackery.
But it works!
The only complaint one might have is that the featsetup functions no
longer take an explicit string which occasionally yields slightly less
perfect error messages, but I've decided this isn't really a problem and
makes the API nicer to use. It's a tradeoff, innit.
Diffstat (limited to 'src/l4daddon.c')
| -rw-r--r-- | src/l4daddon.c | 29 |
1 files changed, 13 insertions, 16 deletions
diff --git a/src/l4daddon.c b/src/l4daddon.c index 5336199..79c5e72 100644 --- a/src/l4daddon.c +++ b/src/l4daddon.c @@ -61,9 +61,9 @@ DECL_VFUNC_DYN(struct VEngineClient, void, ManageAddonsForActiveSession) // don't have to worry about that since it's cdecl (and we don't use it // ourselves, just pass it straight through). typedef void (*FS_MAFAS_func)(bool, char *, char *, bool); -static FS_MAFAS_func orig_FS_MAFAS; -static void hook_FS_MAFAS(bool disallowaddons, char *mission, char *gamemode, - bool ismutation) { +DEF_INLINE_HOOK(FS_MAFAS_func, FS_MAFAS) +static void hookdest_FS_MAFAS(bool disallowaddons, char *mission, + char *gamemode, bool ismutation) { // At the start of a map, particularly in 2204+ in campaigns with L4D1 // commons, there can be a ton of hitches due to the game trying to // load uncached materials as models are drawn. This FS_MAFAS function is @@ -139,21 +139,20 @@ static void hook_FS_MAFAS(bool disallowaddons, char *mission, char *gamemode, orig_FS_MAFAS(disallowaddons, mission, gamemode, ismutation); } -static inline bool find_FS_MAFAS() { +static inline FS_MAFAS_func find_FS_MAFAS() { #ifdef _WIN32 const uchar *insns = engclient->vtable[vtidx_ManageAddonsForActiveSession]; // CEngineClient::ManageAddonsForActiveSession just calls FS_MAFAS for (const uchar *p = insns; p - insns < 32;) { if (p[0] == X86_CALL) { - orig_FS_MAFAS = (FS_MAFAS_func)(p + 5 + mem_loads32(p + 1)); - return true; + return (FS_MAFAS_func)(p + 5 + mem_loads32(p + 1)); } NEXT_INSN(p, "FileSystem_ManageAddonsForActiveSession function"); } #else #warning: TODO(linux): asm search stuff #endif - return false; + return 0; } static inline bool find_addonvecsz(const uchar *insns) { @@ -176,8 +175,7 @@ static inline bool find_addonvecsz(const uchar *insns) { static void *broken_addon_check = 0; static uchar orig_broken_addon_check_bytes[13]; -static inline void try_fix_broken_addon_check() { - uchar *insns = (uchar *)orig_FS_MAFAS; +static inline void try_fix_broken_addon_check(uchar *insns) { for (uchar *p = insns; p - insns < 32;) { if (p[0] == X86_ALUMI8S && p[1] == X86_MODRM(0, 7, 5) && mem_loadptr(p + 2) == addonvecsz) { @@ -227,23 +225,22 @@ INIT { errmsg_errorx("couldn't find pointer to addon list"); return FEAT_INCOMPAT; } - if_cold (!find_FS_MAFAS()) { + FS_MAFAS_func FS_MAFAS = find_FS_MAFAS(); + if_cold (!FS_MAFAS) { errmsg_errorx("couldn't find FileSystem_ManageAddonsForActiveSession"); return FEAT_INCOMPAT; } - try_fix_broken_addon_check(); - struct hook_inline_featsetup_ret h = hook_inline_featsetup( - (void *)orig_FS_MAFAS, (void **)&orig_FS_MAFAS, - "FileSystem_ManageAddonsForActiveSession"); + try_fix_broken_addon_check((uchar *)FS_MAFAS); + struct hook_featsetup_ret_FS_MAFAS h = hook_featsetup_FS_MAFAS(FS_MAFAS); if_cold (h.err) return h.err; - hook_inline_commit(h.prologue, (void *)&hook_FS_MAFAS); + hook_commit_FS_MAFAS(h.hookpos, &hookdest_FS_MAFAS); return FEAT_OK; } END { // TODO(opt): can this unhook be made conditional too? bill suggested it // before but I don't know. maybe Hayden knows - mike - unhook_inline((void *)orig_FS_MAFAS); + unhook_FS_MAFAS(); if_cold (sst_userunloaded) { if (broken_addon_check) { memcpy(broken_addon_check, orig_broken_addon_check_bytes, 13); |
