2 * vim: set ts=4 sw=4 tw=99 noet :
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
35 #include "ForwardSys.h"
36 #include "logic_bridge.h"
38 CForwardManager g_Forwards;
41 * Genesis turns to its source, reduction occurs stepwise although the essence is all one.
42 * End of line. FTL system check.
44 * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
46 * - Pushing no varargs
49 // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
50 // so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
52 CForwardManager::~CForwardManager()
54 CStack<CForward *>::iterator iter;
55 for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
59 m_FreeForwards.popall();
62 void CForwardManager::OnSourceModAllInitialized()
64 scripts->AddPluginsListener(this);
65 sharesys->AddInterface(NULL, this);
68 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
74 fwd = CForward::CreateForward(name, et, num_params, types, ap);
80 scripts->AddFunctionsToForward(name, fwd);
82 m_managed.push_back(fwd);
88 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
94 fwd = CForward::CreateForward(name, et, num_params, types, ap);
100 m_unmanaged.push_back(fwd);
106 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
108 /* Attach any globally managed forwards */
109 List<CForward *>::iterator iter;
112 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
115 IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
118 fwd->AddFunction(pFunc);
123 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
125 List<CForward *>::iterator iter;
128 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
131 fwd->RemoveFunctionsOfPlugin(plugin);
134 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
137 fwd->RemoveFunctionsOfPlugin(plugin);
141 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
143 List<CForward *>::iterator iter;
146 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
149 if (strcmp(fwd->GetForwardName(), name) == 0)
159 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
162 if (strcmp(fwd->GetForwardName(), name) == 0)
180 void CForwardManager::ReleaseForward(IForward *forward)
182 ForwardFree(static_cast<CForward *>(forward));
185 void CForwardManager::ForwardFree(CForward *fwd)
192 m_FreeForwards.push(fwd);
193 m_managed.remove(fwd);
196 CForward *CForwardManager::ForwardMake()
199 if (m_FreeForwards.empty())
203 fwd = m_FreeForwards.front();
204 m_FreeForwards.pop();
209 void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
214 /* Attach any globally managed forwards */
215 List<CForward *>::iterator iter;
218 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
221 IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
222 // Only add functions, if they aren't registered yet!
223 if (pFunc && !fwd->IsFunctionRegistered(pFunc))
225 fwd->AddFunction(pFunc);
230 /*************************************
231 * ACTUAL FORWARD API IMPLEMENTATION *
232 *************************************/
234 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
236 ParamType _types[SP_MAX_EXEC_PARAMS];
238 if (num_params > SP_MAX_EXEC_PARAMS)
243 if (types == NULL && num_params)
245 for (unsigned int i=0; i<num_params; i++)
247 _types[i] = (ParamType)va_arg(ap, int);
248 if (_types[i] == Param_VarArgs && (i != num_params - 1))
255 for (unsigned int i=0; i<num_params; i++)
257 _types[i] = types[i];
258 if (types[i] == Param_VarArgs && (i != num_params - 1))
265 /* First parameter can never be varargs */
266 if (num_params && _types[0] == Param_VarArgs)
271 CForward *pForward = g_Forwards.ForwardMake();
272 pForward->m_IterGuard = NULL;
273 pForward->m_curparam = 0;
274 pForward->m_ExecType = et;
275 snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
277 for (unsigned int i=0; i<num_params; i++)
279 pForward->m_types[i] = _types[i];
282 if (num_params && _types[num_params-1] == Param_VarArgs)
284 pForward->m_varargs = num_params--;
286 pForward->m_varargs = false;
289 pForward->m_numparams = num_params;
290 pForward->m_errstate = SP_ERROR_NONE;
292 pForward->m_functions.clear();
297 int CForward::Execute(cell_t *result, IForwardFilter *filter)
301 int err = m_errstate;
306 FuncIter iter = m_functions.begin();
307 IPluginFunction *func;
308 cell_t cur_result = 0;
309 cell_t high_result = 0;
310 cell_t low_result = 0;
312 unsigned int success=0;
313 unsigned int num_params = m_curparam;
314 FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
318 /* Save local, reset */
319 memcpy(temp_info, m_params, sizeof(m_params));
322 FuncIteratorGuard guard(&m_IterGuard, &iter);
324 while (iter != m_functions.end())
329 filter->Preprocess(func, temp_info);
331 for (unsigned int i=0; i<num_params; i++)
333 int err = SP_ERROR_PARAM;
334 param = &temp_info[i];
336 if (i >= m_numparams || m_types[i] == Param_Any)
338 type = param->pushedas;
345 if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
347 /* If we're byref or we're vararg, we always push everything by ref.
348 * Even if they're byval, we must push them byref.
350 if (type == Param_String)
352 err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
354 else if (type == Param_Float || type == Param_Cell)
356 err = func->PushCellByRef(¶m->val);
360 err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
361 assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
366 /* If we're not byref or not vararg, our job is a bit easier. */
367 assert(type == Param_Cell || type == Param_Float);
368 err = func->PushCell(param->val);
371 if (err != SP_ERROR_NONE)
373 logicore.GenerateError(func->GetParentContext(),
374 func->GetFunctionID(),
376 "Failed to push parameter while executing forward");
381 /* Call the function and deal with the return value. */
382 if ((err=func->Execute(&cur_result)) == SP_ERROR_NONE)
389 if (cur_result > high_result)
391 high_result = cur_result;
397 if (cur_result > high_result)
399 high_result = cur_result;
400 if ((ResultType)high_result == Pl_Stop)
409 /* Check if the current result is the lowest so far (or if it's the first result) */
410 if (cur_result < low_result || success == 1)
412 low_result = cur_result;
423 if (!guard.Triggered())
441 cur_result = high_result;
446 cur_result = low_result;
457 *result = cur_result;
461 return SP_ERROR_NONE;
464 int CForward::PushCell(cell_t cell)
466 if (m_curparam < m_numparams)
468 if (m_types[m_curparam] == Param_Any)
470 m_params[m_curparam].pushedas = Param_Cell;
471 } else if (m_types[m_curparam] != Param_Cell) {
472 return SetError(SP_ERROR_PARAM);
475 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
477 return SetError(SP_ERROR_PARAMS_MAX);
479 m_params[m_curparam].pushedas = Param_Cell;
482 m_params[m_curparam++].val = cell;
484 return SP_ERROR_NONE;
487 int CForward::PushFloat(float number)
489 if (m_curparam < m_numparams)
491 if (m_types[m_curparam] == Param_Any)
493 m_params[m_curparam].pushedas = Param_Float;
494 } else if (m_types[m_curparam] != Param_Float) {
495 return SetError(SP_ERROR_PARAM);
498 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
500 return SetError(SP_ERROR_PARAMS_MAX);
502 m_params[m_curparam].pushedas = Param_Float;
505 m_params[m_curparam++].val = *(cell_t *)&number;
507 return SP_ERROR_NONE;
510 int CForward::PushCellByRef(cell_t *cell, int flags)
512 if (m_curparam < m_numparams)
514 if (m_types[m_curparam] == Param_Any)
516 m_params[m_curparam].pushedas = Param_CellByRef;
517 } else if (m_types[m_curparam] != Param_CellByRef) {
518 return SetError(SP_ERROR_PARAM);
521 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
523 return SetError(SP_ERROR_PARAMS_MAX);
525 m_params[m_curparam].pushedas = Param_CellByRef;
528 _Int_PushArray(cell, 1, flags);
531 return SP_ERROR_NONE;
534 int CForward::PushFloatByRef(float *num, int flags)
536 if (m_curparam < m_numparams)
538 if (m_types[m_curparam] == Param_Any)
540 m_params[m_curparam].pushedas = Param_FloatByRef;
541 } else if (m_types[m_curparam] != Param_FloatByRef) {
542 return SetError(SP_ERROR_PARAM);
545 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
547 return SetError(SP_ERROR_PARAMS_MAX);
549 m_params[m_curparam].pushedas = Param_FloatByRef;
552 _Int_PushArray((cell_t *)num, 1, flags);
555 return SP_ERROR_NONE;
558 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
560 m_params[m_curparam].byref.cells = cells;
561 m_params[m_curparam].byref.flags = flags;
562 m_params[m_curparam].byref.orig_addr = inarray;
565 int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
567 /* We don't allow this here */
570 return SetError(SP_ERROR_PARAM);
573 if (m_curparam < m_numparams)
575 if (m_types[m_curparam] == Param_Any)
577 m_params[m_curparam].pushedas = Param_Array;
578 } else if (m_types[m_curparam] != Param_Array) {
579 return SetError(SP_ERROR_PARAM);
582 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
584 return SetError(SP_ERROR_PARAMS_MAX);
586 m_params[m_curparam].pushedas = Param_Array;
589 _Int_PushArray(inarray, cells, flags);
593 return SP_ERROR_NONE;
596 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
598 m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */
599 m_params[m_curparam].byref.flags = cp_flags;
600 m_params[m_curparam].byref.orig_addr = inarray;
601 m_params[m_curparam].byref.sz_flags = sz_flags;
604 int CForward::PushString(const char *string)
606 if (m_curparam < m_numparams)
608 if (m_types[m_curparam] == Param_Any)
610 m_params[m_curparam].pushedas = Param_String;
611 } else if (m_types[m_curparam] != Param_String) {
612 return SetError(SP_ERROR_PARAM);
615 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
617 return SetError(SP_ERROR_PARAMS_MAX);
619 m_params[m_curparam].pushedas = Param_String;
622 _Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
625 return SP_ERROR_NONE;
628 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
630 if (m_curparam < m_numparams)
632 if (m_types[m_curparam] == Param_Any)
634 m_params[m_curparam].pushedas = Param_String;
635 } else if (m_types[m_curparam] != Param_String) {
636 return SetError(SP_ERROR_PARAM);
639 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
641 return SetError(SP_ERROR_PARAMS_MAX);
643 m_params[m_curparam].pushedas = Param_String;
646 _Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
649 return SP_ERROR_NONE;
652 void CForward::Cancel()
660 m_errstate = SP_ERROR_NONE;
663 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
665 IPluginFunction *pFunc = pContext->GetFunctionById(index);
672 return AddFunction(pFunc);
675 bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
677 IPluginFunction *pFunc = pContext->GetFunctionById(index);
684 return RemoveFunction(pFunc);
687 bool CForward::RemoveFunction(IPluginFunction *func)
691 List<IPluginFunction *> *lst;
693 if (func->IsRunnable())
700 for (iter=lst->begin(); iter!=lst->end(); iter++)
704 m_IterGuard->FixIteratorChain(iter);
711 /* Cancel a call, if any */
712 if (found || m_curparam)
720 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
723 IPluginFunction *func;
724 unsigned int removed = 0;
725 IPluginContext *pContext = plugin->GetBaseContext();
726 for (iter=m_functions.begin(); iter!=m_functions.end();)
729 if (func->GetParentContext() == pContext)
731 iter = m_functions.erase(iter);
741 bool CForward::AddFunction(IPluginFunction *func)
748 if (func->IsRunnable())
750 m_functions.push_back(func);
752 m_paused.push_back(func);
758 bool CForward::IsFunctionRegistered(IPluginFunction *func)
761 List<IPluginFunction *> *lst;
763 if (func->IsRunnable())
770 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
780 const char *CForward::GetForwardName()
785 unsigned int CForward::GetFunctionCount()
787 return m_functions.size();
790 ExecType CForward::GetExecType()