Move ForwardSys from core to logic (bug 5953, r=fyren).
--HG-- rename : core/ForwardSys.cpp => core/logic/ForwardSys.cpp rename : core/ForwardSys.h => core/logic/ForwardSys.h
This commit is contained in:
@@ -63,6 +63,7 @@ files = [
|
||||
'DebugReporter.cpp',
|
||||
'Database.cpp',
|
||||
'smn_database.cpp',
|
||||
'ForwardSys.cpp',
|
||||
]
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
files.append('thread/WinThreads.cpp')
|
||||
|
||||
@@ -0,0 +1,794 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "ForwardSys.h"
|
||||
#include "DebugReporter.h"
|
||||
#include "common_logic.h"
|
||||
|
||||
CForwardManager g_Forwards;
|
||||
|
||||
/**
|
||||
* Genesis turns to its source, reduction occurs stepwise although the essence is all one.
|
||||
* End of line. FTL system check.
|
||||
*
|
||||
* :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
|
||||
* VARARG FUNCTIONS:
|
||||
* - Pushing no varargs
|
||||
*/
|
||||
|
||||
// :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
|
||||
// so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
|
||||
|
||||
CForwardManager::~CForwardManager()
|
||||
{
|
||||
CStack<CForward *>::iterator iter;
|
||||
for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
|
||||
{
|
||||
delete (*iter);
|
||||
}
|
||||
m_FreeForwards.popall();
|
||||
}
|
||||
|
||||
void CForwardManager::OnSourceModAllInitialized()
|
||||
{
|
||||
scripts->AddPluginsListener(this);
|
||||
sharesys->AddInterface(NULL, this);
|
||||
}
|
||||
|
||||
IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
|
||||
{
|
||||
CForward *fwd;
|
||||
va_list ap;
|
||||
va_start(ap, types);
|
||||
|
||||
fwd = CForward::CreateForward(name, et, num_params, types, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if (fwd)
|
||||
{
|
||||
scripts->AddFunctionsToForward(name, fwd);
|
||||
|
||||
m_managed.push_back(fwd);
|
||||
}
|
||||
|
||||
return fwd;
|
||||
}
|
||||
|
||||
IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
|
||||
{
|
||||
CForward *fwd;
|
||||
va_list ap;
|
||||
va_start(ap, types);
|
||||
|
||||
fwd = CForward::CreateForward(name, et, num_params, types, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if (fwd)
|
||||
{
|
||||
m_unmanaged.push_back(fwd);
|
||||
}
|
||||
|
||||
return fwd;
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginLoaded(IPlugin *plugin)
|
||||
{
|
||||
/* Attach any globally managed forwards */
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
|
||||
if (pFunc)
|
||||
{
|
||||
fwd->AddFunction(pFunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
fwd->RemoveFunctionsOfPlugin(plugin);
|
||||
}
|
||||
|
||||
for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
fwd->RemoveFunctionsOfPlugin(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
|
||||
{
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
if (strcmp(fwd->GetForwardName(), name) == 0)
|
||||
{
|
||||
if (ifchng)
|
||||
{
|
||||
*ifchng = NULL;
|
||||
}
|
||||
return fwd;
|
||||
}
|
||||
}
|
||||
|
||||
for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
if (strcmp(fwd->GetForwardName(), name) == 0)
|
||||
{
|
||||
if (ifchng)
|
||||
{
|
||||
*ifchng = fwd;
|
||||
}
|
||||
return fwd;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifchng)
|
||||
{
|
||||
*ifchng = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CForwardManager::ReleaseForward(IForward *forward)
|
||||
{
|
||||
ForwardFree(static_cast<CForward *>(forward));
|
||||
}
|
||||
|
||||
void CForwardManager::ForwardFree(CForward *fwd)
|
||||
{
|
||||
if (fwd == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_FreeForwards.push(fwd);
|
||||
m_managed.remove(fwd);
|
||||
}
|
||||
|
||||
CForward *CForwardManager::ForwardMake()
|
||||
{
|
||||
CForward *fwd;
|
||||
if (m_FreeForwards.empty())
|
||||
{
|
||||
fwd = new CForward;
|
||||
} else {
|
||||
fwd = m_FreeForwards.front();
|
||||
m_FreeForwards.pop();
|
||||
}
|
||||
return fwd;
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
|
||||
{
|
||||
if(paused)
|
||||
return;
|
||||
|
||||
/* Attach any globally managed forwards */
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
|
||||
// Only add functions, if they aren't registered yet!
|
||||
if (pFunc && !fwd->IsFunctionRegistered(pFunc))
|
||||
{
|
||||
fwd->AddFunction(pFunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* ACTUAL FORWARD API IMPLEMENTATION *
|
||||
*************************************/
|
||||
|
||||
CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const 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] = (ParamType)va_arg(ap, int);
|
||||
if (_types[i] == Param_VarArgs && (i != num_params - 1))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
types = _types;
|
||||
} else {
|
||||
for (unsigned int i=0; i<num_params; i++)
|
||||
{
|
||||
_types[i] = types[i];
|
||||
if (types[i] == Param_VarArgs && (i != num_params - 1))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* First parameter can never be varargs */
|
||||
if (num_params && _types[0] == Param_VarArgs)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CForward *pForward = g_Forwards.ForwardMake();
|
||||
pForward->m_IterGuard = NULL;
|
||||
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 = num_params--;
|
||||
} else {
|
||||
pForward->m_varargs = false;
|
||||
}
|
||||
|
||||
pForward->m_numparams = num_params;
|
||||
pForward->m_errstate = SP_ERROR_NONE;
|
||||
|
||||
pForward->m_functions.clear();
|
||||
|
||||
return pForward;
|
||||
}
|
||||
|
||||
int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
{
|
||||
if (m_errstate)
|
||||
{
|
||||
int err = m_errstate;
|
||||
Cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
FuncIter iter = m_functions.begin();
|
||||
IPluginFunction *func;
|
||||
cell_t cur_result = 0;
|
||||
cell_t high_result = 0;
|
||||
cell_t low_result = 0;
|
||||
int err;
|
||||
unsigned int success=0;
|
||||
unsigned int num_params = m_curparam;
|
||||
FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||
FwdParamInfo *param;
|
||||
ParamType type;
|
||||
|
||||
/* Save local, reset */
|
||||
memcpy(temp_info, m_params, sizeof(m_params));
|
||||
m_curparam = 0;
|
||||
|
||||
FuncIteratorGuard guard(&m_IterGuard, &iter);
|
||||
|
||||
while (iter != m_functions.end())
|
||||
{
|
||||
func = (*iter);
|
||||
|
||||
if (filter)
|
||||
filter->Preprocess(func, temp_info);
|
||||
|
||||
for (unsigned int i=0; i<num_params; i++)
|
||||
{
|
||||
int err = SP_ERROR_PARAM;
|
||||
param = &temp_info[i];
|
||||
|
||||
if (i >= m_numparams || m_types[i] == Param_Any)
|
||||
{
|
||||
type = param->pushedas;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = m_types[i];
|
||||
}
|
||||
|
||||
if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
|
||||
{
|
||||
/* If we're byref or we're vararg, we always push everything by ref.
|
||||
* Even if they're byval, we must push them byref.
|
||||
*/
|
||||
if (type == Param_String)
|
||||
{
|
||||
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)
|
||||
{
|
||||
err = func->PushCellByRef(¶m->val);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
|
||||
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we're not byref or not vararg, our job is a bit easier. */
|
||||
assert(type == Param_Cell || type == Param_Float);
|
||||
err = func->PushCell(param->val);
|
||||
}
|
||||
|
||||
if (err != SP_ERROR_NONE)
|
||||
{
|
||||
g_DbgReporter.GenerateError(func->GetParentContext(),
|
||||
func->GetFunctionID(),
|
||||
err,
|
||||
"Failed to push parameter while executing forward");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the function and deal with the return value. */
|
||||
if ((err=func->Execute(&cur_result)) == SP_ERROR_NONE)
|
||||
{
|
||||
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)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ET_LowEvent:
|
||||
{
|
||||
/* Check if the current result is the lowest so far (or if it's the first result) */
|
||||
if (cur_result < low_result || success == 1)
|
||||
{
|
||||
low_result = cur_result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!guard.Triggered())
|
||||
iter++;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (success)
|
||||
{
|
||||
switch (m_ExecType)
|
||||
{
|
||||
case ET_Ignore:
|
||||
{
|
||||
cur_result = 0;
|
||||
break;
|
||||
}
|
||||
case ET_Event:
|
||||
case ET_Hook:
|
||||
{
|
||||
cur_result = high_result;
|
||||
break;
|
||||
}
|
||||
case ET_LowEvent:
|
||||
{
|
||||
cur_result = low_result;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
*result = cur_result;
|
||||
}
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushCell(cell_t cell)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_Cell;
|
||||
} else if (m_types[m_curparam] != Param_Cell) {
|
||||
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_Cell;
|
||||
}
|
||||
|
||||
m_params[m_curparam++].val = cell;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushFloat(float number)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_Float;
|
||||
} else if (m_types[m_curparam] != Param_Float) {
|
||||
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_Float;
|
||||
}
|
||||
|
||||
m_params[m_curparam++].val = *(cell_t *)&number;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushCellByRef(cell_t *cell, int flags)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_CellByRef;
|
||||
} else if (m_types[m_curparam] != Param_CellByRef) {
|
||||
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_CellByRef;
|
||||
}
|
||||
|
||||
_Int_PushArray(cell, 1, 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_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_FloatByRef;
|
||||
} else if (m_types[m_curparam] != Param_FloatByRef) {
|
||||
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_FloatByRef;
|
||||
}
|
||||
|
||||
_Int_PushArray((cell_t *)num, 1, flags);
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int CForward::PushArray(cell_t *inarray, unsigned int cells, 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_params[m_curparam].pushedas = Param_Array;
|
||||
} else if (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);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_Array;
|
||||
}
|
||||
|
||||
_Int_PushArray(inarray, cells, flags);
|
||||
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
|
||||
{
|
||||
m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */
|
||||
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;
|
||||
}
|
||||
|
||||
int CForward::PushString(const char *string)
|
||||
{
|
||||
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_curparam > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
}
|
||||
|
||||
_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
|
||||
{
|
||||
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_curparam > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
}
|
||||
|
||||
_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void CForward::Cancel()
|
||||
{
|
||||
if (!m_curparam)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_curparam = 0;
|
||||
m_errstate = SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
|
||||
{
|
||||
IPluginFunction *pFunc = pContext->GetFunctionById(index);
|
||||
|
||||
if (!pFunc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return AddFunction(pFunc);
|
||||
}
|
||||
|
||||
bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
|
||||
{
|
||||
IPluginFunction *pFunc = pContext->GetFunctionById(index);
|
||||
|
||||
if (!pFunc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return RemoveFunction(pFunc);
|
||||
}
|
||||
|
||||
bool CForward::RemoveFunction(IPluginFunction *func)
|
||||
{
|
||||
bool found = false;
|
||||
FuncIter iter;
|
||||
List<IPluginFunction *> *lst;
|
||||
|
||||
if (func->IsRunnable())
|
||||
{
|
||||
lst = &m_functions;
|
||||
} else {
|
||||
lst = &m_paused;
|
||||
}
|
||||
|
||||
for (iter=lst->begin(); iter!=lst->end(); iter++)
|
||||
{
|
||||
if ((*iter) == func)
|
||||
{
|
||||
m_IterGuard->FixIteratorChain(iter);
|
||||
found = true;
|
||||
lst->erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cancel a call, if any */
|
||||
if (found || m_curparam)
|
||||
{
|
||||
func->Cancel();
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
|
||||
{
|
||||
FuncIter iter;
|
||||
IPluginFunction *func;
|
||||
unsigned int removed = 0;
|
||||
IPluginContext *pContext = plugin->GetBaseContext();
|
||||
for (iter=m_functions.begin(); iter!=m_functions.end();)
|
||||
{
|
||||
func = (*iter);
|
||||
if (func->GetParentContext() == pContext)
|
||||
{
|
||||
iter = m_functions.erase(iter);
|
||||
removed++;
|
||||
} else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool CForward::AddFunction(IPluginFunction *func)
|
||||
{
|
||||
if (m_curparam)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (func->IsRunnable())
|
||||
{
|
||||
m_functions.push_back(func);
|
||||
} else {
|
||||
m_paused.push_back(func);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CForward::IsFunctionRegistered(IPluginFunction *func)
|
||||
{
|
||||
FuncIter iter;
|
||||
List<IPluginFunction *> *lst;
|
||||
|
||||
if (func->IsRunnable())
|
||||
{
|
||||
lst = &m_functions;
|
||||
} else {
|
||||
lst = &m_paused;
|
||||
}
|
||||
|
||||
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||
{
|
||||
if ((*iter) == func)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *CForward::GetForwardName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
unsigned int CForward::GetFunctionCount()
|
||||
{
|
||||
return m_functions.size();
|
||||
}
|
||||
|
||||
ExecType CForward::GetExecType()
|
||||
{
|
||||
return m_ExecType;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||
#define _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||
|
||||
#include <IForwardSys.h>
|
||||
#include <IPluginSys.h>
|
||||
#include "common_logic.h"
|
||||
#include <sh_list.h>
|
||||
#include <sh_stack.h>
|
||||
#include "ISourceMod.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
|
||||
|
||||
class FuncIteratorGuard
|
||||
{
|
||||
bool triggered;
|
||||
FuncIteratorGuard **pprev;
|
||||
FuncIter *iter;
|
||||
FuncIteratorGuard *next;
|
||||
public:
|
||||
FuncIteratorGuard(FuncIteratorGuard **pprev, FuncIter *iter)
|
||||
: triggered(false), pprev(pprev), iter(iter), next(*pprev)
|
||||
{
|
||||
*pprev = this;
|
||||
}
|
||||
|
||||
~FuncIteratorGuard()
|
||||
{
|
||||
*pprev = next;
|
||||
}
|
||||
|
||||
inline bool Triggered()
|
||||
{
|
||||
bool t = triggered;
|
||||
triggered = false;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* This should not read from |this| before the NULL check, because FwdSys
|
||||
* can call (NULL)->FixIteratorChain().
|
||||
*/
|
||||
void FixIteratorChain(FuncIter &other)
|
||||
{
|
||||
FuncIteratorGuard *guard = this;
|
||||
while (guard != NULL)
|
||||
{
|
||||
if (*guard->iter == other)
|
||||
{
|
||||
*(guard->iter) = ++(*(guard->iter));
|
||||
guard->triggered = true;
|
||||
}
|
||||
guard = guard->next;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class CForward : public IChangeableForward
|
||||
{
|
||||
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 PushArray(cell_t *inarray, unsigned int cells, int flags);
|
||||
virtual int PushString(const char *string);
|
||||
virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_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(IPluginContext *ctx, funcid_t index);
|
||||
virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index);
|
||||
public:
|
||||
static CForward *CreateForward(const char *name,
|
||||
ExecType et,
|
||||
unsigned int num_params,
|
||||
const ParamType *types,
|
||||
va_list ap);
|
||||
bool IsFunctionRegistered(IPluginFunction *func);
|
||||
private:
|
||||
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
|
||||
void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_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.
|
||||
*/
|
||||
mutable List<IPluginFunction *> m_functions;
|
||||
mutable List<IPluginFunction *> m_paused;
|
||||
FuncIteratorGuard *m_IterGuard;
|
||||
|
||||
/* Type and name information */
|
||||
FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
|
||||
ParamType m_types[SP_MAX_EXEC_PARAMS];
|
||||
char m_name[FORWARDS_NAME_MAX+1];
|
||||
unsigned int m_numparams;
|
||||
unsigned int m_varargs;
|
||||
ExecType m_ExecType;
|
||||
|
||||
/* State information */
|
||||
unsigned int m_curparam;
|
||||
int m_errstate;
|
||||
};
|
||||
|
||||
class CForwardManager :
|
||||
public IForwardManager,
|
||||
public IPluginsListener,
|
||||
public SMGlobalClass
|
||||
{
|
||||
friend class CForward;
|
||||
public:
|
||||
~CForwardManager();
|
||||
public: //IForwardManager
|
||||
IForward *CreateForward(const char *name,
|
||||
ExecType et,
|
||||
unsigned int num_params,
|
||||
const ParamType *types,
|
||||
...);
|
||||
IChangeableForward *CreateForwardEx(const char *name,
|
||||
ExecType et,
|
||||
int num_params,
|
||||
const ParamType *types,
|
||||
...);
|
||||
IForward *FindForward(const char *name, IChangeableForward **ifchng);
|
||||
void ReleaseForward(IForward *forward);
|
||||
public: //IPluginsListener
|
||||
void OnPluginLoaded(IPlugin *plugin);
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
void OnPluginPauseChange(IPlugin *plugin, bool paused);
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
protected:
|
||||
CForward *ForwardMake();
|
||||
void ForwardFree(CForward *fwd);
|
||||
private:
|
||||
CStack<CForward *> m_FreeForwards;
|
||||
List<CForward *> m_managed;
|
||||
List<CForward *> m_unmanaged;
|
||||
};
|
||||
|
||||
extern CForwardManager g_Forwards;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "NativeOwner.h"
|
||||
#include "HandleSys.h"
|
||||
#include "ExtensionSys.h"
|
||||
#include "ForwardSys.h"
|
||||
|
||||
sm_core_t smcore;
|
||||
IHandleSys *handlesys = &g_HandleSys;
|
||||
@@ -60,7 +61,7 @@ IVEngineServer *engine;
|
||||
IShareSys *sharesys = &g_ShareSys;
|
||||
IRootConsole *rootmenu;
|
||||
IPluginManager *pluginsys = g_PluginSys.GetOldAPI();
|
||||
IForwardManager *forwardsys;
|
||||
IForwardManager *forwardsys = &g_Forwards;
|
||||
ITimerSystem *timersys;
|
||||
ServerGlobals serverGlobals;
|
||||
IPlayerManager *playerhelpers;
|
||||
@@ -124,6 +125,7 @@ static sm_logic_t logic =
|
||||
&g_ShareSys,
|
||||
&g_Extensions,
|
||||
&g_HandleSys,
|
||||
&g_Forwards,
|
||||
NULL,
|
||||
-1.0f
|
||||
};
|
||||
@@ -140,7 +142,6 @@ static void logic_init(const sm_core_t* core, sm_logic_t* _logic)
|
||||
engine = core->engine;
|
||||
g_pSM = core->sm;
|
||||
rootmenu = core->rootmenu;
|
||||
forwardsys = core->forwardsys;
|
||||
timersys = core->timersys;
|
||||
playerhelpers = core->playerhelpers;
|
||||
adminsys = core->adminsys;
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <sp_vm_api.h>
|
||||
#include <sh_vector.h>
|
||||
#include <IExtensionSys.h>
|
||||
#include <IForwardSys.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourcePawn;
|
||||
@@ -50,7 +51,7 @@ using namespace SourceHook;
|
||||
* Add 1 to the RHS of this expression to bump the intercom file
|
||||
* This is to prevent mismatching core/logic binaries
|
||||
*/
|
||||
#define SM_LOGIC_MAGIC (0x0F47C0DE - 24)
|
||||
#define SM_LOGIC_MAGIC (0x0F47C0DE - 25)
|
||||
|
||||
#if defined SM_LOGIC
|
||||
class IVEngineServer
|
||||
@@ -229,7 +230,6 @@ struct sm_core_t
|
||||
IVEngineServer *engine;
|
||||
IFileSystem *filesystem;
|
||||
IRootConsole *rootmenu;
|
||||
IForwardManager *forwardsys;
|
||||
ITimerSystem *timersys;
|
||||
IPlayerManager *playerhelpers;
|
||||
IAdminSystem *adminsys;
|
||||
@@ -298,6 +298,7 @@ struct sm_logic_t
|
||||
IShareSys *sharesys;
|
||||
IExtensionSys *extsys;
|
||||
IHandleSys *handlesys;
|
||||
IForwardManager *forwardsys;
|
||||
IdentityToken_t *core_ident;
|
||||
float sentinel;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user