Dear me, I should have committed this long ago...
authorScott Ehlert <ds@alliedmods.net>
Fri Mar 16 06:54:24 2007 +0000 (2007-03-16)
changeset 6215a0f5014aac1
parent 620 e329c942cb00
child 622 ecf5428b05b1
Dear me, I should have committed this long ago...
1) Added natives to create and manipulate global and private forward
2) Added natives to call forwards and functions
3) Added an IChanageableForward::RemoveFunction overload for convenience or something
4) Added test suite plugins for functions and forwards
5) Some random touch-ups to some include files
core/msvc8/sourcemod_mm.vcproj
core/smn_functions.cpp
core/systems/ForwardSys.cpp
core/systems/ForwardSys.h
core/vm/sp_vm_function.cpp
plugins/include/clients.inc
plugins/include/console.inc
plugins/include/core.inc
plugins/include/files.inc
plugins/include/functions.inc
plugins/include/helpers.inc
plugins/include/sourcemod.inc
plugins/include/string.inc
plugins/include/usermessages.inc
plugins/testsuite/callfunctest.sp
plugins/testsuite/fwdtest1.sp
plugins/testsuite/fwdtest2.sp
public/IForwardSys.h
     1.1 --- a/core/msvc8/sourcemod_mm.vcproj	Thu Mar 15 22:32:45 2007 +0000
     1.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Fri Mar 16 06:54:24 2007 +0000
     1.3 @@ -726,6 +726,10 @@
     1.4  				>
     1.5  			</File>
     1.6  			<File
     1.7 +				RelativePath="..\smn_functions.cpp"
     1.8 +				>
     1.9 +			</File>
    1.10 +			<File
    1.11  				RelativePath="..\smn_halflife.cpp"
    1.12  				>
    1.13  			</File>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/core/smn_functions.cpp	Fri Mar 16 06:54:24 2007 +0000
     2.3 @@ -0,0 +1,590 @@
     2.4 +/**
     2.5 +* ===============================================================
     2.6 +* SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     2.7 +* ===============================================================
     2.8 +*
     2.9 +* This file is not open source and may not be copied without explicit
    2.10 +* written permission of AlliedModders LLC.  This file may not be redistributed 
    2.11 +* in whole or significant part.
    2.12 +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    2.13 +*
    2.14 +* Version: $Id$
    2.15 +*/
    2.16 +
    2.17 +#include "sm_globals.h"
    2.18 +#include "PluginSys.h"
    2.19 +#include "ForwardSys.h"
    2.20 +#include "HandleSys.h"
    2.21 +
    2.22 +HandleType_t g_GlobalFwdType = 0;
    2.23 +HandleType_t g_PrivateFwdType = 0;
    2.24 +
    2.25 +static bool s_CallStarted = false;
    2.26 +static ICallable *s_pCallable = NULL;
    2.27 +static IPluginFunction *s_pFunction = NULL;
    2.28 +static IForward *s_pForward = NULL;
    2.29 +
    2.30 +class ForwardNativeHelpers : 
    2.31 +	public SMGlobalClass,
    2.32 +	public IHandleTypeDispatch
    2.33 +{
    2.34 +public:
    2.35 +	void OnSourceModAllInitialized()
    2.36 +	{
    2.37 +		HandleAccess sec;
    2.38 +
    2.39 +		/* Set GlobalFwd handle access security */
    2.40 +		g_HandleSys.InitAccessDefaults(NULL, &sec);
    2.41 +		sec.access[HandleAccess_Read] = 0;
    2.42 +		sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
    2.43 +
    2.44 +		/* Create 'GlobalFwd' handle type */
    2.45 +		g_GlobalFwdType = g_HandleSys.CreateType("GlobalFwd", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    2.46 +
    2.47 +		/* Private forwards are cloneable */
    2.48 +		sec.access[HandleAccess_Clone] = 0;
    2.49 +
    2.50 +		/* Create 'PrivateFwd' handle type */
    2.51 +		g_PrivateFwdType = g_HandleSys.CreateType("PrivateFwd", this, g_GlobalFwdType, NULL, &sec, g_pCoreIdent, NULL);
    2.52 +	}
    2.53 +
    2.54 +	void OnSourceModShutdown()
    2.55 +	{
    2.56 +		g_HandleSys.RemoveType(g_PrivateFwdType, g_pCoreIdent);
    2.57 +		g_HandleSys.RemoveType(g_GlobalFwdType, g_pCoreIdent);
    2.58 +	}
    2.59 +
    2.60 +	void OnHandleDestroy(HandleType_t type, void *object)
    2.61 +	{
    2.62 +		IForward *pForward = static_cast<IForward *>(object);
    2.63 +
    2.64 +		g_Forwards.ReleaseForward(pForward);
    2.65 +	}
    2.66 +} g_ForwardNativeHelpers;
    2.67 +
    2.68 +
    2.69 +/* Turn a public index into a function ID */
    2.70 +inline funcid_t PublicIndexToFuncId(uint32_t idx)
    2.71 +{
    2.72 +	return (idx << 1) | (1 << 0);
    2.73 +}
    2.74 +
    2.75 +/* Reset global function/forward call variables */
    2.76 +inline void ResetCall()
    2.77 +{
    2.78 +	s_CallStarted = false;
    2.79 +	s_pFunction = NULL;
    2.80 +	s_pCallable = NULL;
    2.81 +}
    2.82 +
    2.83 +static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params)
    2.84 +{
    2.85 +	Handle_t hndl = static_cast<Handle_t>(params[1]);
    2.86 +	HandleError err;
    2.87 +	char *name;
    2.88 +	uint32_t idx;
    2.89 +	IPlugin *pPlugin;
    2.90 +
    2.91 +	if (hndl == 0)
    2.92 +	{
    2.93 +		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
    2.94 +	} else {
    2.95 +		pPlugin = g_PluginSys.PluginFromHandle(hndl, &err);
    2.96 +
    2.97 +		if (!pPlugin)
    2.98 +		{
    2.99 +			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err);
   2.100 +		}
   2.101 +	}
   2.102 +
   2.103 +	pContext->LocalToString(params[2], &name);
   2.104 +
   2.105 +	/* Get public function index */
   2.106 +	if (pPlugin->GetBaseContext()->FindPublicByName(name, &idx) == SP_ERROR_NOT_FOUND)
   2.107 +	{
   2.108 +		/* Return INVALID_FUNCTION if not found */
   2.109 +		return -1;
   2.110 +	}
   2.111 +
   2.112 +	/* Return function ID */
   2.113 +	return PublicIndexToFuncId(idx);
   2.114 +}
   2.115 +
   2.116 +static cell_t sm_CreateGlobalForward(IPluginContext *pContext, const cell_t *params)
   2.117 +{
   2.118 +	cell_t count = params[0];
   2.119 +	char *name;
   2.120 +	ParamType forwardParams[SP_MAX_EXEC_PARAMS];
   2.121 +
   2.122 +	if (count - 2 > SP_MAX_EXEC_PARAMS)
   2.123 +	{
   2.124 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
   2.125 +	}
   2.126 +	
   2.127 +	pContext->LocalToString(params[1], &name);
   2.128 +
   2.129 +	cell_t *addr;
   2.130 +	for (int i = 3; i <= count; i++)
   2.131 +	{
   2.132 +		pContext->LocalToPhysAddr(params[i], &addr);
   2.133 +		forwardParams[i - 3] = static_cast<ParamType>(*addr);
   2.134 +	}
   2.135 +
   2.136 +	IForward *pForward = g_Forwards.CreateForward(name, static_cast<ExecType>(params[2]), count - 2, forwardParams);
   2.137 +
   2.138 +	return g_HandleSys.CreateHandle(g_GlobalFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL);
   2.139 +}
   2.140 +
   2.141 +static cell_t sm_CreateForward(IPluginContext *pContext, const cell_t *params)
   2.142 +{
   2.143 +	cell_t count = params[0];
   2.144 +	ParamType forwardParams[SP_MAX_EXEC_PARAMS];
   2.145 +
   2.146 +	if (count - 1 > SP_MAX_EXEC_PARAMS)
   2.147 +	{
   2.148 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
   2.149 +	}
   2.150 +
   2.151 +	cell_t *addr;
   2.152 +	for (int i = 2; i <= count; i++)
   2.153 +	{
   2.154 +		pContext->LocalToPhysAddr(params[i], &addr);
   2.155 +		forwardParams[i - 2] = static_cast<ParamType>(*addr);
   2.156 +	}
   2.157 +
   2.158 +	IChangeableForward *pForward = g_Forwards.CreateForwardEx(NULL, static_cast<ExecType>(params[1]), count - 1, forwardParams);
   2.159 +
   2.160 +	return g_HandleSys.CreateHandle(g_PrivateFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL);
   2.161 +}
   2.162 +
   2.163 +static cell_t sm_GetForwardFunctionCount(IPluginContext *pContext, const cell_t *params)
   2.164 +{
   2.165 +	Handle_t hndl = static_cast<Handle_t>(params[1]);
   2.166 +	HandleError err;
   2.167 +	IForward *pForward;
   2.168 +
   2.169 +	if ((err=g_HandleSys.ReadHandle(hndl, g_GlobalFwdType, NULL, (void **)&pForward))
   2.170 +		!= HandleError_None)
   2.171 +	{
   2.172 +		return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err);
   2.173 +	}
   2.174 +
   2.175 +	return pForward->GetFunctionCount();
   2.176 +}
   2.177 +
   2.178 +static cell_t sm_AddToForward(IPluginContext *pContext, const cell_t *params)
   2.179 +{
   2.180 +	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
   2.181 +	Handle_t plHandle = static_cast<Handle_t>(params[2]);
   2.182 +	HandleError err;
   2.183 +	IChangeableForward *pForward;
   2.184 +	IPlugin *pPlugin;
   2.185 +
   2.186 +	if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
   2.187 +		!= HandleError_None)
   2.188 +	{
   2.189 +		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
   2.190 +	}
   2.191 +
   2.192 +	if (plHandle == 0)
   2.193 +	{
   2.194 +		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   2.195 +	} else {
   2.196 +		pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);
   2.197 +
   2.198 +		if (!pPlugin)
   2.199 +		{
   2.200 +			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
   2.201 +		}
   2.202 +	}
   2.203 +
   2.204 +	IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
   2.205 +
   2.206 +	if (!pFunction)
   2.207 +	{
   2.208 +		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
   2.209 +	}
   2.210 +
   2.211 +	return pForward->AddFunction(pFunction);
   2.212 +}
   2.213 +
   2.214 +static cell_t sm_RemoveFromForward(IPluginContext *pContext, const cell_t *params)
   2.215 +{
   2.216 +	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
   2.217 +	Handle_t plHandle = static_cast<Handle_t>(params[2]);
   2.218 +	HandleError err;
   2.219 +	IChangeableForward *pForward;
   2.220 +	IPlugin *pPlugin;
   2.221 +
   2.222 +	if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
   2.223 +		!= HandleError_None)
   2.224 +	{
   2.225 +		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
   2.226 +	}
   2.227 +
   2.228 +	if (plHandle == 0)
   2.229 +	{
   2.230 +		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   2.231 +	} else {
   2.232 +		pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);
   2.233 +
   2.234 +		if (!pPlugin)
   2.235 +		{
   2.236 +			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
   2.237 +		}
   2.238 +	}
   2.239 +
   2.240 +	IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
   2.241 +
   2.242 +	if (!pFunction)
   2.243 +	{
   2.244 +		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
   2.245 +	}
   2.246 +
   2.247 +	return pForward->RemoveFunction(pFunction);
   2.248 +}
   2.249 +
   2.250 +static cell_t sm_RemoveAllFromForward(IPluginContext *pContext, const cell_t *params)
   2.251 +{
   2.252 +	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
   2.253 +	Handle_t plHandle = static_cast<Handle_t>(params[2]);
   2.254 +	HandleError err;
   2.255 +	IChangeableForward *pForward;
   2.256 +	IPlugin *pPlugin;
   2.257 +
   2.258 +	if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
   2.259 +		!= HandleError_None)
   2.260 +	{
   2.261 +		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
   2.262 +	}
   2.263 +
   2.264 +	if (plHandle == 0)
   2.265 +	{
   2.266 +		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   2.267 +	} else {
   2.268 +		pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);
   2.269 +
   2.270 +		if (!pPlugin)
   2.271 +		{
   2.272 +			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
   2.273 +		}
   2.274 +	}
   2.275 +
   2.276 +	return pForward->RemoveFunctionsOfPlugin(pPlugin);
   2.277 +}
   2.278 +
   2.279 +static cell_t sm_CallStartFunction(IPluginContext *pContext, const cell_t *params)
   2.280 +{
   2.281 +	Handle_t hndl;
   2.282 +	HandleError err;
   2.283 +	IPlugin *pPlugin;
   2.284 +
   2.285 +	if (s_CallStarted)
   2.286 +	{
   2.287 +		return pContext->ThrowNativeError("Cannot start a call while one is already in progress");
   2.288 +	}
   2.289 +
   2.290 +	hndl = static_cast<Handle_t>(params[1]);
   2.291 +
   2.292 +	if (hndl == 0)
   2.293 +	{
   2.294 +		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   2.295 +	} else {
   2.296 +		pPlugin = g_PluginSys.PluginFromHandle(hndl, &err);
   2.297 +
   2.298 +		if (!pPlugin)
   2.299 +		{
   2.300 +			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err);
   2.301 +		}
   2.302 +	}
   2.303 +
   2.304 +	s_pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[2]);
   2.305 +
   2.306 +	if (!s_pFunction)
   2.307 +	{
   2.308 +		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   2.309 +	}
   2.310 +
   2.311 +	s_pCallable = static_cast<ICallable *>(s_pFunction);
   2.312 +
   2.313 +	s_CallStarted = true;
   2.314 +
   2.315 +	return 1;
   2.316 +}
   2.317 +
   2.318 +static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params)
   2.319 +{
   2.320 +	Handle_t hndl;
   2.321 +	HandleError err;
   2.322 +	IForward *pForward;
   2.323 +
   2.324 +	if (s_CallStarted)
   2.325 +	{
   2.326 +		return pContext->ThrowNativeError("Cannot start a call while one is already in progress");
   2.327 +	}
   2.328 +
   2.329 +	hndl = static_cast<Handle_t>(params[1]);
   2.330 +
   2.331 +	if ((err=g_HandleSys.ReadHandle(hndl, g_GlobalFwdType, NULL, (void **)&pForward))
   2.332 +		!= HandleError_None)
   2.333 +	{
   2.334 +		return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err);
   2.335 +	}
   2.336 +
   2.337 +	s_pForward = pForward;
   2.338 +
   2.339 +	s_pCallable = static_cast<ICallable *>(pForward);
   2.340 +
   2.341 +	s_CallStarted = true;
   2.342 +
   2.343 +	return 1;
   2.344 +}
   2.345 +
   2.346 +static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params)
   2.347 +{
   2.348 +	int err;
   2.349 +
   2.350 +	if (!s_CallStarted)
   2.351 +	{
   2.352 +		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   2.353 +	}
   2.354 +
   2.355 +	err = s_pCallable->PushCell(params[1]);
   2.356 +
   2.357 +	if (err)
   2.358 +	{
   2.359 +		s_pCallable->Cancel();
   2.360 +		ResetCall();
   2.361 +		return pContext->ThrowNativeErrorEx(err, NULL);
   2.362 +	}
   2.363 +
   2.364 +	return 1;
   2.365 +}
   2.366 +
   2.367 +static cell_t sm_CallPushCellRef(IPluginContext *pContext, const cell_t *params)
   2.368 +{
   2.369 +	int err;
   2.370 +	cell_t *addr;
   2.371 +
   2.372 +	if (!s_CallStarted)
   2.373 +	{
   2.374 +		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   2.375 +	}
   2.376 +
   2.377 +	pContext->LocalToPhysAddr(params[1], &addr);
   2.378 +
   2.379 +	err = s_pCallable->PushCellByRef(addr);
   2.380 +
   2.381 +	if (err)
   2.382 +	{
   2.383 +		s_pCallable->Cancel();
   2.384 +		ResetCall();
   2.385 +		return pContext->ThrowNativeErrorEx(err, NULL);
   2.386 +	}
   2.387 +
   2.388 +	return 1;
   2.389 +}
   2.390 +
   2.391 +static cell_t sm_CallPushFloat(IPluginContext *pContext, const cell_t *params)
   2.392 +{
   2.393 +	int err;
   2.394 +
   2.395 +	if (!s_CallStarted)
   2.396 +	{
   2.397 +		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   2.398 +	}
   2.399 +
   2.400 +	err = s_pCallable->PushFloat(sp_ctof(params[1]));
   2.401 +
   2.402 +	if (err)
   2.403 +	{
   2.404 +		s_pCallable->Cancel();
   2.405 +		ResetCall();
   2.406 +		return pContext->ThrowNativeErrorEx(err, NULL);
   2.407 +	}
   2.408 +
   2.409 +	return 1;
   2.410 +}
   2.411 +
   2.412 +static cell_t sm_CallPushFloatRef(IPluginContext *pContext, const cell_t *params)
   2.413 +{
   2.414 +	int err;
   2.415 +	cell_t *addr;
   2.416 +
   2.417 +	if (!s_CallStarted)
   2.418 +	{
   2.419 +		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   2.420 +	}
   2.421 +
   2.422 +	pContext->LocalToPhysAddr(params[1], &addr);
   2.423 +
   2.424 +	err = s_pCallable->PushFloatByRef(reinterpret_cast<float *>(addr));
   2.425 +
   2.426 +	if (err)
   2.427 +	{
   2.428 +		s_pCallable->Cancel();
   2.429 +		ResetCall();
   2.430 +		return pContext->ThrowNativeErrorEx(err, NULL);
   2.431 +	}
   2.432 +
   2.433 +	return 1;
   2.434 +}
   2.435 +
   2.436 +static cell_t sm_CallPushArray(IPluginContext *pContext, const cell_t *params)
   2.437 +{
   2.438 +	int err;
   2.439 +	cell_t *addr;
   2.440 +
   2.441 +	if (!s_CallStarted)
   2.442 +	{
   2.443 +		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   2.444 +	}
   2.445 +
   2.446 +	pContext->LocalToPhysAddr(params[1], &addr);
   2.447 +
   2.448 +	err = s_pCallable->PushArray(addr, params[2], NULL);
   2.449 +
   2.450 +	if (err)
   2.451 +	{
   2.452 +		s_pCallable->Cancel();
   2.453 +		ResetCall();
   2.454 +		return pContext->ThrowNativeErrorEx(err, NULL);
   2.455 +	}
   2.456 +
   2.457 +	return 1;
   2.458 +}
   2.459 +
   2.460 +static cell_t sm_CallPushArrayEx(IPluginContext *pContext, const cell_t *params)
   2.461 +{
   2.462 +	int err;
   2.463 +	cell_t *addr;
   2.464 +
   2.465 +	if (!s_CallStarted)
   2.466 +	{
   2.467 +		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   2.468 +	}
   2.469 +
   2.470 +	pContext->LocalToPhysAddr(params[1], &addr);
   2.471 +
   2.472 +	err = s_pCallable->PushArray(addr, params[2], params[3]);
   2.473 +
   2.474 +	if (err)
   2.475 +	{
   2.476 +		s_pCallable->Cancel();
   2.477 +		ResetCall();
   2.478 +		return pContext->ThrowNativeErrorEx(err, NULL);
   2.479 +	}
   2.480 +
   2.481 +	return 1;
   2.482 +}
   2.483 +
   2.484 +static cell_t sm_CallPushString(IPluginContext *pContext, const cell_t *params)
   2.485 +{
   2.486 +	int err;
   2.487 +	char *value;
   2.488 +
   2.489 +	if (!s_CallStarted)
   2.490 +	{
   2.491 +		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   2.492 +	}
   2.493 +
   2.494 +	pContext->LocalToString(params[1], &value);
   2.495 +
   2.496 +	err = s_pCallable->PushString(value);
   2.497 +
   2.498 +	if (err)
   2.499 +	{
   2.500 +		s_pCallable->Cancel();
   2.501 +		ResetCall();
   2.502 +		return pContext->ThrowNativeErrorEx(err, NULL);
   2.503 +	}
   2.504 +
   2.505 +	return 1;
   2.506 +}
   2.507 +
   2.508 +static cell_t sm_CallPushStringEx(IPluginContext *pContext, const cell_t *params)
   2.509 +{
   2.510 +	int err;
   2.511 +	char *value;
   2.512 +
   2.513 +	if (!s_CallStarted)
   2.514 +	{
   2.515 +		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   2.516 +	}
   2.517 +
   2.518 +	pContext->LocalToString(params[1], &value);
   2.519 +
   2.520 +	err = s_pCallable->PushStringEx(value, params[2], params[3], params[4]);
   2.521 +
   2.522 +	if (err)
   2.523 +	{
   2.524 +		s_pCallable->Cancel();
   2.525 +		ResetCall();
   2.526 +		return pContext->ThrowNativeErrorEx(err, NULL);
   2.527 +	}
   2.528 +
   2.529 +	return 1;
   2.530 +}
   2.531 +
   2.532 +static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
   2.533 +{
   2.534 +	int err;
   2.535 +	cell_t *result;
   2.536 +
   2.537 +	if (!s_CallStarted)
   2.538 +	{
   2.539 +		return pContext->ThrowNativeError("Cannot finish call when there is no call in progress");
   2.540 +	}
   2.541 +
   2.542 +	pContext->LocalToPhysAddr(params[1], &result);
   2.543 +
   2.544 +	if (s_pFunction)
   2.545 +	{
   2.546 +		IPluginFunction *pFunction = s_pFunction;
   2.547 +		err = pFunction->Execute(result);
   2.548 +	} else if (s_pForward) {
   2.549 +		IForward *pForward = s_pForward;
   2.550 +		err = pForward->Execute(result, NULL);
   2.551 +	}
   2.552 +
   2.553 +	ResetCall();
   2.554 +
   2.555 +	return err;
   2.556 +}
   2.557 +
   2.558 +static cell_t sm_CallCancel(IPluginContext *pContext, const cell_t *params)
   2.559 +{
   2.560 +	if (!s_CallStarted)
   2.561 +	{
   2.562 +		return pContext->ThrowNativeError("Cannot cancel call when there is no call in progress");
   2.563 +	}
   2.564 +
   2.565 +	s_pCallable->Cancel();
   2.566 +	ResetCall();
   2.567 +
   2.568 +	return 1;
   2.569 +}
   2.570 +
   2.571 +REGISTER_NATIVES(functionNatives)
   2.572 +{
   2.573 +	{"GetFunctionByName",		sm_GetFunctionByName},
   2.574 +	{"CreateGlobalForward",		sm_CreateGlobalForward},
   2.575 +	{"CreateForward",			sm_CreateForward},
   2.576 +	{"GetForwardFunctionCount",	sm_GetForwardFunctionCount},
   2.577 +	{"AddToForward",			sm_AddToForward},
   2.578 +	{"RemoveFromForward",		sm_RemoveFromForward},
   2.579 +	{"RemoveAllFromForward",	sm_RemoveAllFromForward},
   2.580 +	{"Call_StartFunction",		sm_CallStartFunction},
   2.581 +	{"Call_StartForward",		sm_CallStartForward},
   2.582 +	{"Call_PushCell",			sm_CallPushCell},
   2.583 +	{"Call_PushCellRef",		sm_CallPushCellRef},
   2.584 +	{"Call_PushFloat",			sm_CallPushFloat},
   2.585 +	{"Call_PushFloatRef",		sm_CallPushFloatRef},
   2.586 +	{"Call_PushArray",			sm_CallPushArray},
   2.587 +	{"Call_PushArrayEx",		sm_CallPushArrayEx},
   2.588 +	{"Call_PushString",			sm_CallPushString},
   2.589 +	{"Call_PushStringEx",		sm_CallPushStringEx},
   2.590 +	{"Call_Finish",				sm_CallFinish},
   2.591 +	{"Call_Cancel",				sm_CallCancel},
   2.592 +	{NULL,						NULL},
   2.593 +};
     3.1 --- a/core/systems/ForwardSys.cpp	Thu Mar 15 22:32:45 2007 +0000
     3.2 +++ b/core/systems/ForwardSys.cpp	Fri Mar 16 06:54:24 2007 +0000
     3.3 @@ -601,6 +601,18 @@
     3.4  	return AddFunction(pFunc);
     3.5  }
     3.6  
     3.7 +bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
     3.8 +{
     3.9 +	IPluginFunction *pFunc = pContext->GetFunctionById(index);
    3.10 +
    3.11 +	if (!pFunc)
    3.12 +	{
    3.13 +		return false;
    3.14 +	}
    3.15 +
    3.16 +	return RemoveFunction(pFunc);
    3.17 +}
    3.18 +
    3.19  bool CForward::RemoveFunction(IPluginFunction *func)
    3.20  {
    3.21  	bool found = false;
     4.1 --- a/core/systems/ForwardSys.h	Thu Mar 15 22:32:45 2007 +0000
     4.2 +++ b/core/systems/ForwardSys.h	Fri Mar 16 06:54:24 2007 +0000
     4.3 @@ -64,6 +64,7 @@
     4.4  	virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin);
     4.5  	virtual bool AddFunction(IPluginFunction *func);
     4.6  	virtual bool AddFunction(IPluginContext *ctx, funcid_t index);
     4.7 +	virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index);
     4.8  public:
     4.9  	static CForward *CreateForward(const char *name, 
    4.10  								   ExecType et, 
     5.1 --- a/core/vm/sp_vm_function.cpp	Thu Mar 15 22:32:45 2007 +0000
     5.2 +++ b/core/vm/sp_vm_function.cpp	Fri Mar 16 06:54:24 2007 +0000
     5.3 @@ -81,11 +81,6 @@
     5.4  
     5.5  int CFunction::PushCellByRef(cell_t *cell, int flags)
     5.6  {
     5.7 -	if (m_curparam >= SP_MAX_EXEC_PARAMS)
     5.8 -	{
     5.9 -		return SetError(SP_ERROR_PARAMS_MAX);
    5.10 -	}
    5.11 -
    5.12  	return PushArray(cell, 1, flags);
    5.13  }
    5.14  
     6.1 --- a/plugins/include/clients.inc	Thu Mar 15 22:32:45 2007 +0000
     6.2 +++ b/plugins/include/clients.inc	Fri Mar 16 06:54:24 2007 +0000
     6.3 @@ -272,4 +272,4 @@
     6.4   * @error				Invalid client index, client not connected,
     6.5   *						or client not a fake client.
     6.6   */
     6.7 -native SetFakeClientConVar(client, const String:cvar[], const String:value[]);
     6.8 \ No newline at end of file
     6.9 +native SetFakeClientConVar(client, const String:cvar[], const String:value[]);
     7.1 --- a/plugins/include/console.inc	Thu Mar 15 22:32:45 2007 +0000
     7.2 +++ b/plugins/include/console.inc	Fri Mar 16 06:54:24 2007 +0000
     7.3 @@ -91,7 +91,7 @@
     7.4   * @noreturn
     7.5   * @error				Invalid client index, or client not connected.
     7.6   */
     7.7 -native ClientCommand(client, const String:fmt[], {String,Float,Handle,_}:...);
     7.8 +native ClientCommand(client, const String:fmt[], {String,Float,Handle,Function,_}:...);
     7.9  
    7.10  /**
    7.11   * Sends a message to the server console.
    7.12 @@ -100,7 +100,7 @@
    7.13   * @param ...			Variable number of format parameters.
    7.14   * @noreturn
    7.15   */
    7.16 -native PrintToServer(const String:format[], {Handle,Float,String,_}:...);
    7.17 +native PrintToServer(const String:format[], {Handle,Float,String,Function,_}:...);
    7.18  
    7.19  /**
    7.20   * Sends a message to a client's console.
    7.21 @@ -111,7 +111,7 @@
    7.22   * @noreturn
    7.23   * @error			If the client is not connected an error will be thrown.
    7.24   */
    7.25 -native PrintToConsole(client, const String:format[], {Handle,Float,String,_}:...);
    7.26 +native PrintToConsole(client, const String:format[], {Handle,Float,String,Function,_}:...);
    7.27  
    7.28  /**
    7.29   * Called when a server-only command is invoked.  
     8.1 --- a/plugins/include/core.inc	Thu Mar 15 22:32:45 2007 +0000
     8.2 +++ b/plugins/include/core.inc	Fri Mar 16 06:54:24 2007 +0000
     8.3 @@ -28,6 +28,14 @@
     8.4  };
     8.5  
     8.6  /**
     8.7 + * Function helper values
     8.8 + */
     8.9 +enum Function
    8.10 +{
    8.11 +     INVALID_FUNCTION = -1,
    8.12 +};
    8.13 +
    8.14 +/**
    8.15   * Specifies what to do after a hook completes.
    8.16   */
    8.17  enum Action
     9.1 --- a/plugins/include/files.inc	Thu Mar 15 22:32:45 2007 +0000
     9.2 +++ b/plugins/include/files.inc	Fri Mar 16 06:54:24 2007 +0000
     9.3 @@ -54,7 +54,7 @@
     9.4   * @param ...			Format arguments.
     9.5   * @return				Number of bytes written to buffer (not including null terminator).
     9.6   */
     9.7 -native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], ...);
     9.8 +native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], {Handle,Float,String,Function,_}:...);
     9.9  
    9.10  /**
    9.11   * @brief Opens a directory/folder for contents enumeration.
    9.12 @@ -186,4 +186,4 @@
    9.13   * @param ...			Variable number of format parameters.
    9.14   * @return				True on success, false otherwise.
    9.15   */
    9.16 -native bool:WriteFileLine(Handle:hndl, const String:format[], {Handle,Float,String,_}:...);
    9.17 +native bool:WriteFileLine(Handle:hndl, const String:format[], {Handle,Float,String,Function,_}:...);
    10.1 --- a/plugins/include/functions.inc	Thu Mar 15 22:32:45 2007 +0000
    10.2 +++ b/plugins/include/functions.inc	Fri Mar 16 06:54:24 2007 +0000
    10.3 @@ -13,6 +13,48 @@
    10.4   * Version: $Id$
    10.5   */
    10.6   
    10.7 +#define SP_PARAMFLAG_BYREF	(1<<0)	/**< Internal use only. */
    10.8 +
    10.9 +/**
   10.10 + * Describes the various ways to pass parameters to functions or forwards.
   10.11 + */
   10.12 +enum ParamType
   10.13 +{
   10.14 +	Param_Any			= 0,							/**< Any data type can be pushed */
   10.15 +	Param_Cell			= (1<<1),						/**< Only basic cells can be pushed */
   10.16 +	Param_Float			= (2<<1),						/**< Only floats can be pushed */
   10.17 +	Param_String		= (3<<1)|SP_PARAMFLAG_BYREF,	/**< Only strings can be pushed */
   10.18 +	Param_Array			= (4<<1)|SP_PARAMFLAG_BYREF,	/**< Only arrays can be pushed */
   10.19 +	Param_VarArgs		= (5<<1),						/**< Same as "..." in plugins, anything can be pushed, but it will always be byref */
   10.20 +	Param_CellByRef		= (1<<1)|SP_PARAMFLAG_BYREF,	/**< Only a cell by reference can be pushed */
   10.21 +	Param_FloatByRef	= (2<<1)|SP_PARAMFLAG_BYREF		/**< Only a float by reference can be pushed */
   10.22 +};
   10.23 +
   10.24 +/**
   10.25 + * Defines how a forward iterates through plugin functions.
   10.26 + */
   10.27 +enum ExecType
   10.28 +{
   10.29 +	ET_Ignore	= 0,	/**< Ignore all return values, return 0 */
   10.30 +	ET_Single	= 1,	/**< Only return the last exec, ignore all others */
   10.31 +	ET_Event	= 2,	/**< Acts as an event with the Actions defined in core.inc, no mid-Stops allowed, returns highest */
   10.32 +	ET_Hook		= 3		/**< Acts as a hook with the Actions defined in core.inc, mid-Stops allowed, returns highest */
   10.33 +};
   10.34 +
   10.35 +/**
   10.36 + * @section Flags that are used with Call_PushArrayEx() and Call_PushStringEx()
   10.37 + */
   10.38 +#define SM_PARAM_COPYBACK		(1<<0)		/**< Copy an array/reference back after call */
   10.39 +#define SM_PARAM_STRING_UTF8	(1<<0)		/**< String should be UTF-8 handled */
   10.40 +#define SM_PARAM_STRING_COPY	(1<<1)		/**< String should be copied into the plugin */
   10.41 +
   10.42 +/**
   10.43 + * @endsection
   10.44 + */
   10.45 +
   10.46 +/**
   10.47 + * @section Error codes
   10.48 + */
   10.49  #define SP_ERROR_NONE					0	/**< No error occurred */
   10.50  #define SP_ERROR_FILE_FORMAT			1	/**< File format unrecognized */
   10.51  #define SP_ERROR_DECOMPRESSOR			2	/**< A decompressor was not found */
   10.52 @@ -41,6 +83,243 @@
   10.53  #define SP_ERROR_ABORTED				25	/**< Function call was aborted */
   10.54  
   10.55  /**
   10.56 + * @endsection
   10.57 + */
   10.58 +
   10.59 +/**
   10.60 + * Gets a function id from a function name. 
   10.61 + *
   10.62 + * @param plugin			Handle of the plugin that contains the function.
   10.63 +							Pass INVALID_HANDLE to search in the calling plugin.
   10.64 + * @param name				Name of the function.
   10.65 + * @return 					Function id or INVALID_FUNCTION if not found.
   10.66 + * @error					Invalid or corrupt plugin handle.
   10.67 + */
   10.68 +native Function:GetFunctionByName(Handle:plugin, const String:name[]);
   10.69 +
   10.70 +/**
   10.71 + * Creates a global forward.
   10.72 + *
   10.73 + * @note The name used to create the forward is used as its public function in all target plugins.
   10.74 + * @note This is ideal for global, static forwards that are never changed.
   10.75 + *
   10.76 + * @param name				Name of public function to use in forward.
   10.77 + * @param type				Execution type to be used.
   10.78 + * @param ...				Variable number of parameter types (up to 32).
   10.79 + * @return 					Handle to new global forward.
   10.80 + * @error					More than 32 paramater types passed.
   10.81 + */
   10.82 +native Handle:CreateGlobalForward(const String:name[], ExecType:type, {ParamType}:...);
   10.83 +
   10.84 +/**
   10.85 + * Creates a private forward.
   10.86 + *
   10.87 + * @note No functions are automatically added. Use AddToForward() to do this.
   10.88 + *
   10.89 + * @param type				Execution type to be used.
   10.90 + * @param ...				Variable number of parameter types (up to 32).
   10.91 + * @return 					Handle to new private forward.
   10.92 + * @error					More than 32 paramater types passed.
   10.93 + */
   10.94 +native Handle:CreateForward(ExecType:type, {ParamType}:...);
   10.95 +
   10.96 +/**
   10.97 + * Returns the number of functions in a global or private forward's call list.
   10.98 + *
   10.99 + * @param fwd				Handle to global or private forward.
  10.100 + * @return					Number of functions in forward.
  10.101 + * @error					Invalid or corrupt forward handle.
  10.102 + */
  10.103 +native GetForwardFunctionCount(Handle:fwd);
  10.104 +
  10.105 +/**
  10.106 + * Adds a function to a private forward's call list.
  10.107 + *
  10.108 + * @note Cannot be used during an incompleted call.
  10.109 + *
  10.110 + * @param fwd				Handle to private forward.
  10.111 + * @param plugin			Handle of the plugin that contains the function.
  10.112 + *							Pass INVALID_HANDLE to specify the calling plugin.
  10.113 + * @param func				Function to add to forward.
  10.114 + * @return					True on success, false otherwise.
  10.115 + * @error					Invalid or corrupt private forward handle, invalid or corrupt plugin handle, or invalid function.
  10.116 + */
  10.117 +native bool:AddToForward(Handle:fwd, Handle:plugin, Function:func);
  10.118 +
  10.119 +/**
  10.120 + * Removes a function from a private forward's call list.
  10.121 + *
  10.122 + * @note Only removes one instance.
  10.123 + * @note Functions will be removed automatically if their parent plugin is unloaded.
  10.124 + *
  10.125 + * @param fwd				Handle to private forward.
  10.126 + * @param plugin			Handle of the plugin that contains the function.
  10.127 + *							Pass INVALID_HANDLE to specify the calling plugin.
  10.128 + * @param func				Function to remove from forward.
  10.129 + * @return					True on success, false otherwise.
  10.130 + * @error					Invalid or corrupt private forward handle, invalid or corrupt plugin handle, or invalid function.
  10.131 + */
  10.132 +native bool:RemoveFromForward(Handle:fwd, Handle:plugin, Function:func);
  10.133 +
  10.134 +/**
  10.135 + * Removes all instances of a plugin from a private forward's call list.
  10.136 + *
  10.137 + * @note Functions will be removed automatically if their parent plugin is unloaded.
  10.138 + *
  10.139 + * @param fwd				Handle to private forward.
  10.140 + * @param plugin			Handle of the plugin to remove instances of.
  10.141 + *							Pass INVALID_HANDLE to specify the calling plugin.
  10.142 + * @return					Number of functions removed from forward.
  10.143 + * @error					Invalid or corrupt private forward handle or invalid or corrupt plugin handle.
  10.144 + */
  10.145 +native RemoveAllFromForward(Handle:fwd, Handle:plugin);
  10.146 +
  10.147 +/**
  10.148 + * Starts a call to functions in a forward's call list.
  10.149 + *
  10.150 + * @note Cannot be used during an incompleted call.
  10.151 + *
  10.152 + * @param fwd				Handle to global or private forward.
  10.153 + * @noreturn
  10.154 + * @error					Invalid or corrupt forward handle or called before another call has completed.
  10.155 + */
  10.156 +native Call_StartForward(Handle:fwd);
  10.157 +
  10.158 +/**
  10.159 + * Starts a call to a function.
  10.160 + *
  10.161 + * @note Cannot be used during an incompleted call.
  10.162 + *
  10.163 + * @param plugin			Handle of the plugin that contains the function.
  10.164 + *							Pass INVALID_HANDLE to specify the calling plugin.
  10.165 + * @param func				Function to call.
  10.166 + * @noreturn
  10.167 + * @error					Invalid or corrupt plugin handle, invalid function, or called before another call has completed.
  10.168 + */
  10.169 +native Call_StartFunction(Handle:plugin, Function:func);
  10.170 +
  10.171 +/**
  10.172 + * Pushes a cell onto the current call.
  10.173 + *
  10.174 + * @note Cannot be used before a call has been started.
  10.175 + *
  10.176 + * @param value				Cell value to push.
  10.177 + * @noreturn
  10.178 + * @error					Called before a call has been started.
  10.179 + */
  10.180 +native Call_PushCell({Handle,Function,_}:value);
  10.181 +
  10.182 +/**
  10.183 + * Pushes a cell by reference onto the current call.
  10.184 + *
  10.185 + * @note Cannot be used before a call has been started.
  10.186 + *
  10.187 + * @param value				Cell reference to push.
  10.188 + * @noreturn
  10.189 + * @error					Called before a call has been started.
  10.190 + */
  10.191 +native Call_PushCellRef(&{Handle,Function,_}:value);
  10.192 +
  10.193 +
  10.194 +/**
  10.195 + * Pushes a float onto the current call.
  10.196 + *
  10.197 + * @note Cannot be used before a call has been started.
  10.198 + *
  10.199 + * @param value				Floating point value to push.
  10.200 + * @noreturn
  10.201 + * @error					Called before a call has been started.
  10.202 + */
  10.203 +native Call_PushFloat(Float:value);
  10.204 +
  10.205 +/**
  10.206 + * Pushes a float by reference onto the current call.
  10.207 + *
  10.208 + * @note Cannot be used before a call has been started.
  10.209 + *
  10.210 + * @param value				Floating point reference to push.
  10.211 + * @noreturn
  10.212 + * @error					Called before a call has been started.
  10.213 + */
  10.214 +native Call_PushFloatRef(&Float:value);
  10.215 +
  10.216 +/**
  10.217 + * Pushes an array onto the current call.
  10.218 + *
  10.219 + * @note Changes to array are not copied back to caller. Use PushArrayEx() to do this.
  10.220 + * @note Cannot be used before a call has been started.
  10.221 + *
  10.222 + * @param value				Array to push.
  10.223 + * @param size				Size of array.
  10.224 + * @noreturn
  10.225 + * @error					Called before a call has been started.
  10.226 + */
  10.227 +native Call_PushArray(const {Handle,Float,Function,_}:value[], size);
  10.228 +
  10.229 +/**
  10.230 + * Pushes an array onto the current call.
  10.231 + *
  10.232 + * @note Cannot be used before a call has been started.
  10.233 + *
  10.234 + * @param value				Array to push.
  10.235 + * @param size				Size of array.
  10.236 + * @param cpflags			Whether or not changes should be copied back to the input array.
  10.237 + *							See SP_PARAM_* constants for details.
  10.238 + * @noreturn
  10.239 + * @error					Called before a call has been started.
  10.240 + */
  10.241 +native Call_PushArrayEx({Handle,Float,Function,_}:value[], size, cpflags);
  10.242 +
  10.243 +/**
  10.244 + * Pushes a string onto the current call.
  10.245 + *
  10.246 + * @note Changes to string are not copied back to caller. Use PushStringEx() to do this.
  10.247 + * @note Cannot be used before a call has been started.
  10.248 + *
  10.249 + * @param value				String to push.
  10.250 + * @noreturn
  10.251 + * @error					Called before a call has been started.
  10.252 + */
  10.253 +native Call_PushString(const String:value[]);
  10.254 +
  10.255 +/**
  10.256 + * Pushes a string onto the current call.
  10.257 + *
  10.258 + * @note Cannot be used before a call has been started.
  10.259 + *
  10.260 + * @param value				String to push.
  10.261 + * @param length			Length of string buffer.
  10.262 + * @param szflags			Flags determining how string should be handled.
  10.263 + *							See SP_PARAM_STRING_* constants for details.
  10.264 + * @param cpflags			Whether or not changes should be copied back to the input array.
  10.265 + *							See SP_PARAM_* constants for details.		
  10.266 + * @noreturn
  10.267 + * @error					Called before a call has been started.
  10.268 + */
  10.269 +native Call_PushStringEx(String:value[], length, szflags, cpflags);
  10.270 +
  10.271 +/**
  10.272 + * Completes a call to a function or forward's call list.
  10.273 + *
  10.274 + * @note Cannot be used before a call has been started.
  10.275 + *
  10.276 + * @param result			Return value of function or forward's call list.		
  10.277 + * @return					SP_ERROR_NONE on success, any other integer on failure.
  10.278 + * @error					Called before a call has been started.
  10.279 + */
  10.280 +native Call_Finish(&result);
  10.281 +
  10.282 +/**
  10.283 + * Cancels a call to a function or forward's call list.
  10.284 + *
  10.285 + * @note Cannot be used before a call has been started.
  10.286 + *		
  10.287 + * @noreturn
  10.288 + * @error					Called before a call has been started.
  10.289 + */
  10.290 +native Call_Cancel();
  10.291 +
  10.292 +/**
  10.293   * Defines a native function.
  10.294   *
  10.295   * It is not necessary to validate the parameter count 
  10.296 @@ -69,7 +348,7 @@
  10.297   * @param fmt				Error message format.
  10.298   * @param ...				Format arguments.
  10.299   */
  10.300 -native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,_}:...);
  10.301 +native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,Function,_}:...);
  10.302  
  10.303  /**
  10.304   * Retrieves the string length from a native parameter string.  This is useful 
  10.305 @@ -78,7 +357,7 @@
  10.306   *
  10.307   * @param param				Parameter number, starting from 1.
  10.308   * @param length			Stores the length of the string.
  10.309 - * @return					SP_ERROR_NONE on sucecss, any other integer on failure.
  10.310 + * @return					SP_ERROR_NONE on success, any other integer on failure.
  10.311   * @error					Invalid parameter number or calling from a non-native function.
  10.312   */
  10.313  native GetNativeStringLength(param, &length);
  10.314 @@ -137,7 +416,7 @@
  10.315   * @noreturn
  10.316   * @error					Invalid parameter number or calling from a non-native function.
  10.317   */
  10.318 -native SetNativeCellRef(param, {Float,Handle,_}:value);
  10.319 +native SetNativeCellRef(param, {Float,Function,Handle,_}:value);
  10.320  
  10.321  /**
  10.322   * Gets an array from a native parameter (always by reference).
  10.323 @@ -148,7 +427,7 @@
  10.324   * @return					SP_ERROR_NONE on success, anything else on failure.
  10.325   * @error					Invalid parameter number or calling from a non-native function.
  10.326   */
  10.327 -native GetNativeArray(param, {Float,Handle,_}:local[], size);
  10.328 +native GetNativeArray(param, {Float,Function,Handle,_}:local[], size);
  10.329  
  10.330  /**
  10.331   * Copies a local array into a native parameter array (always by reference).
  10.332 @@ -159,7 +438,7 @@
  10.333   * @return					SP_ERROR_NONE on success, anything else on failure.
  10.334   * @error					Invalid parameter number or calling from a non-native function.
  10.335   */
  10.336 -native SetNativeArray(param, const {Float,Handle,_}:local[], size);
  10.337 +native SetNativeArray(param, const {Float,Function,Handle,_}:local[], size);
  10.338  
  10.339  /**
  10.340   * Formats a string using parameters from a native.
    11.1 --- a/plugins/include/helpers.inc	Thu Mar 15 22:32:45 2007 +0000
    11.2 +++ b/plugins/include/helpers.inc	Fri Mar 16 06:54:24 2007 +0000
    11.3 @@ -44,3 +44,30 @@
    11.4  	
    11.5  	Format(buffer, maxlength, "\"%s<%d><%s><>\"", name, userid, auth);
    11.6  }
    11.7 +
    11.8 +/**
    11.9 + * Returns plugin handle from plugin filename.
   11.10 + *
   11.11 + * @param filename		Filename of the plugin to search for.
   11.12 + * @Returns				Handle to plugin if found, INVALID_HANDLE otherwise.
   11.13 + */
   11.14 +stock Handle:FindPluginByFile(const String:filename[])
   11.15 +{
   11.16 +	decl String:buffer[256];
   11.17 +	
   11.18 +	new Handle:iter = GetPluginIterator();
   11.19 +	new Handle:pl;
   11.20 +	
   11.21 +	while (MorePlugins(iter))
   11.22 +	{
   11.23 +		pl = ReadPlugin(iter);
   11.24 +		
   11.25 +		GetPluginFilename(pl, buffer, sizeof(buffer));
   11.26 +		if (StrCompare(buffer, filename) == 0)
   11.27 +		{
   11.28 +			return pl;
   11.29 +		}
   11.30 +	}
   11.31 +	
   11.32 +	return INVALID_HANDLE;
   11.33 +}
    12.1 --- a/plugins/include/sourcemod.inc	Thu Mar 15 22:32:45 2007 +0000
    12.2 +++ b/plugins/include/sourcemod.inc	Fri Mar 16 06:54:24 2007 +0000
    12.3 @@ -189,7 +189,7 @@
    12.4   * @noreturn
    12.5   * @error				Always!
    12.6   */
    12.7 -native ThrowError(const String:fmt[], {Handle,Float,String,_}:...);
    12.8 +native ThrowError(const String:fmt[], {Handle,Float,String,Function,_}:...);
    12.9  
   12.10  /**
   12.11   * Logs a generic message to the HL2 logs.
   12.12 @@ -198,7 +198,7 @@
   12.13   * @param ...			Format arguments.
   12.14   * @noreturn
   12.15   */
   12.16 -native LogToGame(const String:format[], {Handle,Float,String,_}:...);
   12.17 +native LogToGame(const String:format[], {Handle,Float,String,Function,_}:...);
   12.18  
   12.19  /**
   12.20   * Logs a plugin message to the SourceMod logs.
   12.21 @@ -207,7 +207,7 @@
   12.22   * @param ...			Format arguments.
   12.23   * @noreturn
   12.24   */
   12.25 -native LogMessage(const String:format[], {Handle,Float,String,_}:...);
   12.26 +native LogMessage(const String:format[], {Handle,Float,String,Function,_}:...);
   12.27  
   12.28  /**
   12.29   * Logs a plugin error message to the SourceMod logs.
   12.30 @@ -216,7 +216,7 @@
   12.31   * @param ...			Format arguments.
   12.32   * @noreturn
   12.33   */
   12.34 -native LogError(const String:format[], {Handle,Float,String,_}:...);
   12.35 +native LogError(const String:format[], {Handle,Float,String,Function,_}:...);
   12.36  
   12.37  /**
   12.38   * Gets the system time as a unix timestamp.
    13.1 --- a/plugins/include/string.inc	Thu Mar 15 22:32:45 2007 +0000
    13.2 +++ b/plugins/include/string.inc	Fri Mar 16 06:54:24 2007 +0000
    13.3 @@ -93,7 +93,7 @@
    13.4   * @param ...			Variable number of format parameters.
    13.5   * @return				Number of cells written.
    13.6   */
    13.7 -native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...);
    13.8 +native Format(String:buffer[], maxlength, const String:format[], {Handle,Float,String,Function,_}:...);
    13.9  
   13.10  /**
   13.11   * Formats a string according to the SourceMod format rules (see documentation).
   13.12 @@ -106,7 +106,7 @@
   13.13   * @param ...			Variable number of format parameters.
   13.14   * @return				Number of cells written.
   13.15   */
   13.16 -native FormatEx(String:buffer[], maxlength, const String:format[], {Handle,Float,String,_}:...);
   13.17 +native FormatEx(String:buffer[], maxlength, const String:format[], {Handle,Float,String,Function,_}:...);
   13.18  
   13.19  /**
   13.20   * Formats a string according to the SourceMod format rules (see documentation).
    14.1 --- a/plugins/include/usermessages.inc	Thu Mar 15 22:32:45 2007 +0000
    14.2 +++ b/plugins/include/usermessages.inc	Fri Mar 16 06:54:24 2007 +0000
    14.3 @@ -57,11 +57,12 @@
    14.4   * @param msgname		Message name to start.
    14.5   * @param clients		Array containing player indexes to broadcast to.
    14.6   * @param numClients	Number of players in the array.
    14.7 + * @param flags			Optional flags to set.
    14.8   * @return				A handle to a bf_write bit packing structure, or
    14.9   *						INVALID_HANDLE on failure.
   14.10   * @error				Invalid message name or unable to start a message.
   14.11   */
   14.12 -native Handle:StartMessage(String:msgname[], clients[], numClients, flags);
   14.13 +native Handle:StartMessage(String:msgname[], clients[], numClients, flags=0);
   14.14  
   14.15  /**
   14.16   * Starts a usermessage (network message).
   14.17 @@ -71,11 +72,12 @@
   14.18   * @param msg			Message index to start.
   14.19   * @param clients		Array containing player indexes to broadcast to.
   14.20   * @param numClients	Number of players in the array.
   14.21 + * @param flags			Optional flags to set.
   14.22   * @return				A handle to a bf_write bit packing structure, or
   14.23   *						INVALID_HANDLE on failure.
   14.24   * @error				Invalid message name or unable to start a message.
   14.25   */
   14.26 -native Handle:StartMessageEx(UserMsg:msg, clients[], numClients, flags);
   14.27 +native Handle:StartMessageEx(UserMsg:msg, clients[], numClients, flags=0);
   14.28  
   14.29  /**
   14.30   * Ends a previously started user message (network message).
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/plugins/testsuite/callfunctest.sp	Fri Mar 16 06:54:24 2007 +0000
    15.3 @@ -0,0 +1,104 @@
    15.4 +#include <sourcemod>
    15.5 +
    15.6 +public Plugin:myinfo = 
    15.7 +{
    15.8 +	name = "Function Call Testing Lab",
    15.9 +	author = "AlliedModders LLC",
   15.10 +	description = "Tests basic function calls",
   15.11 +	version = "1.0.0.0",
   15.12 +	url = "http://www.sourcemod.net/"
   15.13 +};
   15.14 +
   15.15 +public OnPluginStart()
   15.16 +{
   15.17 +	RegServerCmd("test_callfunc", Command_CallFunc);
   15.18 +}
   15.19 +
   15.20 +public OnCallFuncReceived(num, Float:fnum, String:str[], String:str2[], &val, &Float:fval, array[], array2[], size, hello2[1])
   15.21 +{
   15.22 +	PrintToServer("Inside OnCallFuncReceived...");
   15.23 +
   15.24 +	PrintToServer("num = %d (expected: %d)", num, 5);
   15.25 +	PrintToServer("fnum = %f (expected: %f)", fnum, 7.17);
   15.26 +	PrintToServer("str[] = \"%s\" (expected: \"%s\")", str, "Gaben");
   15.27 +	PrintToServer("str2[] = \"%s\" (expected: \"%s\")", str2, ".taf si nebaG");
   15.28 +	
   15.29 +	PrintToServer("val = %d (expected %d, setting to %d)", val, 62, 15);
   15.30 +	val = 15;
   15.31 +	
   15.32 +	PrintToServer("fval = %f (expected: %f, setting to %f)", fval, 6.25, 1.5);
   15.33 +	fval = 1.5; 
   15.34 +	
   15.35 +	PrintToServer("Printing %d elements of array[] (expected: %d)", size, 6);
   15.36 +	for (new i = 0; i < size; i++)
   15.37 +	{
   15.38 +		PrintToServer("array[%d] = %d (expected: %d)", i, array[i], i);
   15.39 +	}
   15.40 +	for (new i = 0; i < size; i++)
   15.41 +	{
   15.42 +		PrintToServer("array2[%d] = %d (expected: %d)", i, array[i], i);
   15.43 +	}
   15.44 +	
   15.45 +	/* This shouldn't get copied back */
   15.46 +	StrCopy(str, strlen(str) + 1, "Yeti");
   15.47 +	/* This should get copied back */
   15.48 +	StrCopy(str2, strlen(str2) + 1, "Gaben is fat.");
   15.49 +	
   15.50 +	/* This should get copied back */
   15.51 +	array[0] = 5;
   15.52 +	array[1] = 6;
   15.53 +	/* This shouldn't get copied back */
   15.54 +	hello2[0] = 25;
   15.55 +	
   15.56 +	return 42;
   15.57 +}
   15.58 +
   15.59 +public Action:Command_CallFunc(args)
   15.60 +{
   15.61 +	new a = 62;
   15.62 +	new Float:b = 6.25;
   15.63 +	new const String:what[] = "Gaben";
   15.64 +	new String:truth[] = ".taf si nebaG";
   15.65 +	new hello[] = {0, 1, 2, 3, 4, 5};
   15.66 +	new hello2[] = {9};
   15.67 +	new pm = 6;
   15.68 +	new err;
   15.69 +	new ret;
   15.70 +	
   15.71 +	new Function:func = GetFunctionByName(INVALID_HANDLE, "OnCallFuncReceived");
   15.72 +	
   15.73 +	if (func == INVALID_FUNCTION)
   15.74 +	{
   15.75 +		PrintToServer("Failed to get the function id of OnCallFuncReceived");
   15.76 +		return Plugin_Handled;
   15.77 +	}
   15.78 +	
   15.79 +	PrintToServer("Calling OnCallFuncReceived...");
   15.80 +	
   15.81 +	Call_StartFunction(INVALID_HANDLE, func);
   15.82 +	Call_PushCell(5);
   15.83 +	Call_PushFloat(7.17);
   15.84 +	Call_PushString(what);
   15.85 +	Call_PushStringEx(truth, sizeof(truth), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
   15.86 +	Call_PushCellRef(a);
   15.87 +	Call_PushFloatRef(b);
   15.88 +	Call_PushArrayEx(hello, pm, SM_PARAM_COPYBACK);
   15.89 +	Call_PushArray(hello, pm);
   15.90 +	Call_PushCell(pm);
   15.91 +	Call_PushArray(hello2, 1);
   15.92 +	err = Call_Finish(ret);
   15.93 +	
   15.94 +	PrintToServer("Call to OnCallFuncReceived has finished!");
   15.95 +	PrintToServer("Error code = %d (expected: %d)", err, 0);
   15.96 +	PrintToServer("Return value = %d (expected: %d)", ret, 42);
   15.97 +	
   15.98 +	PrintToServer("a = %d (expected: %d)", a, 15);
   15.99 +	PrintToServer("b = %f (expected: %f)", b, 1.5);
  15.100 +	PrintToServer("what = \"%s\" (expected: \"%s\")", what, "Gaben");
  15.101 +	PrintToServer("truth = \"%s\" (expected: \"%s\")", truth, "Gaben is fat.");
  15.102 +	PrintToServer("hello[0] = %d (expected: %d)", hello[0], 5);
  15.103 +	PrintToServer("hello[1] = %d (expected: %d)", hello[1], 6);
  15.104 +	PrintToServer("hello2[0] = %d (expected: %d)", hello2[0], 9);
  15.105 +	
  15.106 +	return Plugin_Handled;
  15.107 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/plugins/testsuite/fwdtest1.sp	Fri Mar 16 06:54:24 2007 +0000
    16.3 @@ -0,0 +1,169 @@
    16.4 +#include <sourcemod>
    16.5 +
    16.6 +public Plugin:myinfo = 
    16.7 +{
    16.8 +	name = "Forward Testing Lab #1",
    16.9 +	author = "AlliedModders LLC",
   16.10 +	description = "Tests suite #1 for forwards created by plugins",
   16.11 +	version = "1.0.0.0",
   16.12 +	url = "http://www.sourcemod.net/"
   16.13 +};
   16.14 +
   16.15 +new Handle:g_GlobalFwd = INVALID_HANDLE;
   16.16 +new Handle:g_PrivateFwd = INVALID_HANDLE;
   16.17 +
   16.18 +public OnPluginStart()
   16.19 +{
   16.20 +	PrintToServer("OnPluginStart: %d", OnPluginStart);
   16.21 +	
   16.22 +	RegServerCmd("test_create_gforward", Command_CreateGlobalForward);
   16.23 +	RegServerCmd("test_create_pforward", Command_CreatePrivateForward);
   16.24 +	RegServerCmd("test_exec_gforward", Command_ExecGlobalForward);
   16.25 +	RegServerCmd("test_exec_pforward", Command_ExecPrivateForward);
   16.26 +}
   16.27 +
   16.28 +public OnPluginEnd()
   16.29 +{
   16.30 +	CloseHandle(g_GlobalFwd);
   16.31 +	CloseHandle(g_PrivateFwd);
   16.32 +}
   16.33 +
   16.34 +public Action:Command_CreateGlobalForward(args)
   16.35 +{
   16.36 +	if (g_GlobalFwd != INVALID_HANDLE)
   16.37 +	{
   16.38 +		CloseHandle(g_GlobalFwd);
   16.39 +	}
   16.40 +	
   16.41 +	g_GlobalFwd = CreateGlobalForward("OnGlobalForward", ET_Ignore, Param_Any, Param_Cell, Param_Float, Param_String, Param_Array, Param_CellByRef, Param_FloatByRef);
   16.42 +	
   16.43 +	if (g_GlobalFwd == INVALID_HANDLE)
   16.44 +	{
   16.45 +		PrintToServer("Failed to create global forward!");
   16.46 +	}
   16.47 +	
   16.48 +	return Plugin_Handled;
   16.49 +}
   16.50 +
   16.51 +public Action:Command_CreatePrivateForward(args)
   16.52 +{
   16.53 +	new Handle:pl;
   16.54 +	new Function:func;
   16.55 +	
   16.56 +	if (g_PrivateFwd != INVALID_HANDLE)
   16.57 +	{
   16.58 +		CloseHandle(g_PrivateFwd);
   16.59 +	}
   16.60 +	
   16.61 +	g_PrivateFwd = CreateForward(ET_Hook, Param_Cell, Param_String, Param_VarArgs);
   16.62 +	
   16.63 +	if (g_PrivateFwd == INVALID_HANDLE)
   16.64 +	{
   16.65 +		PrintToServer("Failed to create private forward!")
   16.66 +	}
   16.67 +	
   16.68 +	pl = FindPluginByFile("fwdtest2.smx");
   16.69 +	
   16.70 +	if (!pl)
   16.71 +	{
   16.72 +		PrintToServer("Could not find fwdtest2.smx!");
   16.73 +		return Plugin_Handled;
   16.74 +	}
   16.75 +	
   16.76 +	func = GetFunctionByName(pl, "OnPrivateForward");
   16.77 +	
   16.78 +	/* This shouldn't happen, but oh well */
   16.79 +	if (func == INVALID_FUNCTION)
   16.80 +	{
   16.81 +		PrintToServer("Could not find \"OnPrivateForward\" in fwdtest2.smx!");
   16.82 +		return Plugin_Handled;
   16.83 +	}
   16.84 +	
   16.85 +	if (!AddToForward(g_PrivateFwd, pl, func) || !AddToForward(g_PrivateFwd, GetMyHandle(), ZohMyGod))
   16.86 +	{
   16.87 +		PrintToServer("Failed to add functions to private forward!");
   16.88 +		return Plugin_Handled;
   16.89 +	}
   16.90 +	
   16.91 +	return Plugin_Handled;
   16.92 +}
   16.93 +
   16.94 +public Action:Command_ExecGlobalForward(args)
   16.95 +{
   16.96 +	new a = 99;
   16.97 +	new Float:b = 4.215;
   16.98 +	new err, ret;
   16.99 +	
  16.100 +	if (g_GlobalFwd == INVALID_HANDLE)
  16.101 +	{
  16.102 +		PrintToServer("Failed to execute global forward. Create it first.");
  16.103 +		return Plugin_Handled;
  16.104 +	}
  16.105 +	
  16.106 +	PrintToServer("Beginning call to %d functions in global forward \"OnGlobalForward\"", GetForwardFunctionCount(g_GlobalFwd));
  16.107 +	
  16.108 +	Call_StartForward(g_GlobalFwd);
  16.109 +	Call_PushCell(OnPluginStart);
  16.110 +	Call_PushCell(7);
  16.111 +	Call_PushFloat(-8.5);
  16.112 +	Call_PushString("Anata wa doko desu ka?");
  16.113 +	Call_PushArray({0.0, 1.1, 2.2}, 3);
  16.114 +	Call_PushCellRef(a);
  16.115 +	Call_PushFloatRef(b);
  16.116 +	err = Call_Finish(ret);
  16.117 +	
  16.118 +	PrintToServer("Call to global forward \"OnGlobalForward\" completed");
  16.119 +	PrintToServer("Error code = %d (expected: %d)", err, 0);
  16.120 +	PrintToServer("Return value = %d (expected: %d)", ret, Plugin_Continue);
  16.121 +	
  16.122 +	PrintToServer("a = %d (expected: %d)", a, 777);
  16.123 +	PrintToServer("b = %f (expected: %f)", b, -0.782);
  16.124 +	
  16.125 +	return Plugin_Handled;
  16.126 +}
  16.127 +
  16.128 +public Action:Command_ExecPrivateForward(args)
  16.129 +{
  16.130 +	new err, ret;
  16.131 +	
  16.132 +	if (g_PrivateFwd == INVALID_HANDLE)
  16.133 +	{
  16.134 +		PrintToServer("Failed to execute private forward. Create it first.");
  16.135 +		return Plugin_Handled;
  16.136 +	}
  16.137 +	
  16.138 +	PrintToServer("Beginning call to %d functions in private forward", GetForwardFunctionCount(g_PrivateFwd));
  16.139 +	
  16.140 +	Call_StartForward(g_PrivateFwd);
  16.141 +	Call_PushCell(24);
  16.142 +	Call_PushString("I am a format string: %d %d %d %d %d %d");
  16.143 +	Call_PushCell(0);
  16.144 +	Call_PushCell(1);
  16.145 +	Call_PushCell(2);
  16.146 +	Call_PushCell(3);
  16.147 +	Call_PushCell(4);
  16.148 +	Call_PushCell(5);
  16.149 +	err = Call_Finish(ret);
  16.150 +	
  16.151 +	PrintToServer("Call to private forward completed");
  16.152 +	PrintToServer("Error code = %d (expected: %d)", err, 0);
  16.153 +	PrintToServer("Return value = %d (expected: %d)", ret, Plugin_Handled);
  16.154 +
  16.155 +	return Plugin_Handled;
  16.156 +}
  16.157 +
  16.158 +public Action:ZohMyGod(num, const String:format[], ...)
  16.159 +{
  16.160 +	decl String:buffer[128];
  16.161 +	
  16.162 +	PrintToServer("Inside private forward #1");
  16.163 +	
  16.164 +	PrintToServer("num = %d (expected: %d)", num, 24);
  16.165 +	
  16.166 +	VFormat(buffer, sizeof(buffer), format, 3);
  16.167 +	PrintToServer("buffer = \"%s\" (expected: \"%s\")", buffer, "I am a format string: 0 1 2 3 4 5");
  16.168 +	
  16.169 +	PrintToServer("End private forward #1");
  16.170 +	
  16.171 +	return Plugin_Continue;
  16.172 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/plugins/testsuite/fwdtest2.sp	Fri Mar 16 06:54:24 2007 +0000
    17.3 @@ -0,0 +1,43 @@
    17.4 +#include <sourcemod>
    17.5 +
    17.6 +public Plugin:myinfo = 
    17.7 +{
    17.8 +	name = "Forward Testing Lab #2",
    17.9 +	author = "AlliedModders LLC",
   17.10 +	description = "Tests suite #2 for forwards created by plugins",
   17.11 +	version = "1.0.0.0",
   17.12 +	url = "http://www.sourcemod.net/"
   17.13 +};
   17.14 +
   17.15 +public Action:OnPrivateForward(num, const String:format[], ...)
   17.16 +{
   17.17 +	decl String:buffer[128];
   17.18 +	
   17.19 +	PrintToServer("Inside private forward #2");
   17.20 +	
   17.21 +	PrintToServer("num = %d (expected: %d)", num, 24);
   17.22 +	
   17.23 +	VFormat(buffer, sizeof(buffer), format, 3);
   17.24 +	PrintToServer("buffer = \"%s\" (expected: \"%s\")", buffer, "I am a format string: 0 1 2 3 4 5");
   17.25 +	
   17.26 +	PrintToServer("End private forward #2");
   17.27 +	
   17.28 +	return Plugin_Handled;
   17.29 +}
   17.30 +
   17.31 +public OnGlobalForward(Function:a, b, Float:c, const String:d[], Float:e[3], &f, &Float:g)
   17.32 +{
   17.33 +	PrintToServer("Inside global forward \"OnGlobalForward\"");
   17.34 +	
   17.35 +	PrintToServer("a = %d (expected: %d)", a, 11);
   17.36 +	PrintToServer("b = %d (expected: %d)", b, 7);
   17.37 +	PrintToServer("c = %f (expected: %f)", c, -8.5);
   17.38 +	PrintToServer("d = \"%s\" (expected: \"%s\")", d, "Anata wa doko desu ka?");
   17.39 +	PrintToServer("e = %f %f %f (expected: %f %f %f)", e[0], e[1], e[2], 0.0, 1.1, 2.2);
   17.40 +	
   17.41 +	PrintToServer("f = %d (expected %d, setting to %d)", f, 99, 777);
   17.42 +	f = 777;
   17.43 +	
   17.44 +	PrintToServer("g = %f (expected %f, setting to %f)", g, 4.215, -0.782);
   17.45 +	g = -0.782;
   17.46 +}
    18.1 --- a/public/IForwardSys.h	Thu Mar 15 22:32:45 2007 +0000
    18.2 +++ b/public/IForwardSys.h	Fri Mar 16 06:54:24 2007 +0000
    18.3 @@ -227,6 +227,16 @@
    18.4  		 * @return			True on success, otherwise false.
    18.5  		 */
    18.6  		virtual bool AddFunction(IPluginContext *ctx, funcid_t index) =0;
    18.7 +
    18.8 +		/** 
    18.9 +		* @brief Removes a function from the call list.
   18.10 +		* NOTE: Only removes one instance.
   18.11 +		*
   18.12 +		* @param ctx		Context to use as a look-up.
   18.13 +		* @param index		Function id to add.
   18.14 +		* @return			Whether or not the function was removed.
   18.15 +		*/
   18.16 +		virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index) =0;
   18.17  	};
   18.18  
   18.19  	#define SP_PARAMTYPE_ANY	0