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 <IPluginSys.h>
|
||||
#include <IPluginFunction.h>
|
||||
|
||||
#define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager"
|
||||
#define SMINTERFACE_FORWARDMANAGER_VERSION 1
|
||||
@ -24,18 +25,76 @@ namespace SourceMod
|
||||
enum ExecType
|
||||
{
|
||||
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_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.
|
||||
*
|
||||
* NOTE: Parameters should be pushed in forward order, unlike
|
||||
* the virtual machine/IPluginContext order.
|
||||
* NOTE: Some functions are repeated in here because their documentation differs
|
||||
* from their IPluginFunction equivalents.
|
||||
* NOTE: Some functions are repeated in here because their
|
||||
* 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
|
||||
{
|
||||
@ -65,10 +124,25 @@ namespace SourceMod
|
||||
* @brief Executes the forward.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
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:
|
||||
/**
|
||||
* @brief Removes a function from the call list.
|
||||
* NOTE: Only removes one instance.
|
||||
*
|
||||
* @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.
|
||||
@ -92,7 +168,9 @@ namespace SourceMod
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @return True on success, otherwise false.
|
||||
@ -101,7 +179,8 @@ namespace SourceMod
|
||||
|
||||
/**
|
||||
* @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 funcid Function id to add.
|
||||
@ -110,15 +189,24 @@ namespace SourceMod
|
||||
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
|
||||
{
|
||||
Param_Any = 0, //Any type will be accepted
|
||||
Param_Cell = 1, //Only a cell will be accepted
|
||||
Param_Float = 2, //Only a float value will be accepted
|
||||
Param_String = 3, //Only a string will be accepted
|
||||
Param_Array = 4, //Only a 1D array will be accepted
|
||||
Param_VarArgs = 5, //Anything will be accepted
|
||||
ParamTypes_Total = 6,
|
||||
Param_Any = SP_PARAMTYPE_ANY,
|
||||
Param_Cell = SP_PARAMTYPE_CELL,
|
||||
Param_Float = SP_PARAMTYPE_FLOAT,
|
||||
Param_String = SP_PARAMTYPE_STRING,
|
||||
Param_Array = SP_PARAMTYPE_ARRAY,
|
||||
Param_VarArgs = SP_PARAMTYPE_VARARG,
|
||||
Param_CellByRef = SP_PARAMTYPE_CELL|SP_PARAMFLAG_BYREF,
|
||||
Param_FloatByRef = SP_PARAMTYPE_FLOAT|SP_PARAMFLAG_BYREF,
|
||||
};
|
||||
|
||||
class IForwardManager : public SMInterface
|
||||
|
@ -69,7 +69,7 @@ namespace SourceMod
|
||||
*
|
||||
* @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 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.
|
||||
* @return Error code, if any.
|
||||
*/
|
||||
@ -171,6 +171,28 @@ namespace SourceMod
|
||||
* @return Address, or NULL if invalid parameter specified.
|
||||
*/
|
||||
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"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\systems\ForwardSys.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\systems\LibrarySys.cpp"
|
||||
>
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "vm/sp_vm_engine.h"
|
||||
#include <sh_string.h>
|
||||
#include "PluginSys.h"
|
||||
#include "ForwardSys.h"
|
||||
|
||||
SourcePawnEngine g_SourcePawn;
|
||||
SourceModBase g_SourceMod;
|
||||
@ -111,17 +112,21 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
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);
|
||||
IPluginFunction *func = pPlugin->GetFunctionByName("Test");
|
||||
IPluginFunction *func2 = pPlugin->GetFunctionByName("Test2");
|
||||
cell_t result = 2;
|
||||
cell_t val = 6;
|
||||
func->PushCell(1);
|
||||
func->PushCellByRef(&val, SMFUNC_COPYBACK_ONCE);
|
||||
func->Execute(&result, NULL);
|
||||
ParamType types[] = {Param_Cell, Param_CellByRef};
|
||||
va_list ap = va_start(ap, late);
|
||||
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);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr
|
||||
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->size = cells;
|
||||
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].size == 1)
|
||||
{
|
||||
*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
|
||||
} else {
|
||||
memcpy(temp_info[numparams].orig_addr,
|
||||
temp_info[numparams].phys_addr,
|
||||
temp_info[numparams].size * sizeof(cell_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
_skipcopy:
|
||||
base->HeapRelease(temp_info[numparams].local_addr);
|
||||
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