From ec926a611f4d225bb433609bf827269ad8482618 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Tue, 28 Nov 2023 16:28:55 +0700 Subject: [PATCH] Gracefully shutdown metamod and plugins when game is closing (for a proper reload using _restart command) --- metamod/src/dllapi.cpp | 7 +++++-- metamod/src/metamod.cpp | 6 ++++++ metamod/src/metamod.h | 2 ++ metamod/src/mlist.cpp | 9 +++++++++ metamod/src/mlist.h | 1 + metamod/src/mplugin.cpp | 2 +- metamod/src/mreg.cpp | 31 ++++++++++++++++++++----------- metamod/src/sys_module.cpp | 2 ++ 8 files changed, 46 insertions(+), 14 deletions(-) diff --git a/metamod/src/dllapi.cpp b/metamod/src/dllapi.cpp index 711d6dd..94e726e 100644 --- a/metamod/src/dllapi.cpp +++ b/metamod/src/dllapi.cpp @@ -12,8 +12,11 @@ NEW_DLL_FUNCTIONS sNewFunctionTable; NEW_DLL_FUNCTIONS sNewFunctionTable_jit; NEW_DLL_FUNCTIONS *pHookedNewDllFunctions = &sNewFunctionTable; -void MM_PRE_HOOK EXT_FUNC mm_GameShutdown() +// Unload game DLL and meta plugins +void MM_POST_HOOK EXT_FUNC mm_GameShutdown() { + g_metamod_active = false; + if (g_plugins) g_plugins->unload_all(); g_meta_extdll.unload(); g_GameDLL.sys_module.unload(); g_engine.sys_module.unload(); @@ -130,7 +133,7 @@ compile_data_t g_dllfunc_cdata[] = compile_data_t g_newdllfunc_cdata[] = { CDATA_NEWDLL(pfnOnFreeEntPrivateData), // Called right before the object's memory is freed. Calls its destructor. - CDATA_NEWDLL_H(pfnGameShutdown, P_PRE, mm_GameShutdown), // + CDATA_NEWDLL_H(pfnGameShutdown, P_POST, mm_GameShutdown), // CDATA_NEWDLL(pfnShouldCollide), // CDATA_NEWDLL(pfnCvarValue), // (fz) Use mm_CvarValue2 instead diff --git a/metamod/src/metamod.cpp b/metamod/src/metamod.cpp index 5c05b5c..1fede1c 100644 --- a/metamod/src/metamod.cpp +++ b/metamod/src/metamod.cpp @@ -32,6 +32,8 @@ unsigned int g_CALL_API_count = 0; int g_requestid_counter = 0; +bool g_metamod_active = false; + // Very first metamod function that's run. // Do startup operations... void metamod_startup() @@ -61,6 +63,8 @@ void metamod_startup() Sys_Error("Failure to init game DLL; exiting..."); } + g_metamod_active = true; + // Register various console commands and cvars. // Can I do these here, rather than waiting for GameDLLInit() ? // Looks like it works okay.. @@ -509,6 +513,8 @@ static void meta_apply_fix_data(std::vector& data) void meta_rebuild_callbacks() { + if (!g_metamod_active) return; + std::vector fixdata; if (g_metaGlobals.esp_save) { META_LOG("dll: Begin scan to collect callback fix data..."); diff --git a/metamod/src/metamod.h b/metamod/src/metamod.h index 508a9ef..fd770ef 100644 --- a/metamod/src/metamod.h +++ b/metamod/src/metamod.h @@ -74,6 +74,8 @@ extern unsigned int g_CALL_API_count; // stores previous requestid counter extern int g_requestid_counter; +extern bool g_metamod_active; + // (patch by BAILOPAN) // Holds cached player info, right now only things for querying cvars // Max players is always 32, small enough that we can use a static array diff --git a/metamod/src/mlist.cpp b/metamod/src/mlist.cpp index b69b44e..ea0a610 100644 --- a/metamod/src/mlist.cpp +++ b/metamod/src/mlist.cpp @@ -573,6 +573,15 @@ void MPluginList::unpause_all() } } +// Unload all plugins currently loaded +void MPluginList::unload_all() +{ + bool delayed; + for (auto p : m_plugins) { + p->unload(PT_ANYTIME, PNL_CMD_FORCED, delayed); + } +} + // Retry any pending actions on plugins, for instance load/unload delayed // until changelevel. void MPluginList::retry_all(PLUG_LOADTIME now) diff --git a/metamod/src/mlist.h b/metamod/src/mlist.h index 171c360..ee7e56e 100644 --- a/metamod/src/mlist.h +++ b/metamod/src/mlist.h @@ -35,6 +35,7 @@ class MPluginList bool load(); // load the list, at startup bool refresh(PLUG_LOADTIME now); // update from re-read inifile void unpause_all(); // unpause any paused plugins + void unload_all(); // unload all plugins void retry_all(PLUG_LOADTIME now); // retry any pending plugin actions void show(int source_index = 0); // list plugins to console use dynamic alignment void show_static(int source_index = 0); // list plugins to console use static alignment diff --git a/metamod/src/mplugin.cpp b/metamod/src/mplugin.cpp index 433add2..c1600de 100644 --- a/metamod/src/mplugin.cpp +++ b/metamod/src/mplugin.cpp @@ -471,7 +471,7 @@ bool MPlugin::unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, bool& delayed) return false; } } - if (m_action != PA_UNLOAD && m_action != PA_RELOAD) { + if (m_action != PA_UNLOAD && m_action != PA_RELOAD && reason != PNL_CMD_FORCED) { META_WARNING("dll: Not unloading plugin '%s'; not marked for unload (action=%s)", m_desc, str_action()); return false; } diff --git a/metamod/src/mreg.cpp b/metamod/src/mreg.cpp index 39f2236..63af093 100644 --- a/metamod/src/mreg.cpp +++ b/metamod/src/mreg.cpp @@ -64,17 +64,21 @@ MRegCmd* MRegCmdList::add(const char* addname, REG_CMD_FN cmd_handler, MPlugin* void MRegCmdList::remove(char* cmd_name) { - for (auto it = m_list.begin(), end = m_list.end(); it != end; ++it) { + for (auto it = m_list.begin(); it != m_list.end(); ) { auto reg = *it; if (!Q_stricmp(reg->m_name, cmd_name)) { if (g_RehldsFuncs) { g_RehldsFuncs->Cmd_RemoveCmd(cmd_name); - m_list.erase(it); + delete reg; + it = m_list.erase(it); } else { reg->disable(); + it++; } + } else { + it++; } } } @@ -82,17 +86,22 @@ void MRegCmdList::remove(char* cmd_name) // Disable any functions belonging to the given plugin (by index id). void MRegCmdList::remove(int owner_plugin_id) { - for (auto it = m_list.begin(), end = m_list.end(); it != end; ++it) { + for (auto it = m_list.begin(); it != m_list.end(); ) { auto reg = *it; - if (reg->m_plugid == owner_plugin_id) { - if (g_RehldsFuncs) { - g_RehldsFuncs->Cmd_RemoveCmd(reg->m_name); - m_list.erase(it); - } - else { - reg->disable(); - } + if (reg->m_plugid != owner_plugin_id) { + it++; + continue; + } + + if (g_RehldsFuncs) { + g_RehldsFuncs->Cmd_RemoveCmd(reg->m_name); + delete reg; + it = m_list.erase(it); + } + else { + reg->disable(); + it++; } } } diff --git a/metamod/src/sys_module.cpp b/metamod/src/sys_module.cpp index 8f5c7f5..9d97540 100644 --- a/metamod/src/sys_module.cpp +++ b/metamod/src/sys_module.cpp @@ -68,6 +68,7 @@ module_handle_t CSysModule::load(const char *filepath) { if (!m_handle) { m_handle = LoadLibrary(filepath); + if (m_handle) m_free = true; MODULEINFO module_info; if (GetModuleInformation(GetCurrentProcess(), m_handle, &module_info, sizeof(module_info))) { @@ -157,6 +158,7 @@ module_handle_t CSysModule::load(const char *filepath) { if (!m_handle) { m_handle = dlopen(filepath, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND); + if (m_handle) m_free = true; char buf[1024], dummy[1024], path[260]; Q_sprintf(buf, "/proc/%i/maps", getpid());