<?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=V1KT0P</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=V1KT0P"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/V1KT0P"/>
	<updated>2026-05-10T07:11:12Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7918</id>
		<title>Ru:KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7918"/>
		<updated>2010-12-25T05:23:17Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: /* Deletion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues это простая древовидная структура используемая для хранения вложенных разделов состоящих из пар ключ/значение.  Детальная информация про KeyValues может быть найдена на [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
Все KeyValues функции в этом документе находятся в &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
KeyValues состоит из ''узлов'' и ''разделов'', которые содержат пары ключей и значений.  Разделы выглядят примерно так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;раздел&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;ключ&amp;quot;	&amp;quot;значение&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сторка &amp;lt;tt&amp;gt;&amp;quot;раздел&amp;quot;&amp;lt;/tt&amp;gt; является именем раздела.  Строка &amp;lt;tt&amp;gt;&amp;quot;ключ&amp;quot;&amp;lt;/tt&amp;gt; это имя ключа и строка &amp;lt;tt&amp;gt;&amp;quot;значение&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; является значением.&lt;br /&gt;
&lt;br /&gt;
KeyValues структуры создаются с помощью &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  Handle должен быть освобожден после завершения работы для устранения утечки памяти.&lt;br /&gt;
&lt;br /&gt;
=Файлы=&lt;br /&gt;
KeyValues могут быть экспортированы и импортированы с помощью KeyValues файлов.  Эти файлы всегда состоят из главного узла и множества под-ключей или подразделов.  Например файл может выглядеть вот так:&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;
В этом примере &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; это раздел под главным узлом &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Для загрузки KeyValues из файла используйте &amp;lt;tt&amp;gt;FileToKeyValues&amp;lt;/tt&amp;gt;.  Для сохранения KeyValues в файл используйте &amp;lt;tt&amp;gt;KeyValuesFromFile&amp;lt;/tt&amp;gt;.  Для обоих случае вы всегда должны иметь Handle ссылающийся на KeyValues структуру.&lt;br /&gt;
&lt;br /&gt;
=Перемещение=&lt;br /&gt;
SourceMod обеспечивает нативное перемещение по KeyValues структуре.  Однако очень важно понимать как происходит это перемещение.  Внутренне, SourceMod отслеживает из двух частей информации:&lt;br /&gt;
*Главный узел&lt;br /&gt;
*Стек перемещения&lt;br /&gt;
&lt;br /&gt;
Поскольку структура KeyValues изначально рекурсивная (это дерево), ''стек перемещения'' используется для сохранения истории каждого ''перемещения'' (перемещение начинается рекурсивно погружаться в дерево, где текущий уровень вложенности углубляется на одну секцию).  ''верх'' этого стека где все операции имеют место..  &lt;br /&gt;
&lt;br /&gt;
Например, &amp;lt;tt&amp;gt;KvJumpToKey&amp;lt;/tt&amp;gt; будет пытаться найтим под-ключ под текущим разделом.  При успехе позиция в дереве изменяется перемещением вниз на один уровень, и, следовательно, эта позиция помещается в стек перемещения.  Теперь операции такие как &amp;lt;tt&amp;gt;KvGetString&amp;lt;/tt&amp;gt; будут использовать эту новую позицию.&lt;br /&gt;
&lt;br /&gt;
Это нативные изменяют положение, но не меняют стек перемещения.  Например, &amp;lt;tt&amp;gt;KvGotoNextKey&amp;lt;/tt&amp;gt; будет менять текущий раздел перед просмотром, но это не является push/pop операциями для стека перемещения.  Это потому, что уровень вложенности не изменился; он проходит в следующий раздел на том же уровне, скорее чем найти секцию уровнем глубже.&lt;br /&gt;
&lt;br /&gt;
Больше нативных перемещений:&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvGotoFirstSubKey&amp;lt;/tt&amp;gt; - Находит первый подраздел ниже текущей позиции.  Это помещает раздел на стек перемещения.&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvGoBack&amp;lt;/tt&amp;gt; - Берет из стека перемещения (поднимается на уровень выше).&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvRewind&amp;lt;/tt&amp;gt; - Стирает из стека перемещения текущую позицию в главном узле.&lt;br /&gt;
&lt;br /&gt;
==Основной Просмотр==&lt;br /&gt;
Давайте возьмем наш пример &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;.  Как мы можем получить имя &amp;quot;crab&amp;quot; учитывая Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool:GetNameFromSteamID(const String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!KvJumpToKey(kv, steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	CloseHandle(kv);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Обратите внимание:''' &amp;lt;tt&amp;gt;KvJumpToKey&amp;lt;/tt&amp;gt; является нативным перемещением, что изменения уровней вложенности стека перемещения.  Однако &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt; не будет случайно закрывать текущий уровень структуры KeyValues.  Это закроет всю вещь.&lt;br /&gt;
&lt;br /&gt;
==Повторяющийся Просмотр==&lt;br /&gt;
Давайте модифицируер предыдущий пример для использования повторов.  Это имеет ту же функциональность, но демонстрирует, как для просмотра в течение многих разделах.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool:GetNameFromSteamID(const String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			CloseHandle(kv);&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
	return false&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Обратите внимание:''' В этом примере отметим что &amp;lt;tt&amp;gt;KvGotoNextKey&amp;lt;/tt&amp;gt; является итеративной функции, не однократное перемещение.  Так как это не меняет уровень вложенности, мы не должны вызывать &amp;lt;tt&amp;gt;KvGoBack&amp;lt;/tt&amp;gt; для возврата и продолжения итерации.&lt;br /&gt;
&lt;br /&gt;
==Полное Перемещение==&lt;br /&gt;
Например мы хотим просмотреть каждую секцию файла KeyValues.  Пример как это может выглядеть:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (KvGotoFirstSubKey(kv))&lt;br /&gt;
		{&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			KvGoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Эта функция будет просматривать всю структуру KeyValues.  Обратите внимаеие, что каждый успешный вызов &amp;lt;tt&amp;gt;KvGotoFirstSubKey&amp;lt;/tt&amp;gt; сопровождается вызовом &amp;lt;tt&amp;gt;KvGoBack&amp;lt;/tt&amp;gt;.  Это потому, что первый помещается в стек перемещения.  Мы должны взять позицию для того, чтоб могли продолжить просмотр с нашей старой позиции.&lt;br /&gt;
&lt;br /&gt;
=Удаление=&lt;br /&gt;
Есть два пути для удаления секции из структуры KeyValues:&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvDeleteKey&amp;lt;/tt&amp;gt; - Безопасное удаление имени подраздела и все дочерние секции/ключи.&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvDeleteThis&amp;lt;/tt&amp;gt; - Безопасное удаление текущей позиции, если это возможно.&lt;br /&gt;
&lt;br /&gt;
==Простое Удаление==&lt;br /&gt;
Для начала используем наш пример &amp;quot;базовый просмотр&amp;quot; для удаления секции Steam ID:&lt;br /&gt;
&amp;lt;pawn&amp;gt;RemoveSteamID(const String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
	KvDeleteKey(kv, steamid)&lt;br /&gt;
	KvRewind(kv)&lt;br /&gt;
	KeyValuesToFile(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Обратите внимание:''' Мы вызвали &amp;lt;tt&amp;gt;KvRewind&amp;lt;/tt&amp;gt; так файл будет сбрасываться с корневой позиции, вместо текущей.  &lt;br /&gt;
&lt;br /&gt;
==Повторяющееся Удаление==&lt;br /&gt;
Кроме того давайте покажем как ранее повторяющийся пример может быть адаптирован для удаления раздела.  Для этого мы используем &amp;lt;tt&amp;gt;KvDeleteThis&amp;lt;/tt&amp;gt;, который удаляет текущую позицию из предыдущей позиции в стеке перемещения.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;RemoveSteamID(const String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255]&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvDeleteThis(kv)&lt;br /&gt;
			CloseHandle(kv)&lt;br /&gt;
			return&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv))&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Полное Удаление==&lt;br /&gt;
Наконец давайте посмотрим как удалить все (или некоторые) ключи.  &amp;lt;tt&amp;gt;KvDeleteThis&amp;lt;/tt&amp;gt; как особое свойство которое может действовать в качестве автоматического итератора.  Когда удаляется ключ автоматически переходим к следующему, как если бы вызвали &amp;lt;tt&amp;gt;KvGotoNextKey&amp;lt;/tt&amp;gt;.  Если больше нет ключей просто берет стек перемещения.  &lt;br /&gt;
&lt;br /&gt;
Пример удаление всех SteamID-ов содержащие пустые имена:&lt;br /&gt;
&amp;lt;pawn&amp;gt;DeleteAll(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		decl String:name[4]&lt;br /&gt;
		KvGetString(kv, name, sizeof(name))&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (KvDeleteThis(kv) &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!KvGotoNextKey(kv)) {&lt;br /&gt;
			break&lt;br /&gt;
		}	&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Хотя это и выглядет как бесконечный цикл, это не так.  Как только &amp;lt;tt&amp;gt;KvDeleteThis&amp;lt;/tt&amp;gt; вернет неудачу при нахождении ключа, произойдет разрыв цекла.  Аналогично, если &amp;lt;tt&amp;gt;KvGotoNextKey&amp;lt;/tt&amp;gt; вернет неудачу, цикл закончится.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7917</id>
		<title>Ru:KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7917"/>
		<updated>2010-12-25T05:16:17Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: /* Повторяющийся просмотр */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues это простая древовидная структура используемая для хранения вложенных разделов состоящих из пар ключ/значение.  Детальная информация про KeyValues может быть найдена на [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
Все KeyValues функции в этом документе находятся в &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
KeyValues состоит из ''узлов'' и ''разделов'', которые содержат пары ключей и значений.  Разделы выглядят примерно так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;раздел&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;ключ&amp;quot;	&amp;quot;значение&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сторка &amp;lt;tt&amp;gt;&amp;quot;раздел&amp;quot;&amp;lt;/tt&amp;gt; является именем раздела.  Строка &amp;lt;tt&amp;gt;&amp;quot;ключ&amp;quot;&amp;lt;/tt&amp;gt; это имя ключа и строка &amp;lt;tt&amp;gt;&amp;quot;значение&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; является значением.&lt;br /&gt;
&lt;br /&gt;
KeyValues структуры создаются с помощью &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  Handle должен быть освобожден после завершения работы для устранения утечки памяти.&lt;br /&gt;
&lt;br /&gt;
=Файлы=&lt;br /&gt;
KeyValues могут быть экспортированы и импортированы с помощью KeyValues файлов.  Эти файлы всегда состоят из главного узла и множества под-ключей или подразделов.  Например файл может выглядеть вот так:&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;
В этом примере &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; это раздел под главным узлом &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Для загрузки KeyValues из файла используйте &amp;lt;tt&amp;gt;FileToKeyValues&amp;lt;/tt&amp;gt;.  Для сохранения KeyValues в файл используйте &amp;lt;tt&amp;gt;KeyValuesFromFile&amp;lt;/tt&amp;gt;.  Для обоих случае вы всегда должны иметь Handle ссылающийся на KeyValues структуру.&lt;br /&gt;
&lt;br /&gt;
=Перемещение=&lt;br /&gt;
SourceMod обеспечивает нативное перемещение по KeyValues структуре.  Однако очень важно понимать как происходит это перемещение.  Внутренне, SourceMod отслеживает из двух частей информации:&lt;br /&gt;
*Главный узел&lt;br /&gt;
*Стек перемещения&lt;br /&gt;
&lt;br /&gt;
Поскольку структура KeyValues изначально рекурсивная (это дерево), ''стек перемещения'' используется для сохранения истории каждого ''перемещения'' (перемещение начинается рекурсивно погружаться в дерево, где текущий уровень вложенности углубляется на одну секцию).  ''верх'' этого стека где все операции имеют место..  &lt;br /&gt;
&lt;br /&gt;
Например, &amp;lt;tt&amp;gt;KvJumpToKey&amp;lt;/tt&amp;gt; будет пытаться найтим под-ключ под текущим разделом.  При успехе позиция в дереве изменяется перемещением вниз на один уровень, и, следовательно, эта позиция помещается в стек перемещения.  Теперь операции такие как &amp;lt;tt&amp;gt;KvGetString&amp;lt;/tt&amp;gt; будут использовать эту новую позицию.&lt;br /&gt;
&lt;br /&gt;
Это нативные изменяют положение, но не меняют стек перемещения.  Например, &amp;lt;tt&amp;gt;KvGotoNextKey&amp;lt;/tt&amp;gt; будет менять текущий раздел перед просмотром, но это не является push/pop операциями для стека перемещения.  Это потому, что уровень вложенности не изменился; он проходит в следующий раздел на том же уровне, скорее чем найти секцию уровнем глубже.&lt;br /&gt;
&lt;br /&gt;
Больше нативных перемещений:&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvGotoFirstSubKey&amp;lt;/tt&amp;gt; - Находит первый подраздел ниже текущей позиции.  Это помещает раздел на стек перемещения.&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvGoBack&amp;lt;/tt&amp;gt; - Берет из стека перемещения (поднимается на уровень выше).&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvRewind&amp;lt;/tt&amp;gt; - Стирает из стека перемещения текущую позицию в главном узле.&lt;br /&gt;
&lt;br /&gt;
==Основной Просмотр==&lt;br /&gt;
Давайте возьмем наш пример &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;.  Как мы можем получить имя &amp;quot;crab&amp;quot; учитывая Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool:GetNameFromSteamID(const String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!KvJumpToKey(kv, steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	CloseHandle(kv);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Обратите внимание:''' &amp;lt;tt&amp;gt;KvJumpToKey&amp;lt;/tt&amp;gt; является нативным перемещением, что изменения уровней вложенности стека перемещения.  Однако &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt; не будет случайно закрывать текущий уровень структуры KeyValues.  Это закроет всю вещь.&lt;br /&gt;
&lt;br /&gt;
==Повторяющийся Просмотр==&lt;br /&gt;
Давайте модифицируер предыдущий пример для использования повторов.  Это имеет ту же функциональность, но демонстрирует, как для просмотра в течение многих разделах.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool:GetNameFromSteamID(const String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			CloseHandle(kv);&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
	return false&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Обратите внимание:''' В этом примере отметим что &amp;lt;tt&amp;gt;KvGotoNextKey&amp;lt;/tt&amp;gt; является итеративной функции, не однократное перемещение.  Так как это не меняет уровень вложенности, мы не должны вызывать &amp;lt;tt&amp;gt;KvGoBack&amp;lt;/tt&amp;gt; для возврата и продолжения итерации.&lt;br /&gt;
&lt;br /&gt;
==Полное Перемещение==&lt;br /&gt;
Например мы хотим просмотреть каждую секцию файла KeyValues.  Пример как это может выглядеть:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (KvGotoFirstSubKey(kv))&lt;br /&gt;
		{&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			KvGoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Эта функция будет просматривать всю структуру KeyValues.  Обратите внимаеие, что каждый успешный вызов &amp;lt;tt&amp;gt;KvGotoFirstSubKey&amp;lt;/tt&amp;gt; сопровождается вызовом &amp;lt;tt&amp;gt;KvGoBack&amp;lt;/tt&amp;gt;.  Это потому, что первый помещается в стек перемещения.  Мы должны взять позицию для того, чтоб могли продолжить просмотр с нашей старой позиции.&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;KvDeleteKey&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;KvDeleteThis&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;RemoveSteamID(const String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
	KvDeleteKey(kv, steamid)&lt;br /&gt;
	KvRewind(kv)&lt;br /&gt;
	KeyValuesToFile(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;KvRewind&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;KvDeleteThis&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 String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255]&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvDeleteThis(kv)&lt;br /&gt;
			CloseHandle(kv)&lt;br /&gt;
			return&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv))&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Lastly, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;KvDeleteThis&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;KvGotoNextKey&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(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		decl String:name[4]&lt;br /&gt;
		KvGetString(kv, name, sizeof(name))&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (KvDeleteThis(kv) &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!KvGotoNextKey(kv)) {&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;KvDeleteThis&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;KvGotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7916</id>
		<title>Ru:KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7916"/>
		<updated>2010-12-25T05:11:15Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: /* Перемещение */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues это простая древовидная структура используемая для хранения вложенных разделов состоящих из пар ключ/значение.  Детальная информация про KeyValues может быть найдена на [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
Все KeyValues функции в этом документе находятся в &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
KeyValues состоит из ''узлов'' и ''разделов'', которые содержат пары ключей и значений.  Разделы выглядят примерно так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;раздел&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;ключ&amp;quot;	&amp;quot;значение&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сторка &amp;lt;tt&amp;gt;&amp;quot;раздел&amp;quot;&amp;lt;/tt&amp;gt; является именем раздела.  Строка &amp;lt;tt&amp;gt;&amp;quot;ключ&amp;quot;&amp;lt;/tt&amp;gt; это имя ключа и строка &amp;lt;tt&amp;gt;&amp;quot;значение&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; является значением.&lt;br /&gt;
&lt;br /&gt;
KeyValues структуры создаются с помощью &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  Handle должен быть освобожден после завершения работы для устранения утечки памяти.&lt;br /&gt;
&lt;br /&gt;
=Файлы=&lt;br /&gt;
KeyValues могут быть экспортированы и импортированы с помощью KeyValues файлов.  Эти файлы всегда состоят из главного узла и множества под-ключей или подразделов.  Например файл может выглядеть вот так:&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;
В этом примере &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; это раздел под главным узлом &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Для загрузки KeyValues из файла используйте &amp;lt;tt&amp;gt;FileToKeyValues&amp;lt;/tt&amp;gt;.  Для сохранения KeyValues в файл используйте &amp;lt;tt&amp;gt;KeyValuesFromFile&amp;lt;/tt&amp;gt;.  Для обоих случае вы всегда должны иметь Handle ссылающийся на KeyValues структуру.&lt;br /&gt;
&lt;br /&gt;
=Перемещение=&lt;br /&gt;
SourceMod обеспечивает нативное перемещение по KeyValues структуре.  Однако очень важно понимать как происходит это перемещение.  Внутренне, SourceMod отслеживает из двух частей информации:&lt;br /&gt;
*Главный узел&lt;br /&gt;
*Стек перемещения&lt;br /&gt;
&lt;br /&gt;
Поскольку структура KeyValues изначально рекурсивная (это дерево), ''стек перемещения'' используется для сохранения истории каждого ''перемещения'' (перемещение начинается рекурсивно погружаться в дерево, где текущий уровень вложенности углубляется на одну секцию).  ''верх'' этого стека где все операции имеют место..  &lt;br /&gt;
&lt;br /&gt;
Например, &amp;lt;tt&amp;gt;KvJumpToKey&amp;lt;/tt&amp;gt; будет пытаться найтим под-ключ под текущим разделом.  При успехе позиция в дереве изменяется перемещением вниз на один уровень, и, следовательно, эта позиция помещается в стек перемещения.  Теперь операции такие как &amp;lt;tt&amp;gt;KvGetString&amp;lt;/tt&amp;gt; будут использовать эту новую позицию.&lt;br /&gt;
&lt;br /&gt;
Это нативные изменяют положение, но не меняют стек перемещения.  Например, &amp;lt;tt&amp;gt;KvGotoNextKey&amp;lt;/tt&amp;gt; будет менять текущий раздел перед просмотром, но это не является push/pop операциями для стека перемещения.  Это потому, что уровень вложенности не изменился; он проходит в следующий раздел на том же уровне, скорее чем найти секцию уровнем глубже.&lt;br /&gt;
&lt;br /&gt;
Больше нативных перемещений:&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvGotoFirstSubKey&amp;lt;/tt&amp;gt; - Находит первый подраздел ниже текущей позиции.  Это помещает раздел на стек перемещения.&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvGoBack&amp;lt;/tt&amp;gt; - Берет из стека перемещения (поднимается на уровень выше).&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvRewind&amp;lt;/tt&amp;gt; - Стирает из стека перемещения текущую позицию в главном узле.&lt;br /&gt;
&lt;br /&gt;
==Основной Просмотр==&lt;br /&gt;
Давайте возьмем наш пример &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;.  Как мы можем получить имя &amp;quot;crab&amp;quot; учитывая Steam ID?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool:GetNameFromSteamID(const String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!KvJumpToKey(kv, steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	CloseHandle(kv);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Обратите внимание:''' &amp;lt;tt&amp;gt;KvJumpToKey&amp;lt;/tt&amp;gt; является нативным перемещением, что изменения уровней вложенности стека перемещения.  Однако &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt; не будет случайно закрывать текущий уровень структуры KeyValues.  Это закроет всю вещь.&lt;br /&gt;
&lt;br /&gt;
==Повторяющийся просмотр==&lt;br /&gt;
Давайте модифицируер предыдущий пример для использования повторов.  Это имеет ту же функциональность, но демонстрирует, как для просмотра в течение многих разделах.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;bool:GetNameFromSteamID(const String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			CloseHandle(kv);&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
	return false&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Обратите внимание:''' В этом примере отметим что &amp;lt;tt&amp;gt;KvGotoNextKey&amp;lt;/tt&amp;gt; является итеративной функции, не однократное перемещение.  Так как это не меняет уровень вложенности, мы не должны вызывать &amp;lt;tt&amp;gt;KvGoBack&amp;lt;/tt&amp;gt; для возврата и продолжения итерации.&lt;br /&gt;
&lt;br /&gt;
==Полное Перемещение==&lt;br /&gt;
Например мы хотим просмотреть каждую секцию файла KeyValues.  Пример как это может выглядеть:&lt;br /&gt;
&amp;lt;pawn&amp;gt;BrowseKeyValues(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (KvGotoFirstSubKey(kv))&lt;br /&gt;
		{&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			KvGoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Эта функция будет просматривать всю структуру KeyValues.  Обратите внимаеие, что каждый успешный вызов &amp;lt;tt&amp;gt;KvGotoFirstSubKey&amp;lt;/tt&amp;gt; сопровождается вызовом &amp;lt;tt&amp;gt;KvGoBack&amp;lt;/tt&amp;gt;.  Это потому, что первый помещается в стек перемещения.  Мы должны взять позицию для того, чтоб могли продолжить просмотр с нашей старой позиции.&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;KvDeleteKey&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;KvDeleteThis&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;RemoveSteamID(const String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
	KvDeleteKey(kv, steamid)&lt;br /&gt;
	KvRewind(kv)&lt;br /&gt;
	KeyValuesToFile(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;KvRewind&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;KvDeleteThis&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 String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255]&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvDeleteThis(kv)&lt;br /&gt;
			CloseHandle(kv)&lt;br /&gt;
			return&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv))&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Lastly, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;KvDeleteThis&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;KvGotoNextKey&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(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		decl String:name[4]&lt;br /&gt;
		KvGetString(kv, name, sizeof(name))&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (KvDeleteThis(kv) &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!KvGotoNextKey(kv)) {&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;KvDeleteThis&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;KvGotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7915</id>
		<title>Ru:KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7915"/>
		<updated>2010-12-25T04:48:25Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: /* Перемещение */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues это простая древовидная структура используемая для хранения вложенных разделов состоящих из пар ключ/значение.  Детальная информация про KeyValues может быть найдена на [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
Все KeyValues функции в этом документе находятся в &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
KeyValues состоит из ''узлов'' и ''разделов'', которые содержат пары ключей и значений.  Разделы выглядят примерно так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;раздел&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;ключ&amp;quot;	&amp;quot;значение&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сторка &amp;lt;tt&amp;gt;&amp;quot;раздел&amp;quot;&amp;lt;/tt&amp;gt; является именем раздела.  Строка &amp;lt;tt&amp;gt;&amp;quot;ключ&amp;quot;&amp;lt;/tt&amp;gt; это имя ключа и строка &amp;lt;tt&amp;gt;&amp;quot;значение&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; является значением.&lt;br /&gt;
&lt;br /&gt;
KeyValues структуры создаются с помощью &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  Handle должен быть освобожден после завершения работы для устранения утечки памяти.&lt;br /&gt;
&lt;br /&gt;
=Файлы=&lt;br /&gt;
KeyValues могут быть экспортированы и импортированы с помощью KeyValues файлов.  Эти файлы всегда состоят из главного узла и множества под-ключей или подразделов.  Например файл может выглядеть вот так:&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;
В этом примере &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; это раздел под главным узлом &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Для загрузки KeyValues из файла используйте &amp;lt;tt&amp;gt;FileToKeyValues&amp;lt;/tt&amp;gt;.  Для сохранения KeyValues в файл используйте &amp;lt;tt&amp;gt;KeyValuesFromFile&amp;lt;/tt&amp;gt;.  Для обоих случае вы всегда должны иметь Handle ссылающийся на KeyValues структуру.&lt;br /&gt;
&lt;br /&gt;
=Перемещение=&lt;br /&gt;
SourceMod обеспечивает нативное перемещение по KeyValues структуре.  Однако очень важно понимать как происходит это перемещение.  Внутренне, SourceMod отслеживает из двух частей информации:&lt;br /&gt;
*Главный узел&lt;br /&gt;
*Стек перемещения&lt;br /&gt;
&lt;br /&gt;
Поскольку структура KeyValues изначально рекурсивная (это дерево), ''стек перемещения'' используется для сохранения истории каждого ''перемещения'' (перемещение начинается рекурсивно погружаться в дерево, где текущий уровень вложенности углубляется на одну секцию).  ''верх'' этого стека где все операции имеют место..  &lt;br /&gt;
&lt;br /&gt;
Например, &amp;lt;tt&amp;gt;KvJumpToKey&amp;lt;/tt&amp;gt; будет пытаться найтим под-ключ под текущим разделом.  При успехе позиция в дереве изменяется перемещением вниз на один уровень, и, следовательно, эта позиция помещается в стек перемещения.  Теперь операции такие как &amp;lt;tt&amp;gt;KvGetString&amp;lt;/tt&amp;gt; будут использовать эту новую позицию.&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;KvGotoNextKey&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;KvGotoFirstSubKey&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;KvGoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvRewind&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 String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!KvJumpToKey(kv, steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	CloseHandle(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;KvJumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;CloseHandle&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 String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			CloseHandle(kv);&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(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;KvGotoNextKey&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;KvGoBack&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(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (KvGotoFirstSubKey(kv))&lt;br /&gt;
		{&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			KvGoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&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;KvGotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;KvGoBack&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;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvDeleteKey&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;KvDeleteThis&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;RemoveSteamID(const String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
	KvDeleteKey(kv, steamid)&lt;br /&gt;
	KvRewind(kv)&lt;br /&gt;
	KeyValuesToFile(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;KvRewind&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;KvDeleteThis&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 String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255]&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvDeleteThis(kv)&lt;br /&gt;
			CloseHandle(kv)&lt;br /&gt;
			return&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv))&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Lastly, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;KvDeleteThis&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;KvGotoNextKey&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(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		decl String:name[4]&lt;br /&gt;
		KvGetString(kv, name, sizeof(name))&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (KvDeleteThis(kv) &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!KvGotoNextKey(kv)) {&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;KvDeleteThis&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;KvGotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7914</id>
		<title>Ru:KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7914"/>
		<updated>2010-12-25T04:44:20Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;KeyValues это простая древовидная структура используемая для хранения вложенных разделов состоящих из пар ключ/значение.  Детальная информация про KeyValues может быть найдена на [http://developer.valvesoftware.com/wiki/KeyValues_class Valve Developer Wiki].  &lt;br /&gt;
&lt;br /&gt;
Все KeyValues функции в этом документе находятся в &amp;lt;tt&amp;gt;public/include/keyvalues.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
KeyValues состоит из ''узлов'' и ''разделов'', которые содержат пары ключей и значений.  Разделы выглядят примерно так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;раздел&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;ключ&amp;quot;	&amp;quot;значение&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сторка &amp;lt;tt&amp;gt;&amp;quot;раздел&amp;quot;&amp;lt;/tt&amp;gt; является именем раздела.  Строка &amp;lt;tt&amp;gt;&amp;quot;ключ&amp;quot;&amp;lt;/tt&amp;gt; это имя ключа и строка &amp;lt;tt&amp;gt;&amp;quot;значение&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; является значением.&lt;br /&gt;
&lt;br /&gt;
KeyValues структуры создаются с помощью &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  Handle должен быть освобожден после завершения работы для устранения утечки памяти.&lt;br /&gt;
&lt;br /&gt;
=Файлы=&lt;br /&gt;
KeyValues могут быть экспортированы и импортированы с помощью KeyValues файлов.  Эти файлы всегда состоят из главного узла и множества под-ключей или подразделов.  Например файл может выглядеть вот так:&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;
В этом примере &amp;lt;tt&amp;gt;STEAM_0:0:7&amp;lt;/tt&amp;gt; это раздел под главным узлом &amp;lt;tt&amp;gt;MyFile&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Для загрузки KeyValues из файла используйте &amp;lt;tt&amp;gt;FileToKeyValues&amp;lt;/tt&amp;gt;.  Для сохранения KeyValues в файл используйте &amp;lt;tt&amp;gt;KeyValuesFromFile&amp;lt;/tt&amp;gt;.  Для обоих случае вы всегда должны иметь Handle ссылающийся на KeyValues структуру.&lt;br /&gt;
&lt;br /&gt;
=Перемещение=&lt;br /&gt;
SourceMod обеспечивает нативное перемещение по KeyValues структуре.  Однако очень важно понимать как происходит это перемещение.  Внутренне, SourceMod отслеживает из двух частей информации:&lt;br /&gt;
*Главный узел&lt;br /&gt;
*Стек перемещения&lt;br /&gt;
&lt;br /&gt;
Поскольку структура KeyValues изначально рекурсивная (это дерево), ''стек перемещения'' используется для сохранения истории каждого ''перемещения'' (перемещение начинается рекурсивно погружаться в дерево, где текущий уровень вложенности углубляется на одну секцию).  The ''top'' of this stack is where all operations take place.  &lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;KvJumpToKey&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;KvGetString&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;KvGotoNextKey&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;KvGotoFirstSubKey&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;KvGoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvRewind&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 String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!KvJumpToKey(kv, steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	CloseHandle(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;KvJumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;CloseHandle&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 String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			CloseHandle(kv);&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(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;KvGotoNextKey&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;KvGoBack&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(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (KvGotoFirstSubKey(kv))&lt;br /&gt;
		{&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			KvGoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&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;KvGotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;KvGoBack&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;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvDeleteKey&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;KvDeleteThis&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;RemoveSteamID(const String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
	KvDeleteKey(kv, steamid)&lt;br /&gt;
	KvRewind(kv)&lt;br /&gt;
	KeyValuesToFile(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;KvRewind&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;KvDeleteThis&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 String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255]&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvDeleteThis(kv)&lt;br /&gt;
			CloseHandle(kv)&lt;br /&gt;
			return&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv))&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Lastly, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;KvDeleteThis&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;KvGotoNextKey&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(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		decl String:name[4]&lt;br /&gt;
		KvGetString(kv, name, sizeof(name))&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (KvDeleteThis(kv) &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!KvGotoNextKey(kv)) {&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;KvDeleteThis&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;KvGotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7913</id>
		<title>Ru:KeyValues (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:KeyValues_(SourceMod_Scripting)&amp;diff=7913"/>
		<updated>2010-12-25T04:27:29Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: /* Introduction */&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;
=Введение=&lt;br /&gt;
KeyValues состоит из ''узлов'' и ''разделов'', которые содержат пары ключей и значений.  Разделы выглядят примерно так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;раздел&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;ключ&amp;quot;	&amp;quot;значение&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сторка &amp;lt;tt&amp;gt;&amp;quot;раздел&amp;quot;&amp;lt;/tt&amp;gt; является именем раздела.  Строка &amp;lt;tt&amp;gt;&amp;quot;ключ&amp;quot;&amp;lt;/tt&amp;gt; это имя ключа и строка &amp;lt;tt&amp;gt;&amp;quot;значение&amp;quot;&amp;lt;/tt&amp;gt;&amp;quot; является значением.&lt;br /&gt;
&lt;br /&gt;
KeyValues структуры создаются с помощью &amp;lt;tt&amp;gt;CreateKeyValues()&amp;lt;/tt&amp;gt;.  Handle должен быть освобожден после завершения работы для устранения утечки памяти.&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;FileToKeyValues&amp;lt;/tt&amp;gt;  To save KeyValues to a file, use &amp;lt;tt&amp;gt;KeyValuesFromFile&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;KvJumpToKey&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;KvGetString&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;KvGotoNextKey&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;KvGotoFirstSubKey&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;KvGoBack&amp;lt;/tt&amp;gt; - Pops the traversal stack (moves up one level).&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvRewind&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 String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
	if (!KvJumpToKey(kv, steamid))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
	KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
	CloseHandle(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;KvJumpToKey&amp;lt;/tt&amp;gt; is a traversal native that changes the nesting level of the traversal stack.  However, &amp;lt;tt&amp;gt;CloseHandle&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 String:steamid[], String:name[], maxlength)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;);&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255];&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer));&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvGetString(kv, &amp;quot;name&amp;quot;, name, maxlength);&lt;br /&gt;
			CloseHandle(kv);&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(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;KvGotoNextKey&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;KvGoBack&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(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (KvGotoFirstSubKey(kv))&lt;br /&gt;
		{&lt;br /&gt;
			BrowseKeyValues(kv);&lt;br /&gt;
			KvGoBack(kv);&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv));&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;KvGotoFirstSubKey&amp;lt;/tt&amp;gt; is paired with a call to &amp;lt;tt&amp;gt;KvGoBack&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;
=Deletion=&lt;br /&gt;
There are two ways to delete sections from a KeyValues structure:&lt;br /&gt;
*&amp;lt;tt&amp;gt;KvDeleteKey&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;KvDeleteThis&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;RemoveSteamID(const String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
	KvDeleteKey(kv, steamid)&lt;br /&gt;
	KvRewind(kv)&lt;br /&gt;
	KeyValuesToFile(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' We called &amp;lt;tt&amp;gt;KvRewind&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;KvDeleteThis&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 String:steamid[])&lt;br /&gt;
{&lt;br /&gt;
	new Handle:kv = CreateKeyValues(&amp;quot;MyFile&amp;quot;)&lt;br /&gt;
	FileToKeyValues(kv, &amp;quot;myfile.txt&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	decl String:buffer[255]&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		KvGetSectionName(kv, buffer, sizeof(buffer))&lt;br /&gt;
		if (StrEqual(buffer, steamid))&lt;br /&gt;
		{&lt;br /&gt;
			KvDeleteThis(kv)&lt;br /&gt;
			CloseHandle(kv)&lt;br /&gt;
			return&lt;br /&gt;
		}&lt;br /&gt;
	} while (KvGotoNextKey(kv))&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(kv)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Full Deletion==&lt;br /&gt;
Lastly, let's take a look at how we would delete all (or some) keys.  &amp;lt;tt&amp;gt;KvDeleteThis&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;KvGotoNextKey&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(Handle:kv)&lt;br /&gt;
{&lt;br /&gt;
	if (!KvGotoFirstSubKey(kv))&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for (;;)&lt;br /&gt;
	{&lt;br /&gt;
		decl String:name[4]&lt;br /&gt;
		KvGetString(kv, name, sizeof(name))&lt;br /&gt;
		if (name[0] == '\0')&lt;br /&gt;
		{&lt;br /&gt;
			if (KvDeleteThis(kv) &amp;lt; 1)&lt;br /&gt;
			{&lt;br /&gt;
				break&lt;br /&gt;
			}&lt;br /&gt;
		} else if (!KvGotoNextKey(kv)) {&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;KvDeleteThis&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;KvGotoNextKey&amp;lt;/tt&amp;gt; fails, the loop will end.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7912</id>
		<title>Ru:Events (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7912"/>
		<updated>2010-12-25T04:16:50Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: /* Hooking Events */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:''Для просмотра всех событий, нажмите [[Game Events (Source)|здесь]].''&lt;br /&gt;
&lt;br /&gt;
События это короткие сообщения с именем, посылаемые сервером.  Хотя они используются для внутренней передачи сообщений, они также посылаются клиентам.&lt;br /&gt;
&lt;br /&gt;
Все нативные события можно найти в &amp;lt;tt&amp;gt;plugins/include/events.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
События описаны в &amp;lt;tt&amp;gt;.res&amp;lt;/tt&amp;gt; файлах мода в папке &amp;lt;tt&amp;gt;resource&amp;lt;/tt&amp;gt;.  &amp;quot;Стандартные&amp;quot; события находятся в &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;hl2/resource/serverevents.res&amp;lt;/tt&amp;gt;.  Мод может расширить эти события с помощью расширений.  &lt;br /&gt;
&lt;br /&gt;
Для примера посмотрим на &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; из &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID убитого				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID убийцы&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Counter-Strike:Source расширяет это описание в &amp;lt;tt&amp;gt;cstrike/resource/modevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID убитого				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID убийцы&lt;br /&gt;
	&amp;quot;weapon&amp;quot;	&amp;quot;string&amp;quot; 	// название оружие, которым убил убийца &lt;br /&gt;
	&amp;quot;headshot&amp;quot;	&amp;quot;bool&amp;quot;		// сигнал попадания в голову&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что событие состоит в следующем формате:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;name&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key1&amp;quot;	&amp;quot;valueType1&amp;quot;&lt;br /&gt;
	&amp;quot;key2&amp;quot;	&amp;quot;valueType2&amp;quot;&lt;br /&gt;
	...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Посылка сообщений=&lt;br /&gt;
Послать сообщенмя очень просто.  Например мы хотим послать сообщение смерти используя событие &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; описанное выше.  Для Counter-Strike:Source, это будет иметь вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;SendDeathMessage(attacker, victim, const String:weapon[], bool:headshot)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:event = CreateEvent(&amp;quot;player_death&amp;quot;)&lt;br /&gt;
	if (event == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	SetEventInt(event, &amp;quot;userid&amp;quot;, GetClientUserId(victim))&lt;br /&gt;
	SetEventInt(event, &amp;quot;attacker&amp;quot;, GetClientUserId(attacker))&lt;br /&gt;
	SetEventString(event, &amp;quot;weapon&amp;quot;, weapon)&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, headshot)&lt;br /&gt;
	FireEvent(event)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Примечания:&lt;br /&gt;
*Вы не должны вызывать &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; сделает это за вас.&lt;br /&gt;
*Даже если &amp;quot;userid&amp;quot; и &amp;quot;attacker&amp;quot; являются shorts, мы отсылаем их в качестве ints.  Термин &amp;quot;short&amp;quot; используется только для того, чтобы сказать движку сколько байт числа необходимо для отправки.&lt;br /&gt;
*Событие может и не создастся; это происходит если событие не существует или никто не перехватывает его.  Поэтому вы должны убедиться, что вызов &amp;lt;tt&amp;gt;CreateEvent&amp;lt;/tt&amp;gt; возвращает правильный Handle.&lt;br /&gt;
*Большинство событий используют userids вместо индекса.&lt;br /&gt;
*По умолчанию, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; посылает сообщения к клиенту.  Это можно отключить установив &amp;lt;tt&amp;gt;dontBroadcast&amp;lt;/tt&amp;gt; в true.&lt;br /&gt;
&lt;br /&gt;
=Перехват Событий=&lt;br /&gt;
Существует три режима перехвата событий:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; - Перехват события до выполнения.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; - Перехват события после выполнения.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post_NoCopy&amp;lt;/tt&amp;gt; - Перехват события, но не сохраняется любая информация об этом событии (специальная оптимизация).&lt;br /&gt;
&lt;br /&gt;
Перехват событий обычно делается для одной из этих целей.  Для того, чтоб понять какой режим использовать, смотрите ниже список целей:&lt;br /&gt;
*Блокировка события (предотвращение выполнения)&lt;br /&gt;
**'''Всегда &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Изменение события (изменение параметров)&lt;br /&gt;
**'''Всегда &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Выполнить после события (сделать что-то после того как событие произошло)&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;''' если ваши действия должны произойти перед выполнением мода.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;''' если ваши действия должны произойти после выполнением мода.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt;''' если подходит &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; и требуется только имя события.&lt;br /&gt;
&lt;br /&gt;
Как всегда вы не должны убирать перехват события, когда происходит выгрузка плагина.  Они удаляются автоматически.&lt;br /&gt;
&lt;br /&gt;
==Блокировка Событий==&lt;br /&gt;
Блокировку событий сделать очень просто.  Например мы хотим заблокировать событие смерти если смерть произошла от попадания в голову:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	if (GetEventBool(event, &amp;quot;headshot&amp;quot;))&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Handled&lt;br /&gt;
	}&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Изменение Событий==&lt;br /&gt;
Измененить событий тоже очень просто -- события могут быть изменены в режиме перед выполнением события.  Например мы хотим убрать попадание в голову со всех событий:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, false)&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Post Перехват==&lt;br /&gt;
По умолчанию используется перехват после события и как правило наиболее используемый.  Например мы хотим послать сообщение всем игрокам, которые умерли:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public 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 Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	decl String:weapon[64]&lt;br /&gt;
	new victimId = GetEventInt(event, &amp;quot;userid&amp;quot;)&lt;br /&gt;
	new attackerId = GetEventInt(event, &amp;quot;attacker&amp;quot;)&lt;br /&gt;
	new bool:headshot = GetEventBool(event, &amp;quot;headshot&amp;quot;)&lt;br /&gt;
	GetEventString(event, &amp;quot;weapon&amp;quot;, weapon, sizeof(weapon))&lt;br /&gt;
&lt;br /&gt;
	decl String:name[64]&lt;br /&gt;
	new victim = GetClientOfUserId(victimId)&lt;br /&gt;
	new attacker = GetClientOfUserId(attackerId)&lt;br /&gt;
	GetClientName(attacker, name, sizeof(name))&lt;br /&gt;
&lt;br /&gt;
	PrintToConsole(victim,&lt;br /&gt;
		&amp;quot;You were killed by \&amp;quot;%s\&amp;quot; (weapon \&amp;quot;%s\&amp;quot;) (headshot \&amp;quot;%d\&amp;quot;)&amp;quot;,&lt;br /&gt;
		name,&lt;br /&gt;
		weapon,&lt;br /&gt;
		headshot)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это будет писать игроку в консоли кто его убил, с каким оружием и было ли попадание в голову.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что возвращение значений с перехвата после события игнорируется, поэтому тег &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; ненужен.&lt;br /&gt;
&lt;br /&gt;
==PostNoCopy Перехват==&lt;br /&gt;
Наконец есть перехваты где требуется только имя события.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; специальная оптимизация для этого.  При переходе от &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; к &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;, SourceMod должен дублировать событие и все значения.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; предотвращает это.&lt;br /&gt;
&lt;br /&gt;
Например мы хотим найти когда происходят определенные события.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;game_newmap&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_start&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_end&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_message&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public GameEvents(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Event has been fired (event \&amp;quot;%s\&amp;quot;) (nobcast \&amp;quot;%d\&amp;quot;)&amp;quot;, name, dontBroadcast)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что как и обычный &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; перехват, он не требует возврата значений.  Однако, параметр &amp;lt;tt&amp;gt;event&amp;lt;/tt&amp;gt; для &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; '''всегда''' должен быть равным &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;.  Таким образом параметр &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; должен использоваться вместо &amp;lt;tt&amp;gt;GetEventName&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7911</id>
		<title>Ru:Events (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7911"/>
		<updated>2010-12-25T03:49:37Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: /* Посылка сообщений */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:''Для просмотра всех событий, нажмите [[Game Events (Source)|здесь]].''&lt;br /&gt;
&lt;br /&gt;
События это короткие сообщения с именем, посылаемые сервером.  Хотя они используются для внутренней передачи сообщений, они также посылаются клиентам.&lt;br /&gt;
&lt;br /&gt;
Все нативные события можно найти в &amp;lt;tt&amp;gt;plugins/include/events.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
События описаны в &amp;lt;tt&amp;gt;.res&amp;lt;/tt&amp;gt; файлах мода в папке &amp;lt;tt&amp;gt;resource&amp;lt;/tt&amp;gt;.  &amp;quot;Стандартные&amp;quot; события находятся в &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;hl2/resource/serverevents.res&amp;lt;/tt&amp;gt;.  Мод может расширить эти события с помощью расширений.  &lt;br /&gt;
&lt;br /&gt;
Для примера посмотрим на &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; из &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID убитого				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID убийцы&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Counter-Strike:Source расширяет это описание в &amp;lt;tt&amp;gt;cstrike/resource/modevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID убитого				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID убийцы&lt;br /&gt;
	&amp;quot;weapon&amp;quot;	&amp;quot;string&amp;quot; 	// название оружие, которым убил убийца &lt;br /&gt;
	&amp;quot;headshot&amp;quot;	&amp;quot;bool&amp;quot;		// сигнал попадания в голову&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что событие состоит в следующем формате:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;name&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key1&amp;quot;	&amp;quot;valueType1&amp;quot;&lt;br /&gt;
	&amp;quot;key2&amp;quot;	&amp;quot;valueType2&amp;quot;&lt;br /&gt;
	...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Посылка сообщений=&lt;br /&gt;
Послать сообщенмя очень просто.  Например мы хотим послать сообщение смерти используя событие &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; описанное выше.  Для Counter-Strike:Source, это будет иметь вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;SendDeathMessage(attacker, victim, const String:weapon[], bool:headshot)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:event = CreateEvent(&amp;quot;player_death&amp;quot;)&lt;br /&gt;
	if (event == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	SetEventInt(event, &amp;quot;userid&amp;quot;, GetClientUserId(victim))&lt;br /&gt;
	SetEventInt(event, &amp;quot;attacker&amp;quot;, GetClientUserId(attacker))&lt;br /&gt;
	SetEventString(event, &amp;quot;weapon&amp;quot;, weapon)&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, headshot)&lt;br /&gt;
	FireEvent(event)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Примечания:&lt;br /&gt;
*Вы не должны вызывать &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; сделает это за вас.&lt;br /&gt;
*Даже если &amp;quot;userid&amp;quot; и &amp;quot;attacker&amp;quot; являются shorts, мы отсылаем их в качестве ints.  Термин &amp;quot;short&amp;quot; используется только для того, чтобы сказать движку сколько байт числа необходимо для отправки.&lt;br /&gt;
*Событие может и не создастся; это происходит если событие не существует или никто не перехватывает его.  Поэтому вы должны убедиться, что вызов &amp;lt;tt&amp;gt;CreateEvent&amp;lt;/tt&amp;gt; возвращает правильный Handle.&lt;br /&gt;
*Большинство событий используют userids вместо индекса.&lt;br /&gt;
*По умолчанию, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; посылает сообщения к клиенту.  Это можно отключить установив &amp;lt;tt&amp;gt;dontBroadcast&amp;lt;/tt&amp;gt; в true.&lt;br /&gt;
&lt;br /&gt;
=Hooking Events=&lt;br /&gt;
When hooking an event, there are three modes to choose from:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; - Hook the event before it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; - Hook the event after it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post_NoCopy&amp;lt;/tt&amp;gt; - Hook the event, but do not save any of its information (special optimization).&lt;br /&gt;
&lt;br /&gt;
Hooking an event is usually done for one of the following goals.  To get an idea of which mode to use, see the list below each goal:&lt;br /&gt;
*Blocking the event (preventing it from being fired)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Rewriting the event (changing its parameters)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Acting upon the event (doing something once the event is completed)&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;''' if your action must come before the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;''' if your action must come after the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt;''' if your action is &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; and only requires the event name.&lt;br /&gt;
&lt;br /&gt;
As always, you do not need to unhook events when your plugin unloads.  They are automatically removed.&lt;br /&gt;
&lt;br /&gt;
==Blocking Events==&lt;br /&gt;
Blocking events is the easiest thing to do.  Let's say we want to block death events that are headshots:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	if (GetEventBool(event, &amp;quot;headshot&amp;quot;))&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Handled&lt;br /&gt;
	}&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Rewriting Events==&lt;br /&gt;
Rewriting events is just as easy -- events can be modified in pre hooks.  For example, say we want to remove headshots from all events:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, false)&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Post Hooks==&lt;br /&gt;
Post hooks are default, and will usually be the most common usage.  For example, say we want to print a message to every client that dies:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public 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 Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	decl String:weapon[64]&lt;br /&gt;
	new victimId = GetEventInt(event, &amp;quot;userid&amp;quot;)&lt;br /&gt;
	new attackerId = GetEventInt(event, &amp;quot;attacker&amp;quot;)&lt;br /&gt;
	new bool:headshot = GetEventBool(event, &amp;quot;headshot&amp;quot;)&lt;br /&gt;
	GetEventString(event, &amp;quot;weapon&amp;quot;, weapon, sizeof(weapon))&lt;br /&gt;
&lt;br /&gt;
	decl String:name[64]&lt;br /&gt;
	new victim = GetClientOfUserId(victimId)&lt;br /&gt;
	new attacker = GetClientOfUserId(attackerId)&lt;br /&gt;
	GetClientName(attacker, name, sizeof(name))&lt;br /&gt;
&lt;br /&gt;
	PrintToConsole(victim,&lt;br /&gt;
		&amp;quot;You were killed by \&amp;quot;%s\&amp;quot; (weapon \&amp;quot;%s\&amp;quot;) (headshot \&amp;quot;%d\&amp;quot;)&amp;quot;,&lt;br /&gt;
		name,&lt;br /&gt;
		weapon,&lt;br /&gt;
		headshot)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will print a message to a player's console telling them who killed them, with what weapon, and whether it was a headshot or not.&lt;br /&gt;
&lt;br /&gt;
Note that the return value for post hooks is ignored, so the &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; tag is not needed.&lt;br /&gt;
&lt;br /&gt;
==PostNoCopy Hooks==&lt;br /&gt;
Lastly, there are some hooks where the only piece of information needed is the name of the event.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; is a special optimization for this case.  When transitioning from &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;, SourceMod must duplicate the event and all of its key/value pairs.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; prevents that sequence from happening.&lt;br /&gt;
&lt;br /&gt;
For example, let's say we want to find when a certain sequence of events is called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;game_newmap&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_start&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_end&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_message&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public GameEvents(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Event has been fired (event \&amp;quot;%s\&amp;quot;) (nobcast \&amp;quot;%d\&amp;quot;)&amp;quot;, name, dontBroadcast)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that like normal &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; hooks, there is no return value needed.  However, the &amp;lt;tt&amp;gt;event&amp;lt;/tt&amp;gt; parameter for &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; will '''always''' be equal to &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;.  Thus, the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; parameter must be used instead of &amp;lt;tt&amp;gt;GetEventName&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7901</id>
		<title>Ru:Events (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7901"/>
		<updated>2010-12-08T15:17:00Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:''Для просмотра всех событий, нажмите [[Game Events (Source)|здесь]].''&lt;br /&gt;
&lt;br /&gt;
События это короткие сообщения с именем, посылаемые сервером.  Хотя они используются для внутренней передачи сообщений, они также посылаются клиентам.&lt;br /&gt;
&lt;br /&gt;
Все нативные события можно найти в &amp;lt;tt&amp;gt;plugins/include/events.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
События описаны в &amp;lt;tt&amp;gt;.res&amp;lt;/tt&amp;gt; файлах мода в папке &amp;lt;tt&amp;gt;resource&amp;lt;/tt&amp;gt;.  &amp;quot;Стандартные&amp;quot; события находятся в &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;hl2/resource/serverevents.res&amp;lt;/tt&amp;gt;.  Мод может расширить эти события с помощью расширений.  &lt;br /&gt;
&lt;br /&gt;
Для примера посмотрим на &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; из &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID убитого				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID убийцы&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Counter-Strike:Source расширяет это описание в &amp;lt;tt&amp;gt;cstrike/resource/modevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID убитого				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID убийцы&lt;br /&gt;
	&amp;quot;weapon&amp;quot;	&amp;quot;string&amp;quot; 	// название оружие, которым убил убийца &lt;br /&gt;
	&amp;quot;headshot&amp;quot;	&amp;quot;bool&amp;quot;		// сигнал попадания в голову&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что событие состоит в следующем формате:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;name&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key1&amp;quot;	&amp;quot;valueType1&amp;quot;&lt;br /&gt;
	&amp;quot;key2&amp;quot;	&amp;quot;valueType2&amp;quot;&lt;br /&gt;
	...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Посылка сообщений=&lt;br /&gt;
Послать сообщенмя очень просто.  Например мы хотим послать сообщение смерти используя событие &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; описанное выше.  Для Counter-Strike:Source, это будет иметь вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;SendDeathMessage(attacker, victim, const String:weapon[], bool:headshot)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:event = CreateEvent(&amp;quot;player_death&amp;quot;)&lt;br /&gt;
	if (event == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	SetEventInt(event, &amp;quot;userid&amp;quot;, GetClientUserId(victim))&lt;br /&gt;
	SetEventInt(event, &amp;quot;attacker&amp;quot;, GetClientUserId(attacker))&lt;br /&gt;
	SetEventString(event, &amp;quot;weapon&amp;quot;, weapon)&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, headshot)&lt;br /&gt;
	FireEvent(event)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Примечания:&lt;br /&gt;
*Вы не должны вызывать &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; сделает это за вас.&lt;br /&gt;
*Даже если &amp;quot;userid&amp;quot; и &amp;quot;attacker&amp;quot; являются shorts, мы отсылаем их в качестве ints.  Термин &amp;quot;short&amp;quot; используется только для того, чтобы сказать движку сколько байт числа необходимо для отправки.&lt;br /&gt;
*It is possible for event creation to fail; this can happen if the event does not exist, or nothing is hooking the event.  Thus, you should always make sure &amp;lt;tt&amp;gt;CreateEvent&amp;lt;/tt&amp;gt; calls return a valid Handle.&lt;br /&gt;
*Most events use client userids instead of client indexes.&lt;br /&gt;
*By default, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; broadcasts messages to clients.  This can be prevented by passing &amp;lt;tt&amp;gt;dontBroadcast&amp;lt;/tt&amp;gt; as true.&lt;br /&gt;
&lt;br /&gt;
=Hooking Events=&lt;br /&gt;
When hooking an event, there are three modes to choose from:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; - Hook the event before it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; - Hook the event after it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post_NoCopy&amp;lt;/tt&amp;gt; - Hook the event, but do not save any of its information (special optimization).&lt;br /&gt;
&lt;br /&gt;
Hooking an event is usually done for one of the following goals.  To get an idea of which mode to use, see the list below each goal:&lt;br /&gt;
*Blocking the event (preventing it from being fired)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Rewriting the event (changing its parameters)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Acting upon the event (doing something once the event is completed)&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;''' if your action must come before the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;''' if your action must come after the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt;''' if your action is &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; and only requires the event name.&lt;br /&gt;
&lt;br /&gt;
As always, you do not need to unhook events when your plugin unloads.  They are automatically removed.&lt;br /&gt;
&lt;br /&gt;
==Blocking Events==&lt;br /&gt;
Blocking events is the easiest thing to do.  Let's say we want to block death events that are headshots:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	if (GetEventBool(event, &amp;quot;headshot&amp;quot;))&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Handled&lt;br /&gt;
	}&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Rewriting Events==&lt;br /&gt;
Rewriting events is just as easy -- events can be modified in pre hooks.  For example, say we want to remove headshots from all events:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, false)&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Post Hooks==&lt;br /&gt;
Post hooks are default, and will usually be the most common usage.  For example, say we want to print a message to every client that dies:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public 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 Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	decl String:weapon[64]&lt;br /&gt;
	new victimId = GetEventInt(event, &amp;quot;userid&amp;quot;)&lt;br /&gt;
	new attackerId = GetEventInt(event, &amp;quot;attacker&amp;quot;)&lt;br /&gt;
	new bool:headshot = GetEventBool(event, &amp;quot;headshot&amp;quot;)&lt;br /&gt;
	GetEventString(event, &amp;quot;weapon&amp;quot;, weapon, sizeof(weapon))&lt;br /&gt;
&lt;br /&gt;
	decl String:name[64]&lt;br /&gt;
	new victim = GetClientOfUserId(victimId)&lt;br /&gt;
	new attacker = GetClientOfUserId(attackerId)&lt;br /&gt;
	GetClientName(attacker, name, sizeof(name))&lt;br /&gt;
&lt;br /&gt;
	PrintToConsole(victim,&lt;br /&gt;
		&amp;quot;You were killed by \&amp;quot;%s\&amp;quot; (weapon \&amp;quot;%s\&amp;quot;) (headshot \&amp;quot;%d\&amp;quot;)&amp;quot;,&lt;br /&gt;
		name,&lt;br /&gt;
		weapon,&lt;br /&gt;
		headshot)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will print a message to a player's console telling them who killed them, with what weapon, and whether it was a headshot or not.&lt;br /&gt;
&lt;br /&gt;
Note that the return value for post hooks is ignored, so the &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; tag is not needed.&lt;br /&gt;
&lt;br /&gt;
==PostNoCopy Hooks==&lt;br /&gt;
Lastly, there are some hooks where the only piece of information needed is the name of the event.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; is a special optimization for this case.  When transitioning from &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;, SourceMod must duplicate the event and all of its key/value pairs.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; prevents that sequence from happening.&lt;br /&gt;
&lt;br /&gt;
For example, let's say we want to find when a certain sequence of events is called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;game_newmap&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_start&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_end&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_message&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public GameEvents(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Event has been fired (event \&amp;quot;%s\&amp;quot;) (nobcast \&amp;quot;%d\&amp;quot;)&amp;quot;, name, dontBroadcast)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that like normal &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; hooks, there is no return value needed.  However, the &amp;lt;tt&amp;gt;event&amp;lt;/tt&amp;gt; parameter for &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; will '''always''' be equal to &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;.  Thus, the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; parameter must be used instead of &amp;lt;tt&amp;gt;GetEventName&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7900</id>
		<title>Ru:Events (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7900"/>
		<updated>2010-12-08T15:11:23Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:''Для просмотра всех событий, нажмите [[Game Events (Source)|здесь]].''&lt;br /&gt;
&lt;br /&gt;
События это короткие сообщения с именем, посылаемые сервером.  Хотя они используются для внутренней передачи сообщений, они также посылаются клиентам.&lt;br /&gt;
&lt;br /&gt;
Все нативные события можно найти в &amp;lt;tt&amp;gt;plugins/include/events.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
События описаны в &amp;lt;tt&amp;gt;.res&amp;lt;/tt&amp;gt; файлах мода в папке &amp;lt;tt&amp;gt;resource&amp;lt;/tt&amp;gt;.  &amp;quot;Стандартные&amp;quot; события находятся в &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;hl2/resource/serverevents.res&amp;lt;/tt&amp;gt;.  Мод может расширить эти события с помощью расширений.  &lt;br /&gt;
&lt;br /&gt;
Для примера посмотрим на &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; из &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID убитого				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID убийцы&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Counter-Strike:Source расширяет это описание в &amp;lt;tt&amp;gt;cstrike/resource/modevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID убитого				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID убийцы&lt;br /&gt;
	&amp;quot;weapon&amp;quot;	&amp;quot;string&amp;quot; 	// название оружие, которым убил убийца &lt;br /&gt;
	&amp;quot;headshot&amp;quot;	&amp;quot;bool&amp;quot;		// сигнал попадания в голову&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что событие состоит в следующем формате:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;name&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key1&amp;quot;	&amp;quot;valueType1&amp;quot;&lt;br /&gt;
	&amp;quot;key2&amp;quot;	&amp;quot;valueType2&amp;quot;&lt;br /&gt;
	...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Посылка сообщений=&lt;br /&gt;
Послать сообщенмя очень просто.  Например мы хотим послать сообщение смерти используя событие &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; описанное выше.  Для Counter-Strike:Source, это будет иметь вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;SendDeathMessage(attacker, victim, const String:weapon[], bool:headshot)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:event = CreateEvent(&amp;quot;player_death&amp;quot;)&lt;br /&gt;
	if (event == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	SetEventInt(event, &amp;quot;userid&amp;quot;, GetClientUserId(victim))&lt;br /&gt;
	SetEventInt(event, &amp;quot;attacker&amp;quot;, GetClientUserId(attacker))&lt;br /&gt;
	SetEventString(event, &amp;quot;weapon&amp;quot;, weapon)&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, headshot)&lt;br /&gt;
	FireEvent(event)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Примечания:&lt;br /&gt;
*You don't need to call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; does this for us.&lt;br /&gt;
*Even though &amp;quot;userid&amp;quot; and &amp;quot;attacker&amp;quot; are shorts, we set them as ints.  The term &amp;quot;short&amp;quot; is only used to tell the engine how many bytes of the integer are needed to be networked.&lt;br /&gt;
*It is possible for event creation to fail; this can happen if the event does not exist, or nothing is hooking the event.  Thus, you should always make sure &amp;lt;tt&amp;gt;CreateEvent&amp;lt;/tt&amp;gt; calls return a valid Handle.&lt;br /&gt;
*Most events use client userids instead of client indexes.&lt;br /&gt;
*By default, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; broadcasts messages to clients.  This can be prevented by passing &amp;lt;tt&amp;gt;dontBroadcast&amp;lt;/tt&amp;gt; as true.&lt;br /&gt;
&lt;br /&gt;
=Hooking Events=&lt;br /&gt;
When hooking an event, there are three modes to choose from:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; - Hook the event before it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; - Hook the event after it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post_NoCopy&amp;lt;/tt&amp;gt; - Hook the event, but do not save any of its information (special optimization).&lt;br /&gt;
&lt;br /&gt;
Hooking an event is usually done for one of the following goals.  To get an idea of which mode to use, see the list below each goal:&lt;br /&gt;
*Blocking the event (preventing it from being fired)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Rewriting the event (changing its parameters)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Acting upon the event (doing something once the event is completed)&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;''' if your action must come before the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;''' if your action must come after the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt;''' if your action is &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; and only requires the event name.&lt;br /&gt;
&lt;br /&gt;
As always, you do not need to unhook events when your plugin unloads.  They are automatically removed.&lt;br /&gt;
&lt;br /&gt;
==Blocking Events==&lt;br /&gt;
Blocking events is the easiest thing to do.  Let's say we want to block death events that are headshots:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	if (GetEventBool(event, &amp;quot;headshot&amp;quot;))&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Handled&lt;br /&gt;
	}&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Rewriting Events==&lt;br /&gt;
Rewriting events is just as easy -- events can be modified in pre hooks.  For example, say we want to remove headshots from all events:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, false)&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Post Hooks==&lt;br /&gt;
Post hooks are default, and will usually be the most common usage.  For example, say we want to print a message to every client that dies:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public 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 Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	decl String:weapon[64]&lt;br /&gt;
	new victimId = GetEventInt(event, &amp;quot;userid&amp;quot;)&lt;br /&gt;
	new attackerId = GetEventInt(event, &amp;quot;attacker&amp;quot;)&lt;br /&gt;
	new bool:headshot = GetEventBool(event, &amp;quot;headshot&amp;quot;)&lt;br /&gt;
	GetEventString(event, &amp;quot;weapon&amp;quot;, weapon, sizeof(weapon))&lt;br /&gt;
&lt;br /&gt;
	decl String:name[64]&lt;br /&gt;
	new victim = GetClientOfUserId(victimId)&lt;br /&gt;
	new attacker = GetClientOfUserId(attackerId)&lt;br /&gt;
	GetClientName(attacker, name, sizeof(name))&lt;br /&gt;
&lt;br /&gt;
	PrintToConsole(victim,&lt;br /&gt;
		&amp;quot;You were killed by \&amp;quot;%s\&amp;quot; (weapon \&amp;quot;%s\&amp;quot;) (headshot \&amp;quot;%d\&amp;quot;)&amp;quot;,&lt;br /&gt;
		name,&lt;br /&gt;
		weapon,&lt;br /&gt;
		headshot)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will print a message to a player's console telling them who killed them, with what weapon, and whether it was a headshot or not.&lt;br /&gt;
&lt;br /&gt;
Note that the return value for post hooks is ignored, so the &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; tag is not needed.&lt;br /&gt;
&lt;br /&gt;
==PostNoCopy Hooks==&lt;br /&gt;
Lastly, there are some hooks where the only piece of information needed is the name of the event.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; is a special optimization for this case.  When transitioning from &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;, SourceMod must duplicate the event and all of its key/value pairs.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; prevents that sequence from happening.&lt;br /&gt;
&lt;br /&gt;
For example, let's say we want to find when a certain sequence of events is called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;game_newmap&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_start&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_end&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_message&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public GameEvents(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Event has been fired (event \&amp;quot;%s\&amp;quot;) (nobcast \&amp;quot;%d\&amp;quot;)&amp;quot;, name, dontBroadcast)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that like normal &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; hooks, there is no return value needed.  However, the &amp;lt;tt&amp;gt;event&amp;lt;/tt&amp;gt; parameter for &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; will '''always''' be equal to &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;.  Thus, the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; parameter must be used instead of &amp;lt;tt&amp;gt;GetEventName&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7899</id>
		<title>Ru:Events (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:Events_(SourceMod_Scripting)&amp;diff=7899"/>
		<updated>2010-12-08T14:52:21Z</updated>

		<summary type="html">&lt;p&gt;V1KT0P: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:''Для просмотра всех событий, нажмите [[Game Events (Source)|здесь]].''&lt;br /&gt;
&lt;br /&gt;
Events are short, named messages sent by the server.  Although they are used for internal message passing, they are also networked to clients.&lt;br /&gt;
&lt;br /&gt;
All event natives are found in &amp;lt;tt&amp;gt;plugins/include/events.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Events are documented in &amp;lt;tt&amp;gt;.res&amp;lt;/tt&amp;gt; files under a mod's &amp;lt;tt&amp;gt;resource&amp;lt;/tt&amp;gt; folder.  The &amp;quot;default&amp;quot; events are located in &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;hl2/resource/serverevents.res&amp;lt;/tt&amp;gt;.  Mods can extend these events with their own.  &lt;br /&gt;
&lt;br /&gt;
For example, let's look at &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; from &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID who died				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID who killed&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Counter-Strike:Source extends this definition in &amp;lt;tt&amp;gt;cstrike/resource/modevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID who died				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID who killed&lt;br /&gt;
	&amp;quot;weapon&amp;quot;	&amp;quot;string&amp;quot; 	// weapon name killer used &lt;br /&gt;
	&amp;quot;headshot&amp;quot;	&amp;quot;bool&amp;quot;		// signals a headshot&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the event is structured in the following format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;name&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key1&amp;quot;	&amp;quot;valueType1&amp;quot;&lt;br /&gt;
	&amp;quot;key2&amp;quot;	&amp;quot;valueType2&amp;quot;&lt;br /&gt;
	...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Sending Events=&lt;br /&gt;
Events are very easy to send.  For example, let's say we want to send a death message using the &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; event from above.  For Counter-Strike:Source, this would look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;SendDeathMessage(attacker, victim, const String:weapon[], bool:headshot)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:event = CreateEvent(&amp;quot;player_death&amp;quot;)&lt;br /&gt;
	if (event == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		return&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	SetEventInt(event, &amp;quot;userid&amp;quot;, GetClientUserId(victim))&lt;br /&gt;
	SetEventInt(event, &amp;quot;attacker&amp;quot;, GetClientUserId(attacker))&lt;br /&gt;
	SetEventString(event, &amp;quot;weapon&amp;quot;, weapon)&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, headshot)&lt;br /&gt;
	FireEvent(event)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
*You don't need to call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; does this for us.&lt;br /&gt;
*Even though &amp;quot;userid&amp;quot; and &amp;quot;attacker&amp;quot; are shorts, we set them as ints.  The term &amp;quot;short&amp;quot; is only used to tell the engine how many bytes of the integer are needed to be networked.&lt;br /&gt;
*It is possible for event creation to fail; this can happen if the event does not exist, or nothing is hooking the event.  Thus, you should always make sure &amp;lt;tt&amp;gt;CreateEvent&amp;lt;/tt&amp;gt; calls return a valid Handle.&lt;br /&gt;
*Most events use client userids instead of client indexes.&lt;br /&gt;
*By default, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; broadcasts messages to clients.  This can be prevented by passing &amp;lt;tt&amp;gt;dontBroadcast&amp;lt;/tt&amp;gt; as true.&lt;br /&gt;
&lt;br /&gt;
=Hooking Events=&lt;br /&gt;
When hooking an event, there are three modes to choose from:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; - Hook the event before it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; - Hook the event after it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post_NoCopy&amp;lt;/tt&amp;gt; - Hook the event, but do not save any of its information (special optimization).&lt;br /&gt;
&lt;br /&gt;
Hooking an event is usually done for one of the following goals.  To get an idea of which mode to use, see the list below each goal:&lt;br /&gt;
*Blocking the event (preventing it from being fired)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Rewriting the event (changing its parameters)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Acting upon the event (doing something once the event is completed)&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;''' if your action must come before the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;''' if your action must come after the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt;''' if your action is &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; and only requires the event name.&lt;br /&gt;
&lt;br /&gt;
As always, you do not need to unhook events when your plugin unloads.  They are automatically removed.&lt;br /&gt;
&lt;br /&gt;
==Blocking Events==&lt;br /&gt;
Blocking events is the easiest thing to do.  Let's say we want to block death events that are headshots:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	if (GetEventBool(event, &amp;quot;headshot&amp;quot;))&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Handled&lt;br /&gt;
	}&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Rewriting Events==&lt;br /&gt;
Rewriting events is just as easy -- events can be modified in pre hooks.  For example, say we want to remove headshots from all events:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	SetEventBool(event, &amp;quot;headshot&amp;quot;, false)&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Post Hooks==&lt;br /&gt;
Post hooks are default, and will usually be the most common usage.  For example, say we want to print a message to every client that dies:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public 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 Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	decl String:weapon[64]&lt;br /&gt;
	new victimId = GetEventInt(event, &amp;quot;userid&amp;quot;)&lt;br /&gt;
	new attackerId = GetEventInt(event, &amp;quot;attacker&amp;quot;)&lt;br /&gt;
	new bool:headshot = GetEventBool(event, &amp;quot;headshot&amp;quot;)&lt;br /&gt;
	GetEventString(event, &amp;quot;weapon&amp;quot;, weapon, sizeof(weapon))&lt;br /&gt;
&lt;br /&gt;
	decl String:name[64]&lt;br /&gt;
	new victim = GetClientOfUserId(victimId)&lt;br /&gt;
	new attacker = GetClientOfUserId(attackerId)&lt;br /&gt;
	GetClientName(attacker, name, sizeof(name))&lt;br /&gt;
&lt;br /&gt;
	PrintToConsole(victim,&lt;br /&gt;
		&amp;quot;You were killed by \&amp;quot;%s\&amp;quot; (weapon \&amp;quot;%s\&amp;quot;) (headshot \&amp;quot;%d\&amp;quot;)&amp;quot;,&lt;br /&gt;
		name,&lt;br /&gt;
		weapon,&lt;br /&gt;
		headshot)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will print a message to a player's console telling them who killed them, with what weapon, and whether it was a headshot or not.&lt;br /&gt;
&lt;br /&gt;
Note that the return value for post hooks is ignored, so the &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; tag is not needed.&lt;br /&gt;
&lt;br /&gt;
==PostNoCopy Hooks==&lt;br /&gt;
Lastly, there are some hooks where the only piece of information needed is the name of the event.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; is a special optimization for this case.  When transitioning from &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;, SourceMod must duplicate the event and all of its key/value pairs.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; prevents that sequence from happening.&lt;br /&gt;
&lt;br /&gt;
For example, let's say we want to find when a certain sequence of events is called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;game_newmap&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_start&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_end&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
	HookEvent(&amp;quot;game_message&amp;quot;, GameEvents, EventHookMode_PostNoCopy)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public GameEvents(Handle:event, const String:name[], bool:dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Event has been fired (event \&amp;quot;%s\&amp;quot;) (nobcast \&amp;quot;%d\&amp;quot;)&amp;quot;, name, dontBroadcast)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that like normal &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; hooks, there is no return value needed.  However, the &amp;lt;tt&amp;gt;event&amp;lt;/tt&amp;gt; parameter for &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; will '''always''' be equal to &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;.  Thus, the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; parameter must be used instead of &amp;lt;tt&amp;gt;GetEventName&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ru:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>V1KT0P</name></author>
		
	</entry>
</feed>