https://wiki.alliedmods.net/api.php?action=feedcontributions&user=MAGNAT2645&feedformat=atomAlliedModders Wiki - User contributions [en]2024-03-29T08:59:44ZUser contributionsMediaWiki 1.31.6https://wiki.alliedmods.net/index.php?title=Handles_(SourceMod_Scripting)&diff=11126Handles (SourceMod Scripting)2020-12-17T13:17:24Z<p>MAGNAT2645: DBDrivers are not closeable</p>
<hr />
<div>Handles are a special data type used in [[:Category:SourceMod Scripting|SourceMod Scripting]]. They represent a single internal and unique object. For example, there are "File" Handles for files, and "Menu" Handles for menus, but they are both encapsulated under the "Handle" [[Tags (SourceMod Scripting)|tag]].<br />
<br />
Handles are more than "pointers" from C or C++ because they have a ''reference count''. This means that the number of copies floating around in memory is tracked. The actual internal object is not destroyed until each copy is also destroyed.<br />
<br />
Since SourcePawn does not have [[Garbage Collection]], Handles are a special way of intelligently allowing plugins and SourceMod to manage their own memory.<br />
<br />
For more information on using Handles in the SourceMod API, see [[Handle API (SourceMod)]].<br />
<br />
=Opening Handles=<br />
Opening a Handle is usually done implicitly by a native function. For example, OpenDirectory opens a new Handle which is used in other Directory natives. This associates a ''type'' with the Handle. Trying to use a Directory Handle with any other non-Directory native will cause an error (HandleError_Type), because Handles are type checked.<br />
<br />
<sourcepawn>Handle hndl = OpenDirectory("addons/sourcemod/configs");<br />
</sourcepawn><br />
<br />
=Closing Handles=<br />
==Basic operation==<br />
Closing a Handle means seeing if the internal object can be removed from memory. For example, if a plugin creates an SQL connection, closing the Handle means closing and destroying the connection. This is almost always done using the <tt>delete</tt> operator and specifying the handle to close, e.g. <tt>delete hDir;</tt><br />
<br />
==When to close==<br />
When a plugin unloads, all of its Handles are automatically destroyed. This does not mean, however, that closing Handles is optional. Consider the following code:<br />
<br />
<sourcepawn>bool IsFileInFolder(const char[] path, const char[] file)<br />
{<br />
char path[PLATFORM_MAX_PATH];<br />
FileType type;<br />
<br />
DirectoryListing dir = OpenDirectory(path);<br />
if (dir == null)<br />
{<br />
return false;<br />
}<br />
<br />
while (dir.GetNext(path, sizeof(path), type))<br />
{<br />
if (type == FileType_File && StrEqual(path, file))<br />
{<br />
delete dir;<br />
return true;<br />
}<br />
}<br />
<br />
delete dir;<br />
<br />
return false;<br />
}<br />
</sourcepawn><br />
<br />
This function searches a directory for a single file. If this function were to not close the handle with the <tt>delete</tt> operator, it would [[Memory Leak|leak memory]] every time it was called, and eventually the script would fill up with a large number of lingering Handles that were left open.<br />
<br />
So, when do you close Handles? There are generally two rules of thumb to go by:<br />
*If the native uses terminology such as "Opens a [...]" or "Creates a [...]" or gives explicit directions for closing.<br />
*If the Handle represents a temporary object or piece of information, and you will no longer be using it.<br />
<br />
Most of the time, you will be closing Handles. Check the Handle Type documentation at the end of this page.<br />
<br />
==When you can't close==<br />
There are a few Handle types that cannot be closed. The major one is the Handle which identifies a plugin. Plugins cannot unload themselves, and thus destroying their own Handles is not allowed.<br />
<br />
Furthermore, a script cannot close a Handle that is owned by another plugin. This is for protection against API mistakes and accidental errors. For example, if a Handle is shared between two plugins, one accidental free could invalidate a Handle unexpectedly. To allow the sharing of Handles, see [[#Cloning Handles|Cloning Handles]].<br />
<br />
==Reference counters==<br />
Closing Handles does not always destroy the internal data. This is the case when Handles are [[#Cloning Handles|cloned]]. Each clone adds a ''reference count'' to the Handle, and closing each clone removes one reference count. The original object is only actually destroyed once the Handle has no more reference counters. <br />
<br />
=Cloning Handles=<br />
As briefly described earlier, there is a problem when scripts try to share Handles. Imagine this scenario:<br />
*Plugin 'A' creates a Handle.<br />
*Plugin 'B' received the Handle.<br />
*Plugin 'A' is unloaded, and the Handle is destroyed.<br />
*Plugin 'B' tries to use the Handle.<br />
<br />
To prevent this, the CloneHandle native is provided. This function returns a ''new'' Handle that is a "copy" of the original. While their values won't be equal, they contain the same internal data. The data itself will not be destroyed until each copy and the original are closed with the <tt>delete</tt> operator. It does not matter what order they are freed in, however, each Handle can only be freed once.<br />
<br />
There are two ways of cloning. A plugin can either clone a Handle itself, and become the owner, or it can explicitly set a new owner. The difference is one of API design. Example of the former:<br />
<sourcepawn>Database g_hSQL;<br />
/**<br />
* The other plugin calling this function must pass his ID in,<br />
* but doesn't have to call CloneHandle()<br />
*/<br />
public Database GetGlobalSQL(Handle otherPlugin)<br />
{<br />
return view_as<Database>(CloneHandle(g_hSQL, otherPlugin));<br />
}<br />
<br />
/**<br />
* This code would appear in the other plugin<br />
*/<br />
Database sql = GetGlobalSQL(myself);<br />
/* ... */<br />
delete sql;<br />
</sourcepawn><br />
<br />
Example of the latter:<br />
<sourcepawn>Database g_hSQL;<br />
/**<br />
* The calling plugin must call CloneHandle() himself.<br />
*/<br />
public Database GetGlobalSQL()<br />
{<br />
return g_hSQL;<br />
}<br />
<br />
/**<br />
* This code would appear in the other plugin<br />
*/<br />
Database sql = GetGlobalSQL();<br />
if (sql != null)<br />
{<br />
sql = view_as<Database>(CloneHandle(sql));<br />
}<br />
delete sql;<br />
</sourcepawn><br />
<br />
=Handle Types=<br />
The following is a list of some common Handle types provided by SourceMod and some documentation on each.<br />
<br />
==BitBuffers==<br />
{{HandleType|bf_read or bf_write|Only if explicitly stated|Only if it can also be closed|Core|bitbuffer.inc}}<br />
<br />
There are four types of BitBuffer Handles. They are separated into ''bf_write'' (writable buffer) and ''bf_read'' (readable buffer). These are directly abstracted from their Half-Life 2 counterpart. Internally, there are separate Handle types for each; certain functions will use BitBuffer handles that cannot be freed.<br />
<br />
==ConVars==<br />
{{HandleType|ConVar|No|No|Core|convars.inc}}<br />
<br />
ConVar Handles are primarily used for getting and setting a console variable's value. They cannot be cloned nor deleted since they exist until SourceMod is shut down.<br />
<br />
==DataPacks==<br />
{{HandleType|DataPack|Yes|Yes|Core|datapack.inc}}<br />
<br />
DataPack Handles are used to pack data into a sequential stream, for unpacking later. They are unidirectional, meaning that reading and writing affects the same position in the stream.<br />
<br />
The DataPack type is exposed for Extensions to use.<br />
<br />
==Directories==<br />
{{HandleType|Directory|Yes|Yes|Core|files.inc}}<br />
<br />
Directory Handles are used for opening and enumerating the contents of a directory (folder) on the filesystem.<br />
<br />
==Database Drivers==<br />
{{HandleType|DBDriver|No|No|Core|dbi.inc}}<br />
<br />
DBDriver Handles contain information about a database driver. They are static and cannot be closed.<br />
<br />
==Database Queries==<br />
{{HandleType|IQuery|Yes|No|Core|dbi.inc}}<br />
{{HandleType|IPreparedQuery|Yes|No|Core|dbi.inc}}<br />
<br />
Database Queries wrap an <tt>IQuery</tt> pointer for database queries. Closing a query frees its resources, including any prepared statement information and any result sets.<br />
<br />
==Databases==<br />
{{HandleType|IDatabase|Yes|Yes|Core|dbi.inc}}<br />
<br />
Database Handles wrap an <tt>IDatabase</tt> pointer for database connections. Closing these disconnects the database and frees any related resources.<br />
<br />
==Events==<br />
{{HandleType|Event|No|No|Core|events.inc}}<br />
<br />
Event Handles are used for getting and setting data in Half-Life 2 game events as well as for firing them. They can only be closed using CancelCreatedEvent() if the event was not fired for some reason.<br />
<br />
==Files==<br />
{{HandleType|File|Yes|Yes|Core|files.inc}}<br />
<br />
File Handles are used for opening, reading from, writing to, and creating to files on the file system.<br />
<br />
==Forwards==<br />
{{HandleType|Forward|Yes|Only if explicitly stated|Core|functions.inc}}<br />
<br />
Forward Handles are primarily used when calling functions inside a forward container. There are two types of forwards: global and private. Only private forwards can be cloned.<br />
<br />
==KeyValues==<br />
{{HandleType|KeyValues|Yes|No|Core|keyvalues.inc}}<br />
<br />
KeyValues Handles abstract the Valve data type <tt>KeyValues</tt>, which are tree-based, recursive key to value mapping structures, often used to enumerate properties or configuration file directives.<br />
<br />
==Plugins==<br />
{{HandleType|Plugin|No|No|Core|sourcemod.inc}}<br />
<br />
Plugin Handles are used for the unique identification of a Plugin. They are owned by Core and cannot be cloned or closed by any other plugin or extension. However, plugins can use Handles for certain natives which enumerate or retrieve information on plugins. <br />
<br />
Plugin Handles should not be cached globally, as plugins can become unloaded, and the Handle will be invalid.<br />
<br />
==Plugin Iterators==<br />
{{HandleType|PluginIter|Yes|No|Core|sourcemod.inc}}<br />
<br />
Plugin Iterators allow you to walk over a list of plugins. They are intended for temporary use only.<br />
<br />
==Protobuf==<br />
{{HandleType|protobuf|No|No|Core|protobuf.inc}}<br />
<br />
Protobuf Handles are currently used for usermessages in supported games. They directly reference protobuf Messages, which can be a usermessage or a Message field inside of a usermessage. They are owned and managed by Core and cannot be cloned or closed by a plugin.<br />
<br />
==SMC Parsers==<br />
{{HandleType|SMC Parser|Yes|No|Core|textparse.inc}}<br />
<br />
SMC Parsers are Handles which contain a set of functions for hooking parse events in an SMC file. Since they directly reference functions in a plugin, they cannot be cloned.<br />
<br />
==Timers==<br />
{{HandleType|Timer|Yes|No|Core|timers.inc}}<br />
<br />
Timers are temporary Handles which are automatically closed on any of the following events:<br />
*The timer ends (via Plugin_Stop or being a one-time timer that is finished)<br />
*The timer is killed via <tt>KillTimer</tt><br />
*The timer is closed via <tt>delete hHandle;</tt><br />
*The timer's parent plugin unloads<br />
<br />
[[Category:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Format_Class_Functions_(SourceMod_Scripting)&diff=10239Ru:Format Class Functions (SourceMod Scripting)2017-01-11T00:09:24Z<p>MAGNAT2645: /* Использование */</p>
<hr />
<div>=Введение=<br />
Формат классов функций, аргументов переменной - функции в [[SourceMod]] которые позволяют Вам форматировать строки. Простой пример этой <tt>Format()</tt> функции, выглядит следующим образом:<br />
<br />
<pawn>decl String:buffer[512];<br />
Format(buffer, sizeof(buffer), "Ваше имя: %s", userName);</pawn><br />
<br />
Если userName содержит "<tt>Frenzzy</tt>", содержимое <tt>buffer</tt> будет: "<tt>Ваше имя: Frenzzy</tt>". Прототип этих функций почти всегда содержит следующие параметры:<br />
<pawn>const char[] fmt, {Handle,float,_}:...</pawn><br />
<br />
Например, обратите внимание на эти два выражения:<br />
<pawn>native Format(char[] buffer, int maxlength, const char[] fmt, {Handle,float,_}:...);<br />
native PrintToClient(int client, char[] fmt, {Handle,float,_}:...);</pawn><br />
<br />
Таким образом, <tt>PrintToClient</tt> является формат-классовой функцией. Она может быть использована точно так же, как было показано ранее:<br />
<pawn>PrintToClient(client, "Ваше имя: %s", userName);</pawn><br />
<br />
=Спецификаторы Формата=<br />
Спецификаторы Формата имеют код, который позволяет указать, какие типы данных будут отображаться. Наиболее распространенными спецификаторами являются:<br />
*'''Числовые'''<br />
**'''d''' или '''i''': Целое число как десятичные<br />
**'''b''': Бинарные символы в значении<br />
**'''f''': Числа с плавающей точкой<br />
**'''x''' or '''X''': Шестнадцатеричное представление бинарных значений (применение заглавных букв влияет на шестнадцатеричный регистр букв)<br />
*'''Символ(ы)'''<br />
**'''s''': Строка<br />
**'''t''' или '''T''': Переводы фраз (см. в [[Translations (SourceMod_Scripting)#Inline_Translations|Inline Translations]])<br />
**'''c''': Вывод одного символа (совместимо с UTF-8)<br />
*'''Специальные'''<br />
**'''L''': Требуется индекс клиента; расширяется до 1<2><3><>, где 1 - имя игрока, 2 - userid игрока, и 3 - Steam ID игрока. Если клиент имеет индекс 0, строка будет: <tt><nowiki>Console<0><Console><Console></nowiki></tt><br />
**'''N''': Требуется индекс клиента; расширяется до строки, содержащей имя игрока. Если клиент имеет индекс 0, строка будет: <tt>Console</tt><br />
<br />
=Использование=<br />
Спецификаторы формата обозначаются символом <tt>'%s'</tt>. Например, чтобы отобразилось число с плавающей точкой, десятичное число и строка, Вы можете использовать этот код:<br />
<pawn>float fNum = 5.0;<br />
int iNum = 5;<br />
char[] str = "5";<br />
<br />
PrintToClient(client, "Десятичное число: %d Число с плавающей точкой: %f Строка: %s", iNum, fNum, str);</pawn><br />
<br />
'''Примечание''': Использование неправильных типов данных спецификаторов может быть очень опасно. Всегда убедитесь, что выводится правильный тип. Например, указание строки и передача числа, может привести к падению сервера.<br />
<br />
=Расширенный формат=<br />
Спецификаторы формата имеют расширенный синтаксис для управления различными аспектами того, как будут выводиться данные.<br />
Полный синтаксис: <tt>%[flags][width][.precision]specifier</tt><br />
<br />
Каждый раздел в квадратных скобках является дополнительным расширением. Описание поддерживаемых SourceMod расширений формата:<br />
*'''%''': Очевидно, что это требуется всегда.<br />
*'''flags''':<br />
**'''-''': Выравнивание по левому краю (выравнивание по правому краю установлено по умолчанию)<br />
**'''0''': Заполняет 0 вместо пробелов в случае необходимости (см. '''width''' ниже).<br />
*'''width''': Минимальное количество символов, которые будут отображены. Если отображаемая величина будет короче, чем это число, результат будет заполнен пустым пространством. Значение так же не обрежится, даже если результат будет длиннее.<br />
*'''precision''':<br />
**'''For integers''': определяет минимальное количество цифр для отображения (или заполняет пробелами/нулями, если она меньше минимальной).<br />
**'''For strings''': определяет максимальное количество символов для отображения.<br />
**'''For floats''': определяет количество цифр для отображения ''после запятой''.<br />
**'''For all other types''': нет эффекта.<br />
*'''specifier''': символ указывающий тип данных (требуется всегда).<br />
<br />
Для получения более подробной информации см. [http://www.cplusplus.com/reference/clibrary/cstdio/printf.html printf] из C Standard Library, хотя не dсе режимы из C поддерживаются.<br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Format_Class_Functions_(SourceMod_Scripting)&diff=10238Ru:Format Class Functions (SourceMod Scripting)2017-01-11T00:08:44Z<p>MAGNAT2645: </p>
<hr />
<div>=Введение=<br />
Формат классов функций, аргументов переменной - функции в [[SourceMod]] которые позволяют Вам форматировать строки. Простой пример этой <tt>Format()</tt> функции, выглядит следующим образом:<br />
<br />
<pawn>decl String:buffer[512];<br />
Format(buffer, sizeof(buffer), "Ваше имя: %s", userName);</pawn><br />
<br />
Если userName содержит "<tt>Frenzzy</tt>", содержимое <tt>buffer</tt> будет: "<tt>Ваше имя: Frenzzy</tt>". Прототип этих функций почти всегда содержит следующие параметры:<br />
<pawn>const char[] fmt, {Handle,float,_}:...</pawn><br />
<br />
Например, обратите внимание на эти два выражения:<br />
<pawn>native Format(char[] buffer, int maxlength, const char[] fmt, {Handle,float,_}:...);<br />
native PrintToClient(int client, char[] fmt, {Handle,float,_}:...);</pawn><br />
<br />
Таким образом, <tt>PrintToClient</tt> является формат-классовой функцией. Она может быть использована точно так же, как было показано ранее:<br />
<pawn>PrintToClient(client, "Ваше имя: %s", userName);</pawn><br />
<br />
=Спецификаторы Формата=<br />
Спецификаторы Формата имеют код, который позволяет указать, какие типы данных будут отображаться. Наиболее распространенными спецификаторами являются:<br />
*'''Числовые'''<br />
**'''d''' или '''i''': Целое число как десятичные<br />
**'''b''': Бинарные символы в значении<br />
**'''f''': Числа с плавающей точкой<br />
**'''x''' or '''X''': Шестнадцатеричное представление бинарных значений (применение заглавных букв влияет на шестнадцатеричный регистр букв)<br />
*'''Символ(ы)'''<br />
**'''s''': Строка<br />
**'''t''' или '''T''': Переводы фраз (см. в [[Translations (SourceMod_Scripting)#Inline_Translations|Inline Translations]])<br />
**'''c''': Вывод одного символа (совместимо с UTF-8)<br />
*'''Специальные'''<br />
**'''L''': Требуется индекс клиента; расширяется до 1<2><3><>, где 1 - имя игрока, 2 - userid игрока, и 3 - Steam ID игрока. Если клиент имеет индекс 0, строка будет: <tt><nowiki>Console<0><Console><Console></nowiki></tt><br />
**'''N''': Требуется индекс клиента; расширяется до строки, содержащей имя игрока. Если клиент имеет индекс 0, строка будет: <tt>Console</tt><br />
<br />
=Испрльзование=<br />
Спецификаторы формата обозначаются символом <tt>'%s'</tt>. Например, чтобы отобразилось число с плавающей точкой, десятичное число и строка, Вы можете использовать этот код:<br />
<pawn>float fNum = 5.0;<br />
int iNum = 5<br />
char[] str = "5"<br />
<br />
PrintToClient(client, "Десятичное число: %d Число с плавающей точкой: %f Строка: %s", iNum, fNum, str);</pawn><br />
<br />
'''Примечание''': Использование неправильных типов данных спецификаторов может быть очень опасно. Всегда убедитесь, что выводится правильный тип. Например, указание строки и передача числа, может привести к падению сервера.<br />
<br />
=Расширенный формат=<br />
Спецификаторы формата имеют расширенный синтаксис для управления различными аспектами того, как будут выводиться данные.<br />
Полный синтаксис: <tt>%[flags][width][.precision]specifier</tt><br />
<br />
Каждый раздел в квадратных скобках является дополнительным расширением. Описание поддерживаемых SourceMod расширений формата:<br />
*'''%''': Очевидно, что это требуется всегда.<br />
*'''flags''':<br />
**'''-''': Выравнивание по левому краю (выравнивание по правому краю установлено по умолчанию)<br />
**'''0''': Заполняет 0 вместо пробелов в случае необходимости (см. '''width''' ниже).<br />
*'''width''': Минимальное количество символов, которые будут отображены. Если отображаемая величина будет короче, чем это число, результат будет заполнен пустым пространством. Значение так же не обрежится, даже если результат будет длиннее.<br />
*'''precision''':<br />
**'''For integers''': определяет минимальное количество цифр для отображения (или заполняет пробелами/нулями, если она меньше минимальной).<br />
**'''For strings''': определяет максимальное количество символов для отображения.<br />
**'''For floats''': определяет количество цифр для отображения ''после запятой''.<br />
**'''For all other types''': нет эффекта.<br />
*'''specifier''': символ указывающий тип данных (требуется всегда).<br />
<br />
Для получения более подробной информации см. [http://www.cplusplus.com/reference/clibrary/cstdio/printf.html printf] из C Standard Library, хотя не dсе режимы из C поддерживаются.<br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:DataPacks_(SourceMod_Scripting)&diff=10225Ru:DataPacks (SourceMod Scripting)2016-11-24T12:52:12Z<p>MAGNAT2645: /* Функции DataPack */</p>
<hr />
<div>DataPack - легкий способ добавлять и перемещать различные типы данных в [[:Category:SourceMod Scripting|SourceMod Scripting]]. Так как некоторые вещи невозможны в SourcePawn, такие как функция потребления строчки, DataPackи помогают нам получать эти строчки и другие вещи, где они нужны.<br />
<br />
=Примеры использования DataPack=<br />
Синтаксис:<br />
<pawn><br />
//написание<br />
DataPack pack = new DataPack();<br />
pack.WriteCell(23);<br />
pack.WriteString("I'm a little teapot.");<br />
<br />
//чтение<br />
pack.Reset(); //возвращает позицию в начало, необходимо для чтения данных.<br />
int cellValue = pack.ReadCell();<br />
char buffer[1024];<br />
pack.ReadString(buffer, 1024);<br />
</pawn><br />
<br />
=Создание DataPack=<br />
Создать DataPack очень просто; всё, что вам нужно это дескриптор для записи DataPack в него.<br />
<pawn>Datapack dataPackHandle = new DataPack();</pawn><br />
<br />
Для более подробной информации по использованию дескрипторов, смотрите [[Handle API (SourceMod)]].<br />
<br />
=Функции DataPack=<br />
Когда вы создадите DataPack, вы можете использовать множество функций, чтобы управлять DataPack.<br />
<br />
==WritePackCell==<br />
Синтаксис:<br />
<pawn>native void WritePackCell(Handle pack, int cell);<br />
</pawn><br />
<br />
==WritePackFloat==<br />
Эта функция может использоваться, чтобы записать дробь в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackFloat(Handle pack, float val);<br />
</pawn><br />
<br />
==WritePackString==<br />
Эта функция может использоваться, чтобы записать строчку в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackString(Handle pack, const char[] str);<br />
</pawn><br />
<br />
==ReadPackCell==<br />
Синтаксис:<br />
<pawn>native any ReadPackCell(Handle pack);<br />
</pawn><br />
<br />
==ReadPackFloat==<br />
Эта функция может использоваться, чтобы прочитать (получить) дробь из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native float ReadPackFloat(Handle pack);<br />
</pawn><br />
<br />
==ReadPackString==<br />
Эта функция может использоваться, чтобы прочитать (получить) строчку из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void ReadPackString(Handle pack, char[] buffer, maxlen);<br />
</pawn><br />
<br />
==ResetPack==<br />
Эта функция возвращает позицию DataPack в начало.<br />
<br />
Синтаксис:<br />
<pawn>native void ResetPack(Handle pack, bool clear=false);<br />
</pawn><br />
<br />
==GetPackPosition==<br />
Эта функция возвращает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native int GetPackPosition(Handle pack);<br />
</pawn><br />
<br />
==SetPackPosition==<br />
Эта функция устанавливает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void SetPackPosition(Handle pack, int position);<br />
</pawn><br />
<br />
=Отключение DataPack=<br />
Чтобы отключить DataPack, нужно просто закрыть его дескриптор.<br />
<br />
Пример:<br />
<pawn>CloseHandle(dataPackHandle);<br />
</pawn><br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:DataPacks_(SourceMod_Scripting)&diff=10224Ru:DataPacks (SourceMod Scripting)2016-11-24T12:51:36Z<p>MAGNAT2645: /* Функции DataPack */</p>
<hr />
<div>DataPack - легкий способ добавлять и перемещать различные типы данных в [[:Category:SourceMod Scripting|SourceMod Scripting]]. Так как некоторые вещи невозможны в SourcePawn, такие как функция потребления строчки, DataPackи помогают нам получать эти строчки и другие вещи, где они нужны.<br />
<br />
=Примеры использования DataPack=<br />
Синтаксис:<br />
<pawn><br />
//написание<br />
DataPack pack = new DataPack();<br />
pack.WriteCell(23);<br />
pack.WriteString("I'm a little teapot.");<br />
<br />
//чтение<br />
pack.Reset(); //возвращает позицию в начало, необходимо для чтения данных.<br />
int cellValue = pack.ReadCell();<br />
char buffer[1024];<br />
pack.ReadString(buffer, 1024);<br />
</pawn><br />
<br />
=Создание DataPack=<br />
Создать DataPack очень просто; всё, что вам нужно это дескриптор для записи DataPack в него.<br />
<pawn>Datapack dataPackHandle = new DataPack();</pawn><br />
<br />
Для более подробной информации по использованию дескрипторов, смотрите [[Handle API (SourceMod)]].<br />
<br />
=Функции DataPack=<br />
Когда вы создадите DataPack, вы можете использовать множество функций, чтобы управлять DataPack.<br />
<br />
==WritePackCell==<br />
Синтаксис:<br />
<pawn>native void WritePackCell(Handle pack, int cell);<br />
</pawn><br />
<br />
==WritePackFloat==<br />
Эта функция может использоваться, чтобы записать дробь в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackFloat(Handle pack, float val);<br />
</pawn><br />
<br />
==WritePackString==<br />
Эта функция может использоваться, чтобы записать строчку в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackString(Handle pack, const char[] str);<br />
</pawn><br />
<br />
==ReadPackCell==<br />
Синтаксис:<br />
<pawn>native any ReadPackCell(Handle pack);<br />
</pawn><br />
<br />
==ReadPackFloat==<br />
Эта функция может использоваться, чтобы прочитать (получить) дробь из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native float ReadPackFloat(Handle pack);<br />
</pawn><br />
<br />
==ReadPackString==<br />
This function can be used to read a String from a DataPack.<br />
Эта функция может использоваться, чтобы прочитать (получить) строчку из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void ReadPackString(Handle pack, char[] buffer, maxlen);<br />
</pawn><br />
<br />
==ResetPack==<br />
This function resets your position in the DataPack.<br />
Эта функция возвращает позицию DataPack в начало.<br />
<br />
Синтаксис:<br />
<pawn>native void ResetPack(Handle pack, bool clear=false);<br />
</pawn><br />
<br />
==GetPackPosition==<br />
Эта функция возвращает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native int GetPackPosition(Handle pack);<br />
</pawn><br />
<br />
==SetPackPosition==<br />
Эта функция устанавливает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void SetPackPosition(Handle pack, int position);<br />
</pawn><br />
<br />
=Отключение DataPack=<br />
Чтобы отключить DataPack, нужно просто закрыть его дескриптор.<br />
<br />
Пример:<br />
<pawn>CloseHandle(dataPackHandle);<br />
</pawn><br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:DataPacks_(SourceMod_Scripting)&diff=10223Ru:DataPacks (SourceMod Scripting)2016-11-24T12:50:59Z<p>MAGNAT2645: /* Создание DataPack */</p>
<hr />
<div>DataPack - легкий способ добавлять и перемещать различные типы данных в [[:Category:SourceMod Scripting|SourceMod Scripting]]. Так как некоторые вещи невозможны в SourcePawn, такие как функция потребления строчки, DataPackи помогают нам получать эти строчки и другие вещи, где они нужны.<br />
<br />
=Примеры использования DataPack=<br />
Синтаксис:<br />
<pawn><br />
//написание<br />
DataPack pack = new DataPack();<br />
pack.WriteCell(23);<br />
pack.WriteString("I'm a little teapot.");<br />
<br />
//чтение<br />
pack.Reset(); //возвращает позицию в начало, необходимо для чтения данных.<br />
int cellValue = pack.ReadCell();<br />
char buffer[1024];<br />
pack.ReadString(buffer, 1024);<br />
</pawn><br />
<br />
=Создание DataPack=<br />
Создать DataPack очень просто; всё, что вам нужно это дескриптор для записи DataPack в него.<br />
<pawn>Datapack dataPackHandle = new DataPack();</pawn><br />
<br />
Для более подробной информации по использованию дескрипторов, смотрите [[Handle API (SourceMod)]].<br />
<br />
=Функции DataPack=<br />
On you have created your DataPack, you can use a variety of functions to manage the DataPack.<br />
Когда вы создадите DataPack, вы можете использовать множество функций, чтобы управлять DataPack.<br />
<br />
==WritePackCell==<br />
Синтаксис:<br />
<pawn>native void WritePackCell(Handle pack, int cell);<br />
</pawn><br />
<br />
==WritePackFloat==<br />
Эта функция может использоваться, чтобы записать дробь в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackFloat(Handle pack, float val);<br />
</pawn><br />
<br />
==WritePackString==<br />
Эта функция может использоваться, чтобы записать строчку в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackString(Handle pack, const char[] str);<br />
</pawn><br />
<br />
==ReadPackCell==<br />
Синтаксис:<br />
<pawn>native any ReadPackCell(Handle pack);<br />
</pawn><br />
<br />
==ReadPackFloat==<br />
Эта функция может использоваться, чтобы прочитать (получить) дробь из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native float ReadPackFloat(Handle pack);<br />
</pawn><br />
<br />
==ReadPackString==<br />
This function can be used to read a String from a DataPack.<br />
Эта функция может использоваться, чтобы прочитать (получить) строчку из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void ReadPackString(Handle pack, char[] buffer, maxlen);<br />
</pawn><br />
<br />
==ResetPack==<br />
This function resets your position in the DataPack.<br />
Эта функция возвращает позицию DataPack в начало.<br />
<br />
Синтаксис:<br />
<pawn>native void ResetPack(Handle pack, bool clear=false);<br />
</pawn><br />
<br />
==GetPackPosition==<br />
Эта функция возвращает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native int GetPackPosition(Handle pack);<br />
</pawn><br />
<br />
==SetPackPosition==<br />
Эта функция устанавливает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void SetPackPosition(Handle pack, int position);<br />
</pawn><br />
<br />
=Отключение DataPack=<br />
Чтобы отключить DataPack, нужно просто закрыть его дескриптор.<br />
<br />
Пример:<br />
<pawn>CloseHandle(dataPackHandle);<br />
</pawn><br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Category:Ru:SourceMod_Scripting&diff=10222Category:Ru:SourceMod Scripting2016-11-22T18:36:48Z<p>MAGNAT2645: </p>
<hr />
<div>Эта категория содержит статьи о написании скриптов под SourceMod с использованием SourcePawn.<br />
<br />
===Введение===<br />
*[[Ru:Introduction to SourcePawn|Ru:Introduction to SourcePawn]] - Введение в SourcePawn. Обучение синтаксису языка.<br />
*[[Ru:Introduction to SourceMod Plugins|Ru:Introduction to SourceMod Plugins]] - Введение в SourceMod плагины. Создаем Ваш "первый плагин".<br />
*[http://docs.sourcemod.net/api API Reference] - Поиск сценариев в справочнике API.<br />
<br />
===Основной API===<br />
*[[Ru:AutoConfigs (SourceMod Scripting)|Автоконфиги]] - Автоматическое создание .cfg файлов.<br />
*[[Ru:Commands (SourceMod Scripting)|Команды]] - Консольные команды/ввод.<br />
*[[Ru:ConVars (SourceMod Scripting)|Консольные переменные]] - Консольные переменные (cvars).<br />
*[[Ru:Events (SourceMod Scripting)|События]] - Игровые события Half-Life.<br />
*[[Ru:KeyValues (SourceMod Scripting)|КлючЗначение]] - KeyValues анализ/запись файла.<br />
*[[Ru:Menu API (SourceMod)|Меню]] - Создание и отображение меню.<br />
*[[Ru:SQL (SourceMod Scripting)|SQL]] - Использование баз данных (MySQL, SQLite).<br />
*[[Ru:Timers (SourceMod Scripting)|Таймеры]] - Вызов таймеров.<br />
*[[Ru:DataPacks|DataPack]] - Создание и управление DataPack.<br />
*[[Ru:Translations (SourceMod Scripting)|Переводы]] - Создание локализаций.<br />
<br />
===Продвинутый API===<br />
*[[Admin API (SourceMod)|API администрирования]] - Использование кэша администратора.<br />
*[[Admin Menu (SourceMod Scripting)|API админского меню]] - Закрепление в меню администратора.<br />
*[[Creating Natives (SourceMod Scripting)|Создание нативных функция]] - Разоблачение API других плагинов.<br />
*[[Function Calling API (SourceMod Scripting)|API вызова функция]] - Вызовы внешних функций.<br />
*[[Optional Requirements (SourceMod Scripting)|Необязательные требования]] - Управление зависимостями.<br />
*[[SDKTools (SourceMod Scripting)|SDKTools]] - Использование мощного SDK уровней абстракции.<br />
*[[TempEnts (SourceMod SDKTools)|Временные объекты]] - Использование временных объектов.<br />
<br />
===Информация===<br />
*[[Deprecation Schedule (SourceMod Scripting)|Deprecation Schedule]] - Which functions are getting removed.<br />
*[[Ru:Format Class Functions (SourceMod Scripting)|Ru:Format Class Functions]] - Всё про форматирование текста.<br />
*[[Handles (SourceMod Scripting)|Handles]] - Обзор Handle и несколько распространённых типов.<br />
*[[Optimizing Plugins (SourceMod Scripting)|Optimizing Plugins]] - Советы по оптимизации.<br />
*[[Tags (Scripting)|Tags]] - Всё о тэгах.<br />
*[[Vectors Explained (Scripting)|Vectors Explained]] - Объяснение типов Вектора.<br />
<br />
===Дополнительные средства===<br />
*[http://docs.sourcemod.net/api API Reference] - API по кодированию на SourcePawn.<br />
*[[Entity Properties]] - Explanation of Source entity properties.<br />
*[[Game Events (Source)|Game Events]] - Список игровых событий для популярных модификаций.<br />
*[[Mod TempEnt List (Source)|Temp Entity Lists]] - Список временных объектов для популярных модификаций.<br />
*[[SourceMod Profiler]] - Отслеживание производительности и оптимизации.</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Category:Ru:SourceMod_Scripting&diff=10221Category:Ru:SourceMod Scripting2016-11-22T18:32:36Z<p>MAGNAT2645: Fixed url</p>
<hr />
<div>Эта категория содержит статьи о написании скриптов под SourceMod с использованием SourcePawn.<br />
<br />
===Введение===<br />
*[[Ru:Introduction to SourcePawn|Ru:Introduction to SourcePawn]] - Введение в SourcePawn. Обучение синтаксису языка.<br />
*[[Ru:Introduction to SourceMod Plugins|Ru:Introduction to SourceMod Plugins]] - Введение в SourceMod плагины. Создаем Ваш "первый плагин".<br />
*[http://docs.sourcemod.net/api API Reference] - Поиск сценариев в справочнике API.<br />
<br />
===Основной API===<br />
*[[Ru:AutoConfigs (SourceMod Scripting)|Автоконфиги]] - Автоматическое создание .cfg файлов.<br />
*[[Ru:Commands (SourceMod Scripting)|Команды]] - Консольные команды/ввод.<br />
*[[Ru:ConVars (SourceMod Scripting)|Консольные переменные]] - Консольные переменные (cvars).<br />
*[[Ru:Events (SourceMod Scripting)|События]] - Игровые события Half-Life.<br />
*[[Ru:KeyValues (SourceMod Scripting)|КлючЗначение]] - KeyValues анализ/запись файла.<br />
*[[Ru:Menu API (SourceMod)|Меню]] - Создание и отображение меню.<br />
*[[Ru:SQL (SourceMod Scripting)|SQL]] - Использование баз данных (MySQL, SQLite).<br />
*[[Ru:Timers (SourceMod Scripting)|Таймеры]] - Вызов таймеров.<br />
*[[Ru:DataPacks|DataPack]] - Создание и управление DataPack.<br />
*[[Ru:Translations (SourceMod Scripting)|Переводы]] - Создание локализаций.<br />
<br />
===Продвинутый API===<br />
*[[Admin API (SourceMod)|API администрирования]] - Использование кэша администратора.<br />
*[[Admin Menu (SourceMod Scripting)|API админского меню]] - Закрепление в меню администратора.<br />
*[[Creating Natives (SourceMod Scripting)|Создание нативных функция]] - Разоблачение API других плагинов.<br />
*[[Function Calling API (SourceMod Scripting)|API вызова функция]] - Вызовы внешних функций.<br />
*[[Optional Requirements (SourceMod Scripting)|Необязательные требования]] - Управление зависимостями.<br />
*[[SDKTools (SourceMod Scripting)|SDKTools]] - Использование мощного SDK уровней абстракции.<br />
*[[TempEnts (SourceMod SDKTools)|Временные объекты]] - Использование временных объектов.<br />
<br />
===Информация===<br />
*[[Deprecation Schedule (SourceMod Scripting)|Deprecation Schedule]] - Which functions are getting removed.<br />
*[[Ru:Format Class Functions (SourceMod Scripting)|Ru:Format Class Functions]] - Всё про форматирование текста.<br />
*[[Handles (SourceMod Scripting)|Handles]] - Обзор Handle и несколько распространённых типов.<br />
*[[Optimizing Plugins (SourceMod Scripting)|Optimizing Plugins]] - Советы по оптимизации.<br />
*[[Tags (Scripting)|Tags]] - Всё о тэгах.<br />
*[[Vectors Explained (Scripting)|Vectors Explained]] - Объяснение типов Вектора.<br />
<br />
===Дополнительные средства===<br />
*[http://docs.sourcemod.net/api API Reference] - Searchable scripting API reference.<br />
*[[Entity Properties]] - Explanation of Source entity properties.<br />
*[[Game Events (Source)|Game Events]] - Game events listings for popular mods.<br />
*[[Mod TempEnt List (Source)|Temp Entity Lists]] - Temporary entities for popular mods.<br />
*[[SourceMod Profiler]] - Отслеживание производительности и оптимизации.</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:DataPacks&diff=10220Ru:DataPacks2016-11-22T18:31:40Z<p>MAGNAT2645: MAGNAT2645 moved page Ru:DataPacks to Ru:DataPacks (SourceMod Scripting): Url will be able to use with this</p>
<hr />
<div>#REDIRECT [[Ru:DataPacks (SourceMod Scripting)]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:DataPacks_(SourceMod_Scripting)&diff=10219Ru:DataPacks (SourceMod Scripting)2016-11-22T18:31:40Z<p>MAGNAT2645: MAGNAT2645 moved page Ru:DataPacks to Ru:DataPacks (SourceMod Scripting): Url will be able to use with this</p>
<hr />
<div>DataPack - легкий способ добавлять и перемещать различные типы данных в [[:Category:SourceMod Scripting|SourceMod Scripting]]. Так как некоторые вещи невозможны в SourcePawn, такие как функция потребления строчки, DataPackи помогают нам получать эти строчки и другие вещи, где они нужны.<br />
<br />
=Примеры использования DataPack=<br />
Синтаксис:<br />
<pawn><br />
//написание<br />
DataPack pack = new DataPack();<br />
pack.WriteCell(23);<br />
pack.WriteString("I'm a little teapot.");<br />
<br />
//чтение<br />
pack.Reset(); //возвращает позицию в начало, необходимо для чтения данных.<br />
int cellValue = pack.ReadCell();<br />
char buffer[1024];<br />
pack.ReadString(buffer, 1024);<br />
</pawn><br />
<br />
=Создание DataPack=<br />
Creating a DataPack is very simple; all you need is a Handle to write to.<br />
Создать DataPack очень просто; всё, что вам нужно это дескриптор для записи DataPack в него.<br />
<pawn>Datapack dataPackHandle = new DataPack();</pawn><br />
<br />
Для более подробной информации по использованию дескрипторов, смотрите [[Handle API (SourceMod)]].<br />
<br />
=Функции DataPack=<br />
On you have created your DataPack, you can use a variety of functions to manage the DataPack.<br />
Когда вы создадите DataPack, вы можете использовать множество функций, чтобы управлять DataPack.<br />
<br />
==WritePackCell==<br />
Синтаксис:<br />
<pawn>native void WritePackCell(Handle pack, int cell);<br />
</pawn><br />
<br />
==WritePackFloat==<br />
Эта функция может использоваться, чтобы записать дробь в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackFloat(Handle pack, float val);<br />
</pawn><br />
<br />
==WritePackString==<br />
Эта функция может использоваться, чтобы записать строчку в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackString(Handle pack, const char[] str);<br />
</pawn><br />
<br />
==ReadPackCell==<br />
Синтаксис:<br />
<pawn>native any ReadPackCell(Handle pack);<br />
</pawn><br />
<br />
==ReadPackFloat==<br />
Эта функция может использоваться, чтобы прочитать (получить) дробь из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native float ReadPackFloat(Handle pack);<br />
</pawn><br />
<br />
==ReadPackString==<br />
This function can be used to read a String from a DataPack.<br />
Эта функция может использоваться, чтобы прочитать (получить) строчку из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void ReadPackString(Handle pack, char[] buffer, maxlen);<br />
</pawn><br />
<br />
==ResetPack==<br />
This function resets your position in the DataPack.<br />
Эта функция возвращает позицию DataPack в начало.<br />
<br />
Синтаксис:<br />
<pawn>native void ResetPack(Handle pack, bool clear=false);<br />
</pawn><br />
<br />
==GetPackPosition==<br />
Эта функция возвращает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native int GetPackPosition(Handle pack);<br />
</pawn><br />
<br />
==SetPackPosition==<br />
Эта функция устанавливает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void SetPackPosition(Handle pack, int position);<br />
</pawn><br />
<br />
=Отключение DataPack=<br />
Чтобы отключить DataPack, нужно просто закрыть его дескриптор.<br />
<br />
Пример:<br />
<pawn>CloseHandle(dataPackHandle);<br />
</pawn><br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:DataPacks_(SourceMod_Scripting)&diff=10218Ru:DataPacks (SourceMod Scripting)2016-11-22T18:30:39Z<p>MAGNAT2645: Removed old english text</p>
<hr />
<div>DataPack - легкий способ добавлять и перемещать различные типы данных в [[:Category:SourceMod Scripting|SourceMod Scripting]]. Так как некоторые вещи невозможны в SourcePawn, такие как функция потребления строчки, DataPackи помогают нам получать эти строчки и другие вещи, где они нужны.<br />
<br />
=Примеры использования DataPack=<br />
Синтаксис:<br />
<pawn><br />
//написание<br />
DataPack pack = new DataPack();<br />
pack.WriteCell(23);<br />
pack.WriteString("I'm a little teapot.");<br />
<br />
//чтение<br />
pack.Reset(); //возвращает позицию в начало, необходимо для чтения данных.<br />
int cellValue = pack.ReadCell();<br />
char buffer[1024];<br />
pack.ReadString(buffer, 1024);<br />
</pawn><br />
<br />
=Создание DataPack=<br />
Creating a DataPack is very simple; all you need is a Handle to write to.<br />
Создать DataPack очень просто; всё, что вам нужно это дескриптор для записи DataPack в него.<br />
<pawn>Datapack dataPackHandle = new DataPack();</pawn><br />
<br />
Для более подробной информации по использованию дескрипторов, смотрите [[Handle API (SourceMod)]].<br />
<br />
=Функции DataPack=<br />
On you have created your DataPack, you can use a variety of functions to manage the DataPack.<br />
Когда вы создадите DataPack, вы можете использовать множество функций, чтобы управлять DataPack.<br />
<br />
==WritePackCell==<br />
Синтаксис:<br />
<pawn>native void WritePackCell(Handle pack, int cell);<br />
</pawn><br />
<br />
==WritePackFloat==<br />
Эта функция может использоваться, чтобы записать дробь в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackFloat(Handle pack, float val);<br />
</pawn><br />
<br />
==WritePackString==<br />
Эта функция может использоваться, чтобы записать строчку в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackString(Handle pack, const char[] str);<br />
</pawn><br />
<br />
==ReadPackCell==<br />
Синтаксис:<br />
<pawn>native any ReadPackCell(Handle pack);<br />
</pawn><br />
<br />
==ReadPackFloat==<br />
Эта функция может использоваться, чтобы прочитать (получить) дробь из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native float ReadPackFloat(Handle pack);<br />
</pawn><br />
<br />
==ReadPackString==<br />
This function can be used to read a String from a DataPack.<br />
Эта функция может использоваться, чтобы прочитать (получить) строчку из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void ReadPackString(Handle pack, char[] buffer, maxlen);<br />
</pawn><br />
<br />
==ResetPack==<br />
This function resets your position in the DataPack.<br />
Эта функция возвращает позицию DataPack в начало.<br />
<br />
Синтаксис:<br />
<pawn>native void ResetPack(Handle pack, bool clear=false);<br />
</pawn><br />
<br />
==GetPackPosition==<br />
Эта функция возвращает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native int GetPackPosition(Handle pack);<br />
</pawn><br />
<br />
==SetPackPosition==<br />
Эта функция устанавливает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void SetPackPosition(Handle pack, int position);<br />
</pawn><br />
<br />
=Отключение DataPack=<br />
Чтобы отключить DataPack, нужно просто закрыть его дескриптор.<br />
<br />
Пример:<br />
<pawn>CloseHandle(dataPackHandle);<br />
</pawn><br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Category:Ru:SourceMod_Scripting&diff=10217Category:Ru:SourceMod Scripting2016-11-22T18:29:09Z<p>MAGNAT2645: Added url to Ru:DataPacks</p>
<hr />
<div>Эта категория содержит статьи о написании скриптов под SourceMod с использованием SourcePawn.<br />
<br />
===Введение===<br />
*[[Ru:Introduction to SourcePawn|Ru:Introduction to SourcePawn]] - Введение в SourcePawn. Обучение синтаксису языка.<br />
*[[Ru:Introduction to SourceMod Plugins|Ru:Introduction to SourceMod Plugins]] - Введение в SourceMod плагины. Создаем Ваш "первый плагин".<br />
*[http://docs.sourcemod.net/api API Reference] - Поиск сценариев в справочнике API.<br />
<br />
===Основной API===<br />
*[[Ru:AutoConfigs (SourceMod Scripting)|Автоконфиги]] - Автоматическое создание .cfg файлов.<br />
*[[Ru:Commands (SourceMod Scripting)|Команды]] - Консольные команды/ввод.<br />
*[[Ru:ConVars (SourceMod Scripting)|Консольные переменные]] - Консольные переменные (cvars).<br />
*[[Ru:Events (SourceMod Scripting)|События]] - Игровые события Half-Life.<br />
*[[Ru:KeyValues (SourceMod Scripting)|КлючЗначение]] - KeyValues анализ/запись файла.<br />
*[[Ru:Menu API (SourceMod)|Меню]] - Создание и отображение меню.<br />
*[[Ru:SQL (SourceMod Scripting)|SQL]] - Использование баз данных (MySQL, SQLite).<br />
*[[Ru:Timers (SourceMod Scripting)|Таймеры]] - Вызов таймеров.<br />
*[[Ru:DataPacks (SourceMod Scripting)|DataPack]] - Создание и управление DataPack.<br />
*[[Ru:Translations (SourceMod Scripting)|Переводы]] - Создание локализаций.<br />
<br />
===Продвинутый API===<br />
*[[Admin API (SourceMod)|API администрирования]] - Использование кэша администратора.<br />
*[[Admin Menu (SourceMod Scripting)|API админского меню]] - Закрепление в меню администратора.<br />
*[[Creating Natives (SourceMod Scripting)|Создание нативных функция]] - Разоблачение API других плагинов.<br />
*[[Function Calling API (SourceMod Scripting)|API вызова функция]] - Вызовы внешних функций.<br />
*[[Optional Requirements (SourceMod Scripting)|Необязательные требования]] - Управление зависимостями.<br />
*[[SDKTools (SourceMod Scripting)|SDKTools]] - Использование мощного SDK уровней абстракции.<br />
*[[TempEnts (SourceMod SDKTools)|Временные объекты]] - Использование временных объектов.<br />
<br />
===Информация===<br />
*[[Deprecation Schedule (SourceMod Scripting)|Deprecation Schedule]] - Which functions are getting removed.<br />
*[[Ru:Format Class Functions (SourceMod Scripting)|Ru:Format Class Functions]] - Всё про форматирование текста.<br />
*[[Handles (SourceMod Scripting)|Handles]] - Обзор Handle и несколько распространённых типов.<br />
*[[Optimizing Plugins (SourceMod Scripting)|Optimizing Plugins]] - Советы по оптимизации.<br />
*[[Tags (Scripting)|Tags]] - Всё о тэгах.<br />
*[[Vectors Explained (Scripting)|Vectors Explained]] - Объяснение типов Вектора.<br />
<br />
===Дополнительные средства===<br />
*[http://docs.sourcemod.net/api API Reference] - Searchable scripting API reference.<br />
*[[Entity Properties]] - Explanation of Source entity properties.<br />
*[[Game Events (Source)|Game Events]] - Game events listings for popular mods.<br />
*[[Mod TempEnt List (Source)|Temp Entity Lists]] - Temporary entities for popular mods.<br />
*[[SourceMod Profiler]] - Отслеживание производительности и оптимизации.</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:DataPacks_(SourceMod_Scripting)&diff=10216Ru:DataPacks (SourceMod Scripting)2016-11-22T18:26:28Z<p>MAGNAT2645: </p>
<hr />
<div>DataPack - легкий способ добавлять и перемещать различные типы данных в [[:Category:SourceMod Scripting|SourceMod Scripting]]. Since some things are not possible in SourcePawn, such as a function consuming a String, DataPacks help us get these Strings and other items where they need to go.<br />
Так как некоторые вещи невозможны в SourcePawn, такие как функция потребления строчки, DataPackи помогают нам получать эти строчки и другие вещи, где они нужны.<br />
<br />
=Примеры использования DataPack=<br />
Синтаксис:<br />
<pawn><br />
//написание<br />
DataPack pack = new DataPack();<br />
pack.WriteCell(23);<br />
pack.WriteString("I'm a little teapot.");<br />
<br />
//чтение<br />
pack.Reset(); //возвращает позицию в начало, необходимо для чтения данных.<br />
int cellValue = pack.ReadCell();<br />
char buffer[1024];<br />
pack.ReadString(buffer, 1024);<br />
</pawn><br />
<br />
=Создание DataPack=<br />
Creating a DataPack is very simple; all you need is a Handle to write to.<br />
Создать DataPack очень просто; всё, что вам нужно это дескриптор для записи DataPack в него.<br />
<pawn>Datapack dataPackHandle = new DataPack();</pawn><br />
<br />
Для более подробной информации по использованию дескрипторов, смотрите [[Handle API (SourceMod)]].<br />
<br />
=Функции DataPack=<br />
On you have created your DataPack, you can use a variety of functions to manage the DataPack.<br />
Когда вы создадите DataPack, вы можете использовать множество функций, чтобы управлять DataPack.<br />
<br />
==WritePackCell==<br />
Синтаксис:<br />
<pawn>native void WritePackCell(Handle pack, int cell);<br />
</pawn><br />
<br />
==WritePackFloat==<br />
Эта функция может использоваться, чтобы записать дробь в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackFloat(Handle pack, float val);<br />
</pawn><br />
<br />
==WritePackString==<br />
Эта функция может использоваться, чтобы записать строчку в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackString(Handle pack, const char[] str);<br />
</pawn><br />
<br />
==ReadPackCell==<br />
Синтаксис:<br />
<pawn>native any ReadPackCell(Handle pack);<br />
</pawn><br />
<br />
==ReadPackFloat==<br />
Эта функция может использоваться, чтобы прочитать (получить) дробь из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native float ReadPackFloat(Handle pack);<br />
</pawn><br />
<br />
==ReadPackString==<br />
This function can be used to read a String from a DataPack.<br />
Эта функция может использоваться, чтобы прочитать (получить) строчку из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void ReadPackString(Handle pack, char[] buffer, maxlen);<br />
</pawn><br />
<br />
==ResetPack==<br />
This function resets your position in the DataPack.<br />
Эта функция возвращает позицию DataPack в начало.<br />
<br />
Синтаксис:<br />
<pawn>native void ResetPack(Handle pack, bool clear=false);<br />
</pawn><br />
<br />
==GetPackPosition==<br />
Эта функция возвращает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native int GetPackPosition(Handle pack);<br />
</pawn><br />
<br />
==SetPackPosition==<br />
Эта функция устанавливает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void SetPackPosition(Handle pack, int position);<br />
</pawn><br />
<br />
=Отключение DataPack=<br />
Чтобы отключить DataPack, нужно просто закрыть его дескриптор.<br />
<br />
Пример:<br />
<pawn>CloseHandle(dataPackHandle);<br />
</pawn><br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:DataPacks_(SourceMod_Scripting)&diff=10215Ru:DataPacks (SourceMod Scripting)2016-11-22T18:23:32Z<p>MAGNAT2645: </p>
<hr />
<div>DataPack - легкий способ добавлять и перемещать различные типы данных в [[:Category:SourceMod Scripting|SourceMod Scripting]]. Since some things are not possible in SourcePawn, such as a function consuming a String, DataPacks help us get these Strings and other items where they need to go.<br />
Так как некоторые вещи невозможны в SourcePawn, такие как функция потребления строчки, DataPackи помогают нам получать эти строчки и другие вещи, где они нужны.<br />
<br />
=Примеры использования DataPack=<br />
Синтаксис:<br />
<pawn><br />
//написание<br />
DataPack pack = new DataPack();<br />
pack.WriteCell(23);<br />
pack.WriteString("I'm a little teapot.");<br />
<br />
//чтение<br />
pack.Reset(); //возвращает позицию в начало, необходимо для чтения данных.<br />
int cellValue = pack.ReadCell();<br />
char buffer[1024];<br />
pack.ReadString(buffer, 1024);<br />
</pawn><br />
<br />
=Создание DataPack=<br />
Creating a DataPack is very simple; all you need is a Handle to write to.<br />
Создать DataPack очень просто; всё, что вам нужно это дескриптор для записи DataPack в него.<br />
<pawn>Datapack dataPackHandle = new DataPack();</pawn><br />
<br />
Для более подробной информации по использованию дескрипторов, смотрите [[Handle API (SourceMod)]].<br />
<br />
=Функции DataPack=<br />
On you have created your DataPack, you can use a variety of functions to manage the DataPack.<br />
Когда вы создадите DataPack, вы можете использовать множество функций, чтобы управлять DataPack.<br />
<br />
==WritePackCell==<br />
Синтаксис:<br />
<pawn>native void WritePackCell(Handle pack, int cell);<br />
</pawn><br />
<br />
==WritePackFloat==<br />
Эта функция может использоваться, чтобы записать дробь в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackFloat(Handle pack, float val);<br />
</pawn><br />
<br />
==WritePackString==<br />
Эта функция может использоваться, чтобы записать строчку в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackString(Handle pack, const char[] str);<br />
</pawn><br />
<br />
==ReadPackCell==<br />
Синтаксис:<br />
<pawn>native any ReadPackCell(Handle pack);<br />
</pawn><br />
<br />
==ReadPackFloat==<br />
Эта функция может использоваться, чтобы прочитать (получить) дробь из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native float ReadPackFloat(Handle pack);<br />
</pawn><br />
<br />
==ReadPackString==<br />
This function can be used to read a String from a DataPack.<br />
Эта функция может использоваться, чтобы прочитать (получить) строчку из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void ReadPackString(Handle pack, char[] buffer, maxlen);<br />
</pawn><br />
<br />
==ResetPack==<br />
This function resets your position in the DataPack.<br />
Эта функция возвращает позицию DataPack в начало.<br />
<br />
Синтаксис:<br />
<pawn>native void ResetPack(Handle pack, bool clear=false);<br />
</pawn><br />
<br />
==GetPackPosition==<br />
Эта функция возвращает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native int GetPackPosition(Handle pack);<br />
</pawn><br />
<br />
==SetPackPosition==<br />
Эта функция устанавливает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void SetPackPosition(Handle pack, int position);<br />
</pawn><br />
<br />
=Отключение DataPack=<br />
Чтобы отключить DataPack, нужно просто закрыть его дескриптор.<br />
<br />
Пример:<br />
<pawn>CloseHandle(dataPackHandle);<br />
</pawn><br />
<br />
[[Category:SourceMod Scripting]]<br />
<br />
<br />
{{LanguageSwitch}}</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:DataPacks_(SourceMod_Scripting)&diff=10214Ru:DataPacks (SourceMod Scripting)2016-11-22T18:22:09Z<p>MAGNAT2645: Created page with "DataPack - легкий способ добавлять и перемещать различные типы данных в :Category:SourceMod Scripting|SourceMod Scripting..."</p>
<hr />
<div>DataPack - легкий способ добавлять и перемещать различные типы данных в [[:Category:SourceMod Scripting|SourceMod Scripting]]. Since some things are not possible in SourcePawn, such as a function consuming a String, DataPacks help us get these Strings and other items where they need to go.<br />
Так как некоторые вещи невозможны в SourcePawn, такие как функция потребления строчки, DataPackи помогают нам получать эти строчки и другие вещи, где они нужны.<br />
<br />
=Примеры использования DataPack=<br />
Синтаксис:<br />
<pawn><br />
//написание<br />
DataPack pack = new DataPack();<br />
pack.WriteCell(23);<br />
pack.WriteString("I'm a little teapot.");<br />
<br />
//чтение<br />
pack.Reset(); //возвращает позицию в начало, необходимо для чтения данных.<br />
int cellValue = pack.ReadCell();<br />
char buffer[1024];<br />
pack.ReadString(buffer, 1024);<br />
</pawn><br />
<br />
=Создание DataPack=<br />
Creating a DataPack is very simple; all you need is a Handle to write to.<br />
Создать DataPack очень просто; всё, что вам нужно это дескриптор для записи DataPack в него.<br />
<pawn>Datapack dataPackHandle = new DataPack();</pawn><br />
<br />
Для более подробной информации по использованию дескрипторов, смотрите [[Handle API (SourceMod)]].<br />
<br />
=Функции DataPack=<br />
On you have created your DataPack, you can use a variety of functions to manage the DataPack.<br />
Когда вы создадите DataPack, вы можете использовать множество функций, чтобы управлять DataPack.<br />
<br />
==WritePackCell==<br />
Синтаксис:<br />
<pawn>native void WritePackCell(Handle pack, int cell);<br />
</pawn><br />
<br />
==WritePackFloat==<br />
Эта функция может использоваться, чтобы записать дробь в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackFloat(Handle pack, float val);<br />
</pawn><br />
<br />
==WritePackString==<br />
Эта функция может использоваться, чтобы записать строчку в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void WritePackString(Handle pack, const char[] str);<br />
</pawn><br />
<br />
==ReadPackCell==<br />
Синтаксис:<br />
<pawn>native any ReadPackCell(Handle pack);<br />
</pawn><br />
<br />
==ReadPackFloat==<br />
Эта функция может использоваться, чтобы прочитать (получить) дробь из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native float ReadPackFloat(Handle pack);<br />
</pawn><br />
<br />
==ReadPackString==<br />
This function can be used to read a String from a DataPack.<br />
Эта функция может использоваться, чтобы прочитать (получить) строчку из DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void ReadPackString(Handle pack, char[] buffer, maxlen);<br />
</pawn><br />
<br />
==ResetPack==<br />
This function resets your position in the DataPack.<br />
Эта функция возвращает позицию DataPack в начало.<br />
<br />
Синтаксис:<br />
<pawn>native void ResetPack(Handle pack, bool clear=false);<br />
</pawn><br />
<br />
==GetPackPosition==<br />
Эта функция возвращает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native int GetPackPosition(Handle pack);<br />
</pawn><br />
<br />
==SetPackPosition==<br />
Эта функция устанавливает текущую позицию в DataPack.<br />
<br />
Синтаксис:<br />
<pawn>native void SetPackPosition(Handle pack, int position);<br />
</pawn><br />
<br />
=Отключение DataPack=<br />
Чтобы отключить DataPack, нужно просто закрыть его дескриптор.<br />
<br />
Пример:<br />
<pawn>CloseHandle(dataPackHandle);<br />
</pawn><br />
<br />
[[Category:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Introduction_to_SourcePawn_1.7&diff=10204Ru:Introduction to SourcePawn 1.72016-08-26T16:53:51Z<p>MAGNAT2645: /* Объяснение */</p>
<hr />
<div>This guide is designed to give you a very basic overview to fundamentals of scripting in SourcePawn. [[Pawn]] is a "scripting" language used to embed functionality in other programs. That means it is not a standalone language, like C++ or Java, and its details will differ based on the application. SourcePawn is the version of Pawn used in [[SourceMod]].<br />
<br />
This guide does not tell you how to write SourceMod plugins; it is intended as an overview of the syntax and semantics of the language instead. Read the separate article, [[Introduction to SourceMod Plugins]] for SourceMod API specifics. <br />
<br />
=Не программное введение=<br />
This section is intended for non-programmers. If you're still confused, you may want to pick up a book on another language, such as PHP, Python, or Java, to get a better idea of what programming is like.<br />
<br />
==Символы/Ключевые слова==<br />
A symbol is a series of letters, numbers, and/or underscores, that uniquely represents something. Symbols are case-sensitive, and usually start with a letter.<br />
<br />
There are a few reserved symbols that have special meaning. For example, <tt>if</tt>, <tt>for</tt>, and <tt>return</tt> are special constructs in the language that will explained later. They cannot be used as symbol names.<br />
<br />
==Переменные==<br />
There a few important constructs you should know before you begin to script. The first is a '''variable'''. A variable is a symbol, or name, that holds data. For example, the variable "a" could hold the number "2", "16", "0", et cetera. Since a variable holds data, it also allocates the memory needed to store that data.<br />
<br />
In addition to a name, variables have a '''type'''. A type tells the program how to interpret the data, and how much memory the data will use. Pawn has three types of data that are most commonly used:<br />
* Integers, using the <tt>int</tt> type. Integer types may store a whole number from -2147483648 to 2147483647.<br />
* Floats, using the <tt>float</tt> type. Float types may store fractional numbers in a huge range, though they are not as precise as integers.<br />
* Characters, using the <tt>char</tt> type. Character types store one byte of character information, typically an [http://www.asciitable.com/ ASCII] character.<br />
* Booleans, using the <tt>bool</tt> type. Booleans store either true or false.<br />
<br />
Пример создания переменных и добавление значений:<br />
<br />
<pawn>int money = 5400;<br />
float percent = 67.3;<br />
bool enabled = false;<br />
</pawn><br />
<br />
==Функции==<br />
The next important concept is '''functions'''. Functions are symbols or names that perform an action. When you invoke, or call them, they carry out a specific sequence of code and then return a result. There are a few types of functions, but every function is activated the same way. Example:<br />
<br />
<pawn><br />
show(56); // Calls the "show" function, and gives it the number 56.<br />
enable(); // Calls the "enable" function with no values.<br />
bool visible = show(a); //Calls the "show" function, stores its result in a variable.<br />
</pawn><br />
<br />
Every piece of data passed to a function is called a '''parameter'''. A function can have any number of parameters (there is a "reasonable" limit of 32 in SourceMod). Parameters will be explained further in the article.<br />
<br />
==Комментарии==<br />
Знайте, что любой текст после "//" помечается как "комментарий" и это не актуальный (компилятор будет игнорировать комментарии) код. Существует два стиля комментариев:<br />
*<tt>//</tt> - Двойной слэш, всё на этой линии игнорируется.<br />
*<tt>/* */</tt> - Многострочный комментарий, всё между звёздочками игнорируется.<br />
<br />
==Блок кодирования==<br />
Следующей концепцией является блок кодирования. Вы можете групповать код в "блоки", перечисляя его через { и }. Это эффективней делает один большой блок кода из нескольких частей. Для примера:<br />
<br />
<pawn>{<br />
здесь;<br />
есть;<br />
немного;<br />
кода;<br />
}</pawn><br />
<br />
Block coding using braces is used everywhere in programming. Blocks of code can be nested within each other. It is a good idea to adapt a consistent and readable indentation style early on to prevent spaghetti-looking code.<br />
<br />
=Парадигмы языка=<br />
Pawn may seem similar to other languages, like C, but it has fundamental differences. It is not important that you immediately understand these differences, but they may be helpful if you're familiar with another language already.<br />
*'''Pawn is sort of typed.''' Before SourceMod 1.7, Pawn did not have types. Older code and older natives will reflect this by using tags and the <tt>new</tt> keyword. As of SourceMod 1.7, we recommend that all code use types. For more information see [[SourcePawn Transitional Syntax]].<br />
*'''Pawn is not garbage collected.''' Pawn, as a language, has no built-in memory allocation, and thus has no garbage. If a function allocates memory, you may be responsible for freeing it.<br />
*'''Pawn is not object oriented.''' Pawn does not have structs or objects. As of SourceMod 1.7, it has limited sugaring for treating some data types as objects, but users cannot create their own objects or classes.<br />
*'''Pawn is single-threaded.''' As of this writing, Pawn is not thread safe. <br />
*'''Pawn is compiled.''' Pawn is compiled to an intermediate, machine-independent code, which is stored in a ".smx" file. When loading .smx files, SourceMod translates this code to machine code for the platform and CPU it's running on.<br />
<br />
Early language design decisions were made by ITB CompuPhase. It is designed for low-level embedded devices and is thus very small and very fast.<br />
<br />
=Переменные=<br />
На данный момент Pawn поддерживает следующие базовые типы переменных:<br />
*<tt>bool</tt> - true или false. (Правда или ложь)<br />
*<tt>char</tt> - 8-битный символ ASCII.<br />
*<tt>int</tt> - 32-битное целое число.<br />
*<tt>float</tt> - 32-битное число с плавающей точкой IEEE-754.<br />
*<tt>Handle</tt> - базовый тип объекта SourceMod.<br />
<br />
Other types may exist when defined in include files - for example, enums create new types for named integers, and many types derive from <tt>Handle</tt>.<br />
<br />
Strings, currently, are 0-terminated arrays of <tt>char</tt>s. They're described a little further ahead.<br />
<br />
==Объяснение==<br />
Ниже мы приложили немного примеров объявлений переменных, между правильными и неправильными. Имейте ввиду, что в SourcePawn был добавлен новый синтакс, и он указан ниже. Старый код может использовать старый синтакс объявления, который больше не поддерживается.<br />
<br />
<pawn><br />
int a = 5;<br />
float b = 5.0;<br />
bool c = true;<br />
bool d = false;<br />
</pawn><br />
<br />
Неправильное использование переменных:<br />
<pawn><br />
int a = 5.0; // Несоответствие типов. 5.0 это число с плавающей точкой.<br />
float b = 5; // Несоответствие типов. 5 это целое число.<br />
</pawn><br />
<br />
Если значение переменной не указано, оно будет установлено на 0. Пример:<br />
<pawn><br />
int a; // Устанавливается на 0<br />
float b; // Устанавливается на 0.0<br />
bool c; // Устанавливается на false<br />
</pawn><br />
<br />
==Присваивание==<br />
Содержимое переменной может быть переназначено после того, как она была создана. Пример:<br />
<pawn>int a;<br />
float b;<br />
bool c;<br />
<br />
a = 5;<br />
b = 5.0;<br />
c = true;<br />
</pawn><br />
<br />
=Массивы=<br />
An array is a sequence of data in a list. Arrays are useful for storing multiple pieces of data in one variable, or mapping one type of data to another.<br />
<br />
==Объяснение==<br />
An array is declared using brackets. Some examples of arrays:<br />
Массив объявляется, используя квадратные скобки. Немного примеров массивов:<br />
<pawn><br />
int players[32]; // Содержит 32 целых чисел.<br />
float origin[3]; // Содержит 3 числа с плавающей точкой<br />
</pawn><br />
<br />
By default, arrays are initialized to 0. You can assign them different default values, however:<br />
<pawn><br />
int numbers[5] = {1, 2, 3, 4, 5}; // Stores 1, 2, 3, 4, 5.<br />
float origin[3] = {1.0, 2.0, 3.0}; // Stores 1.0, 2.0, 3.0.<br />
</pawn><br />
<br />
You can leave out the array size if you're going to pre-assign data to it. For example:<br />
<pawn><br />
int numbers[] = {1, 3, 5, 7, 9};<br />
</pawn><br />
<br />
The compiler will automatically deduce that you intended an array of size 5.<br />
<br />
When array is declared with brackets after its name, Pawn considers that array to have a '''fixed size'''. The size of a fixed-size array is always known. Some arrays can be '''dynamically sized''', by putting the brackets before the name. For example,<br />
<br />
<pawn><br />
int[] numbers = new int[MaxClients]<br />
</pawn><br />
<br />
This creates an array of size <tt>MaxClients</tt>, which could be anything, so the size of the array is not known until the array is allocated.<br />
<br />
==Использование==<br />
Using an array is just like using a normal variable. The only difference is the array must be '''indexed'''. Indexing an array means choosing the element which you wish to use.<br />
<br />
For example, here is an example of the above code using indexes:<br />
<pawn><br />
int numbers[5];<br />
float origin[3];<br />
<br />
numbers[0] = 1;<br />
numbers[1] = 2;<br />
numbers[2] = 3;<br />
numbers[3] = 4;<br />
numbers[4] = 5;<br />
origin[0] = 1.0;<br />
origin[1] = 2.0;<br />
origin[2] = 3.0;<br />
</pawn><br />
<br />
Note that the '''index''' is what's in between the brackets. The index always starts from 0. That is, if an array has N elements, its valid indexes are from 0 to N-1. Accessing the data at these indexes works like a normal variable.<br />
<br />
Using an incorrect index will cause an error. For example:<br />
<pawn><br />
int numbers[5];<br />
<br />
numbers[5] = 20;</pawn><br />
<br />
This may look correct, but 5 is not a valid index. The highest valid index is 4.<br />
<br />
You can use any expression as an index. For example:<br />
<pawn>int a, numbers[5];<br />
<br />
a = 1; // Устанавливаем значение a = 1<br />
numbers[a] = 4; // Set numbers[1] = 4<br />
numbers[numbers[a]] = 2; // Set numbers[4] = 2<br />
</pawn><br />
<br />
Expressions will be discussed in depth later in the article.<br />
<br />
=Строки=<br />
Strings are a construct for storing text (or even raw binary data). A string is just an array of characters, except that the final character must be 0 (called the null terminator). Without a null terminator, Pawn would not know where to stop reading the string. All strings are [http://en.wikipedia.org/wiki/UTF-8 UTF-8] in SourcePawn.<br />
<br />
In general, you must have an idea of how large a string will be before you store it. SourcePawn does not yet have the capability of pre-determining storage space for strings.<br />
<br />
==Использование==<br />
Обычно строки объявляются в виде массивов. Пример:<br />
<pawn><br />
char message[] = "Привет!";<br />
char clams[6] = "Мидии";<br />
</pawn><br />
<br />
Это эквивалентно можно сделать:<br />
<pawn><br />
char message[7];<br />
char clams[6];<br />
<br />
message[0] = 'П';<br />
message[1] = 'р';<br />
message[2] = 'и';<br />
message[3] = 'в';<br />
message[4] = 'е';<br />
message[5] = 'т';<br />
message[6] = '!';<br />
message[7] = 0;<br />
clams[0] = 'м';<br />
clams[1] = 'и';<br />
clams[2] = 'д';<br />
clams[3] = 'и';<br />
clams[4] = 'и';<br />
clams[5] = 0;<br />
</pawn><br />
<br />
Although strings are rarely initialized in this manner, it is very important to remember the concept of the null terminator, which signals the end of a string. The compiler, and most SourceMod functions will automatically null-terminate for you, so it is mainly important when manipulating strings directly.<br />
<br />
Note that a string is enclosed in double-quotes, but a character is enclosed in single quotes.<br />
<br />
==Characters==<br />
A character of text can be used in either a String or a cell. For example:<br />
<pawn>char text[] = "Crab";<br />
char clam;<br />
<br />
clam = 'D'; //Set clam to 'D'<br />
text[0] = 'A'; //Change the 'C' to 'A', it is now 'Arab'<br />
clam = text[0]; //Set clam to 'A'<br />
text[1] = clam; //Change the 'r' to 'A', is is now 'AAab'<br />
</pawn><br />
<br />
What you can't do is mix character arrays with strings. The internal storage is different. For example:<br />
<pawn><br />
int clams[] = "Clams"; // Invalid.<br />
int clams[] = {'C', 'l', 'a', 'm', 's', 0}; // Valid, but NOT A STRING.<br />
</pawn><br />
<br />
=Functions=<br />
Functions, as stated before, are isolated blocks of code that perform an action. They can be invoked, or '''called''', with '''parameters''' that give specific options.<br />
<br />
There are two types of ways functions are called:<br />
*'''direct call''' - You specifically call a function in your code.<br />
*'''callback''' - The application calls a function in your code, as if it were an event trigger.<br />
<br />
There are six types of functions:<br />
*'''native''': A direct, internal function provided by the application.<br />
*'''public''': A callback function that is visible to the application and other scripts.<br />
*'''normal''': A normal function that only you can call.<br />
*'''static''': The scope of this function is restricted to the current file, can be used in combination with stock.<br />
*'''stock''': A normal function provided by an include file. If unused, it won't be compiled.<br />
*'''forward''': This function is a global event provided by the application. If you implement it, it will be a callback.<br />
<br />
All code in Pawn must exist in functions. This is in contrast to languages like PHP, Perl, and Python which let you write global code. That is because Pawn is a callback-based language: it responds to actions from a parent application, and functions must be written to handle those actions. Although our examples often contain free-floating code, this is purely for demonstration purposes. Free-floating code in our examples implies the code is part of some function.<br />
<br />
==Declaration==<br />
Unlike variables, functions do not need to be declared before you use them. Functions have two pieces, the '''signature''' and the '''body'''. The signature contains the name of your function and the parameters it will accept. The body is the contents of its code.<br />
<br />
Example of a function:<br />
<pawn><br />
int AddTwoNumbers(int first, int second)<br />
{<br />
int sum = first + second;<br />
return sum;<br />
}</pawn><br />
<br />
This is a simple function. The prototype is this line:<br />
<pawn>int AddTwoNumbers(int first, int second)</pawn><br />
<br />
Broken down, it means:<br />
*<tt>int</tt> - Return value type (integer).<br />
*<tt>AddTwoNumbers</tt> - Name of the function.<br />
*<tt>int first</tt> - First parameter, an integer.<br />
*<tt>int second</tt> - Second parameter, an integer.<br />
<br />
The body is a block of code. It creates a new variable, called <tt>sum</tt>, and assigns it the value of the two parameters added together (more on expressions later). The important thing to notice is the <tt>return</tt> statement, which tells the function to end and return a value to the caller of the function. All functions return something on completion, unless they return a special type called <tt>void</tt>.<br />
<br />
A function can accept any type of input, and it can return any non-array type.<br />
<br />
You can, of course, pass variables to functions:<br />
<pawn>int numbers[3] = {1, 2, 0};<br />
<br />
numbers[2] = AddTwoNumbers(numbers[0], numbers[1]);</pawn><br />
<br />
Note that cells are passed '''by value'''. That is, their value cannot be changed by the function. For example:<br />
<pawn>int a = 5;<br />
<br />
ChangeValue(a);<br />
<br />
ChangeValue(b)<br />
{<br />
b = 5;<br />
}</pawn><br />
<br />
This code would not change the value of <tt>a</tt>. That is because a copy of the value in <tt>a</tt> is passed instead of <tt>a</tt> itself. <br />
<br />
More examples of functions will be provided throughout the article.<br />
<br />
==Publics==<br />
Public functions are used to implement callbacks. You should not create a public function unless it is specifically implementing a callback. For example, here are two callbacks from <tt>sourcemod.inc</tt>:<br />
<br />
<pawn>forward void OnPluginStart();<br />
forward void OnClientDisconnected(int client);</pawn><br />
<br />
To implement and receive these two events, you would write functions as such:<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
/* Code here */<br />
}<br />
<br />
public void OnClientDisconnected(int client)<br />
{<br />
/* Code here */<br />
}</pawn><br />
<br />
The '''public''' keyword signals to the parent application that it should attach the function to the appropriate forwarded event.<br />
<br />
==Natives==<br />
Natives are builtin functions provided by SourceMod. You can call them as if they were a normal function. For example, SourceMod has the following function:<br />
<br />
<pawn>native float FloatRound(float num);</pawn><br />
<br />
It can be called like so:<br />
<pawn>int rounded = FloatRound(5.2); // rounded will be 5</pawn><br />
<br />
==Array Parameters==<br />
You can pass arrays or Strings as parameters. It is important to note that these are passed '''by reference'''. That is, rather than making a copy of the data, the data is referenced directly. There is a simple way of explaining this more concretely.<br />
<br />
<pawn><br />
int example[] = {1, 2, 3, 4, 5};<br />
<br />
ChangeArray(example, 2, 29);<br />
<br />
void ChangeArray(int[] array, int index, int value)<br />
{<br />
array[index] = value;<br />
}</pawn><br />
<br />
The function sets the given index in the array to a given value. When it is run on our example array, it changes index 2 to from the value 3 to 29. I.e.:<br />
<pawn>example[2] = 29;</pawn><br />
<br />
Note two important things here. First, arrays are not copied when they are passed to functions - they are passed ''by reference'', so the view of the array is consistent at all times. Second, the brackets changed position in our function signature. This is because our function accepts an array of any size, and since we don't know the size, we must use the dynamic array syntax.<br />
<br />
To prevent an array from being modified in a function, you can mark it as <tt>const</tt>. This will raise an error on code that attempts to modify it. For example:<br />
<br />
<pawn>void CantChangeArray(const array[], int index, int value)<br />
{<br />
array[index] = value; //Won't compile<br />
}</pawn><br />
<br />
It is a good idea to use <tt>const</tt> in array parameters if you know the array won't be modified; this can prevent coding mistakes.<br />
<br />
=Expressions=<br />
Expressions are exactly the same as they are in mathematics. They are groups of operators/symbols which evaluate to one piece of data. They are often parenthetical (comprised of parenthesis). They contain a strict "order of operations." They can contain variables, functions, numbers, and expressions themselves can be nested inside other expressions, or even passed as parameters.<br />
<br />
The simplest expression is a single number. For example:<br />
<pawn><br />
0; //Returns the number 0<br />
(0); //Returns the number 0 as well<br />
</pawn><br />
<br />
Although expressions can return any value, they are also said to either return ''zero or non-zero''. In that sense, ''zero'' is ''false'', and ''non-zero'' is ''true''. For example, -1 is '''true''' in Pawn, since it is non-zero. Do not assume negative numbers are false.<br />
<br />
The order of operations for expressions is similar to C. PMDAS: Parenthesis, Multiplication, Division, Addition, Subtraction. Here are some example expressions:<br />
<pawn><br />
5 + 6; //Evaluates to 11<br />
5 * 6 + 3; //Evaluates to 33<br />
5 * (6 + 3); //Evaluates to 45<br />
5.0 + 2.3; //Evaluates to 7.3<br />
(5 * 6) % 7; //Modulo operator, evaluates to 2<br />
(5 + 3) / 2 * 4 - 9; //Evaluates to -8<br />
</pawn><br />
<br />
As noted, expressions can contain variables, or even functions:<br />
<pawn><br />
int a = 5 * 6;<br />
int b = a * 3; //Evaluates to 90<br />
int c = AddTwoNumbers(a, b) + (a * b);<br />
</pawn><br />
<br />
Note: String manipulation routines may be found in the string.inc file located in the include subdirectory. They may be browsed through the [http://docs.sourcemod.net/api/ API Reference] as well.<br />
<br />
==Operators==<br />
There are a few extra helpful operators in Pawn. The first set simplifies self-aggregation expressions. For example:<br />
<pawn>int a = 5;<br />
<br />
a = a + 5;</pawn><br />
<br />
Can be rewritten as:<br />
<pawn>int a = 5;<br />
a += 5;</pawn><br />
<br />
This is true of the following operators in Pawn:<br />
*Four-function: *, /, -, +<br />
*Bit-wise: |, &, ^, ~, <<, >><br />
<br />
Additionally, there are increment/decrement operators:<br />
<pawn>a = a + 1;<br />
a = a - 1;</pawn><br />
<br />
Can be simplified as:<br />
<pawn>a++;<br />
a--;</pawn><br />
<br />
As an advanced note, the ++ or -- can come before the variable (pre-increment, pre-decrement) or after the variable (post-increment, post-decrement). The difference is in how the rest of the expression containing them sees their result.<br />
<br />
* ''Pre:'' The variable is incremented before evaluation, and the rest of the expression sees the new value.<br />
* ''Post:'' The variable is incremented after evaluation, and the rest of the expression sees the old value.<br />
<br />
In other words, <tt>a++</tt> evaluates to the value of <tt>a</tt> while <tt>++a</tt> evaluates to the value of <tt>a + 1</tt>. In both cases <tt>a</tt> is incremented by <tt>1</tt>.<br />
<br />
For example:<br />
<br />
<pawn>int a = 5;<br />
int b = a++; // b = 5, a = 6 (1)<br />
int c = ++a; // a = 7, c = 7 (2)<br />
</pawn><br />
<br />
In (1) <tt>b</tt> is assigned <tt>a</tt>'s ''old'' value ''before'' it is incremented to <tt>6</tt>, but in (2) <tt>c</tt> is assigned <tt>a</tt>'s ''int'' value ''after'' it is incremented to <tt>7</tt>.<br />
<br />
==Comparison Operators==<br />
There are six operators for comparing two values numerically, and the result is either true (non-zero) or false (zero):<br />
*<tt>a == b</tt> - True if a and b have the same value.<br />
*<tt>a != b</tt> - True if a and b have different values.<br />
*<tt>a &gt; b</tt> - True if a is greater than b<br />
*<tt>a &gt;= b</tt> - True if a is greater than or equal to b<br />
*<tt>a &lt; b</tt> - True if a is less than b<br />
*<tt>a &lt;= b</tt> - True if a is less than or equal to b<br />
<br />
For example:<br />
<pawn><br />
(1 != 3); //Evaluates to true because 1 is not equal to 3.<br />
(3 + 3 == 6); //Evaluates to true because 3+3 is 6.<br />
(5 - 2 >= 4); //Evaluates to false because 3 is less than 4.<br />
</pawn><br />
<br />
Note that these operators do not work on arrays or strings. That is, you cannot compare either using <tt>==</tt>.<br />
<br />
==Truth Operators==<br />
These truth values can be combined using three boolean operators:<br />
*<tt>a && b</tt> - True if both a and b are true. False if a or b (or both) is false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>&&</tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 0<br />
|-<br />
! 1<br />
| 0 || 1<br />
|}<br />
*<tt>a || b</tt> - True if a or b (or both) is true. False if both a and b are false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt><nowiki>||</nowiki></tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 1<br />
|-<br />
! 1<br />
| 1 || 1<br />
|}<br />
*<tt>!a</tt> - True if a is false. False if a is true.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>!</tt> !! 0 !! 1<br />
|- <br />
!<br />
| 1 || 0<br />
|}<br />
<br />
For example:<br />
<pawn><br />
(1 || 0); //Evaluates to true because the expression 1 is true<br />
(1 && 0); //Evaluates to false because the expression 0 is false<br />
(!1 || 0); //Evaluates to false because !1 is false.<br />
</pawn><br />
<br />
==Left/Right Values==<br />
Two important concepts are left-hand and right-hand values, or l-values and r-values. An l-value is what appears on the left-hand side of a variable assignment, and an r-value is what appears on the right side of a variable assignment.<br />
<br />
For example:<br />
<pawn><br />
int a = 5;</pawn><br />
<br />
In this example <tt>a</tt> is an l-value and <tt>5</tt> is an r-value.<br />
<br />
The rules:<br />
*'''Expressions are never l-values'''.<br />
*'''Variables are both l-values and r-values'''.<br />
<br />
=Conditionals=<br />
Conditional statements let you only run code if a certain condition is matched.<br />
<br />
==If Statements==<br />
If statements test one or more conditions. For example:<br />
<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code that will run if the expression was true */<br />
}</pawn><br />
<br />
They can be extended to handle more cases as well:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 6)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 7)<br />
{<br />
/* Code */<br />
}</pawn><br />
<br />
You can also handle the case of no expression being matched. For example:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else<br />
{<br />
/* Code that will run if no expressions were true */<br />
}</pawn><br />
<br />
==Switch Statements==<br />
Switch statements are restricted if statements. They test one expression for a series of possible values. For example:<br />
<br />
<pawn><br />
switch (a)<br />
{<br />
case 5:<br />
{<br />
/* code */<br />
}<br />
case 6:<br />
{<br />
/* code */<br />
}<br />
case 7:<br />
{<br />
/* code */<br />
}<br />
case 8, 9, 10:<br />
{<br />
/* Code */<br />
}<br />
default:<br />
{<br />
/* will run if no case matched */<br />
}<br />
}</pawn><br />
<br />
Unlike some other languages, switches are not fall-through. That is, multiple cases will never be run. When a case matches its code is executed, and the switch is then immediately terminated.<br />
<br />
=Loops=<br />
Loops allow you to conveniently repeat a block of code while a given condition remains true. <br />
<br />
==For Loops==<br />
For loops are loops which have four parts:<br />
*The '''initialization''' statement - run once before the first loop.<br />
*The '''condition''' statement - checks whether the next loop should run, including the first one. The loop terminates when this expression evaluates to false.<br />
*The '''iteration''' statement - run after each loop.<br />
*The '''body''' block - run each time the '''condition''' statement evaluates to true.<br />
<br />
<pawn><br />
for ( /* initialization */ ; /* condition */ ; /* iteration */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
A simple example is a function to sum an array:<br />
<pawn><br />
int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};<br />
int sum = SumArray(array, 10);<br />
<br />
int SumArray(const int array[], int count)<br />
{<br />
int total;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
total += array[i];<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
Broken down:<br />
*<tt>int i = 0</tt> - Creates a new variable for the loop, sets it to 0.<br />
*<tt>i < count</tt> - Only runs the loop if <tt>i</tt> is less than <tt>count</tt>. This ensures that the loop stops reading at a certain point. In this case, we don't want to read invalid indexes in the array.<br />
*<tt>i++</tt> - Increments <tt>i</tt> by one after each loop. This ensures that the loop doesn't run forever; eventually <tt>i</tt> will become too big and the loop will end.<br />
<br />
Thus, the <tt>SumArray</tt> function will loop through each valid index of the array, each time adding that value of the array into a sum. For loops are very common for processing arrays like this.<br />
<br />
==While Loops==<br />
While loops are less common than for loops but are actually the simplest possible loop. They have only two parts:<br />
*The '''condition''' statement - checked before each loop. The loop terminates when it evaluates to false.<br />
*The '''body''' block - run each time through the loop.<br />
<br />
<pawn><br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
As long as the condition expression remains true, the loop will continue. Every for loop can be rewritten as a while loop:<br />
<br />
<pawn><br />
/* initialization */<br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
/* iteration */<br />
}<br />
</pawn><br />
<br />
Here is the previous for loop rewritten as a while loop:<br />
<pawn><br />
int SumArray(const int array[], int count)<br />
{<br />
int total, i;<br />
<br />
while (i < count)<br />
{<br />
total += array[i];<br />
i++;<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
There are also '''do...while''' loops which are even less common. These are the same as while loops except the condition check is AFTER each loop, rather than before. This means the loop is always run at least once. For example:<br />
<br />
<pawn><br />
do<br />
{<br />
/* body */<br />
}<br />
while ( /* condition */ );<br />
</pawn><br />
<br />
==Loop Control==<br />
There are two cases in which you want to selectively control a loop:<br />
*'''skipping''' one iteration of the loop but continuing as normal, or;<br />
*'''breaking''' the loop entirely before it's finished.<br />
<br />
Let's say you have a function which takes in an array and searches for a matching number. You want it to stop once the number is found:<br />
<pawn><br />
/**<br />
* Returns the array index where the value is, or -1 if not found.<br />
*/<br />
int SearchInArray(const int array[], int count, int value)<br />
{<br />
int index = -1;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
if (array[i] == value)<br />
{<br />
index = i;<br />
break;<br />
}<br />
}<br />
<br />
return index;<br />
}</pawn><br />
<br />
Certainly, this function could simply <tt>return i</tt> instead, but the example shows how <tt>break</tt> will terminate the loop.<br />
<br />
Similarly, the <tt>continue</tt> keyword skips an iteration of a loop. For example, let's say we wanted to sum all even numbers:<br />
<pawn><br />
int SumEvenNumbers(const int array[], int count)<br />
{<br />
int sum;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
/* If divisibility by 2 is 1, we know it's odd */<br />
if (array[i] % 2 == 1)<br />
{<br />
/* Skip the rest of this loop iteration */<br />
continue;<br />
}<br />
sum += array[i];<br />
}<br />
<br />
return sum;<br />
}</pawn><br />
<br />
=Scope=<br />
Scope refers to the '''visibility''' of code. That is, code at one level may not be "visible" to code at another level. For example:<br />
<br />
<pawn><br />
int A, B, C;<br />
<br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function2();<br />
}<br />
<br />
void Function2()<br />
{<br />
int C;<br />
}</pawn><br />
<br />
In this example, <tt>A</tt>, <tt>B</tt>, and <tt>C</tt> exist at '''global scope'''. They can be seen by any function. However, the <tt>B</tt> in <tt>Function1</tt> is not the same variable as the <tt>B</tt> at the global level. Instead, it is at '''local scope''', and is thus a '''local variable'''.<br />
<br />
Similarly, <tt>Function1</tt> and <tt>Function2</tt> know nothing about each other's variables.<br />
<br />
Not only is the variable private to <tt>Function1</tt>, but it is re-created each time the function is invoked. Imagine this:<br />
<pawn><br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function1();<br />
}</pawn><br />
<br />
In the above example, <tt>Function1</tt> calls itself. Of course, this is infinite recursion (a bad thing), but the idea is that each time the function runs, there is a new copy of <tt>B</tt>. When the function ends, <tt>B</tt> is destroyed, and the value is lost.<br />
<br />
This property can be simplified by saying that a variable's scope is equal to the nesting level it is in. That is, a variable at global scope is visible globally to all functions. A variable at local scope is visible to all code blocks "beneath" its nesting level. For example:<br />
<br />
<pawn>void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
A = 5;<br />
}<br />
}</pawn><br />
<br />
The above code is valid since A's scope extends throughout the function. The following code, however, is not valid:<br />
<pawn><br />
void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
int B = 5;<br />
}<br />
<br />
B = 5;<br />
}</pawn><br />
<br />
Notice that <tt>B</tt> is declared in a new code block. That means <tt>B</tt> is only accessible to that code block (and all sub-blocks nested within). As soon as the code block terminates, <tt>B</tt> is no longer valid.<br />
<br />
=Dynamic Arrays=<br />
Dynamic arrays are arrays which don't have a hardcoded size. For example:<br />
<br />
<pawn>void Function1(int size)<br />
{<br />
int array[size];<br />
<br />
/* Code */<br />
}</pawn><br />
<br />
Dynamic arrays can have any expression as their size as long as the expression evaluates to a number larger than 0. Like normal arrays, SourcePawn does not know the array size after it is created; you have to save it if you want it later.<br />
<br />
Dynamic arrays are only valid at the local scope level, since code cannot exist globally.<br />
<br />
=Extended Variable Declarations=<br />
Variables can be declared in more ways than simply <tt>int float or char</tt>.<br />
<br />
==static==<br />
The <tt>static</tt> keyword is available at global and local scope. It has different meanings in each.<br />
<br />
===Global static===<br />
A global static variable can only be accessed from within the same file. For example:<br />
<br />
<pawn>//file1.inc<br />
static float g_value1 = 0.15f;<br />
<br />
//file2.inc<br />
static float g_value2 = 0.15f;</pawn><br />
<br />
If a plugin includes both of these files, it will not be able to use either <tt>g_value1</tt> or <tt>g_value2</tt>. This is a simple information hiding mechanism, and is similar to declaring member variables as <tt>private</tt> in languages like C++, Java, or C#.<br />
<br />
===Local static===<br />
A local static variable is a global variable that is only visible from its local lexical scope. For example:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
static int counter = -1;<br />
<br />
counter += inc;<br />
<br />
return counter;<br />
}</pawn><br />
<br />
In this example, <tt>counter</tt> is technically a global variable -- it is initialized once to -1 and is never initialized again. It does not exist on the stack. That means each time <tt>MyFunction</tt> runs, the <tt>counter</tt> variable and its storage in memory is the same.<br />
<br />
Take this example:<br />
<pawn>MyFunction(5);<br />
MyFunction(6);<br />
MyFunction(10);</pawn><br />
<br />
In this example, <tt>counter</tt> will be <tt>-1 + 5 + 6 + 10</tt>, or <tt>20</tt>, because it persists beyond the frame of the function. Note this may pose problems for recursive functions: if your function may be recursive, then <tt>static</tt> is usually not a good idea unless your code is re-entrant. <br />
<br />
The benefit of a local static variable is that you don't have to clutter your script with global variables. As long as the variable doesn't need to be read by another function, you can squirrel it inside the function and its persistence will be guaranteed.<br />
<br />
Note that statics can exist in any local scope:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
if (inc > 0)<br />
{<br />
static int counter;<br />
return (counter += inc);<br />
}<br />
return -1;<br />
}</pawn><br />
<br />
[[Category:SourceMod Scripting]]<br />
<br />
{{LanguageSwitch}}</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Introduction_to_SourcePawn_1.7&diff=10203Ru:Introduction to SourcePawn 1.72016-08-26T16:35:34Z<p>MAGNAT2645: /* Присваивание */</p>
<hr />
<div>This guide is designed to give you a very basic overview to fundamentals of scripting in SourcePawn. [[Pawn]] is a "scripting" language used to embed functionality in other programs. That means it is not a standalone language, like C++ or Java, and its details will differ based on the application. SourcePawn is the version of Pawn used in [[SourceMod]].<br />
<br />
This guide does not tell you how to write SourceMod plugins; it is intended as an overview of the syntax and semantics of the language instead. Read the separate article, [[Introduction to SourceMod Plugins]] for SourceMod API specifics. <br />
<br />
=Не программное введение=<br />
This section is intended for non-programmers. If you're still confused, you may want to pick up a book on another language, such as PHP, Python, or Java, to get a better idea of what programming is like.<br />
<br />
==Символы/Ключевые слова==<br />
A symbol is a series of letters, numbers, and/or underscores, that uniquely represents something. Symbols are case-sensitive, and usually start with a letter.<br />
<br />
There are a few reserved symbols that have special meaning. For example, <tt>if</tt>, <tt>for</tt>, and <tt>return</tt> are special constructs in the language that will explained later. They cannot be used as symbol names.<br />
<br />
==Переменные==<br />
There a few important constructs you should know before you begin to script. The first is a '''variable'''. A variable is a symbol, or name, that holds data. For example, the variable "a" could hold the number "2", "16", "0", et cetera. Since a variable holds data, it also allocates the memory needed to store that data.<br />
<br />
In addition to a name, variables have a '''type'''. A type tells the program how to interpret the data, and how much memory the data will use. Pawn has three types of data that are most commonly used:<br />
* Integers, using the <tt>int</tt> type. Integer types may store a whole number from -2147483648 to 2147483647.<br />
* Floats, using the <tt>float</tt> type. Float types may store fractional numbers in a huge range, though they are not as precise as integers.<br />
* Characters, using the <tt>char</tt> type. Character types store one byte of character information, typically an [http://www.asciitable.com/ ASCII] character.<br />
* Booleans, using the <tt>bool</tt> type. Booleans store either true or false.<br />
<br />
Пример создания переменных и добавление значений:<br />
<br />
<pawn>int money = 5400;<br />
float percent = 67.3;<br />
bool enabled = false;<br />
</pawn><br />
<br />
==Функции==<br />
The next important concept is '''functions'''. Functions are symbols or names that perform an action. When you invoke, or call them, they carry out a specific sequence of code and then return a result. There are a few types of functions, but every function is activated the same way. Example:<br />
<br />
<pawn><br />
show(56); // Calls the "show" function, and gives it the number 56.<br />
enable(); // Calls the "enable" function with no values.<br />
bool visible = show(a); //Calls the "show" function, stores its result in a variable.<br />
</pawn><br />
<br />
Every piece of data passed to a function is called a '''parameter'''. A function can have any number of parameters (there is a "reasonable" limit of 32 in SourceMod). Parameters will be explained further in the article.<br />
<br />
==Комментарии==<br />
Знайте, что любой текст после "//" помечается как "комментарий" и это не актуальный (компилятор будет игнорировать комментарии) код. Существует два стиля комментариев:<br />
*<tt>//</tt> - Двойной слэш, всё на этой линии игнорируется.<br />
*<tt>/* */</tt> - Многострочный комментарий, всё между звёздочками игнорируется.<br />
<br />
==Блок кодирования==<br />
Следующей концепцией является блок кодирования. Вы можете групповать код в "блоки", перечисляя его через { и }. Это эффективней делает один большой блок кода из нескольких частей. Для примера:<br />
<br />
<pawn>{<br />
здесь;<br />
есть;<br />
немного;<br />
кода;<br />
}</pawn><br />
<br />
Block coding using braces is used everywhere in programming. Blocks of code can be nested within each other. It is a good idea to adapt a consistent and readable indentation style early on to prevent spaghetti-looking code.<br />
<br />
=Парадигмы языка=<br />
Pawn may seem similar to other languages, like C, but it has fundamental differences. It is not important that you immediately understand these differences, but they may be helpful if you're familiar with another language already.<br />
*'''Pawn is sort of typed.''' Before SourceMod 1.7, Pawn did not have types. Older code and older natives will reflect this by using tags and the <tt>new</tt> keyword. As of SourceMod 1.7, we recommend that all code use types. For more information see [[SourcePawn Transitional Syntax]].<br />
*'''Pawn is not garbage collected.''' Pawn, as a language, has no built-in memory allocation, and thus has no garbage. If a function allocates memory, you may be responsible for freeing it.<br />
*'''Pawn is not object oriented.''' Pawn does not have structs or objects. As of SourceMod 1.7, it has limited sugaring for treating some data types as objects, but users cannot create their own objects or classes.<br />
*'''Pawn is single-threaded.''' As of this writing, Pawn is not thread safe. <br />
*'''Pawn is compiled.''' Pawn is compiled to an intermediate, machine-independent code, which is stored in a ".smx" file. When loading .smx files, SourceMod translates this code to machine code for the platform and CPU it's running on.<br />
<br />
Early language design decisions were made by ITB CompuPhase. It is designed for low-level embedded devices and is thus very small and very fast.<br />
<br />
=Переменные=<br />
На данный момент Pawn поддерживает следующие базовые типы переменных:<br />
*<tt>bool</tt> - true или false. (Правда или ложь)<br />
*<tt>char</tt> - 8-битный символ ASCII.<br />
*<tt>int</tt> - 32-битное целое число.<br />
*<tt>float</tt> - 32-битное число с плавающей точкой IEEE-754.<br />
*<tt>Handle</tt> - базовый тип объекта SourceMod.<br />
<br />
Other types may exist when defined in include files - for example, enums create new types for named integers, and many types derive from <tt>Handle</tt>.<br />
<br />
Strings, currently, are 0-terminated arrays of <tt>char</tt>s. They're described a little further ahead.<br />
<br />
==Объяснение==<br />
Ниже мы приложили немного примеров объявлений переменных, между правильными и неправильными. Имейте ввиду, что в SourcePawn был добавлен новый синтакс, и он указан ниже. Старый код может использовать старый синтакс объявления, который больше не поддерживается.<br />
<br />
<pawn><br />
int a = 5;<br />
float b = 5.0;<br />
bool c = true;<br />
bool d = false;<br />
</pawn><br />
<br />
Неправильное использование переменных:<br />
<pawn><br />
int a = 5.0; // Несоответствие типов. 5.0 это число с плавающей точкой.<br />
float b = 5; // Несоответствие типов. 5 это целое число.<br />
</pawn><br />
<br />
Если значение переменной не указано, оно будет установлено на 0. Пример:<br />
<pawn><br />
int a; // Устанавливается на 0<br />
float b; // Устанавливается на 0.0<br />
bool c; // Устанавливается на false<br />
</pawn><br />
<br />
==Присваивание==<br />
Содержимое переменной может быть переназначено после того, как она была создана. Пример:<br />
<pawn>int a;<br />
float b;<br />
bool c;<br />
<br />
a = 5;<br />
b = 5.0;<br />
c = true;<br />
</pawn><br />
<br />
=Массивы=<br />
An array is a sequence of data in a list. Arrays are useful for storing multiple pieces of data in one variable, or mapping one type of data to another.<br />
<br />
==Объяснение==<br />
An array is declared using brackets. Some examples of arrays:<br />
<pawn><br />
int players[32]; // Содержит 32 целых чисел.<br />
float origin[3]; // Содержит 3 числа с плавающей точкой<br />
</pawn><br />
<br />
By default, arrays are initialized to 0. You can assign them different default values, however:<br />
<pawn><br />
int numbers[5] = {1, 2, 3, 4, 5}; // Stores 1, 2, 3, 4, 5.<br />
float origin[3] = {1.0, 2.0, 3.0}; // Stores 1.0, 2.0, 3.0.<br />
</pawn><br />
<br />
You can leave out the array size if you're going to pre-assign data to it. For example:<br />
<pawn><br />
int numbers[] = {1, 3, 5, 7, 9};<br />
</pawn><br />
<br />
The compiler will automatically deduce that you intended an array of size 5.<br />
<br />
When array is declared with brackets after its name, Pawn considers that array to have a '''fixed size'''. The size of a fixed-size array is always known. Some arrays can be '''dynamically sized''', by putting the brackets before the name. For example,<br />
<br />
<pawn><br />
int[] numbers = new int[MaxClients]<br />
</pawn><br />
<br />
This creates an array of size <tt>MaxClients</tt>, which could be anything, so the size of the array is not known until the array is allocated.<br />
<br />
==Использование==<br />
Using an array is just like using a normal variable. The only difference is the array must be '''indexed'''. Indexing an array means choosing the element which you wish to use.<br />
<br />
For example, here is an example of the above code using indexes:<br />
<pawn><br />
int numbers[5];<br />
float origin[3];<br />
<br />
numbers[0] = 1;<br />
numbers[1] = 2;<br />
numbers[2] = 3;<br />
numbers[3] = 4;<br />
numbers[4] = 5;<br />
origin[0] = 1.0;<br />
origin[1] = 2.0;<br />
origin[2] = 3.0;<br />
</pawn><br />
<br />
Note that the '''index''' is what's in between the brackets. The index always starts from 0. That is, if an array has N elements, its valid indexes are from 0 to N-1. Accessing the data at these indexes works like a normal variable.<br />
<br />
Using an incorrect index will cause an error. For example:<br />
<pawn><br />
int numbers[5];<br />
<br />
numbers[5] = 20;</pawn><br />
<br />
This may look correct, but 5 is not a valid index. The highest valid index is 4.<br />
<br />
You can use any expression as an index. For example:<br />
<pawn>int a, numbers[5];<br />
<br />
a = 1; // Устанавливаем значение a = 1<br />
numbers[a] = 4; // Set numbers[1] = 4<br />
numbers[numbers[a]] = 2; // Set numbers[4] = 2<br />
</pawn><br />
<br />
Expressions will be discussed in depth later in the article.<br />
<br />
=Строки=<br />
Strings are a construct for storing text (or even raw binary data). A string is just an array of characters, except that the final character must be 0 (called the null terminator). Without a null terminator, Pawn would not know where to stop reading the string. All strings are [http://en.wikipedia.org/wiki/UTF-8 UTF-8] in SourcePawn.<br />
<br />
In general, you must have an idea of how large a string will be before you store it. SourcePawn does not yet have the capability of pre-determining storage space for strings.<br />
<br />
==Использование==<br />
Обычно строки объявляются в виде массивов. Пример:<br />
<pawn><br />
char message[] = "Привет!";<br />
char clams[6] = "Мидии";<br />
</pawn><br />
<br />
Это эквивалентно можно сделать:<br />
<pawn><br />
char message[7];<br />
char clams[6];<br />
<br />
message[0] = 'П';<br />
message[1] = 'р';<br />
message[2] = 'и';<br />
message[3] = 'в';<br />
message[4] = 'е';<br />
message[5] = 'т';<br />
message[6] = '!';<br />
message[7] = 0;<br />
clams[0] = 'м';<br />
clams[1] = 'и';<br />
clams[2] = 'д';<br />
clams[3] = 'и';<br />
clams[4] = 'и';<br />
clams[5] = 0;<br />
</pawn><br />
<br />
Although strings are rarely initialized in this manner, it is very important to remember the concept of the null terminator, which signals the end of a string. The compiler, and most SourceMod functions will automatically null-terminate for you, so it is mainly important when manipulating strings directly.<br />
<br />
Note that a string is enclosed in double-quotes, but a character is enclosed in single quotes.<br />
<br />
==Characters==<br />
A character of text can be used in either a String or a cell. For example:<br />
<pawn>char text[] = "Crab";<br />
char clam;<br />
<br />
clam = 'D'; //Set clam to 'D'<br />
text[0] = 'A'; //Change the 'C' to 'A', it is now 'Arab'<br />
clam = text[0]; //Set clam to 'A'<br />
text[1] = clam; //Change the 'r' to 'A', is is now 'AAab'<br />
</pawn><br />
<br />
What you can't do is mix character arrays with strings. The internal storage is different. For example:<br />
<pawn><br />
int clams[] = "Clams"; // Invalid.<br />
int clams[] = {'C', 'l', 'a', 'm', 's', 0}; // Valid, but NOT A STRING.<br />
</pawn><br />
<br />
=Functions=<br />
Functions, as stated before, are isolated blocks of code that perform an action. They can be invoked, or '''called''', with '''parameters''' that give specific options.<br />
<br />
There are two types of ways functions are called:<br />
*'''direct call''' - You specifically call a function in your code.<br />
*'''callback''' - The application calls a function in your code, as if it were an event trigger.<br />
<br />
There are six types of functions:<br />
*'''native''': A direct, internal function provided by the application.<br />
*'''public''': A callback function that is visible to the application and other scripts.<br />
*'''normal''': A normal function that only you can call.<br />
*'''static''': The scope of this function is restricted to the current file, can be used in combination with stock.<br />
*'''stock''': A normal function provided by an include file. If unused, it won't be compiled.<br />
*'''forward''': This function is a global event provided by the application. If you implement it, it will be a callback.<br />
<br />
All code in Pawn must exist in functions. This is in contrast to languages like PHP, Perl, and Python which let you write global code. That is because Pawn is a callback-based language: it responds to actions from a parent application, and functions must be written to handle those actions. Although our examples often contain free-floating code, this is purely for demonstration purposes. Free-floating code in our examples implies the code is part of some function.<br />
<br />
==Declaration==<br />
Unlike variables, functions do not need to be declared before you use them. Functions have two pieces, the '''signature''' and the '''body'''. The signature contains the name of your function and the parameters it will accept. The body is the contents of its code.<br />
<br />
Example of a function:<br />
<pawn><br />
int AddTwoNumbers(int first, int second)<br />
{<br />
int sum = first + second;<br />
return sum;<br />
}</pawn><br />
<br />
This is a simple function. The prototype is this line:<br />
<pawn>int AddTwoNumbers(int first, int second)</pawn><br />
<br />
Broken down, it means:<br />
*<tt>int</tt> - Return value type (integer).<br />
*<tt>AddTwoNumbers</tt> - Name of the function.<br />
*<tt>int first</tt> - First parameter, an integer.<br />
*<tt>int second</tt> - Second parameter, an integer.<br />
<br />
The body is a block of code. It creates a new variable, called <tt>sum</tt>, and assigns it the value of the two parameters added together (more on expressions later). The important thing to notice is the <tt>return</tt> statement, which tells the function to end and return a value to the caller of the function. All functions return something on completion, unless they return a special type called <tt>void</tt>.<br />
<br />
A function can accept any type of input, and it can return any non-array type.<br />
<br />
You can, of course, pass variables to functions:<br />
<pawn>int numbers[3] = {1, 2, 0};<br />
<br />
numbers[2] = AddTwoNumbers(numbers[0], numbers[1]);</pawn><br />
<br />
Note that cells are passed '''by value'''. That is, their value cannot be changed by the function. For example:<br />
<pawn>int a = 5;<br />
<br />
ChangeValue(a);<br />
<br />
ChangeValue(b)<br />
{<br />
b = 5;<br />
}</pawn><br />
<br />
This code would not change the value of <tt>a</tt>. That is because a copy of the value in <tt>a</tt> is passed instead of <tt>a</tt> itself. <br />
<br />
More examples of functions will be provided throughout the article.<br />
<br />
==Publics==<br />
Public functions are used to implement callbacks. You should not create a public function unless it is specifically implementing a callback. For example, here are two callbacks from <tt>sourcemod.inc</tt>:<br />
<br />
<pawn>forward void OnPluginStart();<br />
forward void OnClientDisconnected(int client);</pawn><br />
<br />
To implement and receive these two events, you would write functions as such:<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
/* Code here */<br />
}<br />
<br />
public void OnClientDisconnected(int client)<br />
{<br />
/* Code here */<br />
}</pawn><br />
<br />
The '''public''' keyword signals to the parent application that it should attach the function to the appropriate forwarded event.<br />
<br />
==Natives==<br />
Natives are builtin functions provided by SourceMod. You can call them as if they were a normal function. For example, SourceMod has the following function:<br />
<br />
<pawn>native float FloatRound(float num);</pawn><br />
<br />
It can be called like so:<br />
<pawn>int rounded = FloatRound(5.2); // rounded will be 5</pawn><br />
<br />
==Array Parameters==<br />
You can pass arrays or Strings as parameters. It is important to note that these are passed '''by reference'''. That is, rather than making a copy of the data, the data is referenced directly. There is a simple way of explaining this more concretely.<br />
<br />
<pawn><br />
int example[] = {1, 2, 3, 4, 5};<br />
<br />
ChangeArray(example, 2, 29);<br />
<br />
void ChangeArray(int[] array, int index, int value)<br />
{<br />
array[index] = value;<br />
}</pawn><br />
<br />
The function sets the given index in the array to a given value. When it is run on our example array, it changes index 2 to from the value 3 to 29. I.e.:<br />
<pawn>example[2] = 29;</pawn><br />
<br />
Note two important things here. First, arrays are not copied when they are passed to functions - they are passed ''by reference'', so the view of the array is consistent at all times. Second, the brackets changed position in our function signature. This is because our function accepts an array of any size, and since we don't know the size, we must use the dynamic array syntax.<br />
<br />
To prevent an array from being modified in a function, you can mark it as <tt>const</tt>. This will raise an error on code that attempts to modify it. For example:<br />
<br />
<pawn>void CantChangeArray(const array[], int index, int value)<br />
{<br />
array[index] = value; //Won't compile<br />
}</pawn><br />
<br />
It is a good idea to use <tt>const</tt> in array parameters if you know the array won't be modified; this can prevent coding mistakes.<br />
<br />
=Expressions=<br />
Expressions are exactly the same as they are in mathematics. They are groups of operators/symbols which evaluate to one piece of data. They are often parenthetical (comprised of parenthesis). They contain a strict "order of operations." They can contain variables, functions, numbers, and expressions themselves can be nested inside other expressions, or even passed as parameters.<br />
<br />
The simplest expression is a single number. For example:<br />
<pawn><br />
0; //Returns the number 0<br />
(0); //Returns the number 0 as well<br />
</pawn><br />
<br />
Although expressions can return any value, they are also said to either return ''zero or non-zero''. In that sense, ''zero'' is ''false'', and ''non-zero'' is ''true''. For example, -1 is '''true''' in Pawn, since it is non-zero. Do not assume negative numbers are false.<br />
<br />
The order of operations for expressions is similar to C. PMDAS: Parenthesis, Multiplication, Division, Addition, Subtraction. Here are some example expressions:<br />
<pawn><br />
5 + 6; //Evaluates to 11<br />
5 * 6 + 3; //Evaluates to 33<br />
5 * (6 + 3); //Evaluates to 45<br />
5.0 + 2.3; //Evaluates to 7.3<br />
(5 * 6) % 7; //Modulo operator, evaluates to 2<br />
(5 + 3) / 2 * 4 - 9; //Evaluates to -8<br />
</pawn><br />
<br />
As noted, expressions can contain variables, or even functions:<br />
<pawn><br />
int a = 5 * 6;<br />
int b = a * 3; //Evaluates to 90<br />
int c = AddTwoNumbers(a, b) + (a * b);<br />
</pawn><br />
<br />
Note: String manipulation routines may be found in the string.inc file located in the include subdirectory. They may be browsed through the [http://docs.sourcemod.net/api/ API Reference] as well.<br />
<br />
==Operators==<br />
There are a few extra helpful operators in Pawn. The first set simplifies self-aggregation expressions. For example:<br />
<pawn>int a = 5;<br />
<br />
a = a + 5;</pawn><br />
<br />
Can be rewritten as:<br />
<pawn>int a = 5;<br />
a += 5;</pawn><br />
<br />
This is true of the following operators in Pawn:<br />
*Four-function: *, /, -, +<br />
*Bit-wise: |, &, ^, ~, <<, >><br />
<br />
Additionally, there are increment/decrement operators:<br />
<pawn>a = a + 1;<br />
a = a - 1;</pawn><br />
<br />
Can be simplified as:<br />
<pawn>a++;<br />
a--;</pawn><br />
<br />
As an advanced note, the ++ or -- can come before the variable (pre-increment, pre-decrement) or after the variable (post-increment, post-decrement). The difference is in how the rest of the expression containing them sees their result.<br />
<br />
* ''Pre:'' The variable is incremented before evaluation, and the rest of the expression sees the new value.<br />
* ''Post:'' The variable is incremented after evaluation, and the rest of the expression sees the old value.<br />
<br />
In other words, <tt>a++</tt> evaluates to the value of <tt>a</tt> while <tt>++a</tt> evaluates to the value of <tt>a + 1</tt>. In both cases <tt>a</tt> is incremented by <tt>1</tt>.<br />
<br />
For example:<br />
<br />
<pawn>int a = 5;<br />
int b = a++; // b = 5, a = 6 (1)<br />
int c = ++a; // a = 7, c = 7 (2)<br />
</pawn><br />
<br />
In (1) <tt>b</tt> is assigned <tt>a</tt>'s ''old'' value ''before'' it is incremented to <tt>6</tt>, but in (2) <tt>c</tt> is assigned <tt>a</tt>'s ''int'' value ''after'' it is incremented to <tt>7</tt>.<br />
<br />
==Comparison Operators==<br />
There are six operators for comparing two values numerically, and the result is either true (non-zero) or false (zero):<br />
*<tt>a == b</tt> - True if a and b have the same value.<br />
*<tt>a != b</tt> - True if a and b have different values.<br />
*<tt>a &gt; b</tt> - True if a is greater than b<br />
*<tt>a &gt;= b</tt> - True if a is greater than or equal to b<br />
*<tt>a &lt; b</tt> - True if a is less than b<br />
*<tt>a &lt;= b</tt> - True if a is less than or equal to b<br />
<br />
For example:<br />
<pawn><br />
(1 != 3); //Evaluates to true because 1 is not equal to 3.<br />
(3 + 3 == 6); //Evaluates to true because 3+3 is 6.<br />
(5 - 2 >= 4); //Evaluates to false because 3 is less than 4.<br />
</pawn><br />
<br />
Note that these operators do not work on arrays or strings. That is, you cannot compare either using <tt>==</tt>.<br />
<br />
==Truth Operators==<br />
These truth values can be combined using three boolean operators:<br />
*<tt>a && b</tt> - True if both a and b are true. False if a or b (or both) is false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>&&</tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 0<br />
|-<br />
! 1<br />
| 0 || 1<br />
|}<br />
*<tt>a || b</tt> - True if a or b (or both) is true. False if both a and b are false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt><nowiki>||</nowiki></tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 1<br />
|-<br />
! 1<br />
| 1 || 1<br />
|}<br />
*<tt>!a</tt> - True if a is false. False if a is true.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>!</tt> !! 0 !! 1<br />
|- <br />
!<br />
| 1 || 0<br />
|}<br />
<br />
For example:<br />
<pawn><br />
(1 || 0); //Evaluates to true because the expression 1 is true<br />
(1 && 0); //Evaluates to false because the expression 0 is false<br />
(!1 || 0); //Evaluates to false because !1 is false.<br />
</pawn><br />
<br />
==Left/Right Values==<br />
Two important concepts are left-hand and right-hand values, or l-values and r-values. An l-value is what appears on the left-hand side of a variable assignment, and an r-value is what appears on the right side of a variable assignment.<br />
<br />
For example:<br />
<pawn><br />
int a = 5;</pawn><br />
<br />
In this example <tt>a</tt> is an l-value and <tt>5</tt> is an r-value.<br />
<br />
The rules:<br />
*'''Expressions are never l-values'''.<br />
*'''Variables are both l-values and r-values'''.<br />
<br />
=Conditionals=<br />
Conditional statements let you only run code if a certain condition is matched.<br />
<br />
==If Statements==<br />
If statements test one or more conditions. For example:<br />
<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code that will run if the expression was true */<br />
}</pawn><br />
<br />
They can be extended to handle more cases as well:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 6)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 7)<br />
{<br />
/* Code */<br />
}</pawn><br />
<br />
You can also handle the case of no expression being matched. For example:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else<br />
{<br />
/* Code that will run if no expressions were true */<br />
}</pawn><br />
<br />
==Switch Statements==<br />
Switch statements are restricted if statements. They test one expression for a series of possible values. For example:<br />
<br />
<pawn><br />
switch (a)<br />
{<br />
case 5:<br />
{<br />
/* code */<br />
}<br />
case 6:<br />
{<br />
/* code */<br />
}<br />
case 7:<br />
{<br />
/* code */<br />
}<br />
case 8, 9, 10:<br />
{<br />
/* Code */<br />
}<br />
default:<br />
{<br />
/* will run if no case matched */<br />
}<br />
}</pawn><br />
<br />
Unlike some other languages, switches are not fall-through. That is, multiple cases will never be run. When a case matches its code is executed, and the switch is then immediately terminated.<br />
<br />
=Loops=<br />
Loops allow you to conveniently repeat a block of code while a given condition remains true. <br />
<br />
==For Loops==<br />
For loops are loops which have four parts:<br />
*The '''initialization''' statement - run once before the first loop.<br />
*The '''condition''' statement - checks whether the next loop should run, including the first one. The loop terminates when this expression evaluates to false.<br />
*The '''iteration''' statement - run after each loop.<br />
*The '''body''' block - run each time the '''condition''' statement evaluates to true.<br />
<br />
<pawn><br />
for ( /* initialization */ ; /* condition */ ; /* iteration */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
A simple example is a function to sum an array:<br />
<pawn><br />
int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};<br />
int sum = SumArray(array, 10);<br />
<br />
int SumArray(const int array[], int count)<br />
{<br />
int total;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
total += array[i];<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
Broken down:<br />
*<tt>int i = 0</tt> - Creates a new variable for the loop, sets it to 0.<br />
*<tt>i < count</tt> - Only runs the loop if <tt>i</tt> is less than <tt>count</tt>. This ensures that the loop stops reading at a certain point. In this case, we don't want to read invalid indexes in the array.<br />
*<tt>i++</tt> - Increments <tt>i</tt> by one after each loop. This ensures that the loop doesn't run forever; eventually <tt>i</tt> will become too big and the loop will end.<br />
<br />
Thus, the <tt>SumArray</tt> function will loop through each valid index of the array, each time adding that value of the array into a sum. For loops are very common for processing arrays like this.<br />
<br />
==While Loops==<br />
While loops are less common than for loops but are actually the simplest possible loop. They have only two parts:<br />
*The '''condition''' statement - checked before each loop. The loop terminates when it evaluates to false.<br />
*The '''body''' block - run each time through the loop.<br />
<br />
<pawn><br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
As long as the condition expression remains true, the loop will continue. Every for loop can be rewritten as a while loop:<br />
<br />
<pawn><br />
/* initialization */<br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
/* iteration */<br />
}<br />
</pawn><br />
<br />
Here is the previous for loop rewritten as a while loop:<br />
<pawn><br />
int SumArray(const int array[], int count)<br />
{<br />
int total, i;<br />
<br />
while (i < count)<br />
{<br />
total += array[i];<br />
i++;<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
There are also '''do...while''' loops which are even less common. These are the same as while loops except the condition check is AFTER each loop, rather than before. This means the loop is always run at least once. For example:<br />
<br />
<pawn><br />
do<br />
{<br />
/* body */<br />
}<br />
while ( /* condition */ );<br />
</pawn><br />
<br />
==Loop Control==<br />
There are two cases in which you want to selectively control a loop:<br />
*'''skipping''' one iteration of the loop but continuing as normal, or;<br />
*'''breaking''' the loop entirely before it's finished.<br />
<br />
Let's say you have a function which takes in an array and searches for a matching number. You want it to stop once the number is found:<br />
<pawn><br />
/**<br />
* Returns the array index where the value is, or -1 if not found.<br />
*/<br />
int SearchInArray(const int array[], int count, int value)<br />
{<br />
int index = -1;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
if (array[i] == value)<br />
{<br />
index = i;<br />
break;<br />
}<br />
}<br />
<br />
return index;<br />
}</pawn><br />
<br />
Certainly, this function could simply <tt>return i</tt> instead, but the example shows how <tt>break</tt> will terminate the loop.<br />
<br />
Similarly, the <tt>continue</tt> keyword skips an iteration of a loop. For example, let's say we wanted to sum all even numbers:<br />
<pawn><br />
int SumEvenNumbers(const int array[], int count)<br />
{<br />
int sum;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
/* If divisibility by 2 is 1, we know it's odd */<br />
if (array[i] % 2 == 1)<br />
{<br />
/* Skip the rest of this loop iteration */<br />
continue;<br />
}<br />
sum += array[i];<br />
}<br />
<br />
return sum;<br />
}</pawn><br />
<br />
=Scope=<br />
Scope refers to the '''visibility''' of code. That is, code at one level may not be "visible" to code at another level. For example:<br />
<br />
<pawn><br />
int A, B, C;<br />
<br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function2();<br />
}<br />
<br />
void Function2()<br />
{<br />
int C;<br />
}</pawn><br />
<br />
In this example, <tt>A</tt>, <tt>B</tt>, and <tt>C</tt> exist at '''global scope'''. They can be seen by any function. However, the <tt>B</tt> in <tt>Function1</tt> is not the same variable as the <tt>B</tt> at the global level. Instead, it is at '''local scope''', and is thus a '''local variable'''.<br />
<br />
Similarly, <tt>Function1</tt> and <tt>Function2</tt> know nothing about each other's variables.<br />
<br />
Not only is the variable private to <tt>Function1</tt>, but it is re-created each time the function is invoked. Imagine this:<br />
<pawn><br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function1();<br />
}</pawn><br />
<br />
In the above example, <tt>Function1</tt> calls itself. Of course, this is infinite recursion (a bad thing), but the idea is that each time the function runs, there is a new copy of <tt>B</tt>. When the function ends, <tt>B</tt> is destroyed, and the value is lost.<br />
<br />
This property can be simplified by saying that a variable's scope is equal to the nesting level it is in. That is, a variable at global scope is visible globally to all functions. A variable at local scope is visible to all code blocks "beneath" its nesting level. For example:<br />
<br />
<pawn>void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
A = 5;<br />
}<br />
}</pawn><br />
<br />
The above code is valid since A's scope extends throughout the function. The following code, however, is not valid:<br />
<pawn><br />
void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
int B = 5;<br />
}<br />
<br />
B = 5;<br />
}</pawn><br />
<br />
Notice that <tt>B</tt> is declared in a new code block. That means <tt>B</tt> is only accessible to that code block (and all sub-blocks nested within). As soon as the code block terminates, <tt>B</tt> is no longer valid.<br />
<br />
=Dynamic Arrays=<br />
Dynamic arrays are arrays which don't have a hardcoded size. For example:<br />
<br />
<pawn>void Function1(int size)<br />
{<br />
int array[size];<br />
<br />
/* Code */<br />
}</pawn><br />
<br />
Dynamic arrays can have any expression as their size as long as the expression evaluates to a number larger than 0. Like normal arrays, SourcePawn does not know the array size after it is created; you have to save it if you want it later.<br />
<br />
Dynamic arrays are only valid at the local scope level, since code cannot exist globally.<br />
<br />
=Extended Variable Declarations=<br />
Variables can be declared in more ways than simply <tt>int float or char</tt>.<br />
<br />
==static==<br />
The <tt>static</tt> keyword is available at global and local scope. It has different meanings in each.<br />
<br />
===Global static===<br />
A global static variable can only be accessed from within the same file. For example:<br />
<br />
<pawn>//file1.inc<br />
static float g_value1 = 0.15f;<br />
<br />
//file2.inc<br />
static float g_value2 = 0.15f;</pawn><br />
<br />
If a plugin includes both of these files, it will not be able to use either <tt>g_value1</tt> or <tt>g_value2</tt>. This is a simple information hiding mechanism, and is similar to declaring member variables as <tt>private</tt> in languages like C++, Java, or C#.<br />
<br />
===Local static===<br />
A local static variable is a global variable that is only visible from its local lexical scope. For example:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
static int counter = -1;<br />
<br />
counter += inc;<br />
<br />
return counter;<br />
}</pawn><br />
<br />
In this example, <tt>counter</tt> is technically a global variable -- it is initialized once to -1 and is never initialized again. It does not exist on the stack. That means each time <tt>MyFunction</tt> runs, the <tt>counter</tt> variable and its storage in memory is the same.<br />
<br />
Take this example:<br />
<pawn>MyFunction(5);<br />
MyFunction(6);<br />
MyFunction(10);</pawn><br />
<br />
In this example, <tt>counter</tt> will be <tt>-1 + 5 + 6 + 10</tt>, or <tt>20</tt>, because it persists beyond the frame of the function. Note this may pose problems for recursive functions: if your function may be recursive, then <tt>static</tt> is usually not a good idea unless your code is re-entrant. <br />
<br />
The benefit of a local static variable is that you don't have to clutter your script with global variables. As long as the variable doesn't need to be read by another function, you can squirrel it inside the function and its persistence will be guaranteed.<br />
<br />
Note that statics can exist in any local scope:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
if (inc > 0)<br />
{<br />
static int counter;<br />
return (counter += inc);<br />
}<br />
return -1;<br />
}</pawn><br />
<br />
[[Category:SourceMod Scripting]]<br />
<br />
{{LanguageSwitch}}</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Introduction_to_SourcePawn_1.7&diff=10202Ru:Introduction to SourcePawn 1.72016-08-26T16:35:15Z<p>MAGNAT2645: /* Присваивание */</p>
<hr />
<div>This guide is designed to give you a very basic overview to fundamentals of scripting in SourcePawn. [[Pawn]] is a "scripting" language used to embed functionality in other programs. That means it is not a standalone language, like C++ or Java, and its details will differ based on the application. SourcePawn is the version of Pawn used in [[SourceMod]].<br />
<br />
This guide does not tell you how to write SourceMod plugins; it is intended as an overview of the syntax and semantics of the language instead. Read the separate article, [[Introduction to SourceMod Plugins]] for SourceMod API specifics. <br />
<br />
=Не программное введение=<br />
This section is intended for non-programmers. If you're still confused, you may want to pick up a book on another language, such as PHP, Python, or Java, to get a better idea of what programming is like.<br />
<br />
==Символы/Ключевые слова==<br />
A symbol is a series of letters, numbers, and/or underscores, that uniquely represents something. Symbols are case-sensitive, and usually start with a letter.<br />
<br />
There are a few reserved symbols that have special meaning. For example, <tt>if</tt>, <tt>for</tt>, and <tt>return</tt> are special constructs in the language that will explained later. They cannot be used as symbol names.<br />
<br />
==Переменные==<br />
There a few important constructs you should know before you begin to script. The first is a '''variable'''. A variable is a symbol, or name, that holds data. For example, the variable "a" could hold the number "2", "16", "0", et cetera. Since a variable holds data, it also allocates the memory needed to store that data.<br />
<br />
In addition to a name, variables have a '''type'''. A type tells the program how to interpret the data, and how much memory the data will use. Pawn has three types of data that are most commonly used:<br />
* Integers, using the <tt>int</tt> type. Integer types may store a whole number from -2147483648 to 2147483647.<br />
* Floats, using the <tt>float</tt> type. Float types may store fractional numbers in a huge range, though they are not as precise as integers.<br />
* Characters, using the <tt>char</tt> type. Character types store one byte of character information, typically an [http://www.asciitable.com/ ASCII] character.<br />
* Booleans, using the <tt>bool</tt> type. Booleans store either true or false.<br />
<br />
Пример создания переменных и добавление значений:<br />
<br />
<pawn>int money = 5400;<br />
float percent = 67.3;<br />
bool enabled = false;<br />
</pawn><br />
<br />
==Функции==<br />
The next important concept is '''functions'''. Functions are symbols or names that perform an action. When you invoke, or call them, they carry out a specific sequence of code and then return a result. There are a few types of functions, but every function is activated the same way. Example:<br />
<br />
<pawn><br />
show(56); // Calls the "show" function, and gives it the number 56.<br />
enable(); // Calls the "enable" function with no values.<br />
bool visible = show(a); //Calls the "show" function, stores its result in a variable.<br />
</pawn><br />
<br />
Every piece of data passed to a function is called a '''parameter'''. A function can have any number of parameters (there is a "reasonable" limit of 32 in SourceMod). Parameters will be explained further in the article.<br />
<br />
==Комментарии==<br />
Знайте, что любой текст после "//" помечается как "комментарий" и это не актуальный (компилятор будет игнорировать комментарии) код. Существует два стиля комментариев:<br />
*<tt>//</tt> - Двойной слэш, всё на этой линии игнорируется.<br />
*<tt>/* */</tt> - Многострочный комментарий, всё между звёздочками игнорируется.<br />
<br />
==Блок кодирования==<br />
Следующей концепцией является блок кодирования. Вы можете групповать код в "блоки", перечисляя его через { и }. Это эффективней делает один большой блок кода из нескольких частей. Для примера:<br />
<br />
<pawn>{<br />
здесь;<br />
есть;<br />
немного;<br />
кода;<br />
}</pawn><br />
<br />
Block coding using braces is used everywhere in programming. Blocks of code can be nested within each other. It is a good idea to adapt a consistent and readable indentation style early on to prevent spaghetti-looking code.<br />
<br />
=Парадигмы языка=<br />
Pawn may seem similar to other languages, like C, but it has fundamental differences. It is not important that you immediately understand these differences, but they may be helpful if you're familiar with another language already.<br />
*'''Pawn is sort of typed.''' Before SourceMod 1.7, Pawn did not have types. Older code and older natives will reflect this by using tags and the <tt>new</tt> keyword. As of SourceMod 1.7, we recommend that all code use types. For more information see [[SourcePawn Transitional Syntax]].<br />
*'''Pawn is not garbage collected.''' Pawn, as a language, has no built-in memory allocation, and thus has no garbage. If a function allocates memory, you may be responsible for freeing it.<br />
*'''Pawn is not object oriented.''' Pawn does not have structs or objects. As of SourceMod 1.7, it has limited sugaring for treating some data types as objects, but users cannot create their own objects or classes.<br />
*'''Pawn is single-threaded.''' As of this writing, Pawn is not thread safe. <br />
*'''Pawn is compiled.''' Pawn is compiled to an intermediate, machine-independent code, which is stored in a ".smx" file. When loading .smx files, SourceMod translates this code to machine code for the platform and CPU it's running on.<br />
<br />
Early language design decisions were made by ITB CompuPhase. It is designed for low-level embedded devices and is thus very small and very fast.<br />
<br />
=Переменные=<br />
На данный момент Pawn поддерживает следующие базовые типы переменных:<br />
*<tt>bool</tt> - true или false. (Правда или ложь)<br />
*<tt>char</tt> - 8-битный символ ASCII.<br />
*<tt>int</tt> - 32-битное целое число.<br />
*<tt>float</tt> - 32-битное число с плавающей точкой IEEE-754.<br />
*<tt>Handle</tt> - базовый тип объекта SourceMod.<br />
<br />
Other types may exist when defined in include files - for example, enums create new types for named integers, and many types derive from <tt>Handle</tt>.<br />
<br />
Strings, currently, are 0-terminated arrays of <tt>char</tt>s. They're described a little further ahead.<br />
<br />
==Объяснение==<br />
Ниже мы приложили немного примеров объявлений переменных, между правильными и неправильными. Имейте ввиду, что в SourcePawn был добавлен новый синтакс, и он указан ниже. Старый код может использовать старый синтакс объявления, который больше не поддерживается.<br />
<br />
<pawn><br />
int a = 5;<br />
float b = 5.0;<br />
bool c = true;<br />
bool d = false;<br />
</pawn><br />
<br />
Неправильное использование переменных:<br />
<pawn><br />
int a = 5.0; // Несоответствие типов. 5.0 это число с плавающей точкой.<br />
float b = 5; // Несоответствие типов. 5 это целое число.<br />
</pawn><br />
<br />
Если значение переменной не указано, оно будет установлено на 0. Пример:<br />
<pawn><br />
int a; // Устанавливается на 0<br />
float b; // Устанавливается на 0.0<br />
bool c; // Устанавливается на false<br />
</pawn><br />
<br />
==Присваивание==<br />
Variables can be re-assigned data after they are created. For example:<br />
Содержимое переменной может быть переназначено после того, как она была создана. Пример:<br />
<pawn>int a;<br />
float b;<br />
bool c;<br />
<br />
a = 5;<br />
b = 5.0;<br />
c = true;<br />
</pawn><br />
<br />
=Массивы=<br />
An array is a sequence of data in a list. Arrays are useful for storing multiple pieces of data in one variable, or mapping one type of data to another.<br />
<br />
==Объяснение==<br />
An array is declared using brackets. Some examples of arrays:<br />
<pawn><br />
int players[32]; // Содержит 32 целых чисел.<br />
float origin[3]; // Содержит 3 числа с плавающей точкой<br />
</pawn><br />
<br />
By default, arrays are initialized to 0. You can assign them different default values, however:<br />
<pawn><br />
int numbers[5] = {1, 2, 3, 4, 5}; // Stores 1, 2, 3, 4, 5.<br />
float origin[3] = {1.0, 2.0, 3.0}; // Stores 1.0, 2.0, 3.0.<br />
</pawn><br />
<br />
You can leave out the array size if you're going to pre-assign data to it. For example:<br />
<pawn><br />
int numbers[] = {1, 3, 5, 7, 9};<br />
</pawn><br />
<br />
The compiler will automatically deduce that you intended an array of size 5.<br />
<br />
When array is declared with brackets after its name, Pawn considers that array to have a '''fixed size'''. The size of a fixed-size array is always known. Some arrays can be '''dynamically sized''', by putting the brackets before the name. For example,<br />
<br />
<pawn><br />
int[] numbers = new int[MaxClients]<br />
</pawn><br />
<br />
This creates an array of size <tt>MaxClients</tt>, which could be anything, so the size of the array is not known until the array is allocated.<br />
<br />
==Использование==<br />
Using an array is just like using a normal variable. The only difference is the array must be '''indexed'''. Indexing an array means choosing the element which you wish to use.<br />
<br />
For example, here is an example of the above code using indexes:<br />
<pawn><br />
int numbers[5];<br />
float origin[3];<br />
<br />
numbers[0] = 1;<br />
numbers[1] = 2;<br />
numbers[2] = 3;<br />
numbers[3] = 4;<br />
numbers[4] = 5;<br />
origin[0] = 1.0;<br />
origin[1] = 2.0;<br />
origin[2] = 3.0;<br />
</pawn><br />
<br />
Note that the '''index''' is what's in between the brackets. The index always starts from 0. That is, if an array has N elements, its valid indexes are from 0 to N-1. Accessing the data at these indexes works like a normal variable.<br />
<br />
Using an incorrect index will cause an error. For example:<br />
<pawn><br />
int numbers[5];<br />
<br />
numbers[5] = 20;</pawn><br />
<br />
This may look correct, but 5 is not a valid index. The highest valid index is 4.<br />
<br />
You can use any expression as an index. For example:<br />
<pawn>int a, numbers[5];<br />
<br />
a = 1; // Устанавливаем значение a = 1<br />
numbers[a] = 4; // Set numbers[1] = 4<br />
numbers[numbers[a]] = 2; // Set numbers[4] = 2<br />
</pawn><br />
<br />
Expressions will be discussed in depth later in the article.<br />
<br />
=Строки=<br />
Strings are a construct for storing text (or even raw binary data). A string is just an array of characters, except that the final character must be 0 (called the null terminator). Without a null terminator, Pawn would not know where to stop reading the string. All strings are [http://en.wikipedia.org/wiki/UTF-8 UTF-8] in SourcePawn.<br />
<br />
In general, you must have an idea of how large a string will be before you store it. SourcePawn does not yet have the capability of pre-determining storage space for strings.<br />
<br />
==Использование==<br />
Обычно строки объявляются в виде массивов. Пример:<br />
<pawn><br />
char message[] = "Привет!";<br />
char clams[6] = "Мидии";<br />
</pawn><br />
<br />
Это эквивалентно можно сделать:<br />
<pawn><br />
char message[7];<br />
char clams[6];<br />
<br />
message[0] = 'П';<br />
message[1] = 'р';<br />
message[2] = 'и';<br />
message[3] = 'в';<br />
message[4] = 'е';<br />
message[5] = 'т';<br />
message[6] = '!';<br />
message[7] = 0;<br />
clams[0] = 'м';<br />
clams[1] = 'и';<br />
clams[2] = 'д';<br />
clams[3] = 'и';<br />
clams[4] = 'и';<br />
clams[5] = 0;<br />
</pawn><br />
<br />
Although strings are rarely initialized in this manner, it is very important to remember the concept of the null terminator, which signals the end of a string. The compiler, and most SourceMod functions will automatically null-terminate for you, so it is mainly important when manipulating strings directly.<br />
<br />
Note that a string is enclosed in double-quotes, but a character is enclosed in single quotes.<br />
<br />
==Characters==<br />
A character of text can be used in either a String or a cell. For example:<br />
<pawn>char text[] = "Crab";<br />
char clam;<br />
<br />
clam = 'D'; //Set clam to 'D'<br />
text[0] = 'A'; //Change the 'C' to 'A', it is now 'Arab'<br />
clam = text[0]; //Set clam to 'A'<br />
text[1] = clam; //Change the 'r' to 'A', is is now 'AAab'<br />
</pawn><br />
<br />
What you can't do is mix character arrays with strings. The internal storage is different. For example:<br />
<pawn><br />
int clams[] = "Clams"; // Invalid.<br />
int clams[] = {'C', 'l', 'a', 'm', 's', 0}; // Valid, but NOT A STRING.<br />
</pawn><br />
<br />
=Functions=<br />
Functions, as stated before, are isolated blocks of code that perform an action. They can be invoked, or '''called''', with '''parameters''' that give specific options.<br />
<br />
There are two types of ways functions are called:<br />
*'''direct call''' - You specifically call a function in your code.<br />
*'''callback''' - The application calls a function in your code, as if it were an event trigger.<br />
<br />
There are six types of functions:<br />
*'''native''': A direct, internal function provided by the application.<br />
*'''public''': A callback function that is visible to the application and other scripts.<br />
*'''normal''': A normal function that only you can call.<br />
*'''static''': The scope of this function is restricted to the current file, can be used in combination with stock.<br />
*'''stock''': A normal function provided by an include file. If unused, it won't be compiled.<br />
*'''forward''': This function is a global event provided by the application. If you implement it, it will be a callback.<br />
<br />
All code in Pawn must exist in functions. This is in contrast to languages like PHP, Perl, and Python which let you write global code. That is because Pawn is a callback-based language: it responds to actions from a parent application, and functions must be written to handle those actions. Although our examples often contain free-floating code, this is purely for demonstration purposes. Free-floating code in our examples implies the code is part of some function.<br />
<br />
==Declaration==<br />
Unlike variables, functions do not need to be declared before you use them. Functions have two pieces, the '''signature''' and the '''body'''. The signature contains the name of your function and the parameters it will accept. The body is the contents of its code.<br />
<br />
Example of a function:<br />
<pawn><br />
int AddTwoNumbers(int first, int second)<br />
{<br />
int sum = first + second;<br />
return sum;<br />
}</pawn><br />
<br />
This is a simple function. The prototype is this line:<br />
<pawn>int AddTwoNumbers(int first, int second)</pawn><br />
<br />
Broken down, it means:<br />
*<tt>int</tt> - Return value type (integer).<br />
*<tt>AddTwoNumbers</tt> - Name of the function.<br />
*<tt>int first</tt> - First parameter, an integer.<br />
*<tt>int second</tt> - Second parameter, an integer.<br />
<br />
The body is a block of code. It creates a new variable, called <tt>sum</tt>, and assigns it the value of the two parameters added together (more on expressions later). The important thing to notice is the <tt>return</tt> statement, which tells the function to end and return a value to the caller of the function. All functions return something on completion, unless they return a special type called <tt>void</tt>.<br />
<br />
A function can accept any type of input, and it can return any non-array type.<br />
<br />
You can, of course, pass variables to functions:<br />
<pawn>int numbers[3] = {1, 2, 0};<br />
<br />
numbers[2] = AddTwoNumbers(numbers[0], numbers[1]);</pawn><br />
<br />
Note that cells are passed '''by value'''. That is, their value cannot be changed by the function. For example:<br />
<pawn>int a = 5;<br />
<br />
ChangeValue(a);<br />
<br />
ChangeValue(b)<br />
{<br />
b = 5;<br />
}</pawn><br />
<br />
This code would not change the value of <tt>a</tt>. That is because a copy of the value in <tt>a</tt> is passed instead of <tt>a</tt> itself. <br />
<br />
More examples of functions will be provided throughout the article.<br />
<br />
==Publics==<br />
Public functions are used to implement callbacks. You should not create a public function unless it is specifically implementing a callback. For example, here are two callbacks from <tt>sourcemod.inc</tt>:<br />
<br />
<pawn>forward void OnPluginStart();<br />
forward void OnClientDisconnected(int client);</pawn><br />
<br />
To implement and receive these two events, you would write functions as such:<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
/* Code here */<br />
}<br />
<br />
public void OnClientDisconnected(int client)<br />
{<br />
/* Code here */<br />
}</pawn><br />
<br />
The '''public''' keyword signals to the parent application that it should attach the function to the appropriate forwarded event.<br />
<br />
==Natives==<br />
Natives are builtin functions provided by SourceMod. You can call them as if they were a normal function. For example, SourceMod has the following function:<br />
<br />
<pawn>native float FloatRound(float num);</pawn><br />
<br />
It can be called like so:<br />
<pawn>int rounded = FloatRound(5.2); // rounded will be 5</pawn><br />
<br />
==Array Parameters==<br />
You can pass arrays or Strings as parameters. It is important to note that these are passed '''by reference'''. That is, rather than making a copy of the data, the data is referenced directly. There is a simple way of explaining this more concretely.<br />
<br />
<pawn><br />
int example[] = {1, 2, 3, 4, 5};<br />
<br />
ChangeArray(example, 2, 29);<br />
<br />
void ChangeArray(int[] array, int index, int value)<br />
{<br />
array[index] = value;<br />
}</pawn><br />
<br />
The function sets the given index in the array to a given value. When it is run on our example array, it changes index 2 to from the value 3 to 29. I.e.:<br />
<pawn>example[2] = 29;</pawn><br />
<br />
Note two important things here. First, arrays are not copied when they are passed to functions - they are passed ''by reference'', so the view of the array is consistent at all times. Second, the brackets changed position in our function signature. This is because our function accepts an array of any size, and since we don't know the size, we must use the dynamic array syntax.<br />
<br />
To prevent an array from being modified in a function, you can mark it as <tt>const</tt>. This will raise an error on code that attempts to modify it. For example:<br />
<br />
<pawn>void CantChangeArray(const array[], int index, int value)<br />
{<br />
array[index] = value; //Won't compile<br />
}</pawn><br />
<br />
It is a good idea to use <tt>const</tt> in array parameters if you know the array won't be modified; this can prevent coding mistakes.<br />
<br />
=Expressions=<br />
Expressions are exactly the same as they are in mathematics. They are groups of operators/symbols which evaluate to one piece of data. They are often parenthetical (comprised of parenthesis). They contain a strict "order of operations." They can contain variables, functions, numbers, and expressions themselves can be nested inside other expressions, or even passed as parameters.<br />
<br />
The simplest expression is a single number. For example:<br />
<pawn><br />
0; //Returns the number 0<br />
(0); //Returns the number 0 as well<br />
</pawn><br />
<br />
Although expressions can return any value, they are also said to either return ''zero or non-zero''. In that sense, ''zero'' is ''false'', and ''non-zero'' is ''true''. For example, -1 is '''true''' in Pawn, since it is non-zero. Do not assume negative numbers are false.<br />
<br />
The order of operations for expressions is similar to C. PMDAS: Parenthesis, Multiplication, Division, Addition, Subtraction. Here are some example expressions:<br />
<pawn><br />
5 + 6; //Evaluates to 11<br />
5 * 6 + 3; //Evaluates to 33<br />
5 * (6 + 3); //Evaluates to 45<br />
5.0 + 2.3; //Evaluates to 7.3<br />
(5 * 6) % 7; //Modulo operator, evaluates to 2<br />
(5 + 3) / 2 * 4 - 9; //Evaluates to -8<br />
</pawn><br />
<br />
As noted, expressions can contain variables, or even functions:<br />
<pawn><br />
int a = 5 * 6;<br />
int b = a * 3; //Evaluates to 90<br />
int c = AddTwoNumbers(a, b) + (a * b);<br />
</pawn><br />
<br />
Note: String manipulation routines may be found in the string.inc file located in the include subdirectory. They may be browsed through the [http://docs.sourcemod.net/api/ API Reference] as well.<br />
<br />
==Operators==<br />
There are a few extra helpful operators in Pawn. The first set simplifies self-aggregation expressions. For example:<br />
<pawn>int a = 5;<br />
<br />
a = a + 5;</pawn><br />
<br />
Can be rewritten as:<br />
<pawn>int a = 5;<br />
a += 5;</pawn><br />
<br />
This is true of the following operators in Pawn:<br />
*Four-function: *, /, -, +<br />
*Bit-wise: |, &, ^, ~, <<, >><br />
<br />
Additionally, there are increment/decrement operators:<br />
<pawn>a = a + 1;<br />
a = a - 1;</pawn><br />
<br />
Can be simplified as:<br />
<pawn>a++;<br />
a--;</pawn><br />
<br />
As an advanced note, the ++ or -- can come before the variable (pre-increment, pre-decrement) or after the variable (post-increment, post-decrement). The difference is in how the rest of the expression containing them sees their result.<br />
<br />
* ''Pre:'' The variable is incremented before evaluation, and the rest of the expression sees the new value.<br />
* ''Post:'' The variable is incremented after evaluation, and the rest of the expression sees the old value.<br />
<br />
In other words, <tt>a++</tt> evaluates to the value of <tt>a</tt> while <tt>++a</tt> evaluates to the value of <tt>a + 1</tt>. In both cases <tt>a</tt> is incremented by <tt>1</tt>.<br />
<br />
For example:<br />
<br />
<pawn>int a = 5;<br />
int b = a++; // b = 5, a = 6 (1)<br />
int c = ++a; // a = 7, c = 7 (2)<br />
</pawn><br />
<br />
In (1) <tt>b</tt> is assigned <tt>a</tt>'s ''old'' value ''before'' it is incremented to <tt>6</tt>, but in (2) <tt>c</tt> is assigned <tt>a</tt>'s ''int'' value ''after'' it is incremented to <tt>7</tt>.<br />
<br />
==Comparison Operators==<br />
There are six operators for comparing two values numerically, and the result is either true (non-zero) or false (zero):<br />
*<tt>a == b</tt> - True if a and b have the same value.<br />
*<tt>a != b</tt> - True if a and b have different values.<br />
*<tt>a &gt; b</tt> - True if a is greater than b<br />
*<tt>a &gt;= b</tt> - True if a is greater than or equal to b<br />
*<tt>a &lt; b</tt> - True if a is less than b<br />
*<tt>a &lt;= b</tt> - True if a is less than or equal to b<br />
<br />
For example:<br />
<pawn><br />
(1 != 3); //Evaluates to true because 1 is not equal to 3.<br />
(3 + 3 == 6); //Evaluates to true because 3+3 is 6.<br />
(5 - 2 >= 4); //Evaluates to false because 3 is less than 4.<br />
</pawn><br />
<br />
Note that these operators do not work on arrays or strings. That is, you cannot compare either using <tt>==</tt>.<br />
<br />
==Truth Operators==<br />
These truth values can be combined using three boolean operators:<br />
*<tt>a && b</tt> - True if both a and b are true. False if a or b (or both) is false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>&&</tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 0<br />
|-<br />
! 1<br />
| 0 || 1<br />
|}<br />
*<tt>a || b</tt> - True if a or b (or both) is true. False if both a and b are false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt><nowiki>||</nowiki></tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 1<br />
|-<br />
! 1<br />
| 1 || 1<br />
|}<br />
*<tt>!a</tt> - True if a is false. False if a is true.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>!</tt> !! 0 !! 1<br />
|- <br />
!<br />
| 1 || 0<br />
|}<br />
<br />
For example:<br />
<pawn><br />
(1 || 0); //Evaluates to true because the expression 1 is true<br />
(1 && 0); //Evaluates to false because the expression 0 is false<br />
(!1 || 0); //Evaluates to false because !1 is false.<br />
</pawn><br />
<br />
==Left/Right Values==<br />
Two important concepts are left-hand and right-hand values, or l-values and r-values. An l-value is what appears on the left-hand side of a variable assignment, and an r-value is what appears on the right side of a variable assignment.<br />
<br />
For example:<br />
<pawn><br />
int a = 5;</pawn><br />
<br />
In this example <tt>a</tt> is an l-value and <tt>5</tt> is an r-value.<br />
<br />
The rules:<br />
*'''Expressions are never l-values'''.<br />
*'''Variables are both l-values and r-values'''.<br />
<br />
=Conditionals=<br />
Conditional statements let you only run code if a certain condition is matched.<br />
<br />
==If Statements==<br />
If statements test one or more conditions. For example:<br />
<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code that will run if the expression was true */<br />
}</pawn><br />
<br />
They can be extended to handle more cases as well:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 6)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 7)<br />
{<br />
/* Code */<br />
}</pawn><br />
<br />
You can also handle the case of no expression being matched. For example:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else<br />
{<br />
/* Code that will run if no expressions were true */<br />
}</pawn><br />
<br />
==Switch Statements==<br />
Switch statements are restricted if statements. They test one expression for a series of possible values. For example:<br />
<br />
<pawn><br />
switch (a)<br />
{<br />
case 5:<br />
{<br />
/* code */<br />
}<br />
case 6:<br />
{<br />
/* code */<br />
}<br />
case 7:<br />
{<br />
/* code */<br />
}<br />
case 8, 9, 10:<br />
{<br />
/* Code */<br />
}<br />
default:<br />
{<br />
/* will run if no case matched */<br />
}<br />
}</pawn><br />
<br />
Unlike some other languages, switches are not fall-through. That is, multiple cases will never be run. When a case matches its code is executed, and the switch is then immediately terminated.<br />
<br />
=Loops=<br />
Loops allow you to conveniently repeat a block of code while a given condition remains true. <br />
<br />
==For Loops==<br />
For loops are loops which have four parts:<br />
*The '''initialization''' statement - run once before the first loop.<br />
*The '''condition''' statement - checks whether the next loop should run, including the first one. The loop terminates when this expression evaluates to false.<br />
*The '''iteration''' statement - run after each loop.<br />
*The '''body''' block - run each time the '''condition''' statement evaluates to true.<br />
<br />
<pawn><br />
for ( /* initialization */ ; /* condition */ ; /* iteration */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
A simple example is a function to sum an array:<br />
<pawn><br />
int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};<br />
int sum = SumArray(array, 10);<br />
<br />
int SumArray(const int array[], int count)<br />
{<br />
int total;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
total += array[i];<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
Broken down:<br />
*<tt>int i = 0</tt> - Creates a new variable for the loop, sets it to 0.<br />
*<tt>i < count</tt> - Only runs the loop if <tt>i</tt> is less than <tt>count</tt>. This ensures that the loop stops reading at a certain point. In this case, we don't want to read invalid indexes in the array.<br />
*<tt>i++</tt> - Increments <tt>i</tt> by one after each loop. This ensures that the loop doesn't run forever; eventually <tt>i</tt> will become too big and the loop will end.<br />
<br />
Thus, the <tt>SumArray</tt> function will loop through each valid index of the array, each time adding that value of the array into a sum. For loops are very common for processing arrays like this.<br />
<br />
==While Loops==<br />
While loops are less common than for loops but are actually the simplest possible loop. They have only two parts:<br />
*The '''condition''' statement - checked before each loop. The loop terminates when it evaluates to false.<br />
*The '''body''' block - run each time through the loop.<br />
<br />
<pawn><br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
As long as the condition expression remains true, the loop will continue. Every for loop can be rewritten as a while loop:<br />
<br />
<pawn><br />
/* initialization */<br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
/* iteration */<br />
}<br />
</pawn><br />
<br />
Here is the previous for loop rewritten as a while loop:<br />
<pawn><br />
int SumArray(const int array[], int count)<br />
{<br />
int total, i;<br />
<br />
while (i < count)<br />
{<br />
total += array[i];<br />
i++;<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
There are also '''do...while''' loops which are even less common. These are the same as while loops except the condition check is AFTER each loop, rather than before. This means the loop is always run at least once. For example:<br />
<br />
<pawn><br />
do<br />
{<br />
/* body */<br />
}<br />
while ( /* condition */ );<br />
</pawn><br />
<br />
==Loop Control==<br />
There are two cases in which you want to selectively control a loop:<br />
*'''skipping''' one iteration of the loop but continuing as normal, or;<br />
*'''breaking''' the loop entirely before it's finished.<br />
<br />
Let's say you have a function which takes in an array and searches for a matching number. You want it to stop once the number is found:<br />
<pawn><br />
/**<br />
* Returns the array index where the value is, or -1 if not found.<br />
*/<br />
int SearchInArray(const int array[], int count, int value)<br />
{<br />
int index = -1;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
if (array[i] == value)<br />
{<br />
index = i;<br />
break;<br />
}<br />
}<br />
<br />
return index;<br />
}</pawn><br />
<br />
Certainly, this function could simply <tt>return i</tt> instead, but the example shows how <tt>break</tt> will terminate the loop.<br />
<br />
Similarly, the <tt>continue</tt> keyword skips an iteration of a loop. For example, let's say we wanted to sum all even numbers:<br />
<pawn><br />
int SumEvenNumbers(const int array[], int count)<br />
{<br />
int sum;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
/* If divisibility by 2 is 1, we know it's odd */<br />
if (array[i] % 2 == 1)<br />
{<br />
/* Skip the rest of this loop iteration */<br />
continue;<br />
}<br />
sum += array[i];<br />
}<br />
<br />
return sum;<br />
}</pawn><br />
<br />
=Scope=<br />
Scope refers to the '''visibility''' of code. That is, code at one level may not be "visible" to code at another level. For example:<br />
<br />
<pawn><br />
int A, B, C;<br />
<br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function2();<br />
}<br />
<br />
void Function2()<br />
{<br />
int C;<br />
}</pawn><br />
<br />
In this example, <tt>A</tt>, <tt>B</tt>, and <tt>C</tt> exist at '''global scope'''. They can be seen by any function. However, the <tt>B</tt> in <tt>Function1</tt> is not the same variable as the <tt>B</tt> at the global level. Instead, it is at '''local scope''', and is thus a '''local variable'''.<br />
<br />
Similarly, <tt>Function1</tt> and <tt>Function2</tt> know nothing about each other's variables.<br />
<br />
Not only is the variable private to <tt>Function1</tt>, but it is re-created each time the function is invoked. Imagine this:<br />
<pawn><br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function1();<br />
}</pawn><br />
<br />
In the above example, <tt>Function1</tt> calls itself. Of course, this is infinite recursion (a bad thing), but the idea is that each time the function runs, there is a new copy of <tt>B</tt>. When the function ends, <tt>B</tt> is destroyed, and the value is lost.<br />
<br />
This property can be simplified by saying that a variable's scope is equal to the nesting level it is in. That is, a variable at global scope is visible globally to all functions. A variable at local scope is visible to all code blocks "beneath" its nesting level. For example:<br />
<br />
<pawn>void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
A = 5;<br />
}<br />
}</pawn><br />
<br />
The above code is valid since A's scope extends throughout the function. The following code, however, is not valid:<br />
<pawn><br />
void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
int B = 5;<br />
}<br />
<br />
B = 5;<br />
}</pawn><br />
<br />
Notice that <tt>B</tt> is declared in a new code block. That means <tt>B</tt> is only accessible to that code block (and all sub-blocks nested within). As soon as the code block terminates, <tt>B</tt> is no longer valid.<br />
<br />
=Dynamic Arrays=<br />
Dynamic arrays are arrays which don't have a hardcoded size. For example:<br />
<br />
<pawn>void Function1(int size)<br />
{<br />
int array[size];<br />
<br />
/* Code */<br />
}</pawn><br />
<br />
Dynamic arrays can have any expression as their size as long as the expression evaluates to a number larger than 0. Like normal arrays, SourcePawn does not know the array size after it is created; you have to save it if you want it later.<br />
<br />
Dynamic arrays are only valid at the local scope level, since code cannot exist globally.<br />
<br />
=Extended Variable Declarations=<br />
Variables can be declared in more ways than simply <tt>int float or char</tt>.<br />
<br />
==static==<br />
The <tt>static</tt> keyword is available at global and local scope. It has different meanings in each.<br />
<br />
===Global static===<br />
A global static variable can only be accessed from within the same file. For example:<br />
<br />
<pawn>//file1.inc<br />
static float g_value1 = 0.15f;<br />
<br />
//file2.inc<br />
static float g_value2 = 0.15f;</pawn><br />
<br />
If a plugin includes both of these files, it will not be able to use either <tt>g_value1</tt> or <tt>g_value2</tt>. This is a simple information hiding mechanism, and is similar to declaring member variables as <tt>private</tt> in languages like C++, Java, or C#.<br />
<br />
===Local static===<br />
A local static variable is a global variable that is only visible from its local lexical scope. For example:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
static int counter = -1;<br />
<br />
counter += inc;<br />
<br />
return counter;<br />
}</pawn><br />
<br />
In this example, <tt>counter</tt> is technically a global variable -- it is initialized once to -1 and is never initialized again. It does not exist on the stack. That means each time <tt>MyFunction</tt> runs, the <tt>counter</tt> variable and its storage in memory is the same.<br />
<br />
Take this example:<br />
<pawn>MyFunction(5);<br />
MyFunction(6);<br />
MyFunction(10);</pawn><br />
<br />
In this example, <tt>counter</tt> will be <tt>-1 + 5 + 6 + 10</tt>, or <tt>20</tt>, because it persists beyond the frame of the function. Note this may pose problems for recursive functions: if your function may be recursive, then <tt>static</tt> is usually not a good idea unless your code is re-entrant. <br />
<br />
The benefit of a local static variable is that you don't have to clutter your script with global variables. As long as the variable doesn't need to be read by another function, you can squirrel it inside the function and its persistence will be guaranteed.<br />
<br />
Note that statics can exist in any local scope:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
if (inc > 0)<br />
{<br />
static int counter;<br />
return (counter += inc);<br />
}<br />
return -1;<br />
}</pawn><br />
<br />
[[Category:SourceMod Scripting]]<br />
<br />
{{LanguageSwitch}}</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Introduction_to_SourcePawn_1.7&diff=10201Ru:Introduction to SourcePawn 1.72016-08-26T16:33:52Z<p>MAGNAT2645: /* Объяснение */</p>
<hr />
<div>This guide is designed to give you a very basic overview to fundamentals of scripting in SourcePawn. [[Pawn]] is a "scripting" language used to embed functionality in other programs. That means it is not a standalone language, like C++ or Java, and its details will differ based on the application. SourcePawn is the version of Pawn used in [[SourceMod]].<br />
<br />
This guide does not tell you how to write SourceMod plugins; it is intended as an overview of the syntax and semantics of the language instead. Read the separate article, [[Introduction to SourceMod Plugins]] for SourceMod API specifics. <br />
<br />
=Не программное введение=<br />
This section is intended for non-programmers. If you're still confused, you may want to pick up a book on another language, such as PHP, Python, or Java, to get a better idea of what programming is like.<br />
<br />
==Символы/Ключевые слова==<br />
A symbol is a series of letters, numbers, and/or underscores, that uniquely represents something. Symbols are case-sensitive, and usually start with a letter.<br />
<br />
There are a few reserved symbols that have special meaning. For example, <tt>if</tt>, <tt>for</tt>, and <tt>return</tt> are special constructs in the language that will explained later. They cannot be used as symbol names.<br />
<br />
==Переменные==<br />
There a few important constructs you should know before you begin to script. The first is a '''variable'''. A variable is a symbol, or name, that holds data. For example, the variable "a" could hold the number "2", "16", "0", et cetera. Since a variable holds data, it also allocates the memory needed to store that data.<br />
<br />
In addition to a name, variables have a '''type'''. A type tells the program how to interpret the data, and how much memory the data will use. Pawn has three types of data that are most commonly used:<br />
* Integers, using the <tt>int</tt> type. Integer types may store a whole number from -2147483648 to 2147483647.<br />
* Floats, using the <tt>float</tt> type. Float types may store fractional numbers in a huge range, though they are not as precise as integers.<br />
* Characters, using the <tt>char</tt> type. Character types store one byte of character information, typically an [http://www.asciitable.com/ ASCII] character.<br />
* Booleans, using the <tt>bool</tt> type. Booleans store either true or false.<br />
<br />
Пример создания переменных и добавление значений:<br />
<br />
<pawn>int money = 5400;<br />
float percent = 67.3;<br />
bool enabled = false;<br />
</pawn><br />
<br />
==Функции==<br />
The next important concept is '''functions'''. Functions are symbols or names that perform an action. When you invoke, or call them, they carry out a specific sequence of code and then return a result. There are a few types of functions, but every function is activated the same way. Example:<br />
<br />
<pawn><br />
show(56); // Calls the "show" function, and gives it the number 56.<br />
enable(); // Calls the "enable" function with no values.<br />
bool visible = show(a); //Calls the "show" function, stores its result in a variable.<br />
</pawn><br />
<br />
Every piece of data passed to a function is called a '''parameter'''. A function can have any number of parameters (there is a "reasonable" limit of 32 in SourceMod). Parameters will be explained further in the article.<br />
<br />
==Комментарии==<br />
Знайте, что любой текст после "//" помечается как "комментарий" и это не актуальный (компилятор будет игнорировать комментарии) код. Существует два стиля комментариев:<br />
*<tt>//</tt> - Двойной слэш, всё на этой линии игнорируется.<br />
*<tt>/* */</tt> - Многострочный комментарий, всё между звёздочками игнорируется.<br />
<br />
==Блок кодирования==<br />
Следующей концепцией является блок кодирования. Вы можете групповать код в "блоки", перечисляя его через { и }. Это эффективней делает один большой блок кода из нескольких частей. Для примера:<br />
<br />
<pawn>{<br />
здесь;<br />
есть;<br />
немного;<br />
кода;<br />
}</pawn><br />
<br />
Block coding using braces is used everywhere in programming. Blocks of code can be nested within each other. It is a good idea to adapt a consistent and readable indentation style early on to prevent spaghetti-looking code.<br />
<br />
=Парадигмы языка=<br />
Pawn may seem similar to other languages, like C, but it has fundamental differences. It is not important that you immediately understand these differences, but they may be helpful if you're familiar with another language already.<br />
*'''Pawn is sort of typed.''' Before SourceMod 1.7, Pawn did not have types. Older code and older natives will reflect this by using tags and the <tt>new</tt> keyword. As of SourceMod 1.7, we recommend that all code use types. For more information see [[SourcePawn Transitional Syntax]].<br />
*'''Pawn is not garbage collected.''' Pawn, as a language, has no built-in memory allocation, and thus has no garbage. If a function allocates memory, you may be responsible for freeing it.<br />
*'''Pawn is not object oriented.''' Pawn does not have structs or objects. As of SourceMod 1.7, it has limited sugaring for treating some data types as objects, but users cannot create their own objects or classes.<br />
*'''Pawn is single-threaded.''' As of this writing, Pawn is not thread safe. <br />
*'''Pawn is compiled.''' Pawn is compiled to an intermediate, machine-independent code, which is stored in a ".smx" file. When loading .smx files, SourceMod translates this code to machine code for the platform and CPU it's running on.<br />
<br />
Early language design decisions were made by ITB CompuPhase. It is designed for low-level embedded devices and is thus very small and very fast.<br />
<br />
=Переменные=<br />
На данный момент Pawn поддерживает следующие базовые типы переменных:<br />
*<tt>bool</tt> - true или false. (Правда или ложь)<br />
*<tt>char</tt> - 8-битный символ ASCII.<br />
*<tt>int</tt> - 32-битное целое число.<br />
*<tt>float</tt> - 32-битное число с плавающей точкой IEEE-754.<br />
*<tt>Handle</tt> - базовый тип объекта SourceMod.<br />
<br />
Other types may exist when defined in include files - for example, enums create new types for named integers, and many types derive from <tt>Handle</tt>.<br />
<br />
Strings, currently, are 0-terminated arrays of <tt>char</tt>s. They're described a little further ahead.<br />
<br />
==Объяснение==<br />
Ниже мы приложили немного примеров объявлений переменных, между правильными и неправильными. Имейте ввиду, что в SourcePawn был добавлен новый синтакс, и он указан ниже. Старый код может использовать старый синтакс объявления, который больше не поддерживается.<br />
<br />
<pawn><br />
int a = 5;<br />
float b = 5.0;<br />
bool c = true;<br />
bool d = false;<br />
</pawn><br />
<br />
Неправильное использование переменных:<br />
<pawn><br />
int a = 5.0; // Несоответствие типов. 5.0 это число с плавающей точкой.<br />
float b = 5; // Несоответствие типов. 5 это целое число.<br />
</pawn><br />
<br />
Если значение переменной не указано, оно будет установлено на 0. Пример:<br />
<pawn><br />
int a; // Устанавливается на 0<br />
float b; // Устанавливается на 0.0<br />
bool c; // Устанавливается на false<br />
</pawn><br />
<br />
==Присваивание==<br />
Variables can be re-assigned data after they are created. For example:<br />
<pawn>int a;<br />
float b;<br />
bool c;<br />
<br />
a = 5;<br />
b = 5.0;<br />
c = true;<br />
</pawn><br />
<br />
=Массивы=<br />
An array is a sequence of data in a list. Arrays are useful for storing multiple pieces of data in one variable, or mapping one type of data to another.<br />
<br />
==Объяснение==<br />
An array is declared using brackets. Some examples of arrays:<br />
<pawn><br />
int players[32]; // Содержит 32 целых чисел.<br />
float origin[3]; // Содержит 3 числа с плавающей точкой<br />
</pawn><br />
<br />
By default, arrays are initialized to 0. You can assign them different default values, however:<br />
<pawn><br />
int numbers[5] = {1, 2, 3, 4, 5}; // Stores 1, 2, 3, 4, 5.<br />
float origin[3] = {1.0, 2.0, 3.0}; // Stores 1.0, 2.0, 3.0.<br />
</pawn><br />
<br />
You can leave out the array size if you're going to pre-assign data to it. For example:<br />
<pawn><br />
int numbers[] = {1, 3, 5, 7, 9};<br />
</pawn><br />
<br />
The compiler will automatically deduce that you intended an array of size 5.<br />
<br />
When array is declared with brackets after its name, Pawn considers that array to have a '''fixed size'''. The size of a fixed-size array is always known. Some arrays can be '''dynamically sized''', by putting the brackets before the name. For example,<br />
<br />
<pawn><br />
int[] numbers = new int[MaxClients]<br />
</pawn><br />
<br />
This creates an array of size <tt>MaxClients</tt>, which could be anything, so the size of the array is not known until the array is allocated.<br />
<br />
==Использование==<br />
Using an array is just like using a normal variable. The only difference is the array must be '''indexed'''. Indexing an array means choosing the element which you wish to use.<br />
<br />
For example, here is an example of the above code using indexes:<br />
<pawn><br />
int numbers[5];<br />
float origin[3];<br />
<br />
numbers[0] = 1;<br />
numbers[1] = 2;<br />
numbers[2] = 3;<br />
numbers[3] = 4;<br />
numbers[4] = 5;<br />
origin[0] = 1.0;<br />
origin[1] = 2.0;<br />
origin[2] = 3.0;<br />
</pawn><br />
<br />
Note that the '''index''' is what's in between the brackets. The index always starts from 0. That is, if an array has N elements, its valid indexes are from 0 to N-1. Accessing the data at these indexes works like a normal variable.<br />
<br />
Using an incorrect index will cause an error. For example:<br />
<pawn><br />
int numbers[5];<br />
<br />
numbers[5] = 20;</pawn><br />
<br />
This may look correct, but 5 is not a valid index. The highest valid index is 4.<br />
<br />
You can use any expression as an index. For example:<br />
<pawn>int a, numbers[5];<br />
<br />
a = 1; // Устанавливаем значение a = 1<br />
numbers[a] = 4; // Set numbers[1] = 4<br />
numbers[numbers[a]] = 2; // Set numbers[4] = 2<br />
</pawn><br />
<br />
Expressions will be discussed in depth later in the article.<br />
<br />
=Строки=<br />
Strings are a construct for storing text (or even raw binary data). A string is just an array of characters, except that the final character must be 0 (called the null terminator). Without a null terminator, Pawn would not know where to stop reading the string. All strings are [http://en.wikipedia.org/wiki/UTF-8 UTF-8] in SourcePawn.<br />
<br />
In general, you must have an idea of how large a string will be before you store it. SourcePawn does not yet have the capability of pre-determining storage space for strings.<br />
<br />
==Использование==<br />
Обычно строки объявляются в виде массивов. Пример:<br />
<pawn><br />
char message[] = "Привет!";<br />
char clams[6] = "Мидии";<br />
</pawn><br />
<br />
Это эквивалентно можно сделать:<br />
<pawn><br />
char message[7];<br />
char clams[6];<br />
<br />
message[0] = 'П';<br />
message[1] = 'р';<br />
message[2] = 'и';<br />
message[3] = 'в';<br />
message[4] = 'е';<br />
message[5] = 'т';<br />
message[6] = '!';<br />
message[7] = 0;<br />
clams[0] = 'м';<br />
clams[1] = 'и';<br />
clams[2] = 'д';<br />
clams[3] = 'и';<br />
clams[4] = 'и';<br />
clams[5] = 0;<br />
</pawn><br />
<br />
Although strings are rarely initialized in this manner, it is very important to remember the concept of the null terminator, which signals the end of a string. The compiler, and most SourceMod functions will automatically null-terminate for you, so it is mainly important when manipulating strings directly.<br />
<br />
Note that a string is enclosed in double-quotes, but a character is enclosed in single quotes.<br />
<br />
==Characters==<br />
A character of text can be used in either a String or a cell. For example:<br />
<pawn>char text[] = "Crab";<br />
char clam;<br />
<br />
clam = 'D'; //Set clam to 'D'<br />
text[0] = 'A'; //Change the 'C' to 'A', it is now 'Arab'<br />
clam = text[0]; //Set clam to 'A'<br />
text[1] = clam; //Change the 'r' to 'A', is is now 'AAab'<br />
</pawn><br />
<br />
What you can't do is mix character arrays with strings. The internal storage is different. For example:<br />
<pawn><br />
int clams[] = "Clams"; // Invalid.<br />
int clams[] = {'C', 'l', 'a', 'm', 's', 0}; // Valid, but NOT A STRING.<br />
</pawn><br />
<br />
=Functions=<br />
Functions, as stated before, are isolated blocks of code that perform an action. They can be invoked, or '''called''', with '''parameters''' that give specific options.<br />
<br />
There are two types of ways functions are called:<br />
*'''direct call''' - You specifically call a function in your code.<br />
*'''callback''' - The application calls a function in your code, as if it were an event trigger.<br />
<br />
There are six types of functions:<br />
*'''native''': A direct, internal function provided by the application.<br />
*'''public''': A callback function that is visible to the application and other scripts.<br />
*'''normal''': A normal function that only you can call.<br />
*'''static''': The scope of this function is restricted to the current file, can be used in combination with stock.<br />
*'''stock''': A normal function provided by an include file. If unused, it won't be compiled.<br />
*'''forward''': This function is a global event provided by the application. If you implement it, it will be a callback.<br />
<br />
All code in Pawn must exist in functions. This is in contrast to languages like PHP, Perl, and Python which let you write global code. That is because Pawn is a callback-based language: it responds to actions from a parent application, and functions must be written to handle those actions. Although our examples often contain free-floating code, this is purely for demonstration purposes. Free-floating code in our examples implies the code is part of some function.<br />
<br />
==Declaration==<br />
Unlike variables, functions do not need to be declared before you use them. Functions have two pieces, the '''signature''' and the '''body'''. The signature contains the name of your function and the parameters it will accept. The body is the contents of its code.<br />
<br />
Example of a function:<br />
<pawn><br />
int AddTwoNumbers(int first, int second)<br />
{<br />
int sum = first + second;<br />
return sum;<br />
}</pawn><br />
<br />
This is a simple function. The prototype is this line:<br />
<pawn>int AddTwoNumbers(int first, int second)</pawn><br />
<br />
Broken down, it means:<br />
*<tt>int</tt> - Return value type (integer).<br />
*<tt>AddTwoNumbers</tt> - Name of the function.<br />
*<tt>int first</tt> - First parameter, an integer.<br />
*<tt>int second</tt> - Second parameter, an integer.<br />
<br />
The body is a block of code. It creates a new variable, called <tt>sum</tt>, and assigns it the value of the two parameters added together (more on expressions later). The important thing to notice is the <tt>return</tt> statement, which tells the function to end and return a value to the caller of the function. All functions return something on completion, unless they return a special type called <tt>void</tt>.<br />
<br />
A function can accept any type of input, and it can return any non-array type.<br />
<br />
You can, of course, pass variables to functions:<br />
<pawn>int numbers[3] = {1, 2, 0};<br />
<br />
numbers[2] = AddTwoNumbers(numbers[0], numbers[1]);</pawn><br />
<br />
Note that cells are passed '''by value'''. That is, their value cannot be changed by the function. For example:<br />
<pawn>int a = 5;<br />
<br />
ChangeValue(a);<br />
<br />
ChangeValue(b)<br />
{<br />
b = 5;<br />
}</pawn><br />
<br />
This code would not change the value of <tt>a</tt>. That is because a copy of the value in <tt>a</tt> is passed instead of <tt>a</tt> itself. <br />
<br />
More examples of functions will be provided throughout the article.<br />
<br />
==Publics==<br />
Public functions are used to implement callbacks. You should not create a public function unless it is specifically implementing a callback. For example, here are two callbacks from <tt>sourcemod.inc</tt>:<br />
<br />
<pawn>forward void OnPluginStart();<br />
forward void OnClientDisconnected(int client);</pawn><br />
<br />
To implement and receive these two events, you would write functions as such:<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
/* Code here */<br />
}<br />
<br />
public void OnClientDisconnected(int client)<br />
{<br />
/* Code here */<br />
}</pawn><br />
<br />
The '''public''' keyword signals to the parent application that it should attach the function to the appropriate forwarded event.<br />
<br />
==Natives==<br />
Natives are builtin functions provided by SourceMod. You can call them as if they were a normal function. For example, SourceMod has the following function:<br />
<br />
<pawn>native float FloatRound(float num);</pawn><br />
<br />
It can be called like so:<br />
<pawn>int rounded = FloatRound(5.2); // rounded will be 5</pawn><br />
<br />
==Array Parameters==<br />
You can pass arrays or Strings as parameters. It is important to note that these are passed '''by reference'''. That is, rather than making a copy of the data, the data is referenced directly. There is a simple way of explaining this more concretely.<br />
<br />
<pawn><br />
int example[] = {1, 2, 3, 4, 5};<br />
<br />
ChangeArray(example, 2, 29);<br />
<br />
void ChangeArray(int[] array, int index, int value)<br />
{<br />
array[index] = value;<br />
}</pawn><br />
<br />
The function sets the given index in the array to a given value. When it is run on our example array, it changes index 2 to from the value 3 to 29. I.e.:<br />
<pawn>example[2] = 29;</pawn><br />
<br />
Note two important things here. First, arrays are not copied when they are passed to functions - they are passed ''by reference'', so the view of the array is consistent at all times. Second, the brackets changed position in our function signature. This is because our function accepts an array of any size, and since we don't know the size, we must use the dynamic array syntax.<br />
<br />
To prevent an array from being modified in a function, you can mark it as <tt>const</tt>. This will raise an error on code that attempts to modify it. For example:<br />
<br />
<pawn>void CantChangeArray(const array[], int index, int value)<br />
{<br />
array[index] = value; //Won't compile<br />
}</pawn><br />
<br />
It is a good idea to use <tt>const</tt> in array parameters if you know the array won't be modified; this can prevent coding mistakes.<br />
<br />
=Expressions=<br />
Expressions are exactly the same as they are in mathematics. They are groups of operators/symbols which evaluate to one piece of data. They are often parenthetical (comprised of parenthesis). They contain a strict "order of operations." They can contain variables, functions, numbers, and expressions themselves can be nested inside other expressions, or even passed as parameters.<br />
<br />
The simplest expression is a single number. For example:<br />
<pawn><br />
0; //Returns the number 0<br />
(0); //Returns the number 0 as well<br />
</pawn><br />
<br />
Although expressions can return any value, they are also said to either return ''zero or non-zero''. In that sense, ''zero'' is ''false'', and ''non-zero'' is ''true''. For example, -1 is '''true''' in Pawn, since it is non-zero. Do not assume negative numbers are false.<br />
<br />
The order of operations for expressions is similar to C. PMDAS: Parenthesis, Multiplication, Division, Addition, Subtraction. Here are some example expressions:<br />
<pawn><br />
5 + 6; //Evaluates to 11<br />
5 * 6 + 3; //Evaluates to 33<br />
5 * (6 + 3); //Evaluates to 45<br />
5.0 + 2.3; //Evaluates to 7.3<br />
(5 * 6) % 7; //Modulo operator, evaluates to 2<br />
(5 + 3) / 2 * 4 - 9; //Evaluates to -8<br />
</pawn><br />
<br />
As noted, expressions can contain variables, or even functions:<br />
<pawn><br />
int a = 5 * 6;<br />
int b = a * 3; //Evaluates to 90<br />
int c = AddTwoNumbers(a, b) + (a * b);<br />
</pawn><br />
<br />
Note: String manipulation routines may be found in the string.inc file located in the include subdirectory. They may be browsed through the [http://docs.sourcemod.net/api/ API Reference] as well.<br />
<br />
==Operators==<br />
There are a few extra helpful operators in Pawn. The first set simplifies self-aggregation expressions. For example:<br />
<pawn>int a = 5;<br />
<br />
a = a + 5;</pawn><br />
<br />
Can be rewritten as:<br />
<pawn>int a = 5;<br />
a += 5;</pawn><br />
<br />
This is true of the following operators in Pawn:<br />
*Four-function: *, /, -, +<br />
*Bit-wise: |, &, ^, ~, <<, >><br />
<br />
Additionally, there are increment/decrement operators:<br />
<pawn>a = a + 1;<br />
a = a - 1;</pawn><br />
<br />
Can be simplified as:<br />
<pawn>a++;<br />
a--;</pawn><br />
<br />
As an advanced note, the ++ or -- can come before the variable (pre-increment, pre-decrement) or after the variable (post-increment, post-decrement). The difference is in how the rest of the expression containing them sees their result.<br />
<br />
* ''Pre:'' The variable is incremented before evaluation, and the rest of the expression sees the new value.<br />
* ''Post:'' The variable is incremented after evaluation, and the rest of the expression sees the old value.<br />
<br />
In other words, <tt>a++</tt> evaluates to the value of <tt>a</tt> while <tt>++a</tt> evaluates to the value of <tt>a + 1</tt>. In both cases <tt>a</tt> is incremented by <tt>1</tt>.<br />
<br />
For example:<br />
<br />
<pawn>int a = 5;<br />
int b = a++; // b = 5, a = 6 (1)<br />
int c = ++a; // a = 7, c = 7 (2)<br />
</pawn><br />
<br />
In (1) <tt>b</tt> is assigned <tt>a</tt>'s ''old'' value ''before'' it is incremented to <tt>6</tt>, but in (2) <tt>c</tt> is assigned <tt>a</tt>'s ''int'' value ''after'' it is incremented to <tt>7</tt>.<br />
<br />
==Comparison Operators==<br />
There are six operators for comparing two values numerically, and the result is either true (non-zero) or false (zero):<br />
*<tt>a == b</tt> - True if a and b have the same value.<br />
*<tt>a != b</tt> - True if a and b have different values.<br />
*<tt>a &gt; b</tt> - True if a is greater than b<br />
*<tt>a &gt;= b</tt> - True if a is greater than or equal to b<br />
*<tt>a &lt; b</tt> - True if a is less than b<br />
*<tt>a &lt;= b</tt> - True if a is less than or equal to b<br />
<br />
For example:<br />
<pawn><br />
(1 != 3); //Evaluates to true because 1 is not equal to 3.<br />
(3 + 3 == 6); //Evaluates to true because 3+3 is 6.<br />
(5 - 2 >= 4); //Evaluates to false because 3 is less than 4.<br />
</pawn><br />
<br />
Note that these operators do not work on arrays or strings. That is, you cannot compare either using <tt>==</tt>.<br />
<br />
==Truth Operators==<br />
These truth values can be combined using three boolean operators:<br />
*<tt>a && b</tt> - True if both a and b are true. False if a or b (or both) is false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>&&</tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 0<br />
|-<br />
! 1<br />
| 0 || 1<br />
|}<br />
*<tt>a || b</tt> - True if a or b (or both) is true. False if both a and b are false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt><nowiki>||</nowiki></tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 1<br />
|-<br />
! 1<br />
| 1 || 1<br />
|}<br />
*<tt>!a</tt> - True if a is false. False if a is true.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>!</tt> !! 0 !! 1<br />
|- <br />
!<br />
| 1 || 0<br />
|}<br />
<br />
For example:<br />
<pawn><br />
(1 || 0); //Evaluates to true because the expression 1 is true<br />
(1 && 0); //Evaluates to false because the expression 0 is false<br />
(!1 || 0); //Evaluates to false because !1 is false.<br />
</pawn><br />
<br />
==Left/Right Values==<br />
Two important concepts are left-hand and right-hand values, or l-values and r-values. An l-value is what appears on the left-hand side of a variable assignment, and an r-value is what appears on the right side of a variable assignment.<br />
<br />
For example:<br />
<pawn><br />
int a = 5;</pawn><br />
<br />
In this example <tt>a</tt> is an l-value and <tt>5</tt> is an r-value.<br />
<br />
The rules:<br />
*'''Expressions are never l-values'''.<br />
*'''Variables are both l-values and r-values'''.<br />
<br />
=Conditionals=<br />
Conditional statements let you only run code if a certain condition is matched.<br />
<br />
==If Statements==<br />
If statements test one or more conditions. For example:<br />
<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code that will run if the expression was true */<br />
}</pawn><br />
<br />
They can be extended to handle more cases as well:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 6)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 7)<br />
{<br />
/* Code */<br />
}</pawn><br />
<br />
You can also handle the case of no expression being matched. For example:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else<br />
{<br />
/* Code that will run if no expressions were true */<br />
}</pawn><br />
<br />
==Switch Statements==<br />
Switch statements are restricted if statements. They test one expression for a series of possible values. For example:<br />
<br />
<pawn><br />
switch (a)<br />
{<br />
case 5:<br />
{<br />
/* code */<br />
}<br />
case 6:<br />
{<br />
/* code */<br />
}<br />
case 7:<br />
{<br />
/* code */<br />
}<br />
case 8, 9, 10:<br />
{<br />
/* Code */<br />
}<br />
default:<br />
{<br />
/* will run if no case matched */<br />
}<br />
}</pawn><br />
<br />
Unlike some other languages, switches are not fall-through. That is, multiple cases will never be run. When a case matches its code is executed, and the switch is then immediately terminated.<br />
<br />
=Loops=<br />
Loops allow you to conveniently repeat a block of code while a given condition remains true. <br />
<br />
==For Loops==<br />
For loops are loops which have four parts:<br />
*The '''initialization''' statement - run once before the first loop.<br />
*The '''condition''' statement - checks whether the next loop should run, including the first one. The loop terminates when this expression evaluates to false.<br />
*The '''iteration''' statement - run after each loop.<br />
*The '''body''' block - run each time the '''condition''' statement evaluates to true.<br />
<br />
<pawn><br />
for ( /* initialization */ ; /* condition */ ; /* iteration */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
A simple example is a function to sum an array:<br />
<pawn><br />
int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};<br />
int sum = SumArray(array, 10);<br />
<br />
int SumArray(const int array[], int count)<br />
{<br />
int total;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
total += array[i];<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
Broken down:<br />
*<tt>int i = 0</tt> - Creates a new variable for the loop, sets it to 0.<br />
*<tt>i < count</tt> - Only runs the loop if <tt>i</tt> is less than <tt>count</tt>. This ensures that the loop stops reading at a certain point. In this case, we don't want to read invalid indexes in the array.<br />
*<tt>i++</tt> - Increments <tt>i</tt> by one after each loop. This ensures that the loop doesn't run forever; eventually <tt>i</tt> will become too big and the loop will end.<br />
<br />
Thus, the <tt>SumArray</tt> function will loop through each valid index of the array, each time adding that value of the array into a sum. For loops are very common for processing arrays like this.<br />
<br />
==While Loops==<br />
While loops are less common than for loops but are actually the simplest possible loop. They have only two parts:<br />
*The '''condition''' statement - checked before each loop. The loop terminates when it evaluates to false.<br />
*The '''body''' block - run each time through the loop.<br />
<br />
<pawn><br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
As long as the condition expression remains true, the loop will continue. Every for loop can be rewritten as a while loop:<br />
<br />
<pawn><br />
/* initialization */<br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
/* iteration */<br />
}<br />
</pawn><br />
<br />
Here is the previous for loop rewritten as a while loop:<br />
<pawn><br />
int SumArray(const int array[], int count)<br />
{<br />
int total, i;<br />
<br />
while (i < count)<br />
{<br />
total += array[i];<br />
i++;<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
There are also '''do...while''' loops which are even less common. These are the same as while loops except the condition check is AFTER each loop, rather than before. This means the loop is always run at least once. For example:<br />
<br />
<pawn><br />
do<br />
{<br />
/* body */<br />
}<br />
while ( /* condition */ );<br />
</pawn><br />
<br />
==Loop Control==<br />
There are two cases in which you want to selectively control a loop:<br />
*'''skipping''' one iteration of the loop but continuing as normal, or;<br />
*'''breaking''' the loop entirely before it's finished.<br />
<br />
Let's say you have a function which takes in an array and searches for a matching number. You want it to stop once the number is found:<br />
<pawn><br />
/**<br />
* Returns the array index where the value is, or -1 if not found.<br />
*/<br />
int SearchInArray(const int array[], int count, int value)<br />
{<br />
int index = -1;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
if (array[i] == value)<br />
{<br />
index = i;<br />
break;<br />
}<br />
}<br />
<br />
return index;<br />
}</pawn><br />
<br />
Certainly, this function could simply <tt>return i</tt> instead, but the example shows how <tt>break</tt> will terminate the loop.<br />
<br />
Similarly, the <tt>continue</tt> keyword skips an iteration of a loop. For example, let's say we wanted to sum all even numbers:<br />
<pawn><br />
int SumEvenNumbers(const int array[], int count)<br />
{<br />
int sum;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
/* If divisibility by 2 is 1, we know it's odd */<br />
if (array[i] % 2 == 1)<br />
{<br />
/* Skip the rest of this loop iteration */<br />
continue;<br />
}<br />
sum += array[i];<br />
}<br />
<br />
return sum;<br />
}</pawn><br />
<br />
=Scope=<br />
Scope refers to the '''visibility''' of code. That is, code at one level may not be "visible" to code at another level. For example:<br />
<br />
<pawn><br />
int A, B, C;<br />
<br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function2();<br />
}<br />
<br />
void Function2()<br />
{<br />
int C;<br />
}</pawn><br />
<br />
In this example, <tt>A</tt>, <tt>B</tt>, and <tt>C</tt> exist at '''global scope'''. They can be seen by any function. However, the <tt>B</tt> in <tt>Function1</tt> is not the same variable as the <tt>B</tt> at the global level. Instead, it is at '''local scope''', and is thus a '''local variable'''.<br />
<br />
Similarly, <tt>Function1</tt> and <tt>Function2</tt> know nothing about each other's variables.<br />
<br />
Not only is the variable private to <tt>Function1</tt>, but it is re-created each time the function is invoked. Imagine this:<br />
<pawn><br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function1();<br />
}</pawn><br />
<br />
In the above example, <tt>Function1</tt> calls itself. Of course, this is infinite recursion (a bad thing), but the idea is that each time the function runs, there is a new copy of <tt>B</tt>. When the function ends, <tt>B</tt> is destroyed, and the value is lost.<br />
<br />
This property can be simplified by saying that a variable's scope is equal to the nesting level it is in. That is, a variable at global scope is visible globally to all functions. A variable at local scope is visible to all code blocks "beneath" its nesting level. For example:<br />
<br />
<pawn>void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
A = 5;<br />
}<br />
}</pawn><br />
<br />
The above code is valid since A's scope extends throughout the function. The following code, however, is not valid:<br />
<pawn><br />
void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
int B = 5;<br />
}<br />
<br />
B = 5;<br />
}</pawn><br />
<br />
Notice that <tt>B</tt> is declared in a new code block. That means <tt>B</tt> is only accessible to that code block (and all sub-blocks nested within). As soon as the code block terminates, <tt>B</tt> is no longer valid.<br />
<br />
=Dynamic Arrays=<br />
Dynamic arrays are arrays which don't have a hardcoded size. For example:<br />
<br />
<pawn>void Function1(int size)<br />
{<br />
int array[size];<br />
<br />
/* Code */<br />
}</pawn><br />
<br />
Dynamic arrays can have any expression as their size as long as the expression evaluates to a number larger than 0. Like normal arrays, SourcePawn does not know the array size after it is created; you have to save it if you want it later.<br />
<br />
Dynamic arrays are only valid at the local scope level, since code cannot exist globally.<br />
<br />
=Extended Variable Declarations=<br />
Variables can be declared in more ways than simply <tt>int float or char</tt>.<br />
<br />
==static==<br />
The <tt>static</tt> keyword is available at global and local scope. It has different meanings in each.<br />
<br />
===Global static===<br />
A global static variable can only be accessed from within the same file. For example:<br />
<br />
<pawn>//file1.inc<br />
static float g_value1 = 0.15f;<br />
<br />
//file2.inc<br />
static float g_value2 = 0.15f;</pawn><br />
<br />
If a plugin includes both of these files, it will not be able to use either <tt>g_value1</tt> or <tt>g_value2</tt>. This is a simple information hiding mechanism, and is similar to declaring member variables as <tt>private</tt> in languages like C++, Java, or C#.<br />
<br />
===Local static===<br />
A local static variable is a global variable that is only visible from its local lexical scope. For example:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
static int counter = -1;<br />
<br />
counter += inc;<br />
<br />
return counter;<br />
}</pawn><br />
<br />
In this example, <tt>counter</tt> is technically a global variable -- it is initialized once to -1 and is never initialized again. It does not exist on the stack. That means each time <tt>MyFunction</tt> runs, the <tt>counter</tt> variable and its storage in memory is the same.<br />
<br />
Take this example:<br />
<pawn>MyFunction(5);<br />
MyFunction(6);<br />
MyFunction(10);</pawn><br />
<br />
In this example, <tt>counter</tt> will be <tt>-1 + 5 + 6 + 10</tt>, or <tt>20</tt>, because it persists beyond the frame of the function. Note this may pose problems for recursive functions: if your function may be recursive, then <tt>static</tt> is usually not a good idea unless your code is re-entrant. <br />
<br />
The benefit of a local static variable is that you don't have to clutter your script with global variables. As long as the variable doesn't need to be read by another function, you can squirrel it inside the function and its persistence will be guaranteed.<br />
<br />
Note that statics can exist in any local scope:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
if (inc > 0)<br />
{<br />
static int counter;<br />
return (counter += inc);<br />
}<br />
return -1;<br />
}</pawn><br />
<br />
[[Category:SourceMod Scripting]]<br />
<br />
{{LanguageSwitch}}</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Introduction_to_SourcePawn_1.7&diff=10200Ru:Introduction to SourcePawn 1.72016-08-26T16:19:14Z<p>MAGNAT2645: /* Комментарии */</p>
<hr />
<div>This guide is designed to give you a very basic overview to fundamentals of scripting in SourcePawn. [[Pawn]] is a "scripting" language used to embed functionality in other programs. That means it is not a standalone language, like C++ or Java, and its details will differ based on the application. SourcePawn is the version of Pawn used in [[SourceMod]].<br />
<br />
This guide does not tell you how to write SourceMod plugins; it is intended as an overview of the syntax and semantics of the language instead. Read the separate article, [[Introduction to SourceMod Plugins]] for SourceMod API specifics. <br />
<br />
=Не программное введение=<br />
This section is intended for non-programmers. If you're still confused, you may want to pick up a book on another language, such as PHP, Python, or Java, to get a better idea of what programming is like.<br />
<br />
==Символы/Ключевые слова==<br />
A symbol is a series of letters, numbers, and/or underscores, that uniquely represents something. Symbols are case-sensitive, and usually start with a letter.<br />
<br />
There are a few reserved symbols that have special meaning. For example, <tt>if</tt>, <tt>for</tt>, and <tt>return</tt> are special constructs in the language that will explained later. They cannot be used as symbol names.<br />
<br />
==Переменные==<br />
There a few important constructs you should know before you begin to script. The first is a '''variable'''. A variable is a symbol, or name, that holds data. For example, the variable "a" could hold the number "2", "16", "0", et cetera. Since a variable holds data, it also allocates the memory needed to store that data.<br />
<br />
In addition to a name, variables have a '''type'''. A type tells the program how to interpret the data, and how much memory the data will use. Pawn has three types of data that are most commonly used:<br />
* Integers, using the <tt>int</tt> type. Integer types may store a whole number from -2147483648 to 2147483647.<br />
* Floats, using the <tt>float</tt> type. Float types may store fractional numbers in a huge range, though they are not as precise as integers.<br />
* Characters, using the <tt>char</tt> type. Character types store one byte of character information, typically an [http://www.asciitable.com/ ASCII] character.<br />
* Booleans, using the <tt>bool</tt> type. Booleans store either true or false.<br />
<br />
Пример создания переменных и добавление значений:<br />
<br />
<pawn>int money = 5400;<br />
float percent = 67.3;<br />
bool enabled = false;<br />
</pawn><br />
<br />
==Функции==<br />
The next important concept is '''functions'''. Functions are symbols or names that perform an action. When you invoke, or call them, they carry out a specific sequence of code and then return a result. There are a few types of functions, but every function is activated the same way. Example:<br />
<br />
<pawn><br />
show(56); // Calls the "show" function, and gives it the number 56.<br />
enable(); // Calls the "enable" function with no values.<br />
bool visible = show(a); //Calls the "show" function, stores its result in a variable.<br />
</pawn><br />
<br />
Every piece of data passed to a function is called a '''parameter'''. A function can have any number of parameters (there is a "reasonable" limit of 32 in SourceMod). Parameters will be explained further in the article.<br />
<br />
==Комментарии==<br />
Знайте, что любой текст после "//" помечается как "комментарий" и это не актуальный (компилятор будет игнорировать комментарии) код. Существует два стиля комментариев:<br />
*<tt>//</tt> - Двойной слэш, всё на этой линии игнорируется.<br />
*<tt>/* */</tt> - Многострочный комментарий, всё между звёздочками игнорируется.<br />
<br />
==Блок кодирования==<br />
Следующей концепцией является блок кодирования. Вы можете групповать код в "блоки", перечисляя его через { и }. Это эффективней делает один большой блок кода из нескольких частей. Для примера:<br />
<br />
<pawn>{<br />
здесь;<br />
есть;<br />
немного;<br />
кода;<br />
}</pawn><br />
<br />
Block coding using braces is used everywhere in programming. Blocks of code can be nested within each other. It is a good idea to adapt a consistent and readable indentation style early on to prevent spaghetti-looking code.<br />
<br />
=Парадигмы языка=<br />
Pawn may seem similar to other languages, like C, but it has fundamental differences. It is not important that you immediately understand these differences, but they may be helpful if you're familiar with another language already.<br />
*'''Pawn is sort of typed.''' Before SourceMod 1.7, Pawn did not have types. Older code and older natives will reflect this by using tags and the <tt>new</tt> keyword. As of SourceMod 1.7, we recommend that all code use types. For more information see [[SourcePawn Transitional Syntax]].<br />
*'''Pawn is not garbage collected.''' Pawn, as a language, has no built-in memory allocation, and thus has no garbage. If a function allocates memory, you may be responsible for freeing it.<br />
*'''Pawn is not object oriented.''' Pawn does not have structs or objects. As of SourceMod 1.7, it has limited sugaring for treating some data types as objects, but users cannot create their own objects or classes.<br />
*'''Pawn is single-threaded.''' As of this writing, Pawn is not thread safe. <br />
*'''Pawn is compiled.''' Pawn is compiled to an intermediate, machine-independent code, which is stored in a ".smx" file. When loading .smx files, SourceMod translates this code to machine code for the platform and CPU it's running on.<br />
<br />
Early language design decisions were made by ITB CompuPhase. It is designed for low-level embedded devices and is thus very small and very fast.<br />
<br />
=Переменные=<br />
На данный момент Pawn поддерживает следующие базовые типы переменных:<br />
*<tt>bool</tt> - true или false. (Правда или ложь)<br />
*<tt>char</tt> - 8-битный символ ASCII.<br />
*<tt>int</tt> - 32-битное целое число.<br />
*<tt>float</tt> - 32-битное число с плавающей точкой IEEE-754.<br />
*<tt>Handle</tt> - базовый тип объекта SourceMod.<br />
<br />
Other types may exist when defined in include files - for example, enums create new types for named integers, and many types derive from <tt>Handle</tt>.<br />
<br />
Strings, currently, are 0-terminated arrays of <tt>char</tt>s. They're described a little further ahead.<br />
<br />
==Объяснение==<br />
Below we include some examples of variable declarations, both valid and invalid. Keep in mind that SourcePawn has recently added new syntax, and that's what's documented below. Older code may use older declaration syntax, which is no longer supported.<br />
<br />
<pawn><br />
int a = 5;<br />
float b = 5.0;<br />
bool c = true;<br />
bool d = false;<br />
</pawn><br />
<br />
Неправильное использование переменных:<br />
<pawn><br />
int a = 5.0; // Несоответствие типов. 5.0 это число с плавающей точкой.<br />
float b = 5; // Несоответствие типов. 5 это целое число.<br />
</pawn><br />
<br />
If a variable is not assigned upon declaration, it will be set to 0. For example:<br />
<pawn><br />
int a; // Set to 0<br />
float b; // Set to 0.0<br />
bool c; // Set to false<br />
</pawn><br />
<br />
==Присваивание==<br />
Variables can be re-assigned data after they are created. For example:<br />
<pawn>int a;<br />
float b;<br />
bool c;<br />
<br />
a = 5;<br />
b = 5.0;<br />
c = true;<br />
</pawn><br />
<br />
=Массивы=<br />
An array is a sequence of data in a list. Arrays are useful for storing multiple pieces of data in one variable, or mapping one type of data to another.<br />
<br />
==Объяснение==<br />
An array is declared using brackets. Some examples of arrays:<br />
<pawn><br />
int players[32]; // Содержит 32 целых чисел.<br />
float origin[3]; // Содержит 3 числа с плавающей точкой<br />
</pawn><br />
<br />
By default, arrays are initialized to 0. You can assign them different default values, however:<br />
<pawn><br />
int numbers[5] = {1, 2, 3, 4, 5}; // Stores 1, 2, 3, 4, 5.<br />
float origin[3] = {1.0, 2.0, 3.0}; // Stores 1.0, 2.0, 3.0.<br />
</pawn><br />
<br />
You can leave out the array size if you're going to pre-assign data to it. For example:<br />
<pawn><br />
int numbers[] = {1, 3, 5, 7, 9};<br />
</pawn><br />
<br />
The compiler will automatically deduce that you intended an array of size 5.<br />
<br />
When array is declared with brackets after its name, Pawn considers that array to have a '''fixed size'''. The size of a fixed-size array is always known. Some arrays can be '''dynamically sized''', by putting the brackets before the name. For example,<br />
<br />
<pawn><br />
int[] numbers = new int[MaxClients]<br />
</pawn><br />
<br />
This creates an array of size <tt>MaxClients</tt>, which could be anything, so the size of the array is not known until the array is allocated.<br />
<br />
==Использование==<br />
Using an array is just like using a normal variable. The only difference is the array must be '''indexed'''. Indexing an array means choosing the element which you wish to use.<br />
<br />
For example, here is an example of the above code using indexes:<br />
<pawn><br />
int numbers[5];<br />
float origin[3];<br />
<br />
numbers[0] = 1;<br />
numbers[1] = 2;<br />
numbers[2] = 3;<br />
numbers[3] = 4;<br />
numbers[4] = 5;<br />
origin[0] = 1.0;<br />
origin[1] = 2.0;<br />
origin[2] = 3.0;<br />
</pawn><br />
<br />
Note that the '''index''' is what's in between the brackets. The index always starts from 0. That is, if an array has N elements, its valid indexes are from 0 to N-1. Accessing the data at these indexes works like a normal variable.<br />
<br />
Using an incorrect index will cause an error. For example:<br />
<pawn><br />
int numbers[5];<br />
<br />
numbers[5] = 20;</pawn><br />
<br />
This may look correct, but 5 is not a valid index. The highest valid index is 4.<br />
<br />
You can use any expression as an index. For example:<br />
<pawn>int a, numbers[5];<br />
<br />
a = 1; // Устанавливаем значение a = 1<br />
numbers[a] = 4; // Set numbers[1] = 4<br />
numbers[numbers[a]] = 2; // Set numbers[4] = 2<br />
</pawn><br />
<br />
Expressions will be discussed in depth later in the article.<br />
<br />
=Строки=<br />
Strings are a construct for storing text (or even raw binary data). A string is just an array of characters, except that the final character must be 0 (called the null terminator). Without a null terminator, Pawn would not know where to stop reading the string. All strings are [http://en.wikipedia.org/wiki/UTF-8 UTF-8] in SourcePawn.<br />
<br />
In general, you must have an idea of how large a string will be before you store it. SourcePawn does not yet have the capability of pre-determining storage space for strings.<br />
<br />
==Использование==<br />
Обычно строки объявляются в виде массивов. Пример:<br />
<pawn><br />
char message[] = "Привет!";<br />
char clams[6] = "Мидии";<br />
</pawn><br />
<br />
Это эквивалентно можно сделать:<br />
<pawn><br />
char message[7];<br />
char clams[6];<br />
<br />
message[0] = 'П';<br />
message[1] = 'р';<br />
message[2] = 'и';<br />
message[3] = 'в';<br />
message[4] = 'е';<br />
message[5] = 'т';<br />
message[6] = '!';<br />
message[7] = 0;<br />
clams[0] = 'м';<br />
clams[1] = 'и';<br />
clams[2] = 'д';<br />
clams[3] = 'и';<br />
clams[4] = 'и';<br />
clams[5] = 0;<br />
</pawn><br />
<br />
Although strings are rarely initialized in this manner, it is very important to remember the concept of the null terminator, which signals the end of a string. The compiler, and most SourceMod functions will automatically null-terminate for you, so it is mainly important when manipulating strings directly.<br />
<br />
Note that a string is enclosed in double-quotes, but a character is enclosed in single quotes.<br />
<br />
==Characters==<br />
A character of text can be used in either a String or a cell. For example:<br />
<pawn>char text[] = "Crab";<br />
char clam;<br />
<br />
clam = 'D'; //Set clam to 'D'<br />
text[0] = 'A'; //Change the 'C' to 'A', it is now 'Arab'<br />
clam = text[0]; //Set clam to 'A'<br />
text[1] = clam; //Change the 'r' to 'A', is is now 'AAab'<br />
</pawn><br />
<br />
What you can't do is mix character arrays with strings. The internal storage is different. For example:<br />
<pawn><br />
int clams[] = "Clams"; // Invalid.<br />
int clams[] = {'C', 'l', 'a', 'm', 's', 0}; // Valid, but NOT A STRING.<br />
</pawn><br />
<br />
=Functions=<br />
Functions, as stated before, are isolated blocks of code that perform an action. They can be invoked, or '''called''', with '''parameters''' that give specific options.<br />
<br />
There are two types of ways functions are called:<br />
*'''direct call''' - You specifically call a function in your code.<br />
*'''callback''' - The application calls a function in your code, as if it were an event trigger.<br />
<br />
There are six types of functions:<br />
*'''native''': A direct, internal function provided by the application.<br />
*'''public''': A callback function that is visible to the application and other scripts.<br />
*'''normal''': A normal function that only you can call.<br />
*'''static''': The scope of this function is restricted to the current file, can be used in combination with stock.<br />
*'''stock''': A normal function provided by an include file. If unused, it won't be compiled.<br />
*'''forward''': This function is a global event provided by the application. If you implement it, it will be a callback.<br />
<br />
All code in Pawn must exist in functions. This is in contrast to languages like PHP, Perl, and Python which let you write global code. That is because Pawn is a callback-based language: it responds to actions from a parent application, and functions must be written to handle those actions. Although our examples often contain free-floating code, this is purely for demonstration purposes. Free-floating code in our examples implies the code is part of some function.<br />
<br />
==Declaration==<br />
Unlike variables, functions do not need to be declared before you use them. Functions have two pieces, the '''signature''' and the '''body'''. The signature contains the name of your function and the parameters it will accept. The body is the contents of its code.<br />
<br />
Example of a function:<br />
<pawn><br />
int AddTwoNumbers(int first, int second)<br />
{<br />
int sum = first + second;<br />
return sum;<br />
}</pawn><br />
<br />
This is a simple function. The prototype is this line:<br />
<pawn>int AddTwoNumbers(int first, int second)</pawn><br />
<br />
Broken down, it means:<br />
*<tt>int</tt> - Return value type (integer).<br />
*<tt>AddTwoNumbers</tt> - Name of the function.<br />
*<tt>int first</tt> - First parameter, an integer.<br />
*<tt>int second</tt> - Second parameter, an integer.<br />
<br />
The body is a block of code. It creates a new variable, called <tt>sum</tt>, and assigns it the value of the two parameters added together (more on expressions later). The important thing to notice is the <tt>return</tt> statement, which tells the function to end and return a value to the caller of the function. All functions return something on completion, unless they return a special type called <tt>void</tt>.<br />
<br />
A function can accept any type of input, and it can return any non-array type.<br />
<br />
You can, of course, pass variables to functions:<br />
<pawn>int numbers[3] = {1, 2, 0};<br />
<br />
numbers[2] = AddTwoNumbers(numbers[0], numbers[1]);</pawn><br />
<br />
Note that cells are passed '''by value'''. That is, their value cannot be changed by the function. For example:<br />
<pawn>int a = 5;<br />
<br />
ChangeValue(a);<br />
<br />
ChangeValue(b)<br />
{<br />
b = 5;<br />
}</pawn><br />
<br />
This code would not change the value of <tt>a</tt>. That is because a copy of the value in <tt>a</tt> is passed instead of <tt>a</tt> itself. <br />
<br />
More examples of functions will be provided throughout the article.<br />
<br />
==Publics==<br />
Public functions are used to implement callbacks. You should not create a public function unless it is specifically implementing a callback. For example, here are two callbacks from <tt>sourcemod.inc</tt>:<br />
<br />
<pawn>forward void OnPluginStart();<br />
forward void OnClientDisconnected(int client);</pawn><br />
<br />
To implement and receive these two events, you would write functions as such:<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
/* Code here */<br />
}<br />
<br />
public void OnClientDisconnected(int client)<br />
{<br />
/* Code here */<br />
}</pawn><br />
<br />
The '''public''' keyword signals to the parent application that it should attach the function to the appropriate forwarded event.<br />
<br />
==Natives==<br />
Natives are builtin functions provided by SourceMod. You can call them as if they were a normal function. For example, SourceMod has the following function:<br />
<br />
<pawn>native float FloatRound(float num);</pawn><br />
<br />
It can be called like so:<br />
<pawn>int rounded = FloatRound(5.2); // rounded will be 5</pawn><br />
<br />
==Array Parameters==<br />
You can pass arrays or Strings as parameters. It is important to note that these are passed '''by reference'''. That is, rather than making a copy of the data, the data is referenced directly. There is a simple way of explaining this more concretely.<br />
<br />
<pawn><br />
int example[] = {1, 2, 3, 4, 5};<br />
<br />
ChangeArray(example, 2, 29);<br />
<br />
void ChangeArray(int[] array, int index, int value)<br />
{<br />
array[index] = value;<br />
}</pawn><br />
<br />
The function sets the given index in the array to a given value. When it is run on our example array, it changes index 2 to from the value 3 to 29. I.e.:<br />
<pawn>example[2] = 29;</pawn><br />
<br />
Note two important things here. First, arrays are not copied when they are passed to functions - they are passed ''by reference'', so the view of the array is consistent at all times. Second, the brackets changed position in our function signature. This is because our function accepts an array of any size, and since we don't know the size, we must use the dynamic array syntax.<br />
<br />
To prevent an array from being modified in a function, you can mark it as <tt>const</tt>. This will raise an error on code that attempts to modify it. For example:<br />
<br />
<pawn>void CantChangeArray(const array[], int index, int value)<br />
{<br />
array[index] = value; //Won't compile<br />
}</pawn><br />
<br />
It is a good idea to use <tt>const</tt> in array parameters if you know the array won't be modified; this can prevent coding mistakes.<br />
<br />
=Expressions=<br />
Expressions are exactly the same as they are in mathematics. They are groups of operators/symbols which evaluate to one piece of data. They are often parenthetical (comprised of parenthesis). They contain a strict "order of operations." They can contain variables, functions, numbers, and expressions themselves can be nested inside other expressions, or even passed as parameters.<br />
<br />
The simplest expression is a single number. For example:<br />
<pawn><br />
0; //Returns the number 0<br />
(0); //Returns the number 0 as well<br />
</pawn><br />
<br />
Although expressions can return any value, they are also said to either return ''zero or non-zero''. In that sense, ''zero'' is ''false'', and ''non-zero'' is ''true''. For example, -1 is '''true''' in Pawn, since it is non-zero. Do not assume negative numbers are false.<br />
<br />
The order of operations for expressions is similar to C. PMDAS: Parenthesis, Multiplication, Division, Addition, Subtraction. Here are some example expressions:<br />
<pawn><br />
5 + 6; //Evaluates to 11<br />
5 * 6 + 3; //Evaluates to 33<br />
5 * (6 + 3); //Evaluates to 45<br />
5.0 + 2.3; //Evaluates to 7.3<br />
(5 * 6) % 7; //Modulo operator, evaluates to 2<br />
(5 + 3) / 2 * 4 - 9; //Evaluates to -8<br />
</pawn><br />
<br />
As noted, expressions can contain variables, or even functions:<br />
<pawn><br />
int a = 5 * 6;<br />
int b = a * 3; //Evaluates to 90<br />
int c = AddTwoNumbers(a, b) + (a * b);<br />
</pawn><br />
<br />
Note: String manipulation routines may be found in the string.inc file located in the include subdirectory. They may be browsed through the [http://docs.sourcemod.net/api/ API Reference] as well.<br />
<br />
==Operators==<br />
There are a few extra helpful operators in Pawn. The first set simplifies self-aggregation expressions. For example:<br />
<pawn>int a = 5;<br />
<br />
a = a + 5;</pawn><br />
<br />
Can be rewritten as:<br />
<pawn>int a = 5;<br />
a += 5;</pawn><br />
<br />
This is true of the following operators in Pawn:<br />
*Four-function: *, /, -, +<br />
*Bit-wise: |, &, ^, ~, <<, >><br />
<br />
Additionally, there are increment/decrement operators:<br />
<pawn>a = a + 1;<br />
a = a - 1;</pawn><br />
<br />
Can be simplified as:<br />
<pawn>a++;<br />
a--;</pawn><br />
<br />
As an advanced note, the ++ or -- can come before the variable (pre-increment, pre-decrement) or after the variable (post-increment, post-decrement). The difference is in how the rest of the expression containing them sees their result.<br />
<br />
* ''Pre:'' The variable is incremented before evaluation, and the rest of the expression sees the new value.<br />
* ''Post:'' The variable is incremented after evaluation, and the rest of the expression sees the old value.<br />
<br />
In other words, <tt>a++</tt> evaluates to the value of <tt>a</tt> while <tt>++a</tt> evaluates to the value of <tt>a + 1</tt>. In both cases <tt>a</tt> is incremented by <tt>1</tt>.<br />
<br />
For example:<br />
<br />
<pawn>int a = 5;<br />
int b = a++; // b = 5, a = 6 (1)<br />
int c = ++a; // a = 7, c = 7 (2)<br />
</pawn><br />
<br />
In (1) <tt>b</tt> is assigned <tt>a</tt>'s ''old'' value ''before'' it is incremented to <tt>6</tt>, but in (2) <tt>c</tt> is assigned <tt>a</tt>'s ''int'' value ''after'' it is incremented to <tt>7</tt>.<br />
<br />
==Comparison Operators==<br />
There are six operators for comparing two values numerically, and the result is either true (non-zero) or false (zero):<br />
*<tt>a == b</tt> - True if a and b have the same value.<br />
*<tt>a != b</tt> - True if a and b have different values.<br />
*<tt>a &gt; b</tt> - True if a is greater than b<br />
*<tt>a &gt;= b</tt> - True if a is greater than or equal to b<br />
*<tt>a &lt; b</tt> - True if a is less than b<br />
*<tt>a &lt;= b</tt> - True if a is less than or equal to b<br />
<br />
For example:<br />
<pawn><br />
(1 != 3); //Evaluates to true because 1 is not equal to 3.<br />
(3 + 3 == 6); //Evaluates to true because 3+3 is 6.<br />
(5 - 2 >= 4); //Evaluates to false because 3 is less than 4.<br />
</pawn><br />
<br />
Note that these operators do not work on arrays or strings. That is, you cannot compare either using <tt>==</tt>.<br />
<br />
==Truth Operators==<br />
These truth values can be combined using three boolean operators:<br />
*<tt>a && b</tt> - True if both a and b are true. False if a or b (or both) is false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>&&</tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 0<br />
|-<br />
! 1<br />
| 0 || 1<br />
|}<br />
*<tt>a || b</tt> - True if a or b (or both) is true. False if both a and b are false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt><nowiki>||</nowiki></tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 1<br />
|-<br />
! 1<br />
| 1 || 1<br />
|}<br />
*<tt>!a</tt> - True if a is false. False if a is true.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>!</tt> !! 0 !! 1<br />
|- <br />
!<br />
| 1 || 0<br />
|}<br />
<br />
For example:<br />
<pawn><br />
(1 || 0); //Evaluates to true because the expression 1 is true<br />
(1 && 0); //Evaluates to false because the expression 0 is false<br />
(!1 || 0); //Evaluates to false because !1 is false.<br />
</pawn><br />
<br />
==Left/Right Values==<br />
Two important concepts are left-hand and right-hand values, or l-values and r-values. An l-value is what appears on the left-hand side of a variable assignment, and an r-value is what appears on the right side of a variable assignment.<br />
<br />
For example:<br />
<pawn><br />
int a = 5;</pawn><br />
<br />
In this example <tt>a</tt> is an l-value and <tt>5</tt> is an r-value.<br />
<br />
The rules:<br />
*'''Expressions are never l-values'''.<br />
*'''Variables are both l-values and r-values'''.<br />
<br />
=Conditionals=<br />
Conditional statements let you only run code if a certain condition is matched.<br />
<br />
==If Statements==<br />
If statements test one or more conditions. For example:<br />
<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code that will run if the expression was true */<br />
}</pawn><br />
<br />
They can be extended to handle more cases as well:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 6)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 7)<br />
{<br />
/* Code */<br />
}</pawn><br />
<br />
You can also handle the case of no expression being matched. For example:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else<br />
{<br />
/* Code that will run if no expressions were true */<br />
}</pawn><br />
<br />
==Switch Statements==<br />
Switch statements are restricted if statements. They test one expression for a series of possible values. For example:<br />
<br />
<pawn><br />
switch (a)<br />
{<br />
case 5:<br />
{<br />
/* code */<br />
}<br />
case 6:<br />
{<br />
/* code */<br />
}<br />
case 7:<br />
{<br />
/* code */<br />
}<br />
case 8, 9, 10:<br />
{<br />
/* Code */<br />
}<br />
default:<br />
{<br />
/* will run if no case matched */<br />
}<br />
}</pawn><br />
<br />
Unlike some other languages, switches are not fall-through. That is, multiple cases will never be run. When a case matches its code is executed, and the switch is then immediately terminated.<br />
<br />
=Loops=<br />
Loops allow you to conveniently repeat a block of code while a given condition remains true. <br />
<br />
==For Loops==<br />
For loops are loops which have four parts:<br />
*The '''initialization''' statement - run once before the first loop.<br />
*The '''condition''' statement - checks whether the next loop should run, including the first one. The loop terminates when this expression evaluates to false.<br />
*The '''iteration''' statement - run after each loop.<br />
*The '''body''' block - run each time the '''condition''' statement evaluates to true.<br />
<br />
<pawn><br />
for ( /* initialization */ ; /* condition */ ; /* iteration */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
A simple example is a function to sum an array:<br />
<pawn><br />
int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};<br />
int sum = SumArray(array, 10);<br />
<br />
int SumArray(const int array[], int count)<br />
{<br />
int total;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
total += array[i];<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
Broken down:<br />
*<tt>int i = 0</tt> - Creates a new variable for the loop, sets it to 0.<br />
*<tt>i < count</tt> - Only runs the loop if <tt>i</tt> is less than <tt>count</tt>. This ensures that the loop stops reading at a certain point. In this case, we don't want to read invalid indexes in the array.<br />
*<tt>i++</tt> - Increments <tt>i</tt> by one after each loop. This ensures that the loop doesn't run forever; eventually <tt>i</tt> will become too big and the loop will end.<br />
<br />
Thus, the <tt>SumArray</tt> function will loop through each valid index of the array, each time adding that value of the array into a sum. For loops are very common for processing arrays like this.<br />
<br />
==While Loops==<br />
While loops are less common than for loops but are actually the simplest possible loop. They have only two parts:<br />
*The '''condition''' statement - checked before each loop. The loop terminates when it evaluates to false.<br />
*The '''body''' block - run each time through the loop.<br />
<br />
<pawn><br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
As long as the condition expression remains true, the loop will continue. Every for loop can be rewritten as a while loop:<br />
<br />
<pawn><br />
/* initialization */<br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
/* iteration */<br />
}<br />
</pawn><br />
<br />
Here is the previous for loop rewritten as a while loop:<br />
<pawn><br />
int SumArray(const int array[], int count)<br />
{<br />
int total, i;<br />
<br />
while (i < count)<br />
{<br />
total += array[i];<br />
i++;<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
There are also '''do...while''' loops which are even less common. These are the same as while loops except the condition check is AFTER each loop, rather than before. This means the loop is always run at least once. For example:<br />
<br />
<pawn><br />
do<br />
{<br />
/* body */<br />
}<br />
while ( /* condition */ );<br />
</pawn><br />
<br />
==Loop Control==<br />
There are two cases in which you want to selectively control a loop:<br />
*'''skipping''' one iteration of the loop but continuing as normal, or;<br />
*'''breaking''' the loop entirely before it's finished.<br />
<br />
Let's say you have a function which takes in an array and searches for a matching number. You want it to stop once the number is found:<br />
<pawn><br />
/**<br />
* Returns the array index where the value is, or -1 if not found.<br />
*/<br />
int SearchInArray(const int array[], int count, int value)<br />
{<br />
int index = -1;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
if (array[i] == value)<br />
{<br />
index = i;<br />
break;<br />
}<br />
}<br />
<br />
return index;<br />
}</pawn><br />
<br />
Certainly, this function could simply <tt>return i</tt> instead, but the example shows how <tt>break</tt> will terminate the loop.<br />
<br />
Similarly, the <tt>continue</tt> keyword skips an iteration of a loop. For example, let's say we wanted to sum all even numbers:<br />
<pawn><br />
int SumEvenNumbers(const int array[], int count)<br />
{<br />
int sum;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
/* If divisibility by 2 is 1, we know it's odd */<br />
if (array[i] % 2 == 1)<br />
{<br />
/* Skip the rest of this loop iteration */<br />
continue;<br />
}<br />
sum += array[i];<br />
}<br />
<br />
return sum;<br />
}</pawn><br />
<br />
=Scope=<br />
Scope refers to the '''visibility''' of code. That is, code at one level may not be "visible" to code at another level. For example:<br />
<br />
<pawn><br />
int A, B, C;<br />
<br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function2();<br />
}<br />
<br />
void Function2()<br />
{<br />
int C;<br />
}</pawn><br />
<br />
In this example, <tt>A</tt>, <tt>B</tt>, and <tt>C</tt> exist at '''global scope'''. They can be seen by any function. However, the <tt>B</tt> in <tt>Function1</tt> is not the same variable as the <tt>B</tt> at the global level. Instead, it is at '''local scope''', and is thus a '''local variable'''.<br />
<br />
Similarly, <tt>Function1</tt> and <tt>Function2</tt> know nothing about each other's variables.<br />
<br />
Not only is the variable private to <tt>Function1</tt>, but it is re-created each time the function is invoked. Imagine this:<br />
<pawn><br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function1();<br />
}</pawn><br />
<br />
In the above example, <tt>Function1</tt> calls itself. Of course, this is infinite recursion (a bad thing), but the idea is that each time the function runs, there is a new copy of <tt>B</tt>. When the function ends, <tt>B</tt> is destroyed, and the value is lost.<br />
<br />
This property can be simplified by saying that a variable's scope is equal to the nesting level it is in. That is, a variable at global scope is visible globally to all functions. A variable at local scope is visible to all code blocks "beneath" its nesting level. For example:<br />
<br />
<pawn>void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
A = 5;<br />
}<br />
}</pawn><br />
<br />
The above code is valid since A's scope extends throughout the function. The following code, however, is not valid:<br />
<pawn><br />
void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
int B = 5;<br />
}<br />
<br />
B = 5;<br />
}</pawn><br />
<br />
Notice that <tt>B</tt> is declared in a new code block. That means <tt>B</tt> is only accessible to that code block (and all sub-blocks nested within). As soon as the code block terminates, <tt>B</tt> is no longer valid.<br />
<br />
=Dynamic Arrays=<br />
Dynamic arrays are arrays which don't have a hardcoded size. For example:<br />
<br />
<pawn>void Function1(int size)<br />
{<br />
int array[size];<br />
<br />
/* Code */<br />
}</pawn><br />
<br />
Dynamic arrays can have any expression as their size as long as the expression evaluates to a number larger than 0. Like normal arrays, SourcePawn does not know the array size after it is created; you have to save it if you want it later.<br />
<br />
Dynamic arrays are only valid at the local scope level, since code cannot exist globally.<br />
<br />
=Extended Variable Declarations=<br />
Variables can be declared in more ways than simply <tt>int float or char</tt>.<br />
<br />
==static==<br />
The <tt>static</tt> keyword is available at global and local scope. It has different meanings in each.<br />
<br />
===Global static===<br />
A global static variable can only be accessed from within the same file. For example:<br />
<br />
<pawn>//file1.inc<br />
static float g_value1 = 0.15f;<br />
<br />
//file2.inc<br />
static float g_value2 = 0.15f;</pawn><br />
<br />
If a plugin includes both of these files, it will not be able to use either <tt>g_value1</tt> or <tt>g_value2</tt>. This is a simple information hiding mechanism, and is similar to declaring member variables as <tt>private</tt> in languages like C++, Java, or C#.<br />
<br />
===Local static===<br />
A local static variable is a global variable that is only visible from its local lexical scope. For example:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
static int counter = -1;<br />
<br />
counter += inc;<br />
<br />
return counter;<br />
}</pawn><br />
<br />
In this example, <tt>counter</tt> is technically a global variable -- it is initialized once to -1 and is never initialized again. It does not exist on the stack. That means each time <tt>MyFunction</tt> runs, the <tt>counter</tt> variable and its storage in memory is the same.<br />
<br />
Take this example:<br />
<pawn>MyFunction(5);<br />
MyFunction(6);<br />
MyFunction(10);</pawn><br />
<br />
In this example, <tt>counter</tt> will be <tt>-1 + 5 + 6 + 10</tt>, or <tt>20</tt>, because it persists beyond the frame of the function. Note this may pose problems for recursive functions: if your function may be recursive, then <tt>static</tt> is usually not a good idea unless your code is re-entrant. <br />
<br />
The benefit of a local static variable is that you don't have to clutter your script with global variables. As long as the variable doesn't need to be read by another function, you can squirrel it inside the function and its persistence will be guaranteed.<br />
<br />
Note that statics can exist in any local scope:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
if (inc > 0)<br />
{<br />
static int counter;<br />
return (counter += inc);<br />
}<br />
return -1;<br />
}</pawn><br />
<br />
[[Category:SourceMod Scripting]]<br />
<br />
{{LanguageSwitch}}</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Introduction_to_SourcePawn_1.7&diff=10199Ru:Introduction to SourcePawn 1.72016-08-26T16:18:17Z<p>MAGNAT2645: Added some russian...</p>
<hr />
<div>This guide is designed to give you a very basic overview to fundamentals of scripting in SourcePawn. [[Pawn]] is a "scripting" language used to embed functionality in other programs. That means it is not a standalone language, like C++ or Java, and its details will differ based on the application. SourcePawn is the version of Pawn used in [[SourceMod]].<br />
<br />
This guide does not tell you how to write SourceMod plugins; it is intended as an overview of the syntax and semantics of the language instead. Read the separate article, [[Introduction to SourceMod Plugins]] for SourceMod API specifics. <br />
<br />
=Не программное введение=<br />
This section is intended for non-programmers. If you're still confused, you may want to pick up a book on another language, such as PHP, Python, or Java, to get a better idea of what programming is like.<br />
<br />
==Символы/Ключевые слова==<br />
A symbol is a series of letters, numbers, and/or underscores, that uniquely represents something. Symbols are case-sensitive, and usually start with a letter.<br />
<br />
There are a few reserved symbols that have special meaning. For example, <tt>if</tt>, <tt>for</tt>, and <tt>return</tt> are special constructs in the language that will explained later. They cannot be used as symbol names.<br />
<br />
==Переменные==<br />
There a few important constructs you should know before you begin to script. The first is a '''variable'''. A variable is a symbol, or name, that holds data. For example, the variable "a" could hold the number "2", "16", "0", et cetera. Since a variable holds data, it also allocates the memory needed to store that data.<br />
<br />
In addition to a name, variables have a '''type'''. A type tells the program how to interpret the data, and how much memory the data will use. Pawn has three types of data that are most commonly used:<br />
* Integers, using the <tt>int</tt> type. Integer types may store a whole number from -2147483648 to 2147483647.<br />
* Floats, using the <tt>float</tt> type. Float types may store fractional numbers in a huge range, though they are not as precise as integers.<br />
* Characters, using the <tt>char</tt> type. Character types store one byte of character information, typically an [http://www.asciitable.com/ ASCII] character.<br />
* Booleans, using the <tt>bool</tt> type. Booleans store either true or false.<br />
<br />
Пример создания переменных и добавление значений:<br />
<br />
<pawn>int money = 5400;<br />
float percent = 67.3;<br />
bool enabled = false;<br />
</pawn><br />
<br />
==Функции==<br />
The next important concept is '''functions'''. Functions are symbols or names that perform an action. When you invoke, or call them, they carry out a specific sequence of code and then return a result. There are a few types of functions, but every function is activated the same way. Example:<br />
<br />
<pawn><br />
show(56); // Calls the "show" function, and gives it the number 56.<br />
enable(); // Calls the "enable" function with no values.<br />
bool visible = show(a); //Calls the "show" function, stores its result in a variable.<br />
</pawn><br />
<br />
Every piece of data passed to a function is called a '''parameter'''. A function can have any number of parameters (there is a "reasonable" limit of 32 in SourceMod). Parameters will be explained further in the article.<br />
<br />
==Комментарии==<br />
Знайте, что любой текст после "//" помечается как "комментарий" и это не актуальный (компилятор будет игнорировать комментарии) код. Существует два стиля комментарием:<br />
*<tt>//</tt> - Двойной слэш, всё на этой линии игнорируется.<br />
*<tt>/* */</tt> - Многострочный комментарий, всё между звёздочками игнорируется.<br />
<br />
<br />
==Блок кодирования==<br />
Следующей концепцией является блок кодирования. Вы можете групповать код в "блоки", перечисляя его через { и }. Это эффективней делает один большой блок кода из нескольких частей. Для примера:<br />
<br />
<pawn>{<br />
здесь;<br />
есть;<br />
немного;<br />
кода;<br />
}</pawn><br />
<br />
Block coding using braces is used everywhere in programming. Blocks of code can be nested within each other. It is a good idea to adapt a consistent and readable indentation style early on to prevent spaghetti-looking code.<br />
<br />
=Парадигмы языка=<br />
Pawn may seem similar to other languages, like C, but it has fundamental differences. It is not important that you immediately understand these differences, but they may be helpful if you're familiar with another language already.<br />
*'''Pawn is sort of typed.''' Before SourceMod 1.7, Pawn did not have types. Older code and older natives will reflect this by using tags and the <tt>new</tt> keyword. As of SourceMod 1.7, we recommend that all code use types. For more information see [[SourcePawn Transitional Syntax]].<br />
*'''Pawn is not garbage collected.''' Pawn, as a language, has no built-in memory allocation, and thus has no garbage. If a function allocates memory, you may be responsible for freeing it.<br />
*'''Pawn is not object oriented.''' Pawn does not have structs or objects. As of SourceMod 1.7, it has limited sugaring for treating some data types as objects, but users cannot create their own objects or classes.<br />
*'''Pawn is single-threaded.''' As of this writing, Pawn is not thread safe. <br />
*'''Pawn is compiled.''' Pawn is compiled to an intermediate, machine-independent code, which is stored in a ".smx" file. When loading .smx files, SourceMod translates this code to machine code for the platform and CPU it's running on.<br />
<br />
Early language design decisions were made by ITB CompuPhase. It is designed for low-level embedded devices and is thus very small and very fast.<br />
<br />
=Переменные=<br />
На данный момент Pawn поддерживает следующие базовые типы переменных:<br />
*<tt>bool</tt> - true или false. (Правда или ложь)<br />
*<tt>char</tt> - 8-битный символ ASCII.<br />
*<tt>int</tt> - 32-битное целое число.<br />
*<tt>float</tt> - 32-битное число с плавающей точкой IEEE-754.<br />
*<tt>Handle</tt> - базовый тип объекта SourceMod.<br />
<br />
Other types may exist when defined in include files - for example, enums create new types for named integers, and many types derive from <tt>Handle</tt>.<br />
<br />
Strings, currently, are 0-terminated arrays of <tt>char</tt>s. They're described a little further ahead.<br />
<br />
==Объяснение==<br />
Below we include some examples of variable declarations, both valid and invalid. Keep in mind that SourcePawn has recently added new syntax, and that's what's documented below. Older code may use older declaration syntax, which is no longer supported.<br />
<br />
<pawn><br />
int a = 5;<br />
float b = 5.0;<br />
bool c = true;<br />
bool d = false;<br />
</pawn><br />
<br />
Неправильное использование переменных:<br />
<pawn><br />
int a = 5.0; // Несоответствие типов. 5.0 это число с плавающей точкой.<br />
float b = 5; // Несоответствие типов. 5 это целое число.<br />
</pawn><br />
<br />
If a variable is not assigned upon declaration, it will be set to 0. For example:<br />
<pawn><br />
int a; // Set to 0<br />
float b; // Set to 0.0<br />
bool c; // Set to false<br />
</pawn><br />
<br />
==Присваивание==<br />
Variables can be re-assigned data after they are created. For example:<br />
<pawn>int a;<br />
float b;<br />
bool c;<br />
<br />
a = 5;<br />
b = 5.0;<br />
c = true;<br />
</pawn><br />
<br />
=Массивы=<br />
An array is a sequence of data in a list. Arrays are useful for storing multiple pieces of data in one variable, or mapping one type of data to another.<br />
<br />
==Объяснение==<br />
An array is declared using brackets. Some examples of arrays:<br />
<pawn><br />
int players[32]; // Содержит 32 целых чисел.<br />
float origin[3]; // Содержит 3 числа с плавающей точкой<br />
</pawn><br />
<br />
By default, arrays are initialized to 0. You can assign them different default values, however:<br />
<pawn><br />
int numbers[5] = {1, 2, 3, 4, 5}; // Stores 1, 2, 3, 4, 5.<br />
float origin[3] = {1.0, 2.0, 3.0}; // Stores 1.0, 2.0, 3.0.<br />
</pawn><br />
<br />
You can leave out the array size if you're going to pre-assign data to it. For example:<br />
<pawn><br />
int numbers[] = {1, 3, 5, 7, 9};<br />
</pawn><br />
<br />
The compiler will automatically deduce that you intended an array of size 5.<br />
<br />
When array is declared with brackets after its name, Pawn considers that array to have a '''fixed size'''. The size of a fixed-size array is always known. Some arrays can be '''dynamically sized''', by putting the brackets before the name. For example,<br />
<br />
<pawn><br />
int[] numbers = new int[MaxClients]<br />
</pawn><br />
<br />
This creates an array of size <tt>MaxClients</tt>, which could be anything, so the size of the array is not known until the array is allocated.<br />
<br />
==Использование==<br />
Using an array is just like using a normal variable. The only difference is the array must be '''indexed'''. Indexing an array means choosing the element which you wish to use.<br />
<br />
For example, here is an example of the above code using indexes:<br />
<pawn><br />
int numbers[5];<br />
float origin[3];<br />
<br />
numbers[0] = 1;<br />
numbers[1] = 2;<br />
numbers[2] = 3;<br />
numbers[3] = 4;<br />
numbers[4] = 5;<br />
origin[0] = 1.0;<br />
origin[1] = 2.0;<br />
origin[2] = 3.0;<br />
</pawn><br />
<br />
Note that the '''index''' is what's in between the brackets. The index always starts from 0. That is, if an array has N elements, its valid indexes are from 0 to N-1. Accessing the data at these indexes works like a normal variable.<br />
<br />
Using an incorrect index will cause an error. For example:<br />
<pawn><br />
int numbers[5];<br />
<br />
numbers[5] = 20;</pawn><br />
<br />
This may look correct, but 5 is not a valid index. The highest valid index is 4.<br />
<br />
You can use any expression as an index. For example:<br />
<pawn>int a, numbers[5];<br />
<br />
a = 1; // Устанавливаем значение a = 1<br />
numbers[a] = 4; // Set numbers[1] = 4<br />
numbers[numbers[a]] = 2; // Set numbers[4] = 2<br />
</pawn><br />
<br />
Expressions will be discussed in depth later in the article.<br />
<br />
=Строки=<br />
Strings are a construct for storing text (or even raw binary data). A string is just an array of characters, except that the final character must be 0 (called the null terminator). Without a null terminator, Pawn would not know where to stop reading the string. All strings are [http://en.wikipedia.org/wiki/UTF-8 UTF-8] in SourcePawn.<br />
<br />
In general, you must have an idea of how large a string will be before you store it. SourcePawn does not yet have the capability of pre-determining storage space for strings.<br />
<br />
==Использование==<br />
Обычно строки объявляются в виде массивов. Пример:<br />
<pawn><br />
char message[] = "Привет!";<br />
char clams[6] = "Мидии";<br />
</pawn><br />
<br />
Это эквивалентно можно сделать:<br />
<pawn><br />
char message[7];<br />
char clams[6];<br />
<br />
message[0] = 'П';<br />
message[1] = 'р';<br />
message[2] = 'и';<br />
message[3] = 'в';<br />
message[4] = 'е';<br />
message[5] = 'т';<br />
message[6] = '!';<br />
message[7] = 0;<br />
clams[0] = 'м';<br />
clams[1] = 'и';<br />
clams[2] = 'д';<br />
clams[3] = 'и';<br />
clams[4] = 'и';<br />
clams[5] = 0;<br />
</pawn><br />
<br />
Although strings are rarely initialized in this manner, it is very important to remember the concept of the null terminator, which signals the end of a string. The compiler, and most SourceMod functions will automatically null-terminate for you, so it is mainly important when manipulating strings directly.<br />
<br />
Note that a string is enclosed in double-quotes, but a character is enclosed in single quotes.<br />
<br />
==Characters==<br />
A character of text can be used in either a String or a cell. For example:<br />
<pawn>char text[] = "Crab";<br />
char clam;<br />
<br />
clam = 'D'; //Set clam to 'D'<br />
text[0] = 'A'; //Change the 'C' to 'A', it is now 'Arab'<br />
clam = text[0]; //Set clam to 'A'<br />
text[1] = clam; //Change the 'r' to 'A', is is now 'AAab'<br />
</pawn><br />
<br />
What you can't do is mix character arrays with strings. The internal storage is different. For example:<br />
<pawn><br />
int clams[] = "Clams"; // Invalid.<br />
int clams[] = {'C', 'l', 'a', 'm', 's', 0}; // Valid, but NOT A STRING.<br />
</pawn><br />
<br />
=Functions=<br />
Functions, as stated before, are isolated blocks of code that perform an action. They can be invoked, or '''called''', with '''parameters''' that give specific options.<br />
<br />
There are two types of ways functions are called:<br />
*'''direct call''' - You specifically call a function in your code.<br />
*'''callback''' - The application calls a function in your code, as if it were an event trigger.<br />
<br />
There are six types of functions:<br />
*'''native''': A direct, internal function provided by the application.<br />
*'''public''': A callback function that is visible to the application and other scripts.<br />
*'''normal''': A normal function that only you can call.<br />
*'''static''': The scope of this function is restricted to the current file, can be used in combination with stock.<br />
*'''stock''': A normal function provided by an include file. If unused, it won't be compiled.<br />
*'''forward''': This function is a global event provided by the application. If you implement it, it will be a callback.<br />
<br />
All code in Pawn must exist in functions. This is in contrast to languages like PHP, Perl, and Python which let you write global code. That is because Pawn is a callback-based language: it responds to actions from a parent application, and functions must be written to handle those actions. Although our examples often contain free-floating code, this is purely for demonstration purposes. Free-floating code in our examples implies the code is part of some function.<br />
<br />
==Declaration==<br />
Unlike variables, functions do not need to be declared before you use them. Functions have two pieces, the '''signature''' and the '''body'''. The signature contains the name of your function and the parameters it will accept. The body is the contents of its code.<br />
<br />
Example of a function:<br />
<pawn><br />
int AddTwoNumbers(int first, int second)<br />
{<br />
int sum = first + second;<br />
return sum;<br />
}</pawn><br />
<br />
This is a simple function. The prototype is this line:<br />
<pawn>int AddTwoNumbers(int first, int second)</pawn><br />
<br />
Broken down, it means:<br />
*<tt>int</tt> - Return value type (integer).<br />
*<tt>AddTwoNumbers</tt> - Name of the function.<br />
*<tt>int first</tt> - First parameter, an integer.<br />
*<tt>int second</tt> - Second parameter, an integer.<br />
<br />
The body is a block of code. It creates a new variable, called <tt>sum</tt>, and assigns it the value of the two parameters added together (more on expressions later). The important thing to notice is the <tt>return</tt> statement, which tells the function to end and return a value to the caller of the function. All functions return something on completion, unless they return a special type called <tt>void</tt>.<br />
<br />
A function can accept any type of input, and it can return any non-array type.<br />
<br />
You can, of course, pass variables to functions:<br />
<pawn>int numbers[3] = {1, 2, 0};<br />
<br />
numbers[2] = AddTwoNumbers(numbers[0], numbers[1]);</pawn><br />
<br />
Note that cells are passed '''by value'''. That is, their value cannot be changed by the function. For example:<br />
<pawn>int a = 5;<br />
<br />
ChangeValue(a);<br />
<br />
ChangeValue(b)<br />
{<br />
b = 5;<br />
}</pawn><br />
<br />
This code would not change the value of <tt>a</tt>. That is because a copy of the value in <tt>a</tt> is passed instead of <tt>a</tt> itself. <br />
<br />
More examples of functions will be provided throughout the article.<br />
<br />
==Publics==<br />
Public functions are used to implement callbacks. You should not create a public function unless it is specifically implementing a callback. For example, here are two callbacks from <tt>sourcemod.inc</tt>:<br />
<br />
<pawn>forward void OnPluginStart();<br />
forward void OnClientDisconnected(int client);</pawn><br />
<br />
To implement and receive these two events, you would write functions as such:<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
/* Code here */<br />
}<br />
<br />
public void OnClientDisconnected(int client)<br />
{<br />
/* Code here */<br />
}</pawn><br />
<br />
The '''public''' keyword signals to the parent application that it should attach the function to the appropriate forwarded event.<br />
<br />
==Natives==<br />
Natives are builtin functions provided by SourceMod. You can call them as if they were a normal function. For example, SourceMod has the following function:<br />
<br />
<pawn>native float FloatRound(float num);</pawn><br />
<br />
It can be called like so:<br />
<pawn>int rounded = FloatRound(5.2); // rounded will be 5</pawn><br />
<br />
==Array Parameters==<br />
You can pass arrays or Strings as parameters. It is important to note that these are passed '''by reference'''. That is, rather than making a copy of the data, the data is referenced directly. There is a simple way of explaining this more concretely.<br />
<br />
<pawn><br />
int example[] = {1, 2, 3, 4, 5};<br />
<br />
ChangeArray(example, 2, 29);<br />
<br />
void ChangeArray(int[] array, int index, int value)<br />
{<br />
array[index] = value;<br />
}</pawn><br />
<br />
The function sets the given index in the array to a given value. When it is run on our example array, it changes index 2 to from the value 3 to 29. I.e.:<br />
<pawn>example[2] = 29;</pawn><br />
<br />
Note two important things here. First, arrays are not copied when they are passed to functions - they are passed ''by reference'', so the view of the array is consistent at all times. Second, the brackets changed position in our function signature. This is because our function accepts an array of any size, and since we don't know the size, we must use the dynamic array syntax.<br />
<br />
To prevent an array from being modified in a function, you can mark it as <tt>const</tt>. This will raise an error on code that attempts to modify it. For example:<br />
<br />
<pawn>void CantChangeArray(const array[], int index, int value)<br />
{<br />
array[index] = value; //Won't compile<br />
}</pawn><br />
<br />
It is a good idea to use <tt>const</tt> in array parameters if you know the array won't be modified; this can prevent coding mistakes.<br />
<br />
=Expressions=<br />
Expressions are exactly the same as they are in mathematics. They are groups of operators/symbols which evaluate to one piece of data. They are often parenthetical (comprised of parenthesis). They contain a strict "order of operations." They can contain variables, functions, numbers, and expressions themselves can be nested inside other expressions, or even passed as parameters.<br />
<br />
The simplest expression is a single number. For example:<br />
<pawn><br />
0; //Returns the number 0<br />
(0); //Returns the number 0 as well<br />
</pawn><br />
<br />
Although expressions can return any value, they are also said to either return ''zero or non-zero''. In that sense, ''zero'' is ''false'', and ''non-zero'' is ''true''. For example, -1 is '''true''' in Pawn, since it is non-zero. Do not assume negative numbers are false.<br />
<br />
The order of operations for expressions is similar to C. PMDAS: Parenthesis, Multiplication, Division, Addition, Subtraction. Here are some example expressions:<br />
<pawn><br />
5 + 6; //Evaluates to 11<br />
5 * 6 + 3; //Evaluates to 33<br />
5 * (6 + 3); //Evaluates to 45<br />
5.0 + 2.3; //Evaluates to 7.3<br />
(5 * 6) % 7; //Modulo operator, evaluates to 2<br />
(5 + 3) / 2 * 4 - 9; //Evaluates to -8<br />
</pawn><br />
<br />
As noted, expressions can contain variables, or even functions:<br />
<pawn><br />
int a = 5 * 6;<br />
int b = a * 3; //Evaluates to 90<br />
int c = AddTwoNumbers(a, b) + (a * b);<br />
</pawn><br />
<br />
Note: String manipulation routines may be found in the string.inc file located in the include subdirectory. They may be browsed through the [http://docs.sourcemod.net/api/ API Reference] as well.<br />
<br />
==Operators==<br />
There are a few extra helpful operators in Pawn. The first set simplifies self-aggregation expressions. For example:<br />
<pawn>int a = 5;<br />
<br />
a = a + 5;</pawn><br />
<br />
Can be rewritten as:<br />
<pawn>int a = 5;<br />
a += 5;</pawn><br />
<br />
This is true of the following operators in Pawn:<br />
*Four-function: *, /, -, +<br />
*Bit-wise: |, &, ^, ~, <<, >><br />
<br />
Additionally, there are increment/decrement operators:<br />
<pawn>a = a + 1;<br />
a = a - 1;</pawn><br />
<br />
Can be simplified as:<br />
<pawn>a++;<br />
a--;</pawn><br />
<br />
As an advanced note, the ++ or -- can come before the variable (pre-increment, pre-decrement) or after the variable (post-increment, post-decrement). The difference is in how the rest of the expression containing them sees their result.<br />
<br />
* ''Pre:'' The variable is incremented before evaluation, and the rest of the expression sees the new value.<br />
* ''Post:'' The variable is incremented after evaluation, and the rest of the expression sees the old value.<br />
<br />
In other words, <tt>a++</tt> evaluates to the value of <tt>a</tt> while <tt>++a</tt> evaluates to the value of <tt>a + 1</tt>. In both cases <tt>a</tt> is incremented by <tt>1</tt>.<br />
<br />
For example:<br />
<br />
<pawn>int a = 5;<br />
int b = a++; // b = 5, a = 6 (1)<br />
int c = ++a; // a = 7, c = 7 (2)<br />
</pawn><br />
<br />
In (1) <tt>b</tt> is assigned <tt>a</tt>'s ''old'' value ''before'' it is incremented to <tt>6</tt>, but in (2) <tt>c</tt> is assigned <tt>a</tt>'s ''int'' value ''after'' it is incremented to <tt>7</tt>.<br />
<br />
==Comparison Operators==<br />
There are six operators for comparing two values numerically, and the result is either true (non-zero) or false (zero):<br />
*<tt>a == b</tt> - True if a and b have the same value.<br />
*<tt>a != b</tt> - True if a and b have different values.<br />
*<tt>a &gt; b</tt> - True if a is greater than b<br />
*<tt>a &gt;= b</tt> - True if a is greater than or equal to b<br />
*<tt>a &lt; b</tt> - True if a is less than b<br />
*<tt>a &lt;= b</tt> - True if a is less than or equal to b<br />
<br />
For example:<br />
<pawn><br />
(1 != 3); //Evaluates to true because 1 is not equal to 3.<br />
(3 + 3 == 6); //Evaluates to true because 3+3 is 6.<br />
(5 - 2 >= 4); //Evaluates to false because 3 is less than 4.<br />
</pawn><br />
<br />
Note that these operators do not work on arrays or strings. That is, you cannot compare either using <tt>==</tt>.<br />
<br />
==Truth Operators==<br />
These truth values can be combined using three boolean operators:<br />
*<tt>a && b</tt> - True if both a and b are true. False if a or b (or both) is false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>&&</tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 0<br />
|-<br />
! 1<br />
| 0 || 1<br />
|}<br />
*<tt>a || b</tt> - True if a or b (or both) is true. False if both a and b are false.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt><nowiki>||</nowiki></tt> !! 0 !! 1<br />
|-<br />
! 0<br />
| 0 || 1<br />
|-<br />
! 1<br />
| 1 || 1<br />
|}<br />
*<tt>!a</tt> - True if a is false. False if a is true.<br />
{| border="1" cellpadding="2" cellspacing="0" align="center"<br />
! <tt>!</tt> !! 0 !! 1<br />
|- <br />
!<br />
| 1 || 0<br />
|}<br />
<br />
For example:<br />
<pawn><br />
(1 || 0); //Evaluates to true because the expression 1 is true<br />
(1 && 0); //Evaluates to false because the expression 0 is false<br />
(!1 || 0); //Evaluates to false because !1 is false.<br />
</pawn><br />
<br />
==Left/Right Values==<br />
Two important concepts are left-hand and right-hand values, or l-values and r-values. An l-value is what appears on the left-hand side of a variable assignment, and an r-value is what appears on the right side of a variable assignment.<br />
<br />
For example:<br />
<pawn><br />
int a = 5;</pawn><br />
<br />
In this example <tt>a</tt> is an l-value and <tt>5</tt> is an r-value.<br />
<br />
The rules:<br />
*'''Expressions are never l-values'''.<br />
*'''Variables are both l-values and r-values'''.<br />
<br />
=Conditionals=<br />
Conditional statements let you only run code if a certain condition is matched.<br />
<br />
==If Statements==<br />
If statements test one or more conditions. For example:<br />
<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code that will run if the expression was true */<br />
}</pawn><br />
<br />
They can be extended to handle more cases as well:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 6)<br />
{<br />
/* Code */<br />
}<br />
else if (a == 7)<br />
{<br />
/* Code */<br />
}</pawn><br />
<br />
You can also handle the case of no expression being matched. For example:<br />
<pawn><br />
if (a == 5)<br />
{<br />
/* Code */<br />
}<br />
else<br />
{<br />
/* Code that will run if no expressions were true */<br />
}</pawn><br />
<br />
==Switch Statements==<br />
Switch statements are restricted if statements. They test one expression for a series of possible values. For example:<br />
<br />
<pawn><br />
switch (a)<br />
{<br />
case 5:<br />
{<br />
/* code */<br />
}<br />
case 6:<br />
{<br />
/* code */<br />
}<br />
case 7:<br />
{<br />
/* code */<br />
}<br />
case 8, 9, 10:<br />
{<br />
/* Code */<br />
}<br />
default:<br />
{<br />
/* will run if no case matched */<br />
}<br />
}</pawn><br />
<br />
Unlike some other languages, switches are not fall-through. That is, multiple cases will never be run. When a case matches its code is executed, and the switch is then immediately terminated.<br />
<br />
=Loops=<br />
Loops allow you to conveniently repeat a block of code while a given condition remains true. <br />
<br />
==For Loops==<br />
For loops are loops which have four parts:<br />
*The '''initialization''' statement - run once before the first loop.<br />
*The '''condition''' statement - checks whether the next loop should run, including the first one. The loop terminates when this expression evaluates to false.<br />
*The '''iteration''' statement - run after each loop.<br />
*The '''body''' block - run each time the '''condition''' statement evaluates to true.<br />
<br />
<pawn><br />
for ( /* initialization */ ; /* condition */ ; /* iteration */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
A simple example is a function to sum an array:<br />
<pawn><br />
int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};<br />
int sum = SumArray(array, 10);<br />
<br />
int SumArray(const int array[], int count)<br />
{<br />
int total;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
total += array[i];<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
Broken down:<br />
*<tt>int i = 0</tt> - Creates a new variable for the loop, sets it to 0.<br />
*<tt>i < count</tt> - Only runs the loop if <tt>i</tt> is less than <tt>count</tt>. This ensures that the loop stops reading at a certain point. In this case, we don't want to read invalid indexes in the array.<br />
*<tt>i++</tt> - Increments <tt>i</tt> by one after each loop. This ensures that the loop doesn't run forever; eventually <tt>i</tt> will become too big and the loop will end.<br />
<br />
Thus, the <tt>SumArray</tt> function will loop through each valid index of the array, each time adding that value of the array into a sum. For loops are very common for processing arrays like this.<br />
<br />
==While Loops==<br />
While loops are less common than for loops but are actually the simplest possible loop. They have only two parts:<br />
*The '''condition''' statement - checked before each loop. The loop terminates when it evaluates to false.<br />
*The '''body''' block - run each time through the loop.<br />
<br />
<pawn><br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
}<br />
</pawn><br />
<br />
As long as the condition expression remains true, the loop will continue. Every for loop can be rewritten as a while loop:<br />
<br />
<pawn><br />
/* initialization */<br />
while ( /* condition */ )<br />
{<br />
/* body */<br />
/* iteration */<br />
}<br />
</pawn><br />
<br />
Here is the previous for loop rewritten as a while loop:<br />
<pawn><br />
int SumArray(const int array[], int count)<br />
{<br />
int total, i;<br />
<br />
while (i < count)<br />
{<br />
total += array[i];<br />
i++;<br />
}<br />
<br />
return total;<br />
}</pawn><br />
<br />
There are also '''do...while''' loops which are even less common. These are the same as while loops except the condition check is AFTER each loop, rather than before. This means the loop is always run at least once. For example:<br />
<br />
<pawn><br />
do<br />
{<br />
/* body */<br />
}<br />
while ( /* condition */ );<br />
</pawn><br />
<br />
==Loop Control==<br />
There are two cases in which you want to selectively control a loop:<br />
*'''skipping''' one iteration of the loop but continuing as normal, or;<br />
*'''breaking''' the loop entirely before it's finished.<br />
<br />
Let's say you have a function which takes in an array and searches for a matching number. You want it to stop once the number is found:<br />
<pawn><br />
/**<br />
* Returns the array index where the value is, or -1 if not found.<br />
*/<br />
int SearchInArray(const int array[], int count, int value)<br />
{<br />
int index = -1;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
if (array[i] == value)<br />
{<br />
index = i;<br />
break;<br />
}<br />
}<br />
<br />
return index;<br />
}</pawn><br />
<br />
Certainly, this function could simply <tt>return i</tt> instead, but the example shows how <tt>break</tt> will terminate the loop.<br />
<br />
Similarly, the <tt>continue</tt> keyword skips an iteration of a loop. For example, let's say we wanted to sum all even numbers:<br />
<pawn><br />
int SumEvenNumbers(const int array[], int count)<br />
{<br />
int sum;<br />
<br />
for (int i = 0; i < count; i++)<br />
{<br />
/* If divisibility by 2 is 1, we know it's odd */<br />
if (array[i] % 2 == 1)<br />
{<br />
/* Skip the rest of this loop iteration */<br />
continue;<br />
}<br />
sum += array[i];<br />
}<br />
<br />
return sum;<br />
}</pawn><br />
<br />
=Scope=<br />
Scope refers to the '''visibility''' of code. That is, code at one level may not be "visible" to code at another level. For example:<br />
<br />
<pawn><br />
int A, B, C;<br />
<br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function2();<br />
}<br />
<br />
void Function2()<br />
{<br />
int C;<br />
}</pawn><br />
<br />
In this example, <tt>A</tt>, <tt>B</tt>, and <tt>C</tt> exist at '''global scope'''. They can be seen by any function. However, the <tt>B</tt> in <tt>Function1</tt> is not the same variable as the <tt>B</tt> at the global level. Instead, it is at '''local scope''', and is thus a '''local variable'''.<br />
<br />
Similarly, <tt>Function1</tt> and <tt>Function2</tt> know nothing about each other's variables.<br />
<br />
Not only is the variable private to <tt>Function1</tt>, but it is re-created each time the function is invoked. Imagine this:<br />
<pawn><br />
void Function1()<br />
{<br />
int B;<br />
<br />
Function1();<br />
}</pawn><br />
<br />
In the above example, <tt>Function1</tt> calls itself. Of course, this is infinite recursion (a bad thing), but the idea is that each time the function runs, there is a new copy of <tt>B</tt>. When the function ends, <tt>B</tt> is destroyed, and the value is lost.<br />
<br />
This property can be simplified by saying that a variable's scope is equal to the nesting level it is in. That is, a variable at global scope is visible globally to all functions. A variable at local scope is visible to all code blocks "beneath" its nesting level. For example:<br />
<br />
<pawn>void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
A = 5;<br />
}<br />
}</pawn><br />
<br />
The above code is valid since A's scope extends throughout the function. The following code, however, is not valid:<br />
<pawn><br />
void Function1()<br />
{<br />
int A;<br />
<br />
if (A)<br />
{<br />
int B = 5;<br />
}<br />
<br />
B = 5;<br />
}</pawn><br />
<br />
Notice that <tt>B</tt> is declared in a new code block. That means <tt>B</tt> is only accessible to that code block (and all sub-blocks nested within). As soon as the code block terminates, <tt>B</tt> is no longer valid.<br />
<br />
=Dynamic Arrays=<br />
Dynamic arrays are arrays which don't have a hardcoded size. For example:<br />
<br />
<pawn>void Function1(int size)<br />
{<br />
int array[size];<br />
<br />
/* Code */<br />
}</pawn><br />
<br />
Dynamic arrays can have any expression as their size as long as the expression evaluates to a number larger than 0. Like normal arrays, SourcePawn does not know the array size after it is created; you have to save it if you want it later.<br />
<br />
Dynamic arrays are only valid at the local scope level, since code cannot exist globally.<br />
<br />
=Extended Variable Declarations=<br />
Variables can be declared in more ways than simply <tt>int float or char</tt>.<br />
<br />
==static==<br />
The <tt>static</tt> keyword is available at global and local scope. It has different meanings in each.<br />
<br />
===Global static===<br />
A global static variable can only be accessed from within the same file. For example:<br />
<br />
<pawn>//file1.inc<br />
static float g_value1 = 0.15f;<br />
<br />
//file2.inc<br />
static float g_value2 = 0.15f;</pawn><br />
<br />
If a plugin includes both of these files, it will not be able to use either <tt>g_value1</tt> or <tt>g_value2</tt>. This is a simple information hiding mechanism, and is similar to declaring member variables as <tt>private</tt> in languages like C++, Java, or C#.<br />
<br />
===Local static===<br />
A local static variable is a global variable that is only visible from its local lexical scope. For example:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
static int counter = -1;<br />
<br />
counter += inc;<br />
<br />
return counter;<br />
}</pawn><br />
<br />
In this example, <tt>counter</tt> is technically a global variable -- it is initialized once to -1 and is never initialized again. It does not exist on the stack. That means each time <tt>MyFunction</tt> runs, the <tt>counter</tt> variable and its storage in memory is the same.<br />
<br />
Take this example:<br />
<pawn>MyFunction(5);<br />
MyFunction(6);<br />
MyFunction(10);</pawn><br />
<br />
In this example, <tt>counter</tt> will be <tt>-1 + 5 + 6 + 10</tt>, or <tt>20</tt>, because it persists beyond the frame of the function. Note this may pose problems for recursive functions: if your function may be recursive, then <tt>static</tt> is usually not a good idea unless your code is re-entrant. <br />
<br />
The benefit of a local static variable is that you don't have to clutter your script with global variables. As long as the variable doesn't need to be read by another function, you can squirrel it inside the function and its persistence will be guaranteed.<br />
<br />
Note that statics can exist in any local scope:<br />
<br />
<pawn><br />
int MyFunction(int inc)<br />
{<br />
if (inc > 0)<br />
{<br />
static int counter;<br />
return (counter += inc);<br />
}<br />
return -1;<br />
}</pawn><br />
<br />
[[Category:SourceMod Scripting]]<br />
<br />
{{LanguageSwitch}}</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Category:Ru:SourceMod_Scripting&diff=10198Category:Ru:SourceMod Scripting2016-08-20T15:27:10Z<p>MAGNAT2645: </p>
<hr />
<div>Эта категория содержит статьи о написании скриптов под SourceMod с использованием SourcePawn.<br />
<br />
===Введение===<br />
*[[Ru:Introduction to SourcePawn|Ru:Introduction to SourcePawn]] - Введение в SourcePawn. Обучение синтаксису языка.<br />
*[[Ru:Introduction to SourceMod Plugins|Ru:Introduction to SourceMod Plugins]] - Введение в SourceMod плагины. Создаем Ваш "первый плагин".<br />
*[http://docs.sourcemod.net/api API Reference] - Поиск сценариев в справочнике API.<br />
<br />
===Основной API===<br />
*[[Ru:AutoConfigs (SourceMod Scripting)|Автоконфиги]] - Автоматическое создание .cfg файлов.<br />
*[[Ru:Commands (SourceMod Scripting)|Команды]] - Консольные команды/ввод.<br />
*[[Ru:ConVars (SourceMod Scripting)|Консольные переменные]] - Консольные переменные (cvars).<br />
*[[Ru:Events (SourceMod Scripting)|События]] - Игровые события Half-Life.<br />
*[[Ru:KeyValues (SourceMod Scripting)|КлючЗначение]] - KeyValues анализ/запись файла.<br />
*[[Ru:Menu API (SourceMod)|Меню]] - Создание и отображение меню.<br />
*[[Ru:SQL (SourceMod Scripting)|SQL]] - Использование баз данных (MySQL, SQLite).<br />
*[[Ru:Timers (SourceMod Scripting)|Таймеры]] - Вызов таймеров.<br />
*[[Ru:Translations (SourceMod Scripting)|Переводы]] - Создание локализаций.<br />
<br />
===Продвинутый API===<br />
*[[Admin API (SourceMod)|API администрирования]] - Использование кэша администратора.<br />
*[[Admin Menu (SourceMod Scripting)|API админского меню]] - Закрепление в меню администратора.<br />
*[[Creating Natives (SourceMod Scripting)|Создание нативных функция]] - Разоблачение API других плагинов.<br />
*[[Function Calling API (SourceMod Scripting)|API вызова функция]] - Вызовы внешних функций.<br />
*[[Optional Requirements (SourceMod Scripting)|Необязательные требования]] - Управление зависимостями.<br />
*[[SDKTools (SourceMod Scripting)|SDKTools]] - Использование мощного SDK уровней абстракции.<br />
*[[TempEnts (SourceMod SDKTools)|Временные объекты]] - Использование временных объектов.<br />
<br />
===Информация===<br />
*[[Deprecation Schedule (SourceMod Scripting)|Deprecation Schedule]] - Which functions are getting removed.<br />
*[[Ru:Format Class Functions (SourceMod Scripting)|Ru:Format Class Functions]] - Всё про форматирование текста.<br />
*[[Handles (SourceMod Scripting)|Handles]] - Обзор Handle и несколько распространённых типов.<br />
*[[Optimizing Plugins (SourceMod Scripting)|Optimizing Plugins]] - Советы по оптимизации.<br />
*[[Tags (Scripting)|Tags]] - Всё о тэгах.<br />
*[[Vectors Explained (Scripting)|Vectors Explained]] - Объяснение типов Вектора.<br />
<br />
===Дополнительные средства===<br />
*[http://docs.sourcemod.net/api API Reference] - Searchable scripting API reference.<br />
*[[Entity Properties]] - Explanation of Source entity properties.<br />
*[[Game Events (Source)|Game Events]] - Game events listings for popular mods.<br />
*[[Mod TempEnt List (Source)|Temp Entity Lists]] - Temporary entities for popular mods.<br />
*[[SourceMod Profiler]] - Отслеживание производительности и оптимизации.</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Commands_(SourceMod_Scripting)&diff=10197Ru:Commands (SourceMod Scripting)2016-08-20T14:53:58Z<p>MAGNAT2645: </p>
<hr />
<div>[[SourceMod]] позволяет создать вам консольные команды, похожие на [[AMX Mod X]]. Есть два главных вида консольных команд:<br />
*'''Серверные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли сервера<br />
**С помощью удаленной консоли (RCON)<br />
**Функция ServerCommand(), либо из SourceMod либо [[Half-Life 2]] движка<br />
*'''Консольные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли клиента<br />
**Любой из методов ввода серверных команд<br />
<br />
Для серверных команд не существует клиентского индекса. Для консольных/клиентских команд, существует клиентский индекс, но он может быть 0, чтобы показать, что команда с сервера.<br />
<br />
Обратите внимание, что кнопка-бинд "commands", такие как +attack и +duck, они не консольные команды. Эти команды отдельно передаются, посколько они отдельно привязаны. <br />
<br />
=Серверные команды=<br />
Как отмечалось выше, серверные команды срабатывают через консоль сервера, будь то удалённую, локальную, или через движок Source. Индекс клиента не связан с серверными командами. <br />
<br />
Серверные команды регистрируются через <tt>RegServerCmd()</tt> функцию, расположенную в <tt>console.inc</tt>. При регистрации команды, вы можете записать поверх существующей команды, и таким образом, возвращаемое значение становится важным.<br />
*<b><tt>Plugin_Continue</tt></b> - The original server command will be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Handled</tt></b> - The original server command will not be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Stop</tt></b> - The original server command will not be processed, if there was one. Additionally, no further hooks will be called for this command until it is fired again.<br />
<br />
==Добавление серверных команд==<br />
Допустим, мы хотим добавить тестовую команду, чтобы показать как Half-Life 2 вычисляет аргументы команды. Вот возможная реализация:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
PrintToServer("Строка аргумента: %s", full)<br />
PrintToServer("Количество аргументов: %d", args)<br />
for (int i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Аргумент %d: %s", i, arg)<br />
}<br />
}<br />
</pawn><br />
<br />
==Блокирование серверных команд==<br />
Допустим мы хотим отключить "kickid" команду на сервере. Нет причин делать это, но для примера сойдет:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("kickid", Command_KickId)<br />
}<br />
<br />
public Action Command_Kickid(int args)<br />
{<br />
return Plugin_Handled<br />
}<br />
</pawn><br />
<br />
=Консольные команды=<br />
В отличие от серверных команд, консольные могут быть вызваны, как сервером, так и клиентом, так что callback функция получает клиентский индекс, а также количество аргументов. Если сервер использовал команду, клиентский индекс будет 0. <br />
<br />
When returning the <tt>Action</tt> from the callback, the following effects will happen:<br />
*<tt>Plugin_Continue</tt>: The original functionality of the command (if any) will still be processed. If there was no original functionality, the client will receive "Unknown command" in their console.<br />
*<tt>Plugin_Handled</tt>: The original functionality of the command (if any) will be blocked. If there was no functionality originally, this prevents clients from seeing "Unknown command" in their console.<br />
*<tt>Plugin_Stop</tt>: Same as <tt>Plugin_Handled</tt>, except that this will be the last hook called.<br />
<br />
Обратите внимание, в отличие от AMX Mod X, SourceMod не сможет зарегистрировать командные фильтры. т.е. нет эквивалента этой команды:<br />
<pawn>register_clcmd("say /ff", "Command_SayFF");</pawn><br />
<br />
Это было удаленно, чтобы сделать наш код проще и быстрее. Написание такого же функционала легче и показано ниже.<br />
<br />
==Добавление команд==<br />
Создать клиентские команды очень просто. Давайте переделаем нашу тест команду, чтобы можно было отобразить информацию о клиенте.<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegConsoleCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int client, int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
if (client)<br />
{<br />
char name[32]<br />
GetClientName(client, name, sizeof(name))<br />
PrintToServer("Команда от клиента: %s", name)<br />
} else {<br />
PrintToServer("Команда от сервера.")<br />
}<br />
<br />
PrintToServer("Строка аргументов: %s", full)<br />
PrintToServer("Количество аргументов: %d", args)<br />
for (int i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Аргумент %d: %s", i, arg)<br />
}<br />
}</pawn><br />
<br />
==Захват команд==<br />
Пример: захват типичной команды say. Let's say we want to tell players whether FF is enabled when they say '/ff' in game. <br />
<br />
Before we implement this, a common point of confusion with the 'say' command is that Half-Life 2 (and Half-Life 1), by default, send it with the text in one big quoted string. This means if you say "I like hot dogs," your command will be broken down as such:<br />
*Argument string: "I like hot dogs"<br />
*Argument count: 1<br />
*Argument #1: I like hot dogs<br />
<br />
However, if a player types this in their console: <tt>say I like yams</tt>, it will be broken up as:<br />
*Argument string: I like yams<br />
*Argument count: 3<br />
*Argument #1: I<br />
*Argument #2: like<br />
*Argument #3: yams<br />
<br />
Thus, to take into account both of these situations, we are going to use <tt>GetCmdArgString</tt> and manually parse the input. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegConsoleCmd("say", Command_Say)<br />
}<br />
<br />
public Action Command_Say(int client, int args)<br />
{<br />
char text[192]<br />
GetCmdArgString(text, sizeof(text))<br />
<br />
int startidx = 0<br />
if (text[0] == '"')<br />
{<br />
startidx = 1<br />
/* Лишаем ковычки от окончания, если есть */<br />
int len = strlen(text);<br />
if (text[len-1] == '"')<br />
{<br />
text[len-1] = '\0'<br />
}<br />
}<br />
<br />
if (StrEqual(text[startidx], "/ff"))<br />
{<br />
Handle ff = FindConVar("mp_friendlyfire")<br />
if (GetConVarInt(ff))<br />
{<br />
PrintToConsole(client, "Огонь по товарищам включен.")<br />
} else {<br />
PrintToConsole(client, "Огонь по товарищам выключен.")<br />
}<br />
/* Блокирование сообщения клиента от вещания */<br />
return Plugin_Handled<br />
}<br />
<br />
/* Пусть работает как обычно */<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
==Создание Админской команды==<br />
Давайте создадим простую админскую команду, которая позволяет кикнуть игрока, по его полному имени. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegAdminCmd("admin_kick",<br />
Command_Kick,<br />
ADMFLAG_KICK,<br />
"Кикает игрока по нику")<br />
}<br />
<br />
public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target));<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
==Иммунитет==<br />
В нашем прошлом примере, мы не сделали иммунитет. Иммунитет является гораздно сложной системой в SourceMod, чем это было в AMX Mod X, и не существует просто флага, чтобы обозначить его. Вместо, этого существует две функции:<br />
*<tt>CanAdminTarget</tt>: Проверяет исходные значения AdminId для иммунитета.<br />
*<tt>CanUserTarget</tt>: Проверяет внутриигровых клиентов для иммунитета.<br />
<br />
While immunity is generally tested ''player versus player'', it is possible you might want to check for immunity and not have a targetting client. While there is no convenience function for this yet, a good idea might be to check for either ''default'' or ''global'' immunity on the player's groups (these can be user-defined for non-player targeted scenarios).<br />
<br />
When checking for immunity, the following heuristics are performed in this exact order:<br />
<ol><li>If the targeting AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting fails.</li><br />
<li>If the targetted AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting succeeds.</li><br />
<li>If the targeting admin has <tt>Admin_Root</tt> (<tt>ADMFLAG_ROOT</tt>), targeting succeeds.</li><br />
<li>If the targetted admin has global immunity, targeting fails.</li><br />
<li>If the targetted admin has default immunity, and the targeting admin belongs to no groups, targeting fails.</li><br />
<li>If the targetted admin has specific immunity from the targeting admin via group immunities, targeting fails.</li><br />
<li>If no conclusion is reached via the previous steps, targeting succeeds.</li><br />
</ol><br />
<br />
So, how can we adapt our function about to use immunity?<br />
<br />
<pawn>public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
if (!CanUserTarget(client, target))<br />
{<br />
PrintToConsole(client, "Вы не можете использовать этого клиента как цель.")<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target))<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
=Только клиентские команды=<br />
SourceMod exposes a forward that is called whenever a client executes any command string in their console, called <tt>OnClientCommand</tt>. An example of this looks like:<br />
<br />
<pawn>public Action OnClientCommand(int client, int args)<br />
{<br />
char cmd[16]<br />
GetCmdArg(0, cmd, sizeof(cmd)); /* Получаем название команды */<br />
<br />
if (StrEqual(cmd, "test_command"))<br />
{<br />
/* Получаем клиентскую команду! Блокируем её... */<br />
return Plugin_Handled<br />
}<br />
<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
It is worth noting that not everything a client sends will be available through this command. Command registered via external sources in C++ may not be available, especially if they are created via <tt>CON_COMMAND</tt> in the game mod itself. For example, "say" is usually implemented this way, because it can be used by both clients and the server, and thus it does not channel through this forward.<br />
<br />
<br />
=Чат триггеры=<br />
SourceMod будет автоматически создавать чат триггеры для каждой команды, которую вы сделали (по ревизии 900). Для примера, если вы создали консольную команду "sm_megaslap", администраторы смогут набрать ее и в <tt>say</tt>/<tt>say_team</tt> режимах:<br />
<pre>!sm_megaslap<br />
!megaslap<br />
/sm_megaslap<br />
/megaslap</pre><br />
<br />
SourceMod будет выполнять эту команду и ее аргументы, как если бы она пришла из консоли клиента.<br />
*"<tt>!</tt>" является ''публичным'' триггером по умолчанию (<tt>PublicChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда будет отображена всем клиентам.<br />
*"<tt>/</tt>" является ''скрытым'' триггером по умолчанию (<tt>SilentChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда не будет показана остальным клиентам<br />
<br />
SourceMod будет исполнять только те команды, которые зарегистрированы с <tt>RegConsoleCmd</tt> или <tt>RegAdminCmd</tt>, и только если эти команды уже не используются Half-life 2 движком или другим игровым модом. Если команда идет с префиксом "sm_", то "sm_" можно исключить, из написания в чате.<br />
<br />
Консольные команды, которые хотят поддерживать использование в качестве триггера чата, не должны использовать нативы вроде <tt>PrintTo*</tt>. Вместо этого, они должны использовать <tt>ReplyToCommand()</tt>, которая будет автоматически печатать ваше сообщение либо в виде сообщения чата либо в виде консоли клиента, в зависимости от источника команды.<br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Commands_(SourceMod_Scripting)&diff=10196Ru:Commands (SourceMod Scripting)2016-08-20T14:49:17Z<p>MAGNAT2645: /* Чат триггеры */</p>
<hr />
<div>[[SourceMod]] позволяет создать вам консольные команды, похожие на [[AMX Mod X]]. Есть два главных вида консольных команд:<br />
*'''Серверные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли сервера<br />
**С помощью удаленной консоли (RCON)<br />
**Функция ServerCommand(), либо из SourceMod либо [[Half-Life 2]] движка<br />
*'''Консольные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли клиента<br />
**Любой из методов ввода серверных команд<br />
<br />
Для серверных команд не существует клиентского индекса. Для консольных/клиентских команд, существует клиентский индекс, но он может быть 0 что-бы показать что команда с сервера.<br />
<br />
Обратите внимание, что кнопка-бинд "commands", такие как +attack и +duck, они не консольные команды. Эти команды отдельно передаются, посколько они отдельно привязаны. <br />
<br />
=Серверные команды=<br />
Как отмечалось выше, серверные команды срабатывают через консоль сервера, будь то удалённую, локальную, или через движок Source. Индекс клиента не связан со серверными командами. <br />
<br />
Серверные команды регистрируются через <tt>RegServerCmd()</tt> функцию, расположенную в <tt>console.inc</tt>. При регистрации команды, вы можете записать поверх существующей команды, и таким образом, возвращаемое значение становится важным.<br />
*<b><tt>Plugin_Continue</tt></b> - The original server command will be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Handled</tt></b> - The original server command will not be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Stop</tt></b> - The original server command will not be processed, if there was one. Additionally, no further hooks will be called for this command until it is fired again.<br />
<br />
==Добавление серверных команд==<br />
Допустим, мы хотим добавить тестовую команду, чтобы показать как Half-Life 2 вычисляет аргументы команды. Вот возможная реализация:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
PrintToServer("Строка аргумента: %s", full)<br />
PrintToServer("Количество аргументов: %d", args)<br />
for (int i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Аргумент %d: %s", i, arg)<br />
}<br />
}<br />
</pawn><br />
<br />
==Блокирование серверных команд==<br />
Допустим мы хотим отключить "kickid" команду на сервере. Нет причин делать это, но для примера сойдет:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("kickid", Command_KickId)<br />
}<br />
<br />
public Action Command_Kickid(int args)<br />
{<br />
return Plugin_Handled<br />
}<br />
</pawn><br />
<br />
=Консольные команды=<br />
В отличие от серверных команд, консольные могут быть вызваны, как сервером, так и клиентом, так что callback функция получает клиентский индекс, а также количество аргументов. Если сервер использовал команду, клиентский индекс будет 0. <br />
<br />
When returning the <tt>Action</tt> from the callback, the following effects will happen:<br />
*<tt>Plugin_Continue</tt>: The original functionality of the command (if any) will still be processed. If there was no original functionality, the client will receive "Unknown command" in their console.<br />
*<tt>Plugin_Handled</tt>: The original functionality of the command (if any) will be blocked. If there was no functionality originally, this prevents clients from seeing "Unknown command" in their console.<br />
*<tt>Plugin_Stop</tt>: Same as <tt>Plugin_Handled</tt>, except that this will be the last hook called.<br />
<br />
Обратите внимание, в отличие от AMX Mod X, SourceMod не сможет зарегистрировать командные фильтры. т.е. нет эквивалента этой команды:<br />
<pawn>register_clcmd("say /ff", "Command_SayFF");</pawn><br />
<br />
Это было удаленно, чтобы сделать наш код проще и быстрее. Написание такого же функционала легче и показано ниже.<br />
<br />
==Добавление команд==<br />
Создать клиентские команды очень просто. Давайте переделаем нашу тест команду, чтобы можно было отобразить информацию о клиенте.<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegConsoleCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int client, int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
if (client)<br />
{<br />
char name[32]<br />
GetClientName(client, name, sizeof(name))<br />
PrintToServer("Команда от клиента: %s", name)<br />
} else {<br />
PrintToServer("Команда от сервера.")<br />
}<br />
<br />
PrintToServer("Строка аргументов: %s", full)<br />
PrintToServer("Количество аргументов: %d", args)<br />
for (int i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Аргумент %d: %s", i, arg)<br />
}<br />
}</pawn><br />
<br />
==Захват команд==<br />
Пример: захват типичной команды say. Let's say we want to tell players whether FF is enabled when they say '/ff' in game. <br />
<br />
Before we implement this, a common point of confusion with the 'say' command is that Half-Life 2 (and Half-Life 1), by default, send it with the text in one big quoted string. This means if you say "I like hot dogs," your command will be broken down as such:<br />
*Argument string: "I like hot dogs"<br />
*Argument count: 1<br />
*Argument #1: I like hot dogs<br />
<br />
However, if a player types this in their console: <tt>say I like yams</tt>, it will be broken up as:<br />
*Argument string: I like yams<br />
*Argument count: 3<br />
*Argument #1: I<br />
*Argument #2: like<br />
*Argument #3: yams<br />
<br />
Thus, to take into account both of these situations, we are going to use <tt>GetCmdArgString</tt> and manually parse the input. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegConsoleCmd("say", Command_Say)<br />
}<br />
<br />
public Action Command_Say(int client, int args)<br />
{<br />
char text[192]<br />
GetCmdArgString(text, sizeof(text))<br />
<br />
int startidx = 0<br />
if (text[0] == '"')<br />
{<br />
startidx = 1<br />
/* Лишаем ковычки от окончания, если есть */<br />
int len = strlen(text);<br />
if (text[len-1] == '"')<br />
{<br />
text[len-1] = '\0'<br />
}<br />
}<br />
<br />
if (StrEqual(text[startidx], "/ff"))<br />
{<br />
Handle ff = FindConVar("mp_friendlyfire")<br />
if (GetConVarInt(ff))<br />
{<br />
PrintToConsole(client, "Огонь по товарищам включен.")<br />
} else {<br />
PrintToConsole(client, "Огонь по товарищам выключен.")<br />
}<br />
/* Блокирование сообщения клиента от вещания */<br />
return Plugin_Handled<br />
}<br />
<br />
/* Пусть работает как обычно */<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
==Создание Админской команды==<br />
Давайте создадим простую админскую команду, которая позволяет кикнуть игрока, по его полному имени. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegAdminCmd("admin_kick",<br />
Command_Kick,<br />
ADMFLAG_KICK,<br />
"Кикает игрока по нику")<br />
}<br />
<br />
public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target));<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
==Иммунитет==<br />
В нашем прошлом примере, мы не сделали иммунитет. Иммунитет является гораздно сложной системой в SourceMod, чем это было в AMX Mod X, и не существует просто флага, чтобы обозначить его. Вместо, этого существует две функции:<br />
*<tt>CanAdminTarget</tt>: Проверяет исходные значения AdminId для иммунитета.<br />
*<tt>CanUserTarget</tt>: Проверяет внутриигровых клиентов для иммунитета.<br />
<br />
While immunity is generally tested ''player versus player'', it is possible you might want to check for immunity and not have a targetting client. While there is no convenience function for this yet, a good idea might be to check for either ''default'' or ''global'' immunity on the player's groups (these can be user-defined for non-player targeted scenarios).<br />
<br />
When checking for immunity, the following heuristics are performed in this exact order:<br />
<ol><li>If the targeting AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting fails.</li><br />
<li>If the targetted AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting succeeds.</li><br />
<li>If the targeting admin has <tt>Admin_Root</tt> (<tt>ADMFLAG_ROOT</tt>), targeting succeeds.</li><br />
<li>If the targetted admin has global immunity, targeting fails.</li><br />
<li>If the targetted admin has default immunity, and the targeting admin belongs to no groups, targeting fails.</li><br />
<li>If the targetted admin has specific immunity from the targeting admin via group immunities, targeting fails.</li><br />
<li>If no conclusion is reached via the previous steps, targeting succeeds.</li><br />
</ol><br />
<br />
So, how can we adapt our function about to use immunity?<br />
<br />
<pawn>public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
if (!CanUserTarget(client, target))<br />
{<br />
PrintToConsole(client, "Вы не можете использовать этого клиента как цель.")<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target))<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
=Только клиентские команды=<br />
SourceMod exposes a forward that is called whenever a client executes any command string in their console, called <tt>OnClientCommand</tt>. An example of this looks like:<br />
<br />
<pawn>public Action OnClientCommand(int client, int args)<br />
{<br />
char cmd[16]<br />
GetCmdArg(0, cmd, sizeof(cmd)); /* Получаем название команды */<br />
<br />
if (StrEqual(cmd, "test_command"))<br />
{<br />
/* Получаем клиентскую команду! Блокируем её... */<br />
return Plugin_Handled<br />
}<br />
<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
It is worth noting that not everything a client sends will be available through this command. Command registered via external sources in C++ may not be available, especially if they are created via <tt>CON_COMMAND</tt> in the game mod itself. For example, "say" is usually implemented this way, because it can be used by both clients and the server, and thus it does not channel through this forward.<br />
<br />
<br />
=Чат триггеры=<br />
SourceMod будет автоматически создавать чат триггеры для каждой команды, которую вы сделали (по ревизии 900). Для примера, если вы создали консольную команду "sm_megaslap", администраторы смогут набрать ее и в <tt>say</tt>/<tt>say_team</tt> режимах:<br />
<pre>!sm_megaslap<br />
!megaslap<br />
/sm_megaslap<br />
/megaslap</pre><br />
<br />
SourceMod будет выполнять эту команду и ее аргументы, как если бы она пришла из консоли клиента.<br />
*"<tt>!</tt>" является ''публичным'' триггером по умолчанию (<tt>PublicChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда будет отображена всем клиентам.<br />
*"<tt>/</tt>" является ''скрытым'' триггером по умолчанию (<tt>SilentChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда не будет показана остальным клиентам<br />
<br />
SourceMod будет исполнять только те команды, которые зарегистрированы с <tt>RegConsoleCmd</tt> или <tt>RegAdminCmd</tt>, и только если эти команды уже не используются Half-life 2 движком или другим игровым модом. Если команда идет с префиксом "sm_", то "sm_" можно исключить, из написания в чате.<br />
<br />
Консольные команды, которые хотят поддерживать использование в качестве триггера чата, не должны использовать нативы вроде <tt>PrintTo*</tt>. Вместо этого, они должны использовать <tt>ReplyToCommand()</tt>, которая будет автоматически печатать ваше сообщение либо в виде сообщения чата либо в виде консоли клиента, в зависимости от источника команды.<br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Commands_(SourceMod_Scripting)&diff=10195Ru:Commands (SourceMod Scripting)2016-08-20T14:40:58Z<p>MAGNAT2645: /* Добавление команд */</p>
<hr />
<div>[[SourceMod]] позволяет создать вам консольные команды, похожие на [[AMX Mod X]]. Есть два главных вида консольных команд:<br />
*'''Серверные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли сервера<br />
**С помощью удаленной консоли (RCON)<br />
**Функция ServerCommand(), либо из SourceMod либо [[Half-Life 2]] движка<br />
*'''Консольные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли клиента<br />
**Любой из методов ввода серверных команд<br />
<br />
Для серверных команд не существует клиентского индекса. Для консольных/клиентских команд, существует клиентский индекс, но он может быть 0 что-бы показать что команда с сервера.<br />
<br />
Обратите внимание, что кнопка-бинд "commands", такие как +attack и +duck, они не консольные команды. Эти команды отдельно передаются, посколько они отдельно привязаны. <br />
<br />
=Серверные команды=<br />
Как отмечалось выше, серверные команды срабатывают через консоль сервера, будь то удалённую, локальную, или через движок Source. Индекс клиента не связан со серверными командами. <br />
<br />
Серверные команды регистрируются через <tt>RegServerCmd()</tt> функцию, расположенную в <tt>console.inc</tt>. При регистрации команды, вы можете записать поверх существующей команды, и таким образом, возвращаемое значение становится важным.<br />
*<b><tt>Plugin_Continue</tt></b> - The original server command will be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Handled</tt></b> - The original server command will not be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Stop</tt></b> - The original server command will not be processed, if there was one. Additionally, no further hooks will be called for this command until it is fired again.<br />
<br />
==Добавление серверных команд==<br />
Допустим, мы хотим добавить тестовую команду, чтобы показать как Half-Life 2 вычисляет аргументы команды. Вот возможная реализация:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
PrintToServer("Строка аргумента: %s", full)<br />
PrintToServer("Количество аргументов: %d", args)<br />
for (int i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Аргумент %d: %s", i, arg)<br />
}<br />
}<br />
</pawn><br />
<br />
==Блокирование серверных команд==<br />
Допустим мы хотим отключить "kickid" команду на сервере. Нет причин делать это, но для примера сойдет:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("kickid", Command_KickId)<br />
}<br />
<br />
public Action Command_Kickid(int args)<br />
{<br />
return Plugin_Handled<br />
}<br />
</pawn><br />
<br />
=Консольные команды=<br />
В отличие от серверных команд, консольные могут быть вызваны, как сервером, так и клиентом, так что callback функция получает клиентский индекс, а также количество аргументов. Если сервер использовал команду, клиентский индекс будет 0. <br />
<br />
When returning the <tt>Action</tt> from the callback, the following effects will happen:<br />
*<tt>Plugin_Continue</tt>: The original functionality of the command (if any) will still be processed. If there was no original functionality, the client will receive "Unknown command" in their console.<br />
*<tt>Plugin_Handled</tt>: The original functionality of the command (if any) will be blocked. If there was no functionality originally, this prevents clients from seeing "Unknown command" in their console.<br />
*<tt>Plugin_Stop</tt>: Same as <tt>Plugin_Handled</tt>, except that this will be the last hook called.<br />
<br />
Обратите внимание, в отличие от AMX Mod X, SourceMod не сможет зарегистрировать командные фильтры. т.е. нет эквивалента этой команды:<br />
<pawn>register_clcmd("say /ff", "Command_SayFF");</pawn><br />
<br />
Это было удаленно, чтобы сделать наш код проще и быстрее. Написание такого же функционала легче и показано ниже.<br />
<br />
==Добавление команд==<br />
Создать клиентские команды очень просто. Давайте переделаем нашу тест команду, чтобы можно было отобразить информацию о клиенте.<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegConsoleCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int client, int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
if (client)<br />
{<br />
char name[32]<br />
GetClientName(client, name, sizeof(name))<br />
PrintToServer("Команда от клиента: %s", name)<br />
} else {<br />
PrintToServer("Команда от сервера.")<br />
}<br />
<br />
PrintToServer("Строка аргументов: %s", full)<br />
PrintToServer("Количество аргументов: %d", args)<br />
for (int i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Аргумент %d: %s", i, arg)<br />
}<br />
}</pawn><br />
<br />
==Захват команд==<br />
Пример: захват типичной команды say. Let's say we want to tell players whether FF is enabled when they say '/ff' in game. <br />
<br />
Before we implement this, a common point of confusion with the 'say' command is that Half-Life 2 (and Half-Life 1), by default, send it with the text in one big quoted string. This means if you say "I like hot dogs," your command will be broken down as such:<br />
*Argument string: "I like hot dogs"<br />
*Argument count: 1<br />
*Argument #1: I like hot dogs<br />
<br />
However, if a player types this in their console: <tt>say I like yams</tt>, it will be broken up as:<br />
*Argument string: I like yams<br />
*Argument count: 3<br />
*Argument #1: I<br />
*Argument #2: like<br />
*Argument #3: yams<br />
<br />
Thus, to take into account both of these situations, we are going to use <tt>GetCmdArgString</tt> and manually parse the input. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegConsoleCmd("say", Command_Say)<br />
}<br />
<br />
public Action Command_Say(int client, int args)<br />
{<br />
char text[192]<br />
GetCmdArgString(text, sizeof(text))<br />
<br />
int startidx = 0<br />
if (text[0] == '"')<br />
{<br />
startidx = 1<br />
/* Лишаем ковычки от окончания, если есть */<br />
int len = strlen(text);<br />
if (text[len-1] == '"')<br />
{<br />
text[len-1] = '\0'<br />
}<br />
}<br />
<br />
if (StrEqual(text[startidx], "/ff"))<br />
{<br />
Handle ff = FindConVar("mp_friendlyfire")<br />
if (GetConVarInt(ff))<br />
{<br />
PrintToConsole(client, "Огонь по товарищам включен.")<br />
} else {<br />
PrintToConsole(client, "Огонь по товарищам выключен.")<br />
}<br />
/* Блокирование сообщения клиента от вещания */<br />
return Plugin_Handled<br />
}<br />
<br />
/* Пусть работает как обычно */<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
==Создание Админской команды==<br />
Давайте создадим простую админскую команду, которая позволяет кикнуть игрока, по его полному имени. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegAdminCmd("admin_kick",<br />
Command_Kick,<br />
ADMFLAG_KICK,<br />
"Кикает игрока по нику")<br />
}<br />
<br />
public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target));<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
==Иммунитет==<br />
В нашем прошлом примере, мы не сделали иммунитет. Иммунитет является гораздно сложной системой в SourceMod, чем это было в AMX Mod X, и не существует просто флага, чтобы обозначить его. Вместо, этого существует две функции:<br />
*<tt>CanAdminTarget</tt>: Проверяет исходные значения AdminId для иммунитета.<br />
*<tt>CanUserTarget</tt>: Проверяет внутриигровых клиентов для иммунитета.<br />
<br />
While immunity is generally tested ''player versus player'', it is possible you might want to check for immunity and not have a targetting client. While there is no convenience function for this yet, a good idea might be to check for either ''default'' or ''global'' immunity on the player's groups (these can be user-defined for non-player targeted scenarios).<br />
<br />
When checking for immunity, the following heuristics are performed in this exact order:<br />
<ol><li>If the targeting AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting fails.</li><br />
<li>If the targetted AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting succeeds.</li><br />
<li>If the targeting admin has <tt>Admin_Root</tt> (<tt>ADMFLAG_ROOT</tt>), targeting succeeds.</li><br />
<li>If the targetted admin has global immunity, targeting fails.</li><br />
<li>If the targetted admin has default immunity, and the targeting admin belongs to no groups, targeting fails.</li><br />
<li>If the targetted admin has specific immunity from the targeting admin via group immunities, targeting fails.</li><br />
<li>If no conclusion is reached via the previous steps, targeting succeeds.</li><br />
</ol><br />
<br />
So, how can we adapt our function about to use immunity?<br />
<br />
<pawn>public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
if (!CanUserTarget(client, target))<br />
{<br />
PrintToConsole(client, "Вы не можете использовать этого клиента как цель.")<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target))<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
=Только клиентские команды=<br />
SourceMod exposes a forward that is called whenever a client executes any command string in their console, called <tt>OnClientCommand</tt>. An example of this looks like:<br />
<br />
<pawn>public Action OnClientCommand(int client, int args)<br />
{<br />
char cmd[16]<br />
GetCmdArg(0, cmd, sizeof(cmd)); /* Получаем название команды */<br />
<br />
if (StrEqual(cmd, "test_command"))<br />
{<br />
/* Получаем клиентскую команду! Блокируем её... */<br />
return Plugin_Handled<br />
}<br />
<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
It is worth noting that not everything a client sends will be available through this command. Command registered via external sources in C++ may not be available, especially if they are created via <tt>CON_COMMAND</tt> in the game mod itself. For example, "say" is usually implemented this way, because it can be used by both clients and the server, and thus it does not channel through this forward.<br />
<br />
<br />
=Чат триггеры=<br />
SourceMod будет автоматически создавать чат триггеры для каждой команды, которую вы сделали (по ревизии 900). Для примера, если вы создали консольную команду "sm_megaslap", администраторы смогут набрать ее и в <tt>say</tt>/<tt>say_team</tt> режимах:<br />
<pre>!sm_megaslap<br />
!megaslap<br />
/sm_megaslap<br />
/megaslap</pre><br />
<br />
SourceMod будет выполнять эту команду и ее аргументы, как если бы она пришла из консоли клиента.<br />
*"<tt>!</tt>" является ''публичным'' триггером по умолчанию (<tt>PublicChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда будет отображена всем клиентам.<br />
*"<tt>/</tt>" является ''скрытым'' триггером по умолчанию (<tt>SilentChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда не будет показана остальным клиентам<br />
<br />
SourceMod будет исполнять только те команды, которые зарегистрированы с <tt>RegConsoleCmd</tt> или <tt>RegAdminCmd</tt>, и только если эти комнды уже не используются Half-life 2 движком или другим игровым модом. Если команда идет с префиксом "sm_" то "sm_" можно исключить, из написания в чате.<br />
<br />
Console commands which wish to support usage as a chat trigger should not use <tt>PrintTo*</tt> natives. Instead, they should use <tt>ReplyToCommand()</tt>, which will automatically print your message either as a chat message or to the client's console, depending on the source of the command.<br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Commands_(SourceMod_Scripting)&diff=10194Ru:Commands (SourceMod Scripting)2016-08-20T14:39:32Z<p>MAGNAT2645: /* Добавление команд */</p>
<hr />
<div>[[SourceMod]] позволяет создать вам консольные команды, похожие на [[AMX Mod X]]. Есть два главных вида консольных команд:<br />
*'''Серверные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли сервера<br />
**С помощью удаленной консоли (RCON)<br />
**Функция ServerCommand(), либо из SourceMod либо [[Half-Life 2]] движка<br />
*'''Консольные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли клиента<br />
**Любой из методов ввода серверных команд<br />
<br />
Для серверных команд не существует клиентского индекса. Для консольных/клиентских команд, существует клиентский индекс, но он может быть 0 что-бы показать что команда с сервера.<br />
<br />
Обратите внимание, что кнопка-бинд "commands", такие как +attack и +duck, они не консольные команды. Эти команды отдельно передаются, посколько они отдельно привязаны. <br />
<br />
=Серверные команды=<br />
Как отмечалось выше, серверные команды срабатывают через консоль сервера, будь то удалённую, локальную, или через движок Source. Индекс клиента не связан со серверными командами. <br />
<br />
Серверные команды регистрируются через <tt>RegServerCmd()</tt> функцию, расположенную в <tt>console.inc</tt>. При регистрации команды, вы можете записать поверх существующей команды, и таким образом, возвращаемое значение становится важным.<br />
*<b><tt>Plugin_Continue</tt></b> - The original server command will be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Handled</tt></b> - The original server command will not be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Stop</tt></b> - The original server command will not be processed, if there was one. Additionally, no further hooks will be called for this command until it is fired again.<br />
<br />
==Добавление серверных команд==<br />
Допустим, мы хотим добавить тестовую команду, чтобы показать как Half-Life 2 вычисляет аргументы команды. Вот возможная реализация:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
PrintToServer("Строка аргумента: %s", full)<br />
PrintToServer("Количество аргументов: %d", args)<br />
for (int i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Аргумент %d: %s", i, arg)<br />
}<br />
}<br />
</pawn><br />
<br />
==Блокирование серверных команд==<br />
Допустим мы хотим отключить "kickid" команду на сервере. Нет причин делать это, но для примера сойдет:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("kickid", Command_KickId)<br />
}<br />
<br />
public Action Command_Kickid(int args)<br />
{<br />
return Plugin_Handled<br />
}<br />
</pawn><br />
<br />
=Консольные команды=<br />
В отличие от серверных команд, консольные могут быть вызваны, как сервером, так и клиентом, так что callback функция получает клиентский индекс, а также количество аргументов. Если сервер использовал команду, клиентский индекс будет 0. <br />
<br />
When returning the <tt>Action</tt> from the callback, the following effects will happen:<br />
*<tt>Plugin_Continue</tt>: The original functionality of the command (if any) will still be processed. If there was no original functionality, the client will receive "Unknown command" in their console.<br />
*<tt>Plugin_Handled</tt>: The original functionality of the command (if any) will be blocked. If there was no functionality originally, this prevents clients from seeing "Unknown command" in their console.<br />
*<tt>Plugin_Stop</tt>: Same as <tt>Plugin_Handled</tt>, except that this will be the last hook called.<br />
<br />
Обратите внимание, в отличие от AMX Mod X, SourceMod не сможет зарегистрировать командные фильтры. т.е. нет эквивалента этой команды:<br />
<pawn>register_clcmd("say /ff", "Command_SayFF");</pawn><br />
<br />
Это было удаленно, чтобы сделать наш код проще и быстрее. Написание такого же функционала легче и показано ниже.<br />
<br />
==Добавление команд==<br />
Создать клиентские команды очень просто. Давайте переделаем нашу тест команду, чтобы можно было отобразить информацию о клиенте.<br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegConsoleCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int client, int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
if (client)<br />
{<br />
char name[32]<br />
GetClientName(client, name, sizeof(name))<br />
PrintToServer("Команда от клиента: %s", name)<br />
} else {<br />
PrintToServer("Команда от сервера.")<br />
}<br />
<br />
PrintToServer("Argument string: %s", full)<br />
PrintToServer("Argument count: %d", args)<br />
for (new i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Argument %d: %s", i, arg)<br />
}<br />
}</pawn><br />
<br />
==Захват команд==<br />
Пример: захват типичной команды say. Let's say we want to tell players whether FF is enabled when they say '/ff' in game. <br />
<br />
Before we implement this, a common point of confusion with the 'say' command is that Half-Life 2 (and Half-Life 1), by default, send it with the text in one big quoted string. This means if you say "I like hot dogs," your command will be broken down as such:<br />
*Argument string: "I like hot dogs"<br />
*Argument count: 1<br />
*Argument #1: I like hot dogs<br />
<br />
However, if a player types this in their console: <tt>say I like yams</tt>, it will be broken up as:<br />
*Argument string: I like yams<br />
*Argument count: 3<br />
*Argument #1: I<br />
*Argument #2: like<br />
*Argument #3: yams<br />
<br />
Thus, to take into account both of these situations, we are going to use <tt>GetCmdArgString</tt> and manually parse the input. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegConsoleCmd("say", Command_Say)<br />
}<br />
<br />
public Action Command_Say(int client, int args)<br />
{<br />
char text[192]<br />
GetCmdArgString(text, sizeof(text))<br />
<br />
int startidx = 0<br />
if (text[0] == '"')<br />
{<br />
startidx = 1<br />
/* Лишаем ковычки от окончания, если есть */<br />
int len = strlen(text);<br />
if (text[len-1] == '"')<br />
{<br />
text[len-1] = '\0'<br />
}<br />
}<br />
<br />
if (StrEqual(text[startidx], "/ff"))<br />
{<br />
Handle ff = FindConVar("mp_friendlyfire")<br />
if (GetConVarInt(ff))<br />
{<br />
PrintToConsole(client, "Огонь по товарищам включен.")<br />
} else {<br />
PrintToConsole(client, "Огонь по товарищам выключен.")<br />
}<br />
/* Блокирование сообщения клиента от вещания */<br />
return Plugin_Handled<br />
}<br />
<br />
/* Пусть работает как обычно */<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
==Создание Админской команды==<br />
Давайте создадим простую админскую команду, которая позволяет кикнуть игрока, по его полному имени. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegAdminCmd("admin_kick",<br />
Command_Kick,<br />
ADMFLAG_KICK,<br />
"Кикает игрока по нику")<br />
}<br />
<br />
public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target));<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
==Иммунитет==<br />
В нашем прошлом примере, мы не сделали иммунитет. Иммунитет является гораздно сложной системой в SourceMod, чем это было в AMX Mod X, и не существует просто флага, чтобы обозначить его. Вместо, этого существует две функции:<br />
*<tt>CanAdminTarget</tt>: Проверяет исходные значения AdminId для иммунитета.<br />
*<tt>CanUserTarget</tt>: Проверяет внутриигровых клиентов для иммунитета.<br />
<br />
While immunity is generally tested ''player versus player'', it is possible you might want to check for immunity and not have a targetting client. While there is no convenience function for this yet, a good idea might be to check for either ''default'' or ''global'' immunity on the player's groups (these can be user-defined for non-player targeted scenarios).<br />
<br />
When checking for immunity, the following heuristics are performed in this exact order:<br />
<ol><li>If the targeting AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting fails.</li><br />
<li>If the targetted AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting succeeds.</li><br />
<li>If the targeting admin has <tt>Admin_Root</tt> (<tt>ADMFLAG_ROOT</tt>), targeting succeeds.</li><br />
<li>If the targetted admin has global immunity, targeting fails.</li><br />
<li>If the targetted admin has default immunity, and the targeting admin belongs to no groups, targeting fails.</li><br />
<li>If the targetted admin has specific immunity from the targeting admin via group immunities, targeting fails.</li><br />
<li>If no conclusion is reached via the previous steps, targeting succeeds.</li><br />
</ol><br />
<br />
So, how can we adapt our function about to use immunity?<br />
<br />
<pawn>public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
if (!CanUserTarget(client, target))<br />
{<br />
PrintToConsole(client, "Вы не можете использовать этого клиента как цель.")<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target))<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
=Только клиентские команды=<br />
SourceMod exposes a forward that is called whenever a client executes any command string in their console, called <tt>OnClientCommand</tt>. An example of this looks like:<br />
<br />
<pawn>public Action OnClientCommand(int client, int args)<br />
{<br />
char cmd[16]<br />
GetCmdArg(0, cmd, sizeof(cmd)); /* Получаем название команды */<br />
<br />
if (StrEqual(cmd, "test_command"))<br />
{<br />
/* Получаем клиентскую команду! Блокируем её... */<br />
return Plugin_Handled<br />
}<br />
<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
It is worth noting that not everything a client sends will be available through this command. Command registered via external sources in C++ may not be available, especially if they are created via <tt>CON_COMMAND</tt> in the game mod itself. For example, "say" is usually implemented this way, because it can be used by both clients and the server, and thus it does not channel through this forward.<br />
<br />
<br />
=Чат триггеры=<br />
SourceMod будет автоматически создавать чат триггеры для каждой команды, которую вы сделали (по ревизии 900). Для примера, если вы создали консольную команду "sm_megaslap", администраторы смогут набрать ее и в <tt>say</tt>/<tt>say_team</tt> режимах:<br />
<pre>!sm_megaslap<br />
!megaslap<br />
/sm_megaslap<br />
/megaslap</pre><br />
<br />
SourceMod будет выполнять эту команду и ее аргументы, как если бы она пришла из консоли клиента.<br />
*"<tt>!</tt>" является ''публичным'' триггером по умолчанию (<tt>PublicChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда будет отображена всем клиентам.<br />
*"<tt>/</tt>" является ''скрытым'' триггером по умолчанию (<tt>SilentChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда не будет показана остальным клиентам<br />
<br />
SourceMod будет исполнять только те команды, которые зарегистрированы с <tt>RegConsoleCmd</tt> или <tt>RegAdminCmd</tt>, и только если эти комнды уже не используются Half-life 2 движком или другим игровым модом. Если команда идет с префиксом "sm_" то "sm_" можно исключить, из написания в чате.<br />
<br />
Console commands which wish to support usage as a chat trigger should not use <tt>PrintTo*</tt> natives. Instead, they should use <tt>ReplyToCommand()</tt>, which will automatically print your message either as a chat message or to the client's console, depending on the source of the command.<br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Commands_(SourceMod_Scripting)&diff=10193Ru:Commands (SourceMod Scripting)2016-08-20T14:38:18Z<p>MAGNAT2645: </p>
<hr />
<div>[[SourceMod]] позволяет создать вам консольные команды, похожие на [[AMX Mod X]]. Есть два главных вида консольных команд:<br />
*'''Серверные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли сервера<br />
**С помощью удаленной консоли (RCON)<br />
**Функция ServerCommand(), либо из SourceMod либо [[Half-Life 2]] движка<br />
*'''Консольные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли клиента<br />
**Любой из методов ввода серверных команд<br />
<br />
Для серверных команд не существует клиентского индекса. Для консольных/клиентских команд, существует клиентский индекс, но он может быть 0 что-бы показать что команда с сервера.<br />
<br />
Обратите внимание, что кнопка-бинд "commands", такие как +attack и +duck, они не консольные команды. Эти команды отдельно передаются, посколько они отдельно привязаны. <br />
<br />
=Серверные команды=<br />
Как отмечалось выше, серверные команды срабатывают через консоль сервера, будь то удалённую, локальную, или через движок Source. Индекс клиента не связан со серверными командами. <br />
<br />
Серверные команды регистрируются через <tt>RegServerCmd()</tt> функцию, расположенную в <tt>console.inc</tt>. При регистрации команды, вы можете записать поверх существующей команды, и таким образом, возвращаемое значение становится важным.<br />
*<b><tt>Plugin_Continue</tt></b> - The original server command will be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Handled</tt></b> - The original server command will not be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Stop</tt></b> - The original server command will not be processed, if there was one. Additionally, no further hooks will be called for this command until it is fired again.<br />
<br />
==Добавление серверных команд==<br />
Допустим, мы хотим добавить тестовую команду, чтобы показать как Half-Life 2 вычисляет аргументы команды. Вот возможная реализация:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
PrintToServer("Строка аргумента: %s", full)<br />
PrintToServer("Количество аргументов: %d", args)<br />
for (int i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Аргумент %d: %s", i, arg)<br />
}<br />
}<br />
</pawn><br />
<br />
==Блокирование серверных команд==<br />
Допустим мы хотим отключить "kickid" команду на сервере. Нет причин делать это, но для примера сойдет:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("kickid", Command_KickId)<br />
}<br />
<br />
public Action Command_Kickid(int args)<br />
{<br />
return Plugin_Handled<br />
}<br />
</pawn><br />
<br />
=Консольные команды=<br />
В отличие от серверных команд, консольные могут быть вызваны, как сервером, так и клиентом, так что callback функция получает клиентский индекс, а также количество аргументов. Если сервер использовал команду, клиентский индекс будет 0. <br />
<br />
When returning the <tt>Action</tt> from the callback, the following effects will happen:<br />
*<tt>Plugin_Continue</tt>: The original functionality of the command (if any) will still be processed. If there was no original functionality, the client will receive "Unknown command" in their console.<br />
*<tt>Plugin_Handled</tt>: The original functionality of the command (if any) will be blocked. If there was no functionality originally, this prevents clients from seeing "Unknown command" in their console.<br />
*<tt>Plugin_Stop</tt>: Same as <tt>Plugin_Handled</tt>, except that this will be the last hook called.<br />
<br />
Обратите внимание, в отличие от AMX Mod X, SourceMod не сможет зарегистрировать командные фильтры. т.е. нет эквивалента этой команды:<br />
<pawn>register_clcmd("say /ff", "Command_SayFF");</pawn><br />
<br />
Это было удаленно, чтобы сделать наш код проще и быстрее. Написание такого же функционала легче и показано ниже.<br />
<br />
==Добавление команд==<br />
Создать клиентские команды очень просто. Давайте переделаем нашу тест команду, чтобы можно было отобразить информацию о клиенте.<br />
<br />
<pawn>public OnPluginStart()<br />
{<br />
RegConsoleCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int client, int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
if (client)<br />
{<br />
char name[32]<br />
GetClientName(client, name, sizeof(name))<br />
PrintToServer("Команда от клиента: %s", name)<br />
} else {<br />
PrintToServer("Команда от сервера.")<br />
}<br />
<br />
PrintToServer("Argument string: %s", full)<br />
PrintToServer("Argument count: %d", args)<br />
for (new i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Argument %d: %s", i, arg)<br />
}<br />
}</pawn><br />
<br />
==Захват команд==<br />
Пример: захват типичной команды say. Let's say we want to tell players whether FF is enabled when they say '/ff' in game. <br />
<br />
Before we implement this, a common point of confusion with the 'say' command is that Half-Life 2 (and Half-Life 1), by default, send it with the text in one big quoted string. This means if you say "I like hot dogs," your command will be broken down as such:<br />
*Argument string: "I like hot dogs"<br />
*Argument count: 1<br />
*Argument #1: I like hot dogs<br />
<br />
However, if a player types this in their console: <tt>say I like yams</tt>, it will be broken up as:<br />
*Argument string: I like yams<br />
*Argument count: 3<br />
*Argument #1: I<br />
*Argument #2: like<br />
*Argument #3: yams<br />
<br />
Thus, to take into account both of these situations, we are going to use <tt>GetCmdArgString</tt> and manually parse the input. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegConsoleCmd("say", Command_Say)<br />
}<br />
<br />
public Action Command_Say(int client, int args)<br />
{<br />
char text[192]<br />
GetCmdArgString(text, sizeof(text))<br />
<br />
int startidx = 0<br />
if (text[0] == '"')<br />
{<br />
startidx = 1<br />
/* Лишаем ковычки от окончания, если есть */<br />
int len = strlen(text);<br />
if (text[len-1] == '"')<br />
{<br />
text[len-1] = '\0'<br />
}<br />
}<br />
<br />
if (StrEqual(text[startidx], "/ff"))<br />
{<br />
Handle ff = FindConVar("mp_friendlyfire")<br />
if (GetConVarInt(ff))<br />
{<br />
PrintToConsole(client, "Огонь по товарищам включен.")<br />
} else {<br />
PrintToConsole(client, "Огонь по товарищам выключен.")<br />
}<br />
/* Блокирование сообщения клиента от вещания */<br />
return Plugin_Handled<br />
}<br />
<br />
/* Пусть работает как обычно */<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
==Создание Админской команды==<br />
Давайте создадим простую админскую команду, которая позволяет кикнуть игрока, по его полному имени. <br />
<br />
<pawn>public void OnPluginStart()<br />
{<br />
RegAdminCmd("admin_kick",<br />
Command_Kick,<br />
ADMFLAG_KICK,<br />
"Кикает игрока по нику")<br />
}<br />
<br />
public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target));<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
==Иммунитет==<br />
В нашем прошлом примере, мы не сделали иммунитет. Иммунитет является гораздно сложной системой в SourceMod, чем это было в AMX Mod X, и не существует просто флага, чтобы обозначить его. Вместо, этого существует две функции:<br />
*<tt>CanAdminTarget</tt>: Проверяет исходные значения AdminId для иммунитета.<br />
*<tt>CanUserTarget</tt>: Проверяет внутриигровых клиентов для иммунитета.<br />
<br />
While immunity is generally tested ''player versus player'', it is possible you might want to check for immunity and not have a targetting client. While there is no convenience function for this yet, a good idea might be to check for either ''default'' or ''global'' immunity on the player's groups (these can be user-defined for non-player targeted scenarios).<br />
<br />
When checking for immunity, the following heuristics are performed in this exact order:<br />
<ol><li>If the targeting AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting fails.</li><br />
<li>If the targetted AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting succeeds.</li><br />
<li>If the targeting admin has <tt>Admin_Root</tt> (<tt>ADMFLAG_ROOT</tt>), targeting succeeds.</li><br />
<li>If the targetted admin has global immunity, targeting fails.</li><br />
<li>If the targetted admin has default immunity, and the targeting admin belongs to no groups, targeting fails.</li><br />
<li>If the targetted admin has specific immunity from the targeting admin via group immunities, targeting fails.</li><br />
<li>If no conclusion is reached via the previous steps, targeting succeeds.</li><br />
</ol><br />
<br />
So, how can we adapt our function about to use immunity?<br />
<br />
<pawn>public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
if (!CanUserTarget(client, target))<br />
{<br />
PrintToConsole(client, "Вы не можете использовать этого клиента как цель.")<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target))<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
=Только клиентские команды=<br />
SourceMod exposes a forward that is called whenever a client executes any command string in their console, called <tt>OnClientCommand</tt>. An example of this looks like:<br />
<br />
<pawn>public Action OnClientCommand(int client, int args)<br />
{<br />
char cmd[16]<br />
GetCmdArg(0, cmd, sizeof(cmd)); /* Получаем название команды */<br />
<br />
if (StrEqual(cmd, "test_command"))<br />
{<br />
/* Получаем клиентскую команду! Блокируем её... */<br />
return Plugin_Handled<br />
}<br />
<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
It is worth noting that not everything a client sends will be available through this command. Command registered via external sources in C++ may not be available, especially if they are created via <tt>CON_COMMAND</tt> in the game mod itself. For example, "say" is usually implemented this way, because it can be used by both clients and the server, and thus it does not channel through this forward.<br />
<br />
<br />
=Чат триггеры=<br />
SourceMod будет автоматически создавать чат триггеры для каждой команды, которую вы сделали (по ревизии 900). Для примера, если вы создали консольную команду "sm_megaslap", администраторы смогут набрать ее и в <tt>say</tt>/<tt>say_team</tt> режимах:<br />
<pre>!sm_megaslap<br />
!megaslap<br />
/sm_megaslap<br />
/megaslap</pre><br />
<br />
SourceMod будет выполнять эту команду и ее аргументы, как если бы она пришла из консоли клиента.<br />
*"<tt>!</tt>" является ''публичным'' триггером по умолчанию (<tt>PublicChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда будет отображена всем клиентам.<br />
*"<tt>/</tt>" является ''скрытым'' триггером по умолчанию (<tt>SilentChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда не будет показана остальным клиентам<br />
<br />
SourceMod будет исполнять только те команды, которые зарегистрированы с <tt>RegConsoleCmd</tt> или <tt>RegAdminCmd</tt>, и только если эти комнды уже не используются Half-life 2 движком или другим игровым модом. Если команда идет с префиксом "sm_" то "sm_" можно исключить, из написания в чате.<br />
<br />
Console commands which wish to support usage as a chat trigger should not use <tt>PrintTo*</tt> natives. Instead, they should use <tt>ReplyToCommand()</tt>, which will automatically print your message either as a chat message or to the client's console, depending on the source of the command.<br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645https://wiki.alliedmods.net/index.php?title=Ru:Commands_(SourceMod_Scripting)&diff=10192Ru:Commands (SourceMod Scripting)2016-08-20T14:25:52Z<p>MAGNAT2645: </p>
<hr />
<div>[[SourceMod]] позволяет создать вам консольные команды, похожие на [[AMX Mod X]]. Есть два главных вида консольных команд:<br />
*'''Серверные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли сервера<br />
**С помощью удаленной консоли (RCON)<br />
**Функция ServerCommand(), либо из SourceMod либо [[Half-Life 2]] движка<br />
*'''Консольные команды''' - Срабатывают с одним из следующих способов ввода:<br />
**С помощью консоли клиента<br />
**Любой из методов ввода серверных команд<br />
<br />
Для серверных команд не существует клиентского индекса. Для консольных/клиентских команд, существует клиентский индекс, но он может быть 0 что-бы показать что команда с сервера.<br />
<br />
Обратите внимание, что кнопка-бинд "commands", такие как +attack и +duck, они не консольные команды. Эти команды отдельно передаются, посколько они отдельно привязаны. <br />
<br />
=Серверные команды=<br />
Как отмечалось выше, серверные команды срабатывают через консоль сервера, будь то удалённую, локальную, или через движок Source. Индекс клиента не связан со серверными командами. <br />
<br />
Серверные команды регистрируются через <tt>RegServerCmd()</tt> функцию, расположенную в <tt>console.inc</tt>. При регистрации команды, вы можете записать поверх существующей команды, и таким образом, возвращаемое значение становится важным.<br />
*<b><tt>Plugin_Continue</tt></b> - The original server command will be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Handled</tt></b> - The original server command will not be processed, if there was one. Если серверная команда создана плагином, здесь не будет эффекта.<br />
*<b><tt>Plugin_Stop</tt></b> - The original server command will not be processed, if there was one. Additionally, no further hooks will be called for this command until it is fired again.<br />
<br />
==Добавление серверных команд==<br />
Допустим, мы хотим добавить тестовую команду, чтобы показать как Half-Life 2 вычисляет аргументы команды. Вот возможная реализация:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int args)<br />
{<br />
char arg[128]<br />
char full[256]<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
PrintToServer("Строка аргумента: %s", full)<br />
PrintToServer("Количество аргументов: %d", args)<br />
for (int i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Аргумент %d: %s", i, arg)<br />
}<br />
}<br />
</pawn><br />
<br />
==Блокирование серверных команд==<br />
Допустим мы хотим отключить "kickid" команду на сервере. Нет причин делать это, но для примера сойдет:<br />
<pawn><br />
public void OnPluginStart()<br />
{<br />
RegServerCmd("kickid", Command_KickId)<br />
}<br />
<br />
public Action Command_Kickid(int args)<br />
{<br />
return Plugin_Handled<br />
}<br />
</pawn><br />
<br />
=Консольные команды=<br />
В отличие от серверных команд, консольные могут быть вызваны, как сервером, так и клиентом, так что callback функция получает клиентский индекс, а также количество аргументов. Если сервер использовал команду, клиентский индекс будет 0. <br />
<br />
When returning the <tt>Action</tt> from the callback, the following effects will happen:<br />
*<tt>Plugin_Continue</tt>: The original functionality of the command (if any) will still be processed. If there was no original functionality, the client will receive "Unknown command" in their console.<br />
*<tt>Plugin_Handled</tt>: The original functionality of the command (if any) will be blocked. If there was no functionality originally, this prevents clients from seeing "Unknown command" in their console.<br />
*<tt>Plugin_Stop</tt>: Same as <tt>Plugin_Handled</tt>, except that this will be the last hook called.<br />
<br />
Обратите внимание, в отличие от AMX Mod X, SourceMod не сможет зарегистрировать командные фильтры. т.е. нет эквивалента этой команды:<br />
<pawn>register_clcmd("say /ff", "Command_SayFF");</pawn><br />
<br />
Это было удаленно, чтобы сделать наш код проще и быстрее. Написание такого же функционала легче и показано ниже.<br />
<br />
==Добавление команд==<br />
Создать клиентские команды очень просто. Давайте переделаем нашу тест команду, чтобы можно было отобразить информацию о клиенте.<br />
<br />
<pawn>public OnPluginStart()<br />
{<br />
RegConsoleCmd("test_command", Command_Test)<br />
}<br />
<br />
public Action Command_Test(int client, int args)<br />
{<br />
char arg[128];<br />
char full[256];<br />
<br />
GetCmdArgString(full, sizeof(full))<br />
<br />
if (client)<br />
{<br />
char name[32]<br />
GetClientName(client, name, sizeof(name))<br />
PrintToServer("Команда от клиента: %s", name);<br />
} else {<br />
PrintToServer("Команда от сервера.");<br />
}<br />
<br />
PrintToServer("Argument string: %s", full)<br />
PrintToServer("Argument count: %d", args)<br />
for (new i = 1; i <= args; i++)<br />
{<br />
GetCmdArg(i, arg, sizeof(arg))<br />
PrintToServer("Argument %d: %s", i, arg)<br />
}<br />
}</pawn><br />
<br />
==Hooking Commands==<br />
A common example is hooking the say command. Let's say we want to tell players whether FF is enabled when they say '/ff' in game. <br />
<br />
Before we implement this, a common point of confusion with the 'say' command is that Half-Life 2 (and Half-Life 1), by default, send it with the text in one big quoted string. This means if you say "I like hot dogs," your command will be broken down as such:<br />
*Argument string: "I like hot dogs"<br />
*Argument count: 1<br />
*Argument #1: I like hot dogs<br />
<br />
However, if a player types this in their console: <tt>say I like yams</tt>, it will be broken up as:<br />
*Argument string: I like yams<br />
*Argument count: 3<br />
*Argument #1: I<br />
*Argument #2: like<br />
*Argument #3: yams<br />
<br />
Thus, to take into account both of these situations, we are going to use <tt>GetCmdArgString</tt> and manually parse the input. <br />
<br />
<pawn>public OnPluginStart()<br />
{<br />
RegConsoleCmd("say", Command_Say)<br />
}<br />
<br />
public Action:Command_Say(client, args)<br />
{<br />
new String:text[192]<br />
GetCmdArgString(text, sizeof(text))<br />
<br />
new startidx = 0<br />
if (text[0] == '"')<br />
{<br />
startidx = 1<br />
/* Strip the ending quote, if there is one */<br />
new len = strlen(text);<br />
if (text[len-1] == '"')<br />
{<br />
text[len-1] = '\0'<br />
}<br />
}<br />
<br />
if (StrEqual(text[startidx], "/ff"))<br />
{<br />
new Handle:ff = FindConVar("mp_friendlyfire")<br />
if (GetConVarInt(ff))<br />
{<br />
PrintToConsole(client, "Friendly fire is enabled.")<br />
} else {<br />
PrintToConsole(client, "Friendly fire is disabled.")<br />
}<br />
/* Block the client's messsage from broadcasting */<br />
return Plugin_Handled<br />
}<br />
<br />
/* Let say continue normally */<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
==Создание Админской команды==<br />
Давай-те создадим простую админскую команду, которая позволяет кикнуть игрока, по его полному имени. <br />
<br />
<pawn>public OnPluginStart()<br />
{<br />
RegAdminCmd("admin_kick",<br />
Command_Kick,<br />
ADMFLAG_KICK,<br />
"Kicks a player by name")<br />
}<br />
<br />
public Action:Command_Kick(client, args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Usage: admin_kick <name>")<br />
return Plugin_Handled<br />
}<br />
<br />
new String:name[32], maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (new i=1; i<=maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
decl String:other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Could not find any player with the name: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target));<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
==Иммунитет==<br />
В нашем прошлом примере, мы не сделали иммунитет. Иммунитет является гораздно сложной системой в SourceMod, чем это было в AMX Mod X, и не существует просто флага, чтобы обозначить его. Вместо, этого существует две функции:<br />
*<tt>CanAdminTarget</tt>: Tests raw AdminId values for immunity.<br />
*<tt>CanUserTarget</tt>: Tests in-game clients for immunity.<br />
<br />
While immunity is generally tested ''player versus player'', it is possible you might want to check for immunity and not have a targetting client. While there is no convenience function for this yet, a good idea might be to check for either ''default'' or ''global'' immunity on the player's groups (these can be user-defined for non-player targeted scenarios).<br />
<br />
When checking for immunity, the following heuristics are performed in this exact order:<br />
<ol><li>If the targeting AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting fails.</li><br />
<li>If the targetted AdminId is <tt>INVALID_ADMIN_ID</tt>, targeting succeeds.</li><br />
<li>If the targeting admin has <tt>Admin_Root</tt> (<tt>ADMFLAG_ROOT</tt>), targeting succeeds.</li><br />
<li>If the targetted admin has global immunity, targeting fails.</li><br />
<li>If the targetted admin has default immunity, and the targeting admin belongs to no groups, targeting fails.</li><br />
<li>If the targetted admin has specific immunity from the targeting admin via group immunities, targeting fails.</li><br />
<li>If no conclusion is reached via the previous steps, targeting succeeds.</li><br />
</ol><br />
<br />
So, how can we adapt our function about to use immunity?<br />
<br />
<pawn>public Action Command_Kick(int client, int args)<br />
{<br />
if (args < 1)<br />
{<br />
PrintToConsole(client, "Использование: admin_kick <ник>")<br />
return Plugin_Handled<br />
}<br />
<br />
char name[32]<br />
int maxplayers, target = -1<br />
GetCmdArg(1, name, sizeof(name))<br />
<br />
maxplayers = GetMaxClients()<br />
for (int i = 1; i <= maxplayers; i++)<br />
{<br />
if (!IsClientConnected(i))<br />
{<br />
continue<br />
}<br />
char other[32]<br />
GetClientName(i, other, sizeof(other))<br />
if (StrEqual(name, other))<br />
{<br />
target = i<br />
}<br />
}<br />
<br />
if (target == -1)<br />
{<br />
PrintToConsole(client, "Не могу найти игрока с ником: \"%s\"", name)<br />
return Plugin_Handled<br />
}<br />
<br />
if (!CanUserTarget(client, target))<br />
{<br />
PrintToConsole(client, "Вы не можете использовать этого клиента как цель.")<br />
return Plugin_Handled<br />
}<br />
<br />
ServerCommand("kickid %d", GetClientUserId(target))<br />
<br />
return Plugin_Handled<br />
}</pawn><br />
<br />
=Только клиентские команды=<br />
SourceMod exposes a forward that is called whenever a client executes any command string in their console, called <tt>OnClientCommand</tt>. An example of this looks like:<br />
<br />
<pawn>public Action OnClientCommand(int client, int args)<br />
{<br />
char cmd[16]<br />
GetCmdArg(0, cmd, sizeof(cmd)); /* Получаем название команды */<br />
<br />
if (StrEqual(cmd, "test_command"))<br />
{<br />
/* Получаем клиентскую команду! Блокируем её... */<br />
return Plugin_Handled<br />
}<br />
<br />
return Plugin_Continue<br />
}</pawn><br />
<br />
It is worth noting that not everything a client sends will be available through this command. Command registered via external sources in C++ may not be available, especially if they are created via <tt>CON_COMMAND</tt> in the game mod itself. For example, "say" is usually implemented this way, because it can be used by both clients and the server, and thus it does not channel through this forward.<br />
<br />
<br />
=Чат триггеры=<br />
SourceMod будет автоматически создавать чат триггеры для каждой команды, которую вы сделали (по ревизии 900). Для примера, если вы создали консольную команду "sm_megaslap", администраторы смогут набрать ее и в <tt>say</tt>/<tt>say_team</tt> режимах:<br />
<pre>!sm_megaslap<br />
!megaslap<br />
/sm_megaslap<br />
/megaslap</pre><br />
<br />
SourceMod будет выполнять эту команду и ее аргументы, как если бы она пришла из консоли клиента.<br />
*"<tt>!</tt>" является ''публичным'' триггером по умолчанию (<tt>PublicChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда будет отображена всем клиентам.<br />
*"<tt>/</tt>" является ''скрытым'' триггером по умолчанию (<tt>SilentChatTrigger</tt> в <tt>configs/core.cfg</tt>) и ваша команда не будет показана остальным клиентам<br />
<br />
SourceMod будет исполнять только те команды, которые зарегистрированы с <tt>RegConsoleCmd</tt> или <tt>RegAdminCmd</tt>, и только если эти комнды уже не используются Half-life 2 движком или другим игровым модом. Если команда идет с префиксом "sm_" то "sm_" можно исключить, из написания в чате.<br />
<br />
Console commands which wish to support usage as a chat trigger should not use <tt>PrintTo*</tt> natives. Instead, they should use <tt>ReplyToCommand()</tt>, which will automatically print your message either as a chat message or to the client's console, depending on the source of the command.<br />
<br />
[[Category:Ru:SourceMod Scripting]]</div>MAGNAT2645