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"
25 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
27 char *name, *defaultVal, *helpText;
29 pContext->LocalToString(params[1], &name);
31 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
32 if (name == NULL || strcmp(name, "") == 0)
34 return pContext->ThrowNativeError("Convar with blank name is not permitted");
37 pContext->LocalToString(params[2], &defaultVal);
38 pContext->LocalToString(params[3], &helpText);
40 bool hasMin = params[5] ? true : false;
41 bool hasMax = params[7] ? true : false;
42 float min = sp_ctof(params[6]);
43 float max = sp_ctof(params[8]);
45 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
47 if (hndl == BAD_HANDLE)
49 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name);
55 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
59 pContext->LocalToString(params[1], &name);
61 return g_ConVarManager.FindConVar(name);
64 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
66 Handle_t hndl = static_cast<Handle_t>(params[1]);
70 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
73 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
76 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
80 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
83 g_ConVarManager.HookConVarChange(pConVar, pFunction);
88 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
90 Handle_t hndl = static_cast<Handle_t>(params[1]);
94 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
97 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
100 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
104 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
107 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
112 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
114 Handle_t hndl = static_cast<Handle_t>(params[1]);
118 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
121 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
124 return pConVar->GetBool();
127 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
129 Handle_t hndl = static_cast<Handle_t>(params[1]);
133 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
136 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
139 return pConVar->GetInt();
142 /* This handles both SetConVarBool() and SetConVarInt() */
143 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
145 Handle_t hndl = static_cast<Handle_t>(params[1]);
149 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
152 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
155 pConVar->SetValue(params[2]);
160 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
162 Handle_t hndl = static_cast<Handle_t>(params[1]);
166 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
169 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
172 float value = pConVar->GetFloat();
174 return sp_ftoc(value);
177 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
179 Handle_t hndl = static_cast<Handle_t>(params[1]);
183 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
186 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
189 float value = sp_ctof(params[2]);
190 pConVar->SetValue(value);
195 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
197 Handle_t hndl = static_cast<Handle_t>(params[1]);
201 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
204 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
207 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
212 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
214 Handle_t hndl = static_cast<Handle_t>(params[1]);
218 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
221 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
225 pContext->LocalToString(params[2], &value);
227 pConVar->SetValue(value);
232 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
234 Handle_t hndl = static_cast<Handle_t>(params[1]);
238 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
241 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
244 return pConVar->GetFlags();
247 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
249 Handle_t hndl = static_cast<Handle_t>(params[1]);
253 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
256 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
259 pConVar->SetFlags(params[2]);
264 static cell_t sm_GetConVarMin(IPluginContext *pContext, const cell_t *params)
266 Handle_t hndl = static_cast<Handle_t>(params[1]);
270 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
273 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
280 pContext->LocalToPhysAddr(params[2], &addr);
282 hasMin = pConVar->GetMin(min);
283 *addr = sp_ftoc(min);
288 static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params)
290 Handle_t hndl = static_cast<Handle_t>(params[1]);
294 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
297 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
304 pContext->LocalToPhysAddr(params[2], &addr);
306 hasMax = pConVar->GetMax(max);
307 *addr = sp_ftoc(max);
312 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
314 Handle_t hndl = static_cast<Handle_t>(params[1]);
318 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
321 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
324 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
329 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
331 Handle_t hndl = static_cast<Handle_t>(params[1]);
335 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
338 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
346 static bool s_QueryAlreadyWarned = false;
348 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
352 IPluginFunction *pCallback;
354 if (g_IsOriginalEngine)
356 if (!s_QueryAlreadyWarned)
358 s_QueryAlreadyWarned = true;
359 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
365 pPlayer = g_Players.GetPlayerByIndex(params[1]);
369 return pContext->ThrowNativeError("Player %d is not a valid player", params[1]);
372 if (!pPlayer->IsConnected())
374 return pContext->ThrowNativeError("Player %d is not connected", params[1]);
377 /* Trying a query on a bot results in callback not be fired, so don't bother */
378 if (pPlayer->IsFakeClient())
383 pContext->LocalToString(params[2], &name);
384 pCallback = pContext->GetFunctionById(params[3]);
388 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
391 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
394 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
397 IPluginFunction *pFunction;
399 pContext->LocalToString(params[1], &name);
400 pContext->LocalToString(params[3], &help);
401 pFunction = pContext->GetFunctionById(params[2]);
405 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
408 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
410 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
416 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
419 IPluginFunction *pFunction;
421 pContext->LocalToString(params[1], &name);
422 pContext->LocalToString(params[3], &help);
423 pFunction = pContext->GetFunctionById(params[2]);
427 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
430 if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
432 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
438 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
442 IPluginFunction *pFunction;
443 FlagBits flags = params[3];
444 int cmdflags = params[6];
446 pContext->LocalToString(params[1], &name);
447 pContext->LocalToString(params[4], &help);
448 pContext->LocalToString(params[5], (char **)&group);
449 pFunction = pContext->GetFunctionById(params[2]);
451 if (group[0] == '\0')
453 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
454 group = pPlugin->GetFilename();
459 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
462 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
464 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
470 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
472 return engine->Cmd_Argc() - 1;
475 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
477 const char *arg = engine->Cmd_Argv(params[1]);
479 pContext->StringToLocalUTF8(params[2], params[3], arg, NULL);
484 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
486 const char *args = engine->Cmd_Args();
493 pContext->StringToLocalUTF8(params[1], params[2], args, NULL);
498 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
504 pCtx->LocalToString(params[1], &fmt);
505 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
507 buffer[res++] = '\n';
510 META_CONPRINT(buffer);
515 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
517 int index = params[1];
518 if ((index < 0) || (index > g_Players.GetMaxClients()))
520 return pCtx->ThrowNativeError("Invalid client index %d", index);
523 CPlayer *pPlayer = NULL;
526 pPlayer = g_Players.GetPlayerByIndex(index);
527 if (!pPlayer->IsInGame())
529 return pCtx->ThrowNativeError("Client %d is not in game", index);
532 /* Silent fail on bots, engine will crash */
533 if (pPlayer->IsFakeClient())
543 pCtx->LocalToString(params[2], &fmt);
544 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
546 buffer[res++] = '\n';
551 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
553 META_CONPRINT(buffer);
559 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
562 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
564 /* One byte for null terminator, one for newline */
565 buffer[len++] = '\n';
568 engine->ServerCommand(buffer);
573 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
576 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
578 /* One byte for null terminator, one for newline */
579 buffer[len++] = '\n';
582 engine->InsertServerCommand(buffer);
587 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
589 engine->ServerExecute();
594 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
596 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
600 return pContext->ThrowNativeError("Player %d is not a valid player", params[1]);
603 if (!pPlayer->IsConnected())
605 return pContext->ThrowNativeError("Player %d is not connected", params[1]);
609 g_SourceMod.FormatString(buffer, sizeof(buffer)-1, pContext, params, 2);
611 engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
616 REGISTER_NATIVES(consoleNatives)
618 {"CreateConVar", sm_CreateConVar},
619 {"FindConVar", sm_FindConVar},
620 {"HookConVarChange", sm_HookConVarChange},
621 {"UnhookConVarChange", sm_UnhookConVarChange},
622 {"GetConVarBool", sm_GetConVarBool},
623 {"SetConVarBool", sm_SetConVarNum},
624 {"GetConVarInt", sm_GetConVarInt},
625 {"SetConVarInt", sm_SetConVarNum},
626 {"GetConVarFloat", sm_GetConVarFloat},
627 {"SetConVarFloat", sm_SetConVarFloat},
628 {"GetConVarString", sm_GetConVarString},
629 {"SetConVarString", sm_SetConVarString},
630 {"GetConVarFlags", sm_GetConVarFlags},
631 {"SetConVarFlags", sm_SetConVarFlags},
632 {"GetConVarName", sm_GetConVarName},
633 {"GetConVarMin", sm_GetConVarMin},
634 {"GetConVarMax", sm_GetConVarMax},
635 {"ResetConVar", sm_ResetConVar},
636 {"QueryClientConVar", sm_QueryClientConVar},
637 {"RegServerCmd", sm_RegServerCmd},
638 {"RegConsoleCmd", sm_RegConsoleCmd},
639 {"GetCmdArgString", sm_GetCmdArgString},
640 {"GetCmdArgs", sm_GetCmdArgs},
641 {"GetCmdArg", sm_GetCmdArg},
642 {"PrintToServer", sm_PrintToServer},
643 {"PrintToConsole", sm_PrintToConsole},
644 {"RegAdminCmd", sm_RegAdminCmd},
645 {"ServerCommand", sm_ServerCommand},
646 {"InsertServerCommand", sm_InsertServerCommand},
647 {"ServerExecute", sm_ServerExecute},
648 {"ClientCommand", sm_ClientCommand},