sm-ext-dhooks2/vhook.cpp

292 lines
7.4 KiB
C++
Raw Normal View History

2013-08-16 05:53:38 +02:00
#include "vhook.h"
2013-08-20 04:33:44 +02:00
#include "vfunc_call.h"
2013-08-16 05:53:38 +02:00
SourceHook::IHookManagerAutoGen *g_pHookManager = NULL;
2013-08-19 17:07:25 +02:00
CUtlVector<DHooksManager *> g_pHooks;
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
using namespace SourceHook;
DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, bool post)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
this->callback = MakeHandler(setup->returnType);
this->hookid = 0;
this->remove_callback = remove_callback;
this->callback->offset = setup->offset;
this->callback->plugin_callback = setup->callback;
this->callback->returnFlag = setup->returnFlag;
this->callback->thisType = setup->thisType;
this->callback->post = post;
this->callback->hookType = setup->hookType;
this->callback->params = setup->params;
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
if(this->callback->hookType == HookType_Entity)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
this->callback->entity = gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
2013-08-16 05:53:38 +02:00
}
else
{
2013-08-19 17:07:25 +02:00
this->callback->entity = -1;
2013-08-16 05:53:38 +02:00
}
2013-08-19 17:07:25 +02:00
CProtoInfoBuilder protoInfo(ProtoInfo::CallConv_ThisCall);
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
for(int i = this->callback->params.Count() -1; i >= 0; i--)
{
protoInfo.AddParam(this->callback->params.Element(i).size, this->callback->params.Element(i).pass_type, this->callback->params.Element(i).flag, NULL, NULL, NULL, NULL);
}
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
if(this->callback->returnType == ReturnType_Void)
{
protoInfo.SetReturnType(0, SourceHook::PassInfo::PassType_Unknown, 0, NULL, NULL, NULL, NULL);
}
else
{
2013-08-20 04:33:44 +02:00
protoInfo.SetReturnType(sizeof(void *), SourceHook::PassInfo::PassType_Basic, setup->returnFlag, NULL, NULL, NULL, NULL);
2013-08-19 17:07:25 +02:00
}
HookManagerPubFunc hook = g_pHookManager->MakeHookMan(protoInfo, 0, this->callback->offset);
this->hookid = g_SHPtr->AddHook(g_PLID,ISourceHook::Hook_Normal, iface, 0, hook, this->callback, this->callback->post);
}
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
void CleanupHooks(IPluginContext *pContext)
{
for(int i = g_pHooks.Count() -1; i >= 0; i--)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
DHooksManager *manager = g_pHooks.Element(i);
if(pContext == NULL || pContext == manager->callback->plugin_callback->GetParentContext())
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
delete manager;
g_pHooks.Remove(i);
2013-08-16 05:53:38 +02:00
}
}
2013-08-19 17:07:25 +02:00
}
bool SetupHookManager(ISmmAPI *ismm)
{
g_pHookManager = static_cast<SourceHook::IHookManagerAutoGen *>(ismm->MetaFactory(MMIFACE_SH_HOOKMANAUTOGEN, NULL, NULL));
return g_pHookManager != NULL;
}
size_t GetParamTypeSize(HookParamType type)
{
return sizeof(void *);
}
SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type)
{
switch(type)
{
case HookParamType_Float:
2013-08-20 04:33:44 +02:00
return SourceHook::PassInfo::PassType_Float;
2013-08-21 02:18:50 +02:00
case HookParamType_Object:
return SourceHook::PassInfo::PassType_Object;
2013-08-19 17:07:25 +02:00
}
2013-08-20 04:33:44 +02:00
return SourceHook::PassInfo::PassType_Basic;
2013-08-19 17:07:25 +02:00
}
size_t GetStackArgsSize(DHooksCallback *dg)
{
size_t res = 0;
for(int i = dg->params.Count() - 1; i >= 0; i--)
{
res += dg->params.Element(i).size;
}
return res;
}
HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t argStackSize)
{
HookParamsStruct *res = new HookParamsStruct();
res->dg = dg;
res->orgParams = (void **)malloc(argStackSize);
res->newParams = (void **)malloc(argStackSize);
2013-08-20 04:33:44 +02:00
res->isChanged = (bool *)malloc(dg->params.Count() * sizeof(bool));
2013-08-19 17:07:25 +02:00
memcpy(res->orgParams, argStack, argStackSize);
for(int i = 0; i < dg->params.Count(); i++)
{
res->newParams[i] = NULL;
2013-08-20 04:33:44 +02:00
res->isChanged[i] = false;
2013-08-19 17:07:25 +02:00
}
return res;
}
HookReturnStruct *GetReturnStruct(DHooksCallback *dg, const void *result)
{
HookReturnStruct *res = new HookReturnStruct();
res->isChanged = false;
res->type = dg->returnType;
2013-08-21 04:21:29 +02:00
res->newResult = malloc(sizeof(void *));
res->orgResult = malloc(sizeof(void *));
2013-08-20 04:33:44 +02:00
if(result && dg->post)
{
switch(dg->returnType)
{
//ReturnType_String,
//ReturnType_Vector,
case ReturnType_Int:
2013-08-21 04:21:29 +02:00
*(int *)res->orgResult = *(int *)result;
2013-08-21 02:18:50 +02:00
case ReturnType_Bool:
2013-08-21 04:21:29 +02:00
*(int *)res->orgResult = *(bool *)result;
2013-08-20 04:33:44 +02:00
break;
case ReturnType_Float:
2013-08-21 04:21:29 +02:00
*(float *)res->orgResult = *(float *)result;
2013-08-21 02:18:50 +02:00
break;
2013-08-20 04:33:44 +02:00
default:
2013-08-21 04:21:29 +02:00
res->orgResult = *(void **)result;
2013-08-21 02:18:50 +02:00
break;
2013-08-20 04:33:44 +02:00
}
}
else
{
res->orgResult = NULL;
}
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
return res;
}
cell_t GetThisPtr(void *iface, ThisPointerType type)
{
if(ThisPointer_CBaseEntity)
{
return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
}
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
return (cell_t)iface;
2013-08-16 05:53:38 +02:00
}
2013-08-20 04:33:44 +02:00
2013-08-19 17:07:25 +02:00
#ifndef __linux__
void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep)
2013-08-20 04:33:44 +02:00
#else
void *Callback(DHooksCallback *dg, void **argStack)
#endif
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL;
Handle_t rHndl;
Handle_t pHndl;
2013-08-16 05:53:38 +02:00
2013-08-20 04:33:44 +02:00
#ifndef __linux__
2013-08-19 17:07:25 +02:00
*argsizep = GetStackArgsSize(dg);
2013-08-20 04:33:44 +02:00
#else
size_t argsize = GetStackArgsSize(dg);
#endif
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
}
if(dg->returnType != ReturnType_Void)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
returnStruct = GetReturnStruct(dg, g_SHPtr->GetOrigRet());
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!rHndl)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
if(returnStruct)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
delete returnStruct;
2013-08-16 05:53:38 +02:00
}
2013-08-19 17:07:25 +02:00
g_SHPtr->SetRes(MRES_IGNORED);
return 0;
2013-08-16 05:53:38 +02:00
}
2013-08-19 17:07:25 +02:00
dg->plugin_callback->PushCell(rHndl);
2013-08-16 05:53:38 +02:00
}
2013-08-20 04:33:44 +02:00
#ifndef __linux__
2013-08-19 17:07:25 +02:00
if(*argsizep > 0)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
paramStruct = GetParamStruct(dg, argStack, *argsizep);
2013-08-20 04:33:44 +02:00
#else
if(argsize > 0)
{
paramStruct = GetParamStruct(dg, argStack, argsize);
#endif
2013-08-19 17:07:25 +02:00
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!pHndl)
{
if(returnStruct)
{
delete returnStruct;
}
if(paramStruct)
{
delete paramStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return 0;
}
dg->plugin_callback->PushCell(pHndl);
2013-08-16 05:53:38 +02:00
}
2013-08-19 17:07:25 +02:00
cell_t result = (cell_t)MRES_Ignored;
dg->plugin_callback->Execute(&result);
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
void *ret = g_SHPtr->GetOverrideRetPtr();
switch((MRESReturn)result)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
case MRES_Handled:
case MRES_ChangedHandled:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
2013-08-20 04:33:44 +02:00
ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
2013-08-19 17:07:25 +02:00
break;
case MRES_ChangedOverride:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
2013-08-20 04:33:44 +02:00
ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
2013-08-19 17:07:25 +02:00
if(dg->returnType != ReturnType_Void)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
if(returnStruct->isChanged)
{
2013-08-21 04:21:29 +02:00
*(void **)ret = returnStruct->newResult;
2013-08-19 17:07:25 +02:00
}
2013-08-16 05:53:38 +02:00
}
2013-08-19 17:07:25 +02:00
break;
case MRES_Override:
g_SHPtr->SetRes(MRES_OVERRIDE);
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
2013-08-21 02:18:50 +02:00
{
2013-08-21 04:21:29 +02:00
*(void **)ret = returnStruct->newResult;
2013-08-19 17:07:25 +02:00
}
else if(dg->post)
{
2013-08-21 04:21:29 +02:00
*(void **)ret = returnStruct->orgResult;
2013-08-19 17:07:25 +02:00
}
}
break;
case MRES_Supercede:
g_SHPtr->SetRes(MRES_SUPERCEDE);
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
2013-08-21 02:18:50 +02:00
{
2013-08-21 04:21:29 +02:00
*(void **)ret = returnStruct->newResult;
2013-08-19 17:07:25 +02:00
}
else if(dg->post)
{
2013-08-21 04:21:29 +02:00
*(void **)ret = returnStruct->orgResult;
2013-08-19 17:07:25 +02:00
}
}
break;
default:
g_SHPtr->SetRes(MRES_IGNORED);
break;
2013-08-16 05:53:38 +02:00
}
2013-08-19 17:07:25 +02:00
HandleSecurity sec(dg->plugin_callback->GetParentContext()->GetIdentity(), myself->GetIdentity());
2013-08-16 05:53:38 +02:00
2013-08-19 17:07:25 +02:00
if(returnStruct)
{
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
handlesys->FreeHandle(pHndl, &sec);
}
2013-08-16 05:53:38 +02:00
2013-08-21 04:21:29 +02:00
if(dg->returnType != ReturnType_Void)
{
return NULL;
}
2013-08-20 04:33:44 +02:00
return ret;
2013-08-21 02:18:50 +02:00
}