Initial import of forward system
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40185
This commit is contained in:
parent
4d89283924
commit
6bef3c2c5a
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
#include <IPluginSys.h>
|
#include <IPluginSys.h>
|
||||||
|
#include <IPluginFunction.h>
|
||||||
|
|
||||||
#define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager"
|
#define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager"
|
||||||
#define SMINTERFACE_FORWARDMANAGER_VERSION 1
|
#define SMINTERFACE_FORWARDMANAGER_VERSION 1
|
||||||
@ -24,18 +25,76 @@ namespace SourceMod
|
|||||||
enum ExecType
|
enum ExecType
|
||||||
{
|
{
|
||||||
ET_Ignore = 0, /* Ignore all return values, return 0 */
|
ET_Ignore = 0, /* Ignore all return values, return 0 */
|
||||||
ET_Single = 1, /* Only return the first exec, ignore all others */
|
ET_Single = 1, /* Only return the last exec, ignore all others */
|
||||||
ET_Event = 2, /* Acts as an event with the ResultTypes above, no mid-Stops allowed, returns highest */
|
ET_Event = 2, /* Acts as an event with the ResultTypes above, no mid-Stops allowed, returns highest */
|
||||||
ET_Hook = 3, /* Acts as a hook with the ResultTypes above, mid-Stops allowed, returns highest */
|
ET_Hook = 3, /* Acts as a hook with the ResultTypes above, mid-Stops allowed, returns highest */
|
||||||
|
ET_Custom = 4, /* Ignored or handled by an IForwardFilter */
|
||||||
|
};
|
||||||
|
|
||||||
|
class IForward;
|
||||||
|
|
||||||
|
class IForwardFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Called when an error occurs executing a plugin.
|
||||||
|
*
|
||||||
|
* @param fwd IForward pointer.
|
||||||
|
* @param func IPluginFunction pointer to the failed function.
|
||||||
|
* @param err Error code.
|
||||||
|
* @return True to handle, false to pass to global error reporter.
|
||||||
|
*/
|
||||||
|
virtual bool OnErrorReport(IForward *fwd,
|
||||||
|
IPluginFunction *func,
|
||||||
|
int err)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called after each function return during execution.
|
||||||
|
* NOTE: Only used for ET_Custom.
|
||||||
|
*
|
||||||
|
* @param fwd IForward pointer.
|
||||||
|
* @param func IPluginFunction pointer to the executed function.
|
||||||
|
* @param retval Pointer to current return value (can be modified).
|
||||||
|
* @return ResultType denoting the next action to take.
|
||||||
|
*/
|
||||||
|
virtual ResultType OnFunctionReturn(IForward *fwd,
|
||||||
|
IPluginFunction *func,
|
||||||
|
cell_t *retval)
|
||||||
|
{
|
||||||
|
return Pl_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when execution begins.
|
||||||
|
*/
|
||||||
|
virtual void OnExecuteBegin()
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when execution ends.
|
||||||
|
*
|
||||||
|
* @param final_ret Final return value (modifiable).
|
||||||
|
* @param success Number of successful execs.
|
||||||
|
* @param failed Number of failed execs.
|
||||||
|
*/
|
||||||
|
virtual void OnExecuteEnd(cell_t *final_ret, unsigned int success, unsigned int failed)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* :TODO: finish this spec
|
|
||||||
* @brief Abstracts multiple function calling.
|
* @brief Abstracts multiple function calling.
|
||||||
|
*
|
||||||
* NOTE: Parameters should be pushed in forward order, unlike
|
* NOTE: Parameters should be pushed in forward order, unlike
|
||||||
* the virtual machine/IPluginContext order.
|
* the virtual machine/IPluginContext order.
|
||||||
* NOTE: Some functions are repeated in here because their documentation differs
|
* NOTE: Some functions are repeated in here because their
|
||||||
* from their IPluginFunction equivalents.
|
* documentation differs from their IPluginFunction equivalents.
|
||||||
|
* Missing are the Push functions, whose only doc change is that
|
||||||
|
* they throw SP_ERROR_PARAM on type mismatches.
|
||||||
*/
|
*/
|
||||||
class IForward : public ICallable
|
class IForward : public ICallable
|
||||||
{
|
{
|
||||||
@ -65,10 +124,25 @@ namespace SourceMod
|
|||||||
* @brief Executes the forward.
|
* @brief Executes the forward.
|
||||||
*
|
*
|
||||||
* @param result Pointer to store result in.
|
* @param result Pointer to store result in.
|
||||||
* @param num_functions Optionally filled with the number of function sucessfully executed.
|
* @param filter Optional pointer to an IForwardFilter.
|
||||||
* @return Error code, if any.
|
* @return Error code, if any.
|
||||||
*/
|
*/
|
||||||
virtual int Execute(cell_t *result, unsigned int *num_functions) =0;
|
virtual int Execute(cell_t *result, IForwardFilter *filter=NULL) =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pushes an array of cells onto the current call. Different rules than ICallable.
|
||||||
|
* NOTE: On Execute, the pointer passed will be modified according to the copyback rule.
|
||||||
|
*
|
||||||
|
* @param array Array to copy. Cannot be NULL, unlike ICallable's version.
|
||||||
|
* @param cells Number of cells to allocate and optionally read from the input array.
|
||||||
|
* @param phys_addr Unused. If a value is passed, it will be filled with NULL.
|
||||||
|
* @param flags Whether or not changes should be copied back to the input array.
|
||||||
|
* @return Error code, if any.
|
||||||
|
*/
|
||||||
|
virtual int PushArray(cell_t *inarray,
|
||||||
|
unsigned int cells,
|
||||||
|
cell_t **phys_addr,
|
||||||
|
int flags=SMFUNC_COPYBACK_NONE) =0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -77,10 +151,12 @@ namespace SourceMod
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Removes a function from the call list.
|
* @brief Removes a function from the call list.
|
||||||
|
* NOTE: Only removes one instance.
|
||||||
*
|
*
|
||||||
* @param func Function to remove.
|
* @param func Function to remove.
|
||||||
|
* @return Whether or not the function was removed.
|
||||||
*/
|
*/
|
||||||
virtual void RemoveFunction(IPluginFunction *func) =0;
|
virtual bool RemoveFunction(IPluginFunction *func) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Removes all instances of a plugin from the call list.
|
* @brief Removes all instances of a plugin from the call list.
|
||||||
@ -92,7 +168,9 @@ namespace SourceMod
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a function to the call list.
|
* @brief Adds a function to the call list.
|
||||||
* NOTE: Cannot be used during a call.
|
* NOTE: Cannot be used during an incompleted call.
|
||||||
|
* NOTE: If used during a call, function is temporarily queued until calls are over.
|
||||||
|
* NOTE: Adding mulitple copies of the same function is illegal.
|
||||||
*
|
*
|
||||||
* @param func Function to add.
|
* @param func Function to add.
|
||||||
* @return True on success, otherwise false.
|
* @return True on success, otherwise false.
|
||||||
@ -101,7 +179,8 @@ namespace SourceMod
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a function to the call list.
|
* @brief Adds a function to the call list.
|
||||||
* NOTE: Cannot be used during a call.
|
* NOTE: Cannot be used during an incompleted call.
|
||||||
|
* NOTE: If used during a call, function is temporarily queued until calls are over.
|
||||||
*
|
*
|
||||||
* @param ctx Context to use as a look-up.
|
* @param ctx Context to use as a look-up.
|
||||||
* @param funcid Function id to add.
|
* @param funcid Function id to add.
|
||||||
@ -110,15 +189,24 @@ namespace SourceMod
|
|||||||
virtual bool AddFunction(sp_context_t *ctx, funcid_t index) =0;
|
virtual bool AddFunction(sp_context_t *ctx, funcid_t index) =0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SP_PARAMTYPE_ANY 0
|
||||||
|
#define SP_PARAMFLAG_BYREF (1<<0)
|
||||||
|
#define SP_PARAMTYPE_CELL (1<<1)
|
||||||
|
#define SP_PARAMTYPE_FLOAT (2<<1)
|
||||||
|
#define SP_PARAMTYPE_STRING (3<<1)|SP_PARAMFLAG_BYREF
|
||||||
|
#define SP_PARAMTYPE_ARRAY (4<<1)|SP_PARAMFLAG_BYREF
|
||||||
|
#define SP_PARAMTYPE_VARARG (5<<1)
|
||||||
|
|
||||||
enum ParamType
|
enum ParamType
|
||||||
{
|
{
|
||||||
Param_Any = 0, //Any type will be accepted
|
Param_Any = SP_PARAMTYPE_ANY,
|
||||||
Param_Cell = 1, //Only a cell will be accepted
|
Param_Cell = SP_PARAMTYPE_CELL,
|
||||||
Param_Float = 2, //Only a float value will be accepted
|
Param_Float = SP_PARAMTYPE_FLOAT,
|
||||||
Param_String = 3, //Only a string will be accepted
|
Param_String = SP_PARAMTYPE_STRING,
|
||||||
Param_Array = 4, //Only a 1D array will be accepted
|
Param_Array = SP_PARAMTYPE_ARRAY,
|
||||||
Param_VarArgs = 5, //Anything will be accepted
|
Param_VarArgs = SP_PARAMTYPE_VARARG,
|
||||||
ParamTypes_Total = 6,
|
Param_CellByRef = SP_PARAMTYPE_CELL|SP_PARAMFLAG_BYREF,
|
||||||
|
Param_FloatByRef = SP_PARAMTYPE_FLOAT|SP_PARAMFLAG_BYREF,
|
||||||
};
|
};
|
||||||
|
|
||||||
class IForwardManager : public SMInterface
|
class IForwardManager : public SMInterface
|
||||||
|
@ -69,7 +69,7 @@ namespace SourceMod
|
|||||||
*
|
*
|
||||||
* @param array Array to copy, NULL if no initial array should be copied.
|
* @param array Array to copy, NULL if no initial array should be copied.
|
||||||
* @param cells Number of cells to allocate and optionally read from the input array.
|
* @param cells Number of cells to allocate and optionally read from the input array.
|
||||||
* @param phys_addr Optional return address for physical array (if array was non-NULL, will be array).
|
* @param phys_addr Optional return address for physical array, if one was made.
|
||||||
* @param flags Whether or not changes should be copied back to the input array.
|
* @param flags Whether or not changes should be copied back to the input array.
|
||||||
* @return Error code, if any.
|
* @return Error code, if any.
|
||||||
*/
|
*/
|
||||||
@ -171,6 +171,28 @@ namespace SourceMod
|
|||||||
* @return Address, or NULL if invalid parameter specified.
|
* @return Address, or NULL if invalid parameter specified.
|
||||||
*/
|
*/
|
||||||
virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0;
|
virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/**
|
||||||
|
* @brief Clones the function object. This can be used to maintain a private copy.
|
||||||
|
* The copy retains no push states and must be freeed with ReleaseCopy().
|
||||||
|
*/
|
||||||
|
virtual IPluginFunction *Copy() =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief If this object is a clone, this function must be called to destroy it.
|
||||||
|
*/
|
||||||
|
virtual void ReleaseCopy() =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns original function pointer, if any.
|
||||||
|
* Note: IsCopyOf() will return the original non-copy, even if used
|
||||||
|
* from a copy.
|
||||||
|
*
|
||||||
|
* @return The original object that this was sourced from.
|
||||||
|
*/
|
||||||
|
virtual IPluginFunction *IsCopyOf() =0;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -259,6 +259,10 @@
|
|||||||
RelativePath="..\systems\CFunction.cpp"
|
RelativePath="..\systems\CFunction.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\systems\ForwardSys.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\systems\LibrarySys.cpp"
|
RelativePath="..\systems\LibrarySys.cpp"
|
||||||
>
|
>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "vm/sp_vm_engine.h"
|
#include "vm/sp_vm_engine.h"
|
||||||
#include <sh_string.h>
|
#include <sh_string.h>
|
||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
|
#include "ForwardSys.h"
|
||||||
|
|
||||||
SourcePawnEngine g_SourcePawn;
|
SourcePawnEngine g_SourcePawn;
|
||||||
SourceModBase g_SourceMod;
|
SourceModBase g_SourceMod;
|
||||||
@ -111,17 +112,21 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/plugins/test.smx", g_BaseDir.c_str());
|
g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/plugins/test.smx", g_BaseDir.c_str());
|
||||||
IPlugin *pPlugin = g_PluginMngr.LoadPlugin(file, false, PluginType_Global, error, err_max);
|
IPlugin *pPlugin = g_PluginMngr.LoadPlugin(file, false, PluginType_Global, error, err_max);
|
||||||
IPluginFunction *func = pPlugin->GetFunctionByName("Test");
|
IPluginFunction *func = pPlugin->GetFunctionByName("Test");
|
||||||
|
IPluginFunction *func2 = pPlugin->GetFunctionByName("Test2");
|
||||||
cell_t result = 2;
|
cell_t result = 2;
|
||||||
cell_t val = 6;
|
cell_t val = 6;
|
||||||
func->PushCell(1);
|
ParamType types[] = {Param_Cell, Param_CellByRef};
|
||||||
func->PushCellByRef(&val, SMFUNC_COPYBACK_ONCE);
|
va_list ap = va_start(ap, late);
|
||||||
func->Execute(&result, NULL);
|
CForward *fwd = CForward::CreateForward(NULL, ET_Custom, 2, types, ap);
|
||||||
|
fwd->AddFunction(func);
|
||||||
|
fwd->AddFunction(func2);
|
||||||
|
fwd->PushCell(1);
|
||||||
|
fwd->PushCellByRef(&val, SMFUNC_COPYBACK_ALWAYS);
|
||||||
|
fwd->Execute(&result, NULL);
|
||||||
g_PluginMngr.UnloadPlugin(pPlugin);
|
g_PluginMngr.UnloadPlugin(pPlugin);
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr
|
|||||||
return SetError(err);
|
return SetError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
info->flags = inarray ? copyback : SMFUNC_COPYBACK_NONE;
|
info->flags = (inarray || (copyback & SMFUNC_COPYBACK_ALWAYS)) ? copyback : SMFUNC_COPYBACK_NONE;
|
||||||
info->marked = true;
|
info->marked = true;
|
||||||
info->size = cells;
|
info->size = cells;
|
||||||
m_params[m_curparam] = info->local_addr;
|
m_params[m_curparam] = info->local_addr;
|
||||||
@ -246,11 +246,16 @@ int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader)
|
|||||||
}
|
}
|
||||||
if (temp_info[numparams].orig_addr)
|
if (temp_info[numparams].orig_addr)
|
||||||
{
|
{
|
||||||
|
if (temp_info[numparams].size == 1)
|
||||||
|
{
|
||||||
|
*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
|
||||||
|
} else {
|
||||||
memcpy(temp_info[numparams].orig_addr,
|
memcpy(temp_info[numparams].orig_addr,
|
||||||
temp_info[numparams].phys_addr,
|
temp_info[numparams].phys_addr,
|
||||||
temp_info[numparams].size * sizeof(cell_t));
|
temp_info[numparams].size * sizeof(cell_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_skipcopy:
|
_skipcopy:
|
||||||
base->HeapRelease(temp_info[numparams].local_addr);
|
base->HeapRelease(temp_info[numparams].local_addr);
|
||||||
temp_info[numparams].marked = false;
|
temp_info[numparams].marked = false;
|
||||||
|
667
core/systems/ForwardSys.cpp
Normal file
667
core/systems/ForwardSys.cpp
Normal file
@ -0,0 +1,667 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "ForwardSys.h"
|
||||||
|
#include "PluginSys.h"
|
||||||
|
|
||||||
|
CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
|
||||||
|
{
|
||||||
|
ParamType _types[SP_MAX_EXEC_PARAMS];
|
||||||
|
|
||||||
|
if (num_params > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (types == NULL && num_params)
|
||||||
|
{
|
||||||
|
for (unsigned int i=0; i<num_params; i++)
|
||||||
|
{
|
||||||
|
_types[i] = va_arg(ap, ParamType);
|
||||||
|
if (_types[i] == Param_VarArgs && (i != num_params - 1))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
types = _types;
|
||||||
|
} else {
|
||||||
|
for (unsigned int i=0; i<num_params; i++)
|
||||||
|
{
|
||||||
|
if (types[i] == Param_VarArgs && (i != num_params - 1))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First parameter can never be varargs */
|
||||||
|
if (types[0] == Param_VarArgs)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CForward *pForward = new CForward;
|
||||||
|
pForward->m_curparam = 0;
|
||||||
|
pForward->m_ExecType = et;
|
||||||
|
snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<num_params; i++)
|
||||||
|
{
|
||||||
|
pForward->m_types[i] = types[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_params && types[num_params-1] == Param_VarArgs)
|
||||||
|
{
|
||||||
|
pForward->m_varargs = true;
|
||||||
|
} else {
|
||||||
|
pForward->m_varargs = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pForward->m_numparams = num_params;
|
||||||
|
pForward->m_errstate = SP_ERROR_NONE;
|
||||||
|
pForward->m_CopyBacks.numrecopy = 0;
|
||||||
|
|
||||||
|
return pForward;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CForward::OnCopybackArray(unsigned int param,
|
||||||
|
unsigned int cells,
|
||||||
|
cell_t *source_addr,
|
||||||
|
cell_t *orig_addr,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
/* Check if the stack is empty, this should be an assertion */
|
||||||
|
if (m_NextStack.empty())
|
||||||
|
{
|
||||||
|
/* This should never happen! */
|
||||||
|
assert(!m_NextStack.empty());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we even want to copy to the next plugin */
|
||||||
|
if (!(flags & SMFUNC_COPYBACK_ALWAYS))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep track of the copy back and save the info */
|
||||||
|
NextCallInfo &info = m_NextStack.front();
|
||||||
|
info.recopy[info.numrecopy++] = param;
|
||||||
|
info.orig_addrs[param] = orig_addr;
|
||||||
|
info.sizes[param] = cells;
|
||||||
|
|
||||||
|
/* We don't want to override the copy. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||||
|
{
|
||||||
|
if (m_errstate)
|
||||||
|
{
|
||||||
|
int err = m_errstate;
|
||||||
|
Cancel();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset marker */
|
||||||
|
m_curparam = 0;
|
||||||
|
|
||||||
|
if (filter)
|
||||||
|
{
|
||||||
|
filter->OnExecuteBegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncIter iter = m_functions.begin();
|
||||||
|
IPluginFunction *func;
|
||||||
|
cell_t cur_result = 0;
|
||||||
|
cell_t high_result = 0;
|
||||||
|
int err;
|
||||||
|
unsigned int failed=0, success=0;
|
||||||
|
unsigned int save_numcopy = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save copyback into to start the chain,
|
||||||
|
* then reset it for re-entrancy
|
||||||
|
*/
|
||||||
|
m_NextStack.push(m_CopyBacks);
|
||||||
|
NextCallInfo &info = m_NextStack.front();
|
||||||
|
m_CopyBacks.numrecopy = 0;
|
||||||
|
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we need to copy a new array back into the plugin.
|
||||||
|
*/
|
||||||
|
if (info.numrecopy)
|
||||||
|
{
|
||||||
|
/* The last plugin has a chained copyback, we must redirect it here. */
|
||||||
|
unsigned int param;
|
||||||
|
cell_t *orig_addr, *targ_addr;
|
||||||
|
for (unsigned int i=0; i<info.numrecopy; i++)
|
||||||
|
{
|
||||||
|
/* Get the parameter info to copy */
|
||||||
|
param = info.recopy[i];
|
||||||
|
targ_addr = func->GetAddressOfPushedParam(param);
|
||||||
|
orig_addr = info.orig_addrs[param];
|
||||||
|
/* Only do the copy for valid targets */
|
||||||
|
if (targ_addr && orig_addr)
|
||||||
|
{
|
||||||
|
if (info.sizes[param] == 1)
|
||||||
|
{
|
||||||
|
*targ_addr = *orig_addr;
|
||||||
|
} else {
|
||||||
|
memcpy(targ_addr, orig_addr, info.sizes[param] * sizeof(cell_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If this failed, the plugin will most likely be failing as well. */
|
||||||
|
}
|
||||||
|
save_numcopy = info.numrecopy;
|
||||||
|
info.numrecopy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the function and deal with the return value.
|
||||||
|
* :TODO: only pass reader if we know we have an array in the list
|
||||||
|
*/
|
||||||
|
if ((err=func->Execute(&cur_result, this)) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
bool handled = false;
|
||||||
|
if (filter)
|
||||||
|
{
|
||||||
|
handled = filter->OnErrorReport(this, func, err);
|
||||||
|
}
|
||||||
|
if (!handled)
|
||||||
|
{
|
||||||
|
/* :TODO: invoke global error reporting here */
|
||||||
|
}
|
||||||
|
/* If we failed, we're not quite done. The copy chain has been broken.
|
||||||
|
* We have to restore it so past changes will continue to get mirrored.
|
||||||
|
*/
|
||||||
|
info.numrecopy = save_numcopy;
|
||||||
|
failed++;
|
||||||
|
} else {
|
||||||
|
success++;
|
||||||
|
switch (m_ExecType)
|
||||||
|
{
|
||||||
|
case ET_Event:
|
||||||
|
{
|
||||||
|
if (cur_result > high_result)
|
||||||
|
{
|
||||||
|
high_result = cur_result;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_Hook:
|
||||||
|
{
|
||||||
|
if (cur_result > high_result)
|
||||||
|
{
|
||||||
|
high_result = cur_result;
|
||||||
|
if ((ResultType)high_result == Pl_Stop)
|
||||||
|
{
|
||||||
|
iter = m_functions.end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_Custom:
|
||||||
|
{
|
||||||
|
if (filter)
|
||||||
|
{
|
||||||
|
if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
|
||||||
|
{
|
||||||
|
iter = m_functions.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_NextStack.pop();
|
||||||
|
|
||||||
|
if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
|
||||||
|
{
|
||||||
|
cur_result = high_result;
|
||||||
|
} else if (m_ExecType == ET_Ignore) {
|
||||||
|
cur_result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = cur_result;
|
||||||
|
|
||||||
|
DumpAdditionQueue();
|
||||||
|
|
||||||
|
if (filter)
|
||||||
|
{
|
||||||
|
filter->OnExecuteEnd(&cur_result, success, failed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CForward::PushCell(cell_t cell)
|
||||||
|
{
|
||||||
|
if (m_curparam < m_numparams)
|
||||||
|
{
|
||||||
|
if (m_types[m_curparam] != Param_Cell && m_types[m_curparam] != Param_Any)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->PushCell(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CForward::PushFloat(float number)
|
||||||
|
{
|
||||||
|
if (m_curparam < m_numparams)
|
||||||
|
{
|
||||||
|
if (m_types[m_curparam] != Param_Float && m_types[m_curparam] != Param_Any)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->PushFloat(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CForward::PushCellByRef(cell_t *cell, int flags)
|
||||||
|
{
|
||||||
|
if (m_curparam < m_numparams)
|
||||||
|
{
|
||||||
|
if (m_types[m_curparam] != Param_CellByRef && m_types[m_curparam] != Param_Any)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & SMFUNC_COPYBACK_ALWAYS)
|
||||||
|
{
|
||||||
|
_Int_PushArray(cell, 1, flags);
|
||||||
|
} else {
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->PushCellByRef(cell, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CForward::PushFloatByRef(float *num, int flags)
|
||||||
|
{
|
||||||
|
if (m_curparam < m_numparams)
|
||||||
|
{
|
||||||
|
if (m_types[m_curparam] != Param_FloatByRef && m_types[m_curparam] != Param_Any)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & SMFUNC_COPYBACK_ALWAYS)
|
||||||
|
{
|
||||||
|
_Int_PushArray((cell_t *)num, 1, flags);
|
||||||
|
} else {
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->PushFloatByRef(num, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CForward::PushCells(cell_t array[], unsigned int numcells, bool each)
|
||||||
|
{
|
||||||
|
if (each)
|
||||||
|
{
|
||||||
|
/* Type check each cell if we need to! */
|
||||||
|
if (m_curparam + numcells >= m_numparams && !m_varargs)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
} else {
|
||||||
|
for (unsigned int i=m_curparam; i<m_numparams; i++)
|
||||||
|
{
|
||||||
|
if (m_types[i] != Param_Any || m_types[i] != Param_Cell)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_curparam < m_numparams)
|
||||||
|
{
|
||||||
|
if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->PushCells(array, numcells, each);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curparam += each ? numcells : 1;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
|
||||||
|
{
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
if (flags & SMFUNC_COPYBACK_ALWAYS)
|
||||||
|
{
|
||||||
|
/* As a special optimization, we create blank default arrays because they will be
|
||||||
|
* copied over anyway!
|
||||||
|
*/
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->PushArray(NULL, cells, NULL, flags);
|
||||||
|
}
|
||||||
|
m_CopyBacks.recopy[m_CopyBacks.numrecopy++] = m_curparam;
|
||||||
|
m_CopyBacks.orig_addrs[m_curparam] = inarray;
|
||||||
|
m_CopyBacks.sizes[m_curparam] = cells;
|
||||||
|
} else {
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->PushArray(inarray, cells, NULL, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
|
||||||
|
{
|
||||||
|
/* We don't allow this here */
|
||||||
|
if (!inarray)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_curparam < m_numparams)
|
||||||
|
{
|
||||||
|
if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phys_addr)
|
||||||
|
{
|
||||||
|
*phys_addr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Int_PushArray(inarray, cells, flags);
|
||||||
|
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CForward::PushString(const char *string)
|
||||||
|
{
|
||||||
|
if (m_curparam < m_numparams)
|
||||||
|
{
|
||||||
|
if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->PushString(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CForward::PushStringByRef(char *string, int flags)
|
||||||
|
{
|
||||||
|
if (m_curparam < m_numparams)
|
||||||
|
{
|
||||||
|
if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->PushStringByRef(string, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CForward::Cancel()
|
||||||
|
{
|
||||||
|
if (!m_curparam)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
func->Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CopyBacks.numrecopy = 0;
|
||||||
|
|
||||||
|
DumpAdditionQueue();
|
||||||
|
|
||||||
|
m_errstate = SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
|
||||||
|
{
|
||||||
|
IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx);
|
||||||
|
if (!pPlugin)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPluginFunction *pFunc = pPlugin->GetFunctionById(index);
|
||||||
|
if (!pFunc)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddFunction(pFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CForward::RemoveFunction(IPluginFunction *func)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *pNext = NULL;
|
||||||
|
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end();)
|
||||||
|
{
|
||||||
|
if ((*iter) == func)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
/* If this iterator is being used, swap in a new one !*/
|
||||||
|
iter = m_functions.erase(iter);
|
||||||
|
} else {
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just in case */
|
||||||
|
m_AddQueue.remove(func);
|
||||||
|
|
||||||
|
/* Cancel a call, if any */
|
||||||
|
if (found && (!m_NextStack.empty() || m_curparam))
|
||||||
|
{
|
||||||
|
func->Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
|
||||||
|
{
|
||||||
|
FuncIter iter;
|
||||||
|
IPluginFunction *func;
|
||||||
|
unsigned int removed = 0;
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end();)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
if (func->GetParentPlugin() == plugin)
|
||||||
|
{
|
||||||
|
iter = m_functions.erase(iter);
|
||||||
|
removed++;
|
||||||
|
} else {
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iter=m_AddQueue.begin(); iter!=m_AddQueue.end();)
|
||||||
|
{
|
||||||
|
func = (*iter);
|
||||||
|
if (func->GetParentPlugin() == plugin)
|
||||||
|
{
|
||||||
|
/* Don't count these toward the total */
|
||||||
|
iter = m_functions.erase(iter);
|
||||||
|
} else {
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CForward::DumpAdditionQueue()
|
||||||
|
{
|
||||||
|
FuncIter iter = m_AddQueue.begin();
|
||||||
|
while (iter != m_AddQueue.end())
|
||||||
|
{
|
||||||
|
m_functions.push_back((*iter));
|
||||||
|
//:TODO: eventually we will tell the plugin we're using it
|
||||||
|
iter = m_AddQueue.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CForward::AddFunction(IPluginFunction *func)
|
||||||
|
{
|
||||||
|
if (m_curparam)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_NextStack.empty())
|
||||||
|
{
|
||||||
|
m_AddQueue.push_back(func);
|
||||||
|
} else {
|
||||||
|
//:TODO: eventually we will tell the plugin we're using it
|
||||||
|
m_functions.push_back(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *CForward::GetForwardName()
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CForward::GetFunctionCount()
|
||||||
|
{
|
||||||
|
return m_functions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecType CForward::GetExecType()
|
||||||
|
{
|
||||||
|
return m_ExecType;
|
||||||
|
}
|
88
core/systems/ForwardSys.h
Normal file
88
core/systems/ForwardSys.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#ifndef _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||||
|
|
||||||
|
#include <IForwardSys.h>
|
||||||
|
#include <IPluginSys.h>
|
||||||
|
#include "sm_globals.h"
|
||||||
|
#include <sh_list.h>
|
||||||
|
#include <sh_stack.h>
|
||||||
|
|
||||||
|
using namespace SourceHook;
|
||||||
|
|
||||||
|
typedef List<IPluginFunction *>::iterator FuncIter;
|
||||||
|
|
||||||
|
//:TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX
|
||||||
|
#define FORWARDS_NAME_MAX 64
|
||||||
|
|
||||||
|
struct NextCallInfo
|
||||||
|
{
|
||||||
|
unsigned int recopy[SP_MAX_EXEC_PARAMS];
|
||||||
|
unsigned int sizes[SP_MAX_EXEC_PARAMS];
|
||||||
|
cell_t *orig_addrs[SP_MAX_EXEC_PARAMS];
|
||||||
|
unsigned int numrecopy;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CForward : public IChangeableForward, IFunctionCopybackReader
|
||||||
|
{
|
||||||
|
public: //ICallable
|
||||||
|
virtual int PushCell(cell_t cell);
|
||||||
|
virtual int PushCellByRef(cell_t *cell, int flags);
|
||||||
|
virtual int PushFloat(float number);
|
||||||
|
virtual int PushFloatByRef(float *number, int flags);
|
||||||
|
virtual int PushCells(cell_t array[], unsigned int numcells, bool each);
|
||||||
|
virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags);
|
||||||
|
virtual int PushString(const char *string);
|
||||||
|
virtual int PushStringByRef(char *string, int flags);
|
||||||
|
virtual void Cancel();
|
||||||
|
public: //IForward
|
||||||
|
virtual const char *GetForwardName();
|
||||||
|
virtual unsigned int GetFunctionCount();
|
||||||
|
virtual ExecType GetExecType();
|
||||||
|
virtual int Execute(cell_t *result, IForwardFilter *filter);
|
||||||
|
public: //IChangeableForward
|
||||||
|
virtual bool RemoveFunction(IPluginFunction *func);
|
||||||
|
virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin);
|
||||||
|
virtual bool AddFunction(IPluginFunction *func);
|
||||||
|
virtual bool AddFunction(sp_context_t *ctx, funcid_t index);
|
||||||
|
public: //IFunctionCopybackReader
|
||||||
|
virtual bool OnCopybackArray(unsigned int param,
|
||||||
|
unsigned int cells,
|
||||||
|
cell_t *source_addr,
|
||||||
|
cell_t *orig_addr,
|
||||||
|
int flags);
|
||||||
|
public:
|
||||||
|
static CForward *CreateForward(const char *name,
|
||||||
|
ExecType et,
|
||||||
|
unsigned int num_params,
|
||||||
|
ParamType *types,
|
||||||
|
va_list ap);
|
||||||
|
private:
|
||||||
|
void DumpAdditionQueue();
|
||||||
|
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
|
||||||
|
inline int SetError(int err)
|
||||||
|
{
|
||||||
|
m_errstate = err;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
/* :TODO: I want a caching list type here.
|
||||||
|
* Destroying these things and using new/delete for their members feels bad.
|
||||||
|
*/
|
||||||
|
List<IPluginFunction *> m_functions;
|
||||||
|
|
||||||
|
/* Type and name information */
|
||||||
|
ParamType m_types[SP_MAX_EXEC_PARAMS];
|
||||||
|
char m_name[FORWARDS_NAME_MAX+1];
|
||||||
|
unsigned int m_numparams;
|
||||||
|
bool m_varargs;
|
||||||
|
ExecType m_ExecType;
|
||||||
|
|
||||||
|
/* State information */
|
||||||
|
unsigned int m_curparam;
|
||||||
|
int m_errstate;
|
||||||
|
CStack<NextCallInfo> m_NextStack;
|
||||||
|
List<IPluginFunction *> m_AddQueue;
|
||||||
|
NextCallInfo m_CopyBacks;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
Loading…
Reference in New Issue
Block a user