core/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Thu Oct 29 01:33:57 2009 -0700 (2009-10-29)
changeset 2846 5e176efe7927
parent 2411 8dfaa3d730b5
child 2883 1d7b415cef73
permissions -rw-r--r--
Use GetSourceEngineBuild() from MM:S 1.8 legacy API (bug 4083, r=ds).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     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.
    11  * 
    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
    15  * details.
    16  *
    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/>.
    19  *
    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>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <assert.h>
    33 #include <stdarg.h>
    34 #include <string.h>
    35 #include "ForwardSys.h"
    36 #include "PluginSys.h"
    37 #include "ShareSys.h"
    38 #include "DebugReporter.h"
    39 
    40 CForwardManager g_Forwards;
    41 
    42 /**
    43  * Genesis turns to its source, reduction occurs stepwise although the essence is all one.
    44  * End of line.  FTL system check.
    45  *
    46  * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
    47  * VARARG FUNCTIONS:
    48  * - Pushing no varargs
    49  */
    50 
    51 // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
    52 // so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
    53 
    54 CForwardManager::~CForwardManager()
    55 {
    56 	CStack<CForward *>::iterator iter;
    57 	for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
    58 	{
    59 		delete (*iter);
    60 	}
    61 	m_FreeForwards.popall();
    62 }
    63 
    64 void CForwardManager::OnSourceModAllInitialized()
    65 {
    66 	g_PluginSys.AddPluginsListener(this);
    67 	g_ShareSys.AddInterface(NULL, this);
    68 }
    69 
    70 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
    71 {
    72 	CForward *fwd;
    73 	va_list ap;
    74 	va_start(ap, types);
    75 	
    76 	fwd = CForward::CreateForward(name, et, num_params, types, ap);
    77 
    78 	va_end(ap);
    79 
    80 	if (fwd)
    81 	{
    82 		g_PluginSys.AddFunctionsToForward(name, fwd);
    83 
    84 		m_managed.push_back(fwd);
    85 	}
    86 
    87 	return fwd;
    88 }
    89 
    90 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
    91 {
    92 	CForward *fwd;
    93 	va_list ap;
    94 	va_start(ap, types);
    95 
    96 	fwd = CForward::CreateForward(name, et, num_params, types, ap);
    97 
    98 	va_end(ap);
    99 
   100 	if (fwd)
   101 	{
   102 		m_unmanaged.push_back(fwd);
   103 	}
   104 
   105 	return fwd;
   106 }
   107 
   108 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
   109 {
   110 	/* Attach any globally managed forwards */
   111 	List<CForward *>::iterator iter;
   112 	CForward *fwd;
   113 
   114 	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   115 	{
   116 		fwd = (*iter);
   117 		IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
   118 		if (pFunc)
   119 		{
   120 			fwd->AddFunction(pFunc);
   121 		}
   122 	}
   123 }
   124 
   125 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
   126 {
   127 	List<CForward *>::iterator iter;
   128 	CForward *fwd;
   129 
   130 	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   131 	{
   132 		fwd = (*iter);
   133 		fwd->RemoveFunctionsOfPlugin(plugin);
   134 	}
   135 
   136 	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   137 	{
   138 		fwd = (*iter);
   139 		fwd->RemoveFunctionsOfPlugin(plugin);
   140 	}
   141 }
   142 
   143 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
   144 {
   145 	List<CForward *>::iterator iter;
   146 	CForward *fwd;
   147 
   148 	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   149 	{
   150 		fwd = (*iter);
   151 		if (strcmp(fwd->GetForwardName(), name) == 0)
   152 		{
   153 			if (ifchng)
   154 			{
   155 				*ifchng = NULL;
   156 			}
   157 			return fwd;
   158 		}
   159 	}
   160 
   161 	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   162 	{
   163 		fwd = (*iter);
   164 		if (strcmp(fwd->GetForwardName(), name) == 0)
   165 		{
   166 			if (ifchng)
   167 			{
   168 				*ifchng = fwd;
   169 			}
   170 			return fwd;
   171 		}
   172 	}
   173 
   174 	if (ifchng)
   175 	{
   176 		*ifchng = NULL;
   177 	}
   178 
   179 	return NULL;
   180 }
   181 
   182 void CForwardManager::ReleaseForward(IForward *forward)
   183 {
   184 	ForwardFree(static_cast<CForward *>(forward));
   185 }
   186 
   187 void CForwardManager::ForwardFree(CForward *fwd)
   188 {
   189     if (fwd == NULL)
   190     {
   191         return;
   192     }
   193 
   194 	m_FreeForwards.push(fwd);
   195 	m_managed.remove(fwd);
   196 }
   197 
   198 CForward *CForwardManager::ForwardMake()
   199 {
   200 	CForward *fwd;
   201 	if (m_FreeForwards.empty())
   202 	{
   203 		fwd = new CForward;
   204 	} else {
   205 		fwd = m_FreeForwards.front();
   206 		m_FreeForwards.pop();
   207 	}
   208 	return fwd;
   209 }
   210 
   211 void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
   212 {
   213 	/* No longer used */
   214 }
   215 
   216 /*************************************
   217  * ACTUAL FORWARD API IMPLEMENTATION *
   218  *************************************/
   219 
   220 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
   221 {
   222 	ParamType _types[SP_MAX_EXEC_PARAMS];
   223 
   224 	if (num_params > SP_MAX_EXEC_PARAMS)
   225 	{
   226 		return NULL;
   227 	}
   228 	
   229 	if (types == NULL && num_params)
   230 	{
   231 		for (unsigned int i=0; i<num_params; i++)
   232 		{
   233 			_types[i] = (ParamType)va_arg(ap, int);
   234 			if (_types[i] == Param_VarArgs && (i != num_params - 1))
   235 			{
   236 				return NULL;
   237 			}
   238 		}
   239 		types = _types;
   240 	} else {
   241 		for (unsigned int i=0; i<num_params; i++)
   242 		{
   243 			_types[i] = types[i];
   244 			if (types[i] == Param_VarArgs && (i != num_params - 1))
   245 			{
   246 				return NULL;
   247 			}
   248 		}
   249 	}
   250 
   251 	/* First parameter can never be varargs */
   252 	if (num_params && _types[0] == Param_VarArgs)
   253 	{
   254 		return NULL;
   255 	}
   256 
   257 	CForward *pForward = g_Forwards.ForwardMake();
   258 	pForward->m_curparam = 0;
   259 	pForward->m_ExecType = et;
   260 	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
   261 	
   262 	for (unsigned int i=0; i<num_params; i++)
   263 	{
   264 		pForward->m_types[i] = _types[i];
   265 	}
   266 
   267 	if (num_params && _types[num_params-1] == Param_VarArgs)
   268 	{
   269 		pForward->m_varargs = num_params--;
   270 	} else {
   271 		pForward->m_varargs = false;
   272 	}
   273 
   274 	pForward->m_numparams = num_params;
   275 	pForward->m_errstate = SP_ERROR_NONE;
   276 
   277 	pForward->m_functions.clear();
   278 
   279 	return pForward;
   280 }
   281 
   282 int CForward::Execute(cell_t *result, IForwardFilter *filter)
   283 {
   284 	if (m_errstate)
   285 	{
   286 		int err = m_errstate;
   287 		Cancel();
   288 		return err;
   289 	}
   290 
   291 	FuncIter iter = m_functions.begin();
   292 	IPluginFunction *func;
   293 	cell_t cur_result = 0;
   294 	cell_t high_result = 0;
   295 	cell_t low_result = 0;
   296 	int err;
   297 	unsigned int failed=0, success=0;
   298 	unsigned int num_params = m_curparam;
   299 	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   300 	FwdParamInfo *param;
   301 	ParamType type;
   302 
   303 	/* Save local, reset */
   304 	memcpy(temp_info, m_params, sizeof(m_params));
   305 	m_curparam = 0;
   306 
   307 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   308 	{
   309 		func = (*iter);
   310 
   311 		for (unsigned int i=0; i<num_params; i++)
   312 		{
   313 			int err = SP_ERROR_PARAM;
   314 			param = &temp_info[i];
   315 
   316 			if (i >= m_numparams || m_types[i] == Param_Any)
   317 			{
   318 				type = param->pushedas;
   319 			}
   320 			else
   321 			{
   322 				type = m_types[i];
   323 			}
   324 
   325 			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
   326 			{
   327 				/* If we're byref or we're vararg, we always push everything by ref.
   328 				 * Even if they're byval, we must push them byref.
   329 				 */
   330 				if (type == Param_String)
   331 				{
   332 					err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
   333 				}
   334 				else if (type == Param_Float || type == Param_Cell)
   335 				{
   336 					err = func->PushCellByRef(&param->val); 
   337 				}
   338 				else
   339 				{
   340 					err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
   341 					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
   342 				}
   343 			}
   344 			else
   345 			{
   346 				/* If we're not byref or not vararg, our job is a bit easier. */
   347 				assert(type == Param_Cell || type == Param_Float);
   348 				err = func->PushCell(param->val);
   349 			}
   350 
   351 			if (err != SP_ERROR_NONE)
   352 			{
   353 				g_DbgReporter.GenerateError(func->GetParentContext(), 
   354 					func->GetFunctionID(), 
   355 					err, 
   356 					"Failed to push parameter while executing forward");
   357 				continue;
   358 			}
   359 		}
   360 		
   361 		/* Call the function and deal with the return value. */
   362 		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
   363 		{
   364 			failed++;
   365 		}
   366 		else
   367 		{
   368 			success++;
   369 			switch (m_ExecType)
   370 			{
   371 			case ET_Event:
   372 				{
   373 					if (cur_result > high_result)
   374 					{
   375 						high_result = cur_result;
   376 					}
   377 					break;
   378 				}
   379 			case ET_Hook:
   380 				{
   381 					if (cur_result > high_result)
   382 					{
   383 						high_result = cur_result;
   384 						if ((ResultType)high_result == Pl_Stop)
   385 						{
   386 							goto done;
   387 						}
   388 					}
   389 					break;
   390 				}
   391 			case ET_LowEvent:
   392 				{
   393 					/* Check if the current result is the lowest so far (or if it's the first result) */
   394 					if (cur_result < low_result || success == 1)
   395 					{
   396 						low_result = cur_result;
   397 					}
   398 					break;
   399 				}
   400 			default:
   401 				{
   402 					break;
   403 				}
   404 			}
   405 		}
   406 	}
   407 
   408 done:
   409 
   410 	if (success)
   411 	{
   412 		switch (m_ExecType)
   413 		{
   414 		case ET_Ignore:
   415 			{
   416 				cur_result = 0;
   417 				break;
   418 			}
   419 		case ET_Event:
   420 		case ET_Hook:
   421 			{
   422 				cur_result = high_result;
   423 				break;
   424 			}
   425 		case ET_LowEvent:
   426 			{
   427 				cur_result = low_result;
   428 				break;
   429 			}
   430 		default:
   431 			{
   432 				break;
   433 			}
   434 		}
   435 
   436 		if (result)
   437 		{
   438 			*result = cur_result;
   439 		}
   440 	}
   441 
   442 	return SP_ERROR_NONE;
   443 }
   444 
   445 int CForward::PushCell(cell_t cell)
   446 {
   447 	if (m_curparam < m_numparams)
   448 	{
   449 		if (m_types[m_curparam] == Param_Any)
   450 		{
   451 			m_params[m_curparam].pushedas = Param_Cell;
   452 		} else if (m_types[m_curparam] != Param_Cell) {
   453 			return SetError(SP_ERROR_PARAM);
   454 		}
   455 	} else {
   456 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   457 		{
   458 			return SetError(SP_ERROR_PARAMS_MAX);
   459 		}
   460 		m_params[m_curparam].pushedas = Param_Cell;
   461 	}
   462 
   463 	m_params[m_curparam++].val = cell;
   464 
   465 	return SP_ERROR_NONE;
   466 }
   467 
   468 int CForward::PushFloat(float number)
   469 {
   470 	if (m_curparam < m_numparams)
   471 	{
   472 		if (m_types[m_curparam] == Param_Any)
   473 		{
   474 			m_params[m_curparam].pushedas = Param_Float;
   475 		} else if (m_types[m_curparam] != Param_Float) {
   476 			return SetError(SP_ERROR_PARAM);
   477 		}
   478 	} else {
   479 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   480 		{
   481 			return SetError(SP_ERROR_PARAMS_MAX);
   482 		}
   483 		m_params[m_curparam].pushedas = Param_Float;
   484 	}
   485 
   486 	m_params[m_curparam++].val = *(cell_t *)&number;
   487 
   488 	return SP_ERROR_NONE;
   489 }
   490 
   491 int CForward::PushCellByRef(cell_t *cell, int flags)
   492 {
   493 	if (m_curparam < m_numparams)
   494 	{
   495 		if (m_types[m_curparam] == Param_Any)
   496 		{
   497 			m_params[m_curparam].pushedas = Param_CellByRef;
   498 		} else if (m_types[m_curparam] != Param_CellByRef) {
   499 			return SetError(SP_ERROR_PARAM);
   500 		}
   501 	} else {
   502 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   503 		{
   504 			return SetError(SP_ERROR_PARAMS_MAX);
   505 		}
   506 		m_params[m_curparam].pushedas = Param_CellByRef;
   507 	}
   508 
   509 	_Int_PushArray(cell, 1, flags);
   510 	m_curparam++;
   511 
   512 	return SP_ERROR_NONE;
   513 }
   514 
   515 int CForward::PushFloatByRef(float *num, int flags)
   516 {
   517 	if (m_curparam < m_numparams)
   518 	{
   519 		if (m_types[m_curparam] == Param_Any)
   520 		{
   521 			m_params[m_curparam].pushedas = Param_FloatByRef;
   522 		} else if (m_types[m_curparam] != Param_FloatByRef) {
   523 			return SetError(SP_ERROR_PARAM);
   524 		}
   525 	} else {
   526 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   527 		{
   528 			return SetError(SP_ERROR_PARAMS_MAX);
   529 		}
   530 		m_params[m_curparam].pushedas = Param_FloatByRef;
   531 	}
   532 
   533 	_Int_PushArray((cell_t *)num, 1, flags);
   534 	m_curparam++;
   535 
   536 	return SP_ERROR_NONE;
   537 }
   538 
   539 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   540 {
   541 	m_params[m_curparam].byref.cells = cells;
   542 	m_params[m_curparam].byref.flags = flags;
   543 	m_params[m_curparam].byref.orig_addr = inarray;
   544 }
   545 
   546 int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
   547 {
   548 	/* We don't allow this here */
   549 	if (!inarray)
   550 	{
   551 		return SetError(SP_ERROR_PARAM);
   552 	}
   553 
   554 	if (m_curparam < m_numparams)
   555 	{
   556 		if (m_types[m_curparam] == Param_Any)
   557 		{
   558 			m_params[m_curparam].pushedas = Param_Array;
   559 		} else if (m_types[m_curparam] != Param_Array) {
   560 			return SetError(SP_ERROR_PARAM);
   561 		}
   562 	} else {
   563 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   564 		{
   565 			return SetError(SP_ERROR_PARAMS_MAX);
   566 		}
   567 		m_params[m_curparam].pushedas = Param_Array;
   568 	}
   569 
   570 	_Int_PushArray(inarray, cells, flags);
   571 
   572 	m_curparam++;
   573 
   574 	return SP_ERROR_NONE;
   575 }
   576 
   577 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
   578 {
   579 	m_params[m_curparam].byref.cells = cells;	/* Notice this contains the char count not cell count */
   580 	m_params[m_curparam].byref.flags = cp_flags;
   581 	m_params[m_curparam].byref.orig_addr = inarray;
   582 	m_params[m_curparam].byref.sz_flags = sz_flags;
   583 }
   584 
   585 int CForward::PushString(const char *string)
   586 {
   587 	if (m_curparam < m_numparams)
   588 	{
   589 		if (m_types[m_curparam] == Param_Any)
   590 		{
   591 			m_params[m_curparam].pushedas = Param_String;
   592 		} else if (m_types[m_curparam] != Param_String) {
   593 			return SetError(SP_ERROR_PARAM);
   594 		}
   595 	} else {
   596 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   597 		{
   598 			return SetError(SP_ERROR_PARAMS_MAX);
   599 		}
   600 		m_params[m_curparam].pushedas = Param_String;
   601 	}
   602 
   603 	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
   604 	m_curparam++;
   605 
   606 	return SP_ERROR_NONE;
   607 }
   608 
   609 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   610 {
   611 	if (m_curparam < m_numparams)
   612 	{
   613 		if (m_types[m_curparam] == Param_Any)
   614 		{
   615 			m_params[m_curparam].pushedas = Param_String;
   616 		} else if (m_types[m_curparam] != Param_String) {
   617 			return SetError(SP_ERROR_PARAM);
   618 		}
   619 	} else {
   620 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   621 		{
   622 			return SetError(SP_ERROR_PARAMS_MAX);
   623 		}
   624 		m_params[m_curparam].pushedas = Param_String;
   625 	}
   626 
   627 	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
   628 	m_curparam++;
   629 
   630 	return SP_ERROR_NONE;
   631 }
   632 
   633 void CForward::Cancel()
   634 {
   635 	if (!m_curparam)
   636 	{
   637 		return;
   638 	}
   639 
   640 	m_curparam = 0;
   641 	m_errstate = SP_ERROR_NONE;
   642 }
   643 
   644 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
   645 {
   646 	IPluginFunction *pFunc = pContext->GetFunctionById(index);
   647 
   648 	if (!pFunc)
   649 	{
   650 		return false;
   651 	}
   652 
   653 	return AddFunction(pFunc);
   654 }
   655 
   656 bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
   657 {
   658 	IPluginFunction *pFunc = pContext->GetFunctionById(index);
   659 
   660 	if (!pFunc)
   661 	{
   662 		return false;
   663 	}
   664 
   665 	return RemoveFunction(pFunc);
   666 }
   667 
   668 bool CForward::RemoveFunction(IPluginFunction *func)
   669 {
   670 	bool found = false;
   671 	FuncIter iter;
   672 	List<IPluginFunction *> *lst;
   673 
   674 	if (func->IsRunnable())
   675 	{
   676 		lst = &m_functions;
   677 	} else {
   678 		lst = &m_paused;
   679 	}
   680 
   681 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   682 	{
   683 		if ((*iter) == func)
   684 		{
   685 			found = true;
   686 			lst->erase(iter);
   687 			break;
   688 		}
   689 	}
   690 
   691 	/* Cancel a call, if any */
   692 	if (found || m_curparam)
   693 	{
   694 		func->Cancel();
   695 	}
   696 
   697 	return found;
   698 }
   699 
   700 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   701 {
   702 	FuncIter iter;
   703 	IPluginFunction *func;
   704 	unsigned int removed = 0;
   705 	IPluginContext *pContext = plugin->GetBaseContext();
   706 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   707 	{
   708 		func = (*iter);
   709 		if (func->GetParentContext() == pContext)
   710 		{
   711 			iter = m_functions.erase(iter);
   712 			removed++;
   713 		} else {
   714 			iter++;
   715 		}
   716 	}
   717 
   718 	return removed;
   719 }
   720 
   721 bool CForward::AddFunction(IPluginFunction *func)
   722 {
   723 	if (m_curparam)
   724 	{
   725 		return false;
   726 	}
   727 
   728 	if (func->IsRunnable())
   729 	{
   730 		m_functions.push_back(func);
   731 	} else {
   732 		m_paused.push_back(func);
   733 	}
   734 
   735 	return true;
   736 }
   737 
   738 const char *CForward::GetForwardName()
   739 {
   740 	return m_name;
   741 }
   742 
   743 unsigned int CForward::GetFunctionCount()
   744 {
   745 	return m_functions.size();
   746 }
   747 
   748 ExecType CForward::GetExecType()
   749 {
   750 	return m_ExecType;
   751 }