core/logic/smn_functions.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4235 ca11e4c5aa43
permissions -rw-r--r--
Update CS:GO team score gamedata.
     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 "common_logic.h"
    33 #include <IPluginSys.h>
    34 #include <IHandleSys.h>
    35 #include <IForwardSys.h>
    36 #include <ISourceMod.h>
    37 #include <am-utility.h>
    38 
    39 HandleType_t g_GlobalFwdType = 0;
    40 HandleType_t g_PrivateFwdType = 0;
    41 
    42 static bool s_CallStarted = false;
    43 static ICallable *s_pCallable = NULL;
    44 static IPluginFunction *s_pFunction = NULL;
    45 static IForward *s_pForward = NULL;
    46 
    47 class ForwardNativeHelpers : 
    48 	public SMGlobalClass,
    49 	public IHandleTypeDispatch
    50 {
    51 public:
    52 	void OnSourceModAllInitialized()
    53 	{
    54 		HandleAccess sec;
    55 
    56 		/* Set GlobalFwd handle access security */
    57 		handlesys->InitAccessDefaults(NULL, &sec);
    58 		sec.access[HandleAccess_Read] = 0;
    59 		sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
    60 
    61 		/* Create 'GlobalFwd' handle type */
    62 		g_GlobalFwdType = handlesys->CreateType("GlobalFwd", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    63 
    64 		/* Private forwards are cloneable */
    65 		sec.access[HandleAccess_Clone] = 0;
    66 
    67 		/* Create 'PrivateFwd' handle type */
    68 		g_PrivateFwdType = handlesys->CreateType("PrivateFwd", this, g_GlobalFwdType, NULL, &sec, g_pCoreIdent, NULL);
    69 	}
    70 
    71 	void OnSourceModShutdown()
    72 	{
    73 		handlesys->RemoveType(g_PrivateFwdType, g_pCoreIdent);
    74 		handlesys->RemoveType(g_GlobalFwdType, g_pCoreIdent);
    75 	}
    76 
    77 	void OnHandleDestroy(HandleType_t type, void *object)
    78 	{
    79 		IForward *pForward = static_cast<IForward *>(object);
    80 
    81 		forwardsys->ReleaseForward(pForward);
    82 	}
    83 
    84 	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
    85 	{
    86 		*pSize = sizeof(IForward*) + (((IForward *)object)->GetFunctionCount() * 12);
    87 		return true;
    88 	}
    89 } g_ForwardNativeHelpers;
    90 
    91 
    92 /* Turn a public index into a function ID */
    93 inline funcid_t PublicIndexToFuncId(uint32_t idx)
    94 {
    95 	return (idx << 1) | (1 << 0);
    96 }
    97 
    98 /* Reset global function/forward call variables */
    99 inline void ResetCall()
   100 {
   101 	s_CallStarted = false;
   102 	s_pFunction = NULL;
   103 	s_pForward = NULL;
   104 	s_pCallable = NULL;
   105 }
   106 
   107 static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params)
   108 {
   109 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   110 	HandleError err;
   111 	char *name;
   112 	uint32_t idx;
   113 	IPlugin *pPlugin;
   114 
   115 	if (hndl == 0)
   116 	{
   117 		pPlugin = pluginsys->FindPluginByContext(pContext->GetContext());
   118 	} else {
   119 		pPlugin = pluginsys->PluginFromHandle(hndl, &err);
   120 
   121 		if (!pPlugin)
   122 		{
   123 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err);
   124 		}
   125 	}
   126 
   127 	pContext->LocalToString(params[2], &name);
   128 
   129 	/* Get public function index */
   130 	if (pPlugin->GetBaseContext()->FindPublicByName(name, &idx) == SP_ERROR_NOT_FOUND)
   131 	{
   132 		/* Return INVALID_FUNCTION if not found */
   133 		return -1;
   134 	}
   135 
   136 	/* Return function ID */
   137 	return PublicIndexToFuncId(idx);
   138 }
   139 
   140 static cell_t sm_CreateGlobalForward(IPluginContext *pContext, const cell_t *params)
   141 {
   142 	cell_t count = params[0];
   143 	char *name;
   144 	ParamType forwardParams[SP_MAX_EXEC_PARAMS];
   145 
   146 	if (count - 2 > SP_MAX_EXEC_PARAMS)
   147 	{
   148 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
   149 	}
   150 	
   151 	pContext->LocalToString(params[1], &name);
   152 
   153 	cell_t *addr;
   154 	for (int i = 3; i <= count; i++)
   155 	{
   156 		pContext->LocalToPhysAddr(params[i], &addr);
   157 		forwardParams[i - 3] = static_cast<ParamType>(*addr);
   158 	}
   159 
   160 	IForward *pForward = forwardsys->CreateForward(name, static_cast<ExecType>(params[2]), count - 2, forwardParams);
   161 
   162 	return handlesys->CreateHandle(g_GlobalFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL);
   163 }
   164 
   165 static cell_t sm_CreateForward(IPluginContext *pContext, const cell_t *params)
   166 {
   167 	cell_t count = params[0];
   168 	ParamType forwardParams[SP_MAX_EXEC_PARAMS];
   169 
   170 	if (count - 1 > SP_MAX_EXEC_PARAMS)
   171 	{
   172 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
   173 	}
   174 
   175 	cell_t *addr;
   176 	for (int i = 2; i <= count; i++)
   177 	{
   178 		pContext->LocalToPhysAddr(params[i], &addr);
   179 		forwardParams[i - 2] = static_cast<ParamType>(*addr);
   180 	}
   181 
   182 	IChangeableForward *pForward = forwardsys->CreateForwardEx(NULL, static_cast<ExecType>(params[1]), count - 1, forwardParams);
   183 
   184 	return handlesys->CreateHandle(g_PrivateFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL);
   185 }
   186 
   187 static cell_t sm_GetForwardFunctionCount(IPluginContext *pContext, const cell_t *params)
   188 {
   189 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   190 	HandleError err;
   191 	IForward *pForward;
   192 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   193 
   194 	if ((err=handlesys->ReadHandle(hndl, g_GlobalFwdType, &sec, (void **)&pForward))
   195 		!= HandleError_None)
   196 	{
   197 		return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err);
   198 	}
   199 
   200 	return pForward->GetFunctionCount();
   201 }
   202 
   203 static cell_t sm_AddToForward(IPluginContext *pContext, const cell_t *params)
   204 {
   205 	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
   206 	Handle_t plHandle = static_cast<Handle_t>(params[2]);
   207 	HandleError err;
   208 	IChangeableForward *pForward;
   209 	IPlugin *pPlugin;
   210 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   211 
   212 	if ((err=handlesys->ReadHandle(fwdHandle, g_PrivateFwdType, &sec, (void **)&pForward))
   213 		!= HandleError_None)
   214 	{
   215 		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
   216 	}
   217 
   218 	if (plHandle == 0)
   219 	{
   220 		pPlugin = pluginsys->FindPluginByContext(pContext->GetContext());
   221 	} else {
   222 		pPlugin = pluginsys->PluginFromHandle(plHandle, &err);
   223 
   224 		if (!pPlugin)
   225 		{
   226 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
   227 		}
   228 	}
   229 
   230 	IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
   231 
   232 	if (!pFunction)
   233 	{
   234 		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
   235 	}
   236 
   237 	return pForward->AddFunction(pFunction);
   238 }
   239 
   240 static cell_t sm_RemoveFromForward(IPluginContext *pContext, const cell_t *params)
   241 {
   242 	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
   243 	Handle_t plHandle = static_cast<Handle_t>(params[2]);
   244 	HandleError err;
   245 	IChangeableForward *pForward;
   246 	IPlugin *pPlugin;
   247 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   248 
   249 	if ((err=handlesys->ReadHandle(fwdHandle, g_PrivateFwdType, &sec, (void **)&pForward))
   250 		!= HandleError_None)
   251 	{
   252 		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
   253 	}
   254 
   255 	if (plHandle == 0)
   256 	{
   257 		pPlugin = pluginsys->FindPluginByContext(pContext->GetContext());
   258 	} else {
   259 		pPlugin = pluginsys->PluginFromHandle(plHandle, &err);
   260 
   261 		if (!pPlugin)
   262 		{
   263 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
   264 		}
   265 	}
   266 
   267 	IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
   268 
   269 	if (!pFunction)
   270 	{
   271 		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
   272 	}
   273 
   274 	return pForward->RemoveFunction(pFunction);
   275 }
   276 
   277 static cell_t sm_RemoveAllFromForward(IPluginContext *pContext, const cell_t *params)
   278 {
   279 	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
   280 	Handle_t plHandle = static_cast<Handle_t>(params[2]);
   281 	HandleError err;
   282 	IChangeableForward *pForward;
   283 	IPlugin *pPlugin;
   284 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   285 
   286 	if ((err=handlesys->ReadHandle(fwdHandle, g_PrivateFwdType, &sec, (void **)&pForward))
   287 		!= HandleError_None)
   288 	{
   289 		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
   290 	}
   291 
   292 	if (plHandle == 0)
   293 	{
   294 		pPlugin = pluginsys->FindPluginByContext(pContext->GetContext());
   295 	} else {
   296 		pPlugin = pluginsys->PluginFromHandle(plHandle, &err);
   297 
   298 		if (!pPlugin)
   299 		{
   300 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
   301 		}
   302 	}
   303 
   304 	return pForward->RemoveFunctionsOfPlugin(pPlugin);
   305 }
   306 
   307 static cell_t sm_CallStartFunction(IPluginContext *pContext, const cell_t *params)
   308 {
   309 	Handle_t hndl;
   310 	HandleError err;
   311 	IPlugin *pPlugin;
   312 
   313 	ResetCall();
   314 
   315 	hndl = static_cast<Handle_t>(params[1]);
   316 
   317 	if (hndl == 0)
   318 	{
   319 		pPlugin = pluginsys->FindPluginByContext(pContext->GetContext());
   320 	} else {
   321 		pPlugin = pluginsys->PluginFromHandle(hndl, &err);
   322 
   323 		if (!pPlugin)
   324 		{
   325 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err);
   326 		}
   327 	}
   328 
   329 	s_pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[2]);
   330 
   331 	if (!s_pFunction)
   332 	{
   333 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   334 	}
   335 
   336 	s_pCallable = static_cast<ICallable *>(s_pFunction);
   337 
   338 	s_CallStarted = true;
   339 
   340 	return 1;
   341 }
   342 
   343 static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params)
   344 {
   345 	Handle_t hndl;
   346 	HandleError err;
   347 	IForward *pForward;
   348 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   349 
   350 	ResetCall();
   351 
   352 	hndl = static_cast<Handle_t>(params[1]);
   353 
   354 	if ((err=handlesys->ReadHandle(hndl, g_GlobalFwdType, &sec, (void **)&pForward))
   355 		!= HandleError_None)
   356 	{
   357 		return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err);
   358 	}
   359 
   360 	s_pForward = pForward;
   361 
   362 	s_pCallable = static_cast<ICallable *>(pForward);
   363 
   364 	s_CallStarted = true;
   365 
   366 	return 1;
   367 }
   368 
   369 static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params)
   370 {
   371 	int err;
   372 
   373 	if (!s_CallStarted)
   374 	{
   375 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   376 	}
   377 
   378 	err = s_pCallable->PushCell(params[1]);
   379 
   380 	if (err)
   381 	{
   382 		s_pCallable->Cancel();
   383 		ResetCall();
   384 		return pContext->ThrowNativeErrorEx(err, NULL);
   385 	}
   386 
   387 	return 1;
   388 }
   389 
   390 static cell_t sm_CallPushCellRef(IPluginContext *pContext, const cell_t *params)
   391 {
   392 	int err;
   393 	cell_t *addr;
   394 
   395 	if (!s_CallStarted)
   396 	{
   397 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   398 	}
   399 
   400 	pContext->LocalToPhysAddr(params[1], &addr);
   401 
   402 	err = s_pCallable->PushCellByRef(addr);
   403 
   404 	if (err)
   405 	{
   406 		s_pCallable->Cancel();
   407 		ResetCall();
   408 		return pContext->ThrowNativeErrorEx(err, NULL);
   409 	}
   410 
   411 	return 1;
   412 }
   413 
   414 static cell_t sm_CallPushFloat(IPluginContext *pContext, const cell_t *params)
   415 {
   416 	int err;
   417 
   418 	if (!s_CallStarted)
   419 	{
   420 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   421 	}
   422 
   423 	err = s_pCallable->PushFloat(sp_ctof(params[1]));
   424 
   425 	if (err)
   426 	{
   427 		s_pCallable->Cancel();
   428 		ResetCall();
   429 		return pContext->ThrowNativeErrorEx(err, NULL);
   430 	}
   431 
   432 	return 1;
   433 }
   434 
   435 static cell_t sm_CallPushFloatRef(IPluginContext *pContext, const cell_t *params)
   436 {
   437 	int err;
   438 	cell_t *addr;
   439 
   440 	if (!s_CallStarted)
   441 	{
   442 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   443 	}
   444 
   445 	pContext->LocalToPhysAddr(params[1], &addr);
   446 
   447 	err = s_pCallable->PushFloatByRef(reinterpret_cast<float *>(addr));
   448 
   449 	if (err)
   450 	{
   451 		s_pCallable->Cancel();
   452 		ResetCall();
   453 		return pContext->ThrowNativeErrorEx(err, NULL);
   454 	}
   455 
   456 	return 1;
   457 }
   458 
   459 static cell_t sm_CallPushArray(IPluginContext *pContext, const cell_t *params)
   460 {
   461 	int err;
   462 	cell_t *addr;
   463 
   464 	if (!s_CallStarted)
   465 	{
   466 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   467 	}
   468 
   469 	pContext->LocalToPhysAddr(params[1], &addr);
   470 
   471 	err = s_pCallable->PushArray(addr, params[2]);
   472 
   473 	if (err)
   474 	{
   475 		s_pCallable->Cancel();
   476 		ResetCall();
   477 		return pContext->ThrowNativeErrorEx(err, NULL);
   478 	}
   479 
   480 	return 1;
   481 }
   482 
   483 static cell_t sm_CallPushArrayEx(IPluginContext *pContext, const cell_t *params)
   484 {
   485 	int err;
   486 	cell_t *addr;
   487 
   488 	if (!s_CallStarted)
   489 	{
   490 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   491 	}
   492 
   493 	pContext->LocalToPhysAddr(params[1], &addr);
   494 
   495 	err = s_pCallable->PushArray(addr, params[2], params[3]);
   496 
   497 	if (err)
   498 	{
   499 		s_pCallable->Cancel();
   500 		ResetCall();
   501 		return pContext->ThrowNativeErrorEx(err, NULL);
   502 	}
   503 
   504 	return 1;
   505 }
   506 
   507 static cell_t sm_CallPushString(IPluginContext *pContext, const cell_t *params)
   508 {
   509 	int err;
   510 	char *value;
   511 
   512 	if (!s_CallStarted)
   513 	{
   514 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   515 	}
   516 
   517 	pContext->LocalToString(params[1], &value);
   518 
   519 	err = s_pCallable->PushString(value);
   520 
   521 	if (err)
   522 	{
   523 		s_pCallable->Cancel();
   524 		ResetCall();
   525 		return pContext->ThrowNativeErrorEx(err, NULL);
   526 	}
   527 
   528 	return 1;
   529 }
   530 
   531 static cell_t sm_CallPushStringEx(IPluginContext *pContext, const cell_t *params)
   532 {
   533 	int err;
   534 	char *value;
   535 
   536 	if (!s_CallStarted)
   537 	{
   538 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   539 	}
   540 
   541 	pContext->LocalToString(params[1], &value);
   542 
   543 	err = s_pCallable->PushStringEx(value, params[2], params[3], params[4]);
   544 
   545 	if (err)
   546 	{
   547 		s_pCallable->Cancel();
   548 		ResetCall();
   549 		return pContext->ThrowNativeErrorEx(err, NULL);
   550 	}
   551 
   552 	return 1;
   553 }
   554 
   555 static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
   556 {
   557 	int err = SP_ERROR_NOT_RUNNABLE;
   558 	cell_t *result;
   559 
   560 	if (!s_CallStarted)
   561 	{
   562 		return pContext->ThrowNativeError("Cannot finish call when there is no call in progress");
   563 	}
   564 
   565 	pContext->LocalToPhysAddr(params[1], &result);
   566 
   567 	if (s_pFunction)
   568 	{
   569 		IPluginFunction *pFunction = s_pFunction;
   570 		ResetCall();
   571 		err = pFunction->Execute(result);
   572 	} else if (s_pForward) {
   573 		IForward *pForward = s_pForward;
   574 		ResetCall();
   575 		err = pForward->Execute(result, NULL);
   576 	}
   577 
   578 	return err;
   579 }
   580 
   581 static cell_t sm_CallCancel(IPluginContext *pContext, const cell_t *params)
   582 {
   583 	if (!s_CallStarted)
   584 	{
   585 		return pContext->ThrowNativeError("Cannot cancel call when there is no call in progress");
   586 	}
   587 
   588 	s_pCallable->Cancel();
   589 	ResetCall();
   590 
   591 	return 1;
   592 }
   593 
   594 struct SMFrameActionData
   595 {
   596 	SMFrameActionData(Handle_t handle, Handle_t ownerhandle, cell_t data) : handle(handle), ownerhandle(ownerhandle), data(data)
   597 	{
   598 	};
   599 	Handle_t handle;
   600 	Handle_t ownerhandle;
   601 	cell_t data;
   602 };
   603 
   604 static void PawnFrameAction(void *pData)
   605 {
   606 	ke::AutoPtr<SMFrameActionData> frame(reinterpret_cast<SMFrameActionData *>(pData));
   607 	IPlugin *pPlugin = pluginsys->PluginFromHandle(frame->ownerhandle, NULL);
   608 	if (!pPlugin)
   609 	{
   610 		return;
   611 	}
   612 
   613 	IChangeableForward *pForward;
   614 	HandleSecurity sec(pPlugin->GetIdentity(), g_pCoreIdent);
   615 	if (handlesys->ReadHandle(frame->handle, g_PrivateFwdType, &sec, (void **)&pForward) != HandleError_None)
   616 	{
   617 		return;
   618 	}
   619 
   620 	pForward->PushCell(frame->data);
   621 	pForward->Execute(NULL);
   622 
   623 	handlesys->FreeHandle(frame->handle, &sec);
   624 }
   625 
   626 static cell_t sm_AddFrameAction(IPluginContext *pContext, const cell_t *params)
   627 {
   628 	IPlugin *pPlugin = pluginsys->FindPluginByContext(pContext->GetContext());
   629 	IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[1]);
   630 	if (!pFunction)
   631 	{
   632 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
   633 	}
   634 
   635 	IChangeableForward *pForward = forwardsys->CreateForwardEx(NULL, ET_Ignore, 1, NULL, Param_Cell);
   636 	IdentityToken_t *pIdentity = pContext->GetIdentity();
   637 	Handle_t Handle = handlesys->CreateHandle(g_PrivateFwdType, pForward, pIdentity, g_pCoreIdent, NULL);
   638 	if (Handle == BAD_HANDLE)
   639 	{
   640 		forwardsys->ReleaseForward(pForward);
   641 		return 0;
   642 	}
   643 
   644 	pForward->AddFunction(pFunction);
   645 
   646 	SMFrameActionData *pData = new SMFrameActionData(Handle, pPlugin->GetMyHandle(), params[2]);
   647 	g_pSM->AddFrameAction(PawnFrameAction, pData);
   648 	return 1;
   649 }
   650 
   651 REGISTER_NATIVES(functionNatives)
   652 {
   653 	{"GetFunctionByName",		sm_GetFunctionByName},
   654 	{"CreateGlobalForward",		sm_CreateGlobalForward},
   655 	{"CreateForward",			sm_CreateForward},
   656 	{"GetForwardFunctionCount",	sm_GetForwardFunctionCount},
   657 	{"AddToForward",			sm_AddToForward},
   658 	{"RemoveFromForward",		sm_RemoveFromForward},
   659 	{"RemoveAllFromForward",	sm_RemoveAllFromForward},
   660 	{"Call_StartFunction",		sm_CallStartFunction},
   661 	{"Call_StartForward",		sm_CallStartForward},
   662 	{"Call_PushCell",			sm_CallPushCell},
   663 	{"Call_PushCellRef",		sm_CallPushCellRef},
   664 	{"Call_PushFloat",			sm_CallPushFloat},
   665 	{"Call_PushFloatRef",		sm_CallPushFloatRef},
   666 	{"Call_PushArray",			sm_CallPushArray},
   667 	{"Call_PushArrayEx",		sm_CallPushArrayEx},
   668 	{"Call_PushString",			sm_CallPushString},
   669 	{"Call_PushStringEx",		sm_CallPushStringEx},
   670 	{"Call_Finish",				sm_CallFinish},
   671 	{"Call_Cancel",				sm_CallCancel},
   672 	{"RequestFrame",			sm_AddFrameAction},
   673 	{NULL,						NULL},
   674 };