#pragma once #include #include #include #include "dusk/mod_api.h" namespace dusk { inline DuskModAPI* g_api = nullptr; inline void init(DuskModAPI* api) { g_api = api; } template T arg(void* args_raw, int n) noexcept { void** a = static_cast(args_raw); return *static_cast>>(a[n]); } template std::remove_reference_t& argRef(void* args_raw, int n) noexcept { void** a = static_cast(args_raw); return *static_cast>>(a[n]); } template void* mfpAddr(F fn) noexcept { void* p = nullptr; static_assert(sizeof(fn) >= sizeof(void*), "unexpected MFP size"); std::memcpy(&p, &fn, sizeof(void*)); return p; } template struct HookEntryBase { static inline Orig g_orig = nullptr; static R trampoline(Self self, A... args) { void* ptrs[] = {static_cast(std::addressof(self)), static_cast(std::addressof(args))...}; if constexpr (std::is_void_v) { const bool cancel = g_api->hook_dispatch_pre(mfpAddr(MFP), static_cast(ptrs), nullptr); if (!cancel) g_orig(self, args...); g_api->hook_dispatch_post(mfpAddr(MFP), static_cast(ptrs), nullptr); } else { R result{}; const bool cancel = g_api->hook_dispatch_pre(mfpAddr(MFP), static_cast(ptrs), static_cast(std::addressof(result))); if (!cancel) result = g_orig(self, args...); g_api->hook_dispatch_post(mfpAddr(MFP), static_cast(ptrs), static_cast(std::addressof(result))); return result; } } }; template struct HookEntryFreeBase { static inline Orig g_orig = nullptr; static R trampoline(A... args) { if constexpr (sizeof...(A) == 0) { if constexpr (std::is_void_v) { const bool cancel = g_api->hook_dispatch_pre(mfpAddr(FP), nullptr, nullptr); if (!cancel) g_orig(args...); g_api->hook_dispatch_post(mfpAddr(FP), nullptr, nullptr); } else { R result{}; const bool cancel = g_api->hook_dispatch_pre(mfpAddr(FP), nullptr, static_cast(std::addressof(result))); if (!cancel) result = g_orig(args...); g_api->hook_dispatch_post(mfpAddr(FP), nullptr, static_cast(std::addressof(result))); return result; } } else { void* ptrs[] = {static_cast(std::addressof(args))...}; if constexpr (std::is_void_v) { const bool cancel = g_api->hook_dispatch_pre(mfpAddr(FP), static_cast(ptrs), nullptr); if (!cancel) g_orig(args...); g_api->hook_dispatch_post(mfpAddr(FP), static_cast(ptrs), nullptr); } else { R result{}; const bool cancel = g_api->hook_dispatch_pre(mfpAddr(FP), static_cast(ptrs), static_cast(std::addressof(result))); if (!cancel) result = g_orig(args...); g_api->hook_dispatch_post(mfpAddr(FP), static_cast(ptrs), static_cast(std::addressof(result))); return result; } } } }; template struct HookEntry; template struct HookEntry : HookEntryBase {}; template struct HookEntry : HookEntryBase {}; template struct HookEntry : HookEntryFreeBase {}; template void hookAddPre(int32_t (*fn)(void* args)) { using E = HookEntry; g_api->hook_install(mfpAddr(MFP), reinterpret_cast(E::trampoline), reinterpret_cast(&E::g_orig)); g_api->hook_pre(mfpAddr(MFP), fn); } template void hookAddPost(void (*fn)(void* args, void* retval)) { using E = HookEntry; g_api->hook_install(mfpAddr(MFP), reinterpret_cast(E::trampoline), reinterpret_cast(&E::g_orig)); g_api->hook_post(mfpAddr(MFP), fn); } template void hookSetReplace(void (*fn)(void* args, void* retval)) { using E = HookEntry; g_api->hook_install(mfpAddr(MFP), reinterpret_cast(E::trampoline), reinterpret_cast(&E::g_orig)); g_api->hook_replace(mfpAddr(MFP), fn); } } // namespace dusk