diff --git a/Makefile b/Makefile
index ba8cbf6..6ba8f57 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ PROJECT = dhooks
#Uncomment for Metamod: Source enabled extension
USEMETA = true
-OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp $(SMSDK)/public/jit/x86/assembler-x86.cpp listeners.cpp natives.cpp vfunc_call.cpp
+OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp $(SMSDK)/public/jit/x86/assembler-x86.cpp listeners.cpp natives.cpp
##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
diff --git a/msvc10/sdk.vcxproj b/msvc10/sdk.vcxproj
index c7cf75e..63c52c2 100644
--- a/msvc10/sdk.vcxproj
+++ b/msvc10/sdk.vcxproj
@@ -886,7 +886,6 @@
-
diff --git a/msvc10/sdk.vcxproj.filters b/msvc10/sdk.vcxproj.filters
index a218cab..4da95fe 100644
--- a/msvc10/sdk.vcxproj.filters
+++ b/msvc10/sdk.vcxproj.filters
@@ -11,7 +11,6 @@
-
diff --git a/natives.cpp b/natives.cpp
index 9b4b11c..9029f2d 100644
--- a/natives.cpp
+++ b/natives.cpp
@@ -947,6 +947,58 @@ cell_t Native_GetParamObjectPtrString(IPluginContext *pContext, const cell_t *pa
}
return 1;
}
+
+// DHookGetReturnVector(Handle:hReturn, Float:vec[3])
+cell_t Native_GetReturnVector(IPluginContext *pContext, const cell_t *params)
+{
+ HookReturnStruct *returnStruct;
+
+ if(!GetHandleIfValidOrError(g_HookReturnHandle, (void **)&returnStruct, pContext, params[1]))
+ {
+ return 0;
+ }
+
+ cell_t *buffer;
+ pContext->LocalToPhysAddr(params[2], &buffer);
+
+ if(returnStruct->type == ReturnType_Vector || returnStruct->type == ReturnType_VectorPtr)
+ {
+ buffer[0] = sp_ftoc((*(Vector **)returnStruct->orgResult)->x);
+ buffer[1] = sp_ftoc((*(Vector **)returnStruct->orgResult)->y);
+ buffer[2] = sp_ftoc((*(Vector **)returnStruct->orgResult)->z);
+
+ return 1;
+ }
+ return pContext->ThrowNativeError("Return type is not a vector type");
+}
+
+//DHookSetReturnVector(Handle:hReturn, Float:vec[3])
+cell_t Native_SetReturnVector(IPluginContext *pContext, const cell_t *params)
+{
+ HookReturnStruct *returnStruct;
+
+ if(!GetHandleIfValidOrError(g_HookReturnHandle, (void **)&returnStruct, pContext, params[1]))
+ {
+ return 0;
+ }
+
+ cell_t *buffer;
+ pContext->LocalToPhysAddr(params[2], &buffer);
+
+ if(returnStruct->type == ReturnType_Vector || returnStruct->type == ReturnType_VectorPtr)
+ {
+ if(*(Vector **)returnStruct->newResult != NULL)
+ {
+ delete *(Vector **)returnStruct->newResult;
+ }
+
+ *(Vector **)returnStruct->newResult = new Vector(sp_ctof(buffer[0]), sp_ctof(buffer[1]), sp_ctof(buffer[2]));
+
+ return 1;
+ }
+ return pContext->ThrowNativeError("Return type is not a vector type");
+}
+
//native bool:DHookIsNullParam(Handle:hParams, num);
cell_t Native_IsNullParam(IPluginContext *pContext, const cell_t *params)
{
@@ -986,8 +1038,8 @@ sp_nativeinfo_t g_Natives[] =
{"DHookSetReturn", Native_SetReturn},
{"DHookSetParam", Native_SetParam},
{"DHookGetParamVector", Native_GetParamVector},
- /*{"DHookGetReturnVector", Native_GetReturnVector},
- {"DHookSetReturnVector", Native_SetReturnVector},*/
+ {"DHookGetReturnVector", Native_GetReturnVector},
+ {"DHookSetReturnVector", Native_SetReturnVector},
{"DHookSetParamVector", Native_SetParamVector},
{"DHookGetParamString", Native_GetParamString},
{"DHookGetReturnString", Native_GetReturnString},
diff --git a/vfunc_call.h b/vfunc_call.h
index 28a11fb..07ca195 100644
--- a/vfunc_call.h
+++ b/vfunc_call.h
@@ -2,6 +2,134 @@
#define _INCLUDE_VFUNC_CALL_H_
#include "vhook.h"
+#include "extension.h"
+
+#define PARAMINFO_SWITCH(passType) \
+ paramInfo[i].flags = dg->params.Element(i).flag; \
+ paramInfo[i].size = dg->params.Element(i).size; \
+ paramInfo[i].type = passType;
+
+#define VSTK_PARAM_SWITCH(paramType) \
+ if(paramStruct->isChanged[i]) \
+ { \
+ *(paramType *)vptr = (paramType)(paramStruct->newParams[i]); \
+ } \
+ else \
+ { \
+ *(paramType *)vptr = (paramType)(paramStruct->orgParams[i]); \
+ } \
+ if(i + 1 != dg->params.Count()) \
+ { \
+ vptr += dg->params.Element(i).size; \
+ } \
+ break;
+#define VSTK_PARAM_SWITCH_FLOAT() \
+ if(paramStruct->isChanged[i]) \
+ { \
+ *(float *)vptr = *(float *)(paramStruct->newParams[i]); \
+ } \
+ else \
+ { \
+ *(float *)vptr = *(float *)(paramStruct->orgParams[i]); \
+ } \
+ if(i + 1 != dg->params.Count()) \
+ { \
+ vptr += dg->params.Element(i).size; \
+ } \
+ break;
+
+template
+T CallVFunction(DHooksCallback *dg, HookParamsStruct *paramStruct, void *iface)
+{
+ SourceMod::PassInfo *paramInfo = NULL;
+ SourceMod::PassInfo returnInfo;
+
+ if(dg->returnType != ReturnType_Void)
+ {
+ returnInfo.flags = dg->returnFlag;
+ returnInfo.size = sizeof(T);
+ if( dg->returnType != ReturnType_Vector)
+ {
+ returnInfo.type = PassType_Basic;
+ }
+ else
+ {
+ returnInfo.type = PassType_Object;
+ }
+ }
+
+ ICallWrapper *pCall;
+
+ size_t size = GetStackArgsSize(dg);
+
+ unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size);
+ unsigned char *vptr = vstk;
+
+ *(void **)vptr = iface;
+
+ if(paramStruct)
+ {
+ vptr += sizeof(void *);
+ paramInfo = (SourceMod::PassInfo *)malloc(sizeof(SourceMod::PassInfo) * dg->params.Count());
+ for(int i = 0; i < dg->params.Count(); i++)
+ {
+ switch(dg->params.Element(i).type)
+ {
+ case HookParamType_Int:
+ PARAMINFO_SWITCH(PassType_Basic);
+ VSTK_PARAM_SWITCH(int);
+ case HookParamType_Bool:
+ PARAMINFO_SWITCH(PassType_Basic);
+ VSTK_PARAM_SWITCH(cell_t);
+ case HookParamType_Float:
+ PARAMINFO_SWITCH(PassType_Float);
+ VSTK_PARAM_SWITCH_FLOAT();
+ case HookParamType_String:
+ PARAMINFO_SWITCH(PassType_Object);
+ VSTK_PARAM_SWITCH(int);
+ case HookParamType_StringPtr:
+ PARAMINFO_SWITCH(PassType_Basic);
+ VSTK_PARAM_SWITCH(string_t *);
+ case HookParamType_CharPtr:
+ PARAMINFO_SWITCH(PassType_Basic);
+ VSTK_PARAM_SWITCH(char *);
+ case HookParamType_VectorPtr:
+ PARAMINFO_SWITCH(PassType_Basic);
+ VSTK_PARAM_SWITCH(Vector *);
+ case HookParamType_CBaseEntity:
+ PARAMINFO_SWITCH(PassType_Basic);
+ VSTK_PARAM_SWITCH(CBaseEntity *);
+ case HookParamType_Edict:
+ PARAMINFO_SWITCH(PassType_Basic);
+ VSTK_PARAM_SWITCH(edict_t *);
+ default:
+ PARAMINFO_SWITCH(PassType_Basic);
+ VSTK_PARAM_SWITCH(void *);
+ }
+ }
+ }
+
+ T ret = 0;
+ if(dg->returnType == ReturnType_Void)
+ {
+ pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, NULL, paramInfo, dg->params.Count());
+ pCall->Execute(vstk, NULL);
+ }
+ else
+ {
+ pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, &returnInfo, paramInfo, dg->params.Count());
+ pCall->Execute(vstk, &ret);
+ }
+
+ pCall->Destroy();
+ free(vstk);
+
+ if(paramInfo != NULL)
+ {
+ free(paramInfo);
+ }
+
+ return ret;
+}
-void *CallVFunction(DHooksCallback *dg, HookParamsStruct *paramStruct, void *iface);
#endif
diff --git a/vhook.cpp b/vhook.cpp
index 08f1378..0c9a6f7 100644
--- a/vhook.cpp
+++ b/vhook.cpp
@@ -53,6 +53,10 @@ DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *rem
{
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(Vector), 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);
@@ -105,16 +109,29 @@ size_t GetStackArgsSize(DHooksCallback *dg)
{
res += dg->params.Element(i).size;
}
+
+ if(dg->returnType == ReturnType_Vector)//Account for result vector ptr.
+ {
+ res += sizeof(void *);
+ }
return res;
}
HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t argStackSize)
{
HookParamsStruct *params = new HookParamsStruct();
params->dg = dg;
- params->orgParams = (void **)malloc(argStackSize);
+ if(dg->returnType != ReturnType_Vector)
+ {
+ params->orgParams = (void **)malloc(argStackSize);
+ memcpy(params->orgParams, argStack, argStackSize);
+ }
+ else //Offset result ptr
+ {
+ params->orgParams = (void **)malloc(argStackSize-sizeof(void *));
+ memcpy(params->orgParams, argStack+sizeof(void *), argStackSize);
+ }
params->newParams = (void **)malloc(dg->params.Count() * sizeof(void *));
params->isChanged = (bool *)malloc(dg->params.Count() * sizeof(bool));
- memcpy(params->orgParams, argStack, argStackSize);
for(int i = 0; i < dg->params.Count(); i++)
{
params->newParams[i] = NULL;
@@ -128,6 +145,7 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg)
res->isChanged = false;
res->type = dg->returnType;
res->newResult = malloc(sizeof(void *));
+ *(void **)res->newResult = NULL;
res->orgResult = malloc(sizeof(void *));
if(g_SHPtr->GetOrigRet() && dg->post)
@@ -137,7 +155,6 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg)
case ReturnType_String:
*(string_t *)res->orgResult = META_RESULT_ORIG_RET(string_t);
break;
- //ReturnType_Vector,
case ReturnType_Int:
*(int *)res->orgResult = META_RESULT_ORIG_RET(int);
break;
@@ -147,7 +164,14 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg)
case ReturnType_Float:
*(float *)res->orgResult = META_RESULT_ORIG_RET(float);
break;
+ case ReturnType_Vector:
+ {
+ Vector vec = META_RESULT_ORIG_RET(Vector);
+ *(Vector **)res->orgResult = new Vector(vec);
+ break;
+ }
default:
+ *(void **)res->orgResult = malloc(sizeof(void **));
*(void **)res->orgResult = META_RESULT_ORIG_RET(void *);
break;
}
@@ -264,7 +288,7 @@ void *Callback(DHooksCallback *dg, void **argStack)
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
- ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
+ ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
@@ -284,7 +308,7 @@ void *Callback(DHooksCallback *dg, void **argStack)
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
- CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
+ CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
@@ -418,7 +442,7 @@ void *Callback_float(DHooksCallback *dg, void **argStack)
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
- ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
+ *(float *)ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
@@ -438,7 +462,7 @@ void *Callback_float(DHooksCallback *dg, void **argStack)
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
- CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
+ CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
@@ -497,3 +521,160 @@ void *Callback_float(DHooksCallback *dg, void **argStack)
}
return *(float *)ret;
}
+Vector *Callback_vector(DHooksCallback *dg, void **argStack, size_t *argsizep)
+{
+ Vector *vec_result = (Vector *)argStack[0]; // Save the result
+
+ HookReturnStruct *returnStruct = NULL;
+ HookParamsStruct *paramStruct = NULL;
+ Handle_t rHndl;
+ Handle_t pHndl;
+
+ #ifndef __linux__
+ *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);
+
+ #ifndef __linux__
+ 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(dg, paramStruct, g_SHPtr->GetIfacePtr());
+ break;
+ case MRES_ChangedOverride:
+ if(dg->returnType != ReturnType_Void)
+ {
+ if(returnStruct->isChanged)
+ {
+ *vec_result = **(Vector **)returnStruct->newResult;
+ }
+ else //Throw an error if no override was set
+ {
+ g_SHPtr->SetRes(MRES_IGNORED);
+ mres = MRES_IGNORED;
+ dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Tried to override return value without return value being set");
+ break;
+ }
+ }
+ g_SHPtr->DoRecall();
+ g_SHPtr->SetRes(MRES_SUPERCEDE);
+ mres = MRES_SUPERCEDE;
+ CallVFunction(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 = **(Vector **)returnStruct->newResult;
+ }
+ else //Throw an error if no override was set
+ {
+ g_SHPtr->SetRes(MRES_IGNORED);
+ mres = MRES_IGNORED;
+ dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("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 = **(Vector **)returnStruct->newResult;
+ }
+ else //Throw an error if no override was set
+ {
+ g_SHPtr->SetRes(MRES_IGNORED);
+ mres = MRES_IGNORED;
+ dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("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)
+ {
+ META_CONPRINT("Returning now\n");
+ vec_result->x = 0;
+ vec_result->y = 0;
+ vec_result->z = 0;
+ return vec_result;
+ }
+ return vec_result;
+}
diff --git a/vhook.h b/vhook.h
index 7bf630a..8aa7d97 100644
--- a/vhook.h
+++ b/vhook.h
@@ -91,7 +91,7 @@ class HookReturnStruct
public:
~HookReturnStruct()
{
- if(this->type != ReturnType_CharPtr && this->type != ReturnType_StringPtr)
+ if(this->type != ReturnType_CharPtr && this->type != ReturnType_StringPtr && this->type != ReturnType_Vector && this->type != ReturnType_VectorPtr)
{
free(this->newResult);
}
@@ -105,6 +105,18 @@ public:
{
delete *(string_t **)this->newResult;
}
+ else if(this->type == ReturnType_Vector || this->type == ReturnType_VectorPtr)
+ {
+ delete *(Vector **)this->newResult;
+ }
+ }
+ if(this->type == ReturnType_Vector || this->type == ReturnType_VectorPtr)
+ {
+ delete *(Vector **)this->orgResult;
+ }
+ else if(this->type != ReturnType_String && this->type != ReturnType_Int && this->type != ReturnType_Bool && this->type != ReturnType_Float)
+ {
+ free(*(void **)this->orgResult);
}
free(this->orgResult);
}
@@ -149,6 +161,7 @@ public:
#ifndef __linux__
void *Callback(DHooksCallback *dg, void **stack, size_t *argsizep);
float Callback_float(DHooksCallback *dg, void **stack, size_t *argsizep);
+Vector *Callback_vector(DHooksCallback *dg, void **stack, size_t *argsizep);
#else
void *Callback(DHooksCallback *dg, void **stack);
float Callback_float(DHooksCallback *dg, void **stack);
@@ -181,23 +194,35 @@ static void *GenerateThunk(ReturnType type)
return base;
}
#else
+// HUGE THANKS TO BAILOPAN (dvander)!
static void *GenerateThunk(ReturnType type)
{
MacroAssemblerX86 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, 4);
- masm.push(esp);
- masm.lea(eax, Operand(ebp, 8));
- masm.push(eax);
- masm.push(ecx);
+ 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.addl(esp, 12);
- masm.pop(ecx); // grab arg size
+ }
+ 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