3 * =============================================================================
4 * SourceMod Basic Commands Plugin
5 * Implements basic admin commands.
7 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
8 * =============================================================================
10 * This program is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License, version 3.0, as published by the
12 * Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
22 * As a special exception, AlliedModders LLC gives you permission to link the
23 * code of this program (as well as its derivative works) to "Half-Life 2," the
24 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
25 * by the Valve Corporation. You must obey the GNU General Public License in
26 * all respects for all other code used. Additionally, AlliedModders LLC grants
27 * this exception to all derivative works. AlliedModders LLC defines further
28 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
29 * or <http://www.sourcemod.net/license.php>.
38 public Plugin:myinfo =
40 name = "Basic Commands",
41 author = "AlliedModders LLC",
42 description = "Basic Admin Commands",
43 version = SOURCEMOD_VERSION,
44 url = "http://www.sourcemod.net/"
47 new Handle:hBanForward = INVALID_HANDLE;
48 new Handle:hAddBanForward = INVALID_HANDLE;
49 new Handle:hBanRemoved = INVALID_HANDLE;
51 public OnPluginStart()
53 LoadTranslations("common.phrases");
55 RegAdminCmd("sm_kick", Command_Kick, ADMFLAG_KICK, "sm_kick <#userid|name> [reason]");
56 RegAdminCmd("sm_map", Command_Map, ADMFLAG_CHANGEMAP, "sm_map <map>");
57 RegAdminCmd("sm_rcon", Command_Rcon, ADMFLAG_RCON, "sm_rcon <args>");
58 RegAdminCmd("sm_cvar", Command_Cvar, ADMFLAG_CONVARS, "sm_cvar <cvar> [value]");
59 RegAdminCmd("sm_execcfg", Command_ExecCfg, ADMFLAG_CONFIG, "sm_execcfg <filename>");
60 RegAdminCmd("sm_who", Command_Who, ADMFLAG_GENERIC, "sm_who [#userid|name]");
61 RegAdminCmd("sm_ban", Command_Ban, ADMFLAG_BAN, "sm_ban <#userid|name> <minutes|0> [reason]");
62 RegAdminCmd("sm_unban", Command_Unban, ADMFLAG_UNBAN, "sm_unban <steamid>");
63 RegAdminCmd("sm_addban", Command_AddBan, ADMFLAG_RCON, "sm_addban <time> <steamid> [reason]");
64 RegAdminCmd("sm_banip", Command_BanIp, ADMFLAG_BAN, "sm_banip <time> <ip|#userid|name> [reason]");
65 RegAdminCmd("sm_reloadadmins", Command_ReloadAdmins, ADMFLAG_BAN, "sm_reloadadmins");
66 RegAdminCmd("sm_cancelvote", Command_CancelVote, ADMFLAG_VOTE, "sm_cancelvote");
68 hBanForward = CreateGlobalForward("OnClientBanned", ET_Hook, Param_Cell, Param_Cell, Param_Cell, Param_String);
69 hAddBanForward = CreateGlobalForward("OnBanAdded", ET_Hook, Param_Cell, Param_String, Param_Cell, Param_String);
70 hBanRemoved = CreateGlobalForward("OnBanRemoved", ET_Hook, Param_Cell, Param_String);
73 public Action:Command_ReloadAdmins(client, args)
76 DumpAdminCache(AdminCache_Groups, true);
77 DumpAdminCache(AdminCache_Overrides, true);
79 LogMessage("\"%L\" refreshed the admin cache.", client);
80 ReplyToCommand(client, "[SM] %t", "Admin cache refreshed");
82 return Plugin_Handled;
85 public Action:Command_BanIp(client, args)
89 ReplyToCommand(client, "[SM] Usage: sm_banip <time> <ip|#userid|name> [reason]");
90 return Plugin_Handled;
93 decl String:arg[50], String:time[20];
94 GetCmdArg(1, time, sizeof(time));
95 GetCmdArg(2, arg, sizeof(arg));
97 if (StrEqual(arg, "0"))
99 ReplyToCommand(client, "[SM] %t", "Cannot ban that IP");
100 return Plugin_Handled;
104 new numClients = SearchForClients(arg, clients, 1);
108 if (client == 0 || (client == 1 && !IsDedicatedServer()))
112 new AdminId:id = GetUserAdmin(client);
113 has_rcon = (id == INVALID_ADMIN_ID) ? false : GetAdminFlag(id, Admin_RCON);
116 new bool:hit_client = false;
118 && !IsFakeClient(clients[0])
119 && (has_rcon || CanUserTarget(client, clients[0])))
121 GetClientIP(clients[0], arg, sizeof(arg));
125 if (!hit_client && !has_rcon)
127 ReplyToCommand(client, "[SM] %t", "No Access");
128 return Plugin_Handled;
131 new minutes = StringToInt(time);
133 decl String:reason[128];
136 GetCmdArg(3, reason, sizeof(reason));
139 new Action:act = Plugin_Continue;
140 Call_StartForward(hAddBanForward);
141 Call_PushCell(client);
142 Call_PushString(arg);
143 Call_PushCell(minutes);
144 Call_PushString(reason);
147 if (act < Plugin_Handled)
149 LogMessage("\"%L\" added ban (minutes \"%d\") (ip \"%s\") (reason \"%s\")", client, minutes, arg, reason);
150 ReplyToCommand(client, "[SM] %t", "Ban added");
153 if (act < Plugin_Stop)
155 ServerCommand("addip %d %s", minutes, arg);
156 ServerCommand("writeip");
159 return Plugin_Handled;
162 public Action:Command_AddBan(client, args)
166 ReplyToCommand(client, "[SM] Usage: sm_addban <time> <steamid> [reason]");
167 return Plugin_Handled;
170 decl String:arg[50], String:time[20];
171 GetCmdArg(1, time, sizeof(time));
172 GetCmdArg(2, arg, sizeof(arg));
174 new minutes = StringToInt(time);
176 new String:reason[128];
179 GetCmdArg(3, reason, sizeof(reason));
182 new Action:act = Plugin_Continue;
183 Call_StartForward(hAddBanForward);
184 Call_PushCell(client);
185 Call_PushString(arg);
186 Call_PushCell(minutes);
187 Call_PushString(reason);
190 if (act < Plugin_Handled)
192 LogMessage("\"%L\" added ban (minutes \"%d\") (id \"%s\") (reason \"%s\")", client, minutes, arg, reason);
193 ReplyToCommand(client, "[SM] %t", "Ban added");
196 if (act < Plugin_Stop)
198 ServerCommand("banid %d %s", minutes, arg);
199 ServerCommand("writeid");
202 return Plugin_Handled;
205 public Action:Command_Unban(client, args)
209 ReplyToCommand(client, "[SM] Usage: sm_unban <steamid>");
210 return Plugin_Handled;
213 decl String:arg[50], String:new_arg[50];
215 GetCmdArgString(arg, sizeof(arg));
217 if(arg[start] == '"')
222 if (strncmp(arg[start], "STEAM_0:", 8, false) == 0)
225 } else if (strncmp(arg[start], "0:1:", 4) == 0 || strncmp(arg[start], "0:0:", 4) == 0) {
229 Format(new_arg, sizeof(new_arg), "STEAM_0:%s", arg[start]);
231 /* Remove white spaces */
232 new len = TrimString(new_arg);
233 if(new_arg[len - 1] == '"')
235 new_arg[len - 1] = '\0';
238 new Action:act = Plugin_Continue;
239 Call_StartForward(hBanRemoved);
240 Call_PushCell(client);
241 Call_PushString(new_arg);
244 if (act < Plugin_Handled)
246 LogMessage("\"%L\" removed ban (filter \"%s\")", client, new_arg);
247 ReplyToCommand(client, "[SM] %t", "Removed bans matching", new_arg);
250 if (act < Plugin_Stop)
252 ServerCommand("removeid %s", new_arg);
253 ServerCommand("writeid");
256 return Plugin_Handled;
259 public Action:Command_Ban(client, args)
263 ReplyToCommand(client, "[SM] Usage: sm_ban <#userid|name> <minutes|0> [reason]");
264 return Plugin_Handled;
268 GetCmdArg(1, arg, sizeof(arg));
270 new target = FindTarget(client, arg, true);
273 return Plugin_Handled;
276 decl String:s_time[12];
277 GetCmdArg(2, s_time, sizeof(s_time));
279 new time = StringToInt(s_time);
281 decl String:reason[128];
284 GetCmdArg(3, reason, sizeof(reason));
289 decl String:authid[64];
290 GetClientAuthString(target, authid, sizeof(authid));
291 GetClientName(target, arg, sizeof(arg));
293 /* Fire the ban forward */
294 new Action:act = Plugin_Continue;
295 Call_StartForward(hBanForward);
296 Call_PushCell(client);
297 Call_PushCell(target);
299 Call_PushString(reason);
302 if (act < Plugin_Handled)
306 if (reason[0] == '\0')
308 ShowActivity(client, "%t", "Permabanned player", arg);
310 ShowActivity(client, "%t", "Permabanned player reason", arg, reason);
313 if (reason[0] == '\0')
315 ShowActivity(client, "%t", "Banned player", arg, time);
317 ShowActivity(client, "%t", "Banned player reason", arg, time, reason);
320 LogMessage("\"%L\" banned \"%L\" (minutes \"%d\") (reason \"%s\")", client, target, time, reason);
323 if (act < Plugin_Stop)
325 if (reason[0] == '\0')
327 strcopy(reason, sizeof(reason), "Banned");
330 ServerCommand("banid %d %s", time, authid);
331 KickClient(target, "%s", reason);
335 ServerCommand("writeid");
339 return Plugin_Handled;
342 #define FLAG_STRINGS 14
343 new String:g_FlagNames[FLAG_STRINGS][20] =
361 FlagsToString(String:buffer[], maxlength, flags)
363 decl String:joins[FLAG_STRINGS][20];
366 for (new i=0; i<FLAG_STRINGS; i++)
370 strcopy(joins[total++], 20, g_FlagNames[i]);
374 ImplodeStrings(joins, total, ", ", buffer, maxlength);
377 public Action:Command_Who(client, args)
382 decl String:t_access[16], String:t_name[16];
383 Format(t_access, sizeof(t_access), "%t", "Access", client);
384 Format(t_name, sizeof(t_name), "%t", "Name", client);
386 PrintToConsole(client, "%-24.23s %s", t_name, t_access);
388 /* List all players */
389 new maxClients = GetMaxClients();
390 decl String:flagstring[255];
392 for (new i=1; i<=maxClients; i++)
394 if (!IsClientInGame(i))
398 new flags = GetUserFlagBits(i);
401 strcopy(flagstring, sizeof(flagstring), "none");
402 } else if (flags & ADMFLAG_ROOT) {
403 strcopy(flagstring, sizeof(flagstring), "root");
405 FlagsToString(flagstring, sizeof(flagstring), flags);
407 decl String:name[65];
408 GetClientName(i, name, sizeof(name));
409 PrintToConsole(client, "%d. %-24.23s %s", i, name, flagstring);
412 if (GetCmdReplySource() == SM_REPLY_TO_CHAT)
414 ReplyToCommand(client, "[SM] %t", "See console for output");
417 return Plugin_Handled;
421 GetCmdArg(1, arg, sizeof(arg));
424 new numClients = SearchForClients(arg, clients, 2);
428 ReplyToCommand(client, "[SM] %t", "No matching client");
429 return Plugin_Handled;
430 } else if (numClients > 1) {
431 ReplyToCommand(client, "[SM] %t", "More than one client matches", arg);
432 return Plugin_Handled;
435 new flags = GetUserFlagBits(clients[0]);
436 decl String:flagstring[255];
439 strcopy(flagstring, sizeof(flagstring), "none");
440 } else if (flags & ADMFLAG_ROOT) {
441 strcopy(flagstring, sizeof(flagstring), "root");
443 FlagsToString(flagstring, sizeof(flagstring), flags);
446 ReplyToCommand(client, "[SM] %t: %s", "Access", flagstring);
448 return Plugin_Handled;
451 public Action:Command_ExecCfg(client, args)
455 ReplyToCommand(client, "[SM] Usage: sm_execcfg <filename>");
456 return Plugin_Handled;
459 new String:path[64] = "cfg/";
460 GetCmdArg(1, path[4], sizeof(path)-4);
462 if (!FileExists(path))
464 ReplyToCommand(client, "[SM] %t", "Config not found", path[4]);
465 return Plugin_Handled;
468 ShowActivity(client, "%t", "Executed config", path[4]);
470 LogMessage("\"%L\" executed config (file \"%s\")", client, path[4]);
472 ServerCommand("exec \"%s\"", path[4]);
474 return Plugin_Handled;
477 public Action:Command_Cvar(client, args)
481 ReplyToCommand(client, "[SM] Usage: sm_cvar <cvar> [value]");
482 return Plugin_Handled;
485 decl String:cvarname[33];
486 GetCmdArg(1, cvarname, sizeof(cvarname));
488 new Handle:hndl = FindConVar(cvarname);
489 if (hndl == INVALID_HANDLE)
491 ReplyToCommand(client, "[SM] %t", "Unable to find cvar", cvarname);
492 return Plugin_Handled;
495 new bool:allowed = false;
496 if (GetConVarFlags(hndl) & FCVAR_PROTECTED)
498 /* If they're root, allow anything */
499 if ((GetUserFlagBits(client) & ADMFLAG_ROOT) == ADMFLAG_ROOT)
503 /* If they're not root, and getting sv_password, see if they have ADMFLAG_PASSWORD */
504 else if (StrEqual(cvarname, "sv_password") && (GetUserFlagBits(client) & ADMFLAG_PASSWORD))
509 /* Do a check for the cheat cvar */
510 else if (StrEqual(cvarname, "sv_cheats"))
512 if (GetUserFlagBits(client) & ADMFLAG_CHEATS
513 || GetUserFlagBits(client) & ADMFLAG_ROOT)
518 /* If we drop down to here, it was a normal cvar. */
526 ReplyToCommand(client, "[SM] %t", "No access to cvar");
527 return Plugin_Handled;
530 decl String:value[255];
533 GetConVarString(hndl, value, sizeof(value));
535 ReplyToCommand(client, "[SM] %t", "Value of cvar", cvarname, value);
536 return Plugin_Handled;
539 GetCmdArg(2, value, sizeof(value));
541 if ((GetConVarFlags(hndl) & FCVAR_PROTECTED) != FCVAR_PROTECTED)
543 ShowActivity(client, "%t", "Cvar changed", cvarname, value);
545 ReplyToCommand(client, "[SM] %t", "Cvar changed", cvarname, value);
548 LogMessage("\"%L\" changed cvar (cvar \"%s\") (value \"%s\")", client, cvarname, value);
550 SetConVarString(hndl, value, true);
552 return Plugin_Handled;
555 public Action:Command_Rcon(client, args)
559 ReplyToCommand(client, "[SM] Usage: sm_rcon <args>");
560 return Plugin_Handled;
563 decl String:argstring[255];
564 GetCmdArgString(argstring, sizeof(argstring));
566 LogMessage("\"%L\" console command (cmdline \"%s\")", client, argstring);
568 ServerCommand("%s", argstring);
570 return Plugin_Handled;
573 public Action:Command_Map(client, args)
577 ReplyToCommand(client, "[SM] Usage: sm_map <map>");
578 return Plugin_Handled;
582 GetCmdArg(1, map, sizeof(map));
584 if (!IsMapValid(map))
586 ReplyToCommand(client, "[SM] %t", "Map was not found", map);
587 return Plugin_Handled;
590 ShowActivity(client, "%t", "Changing map", map);
592 LogMessage("\"%L\" changed map to \"%s\"", client, map);
595 CreateDataTimer(3.0, Timer_ChangeMap, dp);
596 WritePackString(dp, map);
598 return Plugin_Handled;
601 public Action:Timer_ChangeMap(Handle:timer, Handle:dp)
606 ReadPackString(dp, map, sizeof(map));
608 ServerCommand("changelevel \"%s\"", map);
613 public Action:Command_Kick(client, args)
617 ReplyToCommand(client, "[SM] Usage: sm_kick <#userid|name> [reason]");
618 return Plugin_Handled;
622 decl String:Arguments[256];
623 GetCmdArgString(Arguments, sizeof(Arguments));
626 new len = BreakString(Arguments, arg, sizeof(arg));
628 new target = FindTarget(client, arg);
631 return Plugin_Handled;
634 GetClientName(target, arg, sizeof(arg));
638 /* Safely null terminate */
643 ShowActivity(client, "%t", "Kicked player", arg);
644 LogMessage("\"%L\" kicked \"%L\" (reason \"%s\")", client, target, Arguments[len]);
646 KickClient(target, "%s", Arguments[len]);
648 return Plugin_Handled;
651 public Action:Command_CancelVote(client, args)
653 if (!IsVoteInProgress())
655 ReplyToCommand(client, "[SM] %t", "Vote Not In Progress");
656 return Plugin_Handled;
659 ShowActivity(client, "%t", "Cancelled Vote");
663 return Plugin_Handled;