1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/smn_functions.cpp Fri Mar 16 06:54:24 2007 +0000
1.3 @@ -0,0 +1,590 @@
1.4 +/**
1.5 +* ===============================================================
1.6 +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
1.7 +* ===============================================================
1.8 +*
1.9 +* This file is not open source and may not be copied without explicit
1.10 +* written permission of AlliedModders LLC. This file may not be redistributed
1.11 +* in whole or significant part.
1.12 +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
1.13 +*
1.14 +* Version: $Id$
1.15 +*/
1.16 +
1.17 +#include "sm_globals.h"
1.18 +#include "PluginSys.h"
1.19 +#include "ForwardSys.h"
1.20 +#include "HandleSys.h"
1.21 +
1.22 +HandleType_t g_GlobalFwdType = 0;
1.23 +HandleType_t g_PrivateFwdType = 0;
1.24 +
1.25 +static bool s_CallStarted = false;
1.26 +static ICallable *s_pCallable = NULL;
1.27 +static IPluginFunction *s_pFunction = NULL;
1.28 +static IForward *s_pForward = NULL;
1.29 +
1.30 +class ForwardNativeHelpers :
1.31 + public SMGlobalClass,
1.32 + public IHandleTypeDispatch
1.33 +{
1.34 +public:
1.35 + void OnSourceModAllInitialized()
1.36 + {
1.37 + HandleAccess sec;
1.38 +
1.39 + /* Set GlobalFwd handle access security */
1.40 + g_HandleSys.InitAccessDefaults(NULL, &sec);
1.41 + sec.access[HandleAccess_Read] = 0;
1.42 + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
1.43 +
1.44 + /* Create 'GlobalFwd' handle type */
1.45 + g_GlobalFwdType = g_HandleSys.CreateType("GlobalFwd", this, 0, NULL, &sec, g_pCoreIdent, NULL);
1.46 +
1.47 + /* Private forwards are cloneable */
1.48 + sec.access[HandleAccess_Clone] = 0;
1.49 +
1.50 + /* Create 'PrivateFwd' handle type */
1.51 + g_PrivateFwdType = g_HandleSys.CreateType("PrivateFwd", this, g_GlobalFwdType, NULL, &sec, g_pCoreIdent, NULL);
1.52 + }
1.53 +
1.54 + void OnSourceModShutdown()
1.55 + {
1.56 + g_HandleSys.RemoveType(g_PrivateFwdType, g_pCoreIdent);
1.57 + g_HandleSys.RemoveType(g_GlobalFwdType, g_pCoreIdent);
1.58 + }
1.59 +
1.60 + void OnHandleDestroy(HandleType_t type, void *object)
1.61 + {
1.62 + IForward *pForward = static_cast<IForward *>(object);
1.63 +
1.64 + g_Forwards.ReleaseForward(pForward);
1.65 + }
1.66 +} g_ForwardNativeHelpers;
1.67 +
1.68 +
1.69 +/* Turn a public index into a function ID */
1.70 +inline funcid_t PublicIndexToFuncId(uint32_t idx)
1.71 +{
1.72 + return (idx << 1) | (1 << 0);
1.73 +}
1.74 +
1.75 +/* Reset global function/forward call variables */
1.76 +inline void ResetCall()
1.77 +{
1.78 + s_CallStarted = false;
1.79 + s_pFunction = NULL;
1.80 + s_pCallable = NULL;
1.81 +}
1.82 +
1.83 +static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params)
1.84 +{
1.85 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.86 + HandleError err;
1.87 + char *name;
1.88 + uint32_t idx;
1.89 + IPlugin *pPlugin;
1.90 +
1.91 + if (hndl == 0)
1.92 + {
1.93 + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
1.94 + } else {
1.95 + pPlugin = g_PluginSys.PluginFromHandle(hndl, &err);
1.96 +
1.97 + if (!pPlugin)
1.98 + {
1.99 + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err);
1.100 + }
1.101 + }
1.102 +
1.103 + pContext->LocalToString(params[2], &name);
1.104 +
1.105 + /* Get public function index */
1.106 + if (pPlugin->GetBaseContext()->FindPublicByName(name, &idx) == SP_ERROR_NOT_FOUND)
1.107 + {
1.108 + /* Return INVALID_FUNCTION if not found */
1.109 + return -1;
1.110 + }
1.111 +
1.112 + /* Return function ID */
1.113 + return PublicIndexToFuncId(idx);
1.114 +}
1.115 +
1.116 +static cell_t sm_CreateGlobalForward(IPluginContext *pContext, const cell_t *params)
1.117 +{
1.118 + cell_t count = params[0];
1.119 + char *name;
1.120 + ParamType forwardParams[SP_MAX_EXEC_PARAMS];
1.121 +
1.122 + if (count - 2 > SP_MAX_EXEC_PARAMS)
1.123 + {
1.124 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
1.125 + }
1.126 +
1.127 + pContext->LocalToString(params[1], &name);
1.128 +
1.129 + cell_t *addr;
1.130 + for (int i = 3; i <= count; i++)
1.131 + {
1.132 + pContext->LocalToPhysAddr(params[i], &addr);
1.133 + forwardParams[i - 3] = static_cast<ParamType>(*addr);
1.134 + }
1.135 +
1.136 + IForward *pForward = g_Forwards.CreateForward(name, static_cast<ExecType>(params[2]), count - 2, forwardParams);
1.137 +
1.138 + return g_HandleSys.CreateHandle(g_GlobalFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL);
1.139 +}
1.140 +
1.141 +static cell_t sm_CreateForward(IPluginContext *pContext, const cell_t *params)
1.142 +{
1.143 + cell_t count = params[0];
1.144 + ParamType forwardParams[SP_MAX_EXEC_PARAMS];
1.145 +
1.146 + if (count - 1 > SP_MAX_EXEC_PARAMS)
1.147 + {
1.148 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
1.149 + }
1.150 +
1.151 + cell_t *addr;
1.152 + for (int i = 2; i <= count; i++)
1.153 + {
1.154 + pContext->LocalToPhysAddr(params[i], &addr);
1.155 + forwardParams[i - 2] = static_cast<ParamType>(*addr);
1.156 + }
1.157 +
1.158 + IChangeableForward *pForward = g_Forwards.CreateForwardEx(NULL, static_cast<ExecType>(params[1]), count - 1, forwardParams);
1.159 +
1.160 + return g_HandleSys.CreateHandle(g_PrivateFwdType, pForward, pContext->GetIdentity(), g_pCoreIdent, NULL);
1.161 +}
1.162 +
1.163 +static cell_t sm_GetForwardFunctionCount(IPluginContext *pContext, const cell_t *params)
1.164 +{
1.165 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.166 + HandleError err;
1.167 + IForward *pForward;
1.168 +
1.169 + if ((err=g_HandleSys.ReadHandle(hndl, g_GlobalFwdType, NULL, (void **)&pForward))
1.170 + != HandleError_None)
1.171 + {
1.172 + return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err);
1.173 + }
1.174 +
1.175 + return pForward->GetFunctionCount();
1.176 +}
1.177 +
1.178 +static cell_t sm_AddToForward(IPluginContext *pContext, const cell_t *params)
1.179 +{
1.180 + Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
1.181 + Handle_t plHandle = static_cast<Handle_t>(params[2]);
1.182 + HandleError err;
1.183 + IChangeableForward *pForward;
1.184 + IPlugin *pPlugin;
1.185 +
1.186 + if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
1.187 + != HandleError_None)
1.188 + {
1.189 + return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
1.190 + }
1.191 +
1.192 + if (plHandle == 0)
1.193 + {
1.194 + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
1.195 + } else {
1.196 + pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);
1.197 +
1.198 + if (!pPlugin)
1.199 + {
1.200 + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
1.201 + }
1.202 + }
1.203 +
1.204 + IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
1.205 +
1.206 + if (!pFunction)
1.207 + {
1.208 + return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
1.209 + }
1.210 +
1.211 + return pForward->AddFunction(pFunction);
1.212 +}
1.213 +
1.214 +static cell_t sm_RemoveFromForward(IPluginContext *pContext, const cell_t *params)
1.215 +{
1.216 + Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
1.217 + Handle_t plHandle = static_cast<Handle_t>(params[2]);
1.218 + HandleError err;
1.219 + IChangeableForward *pForward;
1.220 + IPlugin *pPlugin;
1.221 +
1.222 + if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
1.223 + != HandleError_None)
1.224 + {
1.225 + return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
1.226 + }
1.227 +
1.228 + if (plHandle == 0)
1.229 + {
1.230 + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
1.231 + } else {
1.232 + pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);
1.233 +
1.234 + if (!pPlugin)
1.235 + {
1.236 + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
1.237 + }
1.238 + }
1.239 +
1.240 + IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
1.241 +
1.242 + if (!pFunction)
1.243 + {
1.244 + return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
1.245 + }
1.246 +
1.247 + return pForward->RemoveFunction(pFunction);
1.248 +}
1.249 +
1.250 +static cell_t sm_RemoveAllFromForward(IPluginContext *pContext, const cell_t *params)
1.251 +{
1.252 + Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
1.253 + Handle_t plHandle = static_cast<Handle_t>(params[2]);
1.254 + HandleError err;
1.255 + IChangeableForward *pForward;
1.256 + IPlugin *pPlugin;
1.257 +
1.258 + if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
1.259 + != HandleError_None)
1.260 + {
1.261 + return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
1.262 + }
1.263 +
1.264 + if (plHandle == 0)
1.265 + {
1.266 + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
1.267 + } else {
1.268 + pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);
1.269 +
1.270 + if (!pPlugin)
1.271 + {
1.272 + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
1.273 + }
1.274 + }
1.275 +
1.276 + return pForward->RemoveFunctionsOfPlugin(pPlugin);
1.277 +}
1.278 +
1.279 +static cell_t sm_CallStartFunction(IPluginContext *pContext, const cell_t *params)
1.280 +{
1.281 + Handle_t hndl;
1.282 + HandleError err;
1.283 + IPlugin *pPlugin;
1.284 +
1.285 + if (s_CallStarted)
1.286 + {
1.287 + return pContext->ThrowNativeError("Cannot start a call while one is already in progress");
1.288 + }
1.289 +
1.290 + hndl = static_cast<Handle_t>(params[1]);
1.291 +
1.292 + if (hndl == 0)
1.293 + {
1.294 + pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
1.295 + } else {
1.296 + pPlugin = g_PluginSys.PluginFromHandle(hndl, &err);
1.297 +
1.298 + if (!pPlugin)
1.299 + {
1.300 + return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", hndl, err);
1.301 + }
1.302 + }
1.303 +
1.304 + s_pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[2]);
1.305 +
1.306 + if (!s_pFunction)
1.307 + {
1.308 + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
1.309 + }
1.310 +
1.311 + s_pCallable = static_cast<ICallable *>(s_pFunction);
1.312 +
1.313 + s_CallStarted = true;
1.314 +
1.315 + return 1;
1.316 +}
1.317 +
1.318 +static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params)
1.319 +{
1.320 + Handle_t hndl;
1.321 + HandleError err;
1.322 + IForward *pForward;
1.323 +
1.324 + if (s_CallStarted)
1.325 + {
1.326 + return pContext->ThrowNativeError("Cannot start a call while one is already in progress");
1.327 + }
1.328 +
1.329 + hndl = static_cast<Handle_t>(params[1]);
1.330 +
1.331 + if ((err=g_HandleSys.ReadHandle(hndl, g_GlobalFwdType, NULL, (void **)&pForward))
1.332 + != HandleError_None)
1.333 + {
1.334 + return pContext->ThrowNativeError("Invalid forward handle %x (error %d)", hndl, err);
1.335 + }
1.336 +
1.337 + s_pForward = pForward;
1.338 +
1.339 + s_pCallable = static_cast<ICallable *>(pForward);
1.340 +
1.341 + s_CallStarted = true;
1.342 +
1.343 + return 1;
1.344 +}
1.345 +
1.346 +static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params)
1.347 +{
1.348 + int err;
1.349 +
1.350 + if (!s_CallStarted)
1.351 + {
1.352 + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
1.353 + }
1.354 +
1.355 + err = s_pCallable->PushCell(params[1]);
1.356 +
1.357 + if (err)
1.358 + {
1.359 + s_pCallable->Cancel();
1.360 + ResetCall();
1.361 + return pContext->ThrowNativeErrorEx(err, NULL);
1.362 + }
1.363 +
1.364 + return 1;
1.365 +}
1.366 +
1.367 +static cell_t sm_CallPushCellRef(IPluginContext *pContext, const cell_t *params)
1.368 +{
1.369 + int err;
1.370 + cell_t *addr;
1.371 +
1.372 + if (!s_CallStarted)
1.373 + {
1.374 + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
1.375 + }
1.376 +
1.377 + pContext->LocalToPhysAddr(params[1], &addr);
1.378 +
1.379 + err = s_pCallable->PushCellByRef(addr);
1.380 +
1.381 + if (err)
1.382 + {
1.383 + s_pCallable->Cancel();
1.384 + ResetCall();
1.385 + return pContext->ThrowNativeErrorEx(err, NULL);
1.386 + }
1.387 +
1.388 + return 1;
1.389 +}
1.390 +
1.391 +static cell_t sm_CallPushFloat(IPluginContext *pContext, const cell_t *params)
1.392 +{
1.393 + int err;
1.394 +
1.395 + if (!s_CallStarted)
1.396 + {
1.397 + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
1.398 + }
1.399 +
1.400 + err = s_pCallable->PushFloat(sp_ctof(params[1]));
1.401 +
1.402 + if (err)
1.403 + {
1.404 + s_pCallable->Cancel();
1.405 + ResetCall();
1.406 + return pContext->ThrowNativeErrorEx(err, NULL);
1.407 + }
1.408 +
1.409 + return 1;
1.410 +}
1.411 +
1.412 +static cell_t sm_CallPushFloatRef(IPluginContext *pContext, const cell_t *params)
1.413 +{
1.414 + int err;
1.415 + cell_t *addr;
1.416 +
1.417 + if (!s_CallStarted)
1.418 + {
1.419 + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
1.420 + }
1.421 +
1.422 + pContext->LocalToPhysAddr(params[1], &addr);
1.423 +
1.424 + err = s_pCallable->PushFloatByRef(reinterpret_cast<float *>(addr));
1.425 +
1.426 + if (err)
1.427 + {
1.428 + s_pCallable->Cancel();
1.429 + ResetCall();
1.430 + return pContext->ThrowNativeErrorEx(err, NULL);
1.431 + }
1.432 +
1.433 + return 1;
1.434 +}
1.435 +
1.436 +static cell_t sm_CallPushArray(IPluginContext *pContext, const cell_t *params)
1.437 +{
1.438 + int err;
1.439 + cell_t *addr;
1.440 +
1.441 + if (!s_CallStarted)
1.442 + {
1.443 + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
1.444 + }
1.445 +
1.446 + pContext->LocalToPhysAddr(params[1], &addr);
1.447 +
1.448 + err = s_pCallable->PushArray(addr, params[2], NULL);
1.449 +
1.450 + if (err)
1.451 + {
1.452 + s_pCallable->Cancel();
1.453 + ResetCall();
1.454 + return pContext->ThrowNativeErrorEx(err, NULL);
1.455 + }
1.456 +
1.457 + return 1;
1.458 +}
1.459 +
1.460 +static cell_t sm_CallPushArrayEx(IPluginContext *pContext, const cell_t *params)
1.461 +{
1.462 + int err;
1.463 + cell_t *addr;
1.464 +
1.465 + if (!s_CallStarted)
1.466 + {
1.467 + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
1.468 + }
1.469 +
1.470 + pContext->LocalToPhysAddr(params[1], &addr);
1.471 +
1.472 + err = s_pCallable->PushArray(addr, params[2], params[3]);
1.473 +
1.474 + if (err)
1.475 + {
1.476 + s_pCallable->Cancel();
1.477 + ResetCall();
1.478 + return pContext->ThrowNativeErrorEx(err, NULL);
1.479 + }
1.480 +
1.481 + return 1;
1.482 +}
1.483 +
1.484 +static cell_t sm_CallPushString(IPluginContext *pContext, const cell_t *params)
1.485 +{
1.486 + int err;
1.487 + char *value;
1.488 +
1.489 + if (!s_CallStarted)
1.490 + {
1.491 + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
1.492 + }
1.493 +
1.494 + pContext->LocalToString(params[1], &value);
1.495 +
1.496 + err = s_pCallable->PushString(value);
1.497 +
1.498 + if (err)
1.499 + {
1.500 + s_pCallable->Cancel();
1.501 + ResetCall();
1.502 + return pContext->ThrowNativeErrorEx(err, NULL);
1.503 + }
1.504 +
1.505 + return 1;
1.506 +}
1.507 +
1.508 +static cell_t sm_CallPushStringEx(IPluginContext *pContext, const cell_t *params)
1.509 +{
1.510 + int err;
1.511 + char *value;
1.512 +
1.513 + if (!s_CallStarted)
1.514 + {
1.515 + return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
1.516 + }
1.517 +
1.518 + pContext->LocalToString(params[1], &value);
1.519 +
1.520 + err = s_pCallable->PushStringEx(value, params[2], params[3], params[4]);
1.521 +
1.522 + if (err)
1.523 + {
1.524 + s_pCallable->Cancel();
1.525 + ResetCall();
1.526 + return pContext->ThrowNativeErrorEx(err, NULL);
1.527 + }
1.528 +
1.529 + return 1;
1.530 +}
1.531 +
1.532 +static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
1.533 +{
1.534 + int err;
1.535 + cell_t *result;
1.536 +
1.537 + if (!s_CallStarted)
1.538 + {
1.539 + return pContext->ThrowNativeError("Cannot finish call when there is no call in progress");
1.540 + }
1.541 +
1.542 + pContext->LocalToPhysAddr(params[1], &result);
1.543 +
1.544 + if (s_pFunction)
1.545 + {
1.546 + IPluginFunction *pFunction = s_pFunction;
1.547 + err = pFunction->Execute(result);
1.548 + } else if (s_pForward) {
1.549 + IForward *pForward = s_pForward;
1.550 + err = pForward->Execute(result, NULL);
1.551 + }
1.552 +
1.553 + ResetCall();
1.554 +
1.555 + return err;
1.556 +}
1.557 +
1.558 +static cell_t sm_CallCancel(IPluginContext *pContext, const cell_t *params)
1.559 +{
1.560 + if (!s_CallStarted)
1.561 + {
1.562 + return pContext->ThrowNativeError("Cannot cancel call when there is no call in progress");
1.563 + }
1.564 +
1.565 + s_pCallable->Cancel();
1.566 + ResetCall();
1.567 +
1.568 + return 1;
1.569 +}
1.570 +
1.571 +REGISTER_NATIVES(functionNatives)
1.572 +{
1.573 + {"GetFunctionByName", sm_GetFunctionByName},
1.574 + {"CreateGlobalForward", sm_CreateGlobalForward},
1.575 + {"CreateForward", sm_CreateForward},
1.576 + {"GetForwardFunctionCount", sm_GetForwardFunctionCount},
1.577 + {"AddToForward", sm_AddToForward},
1.578 + {"RemoveFromForward", sm_RemoveFromForward},
1.579 + {"RemoveAllFromForward", sm_RemoveAllFromForward},
1.580 + {"Call_StartFunction", sm_CallStartFunction},
1.581 + {"Call_StartForward", sm_CallStartForward},
1.582 + {"Call_PushCell", sm_CallPushCell},
1.583 + {"Call_PushCellRef", sm_CallPushCellRef},
1.584 + {"Call_PushFloat", sm_CallPushFloat},
1.585 + {"Call_PushFloatRef", sm_CallPushFloatRef},
1.586 + {"Call_PushArray", sm_CallPushArray},
1.587 + {"Call_PushArrayEx", sm_CallPushArrayEx},
1.588 + {"Call_PushString", sm_CallPushString},
1.589 + {"Call_PushStringEx", sm_CallPushStringEx},
1.590 + {"Call_Finish", sm_CallFinish},
1.591 + {"Call_Cancel", sm_CallCancel},
1.592 + {NULL, NULL},
1.593 +};