diff --git a/include/dusk/hook_system.hpp b/include/dusk/hook_system.hpp index d2d3752f1d..c173a3c44b 100644 --- a/include/dusk/hook_system.hpp +++ b/include/dusk/hook_system.hpp @@ -7,8 +7,8 @@ namespace dusk { void hookInstallByAddr(void* fn_addr, void* tramp_fn, void** orig_store); void hookRegisterPre (void* fn_addr, void* mod, int32_t (*fn)(void* args)); -void hookRegisterPost(void* fn_addr, void* mod, void (*fn)(void* args)); -void hookSetReplace (void* fn_addr, void* mod, void (*fn)(void* args)); +void hookRegisterPost(void* fn_addr, void* mod, const char* mod_name, void (*fn)(void* args)); +bool hookSetReplace (void* fn_addr, void* mod, const char* mod_name, void (*fn)(void* args)); bool hookDispatchPre (void* fn_addr, void* args); void hookDispatchPost(void* fn_addr, void* args); diff --git a/include/dusk/mod_loader.hpp b/include/dusk/mod_loader.hpp index a5a73504b9..72cb268747 100644 --- a/include/dusk/mod_loader.hpp +++ b/include/dusk/mod_loader.hpp @@ -21,8 +21,9 @@ struct LoadedMod { std::string mod_path; std::string dir; - void* handle = nullptr; - bool active = false; + void* handle = nullptr; + bool active = false; + bool load_failed = false; using FnInit = void (*)(DuskModAPI*); using FnTick = void (*)(DuskModAPI*); diff --git a/src/dusk/hook_system.cpp b/src/dusk/hook_system.cpp index 6d0f93df4c..54189dfcd5 100644 --- a/src/dusk/hook_system.cpp +++ b/src/dusk/hook_system.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ struct PreHookFn { }; struct VoidHookFn { void* mod; + const char* mod_name; void (*fn)(void* args); }; @@ -121,15 +123,19 @@ void hookRegisterPre(void* fn_addr, void* mod, int32_t (*fn)(void* args)) { registry()[reinterpret_cast(fn_addr)].pre.push_back({mod, fn}); } -void hookRegisterPost(void* fn_addr, void* mod, void (*fn)(void* args)) { - registry()[reinterpret_cast(fn_addr)].post.push_back({mod, fn}); +void hookRegisterPost(void* fn_addr, void* mod, const char* mod_name, void (*fn)(void* args)) { + registry()[reinterpret_cast(fn_addr)].post.push_back({mod, mod_name, fn}); } -void hookSetReplace(void* fn_addr, void* mod, void (*fn)(void* args)) { +bool hookSetReplace(void* fn_addr, void* mod, const char* mod_name, void (*fn)(void* args)) { auto& slot = registry()[reinterpret_cast(fn_addr)]; - if (slot.replace.fn) - DuskLog.warn("HookSystem: replace hook for {} already set — overwriting", fn_addr); - slot.replace = {mod, fn}; + if (slot.replace.fn) { + DuskLog.error("HookSystem: '{}' conflicts with '{}', both replace the same function", + mod_name, slot.replace.mod_name); + return false; + } + slot.replace = {mod, mod_name, fn}; + return true; } void hookClearMod(void* mod) { diff --git a/src/dusk/imgui/ImGuiMenuMods.cpp b/src/dusk/imgui/ImGuiMenuMods.cpp index c7199fbf13..07d362696f 100644 --- a/src/dusk/imgui/ImGuiMenuMods.cpp +++ b/src/dusk/imgui/ImGuiMenuMods.cpp @@ -48,12 +48,18 @@ void ImGuiMenuMods::showModsWindow() { if (ImGui::BeginTabBar("##ModsOuter")) { for (const auto& mod : mods) { - const std::string tabLabel = mod.name + (mod.active ? "" : " [disabled]"); + const std::string tabLabel = mod.name + (mod.load_failed ? " [failed]" : mod.active ? "" : " [disabled]"); if (ImGui::BeginTabItem(tabLabel.c_str())) { ImGui::Text("Version: %s", mod.version.c_str()); ImGui::Text("Author: %s", mod.author.c_str()); - ImGui::Text("Status: %s", mod.active ? "Active" : "Disabled"); + + if (mod.load_failed) { + ImGui::TextColored(ImVec4(1.f, 0.3f, 0.3f, 1.f), "Status: Failed to load"); + } else { + ImGui::Text("Status: %s", mod.active ? "Active" : "Disabled"); + } + ImGui::Text("Path: %s", mod.mod_path.c_str()); if (!mod.description.empty()) { @@ -61,9 +67,11 @@ void ImGuiMenuMods::showModsWindow() { ImGui::TextWrapped("%s", mod.description.c_str()); } - for (const auto& cb : mod.tab_content) { - ImGui::Separator(); - ModLoader::callDrawCallback(mod, cb); + if (!mod.load_failed) { + for (const auto& cb : mod.tab_content) { + ImGui::Separator(); + ModLoader::callDrawCallback(mod, cb); + } } ImGui::EndTabItem(); diff --git a/src/dusk/mod_loader.cpp b/src/dusk/mod_loader.cpp index 416e6c15e7..4df11baed2 100644 --- a/src/dusk/mod_loader.cpp +++ b/src/dusk/mod_loader.cpp @@ -160,11 +160,15 @@ static void api_hook_pre(void* addr, int32_t (*fn)(void* args)) { } static void api_hook_post(void* addr, void (*fn)(void* args)) { - dusk::hookRegisterPost(addr, g_currentMod, fn); + dusk::hookRegisterPost(addr, g_currentMod, modName(), fn); } static void api_hook_replace(void* addr, void (*fn)(void* args)) { - dusk::hookSetReplace(addr, g_currentMod, fn); + if (!dusk::hookSetReplace(addr, g_currentMod, modName(), fn)) { + if (g_currentMod) { + g_currentMod->load_failed = true; + } + } } namespace dusk { @@ -343,8 +347,12 @@ void ModLoader::init() { ModGuard guard(&mod); try { mod.fn_init(&mod.api); - mod.active = true; - DuskLog.info("ModLoader: '{}' initialized", mod.name); + if (!mod.load_failed) { + mod.active = true; + DuskLog.info("ModLoader: '{}' initialized", mod.name); + } else { + DuskLog.error("ModLoader: '{}' failed to load due to hook conflicts", mod.name); + } } catch (const std::exception& e) { DuskLog.error("ModLoader: exception in {}.mod_init(): {}", mod.name, e.what()); } catch (...) {