From 3cbd6402967caae3b310e334ba96c6bc62fb8cff Mon Sep 17 00:00:00 2001 From: Kevin Masterson Date: Fri, 2 Jan 2026 00:16:05 +0200 Subject: [PATCH] plugin loading changes: - changed plugin_load to return an int: -1 = failure but file existed (do not continue to try new paths), 0 = failure but file not found (continue to try new paths), 1 = success - changed s_main_load_plugin to return a bool - output success or failure message after attempting to loading a plugin --- include/plugin.h | 3 ++- src/main.cpp | 34 ++++++++++++++++++++-------------- src/plugin.cpp | 29 ++++++++++++++++++++++------- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/include/plugin.h b/include/plugin.h index 48d7c82..1c03551 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -55,7 +55,8 @@ extern plugin_globals_t g_plugin_globals; extern std::vector g_plugins; const char* plugin_result_to_str(pluginres_t res); -bool plugin_load(plugin_t& p, std::string file); +// returns: -1 if failed to load and don't continue, 0 if failed to load and continue, 1 if loaded +int plugin_load(plugin_t& p, std::string file); void plugin_unload(plugin_t& p); #endif // __QMM2_PLUGIN_H__ diff --git a/src/main.cpp b/src/main.cpp index 08dd1b4..0721cfb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,7 +29,7 @@ static void s_main_detect_env(); static void s_main_load_config(bool quiet = false); static void s_main_detect_game(std::string cfg_game, bool is_GetGameAPI_mode); static bool s_main_load_mod(std::string cfg_mod); -static void s_main_load_plugin(std::string plugin_path); +static bool s_main_load_plugin(std::string plugin_path); static intptr_t s_main_handle_command_qmm(int arg_inc); static intptr_t s_main_route_vmmain(intptr_t cmd, intptr_t* args); static intptr_t s_main_route_syscall(intptr_t cmd, intptr_t* args); @@ -347,8 +347,11 @@ C_DLLEXPORT intptr_t vmMain(intptr_t cmd, ...) { // load plugins LOG(QMM_LOG_INFO, "QMM") << "Attempting to load plugins\n"; for (auto plugin_path : cfg_get_array_str(g_cfg, "plugins")) { - LOG(QMM_LOG_INFO, "QMM") << fmt::format("Attempting to load plugin \"{}\"\n", plugin_path); - s_main_load_plugin(plugin_path); + LOG(QMM_LOG_INFO, "QMM") << fmt::format("Attempting to load plugin \"{}\"...\n", plugin_path); + if (s_main_load_plugin(plugin_path)) + LOG(QMM_LOG_INFO, "QMM") << fmt::format("Plugin \"{}\" loaded\n", plugin_path); + else + LOG(QMM_LOG_INFO, "QMM") << fmt::format("Plugin \"{}\" not loaded\n", plugin_path); } LOG(QMM_LOG_NOTICE, "QMM") << fmt::format("Successfully loaded {} plugin(s)\n", g_plugins.size()); @@ -606,16 +609,16 @@ static bool s_main_load_mod(std::string cfg_mod) { // general code to find a plugin file to load -static void s_main_load_plugin(std::string plugin_path) { +static bool s_main_load_plugin(std::string plugin_path) { plugin_t p; // absolute path, just attempt to load it directly if (!path_is_relative(plugin_path)) { - // if the plugin decides to cancel itself in QMM_Attach, then plugin_load returns success - // but we only want to only store the plugin if it really loaded - if (plugin_load(p, plugin_path) && p.dll) { + // plugin_load returns 0 if no plugin file was found, 1 if success, and -1 if file was found but failure + if (plugin_load(p, plugin_path) > 0) { g_plugins.push_back(p); + return true; } - return; + return false; } // relative path, try the following locations in order: // "/" @@ -627,14 +630,17 @@ static void s_main_load_plugin(std::string plugin_path) { fmt::format("./{}/{}", g_gameinfo.moddir, plugin_path) }; for (auto& try_path : try_paths) { - // if the plugin decides to cancel itself in QMM_Attach, then plugin_load returns success - // but we only want to only store the plugin if it really loaded - if (plugin_load(p, try_path)) { - if (p.dll) - g_plugins.push_back(p); - return; + // plugin_load returns 0 if no plugin file was found, 1 if success, and -1 if file was found but failure + int ret = plugin_load(p, try_path); + if (ret > 0) { + g_plugins.push_back(p); + return true; } + if (ret < 0) + return false; } + + return false; } diff --git a/src/plugin.cpp b/src/plugin.cpp index 5f12af9..5c21d4e 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -92,7 +92,10 @@ const char* plugin_result_to_str(pluginres_t res) { } -bool plugin_load(plugin_t& p, std::string file) { +// returns: -1 if failed to load and don't continue, 0 if failed to load and continue, 1 if loaded +int plugin_load(plugin_t& p, std::string file) { + int ret = 0; + // if this plugin_t somehow already has a dll pointer, wipe it first if (p.dll) plugin_unload(p); @@ -106,9 +109,21 @@ bool plugin_load(plugin_t& p, std::string file) { // if this DLL is the same as QMM, cancel if ((void*)p.dll == g_gameinfo.qmm_module_ptr) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("plugin_load(\"{}\"): DLL is actually QMM?\n", file); + // treat this failure specially. this is a valid DLL, but it is QMM + ret = -1; goto fail; } + // if this DLL is the same as another loaded plugin, cancel + for (plugin_t& t : g_plugins) { + if (p.dll == t.dll) { + LOG(QMM_LOG_ERROR, "QMM") << fmt::format("plugin_load(\"{}\"): DLL is already loaded as plugin\n", file); + // treat this failure specially. this is a valid plugin, but it is already loaded + ret = -1; + goto fail; + } + } + if (!(p.QMM_Query = (plugin_query)dlsym(p.dll, "QMM_Query"))) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("plugin_load(\"{}\"): Unable to find \"QMM_Query\" function\n", file); goto fail; @@ -178,18 +193,18 @@ bool plugin_load(plugin_t& p, std::string file) { // QMM_Attach(engine syscall, mod vmmain, pointer to plugin result int, table of plugin helper functions, table of plugin variables) if (!(p.QMM_Attach(g_gameinfo.pfnsyscall, g_mod.pfnvmMain, &g_plugin_globals.plugin_result, &s_pluginfuncs, &s_pluginvars))) { LOG(QMM_LOG_ERROR, "QMM") << fmt::format("plugin_load(\"{}\"): QMM_Attach() returned 0\n", file); - // treat this failure specially. since this is a valid plugin, but decided on its own that it shouldn't be loaded, - // we return "true" so that QMM will not try to load the plugin again on a different path - plugin_unload(p); - return true; + // treat this failure specially. this is a valid plugin, but it decided on its own that it shouldn't be loaded + ret = -1; + goto fail; } p.path = file; - return true; + ret = 1; + return ret; fail: plugin_unload(p); - return false; + return ret; }