2 * ===============================================================
3 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
4 * ===============================================================
6 * This file is not open source and may not be copied without explicit
7 * written permission of AlliedModders LLC. This file may not be redistributed
8 * in whole or significant part.
9 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
17 #include "ForwardSys.h"
18 #include "PluginSys.h"
21 CForwardManager g_Forwards;
24 * Gensis turns to its source, reduction occurs stepwise although the essence is all one.
25 * End of line. FTL system check.
27 * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
29 * - Pushing no varargs
32 // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
33 // so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
35 void CForwardManager::OnSourceModAllInitialized()
37 g_PluginSys.AddPluginsListener(this);
38 g_ShareSys.AddInterface(NULL, this);
41 void CForwardManager::OnSourceModShutdown()
43 g_PluginSys.RemovePluginsListener(this);
46 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
52 fwd = CForward::CreateForward(name, et, num_params, types, ap);
58 m_managed.push_back(fwd);
64 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
70 fwd = CForward::CreateForward(name, et, num_params, types, ap);
76 m_unmanaged.push_back(fwd);
82 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
84 /* Attach any globally managed forwards */
85 List<CForward *>::iterator iter;
88 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
91 IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
94 fwd->AddFunction(pFunc);
99 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
101 List<CForward *>::iterator iter;
104 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
107 fwd->RemoveFunctionsOfPlugin(plugin);
110 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
113 fwd->RemoveFunctionsOfPlugin(plugin);
117 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
119 List<CForward *>::iterator iter;
122 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
125 if (strcmp(fwd->GetForwardName(), name) == 0)
135 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
138 if (strcmp(fwd->GetForwardName(), name) == 0)
156 void CForwardManager::ReleaseForward(IForward *forward)
158 ForwardFree(static_cast<CForward *>(forward));
161 void CForwardManager::ForwardFree(CForward *fwd)
163 m_FreeForwards.push(fwd);
164 m_managed.remove(fwd);
167 CForward *CForwardManager::ForwardMake()
170 if (m_FreeForwards.empty())
174 fwd = m_FreeForwards.front();
175 m_FreeForwards.pop();
180 void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
185 /*************************************
186 * ACTUAL FORWARD API IMPLEMENTATION *
187 *************************************/
189 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
191 ParamType _types[SP_MAX_EXEC_PARAMS];
193 if (num_params > SP_MAX_EXEC_PARAMS)
198 if (types == NULL && num_params)
200 for (unsigned int i=0; i<num_params; i++)
202 _types[i] = (ParamType)va_arg(ap, int);
203 if (_types[i] == Param_VarArgs && (i != num_params - 1))
210 for (unsigned int i=0; i<num_params; i++)
212 _types[i] = types[i];
213 if (types[i] == Param_VarArgs && (i != num_params - 1))
220 /* First parameter can never be varargs */
221 if (num_params && _types[0] == Param_VarArgs)
226 CForward *pForward = g_Forwards.ForwardMake();
227 pForward->m_curparam = 0;
228 pForward->m_ExecType = et;
229 snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
231 for (unsigned int i=0; i<num_params; i++)
233 pForward->m_types[i] = _types[i];
236 if (num_params && _types[num_params-1] == Param_VarArgs)
238 pForward->m_varargs = num_params--;
240 pForward->m_varargs = false;
243 pForward->m_numparams = num_params;
244 pForward->m_errstate = SP_ERROR_NONE;
249 int CForward::Execute(cell_t *result, IForwardFilter *filter)
253 int err = m_errstate;
260 filter->OnExecuteBegin();
263 FuncIter iter = m_functions.begin();
264 IPluginFunction *func;
265 cell_t cur_result = 0;
266 cell_t high_result = 0;
268 unsigned int failed=0, success=0;
269 unsigned int num_params = m_curparam;
270 FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
274 /* Save local, reset */
275 memcpy(temp_info, m_params, sizeof(m_params));
278 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
282 for (unsigned int i=0; i<num_params; i++)
284 param = &temp_info[i];
285 if (i >= m_numparams || m_types[i] == Param_Any)
287 type = param->pushedas;
291 if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
293 /* If we're byref or we're vararg, we always push everything by ref.
294 * Even if they're byval, we must push them byref.
296 if (type == Param_String)
298 func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
299 } else if (type == Param_Float || type == Param_Cell) {
300 func->PushCellByRef(¶m->val);
302 func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
303 assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
306 /* If we're not byref or not vararg, our job is a bit easier. */
307 assert(type == Param_Cell || type == Param_Float);
308 func->PushCell(param->val);
312 /* Call the function and deal with the return value. */
313 if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
315 bool handled = false;
318 handled = filter->OnErrorReport(this, func, err);
322 /* :TODO: invoke global error reporting here */
331 if (cur_result > high_result)
333 high_result = cur_result;
339 if (cur_result > high_result)
341 high_result = cur_result;
342 if ((ResultType)high_result == Pl_Stop)
344 iter = m_functions.end();
354 if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
356 iter = m_functions.end();
371 if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
373 cur_result = high_result;
374 } else if (m_ExecType == ET_Ignore) {
379 *result = cur_result;
385 filter->OnExecuteEnd(&cur_result, success, failed);
388 return SP_ERROR_NONE;
391 int CForward::PushCell(cell_t cell)
393 if (m_curparam < m_numparams)
395 if (m_types[m_curparam] == Param_Any)
397 m_params[m_curparam].pushedas = Param_Cell;
398 } else if (m_types[m_curparam] != Param_Cell) {
399 return SetError(SP_ERROR_PARAM);
402 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
404 return SetError(SP_ERROR_PARAMS_MAX);
406 m_params[m_curparam].pushedas = Param_Cell;
409 m_params[m_curparam++].val = cell;
411 return SP_ERROR_NONE;
414 int CForward::PushFloat(float number)
416 if (m_curparam < m_numparams)
418 if (m_types[m_curparam] == Param_Any)
420 m_params[m_curparam].pushedas = Param_Float;
421 } else if (m_types[m_curparam] != Param_Float) {
422 return SetError(SP_ERROR_PARAM);
425 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
427 return SetError(SP_ERROR_PARAMS_MAX);
429 m_params[m_curparam].pushedas = Param_Float;
432 m_params[m_curparam++].val = *(cell_t *)&number;
434 return SP_ERROR_NONE;
437 int CForward::PushCellByRef(cell_t *cell)
439 if (m_curparam < m_numparams)
441 if (m_types[m_curparam] == Param_Any)
443 m_params[m_curparam].pushedas = Param_CellByRef;
444 } else if (m_types[m_curparam] != Param_CellByRef) {
445 return SetError(SP_ERROR_PARAM);
448 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
450 return SetError(SP_ERROR_PARAMS_MAX);
452 m_params[m_curparam].pushedas = Param_CellByRef;
455 _Int_PushArray(cell, 1, SM_PARAM_COPYBACK);
458 return SP_ERROR_NONE;
461 int CForward::PushFloatByRef(float *num)
463 if (m_curparam < m_numparams)
465 if (m_types[m_curparam] == Param_Any)
467 m_params[m_curparam].pushedas = Param_FloatByRef;
468 } else if (m_types[m_curparam] != Param_FloatByRef) {
469 return SetError(SP_ERROR_PARAM);
472 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
474 return SetError(SP_ERROR_PARAMS_MAX);
476 m_params[m_curparam].pushedas = Param_FloatByRef;
479 _Int_PushArray((cell_t *)num, 1, SM_PARAM_COPYBACK);
482 return SP_ERROR_NONE;
485 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
487 m_params[m_curparam].byref.cells = cells;
488 m_params[m_curparam].byref.flags = flags;
489 m_params[m_curparam].byref.orig_addr = inarray;
492 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
494 /* We don't allow this here */
497 return SetError(SP_ERROR_PARAM);
500 if (m_curparam < m_numparams)
502 if (m_types[m_curparam] == Param_Any)
504 m_params[m_curparam].pushedas = Param_Array;
505 } else if (m_types[m_curparam] != Param_Array) {
506 return SetError(SP_ERROR_PARAM);
509 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
511 return SetError(SP_ERROR_PARAMS_MAX);
513 m_params[m_curparam].pushedas = Param_Array;
521 _Int_PushArray(inarray, cells, flags);
525 return SP_ERROR_NONE;
528 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
530 m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */
531 m_params[m_curparam].byref.flags = cp_flags;
532 m_params[m_curparam].byref.orig_addr = inarray;
533 m_params[m_curparam].byref.sz_flags = sz_flags;
536 int CForward::PushString(const char *string)
538 if (m_curparam < m_numparams)
540 if (m_types[m_curparam] == Param_Any)
542 m_params[m_curparam].pushedas = Param_String;
543 } else if (m_types[m_curparam] != Param_String) {
544 return SetError(SP_ERROR_PARAM);
547 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
549 return SetError(SP_ERROR_PARAMS_MAX);
551 m_params[m_curparam].pushedas = Param_String;
554 _Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
557 return SP_ERROR_NONE;
560 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
562 if (m_curparam < m_numparams)
564 if (m_types[m_curparam] == Param_Any)
566 m_params[m_curparam].pushedas = Param_String;
567 } else if (m_types[m_curparam] != Param_String) {
568 return SetError(SP_ERROR_PARAM);
571 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
573 return SetError(SP_ERROR_PARAMS_MAX);
575 m_params[m_curparam].pushedas = Param_String;
578 _Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
581 return SP_ERROR_NONE;
584 void CForward::Cancel()
592 m_errstate = SP_ERROR_NONE;
595 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
597 IPluginFunction *pFunc = pContext->GetFunctionById(index);
604 return AddFunction(pFunc);
607 bool CForward::RemoveFunction(IPluginFunction *func)
611 List<IPluginFunction *> *lst;
613 if (func->IsRunnable())
620 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
630 /* Cancel a call, if any */
631 if (found || m_curparam)
639 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
642 IPluginFunction *func;
643 unsigned int removed = 0;
644 IPluginContext *pContext = plugin->GetBaseContext();
645 for (iter=m_functions.begin(); iter!=m_functions.end();)
648 if (func->GetParentContext() == pContext)
650 iter = m_functions.erase(iter);
660 bool CForward::AddFunction(IPluginFunction *func)
667 if (func->IsRunnable())
669 m_functions.push_back(func);
671 m_paused.push_back(func);
677 const char *CForward::GetForwardName() const
682 unsigned int CForward::GetFunctionCount() const
684 return m_functions.size();
687 ExecType CForward::GetExecType() const