sm-ext-dhooks2/vhook.cpp
Peace-Maker 88451023fb Fix changing of charptr and vectorptr returns and parameters
The new buffer/vector was freed before the old function was called with the new parameters
or the return value could be used by the called. This caused undefined behavior which seemed
to be fine before, where free didn't change the user-payload. free does change the user data now,
causing the changed values to be garbage.

Wait until the next frame before deleting the newly allocated buffers/vectors, so the original code had a chance
to use the live pointers. AddFrameAction might be a bad choice if our hook happens before the game ticks, but
we can tackle that problem when it happens ;)
2019-08-03 18:26:53 +02:00

1009 lines
28 KiB
C++

#include "vhook.h"
#include "vfunc_call.h"
#include "util.h"
#include <macro-assembler-x86.h>
SourceHook::IHookManagerAutoGen *g_pHookManager = NULL;
ke::Vector<DHooksManager *> g_pHooks;
using namespace SourceHook;
using namespace sp;
#ifdef WIN32
#define OBJECT_OFFSET sizeof(void *)
#else
#define OBJECT_OFFSET (sizeof(void *)*2)
#endif
#ifndef WIN32
void *GenerateThunk(ReturnType type)
{
sp::MacroAssembler masm;
static const size_t kStackNeeded = (2) * 4; // 2 args max
static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8;
masm.push(ebp);
masm.movl(ebp, esp);
masm.subl(esp, kReserve);
if (type != ReturnType_String && type != ReturnType_Vector)
{
masm.lea(eax, Operand(ebp, 12)); // grab the incoming caller argument vector
masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
masm.movl(eax, Operand(ebp, 8)); // grab the |this|
masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
}
else
{
masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
masm.movl(eax, Operand(ebp, 12)); // grab the |this|
masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
}
if (type == ReturnType_Float)
{
masm.call(ExternalAddress((void *)Callback_float));
}
else if (type == ReturnType_Vector)
{
masm.call(ExternalAddress((void *)Callback_vector));
}
else if (type == ReturnType_String)
{
masm.call(ExternalAddress((void *)Callback_stringt));
}
else
{
masm.call(ExternalAddress((void *)Callback));
}
masm.addl(esp, kReserve);
masm.pop(ebp); // restore ebp
masm.ret();
void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length());
masm.emitToExecutableMemory(base);
return base;
}
#else
// HUGE THANKS TO BAILOPAN (dvander)!
void *GenerateThunk(ReturnType type)
{
sp::MacroAssembler masm;
static const size_t kStackNeeded = (3 + 1) * 4; // 3 args max, 1 locals max
static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8;
masm.push(ebp);
masm.movl(ebp, esp);
masm.subl(esp, kReserve);
masm.lea(eax, Operand(esp, 3 * 4)); // ptr to 2nd var after argument space
masm.movl(Operand(esp, 2 * 4), eax); // set the ptr as the third argument
masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
masm.movl(Operand(esp, 0 * 4), ecx); // set |this| as the 1st argument
if (type == ReturnType_Float)
{
masm.call(ExternalAddress(Callback_float));
}
else if (type == ReturnType_Vector)
{
masm.call(ExternalAddress(Callback_vector));
}
else
{
masm.call(ExternalAddress(Callback));
}
masm.movl(ecx, Operand(esp, 3 * 4));
masm.addl(esp, kReserve);
masm.pop(ebp); // restore ebp
masm.pop(edx); // grab return address in edx
masm.addl(esp, ecx); // remove arguments
masm.jmp(edx); // return to caller
void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length());
masm.emitToExecutableMemory(base);
return base;
}
#endif
DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, IPluginFunction *plugincb, bool post)
{
this->callback = MakeHandler(setup->returnType);
this->hookid = 0;
this->remove_callback = remove_callback;
this->callback->offset = setup->offset;
this->callback->plugin_callback = plugincb;
this->callback->returnFlag = setup->returnFlag;
this->callback->thisType = setup->thisType;
this->callback->post = post;
this->callback->hookType = setup->hookType;
this->callback->params = setup->params;
this->addr = 0;
if(this->callback->hookType == HookType_Entity)
{
this->callback->entity = gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
}
else
{
if(this->callback->hookType == HookType_Raw)
{
this->addr = (intptr_t)iface;
}
this->callback->entity = -1;
}
CProtoInfoBuilder protoInfo(ProtoInfo::CallConv_ThisCall);
for(int i = this->callback->params.size() -1; i >= 0; i--)
{
protoInfo.AddParam(this->callback->params.at(i).size, this->callback->params.at(i).pass_type, PASSFLAG_BYVAL, NULL, NULL, NULL, NULL);//This seems like we need to do something about it at some point...
}
if(this->callback->returnType == ReturnType_Void)
{
protoInfo.SetReturnType(0, SourceHook::PassInfo::PassType_Unknown, 0, NULL, NULL, NULL, NULL);
}
else if(this->callback->returnType == ReturnType_Float)
{
protoInfo.SetReturnType(sizeof(float), SourceHook::PassInfo::PassType_Float, setup->returnFlag, NULL, NULL, NULL, NULL);
}
else if(this->callback->returnType == ReturnType_String)
{
protoInfo.SetReturnType(sizeof(string_t), SourceHook::PassInfo::PassType_Object, setup->returnFlag, NULL, NULL, NULL, NULL);//We have to be 4 really... or else RIP
}
else if(this->callback->returnType == ReturnType_Vector)
{
protoInfo.SetReturnType(sizeof(SDKVector), SourceHook::PassInfo::PassType_Object, setup->returnFlag, NULL, NULL, NULL, NULL);
}
else
{
protoInfo.SetReturnType(sizeof(void *), SourceHook::PassInfo::PassType_Basic, setup->returnFlag, NULL, NULL, NULL, NULL);
}
this->pManager = g_pHookManager->MakeHookMan(protoInfo, 0, this->callback->offset);
this->hookid = g_SHPtr->AddHook(g_PLID,ISourceHook::Hook_Normal, iface, 0, this->pManager, this->callback, this->callback->post);
}
void CleanupHooks(IPluginContext *pContext)
{
for(int i = g_pHooks.length() -1; i >= 0; i--)
{
DHooksManager *manager = g_pHooks.at(i);
if(pContext == NULL || pContext == manager->callback->plugin_callback->GetParentRuntime()->GetDefaultContext())
{
delete manager;
g_pHooks.remove(i);
}
}
}
bool SetupHookManager(ISmmAPI *ismm)
{
g_pHookManager = static_cast<SourceHook::IHookManagerAutoGen *>(ismm->MetaFactory(MMIFACE_SH_HOOKMANAUTOGEN, NULL, NULL));
return g_pHookManager != NULL;
}
SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type)
{
switch(type)
{
case HookParamType_Float:
return SourceHook::PassInfo::PassType_Float;
case HookParamType_Object:
return SourceHook::PassInfo::PassType_Object;
}
return SourceHook::PassInfo::PassType_Basic;
}
size_t GetStackArgsSize(DHooksCallback *dg)
{
size_t res = GetParamsSize(dg);
#ifdef WIN32
if(dg->returnType == ReturnType_Vector)//Account for result vector ptr.
#else
if(dg->returnType == ReturnType_Vector || dg->returnType == ReturnType_String)
#endif
{
res += OBJECT_OFFSET;
}
return res;
}
HookReturnStruct::~HookReturnStruct()
{
if (this->type == ReturnType_String || this->type == ReturnType_Int || this->type == ReturnType_Bool || this->type == ReturnType_Float || this->type == ReturnType_Vector)
{
free(this->newResult);
free(this->orgResult);
}
}
HookParamsStruct::~HookParamsStruct()
{
if (this->orgParams != NULL)
{
free(this->orgParams);
}
if (this->isChanged != NULL)
{
free(this->isChanged);
}
if (this->newParams != NULL)
{
free(this->newParams);
}
}
HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t argStackSize)
{
HookParamsStruct *params = new HookParamsStruct();
params->dg = dg;
#ifdef WIN32
if(dg->returnType != ReturnType_Vector)
#else
if(dg->returnType != ReturnType_Vector && dg->returnType != ReturnType_String)
#endif
{
params->orgParams = (void **)malloc(argStackSize);
memcpy(params->orgParams, argStack, argStackSize);
}
else //Offset result ptr
{
params->orgParams = (void **)malloc(argStackSize-OBJECT_OFFSET);
memcpy(params->orgParams, argStack+OBJECT_OFFSET, argStackSize-OBJECT_OFFSET);
}
size_t paramsSize = GetParamsSize(dg);
params->newParams = (void **)malloc(paramsSize);
params->isChanged = (bool *)malloc(dg->params.size() * sizeof(bool));
for (unsigned int i = 0; i < dg->params.size(); i++)
{
*(void **)((intptr_t)params->newParams + GetParamOffset(params, i)) = NULL;
params->isChanged[i] = false;
}
return params;
}
HookReturnStruct *GetReturnStruct(DHooksCallback *dg)
{
HookReturnStruct *res = new HookReturnStruct();
res->isChanged = false;
res->type = dg->returnType;
res->orgResult = NULL;
res->newResult = NULL;
if(g_SHPtr->GetOrigRet() && dg->post)
{
switch(dg->returnType)
{
case ReturnType_String:
res->orgResult = malloc(sizeof(string_t));
res->newResult = malloc(sizeof(string_t));
*(string_t *)res->orgResult = META_RESULT_ORIG_RET(string_t);
break;
case ReturnType_Int:
res->orgResult = malloc(sizeof(int));
res->newResult = malloc(sizeof(int));
*(int *)res->orgResult = META_RESULT_ORIG_RET(int);
break;
case ReturnType_Bool:
res->orgResult = malloc(sizeof(bool));
res->newResult = malloc(sizeof(bool));
*(bool *)res->orgResult = META_RESULT_ORIG_RET(bool);
break;
case ReturnType_Float:
res->orgResult = malloc(sizeof(float));
res->newResult = malloc(sizeof(float));
*(float *)res->orgResult = META_RESULT_ORIG_RET(float);
break;
case ReturnType_Vector:
{
res->orgResult = malloc(sizeof(SDKVector));
res->newResult = malloc(sizeof(SDKVector));
SDKVector vec = META_RESULT_ORIG_RET(SDKVector);
*(SDKVector *)res->orgResult = vec;
break;
}
default:
res->orgResult = META_RESULT_ORIG_RET(void *);
break;
}
}
else
{
switch(dg->returnType)
{
case ReturnType_String:
res->orgResult = malloc(sizeof(string_t));
res->newResult = malloc(sizeof(string_t));
*(string_t *)res->orgResult = NULL_STRING;
break;
case ReturnType_Vector:
res->orgResult = malloc(sizeof(SDKVector));
res->newResult = malloc(sizeof(SDKVector));
*(SDKVector *)res->orgResult = SDKVector();
break;
case ReturnType_Int:
res->orgResult = malloc(sizeof(int));
res->newResult = malloc(sizeof(int));
*(int *)res->orgResult = 0;
break;
case ReturnType_Bool:
res->orgResult = malloc(sizeof(bool));
res->newResult = malloc(sizeof(bool));
*(bool *)res->orgResult = false;
break;
case ReturnType_Float:
res->orgResult = malloc(sizeof(float));
res->newResult = malloc(sizeof(float));
*(float *)res->orgResult = 0.0;
break;
}
}
return res;
}
cell_t GetThisPtr(void *iface, ThisPointerType type)
{
if(type == ThisPointer_CBaseEntity)
{
if (!iface)
return -1;
return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
}
return (cell_t)iface;
}
#ifdef WIN32
void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep)
#else
void *Callback(DHooksCallback *dg, void **argStack)
#endif
{
HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL;
Handle_t rHndl;
Handle_t pHndl;
#ifdef WIN32
*argsizep = GetStackArgsSize(dg);
#else
size_t argsize = GetStackArgsSize(dg);
#endif
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
}
if(dg->returnType != ReturnType_Void)
{
returnStruct = GetReturnStruct(dg);
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!rHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(rHndl);
}
#ifdef WIN32
if(*argsizep > 0)
{
paramStruct = GetParamStruct(dg, argStack, *argsizep);
#else
if(argsize > 0)
{
paramStruct = GetParamStruct(dg, argStack, argsize);
#endif
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!pHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity());
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
delete paramStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(pHndl);
}
cell_t result = (cell_t)MRES_Ignored;
META_RES mres = MRES_IGNORED;
dg->plugin_callback->Execute(&result);
void *ret = g_SHPtr->GetOverrideRetPtr();
switch((MRESReturn)result)
{
case MRES_Handled:
case MRES_ChangedHandled:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
ret = CallVFunction<void *>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
if(dg->returnType == ReturnType_String || dg->returnType == ReturnType_Int || dg->returnType == ReturnType_Bool)
{
ret = *(void **)returnStruct->newResult;
}
else
{
ret = returnStruct->newResult;
}
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
break;
}
}
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
CallVFunction<void *>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_OVERRIDE);
mres = MRES_OVERRIDE;
if(dg->returnType == ReturnType_String || dg->returnType == ReturnType_Int || dg->returnType == ReturnType_Bool)
{
ret = *(void **)returnStruct->newResult;
}
else
{
ret = returnStruct->newResult;
}
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
case MRES_Supercede:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
if(dg->returnType == ReturnType_String || dg->returnType == ReturnType_Int || dg->returnType == ReturnType_Bool)
{
ret = *(void **)returnStruct->newResult;
}
else
{
ret = returnStruct->newResult;
}
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
else
{
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
}
break;
default:
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
break;
}
HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity());
if(returnStruct)
{
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
handlesys->FreeHandle(pHndl, &sec);
}
if(dg->returnType == ReturnType_Void || mres <= MRES_HANDLED)
{
return NULL;
}
return ret;
}
#ifdef WIN32
float Callback_float(DHooksCallback *dg, void **argStack, size_t *argsizep)
#else
float Callback_float(DHooksCallback *dg, void **argStack)
#endif
{
HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL;
Handle_t rHndl;
Handle_t pHndl;
#ifdef WIN32
*argsizep = GetStackArgsSize(dg);
#else
size_t argsize = GetStackArgsSize(dg);
#endif
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
}
returnStruct = GetReturnStruct(dg);
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!rHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return 0.0;
}
dg->plugin_callback->PushCell(rHndl);
#ifdef WIN32
if(*argsizep > 0)
{
paramStruct = GetParamStruct(dg, argStack, *argsizep);
#else
if(argsize > 0)
{
paramStruct = GetParamStruct(dg, argStack, argsize);
#endif
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!pHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
if(paramStruct)
{
delete paramStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return 0.0;
}
dg->plugin_callback->PushCell(pHndl);
}
cell_t result = (cell_t)MRES_Ignored;
META_RES mres = MRES_IGNORED;
dg->plugin_callback->Execute(&result);
void *ret = g_SHPtr->GetOverrideRetPtr();
switch((MRESReturn)result)
{
case MRES_Handled:
case MRES_ChangedHandled:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*(float *)ret = CallVFunction<float>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
*(float *)ret = *(float *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
break;
}
}
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
CallVFunction<float>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_OVERRIDE);
mres = MRES_OVERRIDE;
*(float *)ret = *(float *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
case MRES_Supercede:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*(float *)ret = *(float *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
default:
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
break;
}
HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity());
if(returnStruct)
{
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
handlesys->FreeHandle(pHndl, &sec);
}
if(dg->returnType == ReturnType_Void || mres <= MRES_HANDLED)
{
return 0.0;
}
return *(float *)ret;
}
#ifdef WIN32
SDKVector *Callback_vector(DHooksCallback *dg, void **argStack, size_t *argsizep)
#else
SDKVector *Callback_vector(DHooksCallback *dg, void **argStack)
#endif
{
SDKVector *vec_result = (SDKVector *)argStack[0]; // Save the result
HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL;
Handle_t rHndl;
Handle_t pHndl;
#ifdef WIN32
*argsizep = GetStackArgsSize(dg);
#else
size_t argsize = GetStackArgsSize(dg);
#endif
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
}
returnStruct = GetReturnStruct(dg);
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!rHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(rHndl);
#ifdef WIN32
if(*argsizep > 0)
{
paramStruct = GetParamStruct(dg, argStack, *argsizep);
#else
if(argsize > 0)
{
paramStruct = GetParamStruct(dg, argStack, argsize);
#endif
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!pHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
if(paramStruct)
{
delete paramStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(pHndl);
}
cell_t result = (cell_t)MRES_Ignored;
META_RES mres = MRES_IGNORED;
dg->plugin_callback->Execute(&result);
void *ret = g_SHPtr->GetOverrideRetPtr();
ret = vec_result;
switch((MRESReturn)result)
{
case MRES_Handled:
case MRES_ChangedHandled:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*vec_result = CallVFunction<SDKVector>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
*vec_result = **(SDKVector **)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
break;
}
}
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
CallVFunction<SDKVector>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_OVERRIDE);
mres = MRES_OVERRIDE;
*vec_result = **(SDKVector **)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
case MRES_Supercede:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*vec_result = **(SDKVector **)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
default:
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
break;
}
HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity());
if(returnStruct)
{
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
handlesys->FreeHandle(pHndl, &sec);
}
if(dg->returnType == ReturnType_Void || mres <= MRES_HANDLED)
{
vec_result->x = 0;
vec_result->y = 0;
vec_result->z = 0;
return vec_result;
}
return vec_result;
}
#ifndef WIN32
string_t *Callback_stringt(DHooksCallback *dg, void **argStack)
{
string_t *string_result = (string_t *)argStack[0]; // Save the result
HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL;
Handle_t rHndl;
Handle_t pHndl;
size_t argsize = GetStackArgsSize(dg);
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
}
returnStruct = GetReturnStruct(dg);
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!rHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(rHndl);
if(argsize > 0)
{
paramStruct = GetParamStruct(dg, argStack, argsize);
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!pHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
if(paramStruct)
{
delete paramStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(pHndl);
}
cell_t result = (cell_t)MRES_Ignored;
META_RES mres = MRES_IGNORED;
dg->plugin_callback->Execute(&result);
void *ret = g_SHPtr->GetOverrideRetPtr();
ret = string_result;
switch((MRESReturn)result)
{
case MRES_Handled:
case MRES_ChangedHandled:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*string_result = CallVFunction<string_t>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
*string_result = *(string_t *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
break;
}
}
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
CallVFunction<SDKVector>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_OVERRIDE);
mres = MRES_OVERRIDE;
*string_result = *(string_t *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
case MRES_Supercede:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*string_result = *(string_t *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
default:
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
break;
}
HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity());
if(returnStruct)
{
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
handlesys->FreeHandle(pHndl, &sec);
}
if(dg->returnType == ReturnType_Void || mres <= MRES_HANDLED)
{
*string_result = NULL_STRING;
return string_result;
}
return string_result;
}
#endif