Add Call_PushNullVector and Call_PushNullString

Be able to push NULL_[VECTOR|STRING] to a forward or direct function call.
The callee can check the parameter using the IsNullVector/IsNullString natives.
This commit is contained in:
Peace-Maker 2017-05-04 22:56:31 -06:00
parent 3de269946c
commit 41a9889cdd
5 changed files with 214 additions and 3 deletions

View File

@ -273,7 +273,26 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
*/
if (type == Param_String)
{
err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
// If NULL_STRING was pushed, push the reference to the pubvar of the callee instead.
if (param->isnull)
{
IPluginRuntime *runtime = func->GetParentRuntime();
uint32_t null_string_idx;
err = runtime->FindPubvarByName("NULL_STRING", &null_string_idx);
if (!err)
{
cell_t null_string;
err = runtime->GetPubvarAddrs(null_string_idx, &null_string, nullptr);
if (!err)
err = func->PushCell(null_string);
}
}
else
{
err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
}
}
else if (type == Param_Float || type == Param_Cell)
{
@ -281,7 +300,26 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
}
else
{
err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
// If NULL_VECTOR was pushed, push the reference to the pubvar of the callee instead.
if (param->isnull && type == Param_Array)
{
IPluginRuntime *runtime = func->GetParentRuntime();
uint32_t null_vector_idx;
err = runtime->FindPubvarByName("NULL_VECTOR", &null_vector_idx);
if (!err)
{
cell_t null_vector;
err = runtime->GetPubvarAddrs(null_vector_idx, &null_vector, nullptr);
if (!err)
err = func->PushCell(null_vector);
}
}
else
{
err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
}
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
}
}
@ -400,6 +438,7 @@ int CForward::PushCell(cell_t cell)
m_params[m_curparam].pushedas = Param_Cell;
}
m_params[m_curparam].isnull = false;
m_params[m_curparam++].val = cell;
return SP_ERROR_NONE;
@ -423,6 +462,7 @@ int CForward::PushFloat(float number)
m_params[m_curparam].pushedas = Param_Float;
}
m_params[m_curparam].isnull = false;
m_params[m_curparam++].val = *(cell_t *)&number;
return SP_ERROR_NONE;
@ -481,6 +521,7 @@ void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
m_params[m_curparam].byref.cells = cells;
m_params[m_curparam].byref.flags = flags;
m_params[m_curparam].byref.orig_addr = inarray;
m_params[m_curparam].isnull = false;
}
int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
@ -520,6 +561,7 @@ void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags
m_params[m_curparam].byref.flags = cp_flags;
m_params[m_curparam].byref.orig_addr = inarray;
m_params[m_curparam].byref.sz_flags = sz_flags;
m_params[m_curparam].isnull = false;
}
int CForward::PushString(const char *string)
@ -570,6 +612,52 @@ int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_fla
return SP_ERROR_NONE;
}
int CForward::PushNullString()
{
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] == Param_Any)
{
m_params[m_curparam].pushedas = Param_String;
} else if (m_types[m_curparam] != Param_String) {
return SetError(SP_ERROR_PARAM);
}
} else {
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
m_params[m_curparam].pushedas = Param_String;
}
m_params[m_curparam++].isnull = true;
return SP_ERROR_NONE;
}
int CForward::PushNullVector()
{
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] == Param_Any)
{
m_params[m_curparam].pushedas = Param_Array;
} else if (m_types[m_curparam] != Param_Array) {
return SetError(SP_ERROR_PARAM);
}
} else {
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
m_params[m_curparam].pushedas = Param_Array;
}
m_params[m_curparam++].isnull = true;
return SP_ERROR_NONE;
}
void CForward::Cancel()
{
if (!m_curparam)

View File

@ -55,6 +55,8 @@ public: //IForward
virtual unsigned int GetFunctionCount();
virtual ExecType GetExecType();
virtual int Execute(cell_t *result, IForwardFilter *filter);
virtual int PushNullString();
virtual int PushNullVector();
public: //IChangeableForward
virtual bool RemoveFunction(IPluginFunction *func);
virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin);

View File

@ -552,6 +552,88 @@ static cell_t sm_CallPushStringEx(IPluginContext *pContext, const cell_t *params
return 1;
}
static cell_t sm_CallPushNullVector(IPluginContext *pContext, const cell_t *params)
{
int err = SP_ERROR_NOT_FOUND;
if (!s_CallStarted)
{
return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
}
if (s_pFunction)
{
// Find the NULL_VECTOR pubvar in the target plugin and push the local address.
IPluginRuntime *runtime = s_pFunction->GetParentRuntime();
uint32_t null_vector_idx;
err = runtime->FindPubvarByName("NULL_VECTOR", &null_vector_idx);
if (err)
{
return pContext->ThrowNativeErrorEx(err, "Target plugin has no NULL_VECTOR.");
}
cell_t null_vector;
err = runtime->GetPubvarAddrs(null_vector_idx, &null_vector, nullptr);
if (!err)
err = s_pCallable->PushCell(null_vector);
}
else if (s_pForward)
{
err = s_pForward->PushNullVector();
}
if (err)
{
s_pCallable->Cancel();
ResetCall();
return pContext->ThrowNativeErrorEx(err, NULL);
}
return 1;
}
static cell_t sm_CallPushNullString(IPluginContext *pContext, const cell_t *params)
{
int err = SP_ERROR_NOT_FOUND;
if (!s_CallStarted)
{
return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
}
if (s_pFunction)
{
// Find the NULL_STRING pubvar in the target plugin and push the local address.
IPluginRuntime *runtime = s_pFunction->GetParentRuntime();
uint32_t null_string_idx;
err = runtime->FindPubvarByName("NULL_STRING", &null_string_idx);
if (err)
{
return pContext->ThrowNativeErrorEx(err, "Target plugin has no NULL_STRING.");
}
cell_t null_string;
err = runtime->GetPubvarAddrs(null_string_idx, &null_string, nullptr);
if (!err)
err = s_pCallable->PushCell(null_string);
}
else if (s_pForward)
{
err = s_pForward->PushNullString();
}
if (err)
{
s_pCallable->Cancel();
ResetCall();
return pContext->ThrowNativeErrorEx(err, NULL);
}
return 1;
}
static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
{
int err = SP_ERROR_NOT_RUNNABLE;
@ -668,6 +750,8 @@ REGISTER_NATIVES(functionNatives)
{"Call_PushArrayEx", sm_CallPushArrayEx},
{"Call_PushString", sm_CallPushString},
{"Call_PushStringEx", sm_CallPushStringEx},
{"Call_PushNullVector", sm_CallPushNullVector},
{"Call_PushNullString", sm_CallPushNullString},
{"Call_Finish", sm_CallFinish},
{"Call_Cancel", sm_CallCancel},
{"RequestFrame", sm_AddFrameAction},

View File

@ -290,6 +290,16 @@ native void Call_PushArray(const any[] value, int size);
*/
native void Call_PushArrayEx(any[] value, int size, int cpflags);
/**
* Pushes the NULL_VECTOR onto the current call.
* @see IsNullVector
*
* @note Cannot be used before a call has been started.
*
* @error Called before a call has been started.
*/
native void Call_PushNullVector();
/**
* Pushes a string onto the current call.
*
@ -317,6 +327,16 @@ native void Call_PushString(const char[] value);
*/
native void Call_PushStringEx(char[] value, int length, int szflags, int cpflags);
/**
* Pushes the NULL_STRING onto the current call.
* @see IsNullString
*
* @note Cannot be used before a call has been started.
*
* @error Called before a call has been started.
*/
native void Call_PushNullString();
/**
* Completes a call to a function or forward's call list.
*

View File

@ -50,7 +50,7 @@
using namespace SourcePawn;
#define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager"
#define SMINTERFACE_FORWARDMANAGER_VERSION 3
#define SMINTERFACE_FORWARDMANAGER_VERSION 4
/*
* There is some very important documentation at the bottom of this file.
@ -118,6 +118,7 @@ namespace SourceMod
cell_t val;
ByrefInfo byref;
ParamType pushedas;
bool isnull;
};
class IForwardFilter
@ -183,6 +184,22 @@ namespace SourceMod
* @return Error code, if any.
*/
virtual int PushArray(cell_t *inarray, unsigned int cells, int flags=0) =0;
/**
* @brief Pushes the NULL_STRING onto the current call. This will always push the
* correct reference to each function in the forward.
*
* @return Error code, if any.
*/
virtual int PushNullString() =0;
/**
* @brief Pushes the NULL_VECTOR onto the current call. This will always push the
* correct reference to each function in the forward.
*
* @return Error code, if any.
*/
virtual int PushNullVector() =0;
};
/**