3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
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
15 #include "sm_globals.h"
16 #include "HalfLife2.h"
17 #include "sourcemm_api.h"
18 #include "HandleSys.h"
19 #include "ConVarManager.h"
20 #include "ConCmdManager.h"
21 #include "PluginSys.h"
22 #include "sm_stringutil.h"
23 #include "PlayerManager.h"
27 ConVarBound_Upper = 0,
31 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
33 char *name, *defaultVal, *helpText;
35 pContext->LocalToString(params[1], &name);
37 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
38 if (name == NULL || strcmp(name, "") == 0)
40 return pContext->ThrowNativeError("Convar with blank name is not permitted");
43 pContext->LocalToString(params[2], &defaultVal);
44 pContext->LocalToString(params[3], &helpText);
46 bool hasMin = params[5] ? true : false;
47 bool hasMax = params[7] ? true : false;
48 float min = sp_ctof(params[6]);
49 float max = sp_ctof(params[8]);
51 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
53 if (hndl == BAD_HANDLE)
55 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name);
61 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
65 pContext->LocalToString(params[1], &name);
67 return g_ConVarManager.FindConVar(name);
70 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
72 Handle_t hndl = static_cast<Handle_t>(params[1]);
76 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
79 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
82 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
86 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
89 g_ConVarManager.HookConVarChange(pConVar, pFunction);
94 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
96 Handle_t hndl = static_cast<Handle_t>(params[1]);
100 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
103 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
106 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
110 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
113 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
118 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
120 Handle_t hndl = static_cast<Handle_t>(params[1]);
124 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
127 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
130 return pConVar->GetBool();
133 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
135 Handle_t hndl = static_cast<Handle_t>(params[1]);
139 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
142 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
145 return pConVar->GetInt();
148 /* This handles both SetConVarBool() and SetConVarInt() */
149 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
151 Handle_t hndl = static_cast<Handle_t>(params[1]);
155 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
158 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
161 pConVar->SetValue(params[2]);
166 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
168 Handle_t hndl = static_cast<Handle_t>(params[1]);
172 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
175 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
178 float value = pConVar->GetFloat();
180 return sp_ftoc(value);
183 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
185 Handle_t hndl = static_cast<Handle_t>(params[1]);
189 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
192 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
195 float value = sp_ctof(params[2]);
196 pConVar->SetValue(value);
201 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
203 Handle_t hndl = static_cast<Handle_t>(params[1]);
207 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
210 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
213 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
218 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
220 Handle_t hndl = static_cast<Handle_t>(params[1]);
224 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
227 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
231 pContext->LocalToString(params[2], &value);
233 pConVar->SetValue(value);
238 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
240 Handle_t hndl = static_cast<Handle_t>(params[1]);
244 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
247 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
250 return pConVar->GetFlags();
253 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
255 Handle_t hndl = static_cast<Handle_t>(params[1]);
259 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
262 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
265 pConVar->SetFlags(params[2]);
270 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
272 Handle_t hndl = static_cast<Handle_t>(params[1]);
276 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
279 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
288 case ConVarBound_Upper:
289 hasBound = pConVar->GetMax(bound);
291 case ConVarBound_Lower:
292 hasBound = pConVar->GetMin(bound);
295 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
298 pContext->LocalToPhysAddr(params[3], &addr);
299 *addr = sp_ftoc(bound);
304 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
306 Handle_t hndl = static_cast<Handle_t>(params[1]);
310 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
313 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
318 case ConVarBound_Upper:
319 pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
321 case ConVarBound_Lower:
322 pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
325 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
331 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
333 Handle_t hndl = static_cast<Handle_t>(params[1]);
337 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
340 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
343 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
348 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
350 Handle_t hndl = static_cast<Handle_t>(params[1]);
354 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
357 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
365 static bool s_QueryAlreadyWarned = false;
367 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
371 IPluginFunction *pCallback;
373 if (g_IsOriginalEngine)
375 if (!s_QueryAlreadyWarned)
377 s_QueryAlreadyWarned = true;
378 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
384 pPlayer = g_Players.GetPlayerByIndex(params[1]);
388 return pContext->ThrowNativeError("Player %d is not a valid player", params[1]);
391 if (!pPlayer->IsConnected())
393 return pContext->ThrowNativeError("Player %d is not connected", params[1]);
396 /* Trying a query on a bot results in callback not be fired, so don't bother */
397 if (pPlayer->IsFakeClient())
402 pContext->LocalToString(params[2], &name);
403 pCallback = pContext->GetFunctionById(params[3]);
407 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
410 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
413 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
416 IPluginFunction *pFunction;
418 pContext->LocalToString(params[1], &name);
419 pContext->LocalToString(params[3], &help);
420 pFunction = pContext->GetFunctionById(params[2]);
424 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
427 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
429 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
435 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
438 IPluginFunction *pFunction;
440 pContext->LocalToString(params[1], &name);
441 pContext->LocalToString(params[3], &help);
442 pFunction = pContext->GetFunctionById(params[2]);
446 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
449 if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
451 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
457 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
461 IPluginFunction *pFunction;
462 FlagBits flags = params[3];
463 int cmdflags = params[6];
465 pContext->LocalToString(params[1], &name);
466 pContext->LocalToString(params[4], &help);
467 pContext->LocalToString(params[5], (char **)&group);
468 pFunction = pContext->GetFunctionById(params[2]);
470 if (group[0] == '\0')
472 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
473 group = pPlugin->GetFilename();
478 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
481 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
483 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
489 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
491 return engine->Cmd_Argc() - 1;
494 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
496 const char *arg = engine->Cmd_Argv(params[1]);
498 pContext->StringToLocalUTF8(params[2], params[3], arg, NULL);
503 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
505 const char *args = engine->Cmd_Args();
512 pContext->StringToLocalUTF8(params[1], params[2], args, NULL);
517 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
523 pCtx->LocalToString(params[1], &fmt);
524 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
526 buffer[res++] = '\n';
529 META_CONPRINT(buffer);
534 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
536 int index = params[1];
537 if ((index < 0) || (index > g_Players.GetMaxClients()))
539 return pCtx->ThrowNativeError("Invalid client index %d", index);
542 CPlayer *pPlayer = NULL;
545 pPlayer = g_Players.GetPlayerByIndex(index);
546 if (!pPlayer->IsInGame())
548 return pCtx->ThrowNativeError("Client %d is not in game", index);
551 /* Silent fail on bots, engine will crash */
552 if (pPlayer->IsFakeClient())
562 pCtx->LocalToString(params[2], &fmt);
563 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
565 buffer[res++] = '\n';
570 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
572 META_CONPRINT(buffer);
578 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
581 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
583 /* One byte for null terminator, one for newline */
584 buffer[len++] = '\n';
587 engine->ServerCommand(buffer);
592 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
595 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
597 /* One byte for null terminator, one for newline */
598 buffer[len++] = '\n';
601 engine->InsertServerCommand(buffer);
606 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
608 engine->ServerExecute();
613 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
615 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
619 return pContext->ThrowNativeError("Player %d is not a valid player", params[1]);
622 if (!pPlayer->IsConnected())
624 return pContext->ThrowNativeError("Player %d is not connected", params[1]);
628 g_SourceMod.FormatString(buffer, sizeof(buffer)-1, pContext, params, 2);
630 engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
635 REGISTER_NATIVES(consoleNatives)
637 {"CreateConVar", sm_CreateConVar},
638 {"FindConVar", sm_FindConVar},
639 {"HookConVarChange", sm_HookConVarChange},
640 {"UnhookConVarChange", sm_UnhookConVarChange},
641 {"GetConVarBool", sm_GetConVarBool},
642 {"SetConVarBool", sm_SetConVarNum},
643 {"GetConVarInt", sm_GetConVarInt},
644 {"SetConVarInt", sm_SetConVarNum},
645 {"GetConVarFloat", sm_GetConVarFloat},
646 {"SetConVarFloat", sm_SetConVarFloat},
647 {"GetConVarString", sm_GetConVarString},
648 {"SetConVarString", sm_SetConVarString},
649 {"GetConVarFlags", sm_GetConVarFlags},
650 {"SetConVarFlags", sm_SetConVarFlags},
651 {"GetConVarName", sm_GetConVarName},
652 {"GetConVarBounds", sm_GetConVarBounds},
653 {"SetConVarBounds", sm_SetConVarBounds},
654 {"ResetConVar", sm_ResetConVar},
655 {"QueryClientConVar", sm_QueryClientConVar},
656 {"RegServerCmd", sm_RegServerCmd},
657 {"RegConsoleCmd", sm_RegConsoleCmd},
658 {"GetCmdArgString", sm_GetCmdArgString},
659 {"GetCmdArgs", sm_GetCmdArgs},
660 {"GetCmdArg", sm_GetCmdArg},
661 {"PrintToServer", sm_PrintToServer},
662 {"PrintToConsole", sm_PrintToConsole},
663 {"RegAdminCmd", sm_RegAdminCmd},
664 {"ServerCommand", sm_ServerCommand},
665 {"InsertServerCommand", sm_InsertServerCommand},
666 {"ServerExecute", sm_ServerExecute},
667 {"ClientCommand", sm_ClientCommand},