From fb5ec013199b5cb33543ec947ea78718b2968f4a Mon Sep 17 00:00:00 2001 From: shel <9306996+afwn90cj93201nixr2e1re@users.noreply.github.com> Date: Fri, 2 Oct 2020 18:43:07 +0400 Subject: [PATCH] Implemented IsReapiHookOriginalWasCalled which determine whether original function was called or not (#172) --- gradle.properties | 2 +- .../extra/amxmodx/scripting/include/reapi.inc | 10 ++++++ reapi/src/hook_callback.h | 26 ++++++++++---- reapi/src/hook_list.cpp | 6 ++-- reapi/src/hook_list.h | 2 ++ reapi/src/natives/natives_hookchains.cpp | 34 +++++++++++++++++++ 6 files changed, 70 insertions(+), 10 deletions(-) diff --git a/gradle.properties b/gradle.properties index a382be9..66a24d0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ majorVersion=5 -minorVersion=15 +minorVersion=16 maintenanceVersion=0 diff --git a/reapi/extra/amxmodx/scripting/include/reapi.inc b/reapi/extra/amxmodx/scripting/include/reapi.inc index 8a48a91..d3c0dec 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi.inc @@ -192,6 +192,16 @@ native any:GetHookChainReturn(AType:type, any:...); */ native SetHookChainArg(number, AType:type, any:...); +/* +* Return call state of original API function (that are available into enum). +* Look at the enums for parameter lists. +* +* @param func The function to get state +* +* @return Returns true if the original function was called, otherwise false +*/ +native bool:IsReapiHookOriginalWasCalled({EngineFunc, GamedllFunc, GamedllFunc_CBaseAnimating, GamedllFunc_CBasePlayer, GamedllFunc_CSGameRules, GamedllFunc_CGrenade, GamedllFunc_CWeaponBox, ReCheckerFunc, GamedllFunc_CBasePlayerWeapon, GamedllFunc_CGib}:function_id); + /* * Compares the entity to a specified classname. * @note This native also checks the validity of an entity. diff --git a/reapi/src/hook_callback.h b/reapi/src/hook_callback.h index bb0274d..bd8860d 100644 --- a/reapi/src/hook_callback.h +++ b/reapi/src/hook_callback.h @@ -144,12 +144,14 @@ struct hookctx_t extern hookctx_t* g_hookCtx; template -NOINLINE void DLLEXPORT _callVoidForward(const hook_t* hook, original_t original, f_args&&... args) +NOINLINE void DLLEXPORT _callVoidForward(hook_t* hook, original_t original, f_args&&... args) { auto hookCtx = g_hookCtx; hookCtx->reset(); int hc_state = HC_CONTINUE; + hook->wasCalled = false; + for (auto fwd : hook->pre) { if (likely(fwd->GetState() == FSTATE_ENABLED)) @@ -169,16 +171,21 @@ NOINLINE void DLLEXPORT _callVoidForward(const hook_t* hook, original_t original g_hookCtx = nullptr; original(std::forward(args)...); g_hookCtx = hookCtx; + hook->wasCalled = true; } - for (auto fwd : hook->post) { - if (likely(fwd->GetState() == FSTATE_ENABLED)) { + for (auto fwd : hook->post) + { + if (likely(fwd->GetState() == FSTATE_ENABLED)) + { auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), std::forward(args)...); if (unlikely(ret == HC_BREAK)) break; } } + + hook->wasCalled = false; } template @@ -197,13 +204,15 @@ void callVoidForward(size_t func, original_t original, f_args&&... args) } template -NOINLINE R DLLEXPORT _callForward(const hook_t* hook, original_t original, f_args&&... args) +NOINLINE R DLLEXPORT _callForward(hook_t* hook, original_t original, f_args&&... args) { auto hookCtx = g_hookCtx; hookCtx->reset(getApiType(R())); int hc_state = HC_CONTINUE; + hook->wasCalled = false; + for (auto fwd : hook->pre) { if (likely(fwd->GetState() == FSTATE_ENABLED)) @@ -233,6 +242,7 @@ NOINLINE R DLLEXPORT _callForward(const hook_t* hook, original_t original, f_arg g_hookCtx = nullptr; auto retVal = original(std::forward(args)...); g_hookCtx = hookCtx; + hook->wasCalled = true; if (unlikely(!hookCtx->retVal.set)) { switch (sizeof retVal) { @@ -250,14 +260,18 @@ NOINLINE R DLLEXPORT _callForward(const hook_t* hook, original_t original, f_arg } } - for (auto fwd : hook->post) { - if (likely(fwd->GetState() == FSTATE_ENABLED)) { + for (auto fwd : hook->post) + { + if (likely(fwd->GetState() == FSTATE_ENABLED)) + { auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), std::forward(args)...); if (unlikely(ret == HC_BREAK)) break; } } + + hook->wasCalled = false; return *(R *)&hookCtx->retVal._integer; } diff --git a/reapi/src/hook_list.cpp b/reapi/src/hook_list.cpp index 040f2f4..36e307b 100644 --- a/reapi/src/hook_list.cpp +++ b/reapi/src/hook_list.cpp @@ -71,7 +71,7 @@ struct regfunc int regfunc::current_cell = 1; -#define ENG(h,...) { {}, {}, #h, "ReHLDS", [](){ return api_cfg.hasReHLDS(); }, ((!(RH_##h & (MAX_REGION_RANGE - 1)) ? regfunc::current_cell = 1, true : false) || (RH_##h & (MAX_REGION_RANGE - 1)) == regfunc::current_cell++) ? regfunc(h##__VA_ARGS__) : regfunc(#h#__VA_ARGS__), [](){ g_RehldsHookchains->h()->registerHook(&h); }, [](){ g_RehldsHookchains->h()->unregisterHook(&h); }} +#define ENG(h,...) { {}, {}, #h, "ReHLDS", [](){ return api_cfg.hasReHLDS(); }, ((!(RH_##h & (MAX_REGION_RANGE - 1)) ? regfunc::current_cell = 1, true : false) || (RH_##h & (MAX_REGION_RANGE - 1)) == regfunc::current_cell++) ? regfunc(h##__VA_ARGS__) : regfunc(#h#__VA_ARGS__), [](){ g_RehldsHookchains->h()->registerHook(&h); }, [](){ g_RehldsHookchains->h()->unregisterHook(&h); }, false} hook_t hooklist_engine[] = { ENG(SV_StartSound), ENG(SV_DropClient), @@ -80,7 +80,7 @@ hook_t hooklist_engine[] = { ENG(SV_WriteFullClientUpdate, _AMXX) }; -#define DLL(h,...) { {}, {}, #h, "ReGameDLL", [](){ return api_cfg.hasReGameDLL(); }, ((!(RG_##h & (MAX_REGION_RANGE - 1)) ? regfunc::current_cell = 1, true : false) || (RG_##h & (MAX_REGION_RANGE - 1)) == regfunc::current_cell++) ? regfunc(h##__VA_ARGS__) : regfunc(#h#__VA_ARGS__), [](){ g_ReGameHookchains->h()->registerHook(&h); }, [](){ g_ReGameHookchains->h()->unregisterHook(&h); }} +#define DLL(h,...) { {}, {}, #h, "ReGameDLL", [](){ return api_cfg.hasReGameDLL(); }, ((!(RG_##h & (MAX_REGION_RANGE - 1)) ? regfunc::current_cell = 1, true : false) || (RG_##h & (MAX_REGION_RANGE - 1)) == regfunc::current_cell++) ? regfunc(h##__VA_ARGS__) : regfunc(#h#__VA_ARGS__), [](){ g_ReGameHookchains->h()->registerHook(&h); }, [](){ g_ReGameHookchains->h()->unregisterHook(&h); }, false} hook_t hooklist_gamedll[] = { DLL(GetForceCamera), DLL(PlayerBlind), @@ -213,7 +213,7 @@ hook_t hooklist_gib[] = { DLL(CGib_WaitTillLand), }; -#define RCHECK(h,...) { {}, {}, #h, "ReChecker", [](){ return api_cfg.hasRechecker(); }, ((!(RC_##h & (MAX_REGION_RANGE - 1)) ? regfunc::current_cell = 1, true : false) || (RC_##h & (MAX_REGION_RANGE - 1)) == regfunc::current_cell++) ? regfunc(h##__VA_ARGS__) : regfunc(#h#__VA_ARGS__), [](){ g_RecheckerHookchains->h()->registerHook(&h); }, [](){ g_RecheckerHookchains->h()->unregisterHook(&h); }} +#define RCHECK(h,...) { {}, {}, #h, "ReChecker", [](){ return api_cfg.hasRechecker(); }, ((!(RC_##h & (MAX_REGION_RANGE - 1)) ? regfunc::current_cell = 1, true : false) || (RC_##h & (MAX_REGION_RANGE - 1)) == regfunc::current_cell++) ? regfunc(h##__VA_ARGS__) : regfunc(#h#__VA_ARGS__), [](){ g_RecheckerHookchains->h()->registerHook(&h); }, [](){ g_RecheckerHookchains->h()->unregisterHook(&h); }, false} hook_t hooklist_rechecker[] = { RCHECK(FileConsistencyProcess, _AMXX), RCHECK(FileConsistencyFinal), diff --git a/reapi/src/hook_list.h b/reapi/src/hook_list.h index 9997ad6..59cd4e6 100644 --- a/reapi/src/hook_list.h +++ b/reapi/src/hook_list.h @@ -23,6 +23,8 @@ struct hook_t regchain_t unregisterHookchain; // unregister re* API hook void clear(); + + bool wasCalled; }; extern hook_t hooklist_engine[]; diff --git a/reapi/src/natives/natives_hookchains.cpp b/reapi/src/natives/natives_hookchains.cpp index 11fb62b..4d0aa9a 100644 --- a/reapi/src/natives/natives_hookchains.cpp +++ b/reapi/src/natives/natives_hookchains.cpp @@ -314,6 +314,38 @@ cell AMX_NATIVE_CALL SetHookChainArg(AMX *amx, cell *params) return TRUE; } +/* +* Return call state of original API function (that are available into enum). +* Look at the enums for parameter lists. +* +* @param func The function to get state +* +* @return Returns true if the API original function was called, otherwise false +* +* native bool:IsReapiHookOriginalWasCalled(any:function_id); +*/ +cell AMX_NATIVE_CALL IsReapiHookOriginalWasCalled(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_func }; + + int func = params[arg_func]; + auto hook = g_hookManager.getHook(func); + + if (unlikely(hook == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: function with id (%d) doesn't exist in current API version.", __FUNCTION__, func); + return INVALID_HOOKCHAIN; + } + + if (unlikely(!hook->checkRequirements())) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: function (%s) is not available, %s required.", __FUNCTION__, hook->func_name, hook->depend_name); + return INVALID_HOOKCHAIN; + } + + return hook->wasCalled ? TRUE : FALSE; +} + AMX_NATIVE_INFO HookChain_Natives[] = { { "RegisterHookChain", RegisterHookChain }, @@ -326,6 +358,8 @@ AMX_NATIVE_INFO HookChain_Natives[] = { "SetHookChainArg", SetHookChainArg }, + { "IsReapiHookOriginalWasCalled", IsReapiHookOriginalWasCalled }, + { nullptr, nullptr } };