<?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=TheXeon</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=TheXeon"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/TheXeon"/>
	<updated>2026-05-26T04:46:40Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10527</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10527"/>
		<updated>2018-03-10T10:32:56Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: methodmapped&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;new KeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;void BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;void DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10523</id>
		<title>Timers (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10523"/>
		<updated>2018-03-04T11:26:22Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: Change Invalid_Handle to null&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timers in [[SourceMod]] are timed events that occur once or repeatedly at a given interval.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Timers allow you to set an interval, a function to use as the event callback, and an optional Handle to pass through the callback.  This is useful for saving data asynchronously.&lt;br /&gt;
&lt;br /&gt;
All timer functions are in &amp;lt;tt&amp;gt;plugins/include/timers.inc&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
=Basic Usage=&lt;br /&gt;
==One-Time Timers==&lt;br /&gt;
One-time timers are timers that only execute once.  An example of a one-time timer might look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(5.0, LoadStuff);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action LoadStuff(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Loading stuff!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code will print &amp;quot;Loading stuff!&amp;quot; to the server console five seconds after the map loads.  The return value has no meaning for one-time timers.&lt;br /&gt;
&lt;br /&gt;
==Repeatable Timers==&lt;br /&gt;
Repeatable timers execute infinitely many times, once every interval.  Based on the return value, they either continue or cancel.&lt;br /&gt;
&lt;br /&gt;
For example, say you want to display a message five times, once every three seconds:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void someFunction()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(3.0, Timer_PrintMessageFiveTimes, _, TIMER_REPEAT);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Timer_PrintMessageFiveTimes(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	// Create a global variable visible only in the local scope (this function).&lt;br /&gt;
	static int numPrinted = 0;&lt;br /&gt;
&lt;br /&gt;
	if (numPrinted &amp;gt;= 5) &lt;br /&gt;
        {&lt;br /&gt;
		numPrinted = 0;&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	PrintToServer(&amp;quot;Warning! This is a message.&amp;quot;);&lt;br /&gt;
	numPrinted++;&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Continue;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; stops the timer, and &amp;lt;tt&amp;gt;Plugin_Continue&amp;lt;/tt&amp;gt; allows it to continue repeating.&lt;br /&gt;
&lt;br /&gt;
=Passing Data=&lt;br /&gt;
==Simple Values==&lt;br /&gt;
As mentioned earlier, timers let you pass values on to the callback function.  This value can be any type.  For example, let's say we want to print a message to a player fifteen seconds after they connect.  However, we want to cancel the timer if the player disconnects.  Implementing this is very easy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, client);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any client)&lt;br /&gt;
{&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Another example without using handles is to use either UserID or ClientSerial (which is unique to each player):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(15.0, WelcomePlayer, GetClientSerial(client)); // You could also use GetClientUserId(client)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any serial)&lt;br /&gt;
{&lt;br /&gt;
	int client = GetClientFromSerial(serial); // Validate the client serial&lt;br /&gt;
	&lt;br /&gt;
	if (client == 0) // The serial is no longer valid, the player must have disconnected&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
If you want to close or cancel a timer when a client disconnects, then use the first example with handles.&lt;br /&gt;
&lt;br /&gt;
==Handles==&lt;br /&gt;
If you want to pass a Handle as a value, you have the option of using &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt;, which will automatically call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; for you once the timer dies.  &lt;br /&gt;
&lt;br /&gt;
==Data Packs==&lt;br /&gt;
Data packs are packable structures that can be used to hold asynchronous data (data that must be saved and unpacked for later).  They are especially useful for timers, and thus there exists a helper function, called &amp;lt;tt&amp;gt;CreateDataTimer()&amp;lt;/tt&amp;gt;, which creates a timer using a data pack handle.  The handle is created and closed automatically for you.&lt;br /&gt;
&lt;br /&gt;
The above example could be rewritten as:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	DataPack pack;&lt;br /&gt;
	WelcomeTimers[client] = CreateDataTimer(15.0, WelcomePlayer, pack);&lt;br /&gt;
	pack.WriteCell(client);&lt;br /&gt;
	pack.WriteString(&amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, Handle pack)&lt;br /&gt;
{&lt;br /&gt;
	char str[128];&lt;br /&gt;
	int client;&lt;br /&gt;
&lt;br /&gt;
	/* Set to the beginning and unpack it */&lt;br /&gt;
	ResetPack(pack);&lt;br /&gt;
	client = ReadPackCell(pack);&lt;br /&gt;
	ReadPackString(pack, str, sizeof(str));&lt;br /&gt;
&lt;br /&gt;
	PrintToConsole(client, &amp;quot;%s&amp;quot;, str);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Notes=&lt;br /&gt;
==Accuracy==&lt;br /&gt;
The smallest possible interval is 0.1 seconds.  Timers have high precision (floating point) but low accuracy, as the current time is based on the in-game tick count, not the system clock.  This has two implications:&lt;br /&gt;
*If the server is paused (not ticking or hibernating), timers will not run.&lt;br /&gt;
*The server will not always tick at an exact interval.  &lt;br /&gt;
&lt;br /&gt;
For example, a 1.234 second interval timer starting from time &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt; might not tick until &amp;lt;tt&amp;gt;t+1.242&amp;lt;/tt&amp;gt; at a tickrate of 66 ticks per second.&lt;br /&gt;
&lt;br /&gt;
==Timer Death==&lt;br /&gt;
All timers are guaranteed to die either by:&lt;br /&gt;
*&amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; being called (or on plugin unload);&lt;br /&gt;
*&amp;lt;tt&amp;gt;KillTimer()&amp;lt;/tt&amp;gt; being called;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; being returned from a repeatable timer;&lt;br /&gt;
*&amp;lt;tt&amp;gt;TriggerTimer()&amp;lt;/tt&amp;gt; being called on a one-time timer;&lt;br /&gt;
*Execution of a one-time timer finishes.&lt;br /&gt;
&lt;br /&gt;
When a timer dies, if &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt; is set, the Handle will always be closed with the permissions that &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; uses by default.  Since timers cannot be cloned, there should be no ownership issues.&lt;br /&gt;
&lt;br /&gt;
==Changing Intervals==&lt;br /&gt;
The interval of a timer cannot be changed as of this writing.  The timer must be killed and a new one created.&lt;br /&gt;
&lt;br /&gt;
==AMX Mod X==&lt;br /&gt;
Unlike [[AMX Mod X]]'s &amp;lt;tt&amp;gt;set_task&amp;lt;/tt&amp;gt; function, you cannot pass arrays using &amp;lt;tt&amp;gt;CreateTimer&amp;lt;/tt&amp;gt;.  To accomplish this, you should use the data pack functionality explained above.&lt;br /&gt;
&lt;br /&gt;
Similarly, there are no flags for counted repeats (non-infinite loops) or timers based on the map start or end.  These must be done manually.&lt;br /&gt;
&lt;br /&gt;
=External Links=&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=130 On Timer Design, Part 3] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=119 On Timer Design, Part 2] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=118 On Timer Design, Part 1] (SourceMod DevLog)&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10520</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10520"/>
		<updated>2018-02-22T21:13:29Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: /* Full Deletion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;void BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;void DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10519</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10519"/>
		<updated>2018-02-22T21:13:05Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: /* Full Deletion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;void BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;void DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10518</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10518"/>
		<updated>2018-02-22T21:11:42Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: /* Full Traversal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;void BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10517</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10517"/>
		<updated>2018-02-22T21:11:22Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: /* Iterative Deletion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10516</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10516"/>
		<updated>2018-02-22T21:10:18Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: /* Simple Deletion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10515</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10515"/>
		<updated>2018-02-22T21:09:05Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: /* Iterative Lookup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10514</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10514"/>
		<updated>2018-02-22T21:08:28Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: delete on return false;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name,int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10513</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10513"/>
		<updated>2018-02-22T20:21:12Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: Delete structure after use&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		delete kv;&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name,int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10512</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10512"/>
		<updated>2018-02-22T20:20:12Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;kv.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;kv.ExportToFile&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;kv&amp;lt;/tt&amp;gt; is a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name,int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10511</id>
		<title>KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=KeyValues_(SourceMod_Scripting)&amp;diff=10511"/>
		<updated>2018-02-22T20:18:54Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: Change to newdecls&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues are simple, tree-based structures used for storing nested sections containing key/value pairs.  Detailed information on KeyValues can be seen at the [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
All KeyValues specific functions in this document are from &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''Note: While the following examples are correct code-wise, over the years they have occasionally led people to use KeyValues in cases where they really should be using a [https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 database] instead.''&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
KeyValues consist of a ''nodes'', or ''sections'', which contain pairs of keys and values.  A section looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;section&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key&amp;quot;	&amp;quot;value&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;section&amp;quot;&amp;lt;/tt&amp;gt; string denotes the section's name.  The &amp;lt;tt&amp;gt;&amp;quot;key&amp;quot;&amp;lt;/tt&amp;gt; string is the key name, and the &amp;lt;tt&amp;gt;&amp;quot;value&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; string is the value.&lt;br /&gt;
&lt;br /&gt;
KeyValues structures are created with &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  The Handle must be freed when finished in order to avoid a memory leak.&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
KeyValues can be exported and imported via KeyValues files.  These files always consist of a root node and any number of sub-keys or sub-sections.  For example, a file might look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;MyFile&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;STEAM_0:0:7&amp;quot;&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;name&amp;quot;		&amp;quot;crab&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; is a section under &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;, the root node.  &lt;br /&gt;
&lt;br /&gt;
To load KeyValues from a file, use &amp;lt;tt&amp;gt;KeyValues.ImportFromFile&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;KeyValues.ExportToFile&amp;lt;/tt&amp;gt;.  For both cases, you must already have a Handle to a KeyValues structure.&lt;br /&gt;
&lt;br /&gt;
=Traversal=&lt;br /&gt;
SourceMod provides natives for traversing over a KeyValues structure.  However, it is important to understand how this traversal works.  Internally, SourceMod keeps track of two pieces of information:&lt;br /&gt;
*The root node&lt;br /&gt;
*A traversal stack&lt;br /&gt;
&lt;br /&gt;
Since a KeyValues structure is inherently recursive (it's a tree), the ''traversal stack'' is used to save a history of each ''traversal'' made (a traversal being a recursive dive into the tree, where the current nesting level deepens by one section).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; will attempt to find a sub-key under the current section.  If it succeeds, the position in the tree has changed by moving down one level, and thus this position is pushed onto the traversal stack.  Now, operations such as &amp;lt;tt&amp;gt;kv.GetString&amp;lt;/tt&amp;gt; will use this new position.&lt;br /&gt;
&lt;br /&gt;
There are natives which change the position but do not change the traversal stack.  For example, &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; will change the current section being viewed, but there are no push/pop operations to the traversal stack.  This is because the nesting level did not change; it advances to the next section at the same level, rather than finding a section a level deeper.&lt;br /&gt;
&lt;br /&gt;
More traversal natives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; - Finds the first sub-section under the current section.  This pushes the section onto the traversal stack.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; - Clears the traversal stack so the current position is the root node.&lt;br /&gt;
&lt;br /&gt;
==Basic Lookup==&lt;br /&gt;
Let's take our &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above.  How could we retrieve the name &amp;quot;crab&amp;quot; given the Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name, int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' &amp;lt;tt&amp;gt;kv.JumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; will not accidentally close only the current level of the KeyValues structure.  It will close the entire thing.&lt;br /&gt;
&lt;br /&gt;
==Iterative Lookup==&lt;br /&gt;
Let's modify our previous example to use iteration.  This has the same functionality, but demonstrates how to browse over many sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool GetNameFromSteamID(const char[] steamid, char[] name,int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// Jump into the first subsection&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Iterate over subsections at the same nesting level&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.GetString(&amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In this example, note that &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; is an iterative function, not a traversal one.  Since it does not change the nesting level, we don't need to call &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt; to return and continue iterating.&lt;br /&gt;
&lt;br /&gt;
==Full Traversal==&lt;br /&gt;
Let's say we wanted to browse every section of a KeyValues file.  An example of this might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// You can read the section/key name by using kv.GetSectionName here.&lt;br /&gt;
&lt;br /&gt;
		if (kv.GotoFirstSubKey(false))&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a section. Browse it recursively.&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			kv.GoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			// Current key is a regular key, or an empty section.&lt;br /&gt;
			if (kv.GetDataType(NULL_STRING) != KvData_None)&lt;br /&gt;
			{&lt;br /&gt;
				// Read value of key here (use NULL_STRING as key name). You can&lt;br /&gt;
				// also get the key name by using kv.GetSectionName here.&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				// Found an empty sub section. It can be handled here if necessary.&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey(false));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will browse an entire KeyValues structure.  Note that every successful call to &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;kv.GoBack&amp;lt;/tt&amp;gt;.  This is because the former pushes onto the traversal stack.  We must pop the position off so we can continue browsing from our old position.&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;keyOnly&amp;lt;/tt&amp;gt; is set to false in both &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; so that it will jump to regular keys and not just between sections.  Because of this we also need to check if &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; succeeded moving to a regular key before we read the value. This is simply done by getting the data type of the current key.  If &amp;lt;tt&amp;gt;kv.GotoFirstSubKey&amp;lt;/tt&amp;gt; failed to move to any key (the section is empty), the cursor is still on the section, which doesn't have a data type.  If there is a data type, we've confirmed that it's a regular key.&lt;br /&gt;
&lt;br /&gt;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteKey&amp;lt;/tt&amp;gt; - Safely removes a named sub-section and any of its child sections/keys.&lt;br /&gt;
*&amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; - Safely removes the current position if possible.&lt;br /&gt;
&lt;br /&gt;
==Simple Deletion==&lt;br /&gt;
First, let's use our &amp;quot;basic lookup&amp;quot; example to delete a Steam ID section:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	kv.DeleteThis();&lt;br /&gt;
	kv.Rewind();&lt;br /&gt;
	kv.ExportToFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;kv.Rewind&amp;lt;/tt&amp;gt; so the file would be dumped from the root position, instead of the current one.&lt;br /&gt;
&lt;br /&gt;
==Iterative Deletion==&lt;br /&gt;
Likewise, let's show how our earlier iterative example could be adapted for deleting a section.  For this we can use &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt;, which deletes the current position from the previous position in the traversal stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;RemoveSteamID(const char[] steamid)&lt;br /&gt;
{&lt;br /&gt;
	KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	kv.ImportFromFile(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!kv.JumpToKey(steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		kv.GetSectionName(buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			kv.DeleteThis();&lt;br /&gt;
			delete kv;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
	} while (kv.GotoNextKey());&lt;br /&gt;
&lt;br /&gt;
	delete kv;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Now, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; has the special property that it can act as an automatic iterator.  When it deletes a key, it automatically attempts to advance to the next one, as &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; would.  If it can't find any more keys, it simply pops the traversal stack.  &lt;br /&gt;
&lt;br /&gt;
An example of deleting all SteamIDs that have blank names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DeleteAll(KeyValues kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!kv.GotoFirstSubKey())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		char name[4];&lt;br /&gt;
		kv.GetString(&amp;quot;name&amp;quot;, name, sizeof(name));&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (kv.DeleteThis() &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!kv.GotoNextKey()) {&lt;br /&gt;
			break;&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While at first this loop looks infinite, it is not.  If &amp;lt;tt&amp;gt;kv.DeleteThis&amp;lt;/tt&amp;gt; fails to find a subsequent key, it will break out of the loop.  Similarly, if &amp;lt;tt&amp;gt;kv.GotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
==KeyValue Creation==&lt;br /&gt;
This is how you would create the &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt; example from above with the KeyValue API&lt;br /&gt;
&amp;lt;pawn&amp;gt;KeyValues kv = new KeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
kv.JumpToKey(&amp;quot;STEAM_0:0:7&amp;quot;, true);&lt;br /&gt;
kv.SetString(&amp;quot;name&amp;quot;, &amp;quot;crab&amp;quot;);&lt;br /&gt;
kv.Rewind();&lt;br /&gt;
kv.ExportToFile(&amp;quot;C:\javalia.txt&amp;quot;);&lt;br /&gt;
delete kv;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Introduction_to_SourceMod_Plugins&amp;diff=10499</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=10499"/>
		<updated>2018-01-20T04:12:19Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: Grammar&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 [https://forums.alliedmods.net/showthread.php?t=259917 SPEdit], [https://www.crimsoneditor.com/ Crimson Editor], [http://www.pspad.com/ PSPad], [http://www.ultraedit.com/ UltraEdit], [https://notepad-plus-plus.org/ Notepad++], [https://www.textpad.com/ TextPad], [http://sourceforge.net/projects/pawnstudio/ Pawn Studio], [https://forums.alliedmods.net/showthread.php?t=289127 BasicPawn] 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 know 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 is done using &amp;lt;tt&amp;gt;#include&amp;lt;/tt&amp;gt; directive. It tells the 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 the compiler doesn't know about the existence of the latter? SourceMod include files are written specially, so they say that the implementation of functions is ''somewhere else''. The compiler understands that and generates 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 set up 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 is 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 the preferable way to fill 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 tell 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 the 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 [https://sm.alliedmods.net/new-api/console/RegAdminCmd 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.  [https://sm.alliedmods.net/new-api/console/ConCmd Click here] to see its prototype.  Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;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;
}&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! This is because you're not returning Plugin_Handled in your callback. Since you haven't,  SourceMod believes you didn't want the Source Engine to know the command was registered, and it handles it so. The reason SourceMod expects your function to return Plugin_Handled is because of the Action tag you put in your function's prototype. The Action tag specifies that Command_MySlap must return one of four things. See the [https://sm.alliedmods.net/new-api/core/Action Action] enumeration in the sourcemod API to learn more about these return types and when to use them.&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 [https://sm.alliedmods.net/new-api/console/GetCmdArg GetCmdArg()].&lt;br /&gt;
*Find a matching player.  For this we use [https://sm.alliedmods.net/new-api/helpers/FindTarget FindTarget()].&lt;br /&gt;
*Slap them.  For this we use [https://sm.alliedmods.net/new-api/sdktools_functions/SlapPlayer 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 [https://sm.alliedmods.net/new-api/console/ReplyToCommand 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], arg2[32];&lt;br /&gt;
	&lt;br /&gt;
	/* By default, we set damage = 0 */&lt;br /&gt;
	int damage = 0;&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, we set damage to&lt;br /&gt;
	 * what the user specified. If a damage isn't specified&lt;br /&gt;
	 * then it will stay zero. */&lt;br /&gt;
	if (args &amp;gt;= 2)&lt;br /&gt;
	{&lt;br /&gt;
		GetCmdArg(2, arg2, sizeof(arg2));&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 and returns -1 so we know not &lt;br /&gt;
		 * to continue&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 [https://sm.alliedmods.net/new-api/sourcemod/AutoExecConfig AutoExecConfig()] function.  This function will automatically build a default .cfg file containing all of your cvars, annotated with comments, for users.  It is highly recommended 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], 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 [https://sm.alliedmods.net/new-api/logging/LogAction LogAction()] and [https://sm.alliedmods.net/new-api/console/ShowActivity2 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 [https://sm.alliedmods.net/new-api/commandfilters/ProcessTargetString 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 = null;&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], 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;
=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 for 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 = event.GetInt(&amp;quot;userid&amp;quot;);&lt;br /&gt;
   int attacker_id = event.GetInt(&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 can confuse 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>TheXeon</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Introduction_to_SourceMod_Plugins&amp;diff=10498</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=10498"/>
		<updated>2018-01-20T04:01:29Z</updated>

		<summary type="html">&lt;p&gt;TheXeon: Add BasicPawn&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 [https://forums.alliedmods.net/showthread.php?t=259917 SPEdit], [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], [https://forums.alliedmods.net/showthread.php?t=289127 BasicPawn] 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 [https://sm.alliedmods.net/new-api/console/RegAdminCmd 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.  [https://sm.alliedmods.net/new-api/console/ConCmd Click here] to see its prototype.  Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;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;
}&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! This is because you're not returning Plugin_Handled in your callback. Since you haven't,  SourceMod believes you didn't want the Source Engine to know the command was registered, and it handles it so. The reason SourceMod expects your function to return Plugin_Handled is because of the Action tag you put in your function's prototype. The Action tag specifies that Command_MySlap must return one of four things. See the [https://sm.alliedmods.net/new-api/core/Action Action] enumeration in the sourcemod API to learn more about these return types and when to use them.&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 [https://sm.alliedmods.net/new-api/console/GetCmdArg GetCmdArg()].&lt;br /&gt;
*Find a matching player.  For this we use [https://sm.alliedmods.net/new-api/helpers/FindTarget FindTarget()].&lt;br /&gt;
*Slap them.  For this we use [https://sm.alliedmods.net/new-api/sdktools_functions/SlapPlayer 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 [https://sm.alliedmods.net/new-api/console/ReplyToCommand 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], arg2[32];&lt;br /&gt;
	&lt;br /&gt;
	/* By default, we set damage = 0 */&lt;br /&gt;
	int damage = 0;&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, we set damage to&lt;br /&gt;
	 * what the user specified. If a damage isn't specified&lt;br /&gt;
	 * then it will stay zero. */&lt;br /&gt;
	if (args &amp;gt;= 2)&lt;br /&gt;
	{&lt;br /&gt;
		GetCmdArg(2, arg2, sizeof(arg2));&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 and returns -1 so we know not &lt;br /&gt;
		 * to continue&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 [https://sm.alliedmods.net/new-api/sourcemod/AutoExecConfig 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], 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 [https://sm.alliedmods.net/new-api/logging/LogAction LogAction()] and [https://sm.alliedmods.net/new-api/console/ShowActivity2 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 [https://sm.alliedmods.net/new-api/commandfilters/ProcessTargetString 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 = null;&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], 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;
=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 = event.GetInt(&amp;quot;userid&amp;quot;);&lt;br /&gt;
   int attacker_id = event.GetInt(&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>TheXeon</name></author>
		
	</entry>
</feed>