From a927197c89f5e71857a641fcba03a5aa3015e55f Mon Sep 17 00:00:00 2001 From: regenerance <161264320+regenerance@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:24:33 -0700 Subject: [PATCH 1/2] fixed vm lifecycle for replaced functions on iw3 and t4 --- src/game/iw3/mp/components/events.cpp | 7 +++++-- src/game/iw3/mp/structs.h | 6 ++++++ src/game/t4/mp/components/events.cpp | 7 +++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/game/iw3/mp/components/events.cpp b/src/game/iw3/mp/components/events.cpp index 4b1259a6..719f3add 100644 --- a/src/game/iw3/mp/components/events.cpp +++ b/src/game/iw3/mp/components/events.cpp @@ -108,9 +108,12 @@ Detour Events::Load_DelayStream_Detour; void Events::Scr_ShutdownSystem_Hook(unsigned __int8 sys) { - for (size_t i = 0; i < ARRAYSIZE(vmShutdownHandlers); ++i) + if (sys == SCRIPT_USER_GAME) { - vmShutdownHandlers[i](); + for (size_t i = 0; i < ARRAYSIZE(vmShutdownHandlers); ++i) + { + vmShutdownHandlers[i](); + } } // Call original function after callbacks diff --git a/src/game/iw3/mp/structs.h b/src/game/iw3/mp/structs.h index bff2e6c4..42e0c870 100644 --- a/src/game/iw3/mp/structs.h +++ b/src/game/iw3/mp/structs.h @@ -3838,5 +3838,11 @@ static_assert(offsetof(scrVmPub_t, function_frame_start) == 0x20, ""); static_assert(offsetof(scrVmPub_t, stack) == 0x320, ""); static_assert(sizeof(scrVmPub_t) == 0x4320, ""); +enum ScriptSystemUser : unsigned __int8 +{ + SCRIPT_USER_PREGAME = 0x0, + SCRIPT_USER_GAME = 0x1, +}; + } // namespace mp } // namespace iw3 diff --git a/src/game/t4/mp/components/events.cpp b/src/game/t4/mp/components/events.cpp index 5ae4a602..5fcfe021 100644 --- a/src/game/t4/mp/components/events.cpp +++ b/src/game/t4/mp/components/events.cpp @@ -62,9 +62,12 @@ void *Events::Scr_ShutdownSystem_Hook(scriptInstance_t inst, int sys, int bCompl // These handlers own server script state. if (inst == SCRIPTINSTANCE_SERVER) { - for (size_t i = 0; i < ARRAYSIZE(vmShutdownHandlers); ++i) + if (bComplete) // ensures it only clears on game end { - vmShutdownHandlers[i](); + for (size_t i = 0; i < ARRAYSIZE(vmShutdownHandlers); ++i) + { + vmShutdownHandlers[i](); + } } } From d7cd522a4edf787f5fd82bb996488ec188c49b84 Mon Sep 17 00:00:00 2001 From: Michael Oliver Date: Wed, 7 Oct 2026 10:56:34 +0100 Subject: [PATCH 2/2] fix: correct IW3 and T4 script shutdown argument types --- src/game/iw3/mp/components/events.cpp | 6 +++--- src/game/iw3/mp/components/events.h | 2 +- src/game/iw3/mp/structs.h | 6 ------ src/game/iw3/mp/symbols.h | 3 ++- src/game/t4/mp/components/events.cpp | 13 +++++-------- src/game/t4/mp/components/events.h | 2 +- src/game/t4/mp/structs.h | 5 +++++ src/game/t4/mp/symbols.h | 2 +- 8 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/game/iw3/mp/components/events.cpp b/src/game/iw3/mp/components/events.cpp index 719f3add..d0022b54 100644 --- a/src/game/iw3/mp/components/events.cpp +++ b/src/game/iw3/mp/components/events.cpp @@ -106,9 +106,9 @@ void Events::Load_DelayStream_Hook() Detour Events::Load_DelayStream_Detour; -void Events::Scr_ShutdownSystem_Hook(unsigned __int8 sys) +void Events::Scr_ShutdownSystem_Hook(int bComplete) { - if (sys == SCRIPT_USER_GAME) + if (bComplete) { for (size_t i = 0; i < ARRAYSIZE(vmShutdownHandlers); ++i) { @@ -117,7 +117,7 @@ void Events::Scr_ShutdownSystem_Hook(unsigned __int8 sys) } // Call original function after callbacks - Scr_ShutdownSystem_Detour.GetOriginal()(sys); + Scr_ShutdownSystem_Detour.GetOriginal()(bComplete); } Detour Events::Scr_ShutdownSystem_Detour; diff --git a/src/game/iw3/mp/components/events.h b/src/game/iw3/mp/components/events.h index 5c447f63..ee7ef1e3 100644 --- a/src/game/iw3/mp/components/events.h +++ b/src/game/iw3/mp/components/events.h @@ -24,7 +24,7 @@ class Events : public Module static void Load_DelayStream_Hook(); static Detour Scr_ShutdownSystem_Detour; - static void Scr_ShutdownSystem_Hook(unsigned __int8 sys); + static void Scr_ShutdownSystem_Hook(int bComplete); static Detour Com_InitDvars_Detour; static void Com_InitDvars_Hook(); diff --git a/src/game/iw3/mp/structs.h b/src/game/iw3/mp/structs.h index 42e0c870..bff2e6c4 100644 --- a/src/game/iw3/mp/structs.h +++ b/src/game/iw3/mp/structs.h @@ -3838,11 +3838,5 @@ static_assert(offsetof(scrVmPub_t, function_frame_start) == 0x20, ""); static_assert(offsetof(scrVmPub_t, stack) == 0x320, ""); static_assert(sizeof(scrVmPub_t) == 0x4320, ""); -enum ScriptSystemUser : unsigned __int8 -{ - SCRIPT_USER_PREGAME = 0x0, - SCRIPT_USER_GAME = 0x1, -}; - } // namespace mp } // namespace iw3 diff --git a/src/game/iw3/mp/symbols.h b/src/game/iw3/mp/symbols.h index 28760762..56ccdbf8 100644 --- a/src/game/iw3/mp/symbols.h +++ b/src/game/iw3/mp/symbols.h @@ -486,7 +486,8 @@ typedef int (*CL_ConsolePrint_AddLine_t)(int localClientNum, int channel, const unsigned int pixelWidth, char color, int flags); static CL_ConsolePrint_AddLine_t CL_ConsolePrint_AddLine = reinterpret_cast(0x822E1EB8); -typedef void (*Scr_ShutdownSystem_t)(unsigned __int8 sys); +// TU4 omits the sys argument; only bComplete remains. +typedef void (*Scr_ShutdownSystem_t)(int bComplete); static Scr_ShutdownSystem_t Scr_ShutdownSystem = reinterpret_cast(0x82211FD0); typedef void (*Com_InitDvars_t)(); diff --git a/src/game/t4/mp/components/events.cpp b/src/game/t4/mp/components/events.cpp index 5fcfe021..59774f3d 100644 --- a/src/game/t4/mp/components/events.cpp +++ b/src/game/t4/mp/components/events.cpp @@ -57,17 +57,14 @@ void Events::Cmd_Init_Hook() Detour Events::Cmd_Init_Detour; -void *Events::Scr_ShutdownSystem_Hook(scriptInstance_t inst, int sys, int bComplete) +void *Events::Scr_ShutdownSystem_Hook(scriptInstance_t inst, scrSystem_t sys, int bComplete) { - // These handlers own server script state. - if (inst == SCRIPTINSTANCE_SERVER) + // These handlers own server script state and run only on complete shutdowns. + if (inst == SCRIPTINSTANCE_SERVER && bComplete) { - if (bComplete) // ensures it only clears on game end + for (size_t i = 0; i < ARRAYSIZE(vmShutdownHandlers); ++i) { - for (size_t i = 0; i < ARRAYSIZE(vmShutdownHandlers); ++i) - { - vmShutdownHandlers[i](); - } + vmShutdownHandlers[i](); } } diff --git a/src/game/t4/mp/components/events.h b/src/game/t4/mp/components/events.h index 152a93e5..26b5d637 100644 --- a/src/game/t4/mp/components/events.h +++ b/src/game/t4/mp/components/events.h @@ -20,7 +20,7 @@ class Events : public Module static void Cmd_Init_Hook(); static Detour Scr_ShutdownSystem_Detour; - static void *Scr_ShutdownSystem_Hook(scriptInstance_t inst, int sys, int bComplete); + static void *Scr_ShutdownSystem_Hook(scriptInstance_t inst, scrSystem_t sys, int bComplete); static Detour UI_Refresh_Detour; static int UI_Refresh_Hook(int localClientNum); diff --git a/src/game/t4/mp/structs.h b/src/game/t4/mp/structs.h index c1f60e25..4bc848ea 100644 --- a/src/game/t4/mp/structs.h +++ b/src/game/t4/mp/structs.h @@ -767,6 +767,11 @@ enum svscmd_type SV_CMD_RELIABLE = 0x1, }; +enum scrSystem_t : __int32 +{ + SCR_SYS_GAME = 0x1, +}; + enum scriptInstance_t : __int32 { SCRIPTINSTANCE_SERVER = 0x0, diff --git a/src/game/t4/mp/symbols.h b/src/game/t4/mp/symbols.h index 91c16f38..c0d93a79 100644 --- a/src/game/t4/mp/symbols.h +++ b/src/game/t4/mp/symbols.h @@ -189,7 +189,7 @@ static auto Scr_SetClientField = reinterpret_cast(0x8220A2D0); static auto Scr_SetGenericField = reinterpret_cast(0x82254E90); -typedef void *(*Scr_ShutdownSystem_t)(scriptInstance_t inst, int sys, int bComplete); +typedef void *(*Scr_ShutdownSystem_t)(scriptInstance_t inst, scrSystem_t sys, int bComplete); static Scr_ShutdownSystem_t Scr_ShutdownSystem = reinterpret_cast(0x82345388); static auto String_Parse = reinterpret_cast(0x822A8680);