plugins/basecommands.sp
author David Anderson <dvander@alliedmods.net>
Mon Aug 12 00:24:02 2013 +0100 (2013-08-12)
changeset 3993 d06d6dacfa18
parent 3887 3e8a8d9903ce
permissions -rw-r--r--
Remove InfoVars, reassign DAT from EBP to ESI to preserve C++ stacktraces in JIT code (bug 5844 part 10, r=ds).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Basic Commands Plugin
     5  * Implements basic admin commands.
     6  *
     7  * SourceMod (C)2004-2008 AlliedModders LLC.  All rights reserved.
     8  * =============================================================================
     9  *
    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.
    13  * 
    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
    17  * details.
    18  *
    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/>.
    21  *
    22  * As a special exception, AlliedModders LLC gives you permission to link the
    23  * code of this program (as well as its derivative 1works) 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>.
    30  *
    31  * Version: $Id$
    32  */
    33 
    34 #pragma semicolon 1
    35 
    36 #include <sourcemod>
    37 #undef REQUIRE_PLUGIN
    38 #include <adminmenu>
    39 
    40 public Plugin:myinfo =
    41 {
    42 	name = "Basic Commands",
    43 	author = "AlliedModders LLC",
    44 	description = "Basic Admin Commands",
    45 	version = SOURCEMOD_VERSION,
    46 	url = "http://www.sourcemod.net/"
    47 };
    48 
    49 new Handle:hTopMenu = INVALID_HANDLE;
    50 
    51 new Handle:g_MapList;
    52 new Handle:g_ProtectedVars;
    53 
    54 #include "basecommands/kick.sp"
    55 #include "basecommands/reloadadmins.sp"
    56 #include "basecommands/cancelvote.sp"
    57 #include "basecommands/who.sp"
    58 #include "basecommands/map.sp"
    59 #include "basecommands/execcfg.sp"
    60 
    61 public OnPluginStart()
    62 {
    63 	LoadTranslations("common.phrases");
    64 	LoadTranslations("plugin.basecommands");
    65 
    66 	RegAdminCmd("sm_kick", Command_Kick, ADMFLAG_KICK, "sm_kick <#userid|name> [reason]");
    67 	RegAdminCmd("sm_map", Command_Map, ADMFLAG_CHANGEMAP, "sm_map <map>");
    68 	RegAdminCmd("sm_rcon", Command_Rcon, ADMFLAG_RCON, "sm_rcon <args>");
    69 	RegAdminCmd("sm_cvar", Command_Cvar, ADMFLAG_CONVARS, "sm_cvar <cvar> [value]");
    70 	RegAdminCmd("sm_resetcvar", Command_ResetCvar, ADMFLAG_CONVARS, "sm_resetcvar <cvar>");
    71 	RegAdminCmd("sm_execcfg", Command_ExecCfg, ADMFLAG_CONFIG, "sm_execcfg <filename>");
    72 	RegAdminCmd("sm_who", Command_Who, ADMFLAG_GENERIC, "sm_who [#userid|name]");
    73 	RegAdminCmd("sm_reloadadmins", Command_ReloadAdmins, ADMFLAG_BAN, "sm_reloadadmins");
    74 	RegAdminCmd("sm_cancelvote", Command_CancelVote, ADMFLAG_VOTE, "sm_cancelvote");
    75 	RegConsoleCmd("sm_revote", Command_ReVote);
    76 	
    77 	/* Account for late loading */
    78 	new Handle:topmenu;
    79 	if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != INVALID_HANDLE))
    80 	{
    81 		OnAdminMenuReady(topmenu);
    82 	}
    83 	
    84 	g_MapList = CreateMenu(MenuHandler_ChangeMap, MenuAction_Display);
    85 	SetMenuTitle(g_MapList, "%T", "Please select a map", LANG_SERVER);
    86 	SetMenuExitBackButton(g_MapList, true);
    87 	
    88 	decl String:mapListPath[PLATFORM_MAX_PATH];
    89 	BuildPath(Path_SM, mapListPath, sizeof(mapListPath), "configs/adminmenu_maplist.ini");
    90 	SetMapListCompatBind("sm_map menu", mapListPath);
    91 	
    92 	g_ProtectedVars = CreateTrie();
    93 	ProtectVar("rcon_password");
    94 	ProtectVar("sm_show_activity");
    95 	ProtectVar("sm_immunity_mode");
    96 }
    97 
    98 public OnMapStart()
    99 {
   100 	ParseConfigs();
   101 }
   102 
   103 public OnConfigsExecuted()
   104 {
   105 	LoadMapList(g_MapList);
   106 }
   107 
   108 ProtectVar(const String:cvar[])
   109 {
   110 	SetTrieValue(g_ProtectedVars, cvar, 1);
   111 }
   112 
   113 bool:IsVarProtected(const String:cvar[])
   114 {
   115 	decl dummy_value;
   116 	return GetTrieValue(g_ProtectedVars, cvar, dummy_value);
   117 }
   118 
   119 bool:IsClientAllowedToChangeCvar(client, const String:cvarname[])
   120 {
   121 	new Handle:hndl = FindConVar(cvarname);
   122 
   123 	new bool:allowed = false;
   124 	new client_flags = client == 0 ? ADMFLAG_ROOT : GetUserFlagBits(client);
   125 	
   126 	if (client_flags & ADMFLAG_ROOT)
   127 	{
   128 		allowed = true;
   129 	}
   130 	else
   131 	{
   132 		if (GetConVarFlags(hndl) & FCVAR_PROTECTED)
   133 		{
   134 			allowed = ((client_flags & ADMFLAG_PASSWORD) == ADMFLAG_PASSWORD);
   135 		}
   136 		else if (StrEqual(cvarname, "sv_cheats"))
   137 		{
   138 			allowed = ((client_flags & ADMFLAG_CHEATS) == ADMFLAG_CHEATS);
   139 		}
   140 		else if (!IsVarProtected(cvarname))
   141 		{
   142 			allowed = true;
   143 		}
   144 	}
   145 
   146 	return allowed;
   147 }
   148 
   149 public OnAdminMenuReady(Handle:topmenu)
   150 {
   151 	/* Block us from being called twice */
   152 	if (topmenu == hTopMenu)
   153 	{
   154 		return;
   155 	}
   156 	
   157 	/* Save the Handle */
   158 	hTopMenu = topmenu;
   159 	
   160 	/* Build the "Player Commands" category */
   161 	new TopMenuObject:player_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_PLAYERCOMMANDS);
   162 	
   163 	if (player_commands != INVALID_TOPMENUOBJECT)
   164 	{
   165 		AddToTopMenu(hTopMenu, 
   166 			"sm_kick",
   167 			TopMenuObject_Item,
   168 			AdminMenu_Kick,
   169 			player_commands,
   170 			"sm_kick",
   171 			ADMFLAG_KICK);
   172 			
   173 		AddToTopMenu(hTopMenu,
   174 			"sm_who",
   175 			TopMenuObject_Item,
   176 			AdminMenu_Who,
   177 			player_commands,
   178 			"sm_who",
   179 			ADMFLAG_GENERIC);
   180 	}
   181 
   182 	new TopMenuObject:server_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_SERVERCOMMANDS);
   183 
   184 	if (server_commands != INVALID_TOPMENUOBJECT)
   185 	{
   186 		AddToTopMenu(hTopMenu,
   187 			"sm_reloadadmins",
   188 			TopMenuObject_Item,
   189 			AdminMenu_ReloadAdmins,
   190 			server_commands,
   191 			"sm_reloadadmins",
   192 			ADMFLAG_BAN);
   193 			
   194 		AddToTopMenu(hTopMenu,
   195 			"sm_map",
   196 			TopMenuObject_Item,
   197 			AdminMenu_Map,
   198 			server_commands,
   199 			"sm_map",
   200 			ADMFLAG_CHANGEMAP);
   201 			
   202 		AddToTopMenu(hTopMenu,
   203 			"sm_execcfg",
   204 			TopMenuObject_Item,
   205 			AdminMenu_ExecCFG,
   206 			server_commands,
   207 			"sm_execcfg",
   208 			ADMFLAG_CONFIG);		
   209 	}
   210 
   211 	new TopMenuObject:voting_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_VOTINGCOMMANDS);
   212 
   213 	if (voting_commands != INVALID_TOPMENUOBJECT)
   214 	{
   215 		AddToTopMenu(hTopMenu,
   216 			"sm_cancelvote",
   217 			TopMenuObject_Item,
   218 			AdminMenu_CancelVote,
   219 			voting_commands,
   220 			"sm_cancelvote",
   221 			ADMFLAG_VOTE);
   222 	}
   223 }
   224 
   225 public OnLibraryRemoved(const String:name[])
   226 {
   227 	if (strcmp(name, "adminmenu") == 0)
   228 	{
   229 		hTopMenu = INVALID_HANDLE;
   230 	}
   231 }
   232 
   233 #define FLAG_STRINGS		14
   234 new String:g_FlagNames[FLAG_STRINGS][20] =
   235 {
   236 	"res",
   237 	"admin",
   238 	"kick",
   239 	"ban",
   240 	"unban",
   241 	"slay",
   242 	"map",
   243 	"cvars",
   244 	"cfg",
   245 	"chat",
   246 	"vote",
   247 	"pass",
   248 	"rcon",
   249 	"cheat"
   250 };
   251 
   252 CustomFlagsToString(String:buffer[], maxlength, flags)
   253 {
   254 	decl String:joins[6][6];
   255 	new total;
   256 	
   257 	for (new i=_:Admin_Custom1; i<=_:Admin_Custom6; i++)
   258 	{
   259 		if (flags & (1<<i))
   260 		{
   261 			IntToString(i - _:Admin_Custom1 + 1, joins[total++], 6);
   262 		}
   263 	}
   264 	
   265 	ImplodeStrings(joins, total, ",", buffer, maxlength);
   266 	
   267 	return total;
   268 }
   269 
   270 FlagsToString(String:buffer[], maxlength, flags)
   271 {
   272 	decl String:joins[FLAG_STRINGS+1][32];
   273 	new total;
   274 
   275 	for (new i=0; i<FLAG_STRINGS; i++)
   276 	{
   277 		if (flags & (1<<i))
   278 		{
   279 			strcopy(joins[total++], 32, g_FlagNames[i]);
   280 		}
   281 	}
   282 	
   283 	decl String:custom_flags[32];
   284 	if (CustomFlagsToString(custom_flags, sizeof(custom_flags), flags))
   285 	{
   286 		Format(joins[total++], 32, "custom(%s)", custom_flags);
   287 	}
   288 
   289 	ImplodeStrings(joins, total, ", ", buffer, maxlength);
   290 }
   291 
   292 public Action:Command_Cvar(client, args)
   293 {
   294 	if (args < 1)
   295 	{
   296 		if (client == 0)
   297 		{
   298 			ReplyToCommand(client, "[SM] Usage: sm_cvar <cvar|protect> [value]");
   299 		}
   300 		else
   301 		{
   302 			ReplyToCommand(client, "[SM] Usage: sm_cvar <cvar> [value]");
   303 		}
   304 		return Plugin_Handled;
   305 	}
   306 
   307 	decl String:cvarname[64];
   308 	GetCmdArg(1, cvarname, sizeof(cvarname));
   309 	
   310 	if (client == 0 && StrEqual(cvarname, "protect"))
   311 	{
   312 		if (args < 2)
   313 		{
   314 			ReplyToCommand(client, "[SM] Usage: sm_cvar <protect> <cvar>");
   315 			return Plugin_Handled;
   316 		}
   317 		GetCmdArg(2, cvarname, sizeof(cvarname));
   318 		ProtectVar(cvarname);
   319 		ReplyToCommand(client, "[SM] %t", "Cvar is now protected", cvarname);
   320 		return Plugin_Handled;
   321 	}
   322 
   323 	new Handle:hndl = FindConVar(cvarname);
   324 	if (hndl == INVALID_HANDLE)
   325 	{
   326 		ReplyToCommand(client, "[SM] %t", "Unable to find cvar", cvarname);
   327 		return Plugin_Handled;
   328 	}
   329 
   330 	if (!IsClientAllowedToChangeCvar(client, cvarname))
   331 	{
   332 		ReplyToCommand(client, "[SM] %t", "No access to cvar");
   333 		return Plugin_Handled;
   334 	}
   335 
   336 	decl String:value[255];
   337 	if (args < 2)
   338 	{
   339 		GetConVarString(hndl, value, sizeof(value));
   340 
   341 		ReplyToCommand(client, "[SM] %t", "Value of cvar", cvarname, value);
   342 		return Plugin_Handled;
   343 	}
   344 
   345 	GetCmdArg(2, value, sizeof(value));
   346 
   347 	if ((GetConVarFlags(hndl) & FCVAR_PROTECTED) != FCVAR_PROTECTED)
   348 	{
   349 		ShowActivity2(client, "[SM] ", "%t", "Cvar changed", cvarname, value);
   350 	}
   351 	else
   352 	{
   353 		ReplyToCommand(client, "[SM] %t", "Cvar changed", cvarname, value);
   354 	}
   355 
   356 	LogAction(client, -1, "\"%L\" changed cvar (cvar \"%s\") (value \"%s\")", client, cvarname, value);
   357 
   358 	SetConVarString(hndl, value, true);
   359 
   360 	return Plugin_Handled;
   361 }
   362 
   363 public Action:Command_ResetCvar(client, args)
   364 {
   365 	if (args < 1)
   366 	{
   367 		ReplyToCommand(client, "[SM] Usage: sm_resetcvar <cvar>");
   368 
   369 		return Plugin_Handled;
   370 	}
   371 
   372 	decl String:cvarname[64];
   373 	GetCmdArg(1, cvarname, sizeof(cvarname));
   374 	
   375 	new Handle:hndl = FindConVar(cvarname);
   376 	if (hndl == INVALID_HANDLE)
   377 	{
   378 		ReplyToCommand(client, "[SM] %t", "Unable to find cvar", cvarname);
   379 		return Plugin_Handled;
   380 	}
   381 	
   382 	if (!IsClientAllowedToChangeCvar(client, cvarname))
   383 	{
   384 		ReplyToCommand(client, "[SM] %t", "No access to cvar");
   385 		return Plugin_Handled;
   386 	}
   387 
   388 	ResetConVar(hndl);
   389 
   390 	decl String:value[255];
   391 	GetConVarString(hndl, value, sizeof(value));
   392 
   393 	if ((GetConVarFlags(hndl) & FCVAR_PROTECTED) != FCVAR_PROTECTED)
   394 	{
   395 		ShowActivity2(client, "[SM] ", "%t", "Cvar changed", cvarname, value);
   396 	}
   397 	else
   398 	{
   399 		ReplyToCommand(client, "[SM] %t", "Cvar changed", cvarname, value);
   400 	}
   401 
   402 	LogAction(client, -1, "\"%L\" reset cvar (cvar \"%s\") (value \"%s\")", client, cvarname, value);
   403 
   404 	return Plugin_Handled;
   405 }
   406 
   407 public Action:Command_Rcon(client, args)
   408 {
   409 	if (args < 1)
   410 	{
   411 		ReplyToCommand(client, "[SM] Usage: sm_rcon <args>");
   412 		return Plugin_Handled;
   413 	}
   414 
   415 	decl String:argstring[255];
   416 	GetCmdArgString(argstring, sizeof(argstring));
   417 
   418 	LogAction(client, -1, "\"%L\" console command (cmdline \"%s\")", client, argstring);
   419 
   420 	if (client == 0) // They will already see the response in the console.
   421 	{
   422 		ServerCommand("%s", argstring);
   423 	} else {
   424 		new String:responseBuffer[4096];
   425 		ServerCommandEx(responseBuffer, sizeof(responseBuffer), "%s", argstring);
   426 		ReplyToCommand(client, responseBuffer);
   427 	}
   428 
   429 	return Plugin_Handled;
   430 }
   431 
   432 public Action:Command_ReVote(client, args)
   433 {
   434 	if (client == 0)
   435 	{
   436 		ReplyToCommand(client, "[SM] %t", "Command is in-game only");
   437 		return Plugin_Handled;
   438 	}
   439 	
   440 	if (!IsVoteInProgress())
   441 	{
   442 		ReplyToCommand(client, "[SM] %t", "Vote Not In Progress");
   443 		return Plugin_Handled;
   444 	}
   445 	
   446 	if (!IsClientInVotePool(client))
   447 	{
   448 		ReplyToCommand(client, "[SM] %t", "Cannot participate in vote");
   449 		return Plugin_Handled;
   450 	}
   451 	
   452 	if (!RedrawClientVoteMenu(client))
   453 	{
   454 		ReplyToCommand(client, "[SM] %t", "Cannot change vote");
   455 	}
   456 	
   457 	return Plugin_Handled;
   458 }