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