diff --git a/extensions/sdktools/vcallbuilder.cpp b/extensions/sdktools/vcallbuilder.cpp index ab24c937..934b672e 100644 --- a/extensions/sdktools/vcallbuilder.cpp +++ b/extensions/sdktools/vcallbuilder.cpp @@ -60,17 +60,22 @@ ValveCall *CreateValveCall(void *addr, size_t size = 0; vc->stackSize = 0; - /* Get return information - encode only*/ + /* Get return information - encode only */ PassInfo retBuf; size_t retBufSize = 0; + bool retbuf_needs_extra; if (retInfo) { - if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf)) == 0) + if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0) { delete vc; return NULL; } - retBufSize = size; + retBufSize = retBuf.size; + if (retbuf_needs_extra) + { + retBufSize += size; + } } /* Get thisinfo if needed */ @@ -98,14 +103,29 @@ ValveCall *CreateValveCall(void *addr, /* Get parameter info */ PassInfo paramBuf[32]; + size_t sizes[32]; + size_t normSize = 0; + size_t extraSize = 0; for (unsigned int i=0; istackSize += size; + if (needs_extra) + { + sizes[i] = size; + } else { + sizes[i] = 0; + } + normSize += paramBuf[i].size; + extraSize += sizes[i]; } /* Now we can try creating the call */ @@ -135,6 +155,7 @@ ValveCall *CreateValveCall(void *addr, vc->retinfo = &(vc->vparams[numParams]); *vc->retinfo = *retInfo; vc->retinfo->offset = 0; + vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0; /* Allocate stack space */ vc->retbuf = new unsigned char[retBufSize]; } else { @@ -148,18 +169,25 @@ ValveCall *CreateValveCall(void *addr, vc->thisinfo = &(vc->vparams[numParams + 1]); *vc->thisinfo = *thisinfo; vc->thisinfo->offset = 0; + vc->thisinfo->obj_offset = 0; } else { vc->thisinfo = NULL; } /* Now, save info about each parameter. */ + size_t last_extra_offset = 0; for (unsigned int i=0; ivparams[i] = params[i]; vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset; + vc->vparams[i].obj_offset = last_extra_offset; + last_extra_offset += sizes[i]; } + vc->stackSize = normSize + extraSize; + vc->stackEnd = normSize; + return vc; } @@ -179,29 +207,49 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx, size_t size = 0; vc->stackSize = 0; - /* Get return information - encode only*/ + /* Get return information - encode only */ PassInfo retBuf; size_t retBufSize = 0; + bool retbuf_needs_extra; if (retInfo) { - if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf)) == 0) + if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0) { delete vc; return NULL; } - retBufSize = size; + retBufSize = retBuf.size; + if (retbuf_needs_extra) + { + retBufSize += size; + } } /* Get parameter info */ PassInfo paramBuf[32]; + size_t sizes[32]; + size_t normSize = 0; + size_t extraSize = 0; for (unsigned int i=0; istackSize += size; + if (needs_extra) + { + sizes[i] = size; + } else { + sizes[i] = 0; + } + normSize += paramBuf[i].size; + extraSize += sizes[i]; } /* Now we can try creating the call */ @@ -232,6 +280,7 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx, vc->retinfo = &(vc->vparams[numParams]); *vc->retinfo = *retInfo; vc->retinfo->offset = 0; + vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0; /* Allocate stack space */ vc->retbuf = new unsigned char[retBufSize]; } else { @@ -253,15 +302,22 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx, vc->thisinfo->encflags = 0; vc->thisinfo->flags = PASSFLAG_BYVAL; vc->thisinfo->offset = 0; - vc->stackSize += sizeof(void *); + vc->thisinfo->obj_offset = 0; + normSize += sizeof(void *); /* Now, save info about each parameter. */ + size_t last_extra_offset = 0; for (unsigned int i=0; ivparams[i] = params[i]; vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset; + vc->vparams[i].obj_offset = last_extra_offset; + last_extra_offset += sizes[i]; } + vc->stackSize = normSize + extraSize; + vc->stackEnd = normSize; + return vc; } diff --git a/extensions/sdktools/vcallbuilder.h b/extensions/sdktools/vcallbuilder.h index 9f2a2255..23b9e295 100644 --- a/extensions/sdktools/vcallbuilder.h +++ b/extensions/sdktools/vcallbuilder.h @@ -18,6 +18,7 @@ struct ValveCall ValvePassInfo *retinfo; /**< Return buffer info */ ValvePassInfo *thisinfo; /**< Thiscall info */ size_t stackSize; /**< Stack size */ + size_t stackEnd; /**< End of the bintools stack */ unsigned char *retbuf; /**< Return buffer */ CStack stk; /**< Parameter stack */ diff --git a/extensions/sdktools/vcaller.cpp b/extensions/sdktools/vcaller.cpp index 6603e131..f6d8ab6d 100644 --- a/extensions/sdktools/vcaller.cpp +++ b/extensions/sdktools/vcaller.cpp @@ -232,7 +232,8 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Expected 1 parameter for entity pointer; found none"); } if (DecodeValveParam(pContext, - params[startparam], + params[startparam], + vc, vc->thisinfo, ptr) == Data_Fail) { @@ -268,8 +269,9 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params) } if (DecodeValveParam(pContext, params[p], + vc, &(vc->vparams[i]), - ptr + vc->vparams[i].offset) == Data_Fail) + ptr) == Data_Fail) { vc->stk_put(ptr); return 0; @@ -292,8 +294,9 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params) { if (EncodeValveParam(pContext, startparam + i, + vc, &vc->vparams[i], - ptr + vc->vparams[i].offset) == Data_Fail) + ptr) == Data_Fail) { vc->stk_put(ptr); return 0; @@ -326,7 +329,7 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params) { return pContext->ThrowNativeError("Expected argument (2) for Float[3] storage"); } - if (EncodeValveParam(pContext, params[retparam], vc->retinfo, vc->retbuf) + if (EncodeValveParam(pContext, params[retparam], vc, vc->retinfo, vc->retbuf) == Data_Fail) { return 0; diff --git a/extensions/sdktools/vdecoder.cpp b/extensions/sdktools/vdecoder.cpp index cc2f7279..0f01c25d 100644 --- a/extensions/sdktools/vdecoder.cpp +++ b/extensions/sdktools/vdecoder.cpp @@ -1,13 +1,14 @@ #include "smsdk_ext.h" #include "extension.h" #include "vdecoder.h" +#include "vcallbuilder.h" using namespace SourceMod; using namespace SourcePawn; /** * For object pointers, the data looks like this instead: - * 4 bytes: POINTER TO NEXT FOUR BYTES + * 4 bytes: POINTER TO LATER * + bytes: Object internal data * * We use the virtual stack as extra fake stack space and create a temp object. @@ -18,8 +19,10 @@ using namespace SourcePawn; size_t ValveParamToBinParam(ValveType type, PassType pass, unsigned int flags, - PassInfo *info) + PassInfo *info, + bool &needs_extra) { + needs_extra = false; switch (type) { case Valve_Vector: @@ -34,7 +37,8 @@ size_t ValveParamToBinParam(ValveType type, info->type = PassType_Basic; info->flags = flags; info->size = sizeof(Vector *); - mySize += sizeof(Vector); + mySize = sizeof(Vector); + needs_extra = true; } else if (pass == PassType_Object) { info->type = PassType_Object; info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR; @@ -56,7 +60,8 @@ size_t ValveParamToBinParam(ValveType type, info->type = PassType_Basic; info->flags = flags; info->size = sizeof(QAngle *); - mySize += sizeof(QAngle); + mySize = sizeof(QAngle); + needs_extra = true; } else if (pass == PassType_Object) { info->type = PassType_Object; info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR; @@ -126,9 +131,11 @@ size_t ValveParamToBinParam(ValveType type, DataStatus EncodeValveParam(IPluginContext *pContext, cell_t param, + const ValveCall *pCall, const ValvePassInfo *data, - const void *buffer) + const void *_buffer) { + const void *buffer = (const unsigned char *)_buffer + data->offset; switch (data->vtype) { case Valve_Vector: @@ -239,9 +246,11 @@ DataStatus EncodeValveParam(IPluginContext *pContext, DataStatus DecodeValveParam(IPluginContext *pContext, cell_t param, + const ValveCall *pCall, const ValvePassInfo *data, - void *buffer) + void *_buffer) { + void *buffer = (unsigned char *)_buffer + data->offset; switch (data->vtype) { case Valve_Vector: @@ -269,7 +278,7 @@ DataStatus DecodeValveParam(IPluginContext *pContext, return Data_Fail; } } else { - mem += sizeof(Vector *); + mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset; *realPtr = (Vector *)mem; } } @@ -316,7 +325,7 @@ DataStatus DecodeValveParam(IPluginContext *pContext, return Data_Okay; } } else { - mem += sizeof(QAngle *); + mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset; *realPtr = (QAngle *)mem; } } diff --git a/extensions/sdktools/vdecoder.h b/extensions/sdktools/vdecoder.h index 94f9321e..eb98894e 100644 --- a/extensions/sdktools/vdecoder.h +++ b/extensions/sdktools/vdecoder.h @@ -60,8 +60,11 @@ struct ValvePassInfo PassType type; /**< IN: Pass information */ unsigned int flags; /**< IN: Pass flags */ size_t offset; /**< OUT: stack offset */ + size_t obj_offset; /**< OUT: object offset at end of the stack */ }; +struct ValveCall; + /** * @brief Converts a valve parameter to a bintools parameter. * @@ -75,7 +78,8 @@ struct ValvePassInfo size_t ValveParamToBinParam(ValveType type, PassType pass, unsigned int flags, - PassInfo *info); + PassInfo *info, + bool &needs_extra); /** * @brief Decodes data from a plugin to native data. @@ -90,6 +94,7 @@ size_t ValveParamToBinParam(ValveType type, */ DataStatus DecodeValveParam(IPluginContext *pContext, cell_t param, + const ValveCall *pCall, const ValvePassInfo *vdata, void *buffer); @@ -106,6 +111,7 @@ DataStatus DecodeValveParam(IPluginContext *pContext, */ DataStatus EncodeValveParam(IPluginContext *pContext, cell_t param, + const ValveCall *pCall, const ValvePassInfo *vdata, const void *buffer); diff --git a/extensions/sdktools/vnatives.cpp b/extensions/sdktools/vnatives.cpp index 7b3495e2..c016fdb4 100644 --- a/extensions/sdktools/vnatives.cpp +++ b/extensions/sdktools/vnatives.cpp @@ -23,8 +23,9 @@ inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsign #define ENCODE_VALVE_PARAM(num, which, vnum) \ if (EncodeValveParam(pContext, \ params[num], \ + pCall, \ &pCall->which[vnum], \ - vptr + pCall->which[vnum].offset) \ + vptr) \ == Data_Fail) \ { \ return 0; \ @@ -33,8 +34,9 @@ inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsign #define DECODE_VALVE_PARAM(num, which, vnum) \ if (DecodeValveParam(pContext, \ params[num], \ + pCall, \ &pCall->which[vnum], \ - vptr + pCall->which[vnum].offset) \ + vptr) \ == Data_Fail) \ { \ return 0; \