<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.alliedmods.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Shavit</id>
	<title>AlliedModders Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.alliedmods.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Shavit"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/Shavit"/>
	<updated>2026-04-28T23:23:54Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Format_Class_Functions_(SourceMod_Scripting)&amp;diff=10184</id>
		<title>Format Class Functions (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Format_Class_Functions_(SourceMod_Scripting)&amp;diff=10184"/>
		<updated>2016-07-26T03:07:08Z</updated>

		<summary type="html">&lt;p&gt;Shavit: {Handle,Float,_} &amp;gt;&amp;gt; any&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Introduction=&lt;br /&gt;
Format-class functions are variable argument functions in [[SourceMod]] which allow you to format a string.  A simple example of this is the &amp;lt;tt&amp;gt;Format()&amp;lt;/tt&amp;gt; function, which looks like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;char buffer[512];&lt;br /&gt;
Format(buffer, sizeof(buffer), &amp;quot;Your name is: %s&amp;quot;, userName);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If userName contains &amp;quot;&amp;lt;tt&amp;gt;Mark&amp;lt;/tt&amp;gt;,&amp;quot; the contents of &amp;lt;tt&amp;gt;buffer&amp;lt;/tt&amp;gt; will then be: &amp;quot;&amp;lt;tt&amp;gt;Your name is: Mark&amp;lt;/tt&amp;gt;.&amp;quot;  The prototype of these functions almost always contains the following parameters:&lt;br /&gt;
&amp;lt;pawn&amp;gt;const char[] fmt, any ...&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, observe the following two natives:&lt;br /&gt;
&amp;lt;pawn&amp;gt;native void Format(char[] buffer, int maxlength, const char[] fmt, any ...);&lt;br /&gt;
native void PrintToClient(int client, char[] fmt, any ...);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Thus, &amp;lt;tt&amp;gt;PrintToClient&amp;lt;/tt&amp;gt; is a format-class function.  It can be used exactly as shown earlier:&lt;br /&gt;
&amp;lt;pawn&amp;gt;PrintToClient(client, &amp;quot;Your name is: %s&amp;quot;, userName);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Format Specifiers=&lt;br /&gt;
A format specifier is a code that allows you to specify what data-type to print.  The most common specifiers are:&lt;br /&gt;
*'''Numerical'''&lt;br /&gt;
**'''d''' or '''i''': Integer number as decimal&lt;br /&gt;
**'''u''': Unsigned integer number as decimal&lt;br /&gt;
**'''b''': Binary digits in the value&lt;br /&gt;
**'''f''': Floating-point number&lt;br /&gt;
**'''x''' or '''X''': Hexadecimal representation of the binary value (capitalization affects hex letter casing)&lt;br /&gt;
*'''Character(s)'''&lt;br /&gt;
**'''s''': String&lt;br /&gt;
**'''t''' or '''T''': Translates a phrase (explained in [[Translations (SourceMod_Scripting)#Usage_in_a_Plugin|Translations]])&lt;br /&gt;
**'''c''': Prints one character (UTF-8 compliant)&lt;br /&gt;
*'''Special'''&lt;br /&gt;
**'''L''': Requires a client index; expands to 1&amp;lt;2&amp;gt;&amp;lt;3&amp;gt;&amp;lt;&amp;gt; where 1 is the player's name, 2 is the player's userid, and 3 is the player's Steam ID.  If the client index is 0, the string will be: &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;Console&amp;lt;0&amp;gt;&amp;lt;Console&amp;gt;&amp;lt;Console&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
**'''N''': Requires a client index; expands to a string containing the player's name.  If the client index is 0, the string will be: &amp;lt;tt&amp;gt;Console&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Usage=&lt;br /&gt;
Format specifiers are denoted with a &amp;lt;tt&amp;gt;'%s'&amp;lt;/tt&amp;gt; symbol.  For example, to print a float, a number, and a string, you might use this code:&lt;br /&gt;
&amp;lt;pawn&amp;gt;float fNum = 5.0;&lt;br /&gt;
int iNum = 5;&lt;br /&gt;
char[] str = &amp;quot;5&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
PrintToClient(client, &amp;quot;Number: %d Float: %f String: %s&amp;quot;, iNum, fNum, str);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note''': Using the wrong data type with a specifier can be very dangerous.  Always make sure you are printing as the right type.  For example, specifying a string and passing a number can crash the server.&lt;br /&gt;
&lt;br /&gt;
=Advanced Formatting=&lt;br /&gt;
Format specifiers have an extended syntax for controlling various aspects of how data is printed.  The full syntax is:&lt;br /&gt;
&amp;lt;tt&amp;gt;%[flags][width][.precision]specifier&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each bracketed section is an optional extension.  Explanations of supported SourceMod format extensions:&lt;br /&gt;
*'''%''': Obviously, this is always required.&lt;br /&gt;
*'''flags''':&lt;br /&gt;
**'''-''': Left-justify (right-justify is set by default)&lt;br /&gt;
**'''0''': Pads with 0s instead of spaces when needed (see '''width''' below).&lt;br /&gt;
*'''width''': Minimum number of characters to be printed. If the value to be printed is shorter than this number, the result is padded with blank spaces. The value is not truncated even if the result is larger.&lt;br /&gt;
*'''precision''': &lt;br /&gt;
**'''For integers''': specifies the minimum number of digits to print (or pad with spaces/zeroes if below the minimum).  &lt;br /&gt;
**'''For strings''': specifies the maximum number of characters to print.&lt;br /&gt;
**'''For floats''': specifies the number of digits to be printed ''after the decimal point''.&lt;br /&gt;
**'''For all other types''': no effect.&lt;br /&gt;
*'''specifier''': character specifying the data type (always required).&lt;br /&gt;
&lt;br /&gt;
todo: examples&lt;br /&gt;
&lt;br /&gt;
For more information, see [http://www.cplusplus.com/reference/clibrary/cstdio/printf.html printf] from the C Standard Library, although not all modes are supported from C.&lt;br /&gt;
&lt;br /&gt;
=Making your function Format-Class=&lt;br /&gt;
&lt;br /&gt;
Sourcemod allows you to make your function Format-class, ie. pass parameters to format string variables.&lt;br /&gt;
Here's an example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void formatExample(const char[] myString, any ...)&lt;br /&gt;
{&lt;br /&gt;
	int len = strlen(myString) + 255;&lt;br /&gt;
	char[] myFormattedString = new char[len];&lt;br /&gt;
	VFormat(myFormattedString, len, myString, 2);&lt;br /&gt;
	&lt;br /&gt;
	PrintToServer(myFormattedString);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using the parameter &amp;quot;any ...&amp;quot;, we can pass data(s) to format our string.&lt;br /&gt;
Now, in order to replace the Format Specifiers by our data(s), we use the API &amp;quot;VFormat&amp;quot;, which documentation can be found here : [https://sm.alliedmods.net/new-api/].&lt;br /&gt;
&lt;br /&gt;
The three first parameters passed in VFormat are pretty obvious since they are the as in the Format(..) API.&lt;br /&gt;
&lt;br /&gt;
The 4th parameter indicate the &amp;quot;any ...&amp;quot; parameter position in your function prototype.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Function_Calling_API_(SourceMod_Scripting)&amp;diff=10183</id>
		<title>Function Calling API (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Function_Calling_API_(SourceMod_Scripting)&amp;diff=10183"/>
		<updated>2016-07-26T03:04:58Z</updated>

		<summary type="html">&lt;p&gt;Shavit: Fix something I missed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod provides plugins with an API for calling functions.  This API can be used to call public functions in any plugin, including public functions in the same plugin.  &lt;br /&gt;
&lt;br /&gt;
This article is split into two sections.  The first is on generic function calling, which is used for single function calls.  The second is on Forwards, which is used for calling multiple functions in one operation.&lt;br /&gt;
&lt;br /&gt;
For more information on forwards, readers should see [[Writing_Extensions#Creating_Events.2FForwards|forwards in extensions]].&lt;br /&gt;
&lt;br /&gt;
=Generic Calling=&lt;br /&gt;
There are four steps to calling a function in a plugin:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Obtaining a &amp;quot;call Handle.&amp;quot;  This is either in the form of a function ID, tagged with &amp;lt;tt&amp;gt;Function&amp;lt;/tt&amp;gt;, or a Forward Handle, tagged with &amp;lt;tt&amp;gt;Handle&amp;lt;/tt&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Starting the call.&lt;br /&gt;
 &amp;lt;li&amp;gt;Pushing parameters in increasing order in a way that matches the function prototype.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Ending the the call, which performs the call operation and returns the result.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For simplicity, let's consider calling a function in our own plugin.  We have the following function:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnClientDied(int attacker, int victim, const char[] weapon, bool headshot)&lt;br /&gt;
{&lt;br /&gt;
   char name[MAX_NAME_LENGTH];&lt;br /&gt;
   GetClientName(victim, name, sizeof(name))&lt;br /&gt;
   &lt;br /&gt;
   if (attacker != victim)&lt;br /&gt;
   {&lt;br /&gt;
      char other[MAX_NAME_LENGTH];&lt;br /&gt;
      GetClientName(attacker, other, sizeof(other))&lt;br /&gt;
      PrintToServer(&amp;quot;&amp;lt;\&amp;quot;%s\&amp;quot;&amp;gt; killed by &amp;lt;\&amp;quot;%s\&amp;quot;&amp;gt; with \&amp;quot;%s\&amp;quot; (headshot: %d)&amp;quot;, name, other, weapon, headshot)&lt;br /&gt;
   } else if (!attacker) {&lt;br /&gt;
      PrintToServer(&amp;quot;&amp;lt;\&amp;quot;%s\&amp;quot;&amp;gt; killed by \&amp;quot;world\&amp;quot; with \&amp;quot;%s\&amp;quot; (headshot: %d)&amp;quot;, name, weapon, headshot)&lt;br /&gt;
   } else {&lt;br /&gt;
      PrintToServer(&amp;quot;&amp;lt;\&amp;quot;%s\&amp;quot;&amp;gt; killed by \&amp;quot;self\&amp;quot; with \&amp;quot;%s\&amp;quot; (headshot: %d)&amp;quot;, name, weapon, headshot)&lt;br /&gt;
   }&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An indirect way to call this function would be:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public void EventHandler(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
   if (StrEqual(name, &amp;quot;player_death&amp;quot;))&lt;br /&gt;
   {&lt;br /&gt;
      char weapon[64];&lt;br /&gt;
      int result;&lt;br /&gt;
&lt;br /&gt;
      event.GetString(&amp;quot;weapon&amp;quot;, weapon, sizeof(weapon));&lt;br /&gt;
&lt;br /&gt;
      /* Start function call */&lt;br /&gt;
      Call_StartFunction(null, OnClientDied);&lt;br /&gt;
&lt;br /&gt;
      /* Push parameters one at a time */&lt;br /&gt;
      Call_PushCell(GetClientOfUserId(event.GetInt(&amp;quot;attacker&amp;quot;)));&lt;br /&gt;
      Call_PushCell(GetClientOfUserId(event.GetInt(&amp;quot;userid&amp;quot;)));&lt;br /&gt;
      Call_PushString(weapon);&lt;br /&gt;
      Call_PushCell(GetEventInt(event, &amp;quot;headshot&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
      /* Finish the call, get the result */&lt;br /&gt;
      Call_Finish(result);&lt;br /&gt;
   }&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This basic example shows starting and completing a function call.  However, the real use of function calling is with forwards, which is covered in the next section.&lt;br /&gt;
&lt;br /&gt;
=Forwards=&lt;br /&gt;
Forwards are much more advantageous over single function calls.  They are expandable containers, so you can store and complete many calls with very little action.  Furthermore, they also adjust themselves when contained plugins are unloaded.  Lastly, they are type-checked; each forward's parameter types must be known in advance, and if you push a mismatching type, the call will not complete.&lt;br /&gt;
&lt;br /&gt;
Forwards must be created using the following types:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Any&amp;lt;/tt&amp;gt; - Any parameter type can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Cell&amp;lt;/tt&amp;gt; - A non-Float cell can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Float&amp;lt;/tt&amp;gt; - A Float cell can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_String&amp;lt;/tt&amp;gt; - A string can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Array&amp;lt;/tt&amp;gt; - An array can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_VarArgs&amp;lt;/tt&amp;gt; - This and all further parameters can be any type, but will be by reference.  This cannot be the first parameter type, and if it is used, it must be the last parameter type.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_CellByRef&amp;lt;/tt&amp;gt; - A non-Float cell by reference&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_FloatByRef&amp;lt;/tt&amp;gt; - A Float cell by reference&lt;br /&gt;
&lt;br /&gt;
Strings and arrays are implicitly by-reference.  When pushing variable argument parameters, if anything is pushed by-value, it will be internally automatically converted to by-reference.&lt;br /&gt;
&lt;br /&gt;
Since Forwards will call multiple functions in a row, it needs to know how to interpret the return values of functions.  There are four predefined methods:&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Ignore&amp;lt;/tt&amp;gt; - All return values will be ignored; 0 will be returned at the end.&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Single&amp;lt;/tt&amp;gt; - Only the last return value will be returned.&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Event&amp;lt;/tt&amp;gt; - Function should return an &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; value (&amp;lt;tt&amp;gt;core.inc&amp;lt;/tt&amp;gt;).  &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; acts as &amp;lt;tt&amp;gt;Plugin_Handled&amp;lt;/tt&amp;gt;.  The highest value is returned.&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Hook&amp;lt;/tt&amp;gt; - Function should return an &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; value.  &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; ends the forward call immediately.&lt;br /&gt;
&lt;br /&gt;
Let's write a simple example.  Our plugin, Plugin A, wants to tell other plugins when a player dies.  It has two ways of doing this, either via a ''global'' forward or a ''private'' forward.  A global forward acts upon all functions in all plugins that match a single name.  A private forward lets you explicitly manage which functions are in the container.&lt;br /&gt;
&lt;br /&gt;
==Global Forwards==&lt;br /&gt;
Global forwards are very simple to use.  After creation, they do not need to be maintained.  An example plugin below creates a global forward with the following prototype:&lt;br /&gt;
&amp;lt;pawn&amp;gt;forward void OnClientDied(int attacker, int victim, const char[] weapon, bool headshot);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementation:&lt;br /&gt;
&amp;lt;pawn&amp;gt;Handle g_DeathForward;&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
   g_DeathForward = CreateGlobalForward(&amp;quot;OnClientDied&amp;quot;, ET_Event, Param_Cell, Param_Cell, Param_String, Param_Cell)&lt;br /&gt;
   HookEvent(&amp;quot;player_death&amp;quot;, EventHandler)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action EventHandler(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
   char weapon[64];&lt;br /&gt;
   Action result;&lt;br /&gt;
&lt;br /&gt;
   event.GetString(&amp;quot;weapon&amp;quot;, weapon, sizeof(weapon));&lt;br /&gt;
&lt;br /&gt;
   /* Start function call */&lt;br /&gt;
   Call_StartForward(g_DeathForward);&lt;br /&gt;
&lt;br /&gt;
   /* Push parameters one at a time */&lt;br /&gt;
   Call_PushCell(GetClientOfUserId(event.GetInt(&amp;quot;attacker&amp;quot;)));&lt;br /&gt;
   Call_PushCell(GetClientOfUserId(event.GetInt(&amp;quot;userid&amp;quot;)));&lt;br /&gt;
   Call_PushString(weapon);&lt;br /&gt;
   Call_PushCell(GetEventInt(event, &amp;quot;headshot&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
   /* Finish the call, get the result */&lt;br /&gt;
   Call_Finish(result);&lt;br /&gt;
  &lt;br /&gt;
   return result;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Private Forwards==&lt;br /&gt;
Private forwards require you to manually add functions to its container.  This can leave you with much more flexibility.  Like global forwards, they automatically remove functions from unloaded plugins.  &lt;br /&gt;
&lt;br /&gt;
Usually, this is done using dynamic natives; a plugin will expose a function to add to its own forwards.  For example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;typedef OnClientDiedFunc = function Action (int attacker, int victim, const char[] weapon, bool headshot);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Calls the target function when a client dies.&lt;br /&gt;
 *&lt;br /&gt;
 * @param func      OnClientDiedFunc function.&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native void HookClientDeath(OnClientDiedFunc func);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An implementation of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
   g_DeathForward = CreateForward(ET_Event, Param_Cell, Param_Cell, Param_String, Param_Cell)&lt;br /&gt;
   CreateNative(&amp;quot;HookClientDeath&amp;quot;, Native_HookClientDeath)&lt;br /&gt;
   HookEvent(&amp;quot;player_death&amp;quot;, EventHandler)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public int Native_HookClientDeath(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
   AddToForward(g_DeathForward, plugin, view_as&amp;lt;Function&amp;gt;(GetNativeCell(1)))&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the code to call the forward does not need to change at all.&lt;br /&gt;
&lt;br /&gt;
A complete implementation of a private forward may look like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;typedef MyFunction = function void (int client);&lt;br /&gt;
native void My_NativeEx(MyFunction func);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;Handle g_hDeathFwd;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// typedef MyFunction = function void (int client);&lt;br /&gt;
// native void My_NativeEx(MyFunction func);&lt;br /&gt;
public APLRes AskPluginLoad2(Handle plugin, bool late, const char[] error, int err_max)&lt;br /&gt;
{&lt;br /&gt;
	CreateNative(&amp;quot;My_NativeEx&amp;quot;, My_Native);&lt;br /&gt;
	return APLRes_Success;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_Death);&lt;br /&gt;
	g_hDeathFwd = CreateForward(ET_Ignore, Param_Cell);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public int My_Native(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	AddToForward(g_hDeathFwd, plugin, view_as&amp;lt;Function&amp;gt;(GetNativeCell(1)));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Event_Death(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	int client = GetClientOfUserId(event.GetInt(&amp;quot;userid&amp;quot;));&lt;br /&gt;
	Call_StartForward(g_hDeathFwd);&lt;br /&gt;
	Call_PushCell(client);&lt;br /&gt;
	Call_Finish();&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Function_Calling_API_(SourceMod_Scripting)&amp;diff=10182</id>
		<title>Function Calling API (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Function_Calling_API_(SourceMod_Scripting)&amp;diff=10182"/>
		<updated>2016-07-26T03:04:05Z</updated>

		<summary type="html">&lt;p&gt;Shavit: Update example code to transitional syntax&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod provides plugins with an API for calling functions.  This API can be used to call public functions in any plugin, including public functions in the same plugin.  &lt;br /&gt;
&lt;br /&gt;
This article is split into two sections.  The first is on generic function calling, which is used for single function calls.  The second is on Forwards, which is used for calling multiple functions in one operation.&lt;br /&gt;
&lt;br /&gt;
For more information on forwards, readers should see [[Writing_Extensions#Creating_Events.2FForwards|forwards in extensions]].&lt;br /&gt;
&lt;br /&gt;
=Generic Calling=&lt;br /&gt;
There are four steps to calling a function in a plugin:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Obtaining a &amp;quot;call Handle.&amp;quot;  This is either in the form of a function ID, tagged with &amp;lt;tt&amp;gt;Function&amp;lt;/tt&amp;gt;, or a Forward Handle, tagged with &amp;lt;tt&amp;gt;Handle&amp;lt;/tt&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Starting the call.&lt;br /&gt;
 &amp;lt;li&amp;gt;Pushing parameters in increasing order in a way that matches the function prototype.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Ending the the call, which performs the call operation and returns the result.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For simplicity, let's consider calling a function in our own plugin.  We have the following function:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnClientDied(int attacker, int victim, const char[] weapon, bool headshot)&lt;br /&gt;
{&lt;br /&gt;
   char name[MAX_NAME_LENGTH];&lt;br /&gt;
   GetClientName(victim, name, sizeof(name))&lt;br /&gt;
   &lt;br /&gt;
   if (attacker != victim)&lt;br /&gt;
   {&lt;br /&gt;
      char other[MAX_NAME_LENGTH];&lt;br /&gt;
      GetClientName(attacker, other, sizeof(other))&lt;br /&gt;
      PrintToServer(&amp;quot;&amp;lt;\&amp;quot;%s\&amp;quot;&amp;gt; killed by &amp;lt;\&amp;quot;%s\&amp;quot;&amp;gt; with \&amp;quot;%s\&amp;quot; (headshot: %d)&amp;quot;, name, other, weapon, headshot)&lt;br /&gt;
   } else if (!attacker) {&lt;br /&gt;
      PrintToServer(&amp;quot;&amp;lt;\&amp;quot;%s\&amp;quot;&amp;gt; killed by \&amp;quot;world\&amp;quot; with \&amp;quot;%s\&amp;quot; (headshot: %d)&amp;quot;, name, weapon, headshot)&lt;br /&gt;
   } else {&lt;br /&gt;
      PrintToServer(&amp;quot;&amp;lt;\&amp;quot;%s\&amp;quot;&amp;gt; killed by \&amp;quot;self\&amp;quot; with \&amp;quot;%s\&amp;quot; (headshot: %d)&amp;quot;, name, weapon, headshot)&lt;br /&gt;
   }&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An indirect way to call this function would be:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public void EventHandler(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
   if (StrEqual(name, &amp;quot;player_death&amp;quot;))&lt;br /&gt;
   {&lt;br /&gt;
      char weapon[64];&lt;br /&gt;
      int result;&lt;br /&gt;
&lt;br /&gt;
      event.GetString(&amp;quot;weapon&amp;quot;, weapon, sizeof(weapon));&lt;br /&gt;
&lt;br /&gt;
      /* Start function call */&lt;br /&gt;
      Call_StartFunction(null, OnClientDied);&lt;br /&gt;
&lt;br /&gt;
      /* Push parameters one at a time */&lt;br /&gt;
      Call_PushCell(GetClientOfUserId(event.GetInt(&amp;quot;attacker&amp;quot;)));&lt;br /&gt;
      Call_PushCell(GetClientOfUserId(event.GetInt(&amp;quot;userid&amp;quot;)));&lt;br /&gt;
      Call_PushString(weapon);&lt;br /&gt;
      Call_PushCell(GetEventInt(event, &amp;quot;headshot&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
      /* Finish the call, get the result */&lt;br /&gt;
      Call_Finish(result);&lt;br /&gt;
   }&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This basic example shows starting and completing a function call.  However, the real use of function calling is with forwards, which is covered in the next section.&lt;br /&gt;
&lt;br /&gt;
=Forwards=&lt;br /&gt;
Forwards are much more advantageous over single function calls.  They are expandable containers, so you can store and complete many calls with very little action.  Furthermore, they also adjust themselves when contained plugins are unloaded.  Lastly, they are type-checked; each forward's parameter types must be known in advance, and if you push a mismatching type, the call will not complete.&lt;br /&gt;
&lt;br /&gt;
Forwards must be created using the following types:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Any&amp;lt;/tt&amp;gt; - Any parameter type can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Cell&amp;lt;/tt&amp;gt; - A non-Float cell can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Float&amp;lt;/tt&amp;gt; - A Float cell can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_String&amp;lt;/tt&amp;gt; - A string can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Array&amp;lt;/tt&amp;gt; - An array can be pushed&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_VarArgs&amp;lt;/tt&amp;gt; - This and all further parameters can be any type, but will be by reference.  This cannot be the first parameter type, and if it is used, it must be the last parameter type.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_CellByRef&amp;lt;/tt&amp;gt; - A non-Float cell by reference&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_FloatByRef&amp;lt;/tt&amp;gt; - A Float cell by reference&lt;br /&gt;
&lt;br /&gt;
Strings and arrays are implicitly by-reference.  When pushing variable argument parameters, if anything is pushed by-value, it will be internally automatically converted to by-reference.&lt;br /&gt;
&lt;br /&gt;
Since Forwards will call multiple functions in a row, it needs to know how to interpret the return values of functions.  There are four predefined methods:&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Ignore&amp;lt;/tt&amp;gt; - All return values will be ignored; 0 will be returned at the end.&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Single&amp;lt;/tt&amp;gt; - Only the last return value will be returned.&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Event&amp;lt;/tt&amp;gt; - Function should return an &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; value (&amp;lt;tt&amp;gt;core.inc&amp;lt;/tt&amp;gt;).  &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; acts as &amp;lt;tt&amp;gt;Plugin_Handled&amp;lt;/tt&amp;gt;.  The highest value is returned.&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Hook&amp;lt;/tt&amp;gt; - Function should return an &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; value.  &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; ends the forward call immediately.&lt;br /&gt;
&lt;br /&gt;
Let's write a simple example.  Our plugin, Plugin A, wants to tell other plugins when a player dies.  It has two ways of doing this, either via a ''global'' forward or a ''private'' forward.  A global forward acts upon all functions in all plugins that match a single name.  A private forward lets you explicitly manage which functions are in the container.&lt;br /&gt;
&lt;br /&gt;
==Global Forwards==&lt;br /&gt;
Global forwards are very simple to use.  After creation, they do not need to be maintained.  An example plugin below creates a global forward with the following prototype:&lt;br /&gt;
&amp;lt;pawn&amp;gt;forward void OnClientDied(int attacker, int victim, const char[] weapon, bool headshot);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementation:&lt;br /&gt;
&amp;lt;pawn&amp;gt;Handle g_DeathForward;&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
   g_DeathForward = CreateGlobalForward(&amp;quot;OnClientDied&amp;quot;, ET_Event, Param_Cell, Param_Cell, Param_String, Param_Cell)&lt;br /&gt;
   HookEvent(&amp;quot;player_death&amp;quot;, EventHandler)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action EventHandler(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
   char weapon[64];&lt;br /&gt;
   Action result;&lt;br /&gt;
&lt;br /&gt;
   event.GetString(&amp;quot;weapon&amp;quot;, weapon, sizeof(weapon));&lt;br /&gt;
&lt;br /&gt;
   /* Start function call */&lt;br /&gt;
   Call_StartForward(g_DeathForward);&lt;br /&gt;
&lt;br /&gt;
   /* Push parameters one at a time */&lt;br /&gt;
   Call_PushCell(GetClientOfUserId(event.GetInt(&amp;quot;attacker&amp;quot;)));&lt;br /&gt;
   Call_PushCell(GetClientOfUserId(event.GetInt(&amp;quot;userid&amp;quot;)));&lt;br /&gt;
   Call_PushString(weapon);&lt;br /&gt;
   Call_PushCell(GetEventInt(event, &amp;quot;headshot&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
   /* Finish the call, get the result */&lt;br /&gt;
   Call_Finish(result);&lt;br /&gt;
  &lt;br /&gt;
   return result;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Private Forwards==&lt;br /&gt;
Private forwards require you to manually add functions to its container.  This can leave you with much more flexibility.  Like global forwards, they automatically remove functions from unloaded plugins.  &lt;br /&gt;
&lt;br /&gt;
Usually, this is done using dynamic natives; a plugin will expose a function to add to its own forwards.  For example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;typedef OnClientDiedFunc = function Action (int attacker, int victim, const char[] weapon, bool headshot);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Calls the target function when a client dies.&lt;br /&gt;
 *&lt;br /&gt;
 * @param func      OnClientDiedFunc function.&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native void HookClientDeath(OnClientDiedFunc func);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An implementation of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
   g_DeathForward = CreateForward(ET_Event, Param_Cell, Param_Cell, Param_String, Param_Cell)&lt;br /&gt;
   CreateNative(&amp;quot;HookClientDeath&amp;quot;, Native_HookClientDeath)&lt;br /&gt;
   HookEvent(&amp;quot;player_death&amp;quot;, EventHandler)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public int Native_HookClientDeath(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
   AddToForward(g_DeathForward, plugin, Function:GetNativeCell(1))&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the code to call the forward does not need to change at all.&lt;br /&gt;
&lt;br /&gt;
A complete implementation of a private forward may look like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;typedef MyFunction = function void (int client);&lt;br /&gt;
native void My_NativeEx(MyFunction func);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;Handle g_hDeathFwd;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// typedef MyFunction = function void (int client);&lt;br /&gt;
// native void My_NativeEx(MyFunction func);&lt;br /&gt;
public APLRes AskPluginLoad2(Handle plugin, bool late, const char[] error, int err_max)&lt;br /&gt;
{&lt;br /&gt;
	CreateNative(&amp;quot;My_NativeEx&amp;quot;, My_Native);&lt;br /&gt;
	return APLRes_Success;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_Death);&lt;br /&gt;
	g_hDeathFwd = CreateForward(ET_Ignore, Param_Cell);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public int My_Native(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	AddToForward(g_hDeathFwd, plugin, Function:GetNativeCell(1));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Event_Death(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	int client = GetClientOfUserId(event.GetInt(&amp;quot;userid&amp;quot;));&lt;br /&gt;
	Call_StartForward(g_hDeathFwd);&lt;br /&gt;
	Call_PushCell(client);&lt;br /&gt;
	Call_Finish();&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SQL_(SourceMod_Scripting)&amp;diff=10181</id>
		<title>SQL (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SQL_(SourceMod_Scripting)&amp;diff=10181"/>
		<updated>2016-07-26T02:52:13Z</updated>

		<summary type="html">&lt;p&gt;Shavit: Update example code to transitional syntax&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article is an introduction to using SourceMod's SQL features.  It is not an introduction or tutorial about SQL or any specific SQL implementation.&lt;br /&gt;
&lt;br /&gt;
SourceMod's SQL layer is formally called ''DBI'', or the '''D'''ata'''b'''ase '''I'''nterface.  The interface is a generic abstraction of common SQL functions.  To connect to a specific database implementation (such as MySQL, or sqLite), a SourceMod DBI &amp;quot;driver&amp;quot; must be loaded.  Currently, there are drivers for MySQL and SQLite&lt;br /&gt;
&lt;br /&gt;
SourceMod automatically detects and loads drivers on demand (if they exist, of course).  All database natives are in &amp;lt;tt&amp;gt;scripting/include/dbi.inc&amp;lt;/tt&amp;gt;.  The C++ API is in &amp;lt;tt&amp;gt;public/IDBDriver.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Connecting=&lt;br /&gt;
There are two ways to connect to a database.  The first is through named configurations.  Named configurations are preset configurations listed in &amp;lt;tt&amp;gt;configs/databases.cfg&amp;lt;/tt&amp;gt;.  SourceMod specifies that if SQL is being used, there should always be one configuration named &amp;quot;default.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
An example of such a configuration looks like:&lt;br /&gt;
&amp;lt;pre&amp;gt;	&amp;quot;default&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;host&amp;quot;				&amp;quot;localhost&amp;quot;&lt;br /&gt;
		&amp;quot;database&amp;quot;			&amp;quot;sourcemod&amp;quot;&lt;br /&gt;
		&amp;quot;user&amp;quot;				&amp;quot;root&amp;quot;&lt;br /&gt;
		&amp;quot;pass&amp;quot;				&amp;quot;&amp;quot;&lt;br /&gt;
		//&amp;quot;timeout&amp;quot;			&amp;quot;0&amp;quot;&lt;br /&gt;
		//&amp;quot;port&amp;quot;			&amp;quot;0&amp;quot;&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connections based on named configurations can be instantiated with either &amp;lt;tt&amp;gt;SQL_Connect&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;SQL_DefConnect&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
The other option is to use &amp;lt;tt&amp;gt;SQL_ConnectCustom&amp;lt;/tt&amp;gt; and manually specify all connection parameters by passing a keyvalue handle containing them.&lt;br /&gt;
&lt;br /&gt;
Example of a typical connection:&lt;br /&gt;
&amp;lt;pawn&amp;gt;char error[255];&lt;br /&gt;
Database db = SQL_DefConnect(error, sizeof(error));&lt;br /&gt;
&lt;br /&gt;
if (db == null)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Could not connect: %s&amp;quot;, error);&lt;br /&gt;
} &lt;br /&gt;
else &lt;br /&gt;
{&lt;br /&gt;
	delete db;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Queries=&lt;br /&gt;
&lt;br /&gt;
==No Results==&lt;br /&gt;
The simplest queries are ones which do not return results -- for example, CREATE, DROP, UPDATE, INSERT, and DELETE.  For such queries it is recommended to use &amp;lt;tt&amp;gt;SQL_FastQuery()&amp;lt;/tt&amp;gt;.  The name does not imply that the query will be faster, but rather, it is faster to write code using this function.  For example, given that &amp;lt;tt&amp;gt;db&amp;lt;/tt&amp;gt; is a valid database Handle:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;if (!SQL_FastQuery(db, &amp;quot;UPDATE stats SET players = players + 1&amp;quot;))&lt;br /&gt;
{&lt;br /&gt;
	char error[255];&lt;br /&gt;
	SQL_GetError(db, error, sizeof(error));&lt;br /&gt;
	PrintToServer(&amp;quot;Failed to query (error: %s)&amp;quot;, error);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Results==&lt;br /&gt;
If a query returns a result set and the results must be processed, you must use &amp;lt;tt&amp;gt;SQL_Query()&amp;lt;/tt&amp;gt;.  Unlike &amp;lt;tt&amp;gt;SQL_FastQuery()&amp;lt;/tt&amp;gt;, this function returns a Handle which must be closed.&lt;br /&gt;
&lt;br /&gt;
An example of a query which will produce results is:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DBResultSet query = SQL_Query(db, &amp;quot;SELECT userid FROM vb_user WHERE username = 'BAILOPAN'&amp;quot;);&lt;br /&gt;
if (query == null)&lt;br /&gt;
{&lt;br /&gt;
	char error[255];&lt;br /&gt;
	SQL_GetError(db, error, sizeof(error));&lt;br /&gt;
	PrintToServer(&amp;quot;Failed to query (error: %s)&amp;quot;, error);&lt;br /&gt;
} &lt;br /&gt;
else &lt;br /&gt;
{&lt;br /&gt;
	/* Process results here!&lt;br /&gt;
	 */&lt;br /&gt;
&lt;br /&gt;
	/* Free the Handle */&lt;br /&gt;
	delete query;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Prepared Statements=&lt;br /&gt;
Prepared statements are another method of querying.  The idea behind a prepared statement is that you construct a query &amp;quot;template&amp;quot; once, and re-use it as many times as needed.  Prepared statements have the following benefits:&lt;br /&gt;
*A good SQL implementation will be able to cache the query better if it is a prepared statement.&lt;br /&gt;
*You don't have to rebuild the entire query string every execution.&lt;br /&gt;
*You don't have to allocate a new query structure on every execution.&lt;br /&gt;
*Input is &amp;quot;always&amp;quot; secure (more on this later).&lt;br /&gt;
&lt;br /&gt;
A prepared statement has &amp;quot;markers&amp;quot; for inputs.  For example, let's consider a function that takes in a database Handle and a name, and retrieves some info from a table:&lt;br /&gt;
&amp;lt;pawn&amp;gt;int GetSomeInfo(Database db, const char[] name)&lt;br /&gt;
{&lt;br /&gt;
	DBResultSet hQuery;&lt;br /&gt;
	char query[100];&lt;br /&gt;
&lt;br /&gt;
	/* Create enough space to make sure our string is quoted properly  */&lt;br /&gt;
	int buffer_len = strlen(name) * 2 + 1;&lt;br /&gt;
	char[] new_name = new char[buffer_len];&lt;br /&gt;
&lt;br /&gt;
	/* Ask the SQL driver to make sure our string is safely quoted */&lt;br /&gt;
	SQL_EscapeString(db, name, new_name, buffer_len);&lt;br /&gt;
&lt;br /&gt;
	/* Build the query */&lt;br /&gt;
	Format(query, sizeof(query), &amp;quot;SELECT userid FROM vb_user WHERE username = '%s'&amp;quot;, new_name);&lt;br /&gt;
	&lt;br /&gt;
	/* Execute the query */&lt;br /&gt;
	if ((hQuery = SQL_Query(query)) == null)&lt;br /&gt;
	{&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* Get some info here&lt;br /&gt;
	 */&lt;br /&gt;
&lt;br /&gt;
	delete hQuery;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Observe a version with prepared statements:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DBStatement hUserStmt = null;&lt;br /&gt;
int GetSomeInfo(Database db, const char[] name)&lt;br /&gt;
{&lt;br /&gt;
	/* Check if we haven't already created the statement */&lt;br /&gt;
	if (hUserStmt == null)&lt;br /&gt;
	{&lt;br /&gt;
		char error[255];&lt;br /&gt;
		hUserStmt = SQL_PrepareQuery(db, &amp;quot;SELECT userid FROM vb_user WHERE username = ?&amp;quot;, error, sizeof(error));&lt;br /&gt;
		if (hUserStmt == null)&lt;br /&gt;
		{&lt;br /&gt;
			return 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	SQL_BindParamString(hUserStmt, 0, name, false);&lt;br /&gt;
	if (!SQL_Execute(hUserStmt))&lt;br /&gt;
	{&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Get some info here&lt;br /&gt;
	 */&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The important differences:&lt;br /&gt;
*The input string (&amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;) did not need to be backticked (quoted).  The SQL engine automatically performs all type safety and insertion checks.&lt;br /&gt;
*There was no need for quotation marks around the parameter marker, &amp;lt;tt&amp;gt;?&amp;lt;/tt&amp;gt;, even though it accepted a string.&lt;br /&gt;
*We only needed to create the statement Handle once; after that it can live for the lifetime of the database connection.&lt;br /&gt;
&lt;br /&gt;
=Processing Results=&lt;br /&gt;
Processing results is done in the same manner for both normal queries and prepared statements.  The important functions are:&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_GetRowCount()&amp;lt;/tt&amp;gt; - Returns the number of rows.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_FetchRow()&amp;lt;/tt&amp;gt; - Fetches the next row if one is available.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_Fetch[Int|String|Float]()&amp;lt;/tt&amp;gt; - Fetches data from a field in the current row.&lt;br /&gt;
&lt;br /&gt;
Let's consider a sample table that looks like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;CREATE TABLE users (&lt;br /&gt;
	name VARCHAR(64) NOT NULL PRIMARY KEY,&lt;br /&gt;
	age INT UNSIGNED NOT NULL&lt;br /&gt;
	);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following example has code that will print out all users matching a certain age.  There is an example for both prepared statements and normal queries.&lt;br /&gt;
&amp;lt;pawn&amp;gt;void PrintResults(Handle query)&lt;br /&gt;
{&lt;br /&gt;
	/* Even if we have just one row, you must call SQL_FetchRow() first */&lt;br /&gt;
	char name[MAX_NAME_LENGTH];&lt;br /&gt;
	while (SQL_FetchRow(query))&lt;br /&gt;
	{&lt;br /&gt;
		SQL_FetchString(query, 0, name, sizeof(name));&lt;br /&gt;
		PrintToServer(&amp;quot;Name \&amp;quot;%s\&amp;quot; was found.&amp;quot;, name);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bool GetByAge_Query(Database db, int age)&lt;br /&gt;
{&lt;br /&gt;
	char query[100];&lt;br /&gt;
	Format(query, sizeof(query), &amp;quot;SELECT name FROM users WHERE age = %d&amp;quot;, age);&lt;br /&gt;
&lt;br /&gt;
	DBResultSet hQuery = SQL_Query(db, query);&lt;br /&gt;
	if (hQuery == null)&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	PrintResults(hQuery);&lt;br /&gt;
&lt;br /&gt;
	delete hQuery;&lt;br /&gt;
&lt;br /&gt;
	return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
DBStatement hAgeStmt = null;&lt;br /&gt;
bool GetByAge_Statement(Database db, int age)&lt;br /&gt;
{&lt;br /&gt;
	if (hAgeSmt == null)&lt;br /&gt;
	{&lt;br /&gt;
		char error[255];&lt;br /&gt;
		if ((hAgeStmt = SQL_PrepareQuery(db, &lt;br /&gt;
			&amp;quot;SELECT name FROM users WHERE age = ?&amp;quot;, &lt;br /&gt;
			error, &lt;br /&gt;
			sizeof(error))) &lt;br /&gt;
		     == null)&lt;br /&gt;
		{&lt;br /&gt;
			return false;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	SQL_BindParamInt(hAgeStmt, 0, age);&lt;br /&gt;
	if (!SQL_Execute(hAgeStmt))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	PrintResults(hAgeStmt);&lt;br /&gt;
&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that these examples did not close the statement Handles.  These examples assume a global database instance that is only closed when the plugin is unloaded.  For plugins which maintain temporary database connections, prepared statement Handles must be freed or else the database connection will never be closed.&lt;br /&gt;
&lt;br /&gt;
=Threading=&lt;br /&gt;
SourceMod supports threaded SQL querying.  That is, SQL operations can be completed in a separate thread from main gameplay.  If your database server is remote or requires a network connection, queries can cause noticeable gameplay lag, and supporting threading is often a good idea if your queries occur in the middle of gameplay.&lt;br /&gt;
&lt;br /&gt;
Threaded queries are ''asynchronous''.  That is, they are dispatched and you can only find the results through a callback.  Although the callback is guaranteed to fire eventually, it may not fire in any specific given timeframe.  Certain drivers may not support threading; if this is the case, an RTE will be thrown.  If the threader cannot start or the threader is currently disabled, SourceMod will transparently execute the query in the main thread as a fallback.&lt;br /&gt;
&lt;br /&gt;
==Operations==&lt;br /&gt;
All threaded operations (except connecting) use the same callback for result notification: &amp;lt;tt&amp;gt;SQLQueryCallback&amp;lt;/tt&amp;gt;.  The parameters are:&lt;br /&gt;
*&amp;lt;tt&amp;gt;db&amp;lt;/tt&amp;gt; - The cloned database handle.  If the db handle was not found or was invalidated, &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; is passed.&lt;br /&gt;
*&amp;lt;tt&amp;gt;results&amp;lt;/tt&amp;gt; - Result object, or null on failure.&lt;br /&gt;
*&amp;lt;tt&amp;gt;error&amp;lt;/tt&amp;gt; - An error string.&lt;br /&gt;
*&amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt; - Custom data that can be passed via some SQL operations.&lt;br /&gt;
&lt;br /&gt;
The following operations can be done via threads:&lt;br /&gt;
*&amp;lt;b&amp;gt;Connection&amp;lt;/b&amp;gt;, via &amp;lt;tt&amp;gt;SQL_TConnect&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;b&amp;gt;Querying&amp;lt;/b&amp;gt;, via &amp;lt;tt&amp;gt;SQL_TQuery()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*''Note: prepared statements are not yet available for the threader.''&lt;br /&gt;
&lt;br /&gt;
It is always safe to chain one operation from another.&lt;br /&gt;
&lt;br /&gt;
===Connecting===&lt;br /&gt;
It is not necessary to make a threaded connection in order to make threaded queries.  However, creating a threaded connection will not pause the game server if a connection cannot be immediately established. &lt;br /&gt;
Connecting however uses a different callback: &amp;lt;tt&amp;gt;SQLConnectCallback&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The following parameters are used for the threaded connection callback:&lt;br /&gt;
*&amp;lt;tt&amp;gt;db&amp;lt;/tt&amp;gt;: Handle to the database connection, or &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; if it could not be found.&lt;br /&gt;
*&amp;lt;tt&amp;gt;error&amp;lt;/tt&amp;gt;: The error string, if any.&lt;br /&gt;
*&amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: Unused (0)&lt;br /&gt;
&lt;br /&gt;
Example: &lt;br /&gt;
&amp;lt;pawn&amp;gt;Database hDatabase = null;&lt;br /&gt;
&lt;br /&gt;
void StartSQL()&lt;br /&gt;
{&lt;br /&gt;
	Database.Connect(GotDatabase);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void GotDatabase(Database db, const char[] error, any data)&lt;br /&gt;
{&lt;br /&gt;
	if (db == null)&lt;br /&gt;
	{&lt;br /&gt;
		LogError(&amp;quot;Database failure: %s&amp;quot;, error);&lt;br /&gt;
	} &lt;br /&gt;
        else &lt;br /&gt;
        {&lt;br /&gt;
		hDatabase = hndl;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Querying===&lt;br /&gt;
Threaded queries can be performed on any database Handle as long as the driver supports threading.  All query results for the first result set are retrieved while in the thread.  If your query returns more than one set of results (for example, &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; on MySQL with certain functions), the behaviour of the threader is undefined at this time.  &amp;lt;b&amp;gt;Note that if you want to perform both threaded and non-threaded queries on the same connection, you MUST read the &amp;quot;Locking&amp;quot; section below.&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Query operations use the following callback parameters:&lt;br /&gt;
*&amp;lt;tt&amp;gt;owner&amp;lt;/tt&amp;gt;: A Handle to the database used to query.  The Handle is not the same as the Handle originally passed; however, it will test positively with &amp;lt;tt&amp;gt;SQL_IsSameConnection&amp;lt;/tt&amp;gt;.  The Handle can be cloned but it cannot be closed (it is closed automatically).  It may be &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; in the case of a serious error (for example, the driver being unloaded).&lt;br /&gt;
*&amp;lt;tt&amp;gt;hndl&amp;lt;/tt&amp;gt;: A Handle to the query.  It can be cloned, but not closed (it is closed automatically).  It may be &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; if there was an error.&lt;br /&gt;
*&amp;lt;tt&amp;gt;error&amp;lt;/tt&amp;gt;: Error string, if any.&lt;br /&gt;
*&amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: Optional user-defined data passed in through &amp;lt;tt&amp;gt;SQL_TQuery()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Example, continuing from above:&lt;br /&gt;
&amp;lt;pawn&amp;gt;void CheckSteamID(int userid, const char[] auth)&lt;br /&gt;
{&lt;br /&gt;
	char query[255];&lt;br /&gt;
	FormatEx(query, sizeof(query), &amp;quot;SELECT userid FROM users WHERE steamid = '%s'&amp;quot;, auth);&lt;br /&gt;
	hdatabase.Query(T_CheckSteamID, query, userid);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void T_CheckSteamID(Database db, DBResultSet results, const char[] error, any data)&lt;br /&gt;
{&lt;br /&gt;
	int client = 0;&lt;br /&gt;
&lt;br /&gt;
	/* Make sure the client didn't disconnect while the thread was running */&lt;br /&gt;
	if ((client = GetClientOfUserId(data)) == 0)&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (results == null)&lt;br /&gt;
	{&lt;br /&gt;
		LogError(&amp;quot;Query failed! %s&amp;quot;, error);&lt;br /&gt;
		KickClient(client, &amp;quot;Authorization failed&amp;quot;);&lt;br /&gt;
	} else if (results.RowCount == 0) {&lt;br /&gt;
		KickClient(client, &amp;quot;You are not a member&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Locking==&lt;br /&gt;
It is possible to run both threaded and non-threaded queries on the same connection.  However, without the proper precautions, you could corrupt the network stream (even if it's local), corrupt memory, or otherwise cause a crash in the SQL driver.  To solve this, SourceMod has ''database locking''.  Locking is done via &amp;lt;tt&amp;gt;SQL_LockDatabase()&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SQL_UnlockDatabase&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Whenever performing any of the following non-threaded operations on a database, it is absolutely necessary to enclose the entire operation with a lock:&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_Query()&amp;lt;/tt&amp;gt; (and &amp;lt;tt&amp;gt;SQL_FetchMoreResults&amp;lt;/tt&amp;gt; pairings)&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_FastQuery&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_PrepareQuery&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_Bind*&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SQL_Execute&amp;lt;/tt&amp;gt; pairings&lt;br /&gt;
&lt;br /&gt;
The rule of thumb is: if your operation is going to use the database connection, it must be locked until the operation is fully completed.  &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetByAge_Query(Database db, int age)&lt;br /&gt;
{&lt;br /&gt;
	char query[100];&lt;br /&gt;
	FormatEx(query, sizeof(query), &amp;quot;SELECT name FROM users WHERE age = %d&amp;quot;, age);&lt;br /&gt;
&lt;br /&gt;
	SQL_LockDatabase(db);&lt;br /&gt;
	DBResultSet hQuery = SQL_Query(db, query);&lt;br /&gt;
	if (hQuery == null)&lt;br /&gt;
	{&lt;br /&gt;
		SQL_UnlockDatabase(db);&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	SQL_UnlockDatabase(db);&lt;br /&gt;
&lt;br /&gt;
	PrintResults(hQuery);&lt;br /&gt;
&lt;br /&gt;
	delete hQuery;&lt;br /&gt;
&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that it was only necessary to lock the query; SourceMod pre-fetches the result set, and thus the network queue is clean.&lt;br /&gt;
&lt;br /&gt;
===Warnings===&lt;br /&gt;
*&amp;lt;b&amp;gt;Never&amp;lt;/b&amp;gt; call &amp;lt;tt&amp;gt;SQL_LockDatabase&amp;lt;/tt&amp;gt; right before a threaded operation.  You will deadlock the server and have to terminate/kill it.  &lt;br /&gt;
*&amp;lt;b&amp;gt;Always pair every Lock with an Unlock.&amp;lt;/b&amp;gt;  Otherwise you risk a deadlock.&lt;br /&gt;
*If your query returns multiple result sets, for example, a procedure call on MySQL that returns results, you must lock both the query and the entire fetch operation.  SourceMod is only able to fetch one result set at a time, and all result sets must be cleared before a new query is started.&lt;br /&gt;
&lt;br /&gt;
==Priority==&lt;br /&gt;
Threaded SQL operations are placed in a simple priority queue.  The priority levels are &amp;lt;tt&amp;gt;High&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Medium&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;Low&amp;lt;/tt&amp;gt;.  Connections always have the highest priority.  &lt;br /&gt;
&lt;br /&gt;
Changing the priority can be useful if you have many queries with different purposes.  For example, a statistics plugin might execute 10 queries on death, and one query on join.  Because the statistics might rely on the join info, the join query might need to be high priority, while the death queries can be low priority.&lt;br /&gt;
&lt;br /&gt;
You should &amp;lt;b&amp;gt;never&amp;lt;/b&amp;gt; simply assign a high priority to all of your queries simply because you want them to get done fast.  Not only does it not work that way, but you may be inserting subtle problems into other plugins by being greedy.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=SQLite=&lt;br /&gt;
==Introduction==&lt;br /&gt;
[http://www.sqlite.org/ SQLite] is a fast local-file SQL database engine and SourceMod provides a DBI driver for it.  SQLite differs from MySQL, and thus MySQL queries may not work in SQLite.  The driver type for connections is &amp;lt;tt&amp;gt;sqlite&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
Since SQLite is local only, most of the connection parameters can be ignored.  The only connection parameter required is &amp;lt;tt&amp;gt;database&amp;lt;/tt&amp;gt;, which specifies the file name of the database.  Databases are created on demand if they do not already exist, and are stored in &amp;lt;tt&amp;gt;addons/sourcemod/data/sqlite&amp;lt;/tt&amp;gt;.  An extension of &amp;quot;.sq3&amp;quot; is automatically appended to the file name.&lt;br /&gt;
&lt;br /&gt;
Additionally, you can specify sub-folders in the database name.  For example, &amp;quot;cssdm/players&amp;quot; will become &amp;lt;tt&amp;gt;addons/sourcemod/data/sqlite/cssdm/players.sq3&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
SQLite supports the threading layer, and requires all of the same rules as the MySQL driver (including locks on shared connections).&lt;br /&gt;
&lt;br /&gt;
==External Links==&lt;br /&gt;
*[http://www.sqlite.org SQLite Homepage]&lt;br /&gt;
*[http://sqlitebrowser.sourceforge.net/ SQLite Browser]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Optional_Requirements_(SourceMod_Scripting)&amp;diff=10180</id>
		<title>Optional Requirements (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Optional_Requirements_(SourceMod_Scripting)&amp;diff=10180"/>
		<updated>2016-07-26T02:43:20Z</updated>

		<summary type="html">&lt;p&gt;Shavit: Update example code to transitional syntax&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Normally, if you use natives from an extension or another plugin, your plugin will not load unless those natives exist.  However, it is possible to make your dependencies &amp;quot;optional.&amp;quot;  This article details how.&lt;br /&gt;
&lt;br /&gt;
=Disabling Requirements=&lt;br /&gt;
==Extensions==&lt;br /&gt;
To disable an extension being marked as &amp;quot;required,&amp;quot; remove the &amp;lt;tt&amp;gt;REQUIRE_EXTENSIONS&amp;lt;/tt&amp;gt; define.  For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
#undef REQUIRE_EXTENSIONS&lt;br /&gt;
#include &amp;lt;sdktools&amp;gt;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that any extensions included after the &amp;lt;tt&amp;gt;#undef&amp;lt;/tt&amp;gt; will also be marked as not required.  Thus, you may need to move the include down, or do something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
#undef REQUIRE_EXTENSIONS&lt;br /&gt;
#include &amp;lt;sdktools&amp;gt;&lt;br /&gt;
#define REQUIRE_EXTENSIONS&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Plugins==&lt;br /&gt;
To disable an plugin being marked as &amp;quot;required,&amp;quot; remove the &amp;lt;tt&amp;gt;REQUIRE_PLUGIN&amp;lt;/tt&amp;gt; define.  For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
#undef REQUIRE_PLUGIN&lt;br /&gt;
#include &amp;lt;ircrelay&amp;gt;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that any plugins included after the &amp;lt;tt&amp;gt;#undef&amp;lt;/tt&amp;gt; will also be marked as not required.  Thus, you may need to move the include down, or do something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
#undef REQUIRE_PLUGIN&lt;br /&gt;
#include &amp;lt;ircrelay&amp;gt;&lt;br /&gt;
#define REQUIRE_PLUGIN&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Optional Natives==&lt;br /&gt;
To mark a native as optional, use &amp;lt;tt&amp;gt;MarkNativeAsOptional&amp;lt;/tt&amp;gt;.  It should be called in &amp;lt;tt&amp;gt;AskPluginLoad2&amp;lt;/tt&amp;gt;.  For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)&lt;br /&gt;
{&lt;br /&gt;
	MarkNativeAsOptional(&amp;quot;SDKCall&amp;quot;);&lt;br /&gt;
	return APLRes_Success;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Checking Optional Dependencies=&lt;br /&gt;
If you use a plugin or extension as an optional dependency, you may need to check whether it exists.  For example, let's say we're relying on a plugin with the library name of &amp;quot;ircrelay.&amp;quot;  The way to always know whether ircrelay is loaded (and working) is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool ircrelay = false;&lt;br /&gt;
&lt;br /&gt;
public void OnAllPluginsLoaded()&lt;br /&gt;
{&lt;br /&gt;
	ircrelay = LibraryExists(&amp;quot;ircrelay&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnLibraryRemoved(const char[] name)&lt;br /&gt;
{&lt;br /&gt;
	if (StrEqual(name, &amp;quot;ircrelay&amp;quot;))&lt;br /&gt;
	{&lt;br /&gt;
		ircrelay = false;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnLibraryAdded(const char[] name)&lt;br /&gt;
{&lt;br /&gt;
	if (StrEqual(name, &amp;quot;ircrelay&amp;quot;))&lt;br /&gt;
	{&lt;br /&gt;
		ircrelay = true;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Creating a Dependency=&lt;br /&gt;
Allowing other plugins to use your plugin as a library requires making an include file with two structures (the second of which is optional).  The first structure must look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public SharedPlugin __pl_myfile = &lt;br /&gt;
{&lt;br /&gt;
	name = &amp;quot;myfile&amp;quot;,&lt;br /&gt;
	file = &amp;quot;myfile.smx&amp;quot;,&lt;br /&gt;
#if defined REQUIRE_PLUGIN&lt;br /&gt;
	required = 1,&lt;br /&gt;
#else&lt;br /&gt;
	required = 0,&lt;br /&gt;
#endif&lt;br /&gt;
};&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The basic format is:&lt;br /&gt;
*The variable name MUST start with &amp;lt;tt&amp;gt;__pl_&amp;lt;/tt&amp;gt; and must end with a unique string.&lt;br /&gt;
*The &amp;quot;name&amp;quot; portion is treated as the library name and must be unique.&lt;br /&gt;
*The filename must match the filename of the plugin implementing the library.&lt;br /&gt;
*The requirement portion should remain unchanged in order to maintain standards.&lt;br /&gt;
&lt;br /&gt;
Additionally, you should expose a function which marks all of your natives as optional.  You can do this by:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#if !defined REQUIRE_PLUGIN&lt;br /&gt;
public void __pl_myfile_SetNTVOptional()&lt;br /&gt;
{&lt;br /&gt;
	MarkNativeAsOptional(&amp;quot;native1&amp;quot;);&lt;br /&gt;
	MarkNativeAsOptional(&amp;quot;native2&amp;quot;);&lt;br /&gt;
	MarkNativeAsOptional(&amp;quot;native3&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
#endif&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will be secretly called before the plugin loads (if and only if the requirement is optional), thus allowing seamless optional usage by third party developers.  Note that the &amp;lt;tt&amp;gt;__pl_&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;_SetNTVOptional&amp;lt;/tt&amp;gt; portions &amp;lt;b&amp;gt;must&amp;lt;/b&amp;gt; be present, and that everything in between must match the ending of &amp;lt;tt&amp;gt;__pl_&amp;lt;/tt&amp;gt; for the &amp;lt;tt&amp;gt;SharedPlugin&amp;lt;/tt&amp;gt; structure.&lt;br /&gt;
&lt;br /&gt;
You also must register the library name with SourceMod -- again this should be the unique string. This should be done inside the &amp;lt;code&amp;gt;AskPluginLoad2&amp;lt;/code&amp;gt; function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)&lt;br /&gt;
{&lt;br /&gt;
	//... code here ...&lt;br /&gt;
	RegPluginLibrary(&amp;quot;myfile&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return APLRes_Success;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Full Example =&lt;br /&gt;
;''Bounty: bounty.sp''&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
#undef REQUIRE_PLUGIN&lt;br /&gt;
#include &amp;lt;ircrelay&amp;gt;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
;''Bounty: bounty.config.sp''&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
bool plugin_IrcRelay = LibraryExists(&amp;quot;ircrelay&amp;quot;);&lt;br /&gt;
if ((BountyIRC) &amp;amp;&amp;amp; (plugin_IrcRelay))&lt;br /&gt;
{&lt;br /&gt;
	RegisterIrcCommand(&amp;quot;!bounty&amp;quot;, &amp;quot;x&amp;quot;, Irc_ViewBounty);&lt;br /&gt;
	IrcMessage(CHAN_MASTER, &amp;quot;IRC Bounty Running!&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
	if ((BountyIRC) &amp;amp;&amp;amp; (!plugin_IrcRelay))&lt;br /&gt;
	{&lt;br /&gt;
		BountyConsole_Debug(&amp;quot;%t&amp;quot;, &amp;quot;Bounty IRC Relay failed&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
;''IRC Relay: ircrelay.sp''&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)&lt;br /&gt;
{&lt;br /&gt;
	//... code here ...&lt;br /&gt;
	RegPluginLibrary(&amp;quot;ircrelay&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return APLRes_Success;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
;''IRC Relay: ircrelay.inc''&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public SharedPlugin __pl_ircrelay = &lt;br /&gt;
{&lt;br /&gt;
	name = &amp;quot;ircrelay&amp;quot;,&lt;br /&gt;
	file = &amp;quot;ircrelay.smx&amp;quot;,&lt;br /&gt;
#if defined REQUIRE_PLUGIN&lt;br /&gt;
	required = 1,&lt;br /&gt;
#else&lt;br /&gt;
	required = 0,&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
#if !defined REQUIRE_PLUGIN&lt;br /&gt;
public void __pl_ircrelay_SetNTVOptional()&lt;br /&gt;
{&lt;br /&gt;
	MarkNativeAsOptional(&amp;quot;IrcMessage&amp;quot;);&lt;br /&gt;
	MarkNativeAsOptional(&amp;quot;RegisterIrcCommand&amp;quot;);&lt;br /&gt;
	MarkNativeAsOptional(&amp;quot;IrcGetCmdArgc&amp;quot;);&lt;br /&gt;
	MarkNativeAsOptional(&amp;quot;IrcGetCmdArgv&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; value is what will be checked when you run &amp;lt;code&amp;gt;LibraryExists&amp;lt;/code&amp;gt;. This allows the bounty script to fully work, even if the IRC relay plugin is not installed and/or running correctly on your server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Adding_Admins_(SourceMod)&amp;diff=10178</id>
		<title>Adding Admins (SourceMod)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Adding_Admins_(SourceMod)&amp;diff=10178"/>
		<updated>2016-07-09T19:32:45Z</updated>

		<summary type="html">&lt;p&gt;Shavit: fix annoying typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__FORCETOC__&lt;br /&gt;
SourceMod has as very detailed and flexible administration system, and it can be quite daunting to users.  To simplify things, there are a number of &amp;quot;flags&amp;quot; which specify generic permissions administrators can have.&lt;br /&gt;
&lt;br /&gt;
There are currently two provided ways of storing admins.  One is via the admin-flatfile.smx plugin that is enabled by default. This plugin provides two files: a simplified flat file, and another more complex tree-based file. The other way to store admins is using [[SQL Admins (SourceMod)|SQL]].&lt;br /&gt;
&lt;br /&gt;
SourceMod provides three methods of authentication:&lt;br /&gt;
*''Steam ID'' (unique to a Steam account)&lt;br /&gt;
*''IP Address'' (semi-unique to a given computer, better for LANs)&lt;br /&gt;
*''Name'' (requires a password)&lt;br /&gt;
&lt;br /&gt;
=Quick Start=&lt;br /&gt;
On the server, open &amp;lt;code&amp;gt;/addons/sourcemod/configs/admins_simple.ini&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a new line, add the following, replacing yoursteamid (use your client's console '''status''' command to retrieve your Steam ID - formatted as STEAM_n:o:p)&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;yoursteamid&amp;quot; &amp;quot;99:z&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Save the file, then type &amp;lt;code&amp;gt;sm_reloadadmins&amp;lt;/code&amp;gt; in the server console. Connect to the server with the game client. Enter sm_admin in the client console, and then return to the game.  You should see the admin menu.&lt;br /&gt;
&lt;br /&gt;
=Levels=&lt;br /&gt;
First, let's quickly run down the provided levels:&lt;br /&gt;
:{| cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Name&lt;br /&gt;
| Flag&lt;br /&gt;
| Purpose&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| reservation&lt;br /&gt;
| a&lt;br /&gt;
| Reserved slot access.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| generic&lt;br /&gt;
| b&lt;br /&gt;
| Generic admin; required for admins.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| kick&lt;br /&gt;
| c&lt;br /&gt;
| Kick other players.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| ban&lt;br /&gt;
| d&lt;br /&gt;
| Ban other players.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| unban&lt;br /&gt;
| e&lt;br /&gt;
| Remove bans.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| slay&lt;br /&gt;
| f&lt;br /&gt;
| Slay/harm other players.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| changemap&lt;br /&gt;
| g&lt;br /&gt;
| Change the map or major gameplay features.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| cvar&lt;br /&gt;
| h&lt;br /&gt;
| Change most cvars.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| config&lt;br /&gt;
| i&lt;br /&gt;
| Execute config files.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| chat&lt;br /&gt;
| j&lt;br /&gt;
| Special chat privileges.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| vote&lt;br /&gt;
| k&lt;br /&gt;
| Start or create votes.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| password&lt;br /&gt;
| l&lt;br /&gt;
| Set a password on the server.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| rcon&lt;br /&gt;
| m&lt;br /&gt;
| Use RCON commands.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| cheats&lt;br /&gt;
| n&lt;br /&gt;
| Change sv_cheats or use cheating commands.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| root&lt;br /&gt;
| z&lt;br /&gt;
| Magically enables all flags and ignores immunity values.&lt;br /&gt;
&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom1&lt;br /&gt;
| o&lt;br /&gt;
| Custom Group 1.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom2&lt;br /&gt;
| p&lt;br /&gt;
| Custom Group 2.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom3&lt;br /&gt;
| q&lt;br /&gt;
| Custom Group 3.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom4&lt;br /&gt;
| r&lt;br /&gt;
| Custom Group 4.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom5&lt;br /&gt;
| s&lt;br /&gt;
| Custom Group 5.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom6&lt;br /&gt;
| t&lt;br /&gt;
| Custom Group 6.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Immunity=&lt;br /&gt;
In SourceMod, immunity is a flexible system based on ''immunity levels''.  Every admin can have an arbitrary immunity value assigned to them.  Whether an admin can target another admin depends on who has a higher immunity value.&lt;br /&gt;
&lt;br /&gt;
For example, say Admin #1 has an immunity level of &amp;quot;3&amp;quot; and Admin #2 has an immunity level of &amp;quot;10.&amp;quot;  Admin #2 can target Admin #1, but Admin #1 cannot target Admin #2.  The numbers are completely arbitrary, and they can be any number equal to or higher than 0.  Note that 0 always implies no immunity.&lt;br /&gt;
&lt;br /&gt;
By default, admins with the same immunity value can target each other.  This can be changed via &amp;lt;tt&amp;gt;sm_immunity_mode&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cfg/sourcemod.cfg&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Admins with the z flag are not subject to immunity checks.'''  This means they can always target anyone.&lt;br /&gt;
&lt;br /&gt;
=Passwords=&lt;br /&gt;
Using the passwords method is '''optional'''.&lt;br /&gt;
&lt;br /&gt;
For passwords to work, the server administrator must change the &amp;lt;code&amp;gt;PassInfoVar&amp;lt;/code&amp;gt; line in &amp;lt;tt&amp;gt;addons/sourcemod/configs/core.cfg&amp;lt;/tt&amp;gt;.  For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;PassInfoVar&amp;quot;			&amp;quot;_sm1337&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, if an admin has a password, the person must set the password via the ''setinfo'' command in the client console.   For example, using the examples above, the player &amp;lt;tt&amp;gt;BAILOPAN&amp;lt;/tt&amp;gt; would need to type:&lt;br /&gt;
&amp;lt;pre&amp;gt;setinfo &amp;quot;_sm1337&amp;quot; &amp;quot;Gab3n&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To automate this upon connecting to a server, you can create an &amp;quot;autoexec.cfg&amp;quot; file in your client game folder.  This will be located under &amp;lt;tt&amp;gt;SteamApps\common\[game]\[gameabbr]\cfg&amp;lt;/tt&amp;gt;.  For example:&lt;br /&gt;
*&amp;lt;tt&amp;gt;C:\Program Files\Steam\steamapps\common\Counter-Strike Source\cstrike\cfg&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set the password upon connecting.  For Steam and IP authentication, your admin privileges will be automatically assigned if the password is correct.  For name based authentication, your password must be correct before you change your name, or else you will be kicked from the server.&lt;br /&gt;
&lt;br /&gt;
=Simple Admins=&lt;br /&gt;
The easiest way to add administrators is through &amp;lt;tt&amp;gt;configs/admins_simple.ini&amp;lt;/tt&amp;gt;. This is a flat file which requires two parameters per line: authentication info, and flags.&lt;br /&gt;
&lt;br /&gt;
The string's syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt; &amp;gt; - Required&lt;br /&gt;
&lt;br /&gt;
[ ] - Optional&lt;br /&gt;
&lt;br /&gt;
/ - Or&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;&amp;lt;Steam ID/!IP/Steam name&amp;gt;&amp;quot; &amp;quot;[immunity level:]&amp;lt;flag/@group&amp;gt;&amp;quot; [&amp;quot;password&amp;quot;]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;STEAM_0:1:16&amp;quot;		&amp;quot;bce&amp;quot;			//generic, kick, unban for this steam ID. no immunity&lt;br /&gt;
&amp;quot;!127.0.0.1&amp;quot;		&amp;quot;5:z&amp;quot;			//all permissions for this IP, immunity level = 5&lt;br /&gt;
&amp;quot;BAILOPAN&amp;quot;		&amp;quot;abc&amp;quot;	&amp;quot;Gab3n&amp;quot;		//name BAILOPAN, password &amp;quot;Gab3n&amp;quot;: gets reservation, generic, kick&lt;br /&gt;
&amp;quot;Gaben&amp;quot;                 &amp;quot;@Admins&amp;quot;               //name Gaben, group Admins&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Detailed Admins=&lt;br /&gt;
Alternatively, you can add admins via &amp;lt;tt&amp;gt;configs/admins.cfg&amp;lt;/tt&amp;gt;, a more advanced file stored in a KeyValues format.  Each admin is its own block inside a main &amp;quot;Admin&amp;quot; block. You can create and / or modify &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; files with [http://forums.alliedmods.net/showthread.php?t=81160 KVManager]. The format is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Admins&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Admin Name&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;auth&amp;quot;		&amp;quot;[steam|name|ip]&amp;quot;&lt;br /&gt;
		&amp;quot;identity&amp;quot;	&amp;quot;[unique id]&amp;quot;&lt;br /&gt;
		&amp;quot;[option1]&amp;quot;	&amp;quot;[value1]&amp;quot;&lt;br /&gt;
		&amp;quot;[option2]&amp;quot;	&amp;quot;[value2]&amp;quot;&lt;br /&gt;
		/* .... */&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: red; font-family: consolas;&amp;quot;&amp;gt;*&amp;lt;/span&amp;gt; - Required&lt;br /&gt;
*&amp;lt;tt&amp;gt;auth&amp;lt;/tt&amp;gt; &amp;lt;span style=&amp;quot;color: red; font-family: consolas;&amp;quot;&amp;gt;*&amp;lt;/span&amp;gt;: Must be one of &amp;lt;tt&amp;gt;steam&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;ip&amp;lt;/tt&amp;gt; (unless there is a custom auth method), and instructs SourceMod how to interpret the &amp;lt;tt&amp;gt;identity&amp;lt;/tt&amp;gt; value.&lt;br /&gt;
*&amp;lt;tt&amp;gt;identity&amp;lt;/tt&amp;gt; &amp;lt;span style=&amp;quot;color: red; font-family: consolas;&amp;quot;&amp;gt;*&amp;lt;/span&amp;gt;: Unique value that allows SourceMod to find this admin given an authentication method and the given value.&lt;br /&gt;
*&amp;lt;tt&amp;gt;password&amp;lt;/tt&amp;gt;: Specifies the password the user must enter (see [[#Passwords|passwords]]).&lt;br /&gt;
*&amp;lt;tt&amp;gt;group&amp;lt;/tt&amp;gt;: Specifies a group name the user should inherit if available.  More than one &amp;quot;group&amp;quot; line can be specified.  There should be no '@' symbol as there is no ambiguity.&lt;br /&gt;
*&amp;lt;tt&amp;gt;flags&amp;lt;/tt&amp;gt;: Default access flags the user should receive.&lt;br /&gt;
*&amp;lt;tt&amp;gt;immunity&amp;lt;/tt&amp;gt;: Default immunity level the user should receive.&lt;br /&gt;
&lt;br /&gt;
The admin name is optional (it can be blank).  It is not used internally and is intended for convenience usage by 3rd party tools.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;Admins&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;BAILOPAN&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;auth&amp;quot;		&amp;quot;steam&amp;quot;&lt;br /&gt;
		&amp;quot;identity&amp;quot;	&amp;quot;STEAM_0:1:2345&amp;quot;&lt;br /&gt;
		&amp;quot;flags&amp;quot;		&amp;quot;abcdef&amp;quot;&lt;br /&gt;
		&amp;quot;immunity&amp;quot;	&amp;quot;5&amp;quot;&lt;br /&gt;
		&amp;quot;group&amp;quot;		&amp;quot;Awesome Admins&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	&amp;quot;Blue Crab&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;auth&amp;quot;		&amp;quot;steam&amp;quot;&lt;br /&gt;
		&amp;quot;identity&amp;quot;	&amp;quot;STEAM_0:1:666666&amp;quot;&lt;br /&gt;
		&amp;quot;flags&amp;quot;		&amp;quot;z&amp;quot;&lt;br /&gt;
		&amp;quot;immunity&amp;quot;	&amp;quot;99&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=See Also=&lt;br /&gt;
*[[Adding Groups (SourceMod)]]&lt;br /&gt;
*[[Overriding Command Access (SourceMod)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Documentation]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Menu_API_(SourceMod)&amp;diff=10175</id>
		<title>Menu API (SourceMod)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Menu_API_(SourceMod)&amp;diff=10175"/>
		<updated>2016-06-24T11:12:34Z</updated>

		<summary type="html">&lt;p&gt;Shavit: Fix error that could cause an error in compilation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod has an extensive API for building and displaying menus to clients.  Unlike AMX Mod X, this API is highly state driven.  Menus are based on callbacks which are guaranteed to be fired.&lt;br /&gt;
&lt;br /&gt;
For C++, the Menu API can be found in &amp;lt;tt&amp;gt;public/IMenuManager.h&amp;lt;/tt&amp;gt;.  For SourcePawn, it is in &amp;lt;tt&amp;gt;scripting/include/menus.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Objects=&lt;br /&gt;
The SourceMod Menu System is based on an object oriented hierarchy.  Understanding this hierarchy, even for scripting, is critical to using menus effectively.&lt;br /&gt;
&lt;br /&gt;
==Styles==&lt;br /&gt;
The top level object is a ''MenuStyle'' (&amp;lt;tt&amp;gt;IMenuStyle&amp;lt;/tt&amp;gt; in C++).  Styles describe a unique menu system.  There are two such styles built into SourceMod:&lt;br /&gt;
*Valve Style, also called &amp;quot;ESC&amp;quot; menus; 8 items per page, no raw/disabled text can be rendered&lt;br /&gt;
*Radio Style, also called &amp;quot;AMX&amp;quot; menus; 10 items per page, raw/disabled text can be rendered&lt;br /&gt;
&lt;br /&gt;
Each MenuStyle has its own rules and properties.  You can think of them as existing on separate &amp;quot;channels.&amp;quot;  For example, two different menus can exist on a player's screen as both a Valve menu and a Radio menu at the same time, and SourceMod will be able to manage both without any problems.  This is because each style keeps track of its own menus separately.&lt;br /&gt;
&lt;br /&gt;
==Panels==&lt;br /&gt;
Menu displays are drawn with a lower level interface called ''Panels'' (&amp;lt;tt&amp;gt;IMenuPanel&amp;lt;/tt&amp;gt; in C++).  Panels describe exactly one chunk of display text.  Both selectable items and raw text can be added to a panel as long as its parent style supports the contents you're trying to draw.  For example, the Valve style does not support drawing raw text or disabled items.  But with a Radio-style Panel, you can display a large amount of on-screen data in your own format.&lt;br /&gt;
&lt;br /&gt;
Panels are considered temporary objects.  They are created, rendered, displayed, and destroyed.  Although they can be saved indefinitely, it is not necessary to do so.&lt;br /&gt;
&lt;br /&gt;
Valve Style drawing rules/limitations:&lt;br /&gt;
*Max items per page is 8.&lt;br /&gt;
*Disabled items cannot be drawn.&lt;br /&gt;
*Raw text cannot be drawn.&lt;br /&gt;
*Spacers do not add a space/newline, giving a &amp;quot;cramped&amp;quot; feel.&lt;br /&gt;
*Users must press &amp;quot;ESC&amp;quot; or be at their console to view the menu.&lt;br /&gt;
&lt;br /&gt;
Radio Style drawing rules/limitations:&lt;br /&gt;
*Max items per page is 10.&lt;br /&gt;
*Titles appear white; items appear yellow, unless disabled, in which case they are white.&lt;br /&gt;
*The 0th item is always white.  For consistency, this means navigational controls explained in the next section are always white, and simply not drawn if disabled.&lt;br /&gt;
&lt;br /&gt;
==Menus==&lt;br /&gt;
Lastly, there are plain ''Menus'' (&amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; in C++).  These are helper objects designed for storing a menu based on selectable items.  Unlike low-level panels, menus are containers for '''items''', and can only contain items which are selectable (i.e., do not contain raw text).  They fall into two categories:&lt;br /&gt;
*Non-paginated: The menu can only have a certain number of items on it, and no control/navigation options will be added, except for an &amp;quot;Exit&amp;quot; button which will always be in the last position supported by the style.&lt;br /&gt;
**Valve Style maximum items: 8&lt;br /&gt;
**Radio Style maximum items: 10&lt;br /&gt;
*Paginated: The menu can have any number of items.  When displayed, only a certain number of items will be drawn at a time.  Automatic navigation controls are added so players can easily move back and forth to different &amp;quot;pages&amp;quot; of items in the menu.&lt;br /&gt;
**&amp;quot;Previous&amp;quot; is always drawn as the first navigation item, third from the last supported position.  This will not be drawn if the menu only contains one page.  If there are no previous pages, the text will not be drawn on either style; if possible, the menu will be padded so spacing is consistent.&lt;br /&gt;
***Valve Style position: 6&lt;br /&gt;
***Radio Style position: 8&lt;br /&gt;
**&amp;quot;Next&amp;quot; is always drawn as the second navigation item, second from the last supported position.  This will not be drawn if the menu only contains one page.  If there are no further pages, the text will not be drawn on either style; if possible, the menu will be padded so spacing is consistent.&lt;br /&gt;
***Valve Style position: 7&lt;br /&gt;
***Radio Style position: 9&lt;br /&gt;
**&amp;quot;Exit&amp;quot; is drawn if the menu has the exit button property set.  It is always the last supported item position.&lt;br /&gt;
***Valve Style position: 8&lt;br /&gt;
***Radio Style position: 10&lt;br /&gt;
&lt;br /&gt;
The purpose of Menus is to simplify the procedure of storing, drawing, and calculating the selection of items.  Thus, menus do not allow for adding raw text, as that would considerably complicate the drawing algorithm.  ''Note: The C++ API supports hooking &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; drawing procedures and adding raw text; this will be added to the scripting API soon.''&lt;br /&gt;
&lt;br /&gt;
Internally, Menus are drawn via a ''RenderMenu'' algorithm.  This algorithm creates a temporary panel and fills it with items from menus.  This panel is then displayed to a client.  The algorithm attempts to create a consistent feel across all menus, and across all styles.  Thus any menu displayed via the &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; class, or &amp;lt;tt&amp;gt;Menu&amp;lt;/tt&amp;gt; Handles, will look and act the same, and the Menu API is based off the Panel API.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Callbacks=&lt;br /&gt;
==Overview==&lt;br /&gt;
Menus are a callback based system.  Each callback represents an action that occurs during a ''menu display cycle''.  A cycle consists of a number of notifications:&lt;br /&gt;
*Start notification.&lt;br /&gt;
**Display notification if the menu can be displayed to the client.&lt;br /&gt;
**Either an item select or menu cancel notification.&lt;br /&gt;
*End notification.&lt;br /&gt;
&lt;br /&gt;
Since ''End'' signifies the end of a full display cycle, it is usually used to destroy temporary menus.&lt;br /&gt;
&lt;br /&gt;
==Specification==&lt;br /&gt;
A detailed explanation of these events is below.  For C++, an &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; pointer is always available.  For SourcePawn, a &amp;lt;tt&amp;gt;Menu&amp;lt;/tt&amp;gt; Handle and a &amp;lt;tt&amp;gt;MenuAction&amp;lt;/tt&amp;gt; are always set in the &amp;lt;tt&amp;gt;MenuHandler&amp;lt;/tt&amp;gt; callback.  Unlike C++, the SourcePawn API allows certain actions to only be called if they are requested at menu creation time.  This is an optimization.  However, certain actions cannot be prevented from being called.&lt;br /&gt;
&lt;br /&gt;
*'''Start'''.  The menu has been acknowledged.  This does not mean it will be displayed; however, it guarantees that &amp;quot;OnMenuEnd&amp;quot; will be called.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuStart()&amp;lt;/tt&amp;gt; in C++.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Start&amp;lt;/tt&amp;gt; in SourcePawn.  This action is not triggered unless requested.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: Ignored (always 0).&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: Ignored (always 0).&lt;br /&gt;
*'''Display'''.  The menu is being displayed to a client.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuDisplay()&amp;lt;/tt&amp;gt; in C++.  An &amp;lt;tt&amp;gt;IMenuPanel&amp;lt;/tt&amp;gt; pointer and client index are available.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Display&amp;lt;/tt&amp;gt; in SourcePawn.  This action is not triggered unless requested.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: A Handle to a menu panel.&lt;br /&gt;
*'''Select'''.  An item on the menu has been selected.  The item position given will be the position in the menu, rather than the key pressed (unless the menu is a raw panel).  &lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuSelect()&amp;lt;/tt&amp;gt; in C++.  A client index and item position are passed.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Select&amp;lt;/tt&amp;gt; in SourcePawn.  This action is always triggerable, whether requested or not.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: An item position.&lt;br /&gt;
*'''Cancel'''.  The menu's display to one client has been cancelled.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuCancel()&amp;lt;/tt&amp;gt; in C++.  A reason for cancellation is provided.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Cancel&amp;lt;/tt&amp;gt; in SourcePawn.  This action is always triggerable, whether requested or not.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: A menu cancellation reason code.&lt;br /&gt;
*'''End'''.  The menu's display cycle has finished; this means that the &amp;quot;Start&amp;quot; action has occurred, and either &amp;quot;Select&amp;quot; or &amp;quot;Cancel&amp;quot; has occurred thereafter.  This is typically where menu resources are removed/deleted.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuEnd()&amp;lt;/tt&amp;gt; in C++.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt; in SourcePawn.  This action is always triggered, whether requested or not.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A menu end reason code.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: If param1 was MenuEnd_Cancelled, this contains a menu cancellation reason code.&lt;br /&gt;
&lt;br /&gt;
==Panels==&lt;br /&gt;
For panels, the callback rules change.  Panels only receive two of the above callbacks, and it is guaranteed that only one of them will be called for a given display cycle.  For C++, the &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; pointer will always be &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt;.  For SourcePawn, the menu Handle will always be &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*'''Select'''.  A key has been pressed.  This can be any number and should not be considered as reliably in bounds.  For example, even if you only had 2 items in your panel, a client could trigger a key press of &amp;quot;43.&amp;quot;&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuSelect()&amp;lt;/tt&amp;gt; in C++.  A client index and key number pressed are passed.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Select&amp;lt;/tt&amp;gt; in SourcePawn.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: Number of the key pressed.&lt;br /&gt;
*'''Cancel'''.  The menu's display to one client has been cancelled.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuCancel()&amp;lt;/tt&amp;gt; in C++.  A reason for cancellation is provided.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Cancel&amp;lt;/tt&amp;gt; in SourcePawn.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: A menu cancellation reason code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
First, let's start off with a very basic menu.  We want the menu to look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Do you like apples?&lt;br /&gt;
1. Yes&lt;br /&gt;
2. No&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We'll draw this menu with both a basic Menu and a Panel to show the API differences.&lt;br /&gt;
&lt;br /&gt;
==Basic Menu==&lt;br /&gt;
First, let's write our example using the Menu building API.  For a more in-depth guide, see [[Menus Step By Step (SourceMod Scripting)]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;menu_test1&amp;quot;, Menu_Test1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public int MenuHandler1(Menu menu, MenuAction action, int param1, int param2)&lt;br /&gt;
{&lt;br /&gt;
	/* If an option was selected, tell the client about the item. */&lt;br /&gt;
	if (action == MenuAction_Select)&lt;br /&gt;
	{&lt;br /&gt;
		char info[32];&lt;br /&gt;
		bool found = menu.GetItem(param2, info, sizeof(info));&lt;br /&gt;
		PrintToConsole(param1, &amp;quot;You selected item: %d (found? %d info: %s)&amp;quot;, param2, found, info);&lt;br /&gt;
	}&lt;br /&gt;
	/* If the menu was cancelled, print a message to the server about it. */&lt;br /&gt;
	else if (action == MenuAction_Cancel)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToServer(&amp;quot;Client %d's menu was cancelled.  Reason: %d&amp;quot;, param1, param2);&lt;br /&gt;
	}&lt;br /&gt;
	/* If the menu has ended, destroy it */&lt;br /&gt;
	else if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		delete menu;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Menu_Test1(int client, int args)&lt;br /&gt;
{&lt;br /&gt;
	Menu menu = new Menu(MenuHandler1);&lt;br /&gt;
	menu.SetTitle(&amp;quot;Do you like apples?&amp;quot;);&lt;br /&gt;
	menu.AddItem(&amp;quot;yes&amp;quot;, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	menu.AddItem(&amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;);&lt;br /&gt;
	menu.ExitButton = false;&lt;br /&gt;
	menu.Display(client, 20);&lt;br /&gt;
	&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note a few very important points from this example:&lt;br /&gt;
*One of either &amp;lt;tt&amp;gt;Select&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; will always be sent to the action handler.&lt;br /&gt;
*&amp;lt;tt&amp;gt;End&amp;lt;/tt&amp;gt; will always be sent to the action handler.&lt;br /&gt;
*We destroy our Menu in the &amp;lt;tt&amp;gt;End&amp;lt;/tt&amp;gt; action, because our Handle is no longer needed.  If we had destroyed the Menu after &amp;lt;tt&amp;gt;DisplayMenu&amp;lt;/tt&amp;gt;, it would have canceled the menu's display to the client.&lt;br /&gt;
*Menus, by default, have an exit button.  We disabled this in our example.&lt;br /&gt;
*Our menu is set to display for 20 seconds.  That means that if the client does not select an item within 20 seconds, the menu will be canceled.  This is usually desired for menus that are for voting.  Note that unlike AMX Mod X, you do not need to set a timer to make sure the menu will be ended.&lt;br /&gt;
*Although we created and destroyed a new Menu Handle, we didn't need to.  It is perfectly acceptable to create the Handle once for the lifetime of the plugin.&lt;br /&gt;
&lt;br /&gt;
Our finished menu and attached console output looks like this (I selected &amp;quot;Yes&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
[[Image:Basic_menu_1.PNG]]&lt;br /&gt;
&lt;br /&gt;
==Basic Panel==&lt;br /&gt;
Now, let's rewrite our example to use Panels instead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;panel_test1&amp;quot;, Panel_Test1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public int PanelHandler1(Menu menu, MenuAction action, int param1, int param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_Select)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToConsole(param1, &amp;quot;You selected item: %d&amp;quot;, param2);&lt;br /&gt;
	} else if (action == MenuAction_Cancel) {&lt;br /&gt;
		PrintToServer(&amp;quot;Client %d's menu was cancelled.  Reason: %d&amp;quot;, param1, param2);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Panel_Test1(int client, intargs)&lt;br /&gt;
{&lt;br /&gt;
	Panel panel = new Panel();&lt;br /&gt;
	panel.SetTitle(&amp;quot;Do you like apples?&amp;quot;);&lt;br /&gt;
	panel.DrawItem(&amp;quot;Yes&amp;quot;);&lt;br /&gt;
	panel.DrawItem(&amp;quot;No&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
	panel.Send(client, PanelHandler1, 20);&lt;br /&gt;
&lt;br /&gt;
	delete panel;&lt;br /&gt;
	&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, Panels are significantly different.&lt;br /&gt;
*We can destroy the Panel as soon as we're done displaying it.  We can create the Panel once and keep re-using it, but we can destroy it at any time without interrupting client menus.&lt;br /&gt;
*The Handler function gets much less data.  Since panels are designed as a raw display, no &amp;quot;item&amp;quot; information is saved internally.  Thus, the handler function only knows whether the display was canceled or whether (and what) numerical key was pressed.&lt;br /&gt;
*There is no automation.  You cannot add more than a certain amount of selectable items to a Panel and get pagination.  Automated control functionality requires using the heftier Menu object API.&lt;br /&gt;
&lt;br /&gt;
Our finished display and console output looks like this (I selected &amp;quot;Yes&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
[[Image:Basic_panel_1.PNG]]&lt;br /&gt;
&lt;br /&gt;
==Basic Paginated Menu==&lt;br /&gt;
Now, let's take a more advanced example -- pagination. Let's say we want to build a menu for changing the map.  An easy way to do this is to read the &amp;lt;tt&amp;gt;maplist.txt&amp;lt;/tt&amp;gt; file at the start of a plugin and build a menu out of it.&lt;br /&gt;
&lt;br /&gt;
Since reading and parsing a file is an expensive operation, we only want to do this once per map.  Thus we'll build the menu in &amp;lt;tt&amp;gt;OnMapStart&amp;lt;/tt&amp;gt;, and we won't call &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt; until &amp;lt;tt&amp;gt;OnMapEnd&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Source code:&lt;br /&gt;
&amp;lt;pawn&amp;gt;Menu g_MapMenu = null;&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;menu_changemap&amp;quot;, Command_ChangeMap);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnMapStart()&lt;br /&gt;
{&lt;br /&gt;
	g_MapMenu = BuildMapMenu();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnMapEnd()&lt;br /&gt;
{&lt;br /&gt;
	if (g_MapMenu != INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		delete(g_MapMenu);&lt;br /&gt;
		g_MapMenu = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Menu BuildMapMenu()&lt;br /&gt;
{&lt;br /&gt;
	/* Open the file */&lt;br /&gt;
	File file = OpenFile(&amp;quot;maplist.txt&amp;quot;, &amp;quot;rt&amp;quot;);&lt;br /&gt;
	if (file == null)&lt;br /&gt;
	{&lt;br /&gt;
		return null;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	/* Create the menu Handle */&lt;br /&gt;
	Menu menu = new Menu(Menu_ChangeMap);&lt;br /&gt;
	char mapname[255];&lt;br /&gt;
	while (!file.EndOfFile() &amp;amp;&amp;amp; file.ReadLine(mapname, sizeof(mapname)))&lt;br /&gt;
	{&lt;br /&gt;
		if (mapname[0] == ';' || !IsCharAlpha(mapname[0]))&lt;br /&gt;
		{&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
		/* Cut off the name at any whitespace */&lt;br /&gt;
		int len = strlen(mapname);&lt;br /&gt;
		for (int i=0; i&amp;lt;len; i++)&lt;br /&gt;
		{&lt;br /&gt;
			if (IsCharSpace(mapname[i]))&lt;br /&gt;
			{&lt;br /&gt;
				mapname[i] = '\0';&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		/* Check if the map is valid */&lt;br /&gt;
		if (!IsMapValid(mapname))&lt;br /&gt;
		{&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
		/* Add it to the menu */&lt;br /&gt;
		menu.AddItem(mapname, mapname);&lt;br /&gt;
	}&lt;br /&gt;
	/* Make sure we close the file! */&lt;br /&gt;
	file.Close();&lt;br /&gt;
	&lt;br /&gt;
	/* Finally, set the title */&lt;br /&gt;
	menu.SetTitle(&amp;quot;Please select a map:&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return menu;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public int Menu_ChangeMap(Menu menu, MenuAction action, int param1, int param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_Select)&lt;br /&gt;
	{&lt;br /&gt;
		char info[32];&lt;br /&gt;
&lt;br /&gt;
		/* Get item info */&lt;br /&gt;
		bool found = menu.GetItem(param2, info, sizeof(info));&lt;br /&gt;
&lt;br /&gt;
		/* Tell the client */&lt;br /&gt;
		PrintToConsole(param1, &amp;quot;You selected item: %d (found? %d info: %s)&amp;quot;, param2, found, info);&lt;br /&gt;
&lt;br /&gt;
		/* Change the map */&lt;br /&gt;
		ServerCommand(&amp;quot;changelevel %s&amp;quot;, info);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Command_ChangeMap(int client, int args)&lt;br /&gt;
{&lt;br /&gt;
	if (g_MapMenu == null)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToConsole(client, &amp;quot;The maplist.txt file was not found!&amp;quot;);&lt;br /&gt;
		return Plugin_Handled;&lt;br /&gt;
	}	&lt;br /&gt;
	&lt;br /&gt;
	g_MapMenu.Display(client, MENU_TIME_FOREVER);&lt;br /&gt;
	&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This menu results in many selections (my &amp;lt;tt&amp;gt;maplist.txt&amp;lt;/tt&amp;gt; file had around 18 maps).  So, our final menu has 3 pages, which side by side, look like:&lt;br /&gt;
&lt;br /&gt;
[[Image:Basic_menu_2_page1.PNG]]&lt;br /&gt;
[[Image:Basic_menu_2_page2.PNG]]&lt;br /&gt;
[[Image:Basic_menu_2_page3.PNG]]&lt;br /&gt;
&lt;br /&gt;
Finally, the console output printed this before the map changed to my selection, &amp;lt;tt&amp;gt;cs_office&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;You selected item: 8 (found? 1 info: cs_office)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Displaying and designing this Menu with a raw &amp;lt;tt&amp;gt;ShowMenu&amp;lt;/tt&amp;gt; message or &amp;lt;tt&amp;gt;Panel&amp;lt;/tt&amp;gt; API would be very time consuming and difficult.  We would have to keep track of all the items in an array of hardcoded size, pages which the user is viewing, and write a function which calculated item selection based on current page and key press.  The Menu system, thankfully, handles all of this for you.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
*Control options which are not available are not drawn.  For example, in the first page, you cannot go &amp;quot;back,&amp;quot; and in the last page, you cannot go &amp;quot;next.&amp;quot;  Despite this, the menu API tries to keep each the interface as consistent as possible.  Thus, visually, each navigational control is always in the same position.  &lt;br /&gt;
*Although we specified no time out for our menu, if we had placed a timeout, flipping through pages does not affect the overall time.  For example, if we had a timeout of 20, each successive page flip would continue to detract from the overall display time, rather than restart the allowed hold time back to 20.&lt;br /&gt;
*If we had disabled the Exit button, options 8 and 9 would still be &amp;quot;Back&amp;quot; and &amp;quot;Next,&amp;quot; respectively.&lt;br /&gt;
*Again, we did not free the Menu Handle in &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;.  This is because our menu is global/static, and we don't want to rebuild it every time.&lt;br /&gt;
*These images show &amp;quot;Back.&amp;quot;  In SourceMod revisions 1011 and higher, &amp;quot;Back&amp;quot; is changed to &amp;quot;Previous,&amp;quot; and &amp;quot;Back&amp;quot; is reserved for the special &amp;quot;ExitBack&amp;quot; functionality.&lt;br /&gt;
&lt;br /&gt;
=Voting=&lt;br /&gt;
SourceMod also has API for displaying menus as votable choices to more than one client.  SourceMod automatically handles selecting an item and randomly picking a tie-breaker.  The voting API adds two new &amp;lt;tt&amp;gt;MenuAction&amp;lt;/tt&amp;gt; values, which for vote displays, are '''always''' passed:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;MenuAction_VoteStart&amp;lt;/tt&amp;gt;: Fired after &amp;lt;tt&amp;gt;MenuAction_Start&amp;lt;/tt&amp;gt; when the voting has officially started.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt;: Fired when all clients have either voted or cancelled their vote menu.  The chosen item is passed through &amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;.  This is fired '''before''' &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;.  It is important to note that it does not supercede &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;, nor is it the same thing.  Menus should never be destroyed in &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt;.  '''Note:''' This is not called if &amp;lt;tt&amp;gt;SetVoteResultCallback&amp;lt;/tt&amp;gt;() is used.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MenuAction_VoteCancel&amp;lt;/tt&amp;gt;: Fired if the menu is cancelled while the vote is in progress.  If this is called, &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt; or the result callback will not be called, but &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt; will be afterwards.  A vote cancellation reason is passed in &amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
The voting system extends overall menus with two additional properties:&lt;br /&gt;
*Only one vote can be active at a time.  You must call &amp;lt;tt&amp;gt;IsVoteInProgress&amp;lt;/tt&amp;gt;() or else &amp;lt;tt&amp;gt;VoteMenu&amp;lt;/tt&amp;gt;() will fail.&lt;br /&gt;
*If a client votes and then disconnects while the vote is still active, the client's vote will be invalidated.&lt;br /&gt;
&lt;br /&gt;
The example below shows has to create a function called &amp;lt;tt&amp;gt;DoVoteMenu()&amp;lt;/tt&amp;gt; which will ask all clients whether or not they would like to change to the given map.&lt;br /&gt;
&lt;br /&gt;
==Simple Vote==&lt;br /&gt;
&amp;lt;pawn&amp;gt;public int Handle_VoteMenu(Menu menu, MenuAction action, int param1,int param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		/* This is called after VoteEnd */&lt;br /&gt;
		delete menu;&lt;br /&gt;
	} else if (action == MenuAction_VoteEnd) {&lt;br /&gt;
		/* 0=yes, 1=no */&lt;br /&gt;
		if (param1 == 0)&lt;br /&gt;
		{&lt;br /&gt;
			char map[64];&lt;br /&gt;
			menu.GetItem(param1, map, sizeof(map));&lt;br /&gt;
			ServerCommand(&amp;quot;changelevel %s&amp;quot;, map);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void DoVoteMenu(const char[] map)&lt;br /&gt;
{&lt;br /&gt;
	if (IsVoteInProgress())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	Menu menu = new Menu(Handle_VoteMenu);&lt;br /&gt;
	menu.SetTitle(&amp;quot;Change map to: %s?&amp;quot;, map);&lt;br /&gt;
	menu.AddItem(map, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	menu.AddItem(&amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;);&lt;br /&gt;
	menu.ExitButton = false;&lt;br /&gt;
	menu.DisplayVoteToAll(20);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Advanced Voting==&lt;br /&gt;
If you need more information about voting results than &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt; gives you, you can choose to have a different callback invoked.  The new callback will provide much more information, but at a price: &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt; will not be called, and you will have to decide how to interpret the results.  This is done via &amp;lt;tt&amp;gt;SetVoteResultCallback&amp;lt;/tt&amp;gt;().&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public int Handle_VoteMenu(Menu menu, MenuAction action, int param1, int param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		/* This is called after VoteEnd */&lt;br /&gt;
		delete menu;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void Handle_VoteResults(Menu menu, &lt;br /&gt;
			int num_votes, &lt;br /&gt;
			int num_clients, &lt;br /&gt;
			const int[][] client_info, &lt;br /&gt;
			int num_items, &lt;br /&gt;
			const int[][] item_info)&lt;br /&gt;
{&lt;br /&gt;
	/* See if there were multiple winners */&lt;br /&gt;
	int winner = 0;&lt;br /&gt;
	if (num_items &amp;gt; 1&lt;br /&gt;
	    &amp;amp;&amp;amp; (item_info[0][VOTEINFO_ITEM_VOTES] == item_info[1][VOTEINFO_ITEM_VOTES]))&lt;br /&gt;
	{&lt;br /&gt;
		winner = GetRandomInt(0, 1);&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	char map[64];&lt;br /&gt;
	menu.GetItem(item_info[winner][VOTEINFO_ITEM_INDEX], map, sizeof(map));&lt;br /&gt;
	ServerCommand(&amp;quot;changelevel %s&amp;quot;, map);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void DoVoteMenu(const char[] map)&lt;br /&gt;
{&lt;br /&gt;
	if (IsVoteInProgress())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	Menu menu = new Menu(Handle_VoteMenu);&lt;br /&gt;
	menu.VoteResultCallback = Handle_VoteResults;&lt;br /&gt;
	menu.SetTitle(&amp;quot;Change map to: %s?&amp;quot;, map);&lt;br /&gt;
	menu.AddItem(map, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	menu.AddItem(&amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;);&lt;br /&gt;
	menu.ExitButton = false;&lt;br /&gt;
	menu.DisplayVoteToAll(20);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=ExitBack=&lt;br /&gt;
ExitBack is a special term to refer to the &amp;quot;ExitBack Button.&amp;quot;  This button is disabled by default.  Normally, paginated menus have no &amp;quot;Previous&amp;quot; item for the first page.  If the &amp;quot;ExitBack&amp;quot; button is enabled, the &amp;quot;Previous&amp;quot; item will show up as &amp;quot;Back.&amp;quot;  &lt;br /&gt;
&lt;br /&gt;
Selecting the &amp;quot;ExitBack&amp;quot; option will exit the menu with &amp;lt;tt&amp;gt;MenuCancel_ExitBack&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;MenuEnd_ExitBack&amp;lt;/tt&amp;gt;.  The functionality of this is the same as a normal menu exit internally; extra functionality must be defined through the callbacks.&lt;br /&gt;
&lt;br /&gt;
=Closing Menu Handles=&lt;br /&gt;
It is only necessary to close a menu handle on &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;.  The &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt; is done every time a menu is closed and no longer needed.&lt;br /&gt;
&lt;br /&gt;
=Translations=&lt;br /&gt;
It is possible to dynamically translate menus to each player through the &amp;lt;tt&amp;gt;MenuAction_DisplayItem&amp;lt;/tt&amp;gt; callback.  A special native, &amp;lt;tt&amp;gt;RedrawMenuItem&amp;lt;/tt&amp;gt;, is used to transform the text while inside the callback.  Let's redo the vote example from earlier to be translated:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public int Handle_VoteMenu(Menu menu, MenuAction action, int param1, int param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		/* This is called after VoteEnd */&lt;br /&gt;
		delete menu;&lt;br /&gt;
	} else if (action == MenuAction_VoteEnd) {&lt;br /&gt;
		/* 0=yes, 1=no */&lt;br /&gt;
		if (param1 == 0)&lt;br /&gt;
		{&lt;br /&gt;
			char map[64];&lt;br /&gt;
			menu.GetItem(param1, map, sizeof(map));&lt;br /&gt;
			ServerCommand(&amp;quot;changelevel %s&amp;quot;, map);&lt;br /&gt;
		}&lt;br /&gt;
	} else if (action == MenuAction_DisplayItem) {&lt;br /&gt;
		/* Get the display string, we'll use it as a translation phrase */&lt;br /&gt;
		char display[64];&lt;br /&gt;
		menu.GetItem(param2, &amp;quot;&amp;quot;, 0, _, display, sizeof(display));&lt;br /&gt;
&lt;br /&gt;
		/* Translate the string to the client's language */&lt;br /&gt;
		char buffer[255];&lt;br /&gt;
		Format(buffer, sizeof(buffer), &amp;quot;%T&amp;quot;, display, param1);&lt;br /&gt;
&lt;br /&gt;
		/* Override the text */&lt;br /&gt;
		return RedrawMenuItem(buffer);&lt;br /&gt;
	} else if (action == MenuAction_Display) {&lt;br /&gt;
		/* Panel Handle is the second parameter */&lt;br /&gt;
		Panel panel = view_as&amp;lt;Panel&amp;gt;(param2);&lt;br /&gt;
		&lt;br /&gt;
		/* Get the map name we're changing to from the first item */&lt;br /&gt;
		char map[64];&lt;br /&gt;
		menu.GetItem(0, map, sizeof(map));&lt;br /&gt;
		&lt;br /&gt;
		/* Translate to our phrase */&lt;br /&gt;
		char buffer[255];&lt;br /&gt;
		Format(buffer, sizeof(buffer), &amp;quot;%T&amp;quot;, &amp;quot;Change map to?&amp;quot;, client, map);&lt;br /&gt;
&lt;br /&gt;
		panel.SetTitle(buffer);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void DoVoteMenu(const char[] map)&lt;br /&gt;
{&lt;br /&gt;
	if (IsVoteInProgress())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
 &lt;br /&gt;
	Menu menu = new Menu(Handle_VoteMenu,MenuAction_DisplayItem|MenuAction_Display);&lt;br /&gt;
	menu.SetTitle(&amp;quot;Change map to: %s?&amp;quot;, map);&lt;br /&gt;
	menu.AddItem(map, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	menu.AddItem(&amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;);&lt;br /&gt;
	menu.ExitButton = false;&lt;br /&gt;
	menu.DisplayVoteToAll(20);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Development]]&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=AutoConfigs_(SourceMod_Scripting)&amp;diff=10168</id>
		<title>AutoConfigs (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=AutoConfigs_(SourceMod_Scripting)&amp;diff=10168"/>
		<updated>2016-06-06T11:09:22Z</updated>

		<summary type="html">&lt;p&gt;Shavit: Explain about FCVAR_DONTRECORD&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__FORCETOC__&lt;br /&gt;
{{Languages|AutoConfigs_(SourceMod_Scripting)}}&lt;br /&gt;
SourceMod provides a system for simple plugins to automatically generate config files which get executed on load.  This is done via the &amp;lt;tt&amp;gt;AutoExecConfig&amp;lt;/tt&amp;gt; native in &amp;lt;tt&amp;gt;scripting/include/sourcemod.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Once all configuration files are executed, &amp;lt;tt&amp;gt;OnConfigsExecuted&amp;lt;/tt&amp;gt; is called.  This forward will always be called, even if your plugin had no configs or if it was loaded late.&lt;br /&gt;
&lt;br /&gt;
=Usage=&lt;br /&gt;
There are three parameters to this call:&lt;br /&gt;
*''autoCreate'' - If true, SourceMod will dump all ConVars created by the plugin into a config file if the specified config file does not exist.&lt;br /&gt;
*''name'' - Name of the config file (excluding the .cfg extension).  If empty, the plugin's name will be used instead, with &amp;lt;tt&amp;gt;plugin.&amp;lt;/tt&amp;gt; prepended.  For example, &amp;lt;tt&amp;gt;hat.smx&amp;lt;/tt&amp;gt; becomes &amp;lt;tt&amp;gt;plugin.hat.cfg&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*''folder'' - Optionally change the folder under the main &amp;lt;tt&amp;gt;cfg&amp;lt;/tt&amp;gt; folder.  By default this is &amp;lt;tt&amp;gt;sourcemod&amp;lt;/tt&amp;gt;, and configs go in &amp;lt;tt&amp;gt;cfg/sourcemod/&amp;lt;/tt&amp;gt;.  If empty, the config will be in &amp;lt;tt&amp;gt;cfg/&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note'': It is possible to write nested folders; SourceMod will attempt to create each one.&lt;br /&gt;
&lt;br /&gt;
''Note'': If you have multiple &amp;lt;tt&amp;gt;AutoExecConfig&amp;lt;/tt&amp;gt; calls marked with '''autoCreate''' being true, the first file to be auto created will prevent any others from being created.  Thus, there is no way to automatically split cvars between multiple files.&lt;br /&gt;
&lt;br /&gt;
''Note'': If a cvar has the flag &amp;lt;tt&amp;gt;FCVAR_DONTRECORD&amp;lt;/tt&amp;gt;, it will not show up in the autoconfig. A good example of a use for this flag in a cvar, would be for the '''version''' cvar plugins need for the sake of tracking.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Example Dump=&lt;br /&gt;
The autoCreate feature exports a config file that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This file was auto-generated by SourceMod (v1.0.0.986)&lt;br /&gt;
// ConVars for plugin &amp;quot;hat.smx&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// MySQL database&lt;br /&gt;
// -&lt;br /&gt;
// Default: &amp;quot;&amp;quot;&lt;br /&gt;
mysqlk_database &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// MySQL host, use this to configure various&lt;br /&gt;
// things for your server.&lt;br /&gt;
// -&lt;br /&gt;
// Default: &amp;quot;localhost&amp;quot;&lt;br /&gt;
mysqlk_host &amp;quot;localhost&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Introduction_to_SourceMod_Plugins&amp;diff=9934</id>
		<title>Introduction to SourceMod Plugins</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Introduction_to_SourceMod_Plugins&amp;diff=9934"/>
		<updated>2015-07-06T07:53:51Z</updated>

		<summary type="html">&lt;p&gt;Shavit: Updated to the new 1.7 syntax&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This guide will give you a basic introduction to writing a [[SourceMod]] plugin.  If you are not familiar with the SourcePawn language, it is recommended that you at least briefly read the [[Introduction to SourcePawn]] article.&lt;br /&gt;
&lt;br /&gt;
For information on compiling plugins, see [[Compiling SourceMod Plugins]]. You can use [http://www.crimsoneditor.com/ Crimson Editor], [http://www.pspad.com/ PSPad], [http://www.ultraedit.com/ UltraEdit], [http://notepad-plus.sourceforge.net/uk/site.htm Notepad++], [http://www.textpad.com/ TextPad], [http://sourceforge.net/projects/pawnstudio/ Pawn Studio] or any other text editor you're comfortable with to write plugins.&lt;br /&gt;
&lt;br /&gt;
=Starting from scratch=&lt;br /&gt;
Open your favorite text editor and create a new empty file. When you have an empty file you can just start writing code using the core language, however, you will not be able to use any of SourceMod features because the compiler does not now about them. This is done deliberately so it is possible to use SourcePawn outside of SourceMod. But since we are writing a SourceMod plugin, it is a good idea to enable access to SourceMod features first. This it done using &amp;lt;tt&amp;gt;#include&amp;lt;/tt&amp;gt; directive. It tells compiler to &amp;quot;paste&amp;quot; the code from another file into yours.&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;sourcemod&amp;gt;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
How does this work? First of all, note that we enclosed file name into angle brackets. Angle brackets tell the compiler to look in the default include directory. By default, it is '''scripting/include'''. You can open it right now and see a lot of inc files there. Those are SourceMod include files that describe various functions, tags and other features available for SourceMod plugins. The files are plain-text and you are encouraged to read them. You will notice however, that there's not much code in there, certainly not enough to implement all the great features of SourceMod, so where are they? They are implemented inside a SourceMod core which is written in C++ and is compiled into binary files which end up in '''bin''' directory. So how does your SourcePawn code and SM core link together if compiler doesn't know about existence of the latter? SourceMod include files are written specially, so they say that the implementation of functions is ''somewhere else''. Compiler understands that and generate a special code that says that this function call is going outside. When SourceMod loads your plugin, it inspects these bits of code and substitutes it's own internal functions instead. This is called [http://en.wikipedia.org/wiki/Dynamic_linking dynamic linking].&lt;br /&gt;
&lt;br /&gt;
=Setting up plugin info=&lt;br /&gt;
Now that we got access to SourceMod features, it is time to setup the information that will be displayed via &amp;lt;tt&amp;gt;sm plugins list&amp;lt;/tt&amp;gt; command. No one likes unnamed plugins. To do that we are going to look inside '''sourcemod.inc''' file and see the format that information should be declared. It's always helpful to look inside SM include files to find out information you don't know. There is also an [http://docs.sourcemod.net/api/ API documentation] but it can be outdated and it only has SM core files so if your plugin are going to use any third party extension or another plugin, you will have to study inc files. So, open '''sourcemod.inc''' and scroll down a bit until you see this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Plugin public information.&lt;br /&gt;
 */&lt;br /&gt;
struct Plugin&lt;br /&gt;
{&lt;br /&gt;
   public const char[] name;		/**&amp;lt; Plugin Name */&lt;br /&gt;
   public const char[] description;	/**&amp;lt; Plugin Description */&lt;br /&gt;
   public const char[] author;		/**&amp;lt; Plugin Author */&lt;br /&gt;
   public const char[] version;		/**&amp;lt; Plugin Version */&lt;br /&gt;
   public const char[] url;			/**&amp;lt; Plugin URL */&lt;br /&gt;
};&amp;lt;/pawn&amp;gt;&lt;br /&gt;
and this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Declare this as a struct in your plugin to expose its information.&lt;br /&gt;
 * Example:&lt;br /&gt;
 *&lt;br /&gt;
 * public Plugin myinfo =&lt;br /&gt;
 * {&lt;br /&gt;
 *    name = &amp;quot;My Plugin&amp;quot;,&lt;br /&gt;
 *    //etc&lt;br /&gt;
 * };&lt;br /&gt;
 */&lt;br /&gt;
public Plugin myinfo;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It tells us that we need to create a global public variable &amp;lt;tt&amp;gt;myinfo&amp;lt;/tt&amp;gt; which must be of type &amp;lt;tt&amp;gt;Plugin&amp;lt;/tt&amp;gt; which is a struct with 5 fields which themselves are strings. It may sound complicated for a beginner but it's easy. Let's go ahead and create one:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Plugin myinfo =&lt;br /&gt;
{&lt;br /&gt;
	name = &amp;quot;My First Plugin&amp;quot;,&lt;br /&gt;
	author = &amp;quot;Me&amp;quot;,&lt;br /&gt;
	description = &amp;quot;My first plugin ever&amp;quot;,&lt;br /&gt;
	version = &amp;quot;1.0&amp;quot;,&lt;br /&gt;
	url = &amp;quot;http://www.sourcemod.net/&amp;quot;&lt;br /&gt;
};&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;public&amp;lt;/tt&amp;gt; keyword means that SourceMod will be able to directly access our variable. &amp;lt;tt&amp;gt;Plugin:&amp;lt;/tt&amp;gt; defines a type of our variable. &amp;lt;tt&amp;gt;myinfo&amp;lt;/tt&amp;gt; is, obviously, a name of our variable as required by SourceMod. You see that we initialize it right away. This is preferred way to do when filling out plugin info.&lt;br /&gt;
&lt;br /&gt;
After that the full code of your plugin should look like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public Plugin myinfo =&lt;br /&gt;
{&lt;br /&gt;
	name = &amp;quot;My First Plugin&amp;quot;,&lt;br /&gt;
	author = &amp;quot;Me&amp;quot;,&lt;br /&gt;
	description = &amp;quot;My first plugin ever&amp;quot;,&lt;br /&gt;
	version = &amp;quot;1.0&amp;quot;,&lt;br /&gt;
	url = &amp;quot;http://www.sourcemod.net/&amp;quot;&lt;br /&gt;
};&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Getting code to run=&lt;br /&gt;
We already include SourceMod features and filled up or plugin info. We now have a perfectly well formed plugin which can be compiled and loaded by SourceMod. However, there is one problem - it does nothing. You might be tempted to just start writing a code after &amp;lt;tt&amp;gt;myinfo&amp;lt;/tt&amp;gt; declaration just to see that it will not compile. SourcePawn, unlike other scripting languages like Lua, does not allow a code to be outside of functions. After reading that, you may probably want to just define some function, name it &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; probably, compile and load a plugin and see that your code never gets called. So how do we make SourceMod call our code? For this exact reason we have forwards. Forwards are function prototypes declared by one party that can be implemented by another party as a [http://en.wikipedia.org/wiki/Callback_%28computer_programming%29 callback]. When a first party starts a forward call, all parties that have matching callbacks receive the call. SourceMod declares a plenty of interesting forwards that we can implement. As you can see, forwards are the only way to get our code executed, keep that in mind. So let's implement &amp;lt;tt&amp;gt;OnPluginStart&amp;lt;/tt&amp;gt; forward. As you may have guessed, it is called when our plugin starts. To do that, we'll have to look up the declaration of &amp;lt;tt&amp;gt;OnPluginStart&amp;lt;/tt&amp;gt;. It is declared inside '''sourcemod.inc''', a file we are already familiar with, let's find it:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Called when the plugin is fully initialized and all known external references &lt;br /&gt;
 * are resolved. This is only called once in the lifetime of the plugin, and is &lt;br /&gt;
 * paired with OnPluginEnd().&lt;br /&gt;
 *&lt;br /&gt;
 * If any run-time error is thrown during this callback, the plugin will be marked &lt;br /&gt;
 * as failed.&lt;br /&gt;
 *&lt;br /&gt;
 * It is not necessary to close any handles or remove hooks in this function.  &lt;br /&gt;
 * SourceMod guarantees that plugin shutdown automatically and correctly releases &lt;br /&gt;
 * all resources.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
forward void OnPluginStart();&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Empty parentheses tells us that no arguments are passed inside this forward, &amp;lt;tt&amp;gt;@noreturn&amp;lt;/tt&amp;gt; inside documentation tells us that we don't have to return anything, pretty simple forward. So how to write a correct callback for it? Firstly, our callback must have the same name, so it's &amp;lt;tt&amp;gt;OnPluginStart&amp;lt;/tt&amp;gt;, secondly, our callback should have the same number of arguments, none in this case, and lastly, SourceMod needs to be able to call our callback so it needs to be &amp;lt;tt&amp;gt;public&amp;lt;/tt&amp;gt;. So the implementation looks like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we can write code inside curly braces and it will be executed when our plugin starts. Let's output &amp;lt;tt&amp;gt;&amp;quot;Hello world!&amp;quot;&amp;lt;/tt&amp;gt; to server console. To do that we are going to use &amp;lt;tt&amp;gt;PrintToServer&amp;lt;/tt&amp;gt; function. It is declared inside '''console.inc''', however, we don't need to manually include '''console.inc''' because it is included automatically as part of '''sourcemod.inc'''.&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Sends a message to the server console.&lt;br /&gt;
 *&lt;br /&gt;
 * @param format		Formatting rules.&lt;br /&gt;
 * @param ...			Variable number of format parameters.&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native int PrintToServer(const char[] format, any ...);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
As you can see, this is a native function. It is implemented inside SM core. Judging by it's arguments, we can see that it is a [[Format_Class_Functions_%28SourceMod_Scripting%29|format class function]]. However, we don't need any formatting right now, so let's just pass &amp;lt;tt&amp;gt;&amp;quot;Hello world!&amp;quot;&amp;lt;/tt&amp;gt; string as an only argument:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Hello world!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
That's it! The full code of your plugin should look like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public Plugin myinfo =&lt;br /&gt;
{&lt;br /&gt;
	name = &amp;quot;My First Plugin&amp;quot;,&lt;br /&gt;
	author = &amp;quot;Me&amp;quot;,&lt;br /&gt;
	description = &amp;quot;My first plugin ever&amp;quot;,&lt;br /&gt;
	version = &amp;quot;1.0&amp;quot;,&lt;br /&gt;
	url = &amp;quot;http://www.sourcemod.net/&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Hello world!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Compile and load your plugin on your server and see for yourself that the message is displayed in server console.&lt;br /&gt;
&lt;br /&gt;
=Includes=&lt;br /&gt;
Pawn requires '''include files''', much like C requires header files.  Include files list all of the structures, functions, callbacks, and tags that are available.  There are three types of include files:&lt;br /&gt;
*'''Core''' - &amp;lt;tt&amp;gt;sourcemod.inc&amp;lt;/tt&amp;gt; and anything it includes.  These are all provided by SourceMod's Core.&lt;br /&gt;
*'''Extension''' - adds a dependency against a certain extension.&lt;br /&gt;
*'''Plugin''' - adds a dependency against a certain plugin.&lt;br /&gt;
&lt;br /&gt;
Include files are loaded using the &amp;lt;tt&amp;gt;#include&amp;lt;/tt&amp;gt; compiler directive.&lt;br /&gt;
&lt;br /&gt;
=Commands=&lt;br /&gt;
Our first example will be writing a simple admin command to slap a player.  We'll continue to extend this example with more features until we have a final, complete result.&lt;br /&gt;
&lt;br /&gt;
==Declaration==&lt;br /&gt;
First, let's look at what an admin command requires.  Admin commands are registered using the [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=471&amp;amp; RegAdminCmd] function.  They require a '''name''', a '''callback function''', and '''default admin flags'''.  &lt;br /&gt;
&lt;br /&gt;
The callback function is what's invoked every time the command is used.  [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=771&amp;amp; Click here] to see its prototype.  Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegAdminCmd(&amp;quot;sm_myslap&amp;quot;, Command_MySlap, ADMFLAG_SLAY);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Command_MySlap(client, args)&lt;br /&gt;
{&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we've successfully implemented a command -- though it doesn't do anything yet.  In fact, it will say &amp;quot;Unknown command&amp;quot; if you use it!  The reason is because of the &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; tag.  Any command that you type in the console, even if it's registered by SourceMod, will be sent to the engine to be processed. Because we have not had SourceMod block this functionality yet, the engine replies with &amp;quot;Unknown command&amp;quot; because it is not a valid engine command.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Action Command_MySlap(int client, int args)&lt;br /&gt;
{&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now the command will report no error, but it still won't do anything. This is because returning &amp;quot;Plugin_Handled&amp;quot; in a command callback will prevent the engine from processing the command. The engine will never even see that the command was run. This is what you will want to do if you are registering a completely new command through SourceMod.&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
Let's decide what the command will look like.  Let's have it act like the default &amp;lt;tt&amp;gt;sm_slap&amp;lt;/tt&amp;gt; command:&lt;br /&gt;
&amp;lt;pre&amp;gt;sm_myslap &amp;lt;name|#userid&amp;gt; [damage]&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To implement this, we'll need a few steps:&lt;br /&gt;
*Get the input from the console.  For this we use [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=473&amp;amp; GetCmdArg()].&lt;br /&gt;
*Find a matching player.  For this we use [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=144&amp;amp; FindTarget()].&lt;br /&gt;
*Slap them.  For this we use [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=42&amp;amp; SlapPlayer()], which requires including &amp;lt;tt&amp;gt;sdktools&amp;lt;/tt&amp;gt;, an extension bundled with SourceMod.&lt;br /&gt;
*Respond to the admin.  For this we use [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=462&amp;amp; ReplyToCommand()].&lt;br /&gt;
&lt;br /&gt;
Full example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
#include &amp;lt;sdktools&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public Plugin myinfo =&lt;br /&gt;
{&lt;br /&gt;
	name = &amp;quot;My First Plugin&amp;quot;,&lt;br /&gt;
	author = &amp;quot;Me&amp;quot;,&lt;br /&gt;
	description = &amp;quot;My first plugin ever&amp;quot;,&lt;br /&gt;
	version = &amp;quot;1.0.0.0&amp;quot;,&lt;br /&gt;
	url = &amp;quot;http://www.sourcemod.net/&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegAdminCmd(&amp;quot;sm_myslap&amp;quot;, Command_MySlap, ADMFLAG_SLAY);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Command_MySlap(int client, int args)&lt;br /&gt;
{&lt;br /&gt;
	char arg1[32], char arg2[32];&lt;br /&gt;
	int damage;&lt;br /&gt;
&lt;br /&gt;
	/* Get the first argument */&lt;br /&gt;
	GetCmdArg(1, arg1, sizeof(arg1));&lt;br /&gt;
&lt;br /&gt;
	/* If there are 2 or more arguments, and the second argument fetch &lt;br /&gt;
	 * is successful, convert it to an integer.&lt;br /&gt;
	 */&lt;br /&gt;
	if (args &amp;gt;= 2 &amp;amp;&amp;amp; GetCmdArg(2, arg2, sizeof(arg2)))&lt;br /&gt;
	{&lt;br /&gt;
		damage = StringToInt(arg2);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* Try and find a matching player */&lt;br /&gt;
	int target = FindTarget(client, arg1);&lt;br /&gt;
	if (target == -1)&lt;br /&gt;
	{&lt;br /&gt;
		/* FindTarget() automatically replies with the &lt;br /&gt;
		 * failure reason.&lt;br /&gt;
		 */&lt;br /&gt;
		return Plugin_Handled;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	SlapPlayer(target, damage);&lt;br /&gt;
&lt;br /&gt;
	char name[MAX_NAME_LENGTH];&lt;br /&gt;
	&lt;br /&gt;
	GetClientName(target, name, sizeof(name));&lt;br /&gt;
	ReplyToCommand(client, &amp;quot;[SM] You slapped %s for %d damage!&amp;quot;, name, damage);&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more information on what %s and %d are, see [[Format Class Functions (SourceMod Scripting)|Format Class Functions]].  Note that you never need to unregister or remove your admin command.  When a plugin is unloaded, SourceMod cleans it up for you.&lt;br /&gt;
&lt;br /&gt;
=ConVars=&lt;br /&gt;
ConVars, also known as cvars, are global console variables in the Source engine.  They can have integer, float, or string values.  ConVar accessing is done through [[Handles (SourceMod Scripting)|Handles]].  Since ConVars are global, you do not need to close ConVar Handles (in fact, you cannot).&lt;br /&gt;
&lt;br /&gt;
The handy feature of ConVars is that they are easy for users to configure.  They can be placed in any .cfg file, such as &amp;lt;tt&amp;gt;server.cfg&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;sourcemod.cfg&amp;lt;/tt&amp;gt;.  To make this easier, SourceMod has an [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=607&amp;amp; AutoExecConfig()] function.  This function will automatically build a default .cfg file containing all of your cvars, annotated with comments, for users.  It is highly recommend that you call this if you have customizable ConVars.&lt;br /&gt;
&lt;br /&gt;
Let's extend your example from earlier with a new ConVar.  Our ConVar will be &amp;lt;tt&amp;gt;sm_myslap_damage&amp;lt;/tt&amp;gt; and will specify the default damage someone is slapped for if no damage is specified.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;ConVar sm_myslap_damage = null&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegAdminCmd(&amp;quot;sm_myslap&amp;quot;, Command_MySlap, ADMFLAG_SLAY);&lt;br /&gt;
&lt;br /&gt;
	sm_myslap_damage = CreateConVar(&amp;quot;sm_myslap_damage&amp;quot;, &amp;quot;5&amp;quot;, &amp;quot;Default slap damage&amp;quot;);&lt;br /&gt;
	AutoExecConfig(true, &amp;quot;plugin_myslap&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Command_MySlap(int client, int args)&lt;br /&gt;
{&lt;br /&gt;
	char arg1[32], char arg2[32];&lt;br /&gt;
	int damage = GetConVarInt(sm_myslap_damage);&lt;br /&gt;
&lt;br /&gt;
	/* The rest remains unchanged! */&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Showing Activity, Logging=&lt;br /&gt;
Almost all admin commands should log their activity, and some admin commands should show their activity to in-game clients.  This can be done via the [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=599&amp;amp; LogAction()] and [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=466&amp;amp; ShowActivity2()] functions.  The exact functionality of ShowActivity2() is determined by the &amp;lt;tt&amp;gt;sm_show_activity&amp;lt;/tt&amp;gt; cvar.&lt;br /&gt;
&lt;br /&gt;
For example, let's rewrite the last few lines of our slap command:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
	SlapPlayer(target, damage);&lt;br /&gt;
&lt;br /&gt;
	char name[MAX_NAME_LENGTH];&lt;br /&gt;
	&lt;br /&gt;
	GetClientName(target, name, sizeof(name));&lt;br /&gt;
&lt;br /&gt;
	ShowActivity2(client, &amp;quot;[SM] &amp;quot;, &amp;quot;Slapped %s for %d damage!&amp;quot;, name, damage);&lt;br /&gt;
	LogAction(client, target, &amp;quot;\&amp;quot;%L\&amp;quot; slapped \&amp;quot;%L\&amp;quot; (damage %d)&amp;quot;, client, target, damage);&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Multiple Targets=&lt;br /&gt;
To fully complete our slap demonstration, let's make it support multiple targets.  SourceMod's [[Admin_Commands_%28SourceMod%29#How_to_Target|targeting system]] is quite advanced, so using it may seem complicated at first.  &lt;br /&gt;
&lt;br /&gt;
The function we use is [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=703&amp;amp; ProcessTargetString()].  It takes in input from the console, and returns a list of matching clients.  It also returns a noun that will identify either a single client or describe a list of clients.  The idea is that each client is then processed, but the activity shown to all players is only processed once.  This reduces screen spam.&lt;br /&gt;
&lt;br /&gt;
This method of target processing is used for almost every admin command in SourceMod, and in fact FindTarget() is just a simplified version.&lt;br /&gt;
&lt;br /&gt;
Full, final example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
#include &amp;lt;sdktools&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ConVar sm_myslap_damage = INVALID_HANDLE&lt;br /&gt;
&lt;br /&gt;
public Plugin myinfo =&lt;br /&gt;
{&lt;br /&gt;
	name = &amp;quot;My First Plugin&amp;quot;,&lt;br /&gt;
	author = &amp;quot;Me&amp;quot;,&lt;br /&gt;
	description = &amp;quot;My first plugin ever&amp;quot;,&lt;br /&gt;
	version = &amp;quot;1.0.0.0&amp;quot;,&lt;br /&gt;
	url = &amp;quot;http://www.sourcemod.net/&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	LoadTranslations(&amp;quot;common.phrases&amp;quot;);&lt;br /&gt;
	RegAdminCmd(&amp;quot;sm_myslap&amp;quot;, Command_MySlap, ADMFLAG_SLAY);&lt;br /&gt;
&lt;br /&gt;
	sm_myslap_damage = CreateConVar(&amp;quot;sm_myslap_damage&amp;quot;, &amp;quot;5&amp;quot;, &amp;quot;Default slap damage&amp;quot;);&lt;br /&gt;
	AutoExecConfig(true, &amp;quot;plugin_myslap&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Command_MySlap(int client, int args)&lt;br /&gt;
{&lt;br /&gt;
	char arg1[32], char arg2[32];&lt;br /&gt;
	int damage = GetConVarInt(sm_myslap_damage);&lt;br /&gt;
&lt;br /&gt;
	/* Get the first argument */&lt;br /&gt;
	GetCmdArg(1, arg1, sizeof(arg1));&lt;br /&gt;
&lt;br /&gt;
	/* If there are 2 or more arguments, and the second argument fetch &lt;br /&gt;
	 * is successful, convert it to an integer.&lt;br /&gt;
	 */&lt;br /&gt;
	if (args &amp;gt;= 2 &amp;amp;&amp;amp; GetCmdArg(2, arg2, sizeof(arg2)))&lt;br /&gt;
	{&lt;br /&gt;
		damage = StringToInt(arg2);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * target_name - stores the noun identifying the target(s)&lt;br /&gt;
	 * target_list - array to store clients&lt;br /&gt;
	 * target_count - variable to store number of clients&lt;br /&gt;
	 * tn_is_ml - stores whether the noun must be translated&lt;br /&gt;
	 */&lt;br /&gt;
	char target_name[MAX_TARGET_LENGTH];&lt;br /&gt;
	int target_list[MAXPLAYERS], target_count;&lt;br /&gt;
	bool tn_is_ml;&lt;br /&gt;
&lt;br /&gt;
	if ((target_count = ProcessTargetString(&lt;br /&gt;
			arg1,&lt;br /&gt;
			client,&lt;br /&gt;
			target_list,&lt;br /&gt;
			MAXPLAYERS,&lt;br /&gt;
			COMMAND_FILTER_ALIVE, /* Only allow alive players */&lt;br /&gt;
			target_name,&lt;br /&gt;
			sizeof(target_name),&lt;br /&gt;
			tn_is_ml)) &amp;lt;= 0)&lt;br /&gt;
	{&lt;br /&gt;
		/* This function replies to the admin with a failure message */&lt;br /&gt;
		ReplyToTargetError(client, target_count);&lt;br /&gt;
		return Plugin_Handled;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i &amp;lt; target_count; i++)&lt;br /&gt;
	{&lt;br /&gt;
		SlapPlayer(target_list[i], damage);&lt;br /&gt;
		LogAction(client, target_list[i], &amp;quot;\&amp;quot;%L\&amp;quot; slapped \&amp;quot;%L\&amp;quot; (damage %d)&amp;quot;, client, target_list[i], damage);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (tn_is_ml)&lt;br /&gt;
	{&lt;br /&gt;
		ShowActivity2(client, &amp;quot;[SM] &amp;quot;, &amp;quot;Slapped %t for %d damage!&amp;quot;, target_name, damage);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		ShowActivity2(client, &amp;quot;[SM] &amp;quot;, &amp;quot;Slapped %s for %d damage!&amp;quot;, target_name, damage);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Client and Entity Indexes=&lt;br /&gt;
One major point of confusion with Half-Life 2 is the difference between the following things:&lt;br /&gt;
*Client index&lt;br /&gt;
*Entity index&lt;br /&gt;
*Userid&lt;br /&gt;
&lt;br /&gt;
The first answer is that clients are entities.  Thus, a client index and an entity index are the same thing.  When a SourceMod function asks for an entity index, a client index can be specified.  When a SourceMod function asks for a client index, usually it means only a client index can be specified.&lt;br /&gt;
&lt;br /&gt;
A fast way to check if an entity index is a client is checking whether it's between 1 and [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=397&amp;amp; GetMaxClients()] (inclusive).  If a server has N client slots maximum, then entities 1 through N are always reserved for clients.  Note that 0 is a valid entity index; it is the world entity (worldspawn).&lt;br /&gt;
&lt;br /&gt;
A userid, on the other hand, is completely different.  The server maintains a global &amp;quot;connection count&amp;quot; number, and it starts at 1.  Each time a client connects, the connection count is incremented, and the client receives that new number as their userid.&lt;br /&gt;
&lt;br /&gt;
For example, the first client to connect has a userid of 2.  If he exits and rejoins, his userid will be 3 (unless another client joins in-between).  Although SourceMod fires the OnClientConnected and OnClientDisconnected callbacks every map change, the server tracks players across map changes and does not change their userids or client indexes.  To see if a client really connected or disconnected, hook the  [[Generic Source Server Events#player_connect|player_connect]] and [[Generic Source Server Events#player_disconnect|player_disconnect]] events instead.&lt;br /&gt;
&lt;br /&gt;
SourceMod provides two functions for userids: [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=442&amp;amp; GetClientOfUserId()] and [http://docs.sourcemod.net/api/index.php?fastload=show&amp;amp;id=402&amp;amp; GetClientUserId()].&lt;br /&gt;
&lt;br /&gt;
=Events=&lt;br /&gt;
Events are informational notification messages passed between objects in the server.  Many are also passed from the server to the client.  They are defined in .res files under the &amp;lt;tt&amp;gt;hl2/resource&amp;lt;/tt&amp;gt; folder and &amp;lt;tt&amp;gt;resource&amp;lt;/tt&amp;gt; folders of specific mods.  For a basic listing, see [[Game Events (Source)|Source Game Events]].&lt;br /&gt;
&lt;br /&gt;
It is important to note a few concepts about events:&lt;br /&gt;
*They are almost always informational.  That is, blocking &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; will not stop a player from dying.  It may block a HUD or console message or something else minor.&lt;br /&gt;
*They almost always use userids instead of client indexes.&lt;br /&gt;
*Just because it is in a resource file does not mean it is ever called, or works the way you expect it to.  Mods are notorious at not properly documenting their event functionality.&lt;br /&gt;
&lt;br /&gt;
An example of finding when a player dies:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
   HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
   int  victim_id = GetEventInt(event, &amp;quot;userid&amp;quot;);&lt;br /&gt;
   int attacker_id = GetEventInt(event, &amp;quot;attacker&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   int victim = GetClientOfUserId(victim_id);&lt;br /&gt;
   int attacker = GetClientOfUserId(attacker_id);&lt;br /&gt;
&lt;br /&gt;
   /* CODE */&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Callback Orders and Pairing=&lt;br /&gt;
SourceMod has a number of builtin callbacks about the state of the server and plugin.  Some of these are paired in special ways which is confusing to users.&lt;br /&gt;
&lt;br /&gt;
==Pairing==&lt;br /&gt;
'''Pairing''' is SourceMod terminology.  Examples of it are:&lt;br /&gt;
*OnMapEnd() cannot be called without an OnMapStart(), and if OnMapStart() is called, it cannot be called again without an OnMapEnd().&lt;br /&gt;
*OnClientConnected(N) for a given client N will only be called once, until an OnClientDisconnected(N) for the same client N is called (which is guaranteed to happen).&lt;br /&gt;
&lt;br /&gt;
There is a formal definition of SourceMod's pairing.  For two functions X and Y, both with input A, the following conditions hold:&lt;br /&gt;
*If X is invoked with input A, it cannot be invoked again with the same input unless Y is called with input A.&lt;br /&gt;
*If X is invoked with input A, it is guaranteed that Y will, at some point, be called with input A.&lt;br /&gt;
*Y cannot be invoked with any input A unless X was called first with input A.&lt;br /&gt;
*The relationship is described as, &amp;quot;X is paired with Y,&amp;quot; and &amp;quot;Y is paired to X.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Callbacks==&lt;br /&gt;
These callbacks are listed in the order they are called, in the lifetime of a plugin and the server.&lt;br /&gt;
&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/sourcemod/AskPluginLoad2 AskPluginLoad2()] - Called once, immediately after the plugin is loaded from the disk.  This function can be used to stop a plugin from loading and return a custom error message; return APLRes_Failure and use strcopy on to replace the error string.  All CreateNative and RegPluginLibrary calls should be done here.  &lt;br /&gt;
*[https://sm.alliedmods.net/new-api/sourcemod/OnPluginStart OnPluginStart()] - Called once, after the plugin has been fully initialized and can proceed to load.  Any run-time errors in this function will cause the plugin to fail to load.  '''This is paired with OnPluginEnd()'''.&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/sourcemod/OnAllPluginsLoaded OnAllPluginsLoaded()] - Called once, after all non-late loaded plugins have called OnPluginStart.  &lt;br /&gt;
*[https://sm.alliedmods.net/new-api/sourcemod/OnMapStart OnMapStart()] - Called every time the map loads.  If the plugin is loaded late, and the map has already started, this function is called anyway after load, in order to preserve pairing.  '''This function is paired with OnMapEnd().'''&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/sourcemod/OnConfigsExecuted OnConfigsExecuted()] - Called once per map-change after  &amp;lt;tt&amp;gt;servercfgfile&amp;lt;/tt&amp;gt; (usually &amp;lt;tt&amp;gt;server.cfg&amp;lt;/tt&amp;gt;), &amp;lt;tt&amp;gt;sourcemod.cfg&amp;lt;/tt&amp;gt;, and all plugin config files have finished executing.  If a plugin is loaded after this has happened, the callback is called anyway, in order to preserve pairing.  '''This function is paired with OnMapEnd().'''&lt;br /&gt;
*At this point, most game callbacks can occur, such as events and callbacks involving clients (or other things, like OnGameFrame).&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/sourcemod/OnMapEnd OnMapEnd()] - Called when the map is about to end.  At this point, all clients are disconnected, but &amp;lt;tt&amp;gt;TIMER_NO_MAPCHANGE&amp;lt;/tt&amp;gt; timers are not yet destroyed.  '''This function is paired to OnMapStart().'''&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/sourcemod/OnPluginEnd OnPluginEnd()] - Called once, immediately before the plugin is unloaded.  '''This function is paired to OnPluginStart().'''&lt;br /&gt;
&lt;br /&gt;
==Client Callbacks==&lt;br /&gt;
These callbacks are listed in no specific order, however, their documentation holds for both fake and real clients.&lt;br /&gt;
&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/clients/OnClientConnect OnClientConnect()] - Called when a player initiates a connection.  You can block a player from connecting by returning Plugin_Stop and setting rejectmsg to an error message.&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/clients/OnClientConnected OnClientConnected()] - Called after a player connects. Signifies that the player is in-game and IsClientConnected() will return true. '''This is paired with OnClientDisconnect() for successful connections only.'''&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/clients/OnClientAuthorized OnClientAuthorized()] - Called when a player gets a Steam ID.  It is important to note that this may never be called.  It may occur any time in between OnClientConnected and OnClientPreAdminCheck/OnClientDisconnect.  Do not rely on it unless you are writing something that needs Steam IDs, and even then you should use OnClientPostAdminCheck().&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/clients/OnClientPutInServer OnClientPutInServer()] - Signifies that the player is in-game and IsClientInGame() will return true.&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/clients/OnClientPostAdminCheck OnClientPostAdminCheck()] - Called after the player is '''both authorized and in-game'''.  This is the best callback for checking administrative access after connect.&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/clients/OnClientDisconnect OnClientDisconnect()] - Called when a player's disconnection starts.  '''This is paired to OnClientConnected().'''&lt;br /&gt;
*[https://sm.alliedmods.net/new-api/clients/OnClientDisconnect_Post OnClientDisconnect_Post()] - Called when a player's disconnection ends.  '''This is paired to OnClientConnected().'''&lt;br /&gt;
&lt;br /&gt;
=Frequently Asked Questions=&lt;br /&gt;
==Are plugins reloaded every mapchange?==&lt;br /&gt;
Plugins, by default, are not reloaded on mapchange unless their timestamp changes.  This is a feature so plugin authors have more flexibility with the state of their plugins.  &lt;br /&gt;
&lt;br /&gt;
==Do I need to call CloseHandle in OnPluginEnd?==&lt;br /&gt;
No.  SourceMod automatically closes your Handles when your plugin is unloaded, in order to prevent memory errors.&lt;br /&gt;
&lt;br /&gt;
==Do I need to #include every individual .inc?==&lt;br /&gt;
No.  &amp;lt;tt&amp;gt;#include &amp;lt;sourcemod&amp;gt;&amp;lt;/tt&amp;gt; will give you 95% of the .incs.  Similarly, &amp;lt;tt&amp;gt;#include &amp;lt;sdktools&amp;gt;&amp;lt;/tt&amp;gt; includes everything starting with &amp;lt;sdktools&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Why don't some events fire?==&lt;br /&gt;
There is no guarantee that events will fire.  The event listing is not a specification, it is a list of the events that a game is capable of firing.  Whether the game actually fires them is up to Valve or the developer.&lt;br /&gt;
&lt;br /&gt;
==Do I need to CloseHandle timers?==&lt;br /&gt;
No.  In fact, doing so may cause errors.  Timers naturally die on their own unless they are infinite timers, in which case you can use KillTimer() or die gracefully by returning &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; in the callback.&lt;br /&gt;
&lt;br /&gt;
==Are clients disconnected on mapchange?==&lt;br /&gt;
All clients are fully disconnected before the map changes.  They are all reconnected after the next map starts.&lt;br /&gt;
&lt;br /&gt;
If you only want to detect when a client initially connects or leaves your server, hook the [[Generic Source Server Events#player_connect|player_connect]] or [[Generic Source Server Events#player_disconnect|player_disconnect]] events respectively.&lt;br /&gt;
&lt;br /&gt;
=Further Reading=&lt;br /&gt;
For further reading, see the &amp;quot;Scripting&amp;quot; section at the [http://docs.sourcemod.net/ SourceMod Documentation].&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=He:Adding_Admins_(SourceMod)&amp;diff=8983</id>
		<title>He:Adding Admins (SourceMod)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=He:Adding_Admins_(SourceMod)&amp;diff=8983"/>
		<updated>2013-08-23T07:41:40Z</updated>

		<summary type="html">&lt;p&gt;Shavit: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=He:Adding_Admins_(SourceMod)&amp;diff=8982</id>
		<title>He:Adding Admins (SourceMod)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=He:Adding_Admins_(SourceMod)&amp;diff=8982"/>
		<updated>2013-08-23T07:41:00Z</updated>

		<summary type="html">&lt;p&gt;Shavit: Created page with &amp;quot;__FORCETOC__ SourceMod has as very detailed and flexible administration system, and it can be quite daunting to users.  To simplify things, there are a number of &amp;quot;flags&amp;quot; which...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__FORCETOC__&lt;br /&gt;
SourceMod has as very detailed and flexible administration system, and it can be quite daunting to users.  To simplify things, there are a number of &amp;quot;flags&amp;quot; which specify generic permissions administrators can have.&lt;br /&gt;
&lt;br /&gt;
There are currently two provided ways of storing admins.  One is via the admin-flatfile.smx plugin that is enabled by default. This plugin provides two files: a simplified flat file, and another more complex tree-based file. The other way to store admins is using [[SQL Admins (SourceMod)|SQL]].&lt;br /&gt;
&lt;br /&gt;
SourceMod provides three methods of authentication:&lt;br /&gt;
*''Steam ID'' (unique to a Steam account)&lt;br /&gt;
*''IP Address'' (semi-unique to a given computer, better for LANs)&lt;br /&gt;
*''Name'' (requires a password)&lt;br /&gt;
&lt;br /&gt;
=Quick Start=&lt;br /&gt;
On the server, open [modfolder]/addons/sourcemod/configs/admins_simple.ini&lt;br /&gt;
&lt;br /&gt;
In a new line, add the following, replacing yoursteamid (use your client's console '''status''' command to retrieve your Steam ID - formatted as STEAM_n:o:p)&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;yoursteamid&amp;quot; &amp;quot;99:z&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Save the file, then type sm_reloadadmins in the server console. Connect to the server with the game client. Enter sm_admin in the client console, and then return to the game.  You should see the admin menu.&lt;br /&gt;
&lt;br /&gt;
=Levels=&lt;br /&gt;
First, let's quickly run down the provided levels:&lt;br /&gt;
:{| cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Name&lt;br /&gt;
| Flag&lt;br /&gt;
| Purpose&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| reservation&lt;br /&gt;
| a&lt;br /&gt;
| Reserved slot access.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| generic&lt;br /&gt;
| b&lt;br /&gt;
| Generic admin; required for admins.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| kick&lt;br /&gt;
| c&lt;br /&gt;
| Kick other players.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| ban&lt;br /&gt;
| d&lt;br /&gt;
| Ban other players.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| unban&lt;br /&gt;
| e&lt;br /&gt;
| Remove bans.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| slay&lt;br /&gt;
| f&lt;br /&gt;
| Slay/harm other players.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| changemap&lt;br /&gt;
| g&lt;br /&gt;
| Change the map or major gameplay features.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| cvar&lt;br /&gt;
| h&lt;br /&gt;
| Change most cvars.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| config&lt;br /&gt;
| i&lt;br /&gt;
| Execute config files.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| chat&lt;br /&gt;
| j&lt;br /&gt;
| Special chat privileges.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| vote&lt;br /&gt;
| k&lt;br /&gt;
| Start or create votes.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| password&lt;br /&gt;
| l&lt;br /&gt;
| Set a password on the server.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| rcon&lt;br /&gt;
| m&lt;br /&gt;
| Use RCON commands.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| cheats&lt;br /&gt;
| n&lt;br /&gt;
| Change sv_cheats or use cheating commands.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| root&lt;br /&gt;
| z&lt;br /&gt;
| Magically enables all flags.&lt;br /&gt;
&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom1&lt;br /&gt;
| o&lt;br /&gt;
| Custom Group 1.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom2&lt;br /&gt;
| p&lt;br /&gt;
| Custom Group 2.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom3&lt;br /&gt;
| q&lt;br /&gt;
| Custom Group 3.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom4&lt;br /&gt;
| r&lt;br /&gt;
| Custom Group 4.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom5&lt;br /&gt;
| s&lt;br /&gt;
| Custom Group 5.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| custom6&lt;br /&gt;
| t&lt;br /&gt;
| Custom Group 6.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Immunity=&lt;br /&gt;
In SourceMod, immunity is a flexible system based on ''immunity levels''.  Every admin can have an arbitrary immunity value assigned to them.  Whether an admin can target another admin depends on who has a higher immunity value.&lt;br /&gt;
&lt;br /&gt;
For example, say Admin #1 has an immunity level of &amp;quot;3&amp;quot; and Admin #2 has an immunity level of &amp;quot;10.&amp;quot;  Admin #2 can target Admin #1, but Admin #1 cannot target Admin #2.  The numbers are completely arbitrary, and they can be any number equal to or higher than 0.  Note that 0 always implies no immunity.&lt;br /&gt;
&lt;br /&gt;
By default, admins with the same immunity value can target each other.  This can be changed via &amp;lt;tt&amp;gt;sm_immunity_mode&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cfg/sourcemod.cfg&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Passwords=&lt;br /&gt;
For passwords to work, the server administrator must change the &amp;quot;PassInfoVar&amp;quot; line in &amp;lt;tt&amp;gt;addons/sourcemod/configs/core.cfg&amp;lt;/tt&amp;gt;.  For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;PassInfoVar&amp;quot;			&amp;quot;_sm1337&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, if an admin has a password, he or she must set the password via the ''setinfo'' command in the client console.   For example, using the examples above, &amp;lt;tt&amp;gt;BAILOPAN&amp;lt;/tt&amp;gt; would need to type:&lt;br /&gt;
&amp;lt;pre&amp;gt;setinfo &amp;quot;_sm1337&amp;quot; &amp;quot;Gab3n&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To automate this upon connecting to a server, you can create an &amp;quot;autoexec.cfg&amp;quot; file in your client game folder.  This will be located under &amp;lt;tt&amp;gt;SteamApps\ACCOUNT\[game]\[gameabbr]\cfg&amp;lt;/tt&amp;gt;.  For example:&lt;br /&gt;
*&amp;lt;tt&amp;gt;C:\Program Files\Steam\steamapps\bailopan\Counter-Strike Source\cstrike\cfg&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set the password upon connecting.  For Steam and IP authentication, your admin privileges will be automatically assigned if the password is correct.  For name based authentication, your password must be correct before you change your name, or else you will be kicked from the server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Simple Admins=&lt;br /&gt;
The easiest way to add administrators is through &amp;lt;tt&amp;gt;configs/admins_simple.ini&amp;lt;/tt&amp;gt;.  This is a flat file which requires two parameters per line: authentication info, and flags.  The flag string is somewhat flexible and can have the following information:&lt;br /&gt;
*An optional immunity level value, followed by a colon (':');&lt;br /&gt;
*A flag string, '''or''';&lt;br /&gt;
*A group name, preceded by an '@' symbol&lt;br /&gt;
&lt;br /&gt;
Three examples are provided:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;STEAM_0:1:16&amp;quot;		&amp;quot;bce&amp;quot;			//generic, kick, unban for this steam ID.  no immunity&lt;br /&gt;
&amp;quot;!127.0.0.1&amp;quot;		&amp;quot;5:z&amp;quot;			//all permissions for this ip, immunity level = 5&lt;br /&gt;
&amp;quot;BAILOPAN&amp;quot;		&amp;quot;abc&amp;quot;	&amp;quot;Gab3n&amp;quot;		//name BAILOPAN, password &amp;quot;Gab3n&amp;quot;: gets reservation, generic, kick&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Detailed Admins=&lt;br /&gt;
Alternatively, you can add admins via &amp;lt;tt&amp;gt;configs/admins.cfg&amp;lt;/tt&amp;gt;, a more advanced file stored in a KeyValues format.  Each admin is its own block inside a main &amp;quot;Admin&amp;quot; block. You can create and / or modify &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; files with [http://forums.alliedmods.net/showthread.php?t=81160 KVManager]. The format is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Admins&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Admin Name&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;auth&amp;quot;		&amp;quot;[steam|name|ip]&amp;quot;&lt;br /&gt;
		&amp;quot;identity&amp;quot;	&amp;quot;[unique id]&amp;quot;&lt;br /&gt;
		&amp;quot;[option1]&amp;quot;	&amp;quot;[value1]&amp;quot;&lt;br /&gt;
		&amp;quot;[option2]&amp;quot;	&amp;quot;[value2]&amp;quot;&lt;br /&gt;
		/* .... */&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available options are:&lt;br /&gt;
*&amp;lt;tt&amp;gt;auth&amp;lt;/tt&amp;gt;: Required.  Must be one of &amp;lt;tt&amp;gt;steam&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;ip&amp;lt;/tt&amp;gt; (unless there is a custom auth method), and instructs SourceMod how to interpret the &amp;lt;tt&amp;gt;identity&amp;lt;/tt&amp;gt; value.&lt;br /&gt;
*&amp;lt;tt&amp;gt;identity&amp;lt;/tt&amp;gt;: Required.  Unique value that allows SourceMod to find this admin given an authentication method and the given value.&lt;br /&gt;
*&amp;lt;tt&amp;gt;password&amp;lt;/tt&amp;gt;: Optional.  Specifies the password the user must enter (see above section on passwords).&lt;br /&gt;
*&amp;lt;tt&amp;gt;group&amp;lt;/tt&amp;gt;: Optional.  Specifies a group name the user should inherit if available.  More than one &amp;quot;group&amp;quot; line can be specified.  There should be no '@' symbol as there is no ambiguity.&lt;br /&gt;
*&amp;lt;tt&amp;gt;flags&amp;lt;/tt&amp;gt;: Optional.  Default access flags the user should receive.&lt;br /&gt;
*&amp;lt;tt&amp;gt;immunity&amp;lt;/tt&amp;gt;: Optional:  Default immunity level the user should receive.&lt;br /&gt;
&lt;br /&gt;
The admin name is optional (it can be blank).  It is not used internally and is intended for convenience usage by 3rd party tools.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;Admins&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;BAILOPAN&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;auth&amp;quot;		&amp;quot;steam&amp;quot;&lt;br /&gt;
		&amp;quot;identity&amp;quot;	&amp;quot;STEAM_0:1:2345&amp;quot;&lt;br /&gt;
		&amp;quot;flags&amp;quot;		&amp;quot;abcdef&amp;quot;&lt;br /&gt;
		&amp;quot;immunity&amp;quot;	&amp;quot;5&amp;quot;&lt;br /&gt;
		&amp;quot;group&amp;quot;		&amp;quot;Awesome Admins&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	&amp;quot;Blue Crab&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;auth&amp;quot;		&amp;quot;steam&amp;quot;&lt;br /&gt;
		&amp;quot;identity&amp;quot;	&amp;quot;STEAM_0:1:666666&amp;quot;&lt;br /&gt;
		&amp;quot;flags&amp;quot;		&amp;quot;z&amp;quot;&lt;br /&gt;
		&amp;quot;immunity&amp;quot;	&amp;quot;99&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=See Also=&lt;br /&gt;
*[[Adding Groups (SourceMod)]]&lt;br /&gt;
*[[Overriding Command Access (SourceMod)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Documentation]]&lt;/div&gt;</summary>
		<author><name>Shavit</name></author>
		
	</entry>
</feed>