core/smn_functions.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Jul 15 08:00:26 2007 +0000 (2007-07-15)
changeset 1116 40cc5e9f0f1b
parent 1082 bb923439d570
child 1231 17badaf66ce4
permissions -rw-r--r--
Removed strange debugging code
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "sm_globals.h"
    16 #include "PluginSys.h"
    17 #include "ForwardSys.h"
    18 #include "HandleSys.h"
    19 
    20 HandleType_t g_GlobalFwdType = 0;
    21 HandleType_t g_PrivateFwdType = 0;
    22 
    23 static bool s_CallStarted = false;
    24 static ICallable *s_pCallable = NULL;
    25 static IPluginFunction *s_pFunction = NULL;
    26 static IForward *s_pForward = NULL;
    27 
    28 class ForwardNativeHelpers : 
    29 	public SMGlobalClass,
    30 	public IHandleTypeDispatch
    31 {
    32 public:
    33 	void OnSourceModAllInitialized()
    34 	{
    35 		HandleAccess sec;
    36 
    37 		/* Set GlobalFwd handle access security */
    38 		g_HandleSys.InitAccessDefaults(NULL, &sec);
    39 		sec.access[HandleAccess_Read] = 0;
    40 		sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
    41 
    42 		/* Create 'GlobalFwd' handle type */
    43 		g_GlobalFwdType = g_HandleSys.CreateType("GlobalFwd", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    44 
    45 		/* Private forwards are cloneable */
    46 		sec.access[HandleAccess_Clone] = 0;
    47 
    48 		/* Create 'PrivateFwd' handle type */
    49 		g_PrivateFwdType = g_HandleSys.CreateType("PrivateFwd", this, g_GlobalFwdType, NULL, &sec, g_pCoreIdent, NULL);
    50 	}
    51 
    52 	void OnSourceModShutdown()
    53 	{
    54 		g_HandleSys.RemoveType(g_PrivateFwdType, g_pCoreIdent);
    55 		g_HandleSys.RemoveType(g_GlobalFwdType, g_pCoreIdent);
    56 	}
    57 
    58 	void OnHandleDestroy(HandleType_t type, void *object)
    59 	{
    60 		IForward *pForward = static_cast<IForward *>(object);
    61 
    62 		g_Forwards.ReleaseForward(pForward);
    63 	}
    64 } g_ForwardNativeHelpers;
    65 
    66 
    67 /* Turn a public index into a function ID */
    68 inline funcid_t PublicIndexToFuncId(uint32_t idx)
    69 {
    70 	return (idx << 1) | (1 << 0);
    71 }
    72 
    73 /* Reset global function/forward call variables */
    74 inline void ResetCall()
    75 {
    76 	s_CallStarted = false;
    77 	s_pFunction = NULL;
    78 	s_pForward = NULL;
    79 	s_pCallable = NULL;
    80 }
    81 
    82 static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params)
    83 {
    84 	Handle_t hndl = static_cast<Handle_t>(params[1]);
    85 	HandleError err;
    86 	char *name;
    87 	uint32_t idx;
    88 	IPlugin *pPlugin;
    89 
    90 	if (hndl == 0)
    91 	{
    92 		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
    93 	} else {
    94 		pPlugin = g_PluginSys.PluginFromHandle(hndl, &err);
    95 
    96 		if (!pPlugin)
    97 		{
    98 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err);
    99 		}
   100 	}
   101 
   102 	pContext->LocalToString(params[2], &name);
   103 
   104 	/* Get public function index */
   105 	if (pPlugin->GetBaseContext()->FindPublicByName(name, &idx) == SP_ERROR_NOT_FOUND)
   106 	{
   107 		/* Return INVALID_FUNCTION if not found */
   108 		return -1;
   109 	}
   110 
   111 	/* Return function ID */
   112 	return PublicIndexToFuncId(idx);
   113 }
   114 
   115 static cell_t sm_CreateGlobalForward(IPluginContext *pContext, const cell_t *params)
   116 {
   117 	cell_t count = params[0];
   118 	char *name;
   119 	ParamType forwardParams[SP_MAX_EXEC_PARAMS];
   120 
   121 	if (count - 2 > SP_MAX_EXEC_PARAMS)
   122 	{
   123 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
   124 	}
   125 	
   126 	pContext->LocalToString(params[1], &name);
   127 
   128 	cell_t *addr;
   129 	for (int i = 3; i <= count; i++)
   130 	{
   131 		pContext->LocalToPhysAddr(params[i], &addr);
   132 		forwardParams[i - 3] = static_cast<ParamType>(*addr);
   133 	}
   134 
   135 	IForward *pForward = g_Forwards.CreateForward(name, static_cast<ExecType>(params[2]), count - 2, forwardParams);
   136 
   137 	return g_HandleSys.CreateHandle(g_GlobalFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL);
   138 }
   139 
   140 static cell_t sm_CreateForward(IPluginContext *pContext, const cell_t *params)
   141 {
   142 	cell_t count = params[0];
   143 	ParamType forwardParams[SP_MAX_EXEC_PARAMS];
   144 
   145 	if (count - 1 > SP_MAX_EXEC_PARAMS)
   146 	{
   147 		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
   148 	}
   149 
   150 	cell_t *addr;
   151 	for (int i = 2; i <= count; i++)
   152 	{
   153 		pContext->LocalToPhysAddr(params[i], &addr);
   154 		forwardParams[i - 2] = static_cast<ParamType>(*addr);
   155 	}
   156 
   157 	IChangeableForward *pForward = g_Forwards.CreateForwardEx(NULL, static_cast<ExecType>(params[1]), count - 1, forwardParams);
   158 
   159 	return g_HandleSys.CreateHandle(g_PrivateFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL);
   160 }
   161 
   162 static cell_t sm_GetForwardFunctionCount(IPluginContext *pContext, const cell_t *params)
   163 {
   164 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   165 	HandleError err;
   166 	IForward *pForward;
   167 
   168 	if ((err=g_HandleSys.ReadHandle(hndl, g_GlobalFwdType, NULL, (void **)&pForward))
   169 		!= HandleError_None)
   170 	{
   171 		return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err);
   172 	}
   173 
   174 	return pForward->GetFunctionCount();
   175 }
   176 
   177 static cell_t sm_AddToForward(IPluginContext *pContext, const cell_t *params)
   178 {
   179 	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
   180 	Handle_t plHandle = static_cast<Handle_t>(params[2]);
   181 	HandleError err;
   182 	IChangeableForward *pForward;
   183 	IPlugin *pPlugin;
   184 
   185 	if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
   186 		!= HandleError_None)
   187 	{
   188 		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
   189 	}
   190 
   191 	if (plHandle == 0)
   192 	{
   193 		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   194 	} else {
   195 		pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);
   196 
   197 		if (!pPlugin)
   198 		{
   199 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
   200 		}
   201 	}
   202 
   203 	IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
   204 
   205 	if (!pFunction)
   206 	{
   207 		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
   208 	}
   209 
   210 	return pForward->AddFunction(pFunction);
   211 }
   212 
   213 static cell_t sm_RemoveFromForward(IPluginContext *pContext, const cell_t *params)
   214 {
   215 	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
   216 	Handle_t plHandle = static_cast<Handle_t>(params[2]);
   217 	HandleError err;
   218 	IChangeableForward *pForward;
   219 	IPlugin *pPlugin;
   220 
   221 	if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
   222 		!= HandleError_None)
   223 	{
   224 		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
   225 	}
   226 
   227 	if (plHandle == 0)
   228 	{
   229 		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   230 	} else {
   231 		pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);
   232 
   233 		if (!pPlugin)
   234 		{
   235 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
   236 		}
   237 	}
   238 
   239 	IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
   240 
   241 	if (!pFunction)
   242 	{
   243 		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
   244 	}
   245 
   246 	return pForward->RemoveFunction(pFunction);
   247 }
   248 
   249 static cell_t sm_RemoveAllFromForward(IPluginContext *pContext, const cell_t *params)
   250 {
   251 	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
   252 	Handle_t plHandle = static_cast<Handle_t>(params[2]);
   253 	HandleError err;
   254 	IChangeableForward *pForward;
   255 	IPlugin *pPlugin;
   256 
   257 	if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
   258 		!= HandleError_None)
   259 	{
   260 		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
   261 	}
   262 
   263 	if (plHandle == 0)
   264 	{
   265 		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   266 	} else {
   267 		pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);
   268 
   269 		if (!pPlugin)
   270 		{
   271 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
   272 		}
   273 	}
   274 
   275 	return pForward->RemoveFunctionsOfPlugin(pPlugin);
   276 }
   277 
   278 static cell_t sm_CallStartFunction(IPluginContext *pContext, const cell_t *params)
   279 {
   280 	Handle_t hndl;
   281 	HandleError err;
   282 	IPlugin *pPlugin;
   283 
   284 	if (s_CallStarted)
   285 	{
   286 		return pContext->ThrowNativeError("Cannot start a call while one is already in progress");
   287 	}
   288 
   289 	hndl = static_cast<Handle_t>(params[1]);
   290 
   291 	if (hndl == 0)
   292 	{
   293 		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   294 	} else {
   295 		pPlugin = g_PluginSys.PluginFromHandle(hndl, &err);
   296 
   297 		if (!pPlugin)
   298 		{
   299 			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err);
   300 		}
   301 	}
   302 
   303 	s_pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[2]);
   304 
   305 	if (!s_pFunction)
   306 	{
   307 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   308 	}
   309 
   310 	s_pCallable = static_cast<ICallable *>(s_pFunction);
   311 
   312 	s_CallStarted = true;
   313 
   314 	return 1;
   315 }
   316 
   317 static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params)
   318 {
   319 	Handle_t hndl;
   320 	HandleError err;
   321 	IForward *pForward;
   322 
   323 	if (s_CallStarted)
   324 	{
   325 		return pContext->ThrowNativeError("Cannot start a call while one is already in progress");
   326 	}
   327 
   328 	hndl = static_cast<Handle_t>(params[1]);
   329 
   330 	if ((err=g_HandleSys.ReadHandle(hndl, g_GlobalFwdType, NULL, (void **)&pForward))
   331 		!= HandleError_None)
   332 	{
   333 		return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err);
   334 	}
   335 
   336 	s_pForward = pForward;
   337 
   338 	s_pCallable = static_cast<ICallable *>(pForward);
   339 
   340 	s_CallStarted = true;
   341 
   342 	return 1;
   343 }
   344 
   345 static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params)
   346 {
   347 	int err;
   348 
   349 	if (!s_CallStarted)
   350 	{
   351 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   352 	}
   353 
   354 	err = s_pCallable->PushCell(params[1]);
   355 
   356 	if (err)
   357 	{
   358 		s_pCallable->Cancel();
   359 		ResetCall();
   360 		return pContext->ThrowNativeErrorEx(err, NULL);
   361 	}
   362 
   363 	return 1;
   364 }
   365 
   366 static cell_t sm_CallPushCellRef(IPluginContext *pContext, const cell_t *params)
   367 {
   368 	int err;
   369 	cell_t *addr;
   370 
   371 	if (!s_CallStarted)
   372 	{
   373 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   374 	}
   375 
   376 	pContext->LocalToPhysAddr(params[1], &addr);
   377 
   378 	err = s_pCallable->PushCellByRef(addr);
   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_CallPushFloat(IPluginContext *pContext, const cell_t *params)
   391 {
   392 	int err;
   393 
   394 	if (!s_CallStarted)
   395 	{
   396 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   397 	}
   398 
   399 	err = s_pCallable->PushFloat(sp_ctof(params[1]));
   400 
   401 	if (err)
   402 	{
   403 		s_pCallable->Cancel();
   404 		ResetCall();
   405 		return pContext->ThrowNativeErrorEx(err, NULL);
   406 	}
   407 
   408 	return 1;
   409 }
   410 
   411 static cell_t sm_CallPushFloatRef(IPluginContext *pContext, const cell_t *params)
   412 {
   413 	int err;
   414 	cell_t *addr;
   415 
   416 	if (!s_CallStarted)
   417 	{
   418 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   419 	}
   420 
   421 	pContext->LocalToPhysAddr(params[1], &addr);
   422 
   423 	err = s_pCallable->PushFloatByRef(reinterpret_cast<float *>(addr));
   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_CallPushArray(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->PushArray(addr, params[2]);
   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_CallPushArrayEx(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], params[3]);
   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_CallPushString(IPluginContext *pContext, const cell_t *params)
   484 {
   485 	int err;
   486 	char *value;
   487 
   488 	if (!s_CallStarted)
   489 	{
   490 		return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
   491 	}
   492 
   493 	pContext->LocalToString(params[1], &value);
   494 
   495 	err = s_pCallable->PushString(value);
   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_CallPushStringEx(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->PushStringEx(value, params[2], params[3], params[4]);
   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_CallFinish(IPluginContext *pContext, const cell_t *params)
   532 {
   533 	int err = SP_ERROR_NOT_RUNNABLE;
   534 	cell_t *result;
   535 
   536 	if (!s_CallStarted)
   537 	{
   538 		return pContext->ThrowNativeError("Cannot finish call when there is no call in progress");
   539 	}
   540 
   541 	pContext->LocalToPhysAddr(params[1], &result);
   542 
   543 	if (s_pFunction)
   544 	{
   545 		IPluginFunction *pFunction = s_pFunction;
   546 		ResetCall();
   547 		err = pFunction->Execute(result);
   548 	} else if (s_pForward) {
   549 		IForward *pForward = s_pForward;
   550 		ResetCall();
   551 		err = pForward->Execute(result, NULL);
   552 	}
   553 
   554 	return err;
   555 }
   556 
   557 static cell_t sm_CallCancel(IPluginContext *pContext, const cell_t *params)
   558 {
   559 	if (!s_CallStarted)
   560 	{
   561 		return pContext->ThrowNativeError("Cannot cancel call when there is no call in progress");
   562 	}
   563 
   564 	s_pCallable->Cancel();
   565 	ResetCall();
   566 
   567 	return 1;
   568 }
   569 
   570 REGISTER_NATIVES(functionNatives)
   571 {
   572 	{"GetFunctionByName",		sm_GetFunctionByName},
   573 	{"CreateGlobalForward",		sm_CreateGlobalForward},
   574 	{"CreateForward",			sm_CreateForward},
   575 	{"GetForwardFunctionCount",	sm_GetForwardFunctionCount},
   576 	{"AddToForward",			sm_AddToForward},
   577 	{"RemoveFromForward",		sm_RemoveFromForward},
   578 	{"RemoveAllFromForward",	sm_RemoveAllFromForward},
   579 	{"Call_StartFunction",		sm_CallStartFunction},
   580 	{"Call_StartForward",		sm_CallStartForward},
   581 	{"Call_PushCell",			sm_CallPushCell},
   582 	{"Call_PushCellRef",		sm_CallPushCellRef},
   583 	{"Call_PushFloat",			sm_CallPushFloat},
   584 	{"Call_PushFloatRef",		sm_CallPushFloatRef},
   585 	{"Call_PushArray",			sm_CallPushArray},
   586 	{"Call_PushArrayEx",		sm_CallPushArrayEx},
   587 	{"Call_PushString",			sm_CallPushString},
   588 	{"Call_PushStringEx",		sm_CallPushStringEx},
   589 	{"Call_Finish",				sm_CallFinish},
   590 	{"Call_Cancel",				sm_CallCancel},
   591 	{NULL,						NULL},
   592 };