diff --git a/extensions/sdkhooks/extension.cpp b/extensions/sdkhooks/extension.cpp index 66fad79530..31f2d44454 100644 --- a/extensions/sdkhooks/extension.cpp +++ b/extensions/sdkhooks/extension.cpp @@ -221,8 +221,6 @@ bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late) SetupHooks(); - g_pSM->AddGameFrameHook(&SDKHooks::DrainPendingDeletes); - #if SOURCE_ENGINE >= SE_ORANGEBOX int index; CBaseHandle hndl; @@ -288,27 +286,17 @@ bool SDKHooks::QueryInterfaceDrop(SMInterface* pInterface) return IExtensionInterface::QueryInterfaceDrop(pInterface); } -#define KILL_HOOK_IF_ACTIVE(hook) \ - if (hook != 0) \ - { \ - SH_REMOVE_HOOK_ID(hook); \ - hook = 0; \ - } - void SDKHooks::SDK_OnUnload() { - m_bUnloading = true; - - g_pSM->RemoveGameFrameHook(&SDKHooks::DrainPendingDeletes); - // Remove left over hooks - Unhook(reinterpret_cast(NULL)); - - for (CVTableList *list : m_PendingDeletes) + for (size_t type = 0; type < SDKHook_MAXHOOKS; ++type) { - delete list; + for (CVTableList *list : g_HookList[type]) + { + delete list; + } + g_HookList[type].clear(); } - m_PendingDeletes.clear(); m_HookLevelInit.Remove(gamedll); @@ -431,6 +419,11 @@ FeatureStatus SDKHooks::GetFeatureStatus(FeatureType type, const char *name) static void PopulateCallbackList(const std::vector &source, std::vector &destination, int entity) { + if (source.empty()) + { + return; + } + destination.reserve(8); for (size_t iter = 0; iter < source.size(); ++iter) { @@ -448,6 +441,30 @@ cell_t SDKHooks::Call(int entity, SDKHookType type, int other) return Call(gamehelpers->ReferenceToEntity(entity), type, gamehelpers->ReferenceToEntity(other)); } +static bool GetHookCallbacks(SDKHookType type, CBaseEntity *pEntity, int &entity, std::vector &callbackList) +{ + void** vtable = *(void***)pEntity; + std::vector &vtablehooklist = g_HookList[type]; + for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + { + if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) + { + continue; + } + + if (vtablehooklist[entry]->hooks.empty()) + { + break; + } + + entity = gamehelpers->EntityToBCompatRef(pEntity); + PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); + break; + } + + return !callbackList.empty(); +} + cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, int other) { return Call(pEnt, type, gamehelpers->ReferenceToEntity(other)); @@ -457,35 +474,27 @@ cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, CBaseEntity *pOther) { cell_t ret = Pl_Continue; - void** vtable = *(void***)pEnt; - std::vector &vtablehooklist = g_HookList[type]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(type, pEnt, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } + return ret; + } - int entity = gamehelpers->EntityToBCompatRef(pEnt); - int other = gamehelpers->EntityToBCompatRef(pOther); + int other = gamehelpers->EntityToBCompatRef(pOther); - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCell(other); + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCell(other); - cell_t res; - callback->Execute(&res); - if(res > ret) - { - ret = res; - } + cell_t res; + callback->Execute(&res); + if(res > ret) + { + ret = res; } - - break; } return ret; @@ -779,32 +788,6 @@ HookReturn SDKHooks::Hook(int entity, SDKHookType type, IPluginFunction *callbac return HookRet_Successful; } -void SDKHooks::DrainPendingDeletes(bool simulating) -{ - auto &pending = g_Interface.m_PendingDeletes; - if (pending.empty()) - return; - - std::vector batch; - batch.swap(pending); - - for (CVTableList *list : batch) - { - delete list; - } -} - -void SDKHooks::DeleteVtableHookList(CVTableList *list) -{ - if (m_bUnloading) - { - delete list; - return; - } - - m_PendingDeletes.push_back(list); -} - void SDKHooks::Unhook(CBaseEntity *pEntity) { if (pEntity == NULL) @@ -828,13 +811,13 @@ void SDKHooks::Unhook(CBaseEntity *pEntity) pawnhooks.erase(pawnhooks.begin() + entry); entry--; - } - if (pawnhooks.size() == 0) - { - DeleteVtableHookList(vtablehooklist[listentry]); - vtablehooklist.erase(vtablehooklist.begin() + listentry); - listentry--; + if (pawnhooks.size() == 0) + { + delete vtablehooklist[listentry]; + vtablehooklist.erase(vtablehooklist.begin() + listentry); + listentry--; + } } } } @@ -857,13 +840,13 @@ void SDKHooks::Unhook(IPluginContext *pContext) pawnhooks.erase(pawnhooks.begin() + entry); entry--; - } - if (pawnhooks.size() == 0) - { - DeleteVtableHookList(vtablehooklist[listentry]); - vtablehooklist.erase(vtablehooklist.begin() + listentry); - listentry--; + if (pawnhooks.size() == 0) + { + delete vtablehooklist[listentry]; + vtablehooklist.erase(vtablehooklist.begin() + listentry); + listentry--; + } } } } @@ -899,13 +882,13 @@ void SDKHooks::Unhook(int entity, SDKHookType type, IPluginFunction *pCallback) pawnhooks.erase(pawnhooks.begin() + entry); entry--; - } - if (pawnhooks.size() == 0) - { - DeleteVtableHookList(vtablehooklist[listentry]); - vtablehooklist.erase(vtablehooklist.begin() + listentry); - listentry--; + if (pawnhooks.size() == 0) + { + delete vtablehooklist[listentry]; + vtablehooklist.erase(vtablehooklist.begin() + listentry); + listentry--; + } } break; @@ -976,46 +959,35 @@ KHook::Return SDKHooks::Hook_LevelInit(IServerGameDLL*, char const *pMapNa */ KHook::Return SDKHooks::Hook_CanBeAutobalanced(CBaseEntity* this_ptr) { - CBaseEntity *pPlayer = this_ptr; - - void** vtable = *(void***)pPlayer; - std::vector &vtablehooklist = g_HookList[SDKHook_CanBeAutobalanced]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_CanBeAutobalanced, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } - - int entity = gamehelpers->EntityToBCompatRef(pPlayer); - - auto mfp = KHook::BuildMFP(KHook::FindOriginalVirtual(*(void***)this_ptr, g_HookTypes[SDKHook_CanBeAutobalanced].offset)); - bool origRet = (this_ptr->*mfp)(); - bool newRet = origRet; - - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - cell_t res = origRet; - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCell(origRet); - callback->Execute(&res); - - // Only update our new ret if different from original - // (so if multiple plugins returning different answers, - // the one(s) that changed it win) - if ((bool)res != origRet) - newRet = !origRet; - } + return { KHook::Action::Ignore, false }; + } - if (newRet != origRet) - return { KHook::Action::Supersede, newRet }; + auto mfp = KHook::BuildMFP(KHook::FindOriginalVirtual(*(void***)this_ptr, g_HookTypes[SDKHook_CanBeAutobalanced].offset)); + bool origRet = (this_ptr->*mfp)(); + bool newRet = origRet; - break; + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + cell_t res = origRet; + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCell(origRet); + callback->Execute(&res); + + // Only update our new ret if different from original + // (so if multiple plugins returning different answers, + // the one(s) that changed it win) + if ((bool)res != origRet) + newRet = !origRet; } + if (newRet != origRet) + return { KHook::Action::Supersede, newRet }; + return { KHook::Action::Ignore, false }; } @@ -1036,8 +1008,12 @@ KHook::Return SDKHooks::Hook_EndTouchPost(CBaseEntity* this_ptr, CBaseEnti KHook::Return SDKHooks::Hook_FireBulletsPost(CBaseEntity* this_ptr, const FireBulletsInfo_t &info) { - CBaseEntity *pEntity = this_ptr; - int entity = gamehelpers->EntityToBCompatRef(pEntity); + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_FireBulletsPost, this_ptr, entity, callbackList)) + { + return { KHook::Action::Ignore }; + } IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(entity); if(!pPlayer) @@ -1047,29 +1023,15 @@ KHook::Return SDKHooks::Hook_FireBulletsPost(CBaseEntity* this_ptr, const if(!pInfo) return { KHook::Action::Ignore }; - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[SDKHook_FireBulletsPost]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) - { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } - - const char *weapon = pInfo->GetWeaponName(); - - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCell(info.m_iShots); - callback->PushString(weapon?weapon:""); - callback->Execute(NULL); - } + const char *weapon = pInfo->GetWeaponName(); - break; + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCell(info.m_iShots); + callback->PushString(weapon?weapon:""); + callback->Execute(NULL); } return { KHook::Action::Ignore }; @@ -1078,52 +1040,42 @@ KHook::Return SDKHooks::Hook_FireBulletsPost(CBaseEntity* this_ptr, const #ifdef GETMAXHEALTH_IS_VIRTUAL KHook::Return SDKHooks::Hook_GetMaxHealth(CBaseEntity* this_ptr) { - CBaseEntity *pEntity = this_ptr; - auto mfp = KHook::BuildMFP(KHook::FindOriginalVirtual(*(void***)pEntity, g_HookTypes[SDKHook_GetMaxHealth].offset)); - int original_max = (pEntity->*mfp)(); - - void** vtable = *(void***)this_ptr; - std::vector &vtablehooklist = g_HookList[SDKHook_GetMaxHealth]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_GetMaxHealth, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } + return { KHook::Action::Ignore, 0 }; + } - int entity = gamehelpers->EntityToBCompatRef(pEntity); + auto mfp = KHook::BuildMFP(KHook::FindOriginalVirtual(*(void***)this_ptr, g_HookTypes[SDKHook_GetMaxHealth].offset)); + int original_max = (this_ptr->*mfp)(); - int new_max = original_max; + int new_max = original_max; - cell_t ret = Pl_Continue; + cell_t ret = Pl_Continue; - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCellByRef(&new_max); + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCellByRef(&new_max); - cell_t res; - callback->Execute(&res); + cell_t res; + callback->Execute(&res); - if (res > ret) - { - ret = res; - } + if (res > ret) + { + ret = res; } + } - if (ret >= Pl_Handled) - return { KHook::Action::Supersede, original_max }; - - if (ret >= Pl_Changed) - return { KHook::Action::Supersede, new_max }; + if (ret >= Pl_Handled) + return { KHook::Action::Supersede, original_max }; - break; - } + if (ret >= Pl_Changed) + return { KHook::Action::Supersede, new_max }; - return { KHook::Action::Ignore, original_max }; + return { KHook::Action::Ignore, 0 }; } #endif @@ -1135,136 +1087,115 @@ KHook::Return SDKHooks::Hook_GroundEntChangedPost(CBaseEntity* this_ptr, v KHook::Return SDKHooks::HandleOnTakeDamageHook(CBaseEntity* this_ptr, CTakeDamageInfoHack &info, SDKHookType hookType) { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[hookType]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(hookType, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } + return { KHook::Action::Ignore, 0 }; + } - int entity = gamehelpers->EntityToBCompatRef(pEntity); - int attacker = info.GetAttacker(); - int inflictor = info.GetInflictor(); - float damage = info.GetDamage(); - int damagetype = info.GetDamageType(); - int weapon = info.GetWeapon(); + int attacker = info.GetAttacker(); + int inflictor = info.GetInflictor(); + float damage = info.GetDamage(); + int damagetype = info.GetDamageType(); + int weapon = info.GetWeapon(); - Vector force = info.GetDamageForce(); - cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) }; + Vector force = info.GetDamageForce(); + cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) }; - Vector pos = info.GetDamagePosition(); - cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) }; + Vector pos = info.GetDamagePosition(); + cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) }; - cell_t res, ret = Pl_Continue; + cell_t res, ret = Pl_Continue; - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCellByRef(&attacker); + callback->PushCellByRef(&inflictor); + callback->PushFloatByRef(&damage); + callback->PushCellByRef(&damagetype); + callback->PushCellByRef(&weapon); + callback->PushArray(damageForce, 3, SM_PARAM_COPYBACK); + callback->PushArray(damagePosition, 3, SM_PARAM_COPYBACK); + callback->PushCell(info.GetDamageCustom()); + callback->Execute(&res); + + if (res >= ret) { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCellByRef(&attacker); - callback->PushCellByRef(&inflictor); - callback->PushFloatByRef(&damage); - callback->PushCellByRef(&damagetype); - callback->PushCellByRef(&weapon); - callback->PushArray(damageForce, 3, SM_PARAM_COPYBACK); - callback->PushArray(damagePosition, 3, SM_PARAM_COPYBACK); - callback->PushCell(info.GetDamageCustom()); - callback->Execute(&res); - - if (res >= ret) + ret = res; + if (ret == Pl_Changed) { - ret = res; - if (ret == Pl_Changed) + CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker); + if (!pEntAttacker && attacker != -1) + { + callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for attacker is invalid", attacker); + return { KHook::Action::Ignore, 0 }; + } + CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor); + if (!pEntInflictor && inflictor != -1) { - CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker); - if (!pEntAttacker && attacker != -1) - { - callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for attacker is invalid", attacker); - return { KHook::Action::Ignore, 0 }; - } - CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor); - if (!pEntInflictor && inflictor != -1) - { - callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for inflictor is invalid", inflictor); - return { KHook::Action::Ignore, 0 }; - } - - info.SetAttacker(pEntAttacker); - info.SetInflictor(pEntInflictor); - info.SetDamage(damage); - info.SetDamageType(damagetype); - info.SetWeapon(gamehelpers->ReferenceToEntity(weapon)); - info.SetDamageForce( - sp_ctof(damageForce[0]), - sp_ctof(damageForce[1]), - sp_ctof(damageForce[2])); - info.SetDamagePosition( - sp_ctof(damagePosition[0]), - sp_ctof(damagePosition[1]), - sp_ctof(damagePosition[2])); + callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for inflictor is invalid", inflictor); + return { KHook::Action::Ignore, 0 }; } + + info.SetAttacker(pEntAttacker); + info.SetInflictor(pEntInflictor); + info.SetDamage(damage); + info.SetDamageType(damagetype); + info.SetWeapon(gamehelpers->ReferenceToEntity(weapon)); + info.SetDamageForce( + sp_ctof(damageForce[0]), + sp_ctof(damageForce[1]), + sp_ctof(damageForce[2])); + info.SetDamagePosition( + sp_ctof(damagePosition[0]), + sp_ctof(damagePosition[1]), + sp_ctof(damagePosition[2])); } } + } - if (ret >= Pl_Handled) - return { KHook::Action::Supersede, 1 }; - - if (ret == Pl_Changed) - return { KHook::Action::Ignore, 1 }; + if (ret >= Pl_Handled) + return { KHook::Action::Supersede, 1 }; - break; - } + if (ret == Pl_Changed) + return { KHook::Action::Ignore, 1 }; return { KHook::Action::Ignore, 0 }; } KHook::Return SDKHooks::HandleOnTakeDamageHookPost(CBaseEntity* this_ptr, CTakeDamageInfoHack &info, SDKHookType hookType) { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[hookType]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(hookType, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } - - int entity = gamehelpers->EntityToBCompatRef(pEntity); - - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCell(info.GetAttacker()); - callback->PushCell(info.GetInflictor()); - callback->PushFloat(info.GetDamage()); - callback->PushCell(info.GetDamageType()); - callback->PushCell(info.GetWeapon()); + return { KHook::Action::Ignore, 0 }; + } - Vector force = info.GetDamageForce(); - cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) }; - callback->PushArray(damageForce, 3); + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCell(info.GetAttacker()); + callback->PushCell(info.GetInflictor()); + callback->PushFloat(info.GetDamage()); + callback->PushCell(info.GetDamageType()); + callback->PushCell(info.GetWeapon()); - Vector pos = info.GetDamagePosition(); - cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) }; - callback->PushArray(damagePosition, 3); + Vector force = info.GetDamageForce(); + cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) }; + callback->PushArray(damageForce, 3); - callback->PushCell(info.GetDamageCustom()); + Vector pos = info.GetDamagePosition(); + cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) }; + callback->PushArray(damagePosition, 3); - callback->Execute(NULL); - } + callback->PushCell(info.GetDamageCustom()); - break; + callback->Execute(NULL); } return { KHook::Action::Ignore, 0 }; @@ -1316,65 +1247,45 @@ KHook::Return SDKHooks::Hook_PostThinkPost(CBaseEntity* this_ptr) KHook::Return SDKHooks::Hook_Reload(CBaseEntity* this_ptr) { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[SDKHook_Reload]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_Reload, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } - - int entity = gamehelpers->EntityToBCompatRef(pEntity); - cell_t res = Pl_Continue; - - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->Execute(&res); - } + return { KHook::Action::Ignore, true }; + } - if (res >= Pl_Handled) - return { KHook::Action::Supersede, false }; + cell_t res = Pl_Continue; - break; + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->Execute(&res); } + if (res >= Pl_Handled) + return { KHook::Action::Supersede, false }; + return { KHook::Action::Ignore, true }; } KHook::Return SDKHooks::Hook_ReloadPost(CBaseEntity* this_ptr) { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[SDKHook_ReloadPost]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_ReloadPost, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } - - int entity = gamehelpers->EntityToBCompatRef(pEntity); - cell_t origreturn = (*(bool*)::KHook::GetCurrentValuePtr()) ? 1 : 0; + return { KHook::Action::Ignore, true }; + } - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCell(origreturn); - callback->Execute(NULL); - } + cell_t origreturn = (*(bool*)::KHook::GetCurrentValuePtr()) ? 1 : 0; - break; + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCell(origreturn); + callback->Execute(NULL); } return { KHook::Action::Ignore, true }; @@ -1392,83 +1303,63 @@ KHook::Return SDKHooks::Hook_SetTransmit(CBaseEntity* this_ptr, CCheckTran KHook::Return SDKHooks::Hook_ShouldCollide(CBaseEntity* this_ptr, int collisionGroup, int contentsMask) { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[SDKHook_ShouldCollide]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_ShouldCollide, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } - - int entity = gamehelpers->EntityToBCompatRef(pEntity); - cell_t origRet = (*(bool*)KHook::GetCurrentValuePtr()) ? 1 : 0; - cell_t res = 0; + return { KHook::Action::Ignore, true }; + } - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCell(collisionGroup); - callback->PushCell(contentsMask); - callback->PushCell(origRet); - callback->Execute(&res); - } + cell_t origRet = (*(bool*)KHook::GetCurrentValuePtr()) ? 1 : 0; + cell_t res = 0; - bool ret = false; - if (res != 0) - { - ret = true; - } + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCell(collisionGroup); + callback->PushCell(contentsMask); + callback->PushCell(origRet); + callback->Execute(&res); + } - return { KHook::Action::Supersede, ret }; + bool ret = false; + if (res != 0) + { + ret = true; } - return { KHook::Action::Ignore, true }; + return { KHook::Action::Supersede, ret }; } KHook::Return SDKHooks::Hook_Spawn(CBaseEntity* this_ptr) { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[SDKHook_Spawn]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_Spawn, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } + return { KHook::Action::Ignore }; + } - int entity = gamehelpers->EntityToBCompatRef(pEntity); - cell_t ret = Pl_Continue; + cell_t ret = Pl_Continue; - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); - cell_t res; - callback->Execute(&res); + cell_t res; + callback->Execute(&res); - if (res > ret) - { - ret = res; - } + if (res > ret) + { + ret = res; } - - if (ret >= Pl_Handled) - return { KHook::Action::Supersede }; - - break; } + if (ret >= Pl_Handled) + return { KHook::Action::Supersede }; + return { KHook::Action::Ignore }; } @@ -1532,76 +1423,66 @@ KHook::Return SDKHooks::Hook_TraceAttack(CBaseEntity* this_ptr, CTakeDamag KHook::Return SDKHooks::Hook_TraceAttack(CBaseEntity* this_ptr, CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr) #endif { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[SDKHook_TraceAttack]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_TraceAttack, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } + return { KHook::Action::Ignore }; + } - int entity = gamehelpers->EntityToBCompatRef(pEntity); - int attacker = info.GetAttacker(); - int inflictor = info.GetInflictor(); - float damage = info.GetDamage(); - int damagetype = info.GetDamageType(); - int ammotype = info.GetAmmoType(); - cell_t res, ret = Pl_Continue; + int attacker = info.GetAttacker(); + int inflictor = info.GetInflictor(); + float damage = info.GetDamage(); + int damagetype = info.GetDamageType(); + int ammotype = info.GetAmmoType(); + cell_t res, ret = Pl_Continue; - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCellByRef(&attacker); + callback->PushCellByRef(&inflictor); + callback->PushFloatByRef(&damage); + callback->PushCellByRef(&damagetype); + callback->PushCellByRef(&ammotype); + callback->PushCell(ptr->hitbox); + callback->PushCell(ptr->hitgroup); + callback->Execute(&res); + + if(res > ret) { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCellByRef(&attacker); - callback->PushCellByRef(&inflictor); - callback->PushFloatByRef(&damage); - callback->PushCellByRef(&damagetype); - callback->PushCellByRef(&ammotype); - callback->PushCell(ptr->hitbox); - callback->PushCell(ptr->hitgroup); - callback->Execute(&res); - - if(res > ret) - { - ret = res; + ret = res; - if(ret == Pl_Changed) + if(ret == Pl_Changed) + { + CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker); + if(!pEntAttacker) + { + callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for attacker is invalid", attacker); + return { KHook::Action::Ignore }; + } + CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor); + if(!pEntInflictor) { - CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker); - if(!pEntAttacker) - { - callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for attacker is invalid", attacker); - return { KHook::Action::Ignore }; - } - CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor); - if(!pEntInflictor) - { - callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for inflictor is invalid", inflictor); - return { KHook::Action::Ignore }; - } - - info.SetAttacker(pEntAttacker); - info.SetInflictor(pEntInflictor); - info.SetDamage(damage); - info.SetDamageType(damagetype); - info.SetAmmoType(ammotype); + callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for inflictor is invalid", inflictor); + return { KHook::Action::Ignore }; } + + info.SetAttacker(pEntAttacker); + info.SetInflictor(pEntInflictor); + info.SetDamage(damage); + info.SetDamageType(damagetype); + info.SetAmmoType(ammotype); } } + } - if(ret >= Pl_Handled) - return { KHook::Action::Supersede }; - - if(ret == Pl_Changed) - return { KHook::Action::Ignore }; + if(ret >= Pl_Handled) + return { KHook::Action::Supersede }; - break; - } + if(ret == Pl_Changed) + return { KHook::Action::Ignore }; return { KHook::Action::Ignore }; } @@ -1613,36 +1494,25 @@ KHook::Return SDKHooks::Hook_TraceAttackPost(CBaseEntity* this_ptr, CTakeD KHook::Return SDKHooks::Hook_TraceAttackPost(CBaseEntity* this_ptr, CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr) #endif { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[SDKHook_TraceAttackPost]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_TraceAttackPost, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } - - int entity = gamehelpers->EntityToBCompatRef(pEntity); - - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCell(info.GetAttacker()); - callback->PushCell(info.GetInflictor()); - callback->PushFloat(info.GetDamage()); - callback->PushCell(info.GetDamageType()); - callback->PushCell(info.GetAmmoType()); - callback->PushCell(ptr->hitbox); - callback->PushCell(ptr->hitgroup); - callback->Execute(NULL); - } + return { KHook::Action::Ignore }; + } - break; + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCell(info.GetAttacker()); + callback->PushCell(info.GetInflictor()); + callback->PushFloat(info.GetDamage()); + callback->PushCell(info.GetDamageType()); + callback->PushCell(info.GetAmmoType()); + callback->PushCell(ptr->hitbox); + callback->PushCell(ptr->hitgroup); + callback->Execute(NULL); } return { KHook::Action::Ignore }; @@ -1650,82 +1520,62 @@ KHook::Return SDKHooks::Hook_TraceAttackPost(CBaseEntity* this_ptr, CTakeD KHook::Return SDKHooks::Hook_Use(CBaseEntity* this_ptr, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[SDKHook_Use]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_Use, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } + return { KHook::Action::Ignore }; + } - int entity = gamehelpers->EntityToBCompatRef(pEntity); - int activator = gamehelpers->EntityToBCompatRef(pActivator); - int caller = gamehelpers->EntityToBCompatRef(pCaller); - cell_t ret = Pl_Continue; + int activator = gamehelpers->EntityToBCompatRef(pActivator); + int caller = gamehelpers->EntityToBCompatRef(pCaller); + cell_t ret = Pl_Continue; - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCell(activator); - callback->PushCell(caller); - callback->PushCell(useType); - callback->PushFloat(value); + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCell(activator); + callback->PushCell(caller); + callback->PushCell(useType); + callback->PushFloat(value); - cell_t res; - callback->Execute(&res); + cell_t res; + callback->Execute(&res); - if (res > ret) - { - ret = res; - } + if (res > ret) + { + ret = res; } - - if (ret >= Pl_Handled) - return { KHook::Action::Supersede }; - - break; } + if (ret >= Pl_Handled) + return { KHook::Action::Supersede }; + return { KHook::Action::Ignore }; } KHook::Return SDKHooks::Hook_UsePost(CBaseEntity* this_ptr, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { - CBaseEntity *pEntity = this_ptr; - - void** vtable = *(void***)pEntity; - std::vector &vtablehooklist = g_HookList[SDKHook_UsePost]; - for (size_t entry = 0; entry < vtablehooklist.size(); ++entry) + int entity; + std::vector callbackList; + if (!GetHookCallbacks(SDKHook_UsePost, this_ptr, entity, callbackList)) { - if (vtable != vtablehooklist[entry]->vtablehook->GetVTablePtr()) - { - continue; - } - - int entity = gamehelpers->EntityToBCompatRef(pEntity); - int activator = gamehelpers->EntityToBCompatRef(pActivator); - int caller = gamehelpers->EntityToBCompatRef(pCaller); + return { KHook::Action::Ignore }; + } - std::vector callbackList; - PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity); - for (entry = 0; entry < callbackList.size(); ++entry) - { - IPluginFunction *callback = callbackList[entry]; - callback->PushCell(entity); - callback->PushCell(activator); - callback->PushCell(caller); - callback->PushCell(useType); - callback->PushFloat(value); - callback->Execute(NULL); - } + int activator = gamehelpers->EntityToBCompatRef(pActivator); + int caller = gamehelpers->EntityToBCompatRef(pCaller); - break; + for (size_t entry = 0; entry < callbackList.size(); ++entry) + { + IPluginFunction *callback = callbackList[entry]; + callback->PushCell(entity); + callback->PushCell(activator); + callback->PushCell(caller); + callback->PushCell(useType); + callback->PushFloat(value); + callback->Execute(NULL); } return { KHook::Action::Ignore }; diff --git a/extensions/sdkhooks/extension.h b/extensions/sdkhooks/extension.h index 1b5b5df6b1..26f74297c3 100644 --- a/extensions/sdkhooks/extension.h +++ b/extensions/sdkhooks/extension.h @@ -352,8 +352,6 @@ class SDKHooks : void HandleEntityDeleted(CBaseEntity *pEntity); void Unhook(CBaseEntity *pEntity); void Unhook(IPluginContext *pContext); - void DeleteVtableHookList(CVTableList *list); - static void DrainPendingDeletes(bool simulating); private: KHook::Return HandleOnTakeDamageHook(CBaseEntity*, CTakeDamageInfoHack &info, SDKHookType hookType); @@ -362,8 +360,6 @@ class SDKHooks : private: inline bool IsEntityIndexInRange(int i) { return i >= 0 && i < NUM_ENT_ENTRIES; } cell_t m_EntityCache[NUM_ENT_ENTRIES]; - bool m_bUnloading = false; - std::vector m_PendingDeletes; }; extern CGlobalVars *gpGlobals; diff --git a/extensions/sdktools/hooks.cpp b/extensions/sdktools/hooks.cpp index db11665ed5..98919cdfae 100644 --- a/extensions/sdktools/hooks.cpp +++ b/extensions/sdktools/hooks.cpp @@ -127,7 +127,6 @@ void CHookManager::Initialize() void CHookManager::Shutdown() { - if (PRCH_used) { for (size_t i = 0; i < m_runUserCmdHooks.size(); ++i) @@ -435,14 +434,25 @@ void CHookManager::NetChannelHook(int client) } else #endif - if (!m_netChannelHooks.size()) { - m_netChannelHooks.push_back( - new CVTableHookDetails( - *(void***)basefilesystem, - KHook::GetVtableIndex(&IBaseFileSystem::FileExists), - this, &CHookManager::FileExists, nullptr - )); + void** fsvtable = *(void***)basefilesystem; + for (iter = 0; iter < m_netChannelHooks.size(); ++iter) + { + if (fsvtable == m_netChannelHooks[iter]->GetVTablePtr()) + { + break; + } + } + + if (iter == m_netChannelHooks.size()) + { + m_netChannelHooks.push_back( + new CVTableHookDetails( + fsvtable, + KHook::GetVtableIndex(&IBaseFileSystem::FileExists), + this, &CHookManager::FileExists, nullptr + )); + } } for (iter = 0; iter < m_netChannelHooks.size(); ++iter) @@ -572,6 +582,11 @@ KHook::Return CHookManager::SendFile(INetChannel* this_ptr, const char *fi #if !defined CLIENTVOICE_HOOK_SUPPORT KHook::Return CHookManager::ProcessVoiceData(IClientMessageHandler* this_ptr, CLC_VoiceData *msg) { + if (!m_OnClientSpeaking->GetFunctionCount() && !m_OnClientSpeakingEnd->GetFunctionCount()) + { + return { KHook::Action::Ignore, true }; + } + IClient *pClient = (IClient *)((intptr_t)(this_ptr) - sizeof(void *)); if (pClient == NULL) { @@ -655,55 +670,6 @@ void CHookManager::OnPluginLoaded(IPlugin *plugin) #endif } -void CHookManager::OnPluginUnloaded(IPlugin *plugin) -{ - if (PRCH_used && (!m_usercmdsFwd->GetFunctionCount() && !m_usercmdsPreFwd->GetFunctionCount())) - { - for (size_t i = 0; i < m_runUserCmdHooks.size(); ++i) - { - delete m_runUserCmdHooks[i]; - } - - m_runUserCmdHooks.clear(); - PRCH_used = false; - } - - if (PRCHPost_used && !m_usercmdsPostFwd->GetFunctionCount()) - { - for (size_t i = 0; i < m_runUserCmdPostHooks.size(); ++i) - { - delete m_runUserCmdPostHooks[i]; - } - - m_runUserCmdPostHooks.clear(); - PRCHPost_used = false; - } - - if (FILE_used && !m_netFileSendFwd->GetFunctionCount() && !m_netFileReceiveFwd->GetFunctionCount()) - { - for (size_t i = 0; i < m_netChannelHooks.size(); ++i) - { - delete m_netChannelHooks[i]; - } - - m_netChannelHooks.clear(); - FILE_used = false; - } - -#if !defined CLIENTVOICE_HOOK_SUPPORT - if (PVD_used && !m_OnClientSpeaking->GetFunctionCount() && !m_OnClientSpeakingEnd->GetFunctionCount()) - { - for (size_t i = 0; i < m_netProcessVoiceData.size(); ++i) - { - delete m_netProcessVoiceData[i]; - } - - m_netProcessVoiceData.clear(); - PVD_used = false; - } -#endif -} - FeatureStatus CHookManager::GetFeatureStatus(FeatureType type, const char *name) { return FeatureStatus_Available; diff --git a/extensions/sdktools/hooks.h b/extensions/sdktools/hooks.h index 4d1e997e3e..01080d644c 100644 --- a/extensions/sdktools/hooks.h +++ b/extensions/sdktools/hooks.h @@ -68,7 +68,6 @@ class CHookManager : IPluginsListener, IFeatureProvider KHook::Return ProcessPacket_Post(INetChannel*, struct netpacket_s *packet, bool bHasHeader); public: //IPluginsListener void OnPluginLoaded(IPlugin *plugin); - void OnPluginUnloaded(IPlugin *plugin); public: //IFeatureProvider virtual FeatureStatus GetFeatureStatus(FeatureType type, const char *name); diff --git a/extensions/tf2/teleporter.cpp b/extensions/tf2/teleporter.cpp index b070942ec3..4015f927f8 100644 --- a/extensions/tf2/teleporter.cpp +++ b/extensions/tf2/teleporter.cpp @@ -142,6 +142,6 @@ bool InitialiseTeleporterDetour() void RemoveTeleporterDetour() { - KHook::RemoveHook(g_HookCanPlayerBeTeleportedClass, true); + KHook::RemoveHook(g_HookCanPlayerBeTeleportedClass, false); g_HookCanPlayerBeTeleportedClass = KHook::INVALID_HOOK; } diff --git a/public/vtable_hook_helper.h b/public/vtable_hook_helper.h index 3dca401490..dc8e3a3f02 100644 --- a/public/vtable_hook_helper.h +++ b/public/vtable_hook_helper.h @@ -59,108 +59,128 @@ class CVTableHook template class CVTableHookDetails : public CVTableHook { +private: + class __Internal { + using Self = __Internal; public: - using Self = CVTableHookDetails; - - CVTableHookDetails(void** vtable, std::int32_t index, CONTEXT* ctx, KHook::Return (CONTEXT::*pre)(CLASSNAME*, ARGS...), KHook::Return (CONTEXT::*post)(CLASSNAME*, ARGS...)) - : CVTableHook(vtable), - _ctx(ctx), - _main_thread(std::this_thread::get_id()), - _pre(pre), - _post(post) { - _id = KHook::SetupVirtualHook( - vtable, - index, - this, - nullptr, - KHook::ExtractMFP(&Self::_KHOOK_CALLBACK_PRE), - KHook::ExtractMFP(&Self::_KHOOK_CALLBACK_POST), - KHook::ExtractMFP(&Self::_KHOOK_MAKE_RETURN), - KHook::ExtractMFP(&Self::_KHOOK_MAKE_ORIGINAL), - KHook::Hook::template _copy_stack_size(), - false); - } + void Remove() { + _ctx = nullptr; + _pre = nullptr; + _post = nullptr; + KHook::RemoveHook(_id); + } - virtual ~CVTableHookDetails() { - if (_id != KHook::INVALID_HOOK) { - KHook::RemoveHook(_id, true); + __Internal(void** vtable, std::int32_t index, CONTEXT* ctx, KHook::Return (CONTEXT::*pre)(CLASSNAME*, ARGS...), KHook::Return (CONTEXT::*post)(CLASSNAME*, ARGS...)) + : _ctx(ctx), + _main_thread(std::this_thread::get_id()), + _pre(pre), + _post(post) { + _id = KHook::SetupVirtualHook( + vtable, + index, + this, + (void*)&Self::_KHOOK_REMOVE, + KHook::ExtractMFP(&Self::_KHOOK_CALLBACK_PRE), + KHook::ExtractMFP(&Self::_KHOOK_CALLBACK_POST), + KHook::ExtractMFP(&Self::_KHOOK_MAKE_RETURN), + KHook::ExtractMFP(&Self::_KHOOK_MAKE_ORIGINAL), + KHook::Hook::template _copy_stack_size(), + false); } - } +private: + + inline RETURN _KHOOK_CALLBACK(bool pre, CLASSNAME* original_this, ARGS... args) { + if (std::this_thread::get_id() != _main_thread) { + if constexpr(!std::is_same::value) { + KHook::SaveReturnValue(KHook::Action::Ignore, nullptr, 0, nullptr, nullptr, false); + return RETURN(); + } else { + return; + } + } + + KHook::Return ret { KHook::Action::Ignore }; + if (pre && _pre) { + ret = (_ctx->*_pre)(original_this, args...); + } else if (!pre && _post) { + ret = (_ctx->*_post)(original_this, args...); + } + + RETURN* return_ptr = nullptr; + void* init_op = nullptr; + void* deinit_op = nullptr; + std::size_t size = 0; + if constexpr(!std::is_same::value) { + return_ptr = const_cast(&ret.ret); + init_op = reinterpret_cast(::KHook::init_operator); + deinit_op = reinterpret_cast(::KHook::deinit_operator); + size = sizeof(RETURN); + } - inline RETURN _KHOOK_CALLBACK(bool pre, CLASSNAME* original_this, ARGS... args) { - if (std::this_thread::get_id() != _main_thread) { + ::KHook::SaveReturnValue(ret.action, return_ptr, size, init_op, deinit_op, false); if constexpr(!std::is_same::value) { - KHook::SaveReturnValue(KHook::Action::Ignore, nullptr, 0, nullptr, nullptr, false); - return RETURN(); + return *return_ptr; } else { return; } } - KHook::Return ret { KHook::Action::Ignore }; - if (pre && _pre) { - ret = (_ctx->*_pre)(original_this, args...); - } else if (!pre && _post) { - ret = (_ctx->*_post)(original_this, args...); + RETURN _KHOOK_CALLBACK_PRE(ARGS... args) { + auto real_this = (Self*)KHook::GetContext(); + return real_this->_KHOOK_CALLBACK(true, (CLASSNAME*)this, args...); + } + + RETURN _KHOOK_CALLBACK_POST(ARGS... args) { + auto real_this = (Self*)KHook::GetContext(); + return real_this->_KHOOK_CALLBACK(false, (CLASSNAME*)this, args...); } - RETURN* return_ptr = nullptr; - void* init_op = nullptr; - void* deinit_op = nullptr; - std::size_t size = 0; - if constexpr(!std::is_same::value) { - return_ptr = const_cast(&ret.ret); - init_op = reinterpret_cast(::KHook::init_operator); - deinit_op = reinterpret_cast(::KHook::deinit_operator); - size = sizeof(RETURN); + RETURN _KHOOK_MAKE_RETURN(ARGS...) { + if constexpr(std::is_same::value) { + ::KHook::DestroyReturnValue(); + return; + } else { + RETURN ret = *(RETURN*)::KHook::GetCurrentValuePtr(true); + ::KHook::DestroyReturnValue(); + return ret; + } } - ::KHook::SaveReturnValue(ret.action, return_ptr, size, init_op, deinit_op, false); - if constexpr(!std::is_same::value) { - return *return_ptr; - } else { - return; + RETURN _KHOOK_MAKE_ORIGINAL(ARGS ...args) { + auto ptr = ::KHook::BuildMFP(::KHook::GetOriginalFunction()); + if constexpr(std::is_same::value) { + (((CLASSNAME*)this)->*ptr)(args...); + ::KHook::__internal__savereturnvalue(KHook::Return{ KHook::Action::Ignore }, true); + } else { + RETURN ret = (((CLASSNAME*)this)->*ptr)(args...); + ::KHook::__internal__savereturnvalue(KHook::Return{ KHook::Action::Ignore, ret }, true); + return ret; + } } - } - RETURN _KHOOK_CALLBACK_PRE(ARGS... args) { - auto real_this = (Self*)KHook::GetContext(); - return real_this->_KHOOK_CALLBACK(true, (CLASSNAME*)this, args...); - } + static void _KHOOK_REMOVE(KHook::HookID_t) { + delete (Self*)KHook::GetContext(); + } - RETURN _KHOOK_CALLBACK_POST(ARGS... args) { - auto real_this = (Self*)KHook::GetContext(); - return real_this->_KHOOK_CALLBACK(false, (CLASSNAME*)this, args...); - } + KHook::HookID_t _id; + CONTEXT* _ctx; + std::thread::id _main_thread; + KHook::Return (CONTEXT::*_pre)(CLASSNAME*, ARGS...); + KHook::Return (CONTEXT::*_post)(CLASSNAME*, ARGS...); + }; +public: + using Self = CVTableHookDetails; - RETURN _KHOOK_MAKE_RETURN(ARGS...) { - if constexpr(std::is_same::value) { - ::KHook::DestroyReturnValue(); - return; - } else { - RETURN ret = *(RETURN*)::KHook::GetCurrentValuePtr(true); - ::KHook::DestroyReturnValue(); - return ret; - } + CVTableHookDetails(void** vtable, std::int32_t index, CONTEXT* ctx, KHook::Return (CONTEXT::*pre)(CLASSNAME*, ARGS...), KHook::Return (CONTEXT::*post)(CLASSNAME*, ARGS...)) + : CVTableHook(vtable), + _hook(new __Internal(vtable, index, ctx, pre, post)) { } - RETURN _KHOOK_MAKE_ORIGINAL(ARGS ...args) { - auto ptr = ::KHook::BuildMFP(::KHook::GetOriginalFunction()); - if constexpr(std::is_same::value) { - (((CLASSNAME*)this)->*ptr)(args...); - ::KHook::__internal__savereturnvalue(KHook::Return{ KHook::Action::Ignore }, true); - } else { - RETURN ret = (((CLASSNAME*)this)->*ptr)(args...); - ::KHook::__internal__savereturnvalue(KHook::Return{ KHook::Action::Ignore, ret }, true); - return ret; - } + virtual ~CVTableHookDetails() { + _hook->Remove(); } - KHook::HookID_t _id; - CONTEXT* _ctx; - std::thread::id _main_thread; - KHook::Return (CONTEXT::*_pre)(CLASSNAME*, ARGS...); - KHook::Return (CONTEXT::*_post)(CLASSNAME*, ARGS...); + __Internal* _hook; }; #endif //_INCLUDE_VTABLE_HOOK_HELPER_H_