<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.alliedmods.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Psychonic</id>
	<title>AlliedModders Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.alliedmods.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Psychonic"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/Psychonic"/>
	<updated>2026-04-19T12:07:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Releasing_Products&amp;diff=11874</id>
		<title>Releasing Products</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Releasing_Products&amp;diff=11874"/>
		<updated>2026-04-11T20:02:24Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Update for GitHub Actions workflow&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Releasing SourceMod ==&lt;br /&gt;
&lt;br /&gt;
'''''Bold italic''''' values should be replaced as appropriate for the release.&lt;br /&gt;
* General&lt;br /&gt;
** Create a git branch&lt;br /&gt;
** Bump product.version and plugins/include/version.inc numbers for manual builds&lt;br /&gt;
* GitHub Actions CI&lt;br /&gt;
** CI triggers automatically on pushes to &amp;lt;code&amp;gt;master&amp;lt;/code&amp;gt; and branches matching &amp;lt;code&amp;gt;[0-9]+.[0-9]+-dev&amp;lt;/code&amp;gt;. No manual build forcing is needed.&lt;br /&gt;
** On web01, update &amp;lt;code&amp;gt;version_branches&amp;lt;/code&amp;gt; in the webhook app's &amp;lt;code&amp;gt;config.yaml&amp;lt;/code&amp;gt; (add &amp;lt;code&amp;gt;&amp;quot;'''''1.13'''''&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;code&amp;gt;: &amp;quot;'''''1.13-dev'''''&amp;quot;&amp;lt;/code&amp;gt; for the new stable branch; update the &amp;lt;code&amp;gt;master&amp;lt;/code&amp;gt; entry to the new dev version). Then redeploy: &amp;lt;code&amp;gt;systemctl restart sourcemod-github-artifact-webhook&amp;lt;/code&amp;gt;&lt;br /&gt;
* Downloads&lt;br /&gt;
** Run &amp;lt;code&amp;gt;mount -orw /mnt/downloads&amp;lt;/code&amp;gt; on web01&lt;br /&gt;
** Run &amp;lt;code&amp;gt;mkdir /mnt/downloads/smdrop/'''''1.11'''''&amp;lt;/code&amp;gt;, chmod 775 it, fix ownership&lt;br /&gt;
** Run &amp;lt;code&amp;gt;mount -oro /mnt/downloads&amp;lt;/code&amp;gt;&lt;br /&gt;
** Fix sm_commit_log by updating last ~N master builds to be the new stable branch&lt;br /&gt;
** Update &amp;lt;code&amp;gt;~sourcemod/public_html/downloads.php&amp;lt;/code&amp;gt; — add new stable/dev version objects and update the &amp;lt;code&amp;gt;stable&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;dev&amp;lt;/code&amp;gt; aliases in &amp;lt;code&amp;gt;$branchMap&amp;lt;/code&amp;gt;&lt;br /&gt;
** Update &amp;lt;code&amp;gt;~sourcemod/public_html/latest.php&amp;lt;/code&amp;gt; — add new version to &amp;lt;code&amp;gt;$versionMap&amp;lt;/code&amp;gt; and update the &amp;lt;code&amp;gt;stable&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;dev&amp;lt;/code&amp;gt; aliases (must stay in sync with downloads.php)&lt;br /&gt;
* Gamedata updater (run commands from inside &amp;lt;code&amp;gt;~sourcemod/update&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Clone the new branch into &amp;lt;code&amp;gt;'''''1.11-dev'''''&amp;lt;/code&amp;gt;&lt;br /&gt;
** Create a &amp;lt;code&amp;gt;'''''update-1.11.sh'''''&amp;lt;/code&amp;gt; script for the new version&lt;br /&gt;
** Run &amp;lt;code&amp;gt;php add_version.php --version '''''1.11.0''''' --path '''''1.11-dev'''''&amp;lt;/code&amp;gt;&lt;br /&gt;
** Run &amp;lt;code&amp;gt;php update/add_version.php --version '''''1.12.0''''' --path master&amp;lt;/code&amp;gt;&lt;br /&gt;
** Run &amp;lt;code&amp;gt;./'''''update-1.11.sh'''''&amp;lt;/code&amp;gt;&lt;br /&gt;
** Run &amp;lt;code&amp;gt;./update-master.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
* Web compiler and forum&lt;br /&gt;
** Create a &amp;lt;code&amp;gt;~sourcemod/'''''compiler-1.11'''''&amp;lt;/code&amp;gt; directory, drop spcomp + includes there&lt;br /&gt;
** Change the &amp;lt;code&amp;gt;~sourcemod/compiler&amp;lt;/code&amp;gt; symlink to the new version&lt;br /&gt;
** Update hardcoded version in &amp;lt;code&amp;gt;~sourcemod/public_html/compiler.php&amp;lt;/code&amp;gt; and change the &amp;quot;you can use this to compile plugins for SourceMod '''''1.11''''' or higher&amp;quot; text if necessary&lt;br /&gt;
** Update &amp;lt;code&amp;gt;~sourcemod/public_html/vbcompiler.php&amp;lt;/code&amp;gt;&lt;br /&gt;
** Update forum's newthread.php and editpost.php (search for ccversion). Do this on staging, create a production PR in bitbucket, then pull&lt;br /&gt;
* SP docs&lt;br /&gt;
** Pull and rebuild &amp;lt;code&amp;gt;~sourcemod/scripts/sourcepawn/exp/tools/docparse&amp;lt;/code&amp;gt; if needed&lt;br /&gt;
** &amp;lt;code&amp;gt;git checkout&amp;lt;/code&amp;gt; new branch into &amp;lt;code&amp;gt;~sourcemod/scripts/sourcemod&amp;lt;/code&amp;gt;&lt;br /&gt;
** From &amp;lt;code&amp;gt;~sourcemod/scripts/sourcepawn/exp/docgen/generate/&amp;lt;/code&amp;gt;, run &amp;lt;code&amp;gt;python generate.py&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Metamod&amp;diff=11871</id>
		<title>Metamod</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Metamod&amp;diff=11871"/>
		<updated>2026-04-05T00:45:04Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Reverted edits by OilFreak (talk) to last revision by Fidora&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== About Metamod ==&lt;br /&gt;
[[Category:Half-Life_1]]&lt;br /&gt;
Metamod is a plugin/DLL manager that sits between the [[Half-Life_1|Half-Life]] Engine and an HL Game mod, allowing the dynamic loading/unloading of mod-like DLL plugins to add functionality to the HL server or game mod.&lt;br /&gt;
&lt;br /&gt;
[[AMX_Mod_X|AMX Mod X]] is a Metamod plugin.&lt;br /&gt;
&lt;br /&gt;
{{Stub}}&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Required_Versions_(SourceMod)&amp;diff=11827</id>
		<title>Required Versions (SourceMod)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Required_Versions_(SourceMod)&amp;diff=11827"/>
		<updated>2025-04-06T18:07:33Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Update pass&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As Valve updates their games, new fixes get added to Metamod:Source and SourceMod. This page is to document the current ''minimum'' required version for specific games.  If a specific snapshot isn't needed, please put Current Stable or Current Development.&lt;br /&gt;
&lt;br /&gt;
Current Stable MM:S version: '''1.12'''&amp;lt;br&amp;gt;&lt;br /&gt;
Current Stable SM version: '''1.12''' builds&lt;br /&gt;
&lt;br /&gt;
Current Development MM:S versions: '''2.0.0''' git builds&amp;lt;br&amp;gt;&lt;br /&gt;
Current Development SM versions: '''1.13''' builds&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specific Metamod:Source versions and Current Development refer to [http://www.sourcemm.net/snapshots Metamod:Source snapshots].&amp;lt;br /&amp;gt;&lt;br /&gt;
For SourceMod, Current Stable builds refer to [http://www.sourcemod.net/downloads.php?branch=stable Stable builds]. Current Development builds refer to [http://sourcemod.net/downloads.php?branch=master Unstable builds].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Game&lt;br /&gt;
! Metamod:Source Version&lt;br /&gt;
! SourceMod Version&lt;br /&gt;
! Extras&lt;br /&gt;
|-&lt;br /&gt;
| Alien Swarm&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Black Mesa Source&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Blade Symphony&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Bloody Good Time&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Contagion&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Counter-Strike: Source&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Counter-Strike: Global Offensive&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Counter-Strike 2&lt;br /&gt;
| Current Development&lt;br /&gt;
| Unsupported&lt;br /&gt;
|-&lt;br /&gt;
| Dark Messiah of Might &amp;amp;amp; Magic&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Day of Defeat: Source&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Deadlock&lt;br /&gt;
| Current Development&lt;br /&gt;
| Unsupported&lt;br /&gt;
|-&lt;br /&gt;
| Dota 2&lt;br /&gt;
| Current Development&lt;br /&gt;
| Unsupported&lt;br /&gt;
|-&lt;br /&gt;
| EYE: Divine Cybermancy&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Half-Life 2: DeatchMatch&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Insurgency (2014)&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Left 4 Dead&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
| [http://www.sourcemm.net/vdf Manually Generated metamod.vdf] Required&lt;br /&gt;
|-&lt;br /&gt;
| Left 4 Dead 2&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Nuclear Dawn&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Source 2006 Mods&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Mods: Insurgency: Modern Infantry Combat mod version&lt;br /&gt;
|-&lt;br /&gt;
| Source 2007 Mods&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Source 2013 Mods&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Mods: Fistful of Frags, No More Room in Hell&lt;br /&gt;
|-&lt;br /&gt;
| Team Fortress 2&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
| SourceMod was rebuilt for the 2021/09/16 update &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Supported_Games_(Metamod:Source)&amp;diff=11826</id>
		<title>Supported Games (Metamod:Source)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Supported_Games_(Metamod:Source)&amp;diff=11826"/>
		<updated>2025-04-06T18:03:02Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Revert list from supported games for API, to unsupported games. Add ConCommandBase calls&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Metamod:Source]] generally tries to support most Source engine based games and mods. However, some API features may only be supported by some of them. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== '''[[Introduction to SourceMM Coding#User_Message_Enumeration|User Message API Functions]]''' - &amp;lt;tt&amp;gt;GetUserMessageCount()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;FindUserMessage()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;GetUserMessage()&amp;lt;/tt&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
These APIs are not supported on games that use Protobuf-encoded user messages due to changes in how they are registered. Those games include:&lt;br /&gt;
* Blade Symphony&lt;br /&gt;
* Counter-Strike: Global Offensive&lt;br /&gt;
* Counter-Strike 2&lt;br /&gt;
* Deadlock&lt;br /&gt;
* Dota 2&lt;br /&gt;
* Military Conflict: Vietnam&lt;br /&gt;
&lt;br /&gt;
=== ConCommandBase functions - &amp;lt;tt&amp;gt;RegisterConCommandBase()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;UnregisterConCommandBase&amp;lt;/tt&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
These functions are deprecated, as there is no concept of ConCommandBase in Source 2. As such, they don't function at all on the below games. Use the ConVar or ConCommand registration / unregistration functions instead.&lt;br /&gt;
&lt;br /&gt;
* Counter-Strike 2&lt;br /&gt;
* Deadlock&lt;br /&gt;
* Dota 2&lt;br /&gt;
&lt;br /&gt;
[[Category:Metamod:Source Documentation]]&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Releasing_Products&amp;diff=11728</id>
		<title>Releasing Products</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Releasing_Products&amp;diff=11728"/>
		<updated>2024-10-20T16:58:58Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Add product.version to files needing bumpage&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Releasing SourceMod ==&lt;br /&gt;
&lt;br /&gt;
'''''Bold italic''''' values should be replaced as appropriate for the release.&lt;br /&gt;
* General&lt;br /&gt;
** Create a git branch&lt;br /&gt;
** Bump product.version and plugins/include/version.inc numbers for manual builds&lt;br /&gt;
* Buildbot&lt;br /&gt;
** Update master.cfg in buildbot buildmaster. Don't forget to push the change to github&lt;br /&gt;
** Force builds on the new dev and stable branches via pushbuild.txt&lt;br /&gt;
* Downloads&lt;br /&gt;
** Run &amp;lt;code&amp;gt;mount -orw /mnt/downloads&amp;lt;/code&amp;gt; on web01&lt;br /&gt;
** Run &amp;lt;code&amp;gt;mkdir /mnt/downloads/smdrop/'''''1.11'''''&amp;lt;/code&amp;gt;, chmod 775 it, fix ownership&lt;br /&gt;
** Run &amp;lt;code&amp;gt;mount -oro /mnt/downloads&amp;lt;/code&amp;gt;&lt;br /&gt;
** Fix sm_commit_log by updating last ~N master builds to be the new stable branch&lt;br /&gt;
** Update &amp;lt;code&amp;gt;~sourcemod/public_html/downloads.php&amp;lt;/code&amp;gt;&lt;br /&gt;
** Add an entry to &amp;lt;code&amp;gt;~sourcemod/web-commit-updater/updater.php&amp;lt;/code&amp;gt; for the new version&lt;br /&gt;
* Gamedata updater (run commands from inside &amp;lt;code&amp;gt;~sourcemod/update&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Clone the new branch into &amp;lt;code&amp;gt;'''''1.11-dev'''''&amp;lt;/code&amp;gt;&lt;br /&gt;
** Create a &amp;lt;code&amp;gt;'''''update-1.11.sh'''''&amp;lt;/code&amp;gt; script for the new version&lt;br /&gt;
** Run &amp;lt;code&amp;gt;php add_version.php --version '''''1.11.0''''' --path '''''1.11-dev'''''&amp;lt;/code&amp;gt;&lt;br /&gt;
** Run &amp;lt;code&amp;gt;php update/add_version.php --version '''''1.12.0''''' --path master&amp;lt;/code&amp;gt;&lt;br /&gt;
** Run &amp;lt;code&amp;gt;./'''''update-1.11.sh'''''&amp;lt;/code&amp;gt;&lt;br /&gt;
** Run &amp;lt;code&amp;gt;./update-master.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
* Web compiler and forum&lt;br /&gt;
** Create a &amp;lt;code&amp;gt;~sourcemod/'''''compiler-1.11'''''&amp;lt;/code&amp;gt; directory, drop spcomp + includes there&lt;br /&gt;
** Change the &amp;lt;code&amp;gt;~sourcemod/compiler&amp;lt;/code&amp;gt; symlink to the new version&lt;br /&gt;
** Update hardcoded version in &amp;lt;code&amp;gt;~sourcemod/public_html/compiler.php&amp;lt;/code&amp;gt; and change the &amp;quot;you can use this to compile plugins for SourceMod '''''1.11''''' or higher&amp;quot; text if necessary&lt;br /&gt;
** Update &amp;lt;code&amp;gt;~sourcemod/public_html/vbcompiler.php&amp;lt;/code&amp;gt;&lt;br /&gt;
** Update forum's newthread.php and editpost.php (search for ccversion). Do this on staging, create a production PR in bitbucket, then pull&lt;br /&gt;
* SP docs&lt;br /&gt;
** Pull and rebuild &amp;lt;code&amp;gt;~sourcemod/scripts/sourcepawn/exp/tools/docparse&amp;lt;/code&amp;gt; if needed&lt;br /&gt;
** &amp;lt;code&amp;gt;git checkout&amp;lt;/code&amp;gt; new branch into &amp;lt;code&amp;gt;~sourcemod/scripts/sourcemod&amp;lt;/code&amp;gt;&lt;br /&gt;
** From &amp;lt;code&amp;gt;~sourcemod/scripts/sourcepawn/exp/docgen/generate/&amp;lt;/code&amp;gt;, run &amp;lt;code&amp;gt;python generate.py&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Porting_to_x64&amp;diff=11690</id>
		<title>Porting to x64</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Porting_to_x64&amp;diff=11690"/>
		<updated>2024-05-09T02:19:32Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Add Windows x64 gamedata key name and format table&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
Many plugins are already compatible with the x64 architecture, but many that manipulate game memory (such as with hooks or patches) will require extensive revisions to run under the new 64-bit servers.&lt;br /&gt;
Overall, if your plugin:&lt;br /&gt;
* Uses the address natives or the Address type,&lt;br /&gt;
* Uses dhooks&lt;br /&gt;
* Uses sdkcalls or sdktools (''not sdkhooks'')&lt;br /&gt;
&lt;br /&gt;
...you will need to update your plugin for 64 bits.&lt;br /&gt;
&lt;br /&gt;
Extensions may be good to go with just a recompile for 64-bits, but some may need more extensives changes.&lt;br /&gt;
&lt;br /&gt;
== I'm having an issue! ==&lt;br /&gt;
&lt;br /&gt;
In general, '''prototypes need to be exactly correct''' (including class statics like copy/destruct/constructors) as there are now significantly more quirks that will cause ABIs to be laid out differently.&lt;br /&gt;
&lt;br /&gt;
Here are some things to check for that may be tripping you up:&lt;br /&gt;
&lt;br /&gt;
* The type you thought was an ''int'' was actually a ''size_t''!&lt;br /&gt;
* The type you put down as an int or pointer was actually a ''float''!&lt;br /&gt;
* Handling pointers as ''int''s when they should be ''void*'' or ''size_t'' (why would you do this??)&lt;br /&gt;
* '''The calling convention has changed.''' Make sure to account for this in detours and patches. Make sure your prototypes are exactly correct!&lt;br /&gt;
* '''In patches:''' Did you forget the 64-bit opcode prefix when assembling your patch? EAX and RAX are accessed using different opcode prefixes!&lt;br /&gt;
&lt;br /&gt;
=== Linux Calling Convention Quirks ===&lt;br /&gt;
&lt;br /&gt;
Linux uses the System-V x64 ABI. There are many great sources of documentation all over the internet: [https://wiki.osdev.org/System_V_ABI OSDev Wiki] [https://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions Wikipedia]&lt;br /&gt;
* All calling conventions are now an up to 8-register fastcall depending on the types (!!)&lt;br /&gt;
* RCX can be a thisptr, first argument, or stack return pointer depending on the context&lt;br /&gt;
* '''Integer arguments and float arguments are passed in different registers!''' (generic for ints, SIMD registers for floats)&lt;br /&gt;
* Varargs are now more complex to call when floats are included in the vararg&lt;br /&gt;
&lt;br /&gt;
The exact value of return types with C++ shenanigans (destructors, etc) still needs to be figured out by someone. However, in general.&lt;br /&gt;
* The return argument is always passed in RCX, and will bump the thisptr to RDX (todo: confirm this)&lt;br /&gt;
* Some return types that are 128-bits will be returned in both RAX and RDX??&lt;br /&gt;
&lt;br /&gt;
=== MSVC Calling Convention Quirks ===&lt;br /&gt;
Microsoft has some excellent official documentation [https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170 in their MSVC docs].&lt;br /&gt;
&lt;br /&gt;
* All calling conventions are now a four-register fastcall&lt;br /&gt;
* RCX can be a thisptr OR the first arg! It is not always a thisptr now. RCX can also be the return value (see below), bumping the thisptr to RDX.&lt;br /&gt;
* '''Integer arguments and float arguments are passed in different registers!''' (generic for ints, SIMD registers for floats)&lt;br /&gt;
* All objects larger than 8 bytes are now passed exclusively by reference (even on the stack??)&lt;br /&gt;
* Float arguments passed to varargs need to be put in both the generic and SIMD register for the appropiate argument index. Varargs are still fastcalls... somehow...&lt;br /&gt;
* '''setjmp has new behavior''' and destroys objects as if the scope has been exited. (if you ''are'' using setjmp, good luck)&lt;br /&gt;
&lt;br /&gt;
Return types also have their usual obscure shenanigans. More specifically,&lt;br /&gt;
* The return argument is always passed in RCX, and will bump the thisptr to RDX (todo: confirm this)&lt;br /&gt;
* Returns with all types larger than 8 bytes occur on the stack&lt;br /&gt;
* Returns with any type that has a user-defined base classes, virtual methods, constructor, destructor, or copy operation happens on the stack (''regardless of size'')&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Porting Plugins ==&lt;br /&gt;
&lt;br /&gt;
=== Gamedata ===&lt;br /&gt;
&lt;br /&gt;
All signatures will need to be updated, and likely many offsets.&lt;br /&gt;
&lt;br /&gt;
==== Gamedata key names ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| Arch/OS&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| Linux&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| Windows&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| x86&lt;br /&gt;
| linux&lt;br /&gt;
| windows&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| x64&lt;br /&gt;
| linux64&lt;br /&gt;
| windows64&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Address Natives ===&lt;br /&gt;
&lt;br /&gt;
New address natives that support 64-bits are still under development&lt;br /&gt;
&lt;br /&gt;
=== DHooks ===&lt;br /&gt;
&lt;br /&gt;
DHooks does not support 64-bits at all for the time being. It will need heavy revisions to work under the new architecture, starting with better SourceHook support for the 64-bit architecture (see: hookmangen)&lt;br /&gt;
&lt;br /&gt;
=== SDKCalls ===&lt;br /&gt;
&lt;br /&gt;
SDKCalls will need to be updated to learn how to accept a thisptr. However, all non-raw calls (eg, those to entities or gamerules that does not require a thisptr) should be fine as long as none of the arguments are 64-bits (including 64-bit ints!)&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Documentation]]&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Installing_Metamod:Source&amp;diff=11661</id>
		<title>Installing Metamod:Source</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Installing_Metamod:Source&amp;diff=11661"/>
		<updated>2023-09-10T15:43:30Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article will guide you through a [[Metamod:Source]] installation.&lt;br /&gt;
&lt;br /&gt;
=Normal Installation=&lt;br /&gt;
&lt;br /&gt;
''Not applicable for Source 2. See GameInfo section below''&lt;br /&gt;
&lt;br /&gt;
Valve sometimes makes changes in their games that break Metamod:Source between releases.  When this happens, you may need to install a snapshot versions of Metamod:Source.  You can see if this is required on the [[Required Versions (SourceMod)|Required Versions]] page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[http://www.metamodsource.net/ Download] Metamod:Source.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Extract the package to your game folder.  For example, for Counter-Strike:Source, you would have &amp;lt;code&amp;gt;cstrike/addons/metamod&amp;lt;/code&amp;gt; after extracting.  If you are uploading to FTP, extract the files locally before transferring to your server's game folder.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Restart your server.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Type &amp;quot;meta version&amp;quot; in your server console (or RCon).  You should see a line like: &amp;quot;Loaded As: Valve Server Plugin.&amp;quot;  If the command is not recognized, see the sections below.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When using a Linux server, you may see the following messages:&lt;br /&gt;
&lt;br /&gt;
* An error indicating that it could not be loaded due to &amp;quot;wrong ELF class: ELFCLASS64&amp;quot;.  If you are using a 32-bit dedicated server installation, this is normal behavior; as long as &amp;lt;code&amp;gt;meta version&amp;lt;/code&amp;gt; is recognized, Metamod:Source is installed.&lt;br /&gt;
* An error indicating that it could not be loaded because &amp;quot;/path/to/server_install/bin/libgcc_s.so.1: version `GCC_7.0.0` not found (required by /some_system_path_to/libstdc++.so.6&amp;quot;.  This is because Valve ships their own copies of those libraries.  As modern systems will have newer versions, you can safely delete the listed file from the server install.  Do not delete the file in the system path (usually &amp;lt;code&amp;gt;lib&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;lib32&amp;lt;/code&amp;gt;).&lt;br /&gt;
* If you are running a 64-bit operating system yourself, you may need to install the system's 32-bit libraries.&lt;br /&gt;
** On Debian / Ubuntu, you can do this with &amp;lt;code&amp;gt;apt install gcc-multilib&amp;lt;/code&amp;gt;.&lt;br /&gt;
* You may find more information about any load failures under a &amp;lt;code&amp;gt;metamod-fatal.log&amp;lt;/code&amp;gt; in metamod's &amp;lt;code&amp;gt;bin&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
==Custom VDF File==&lt;br /&gt;
'''Note: This is normally not needed - Metamod:Source 1.10.0 and later include a &amp;lt;code&amp;gt;metamod.vdf&amp;lt;/code&amp;gt; file for easier installation on most games.'''&lt;br /&gt;
&lt;br /&gt;
If you have trouble getting it to load, [http://www.metamodsource.net/?go=vdf go here] to generate a VDF file specific to your game. This file should be placed into your server's &amp;lt;code&amp;gt;addons&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
Known setups that require this step:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Left 4 Dead 1&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;3rd party mods using the Source SDK Base.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Listen servers (created with the in-game &amp;quot;Create Server&amp;quot; option) for non-english game clients.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=GameInfo=&lt;br /&gt;
'''Note: On Source 1, this is normally not needed - if you do not understand what this is, do NOT do this unless instructed to. The above instructions are sufficient to install Metamod:Source for 99% of servers. For Source 2, this is, however, the only supported loading method.'''&lt;br /&gt;
&lt;br /&gt;
Metamod:Source 1.4.2 and lower used an older method for loading itself.  The advantage of this method was that Metamod:Source could be loaded before the actual game mod, which gave it a small amount of extra functionality.  This functionality was never used by plugin developers, and Steam updates kept overwriting &amp;lt;code&amp;gt;gameinfo&amp;lt;/code&amp;gt; files, so we switched to a different loading mechanism.&lt;br /&gt;
&lt;br /&gt;
However this loading mechanism may still be desirable if you run into backwards compatibility issues, or you have a plugin which takes advantage of the early-loading mechanism.  If this is your case, here are the &amp;lt;code&amp;gt;gameinfo&amp;lt;/code&amp;gt; directions below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Open the file in the mod folder called &amp;quot;gameinfo.txt&amp;quot; (Source 1) or &amp;quot;gameinfo.gi&amp;quot; (Source 2). You will see a few lines at the bottom like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SearchPaths&lt;br /&gt;
{&lt;br /&gt;
	Game				|gameinfo_path|. &lt;br /&gt;
	Game				cstrike&lt;br /&gt;
	Game				hl2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Add a line after the &amp;quot;{&amp;quot; sign but before all of the &amp;quot;Game&amp;quot; entries that looks like this:&amp;lt;pre&amp;gt;GameBin				|gameinfo_path|addons/metamod/bin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If you're using Windows, you may need to use a backwards slash (\) instead.&lt;br /&gt;
&amp;lt;li&amp;gt;You're done! To test whether it worked, restart your game server and type &amp;quot;meta version&amp;quot; in the server console.  You should see a line that says &amp;quot;Loaded as: GameDLL (gameinfo.txt).&amp;quot;  If it doesn't recognize the command, the installation probably failed.  If the &amp;quot;Loaded as:&amp;quot; line says something else, &amp;lt;code&amp;gt;gameinfo&amp;lt;/code&amp;gt; was probably not modified correctly.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For more information or documentation, see [[:Category:Metamod:Source Documentation]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Metamod:Source Documentation]]&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Template:Alert&amp;diff=10921</id>
		<title>Template:Alert</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Template:Alert&amp;diff=10921"/>
		<updated>2020-03-27T18:52:31Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Undo revision 10918 by Psychonic (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;{{#switch: {{{1}}}&lt;br /&gt;
            | info     = border-color: #bcdff1; color: #31708f; {{#switch:{{{opt}}}|bg = background-color: #d9edf7;|}}&lt;br /&gt;
            | success  = border-color: #d0e9c6; color: #3c763d; {{#switch:{{{opt}}}|bg = background-color: #dff0d8;|}}&lt;br /&gt;
            | warning  = border-color: #faf2cc; color: #8a6d3b; {{#switch:{{{opt}}}|bg = background-color: #fcf8e3;|}}&lt;br /&gt;
            | danger   = border-color: #ebcccc; color: #a94442; {{#switch:{{{opt}}}|bg = background-color: #f2dede;|}}&lt;br /&gt;
            | #default = border-color: #bcdff1; color: #3c763d; {{#switch:{{{opt}}}|bg = background-color: #d9edf7;|}}&lt;br /&gt;
            }}&lt;br /&gt;
&lt;br /&gt;
            {{#switch:{{{opt}}}&lt;br /&gt;
            | full-border = border-width: 1px; border-top-style: solid; border-bottom-style: solid;&lt;br /&gt;
            | #default =&lt;br /&gt;
            }}&lt;br /&gt;
            border-left-width: 3px;&lt;br /&gt;
            border-right-width: 3px;&lt;br /&gt;
            border-left-style: solid;&lt;br /&gt;
            border-right-style: solid;&lt;br /&gt;
            border-radius: 5px;&lt;br /&gt;
            {{ #ifeq: {{{inline|no}}} | yes &lt;br /&gt;
            | display: inline-table; margin-top: 5px; margin-bottom: 5px;&lt;br /&gt;
            | display: table; margin-top: 10px; margin-bottom: 10px;&lt;br /&gt;
            }}&lt;br /&gt;
            border-collapse: separate;&lt;br /&gt;
            border-spacing: 5px;&lt;br /&gt;
&amp;quot;&amp;gt; {{#if: {{{3|}}}&lt;br /&gt;
   | &amp;lt;strong style=&amp;quot;display: table-cell; padding-right: 5px; vertical-align: middle;&amp;quot;&amp;gt;{{{2}}}&amp;lt;/strong&amp;gt;{{{3}}}&lt;br /&gt;
   | &amp;lt;span&amp;gt;{{{2}}}&amp;lt;/span&amp;gt;&lt;br /&gt;
   }}&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Template:Alert&amp;diff=10920</id>
		<title>Template:Alert</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Template:Alert&amp;diff=10920"/>
		<updated>2020-03-27T18:52:11Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Undo revision 10919 by Psychonic (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;{{#switch: {{{1}}}&lt;br /&gt;
            {{!}} info     = border-color: #bcdff1; color: #31708f; {{#switch:{{{opt}}}|bg = background-color: #d9edf7;|}}&lt;br /&gt;
            {{!}} success  = border-color: #d0e9c6; color: #3c763d; {{#switch:{{{opt}}}|bg = background-color: #dff0d8;|}}&lt;br /&gt;
            {{!}} warning  = border-color: #faf2cc; color: #8a6d3b; {{#switch:{{{opt}}}|bg = background-color: #fcf8e3;|}}&lt;br /&gt;
            {{!}} danger   = border-color: #ebcccc; color: #a94442; {{#switch:{{{opt}}}|bg = background-color: #f2dede;|}}&lt;br /&gt;
            {{!}} #default = border-color: #bcdff1; color: #3c763d; {{#switch:{{{opt}}}|bg = background-color: #d9edf7;|}}&lt;br /&gt;
            }}&lt;br /&gt;
&lt;br /&gt;
            {{#switch:{{{opt}}}&lt;br /&gt;
            {{!}} full-border = border-width: 1px; border-top-style: solid; border-bottom-style: solid;&lt;br /&gt;
            {{!}} #default =&lt;br /&gt;
            }}&lt;br /&gt;
            border-left-width: 3px;&lt;br /&gt;
            border-right-width: 3px;&lt;br /&gt;
            border-left-style: solid;&lt;br /&gt;
            border-right-style: solid;&lt;br /&gt;
            border-radius: 5px;&lt;br /&gt;
            {{ #ifeq: {{{inline|no}}} | yes &lt;br /&gt;
            {{!}} display: inline-table; margin-top: 5px; margin-bottom: 5px;&lt;br /&gt;
            {{!}} display: table; margin-top: 10px; margin-bottom: 10px;&lt;br /&gt;
            }}&lt;br /&gt;
            border-collapse: separate;&lt;br /&gt;
            border-spacing: 5px;&lt;br /&gt;
&amp;quot;&amp;gt; {{#if: {{{3|}}}&lt;br /&gt;
   {{!}} &amp;lt;strong style=&amp;quot;display: table-cell; padding-right: 5px; vertical-align: middle;&amp;quot;&amp;gt;{{{2}}}&amp;lt;/strong&amp;gt;{{{3}}}&lt;br /&gt;
   {{!}} &amp;lt;span&amp;gt;{{{2}}}&amp;lt;/span&amp;gt;&lt;br /&gt;
   }}&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Template:Alert&amp;diff=10919</id>
		<title>Template:Alert</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Template:Alert&amp;diff=10919"/>
		<updated>2020-03-27T18:48:47Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;{{#switch: {{{1}}}&lt;br /&gt;
            ! info     = border-color: #bcdff1; color: #31708f; {{#switch:{{{opt}}}|bg = background-color: #d9edf7;|}}&lt;br /&gt;
            ! success  = border-color: #d0e9c6; color: #3c763d; {{#switch:{{{opt}}}|bg = background-color: #dff0d8;|}}&lt;br /&gt;
            ! warning  = border-color: #faf2cc; color: #8a6d3b; {{#switch:{{{opt}}}|bg = background-color: #fcf8e3;|}}&lt;br /&gt;
            ! danger   = border-color: #ebcccc; color: #a94442; {{#switch:{{{opt}}}|bg = background-color: #f2dede;|}}&lt;br /&gt;
            ! #default = border-color: #bcdff1; color: #3c763d; {{#switch:{{{opt}}}|bg = background-color: #d9edf7;|}}&lt;br /&gt;
            }}&lt;br /&gt;
&lt;br /&gt;
            {{#switch:{{{opt}}}&lt;br /&gt;
            ! full-border = border-width: 1px; border-top-style: solid; border-bottom-style: solid;&lt;br /&gt;
            ! #default =&lt;br /&gt;
            }}&lt;br /&gt;
            border-left-width: 3px;&lt;br /&gt;
            border-right-width: 3px;&lt;br /&gt;
            border-left-style: solid;&lt;br /&gt;
            border-right-style: solid;&lt;br /&gt;
            border-radius: 5px;&lt;br /&gt;
            {{ #ifeq: {{{inline|no}}} | yes &lt;br /&gt;
            ! display: inline-table; margin-top: 5px; margin-bottom: 5px;&lt;br /&gt;
            ! display: table; margin-top: 10px; margin-bottom: 10px;&lt;br /&gt;
            }}&lt;br /&gt;
            border-collapse: separate;&lt;br /&gt;
            border-spacing: 5px;&lt;br /&gt;
&amp;quot;&amp;gt; {{#if: {{{3|}}}&lt;br /&gt;
   ! &amp;lt;strong style=&amp;quot;display: table-cell; padding-right: 5px; vertical-align: middle;&amp;quot;&amp;gt;{{{2}}}&amp;lt;/strong&amp;gt;{{{3}}}&lt;br /&gt;
   ! &amp;lt;span&amp;gt;{{{2}}}&amp;lt;/span&amp;gt;&lt;br /&gt;
   }}&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Template:Alert&amp;diff=10918</id>
		<title>Template:Alert</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Template:Alert&amp;diff=10918"/>
		<updated>2020-03-27T18:47:18Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;{{#switch: {{{1}}}&lt;br /&gt;
            {{!}} info     = border-color: #bcdff1; color: #31708f; {{#switch:{{{opt}}}|bg = background-color: #d9edf7;|}}&lt;br /&gt;
            {{!}} success  = border-color: #d0e9c6; color: #3c763d; {{#switch:{{{opt}}}|bg = background-color: #dff0d8;|}}&lt;br /&gt;
            {{!}} warning  = border-color: #faf2cc; color: #8a6d3b; {{#switch:{{{opt}}}|bg = background-color: #fcf8e3;|}}&lt;br /&gt;
            {{!}} danger   = border-color: #ebcccc; color: #a94442; {{#switch:{{{opt}}}|bg = background-color: #f2dede;|}}&lt;br /&gt;
            {{!}} #default = border-color: #bcdff1; color: #3c763d; {{#switch:{{{opt}}}|bg = background-color: #d9edf7;|}}&lt;br /&gt;
            }}&lt;br /&gt;
&lt;br /&gt;
            {{#switch:{{{opt}}}&lt;br /&gt;
            {{!}} full-border = border-width: 1px; border-top-style: solid; border-bottom-style: solid;&lt;br /&gt;
            {{!}} #default =&lt;br /&gt;
            }}&lt;br /&gt;
            border-left-width: 3px;&lt;br /&gt;
            border-right-width: 3px;&lt;br /&gt;
            border-left-style: solid;&lt;br /&gt;
            border-right-style: solid;&lt;br /&gt;
            border-radius: 5px;&lt;br /&gt;
            {{ #ifeq: {{{inline|no}}} | yes &lt;br /&gt;
            {{!}} display: inline-table; margin-top: 5px; margin-bottom: 5px;&lt;br /&gt;
            {{!}} display: table; margin-top: 10px; margin-bottom: 10px;&lt;br /&gt;
            }}&lt;br /&gt;
            border-collapse: separate;&lt;br /&gt;
            border-spacing: 5px;&lt;br /&gt;
&amp;quot;&amp;gt; {{#if: {{{3|}}}&lt;br /&gt;
   {{!}} &amp;lt;strong style=&amp;quot;display: table-cell; padding-right: 5px; vertical-align: middle;&amp;quot;&amp;gt;{{{2}}}&amp;lt;/strong&amp;gt;{{{3}}}&lt;br /&gt;
   {{!}} &amp;lt;span&amp;gt;{{{2}}}&amp;lt;/span&amp;gt;&lt;br /&gt;
   }}&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Optimizing_Plugins_(SourceMod_Scripting)&amp;diff=10917</id>
		<title>Optimizing Plugins (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Optimizing_Plugins_(SourceMod_Scripting)&amp;diff=10917"/>
		<updated>2020-03-26T19:51:58Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: pre -&amp;gt; sourcepawn&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
This guide contains some general suggestions as to how to improve local performance in your code. However, '''take note'''. Do not use this as a guide to prematurely optimizing your program. You should focus on making your scripts easily readable and maintainable. Premature optimization can make your code more complex, introducing bugs that you otherwise wouldn't have had.&lt;br /&gt;
&lt;br /&gt;
If you do notice performance problems on your server, and you think they are introduced by your plugin, there are a few steps you can take. The best way to start is to get a profiler. You can use the [[SourceMod Profiler]] to tell you how much time is being spent in script functions.&lt;br /&gt;
&lt;br /&gt;
However, if you are worried about your code, you can also try to estimate the cost of operations in your program. Anything that happens repeatedly in a small period of time - the contents of a loop, the body of a timer, an &amp;lt;tt&amp;gt;OnGameFrame&amp;lt;/tt&amp;gt; hook - are good targets.&lt;br /&gt;
&lt;br /&gt;
'''DISCLAIMER:''' The units of time in this article are comparative only. We estimate most SourcePawn operations as costing 1-10 cycles, where a cycle is measured in nanoseconds.&lt;br /&gt;
&lt;br /&gt;
=Estimating Cost=&lt;br /&gt;
&lt;br /&gt;
The goal of estimating cost is to figure out two things:&lt;br /&gt;
* How expensive an operation is, run only once.&lt;br /&gt;
* How many times the operation is repeated.&lt;br /&gt;
&lt;br /&gt;
Let's try this with a simple example loop below. Most syntactic language features have a simple cost. Natives can be trickier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;for (new i = 0; i &amp;lt; strlen(string); i++) {&lt;br /&gt;
    if (string[i] == '&amp;quot;')&lt;br /&gt;
        return i;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, let's determine how many times this loop will run. If the length of &amp;lt;tt&amp;gt;string&amp;lt;/tt&amp;gt; is ''n'', then the loop will run ''n'' times. Next, let's see what each iteration of the loop costs:&lt;br /&gt;
* &amp;lt;tt&amp;gt;strlen(string)&amp;lt;/tt&amp;gt;: This has to count all of the characters in |string|. Let's say counting a character costs 1 unit of time. Therefore, |strlen(string)| will cost ''n'' units of time.&lt;br /&gt;
* &amp;lt;tt&amp;gt;if (string[i] == '&amp;quot;')&amp;lt;/tt&amp;gt;: This contains an array load and comparison. Let's say those each cost 1 unit of time, totaling 2.&lt;br /&gt;
* &amp;lt;tt&amp;gt;i++&amp;lt;/tt&amp;gt;: This increments a local variable. Let's say that costs 1 unit of time.&lt;br /&gt;
&lt;br /&gt;
Therefore, every iteration of the loop costs &amp;lt;tt&amp;gt;n + 3&amp;lt;/tt&amp;gt; units of time.&lt;br /&gt;
&lt;br /&gt;
That means this loop may cost up to &amp;lt;tt&amp;gt;(n * (n + 3))&amp;lt;/tt&amp;gt; units of time. Now, if we know that &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; is always small - say, under 100 - that might not be a problem. But what happens if the string has 10,000 characters? Now, the loop will take over 100,000,000 units of time! If a &amp;quot;unit of time&amp;quot; is even as small as a nanosecond, that loop will take a whole tenth of a second, delaying the server by multiple frames!&lt;br /&gt;
&lt;br /&gt;
This example is easy to fix. We can identify that &amp;lt;tt&amp;gt;strlen&amp;lt;/tt&amp;gt; magnifies the cost of the loop, and rewrite it like this:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;new length = strlen(string);&lt;br /&gt;
for (new i = 0; i &amp;lt; length; i++) {&lt;br /&gt;
    if (string[i] == '&amp;quot;')&lt;br /&gt;
        return i;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now the cost of this loop is just: &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; times a very, very small amount of time.&lt;br /&gt;
&lt;br /&gt;
=Decl on Local Arrays=&lt;br /&gt;
&lt;br /&gt;
Here is another example, using OnGameFrame:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public OnGameFrame()&lt;br /&gt;
{&lt;br /&gt;
    new String:buffer[4096];&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you declare an array with &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;, Pawn initializes each slot to 0. Let's say writing to an array slot costs 1 unit of time. Declaring this array therefore costs a fixed 4096 units of time. Is that a problem? Well, the game server ticks at 33 times per second. Therefore this costs about 150,000 units of time per second. If a &amp;quot;unit of time&amp;quot; is a nanosecond, we could estimate this costing around 0.1 milliseconds. That could be a lot depending on what your plugin does. You get about 15ms per frame, of which about half is used by the server. If you use more than this time, you could start delaying frames.&lt;br /&gt;
&lt;br /&gt;
Let's say that you have declared this big array inside a loop, inside OnGameFrame, and you are worried about the cost. The preferred way of solving this is to use &amp;lt;tt&amp;gt;decl&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;, which does not perform any initialization:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public OnGameFrame()&lt;br /&gt;
{&lt;br /&gt;
    decl String:buffer[4096];&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''NOTE: You must be very careful not to read from uninitialized variables. They will contain garbage, and you could crash the server by attempting to print or operate on garbage strings.'''&lt;br /&gt;
&lt;br /&gt;
You should only use &amp;lt;tt&amp;gt;decl&amp;lt;/tt&amp;gt; on performance-critical arrays. It is never needed anywhere else.&lt;br /&gt;
&lt;br /&gt;
=Avoid Large KeyValues=&lt;br /&gt;
KeyValues is an n-ary structure using linked lists.  This type of structure is extremely expensive to allocate and traverse.  While it might be suitable for tiny pieces of information (that is, under 10KB of data or so), its complexity growth is very poor.&lt;br /&gt;
&lt;br /&gt;
If you load KeyValues data, you should make an effort to, at the very least, cache its Handle so you don't need to reparse the file every time.  Caching its contents on a needed basis would be a bonus as well.&lt;br /&gt;
&lt;br /&gt;
If you're trying to use a KeyValues file with thousands of entries and updating/loading it on events such as player connections or disconnections, you will find that the structure will grow to an unmanageably slow size.  If that's the case, you should consider moving to something like SQLite or MySQL.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Creating_Natives_(SourceMod_Scripting)&amp;diff=10916</id>
		<title>Creating Natives (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Creating_Natives_(SourceMod_Scripting)&amp;diff=10916"/>
		<updated>2020-03-26T19:49:07Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: pawn -&amp;gt; sourcepawn tag&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod allows plugins to create their own natives that other plugins can use.  This is very similar to AMX Mod X's {{amxx_func|register_native}} function.  It is a powerful inter-plugin communication resource that can greatly enhance the functionality you provide.&lt;br /&gt;
&lt;br /&gt;
''Prerequisites:'' You should have a good grasp of Pawn or SourcePawn scripting, as well as how [[Tags (Scripting)|Tags]] work.&amp;lt;br&amp;gt;&lt;br /&gt;
''Note:'' Most functions herein can be found in the [[SourceMod SDK]], under &amp;lt;tt&amp;gt;plugins/include/functions.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Before creating natives, you should always document and specify exactly how they will work.  This means writing your &amp;quot;include file&amp;quot; beforehand.  Not only does this guide you in writing your natives, but it has the added benefit of completing a large portion of documentation at the same time.&lt;br /&gt;
&lt;br /&gt;
==Include File==&lt;br /&gt;
For our first example, let's start off with a simple native that adds two numbers, a float and a non-float.  It might look like this:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/** Double-include prevention */&lt;br /&gt;
#if defined _mynatives_included_&lt;br /&gt;
  #endinput&lt;br /&gt;
#endif&lt;br /&gt;
#define _mynatives_included_&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Adds two numbers together.&lt;br /&gt;
 *&lt;br /&gt;
 * @param num1    An integer.&lt;br /&gt;
 * @param num2    A float.&lt;br /&gt;
 * @return        The float value of the integer and float added together.&lt;br /&gt;
 */&lt;br /&gt;
native float My_AddNumbers(int num1, int num2);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The documentation and commenting style above is a SourceMod Development Team convention.  While you are not required to follow it for your own code, it may be a good idea to enhance readability (as readers will expect the style to conform).&lt;br /&gt;
&lt;br /&gt;
==Creating the Native==&lt;br /&gt;
To actually create the native, first let's define the native handler itself.  From &amp;lt;tt&amp;gt;functions.inc&amp;lt;/tt&amp;gt; we can see that this follows the prototype:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;typedef NativeCall = function int (Handle plugin, int numParams);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Thus, we have a function like:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public int Native_My_AddNumbers(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we don't use the same function name as we did in our include file.  This is to prevent a possible ''name clash''.  Otherwise, two different symbols (one a native, another a function) could have the same name, and that's not allowed.  We'll see later how we bind the native to its actual name.&lt;br /&gt;
&lt;br /&gt;
Next, we need to implement our native.  &lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public int Native_My_AddNumbers(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	/* Retrieve the first parameter we receive */&lt;br /&gt;
	int num1 = GetNativeCell(1);&lt;br /&gt;
	/* Retrieve the second parameter we receive */&lt;br /&gt;
	float num2 = view_as&amp;lt;float&amp;gt;(GetNativeCell(2));&lt;br /&gt;
	/* Add them together */&lt;br /&gt;
	float value = num1 + num2;&lt;br /&gt;
	/* Return the value */&lt;br /&gt;
	return value;&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should note four important details.  The first is that we have to manually grab the parameters -- they're not easily sent via arguments.  This is for technical reasons that go beyond the scope of this document.  That means you have to know exactly ''how'' to grab each parameter.  For our example, we know that both parameters are simply cells, and thus we can use &amp;lt;tt&amp;gt;GetNativeCell&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
However, the second detail is that there is no &amp;lt;tt&amp;gt;GetNativeCellFloat&amp;lt;/tt&amp;gt;.  This is because a &amp;lt;tt&amp;gt;Float&amp;lt;/tt&amp;gt; is still a cell; the data is just interpreted differently.  Thus, we ''change'' the tag to &amp;lt;tt&amp;gt;Float&amp;lt;/tt&amp;gt; manual.  '''This is different from calling float(GetNativeCell(2)).'''  In fact, that would not work; the &amp;lt;tt&amp;gt;float()&amp;lt;/tt&amp;gt; call would interpret the cell as an integer, when in fact it's already a float, just with the wrong tag (i.e., no tag at all).&lt;br /&gt;
&lt;br /&gt;
Similarly, the third detail is that we cannot simply put &amp;lt;tt&amp;gt;return value&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;return FloatRound(value)&amp;lt;/tt&amp;gt;.  The reason is that our native is supposed to be returning a float.  If we return &amp;lt;tt&amp;gt;value&amp;lt;/tt&amp;gt;, we'll get a tag mismatch.  If we return &amp;lt;tt&amp;gt;FloatRound(value)&amp;lt;/tt&amp;gt;, we'll be returning an integer when a float is expected.  The solution is to change the tag to the default tag, which will retain the value but remove the tag warning.&lt;br /&gt;
&lt;br /&gt;
Lastly, we did not need to verify &amp;lt;tt&amp;gt;numParams&amp;lt;/tt&amp;gt;.  The compiler will always send the correct amount of parameters - the user can't mess this up in any easy way.  Only if you use variadic arguments, or add parameters and need to support older binaries, do you need to handle &amp;lt;tt&amp;gt;numParams&amp;lt;/tt&amp;gt; variations.&lt;br /&gt;
&lt;br /&gt;
==Registering the Native==&lt;br /&gt;
Natives must be registered in &amp;lt;tt&amp;gt;AskPluginLoad2&amp;lt;/tt&amp;gt;.  Although they can be registered elsewhere, only this function guarantees that all other plugins will see your native.  The definition for this forward is in &amp;lt;tt&amp;gt;sourcemod.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)&lt;br /&gt;
{&lt;br /&gt;
	CreateNative(&amp;quot;My_AddNumbers&amp;quot;, Native_My_AddNumbers);&lt;br /&gt;
	return APLRes_Success;&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, any plugin will be able to use our native as if it were from a Core or a C++ extension.&lt;br /&gt;
&lt;br /&gt;
=Usage=&lt;br /&gt;
==By-Reference==&lt;br /&gt;
Sometimes, it may be desirable to return data through by-reference parameters.  For example, observe the following native prototype:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/**&lt;br /&gt;
 * Closes a Handle, and sets the variable to INVALID_HANDLE by reference.&lt;br /&gt;
 *&lt;br /&gt;
 * @param hndl     Handle to close and clear.&lt;br /&gt;
 * @return         Anything that CloseHandle() returns.&lt;br /&gt;
 */&lt;br /&gt;
native bool AltCloseHandle(Handle &amp;amp;hndl);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An implementation of this would look like:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public int Native_AltCloseHandle(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	Handle hndl = view_as&amp;lt;Handle&amp;gt;(GetNativeCellRef(1));&lt;br /&gt;
	SetNativeCellRef(1, 0);   /* Zero out the variable by reference */&lt;br /&gt;
	return CloseHandle(hndl);&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we have a native that is &amp;quot;safer&amp;quot; than a normal &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt;, as it ensures we don't hold onto invalid Handles.&lt;br /&gt;
&lt;br /&gt;
==Strings==&lt;br /&gt;
Strings can be retrieved and altered via dynamic natives.  Observe the following native prototype:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/**&lt;br /&gt;
 * Converts a string to upper case.&lt;br /&gt;
 *&lt;br /&gt;
 * @param str      String to convert.&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native void StringToUpper(char[] str);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An implementation of this is very easy, because of dynamic arrays:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public int Native_StringToUpper(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	int len;&lt;br /&gt;
	GetNativeStringLength(1, len);&lt;br /&gt;
&lt;br /&gt;
	if (len &amp;lt;= 0)&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	char[] str = new char[len + 1];&lt;br /&gt;
	GetNativeString(1, str, len + 1);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i &amp;lt; len; i++)&lt;br /&gt;
	{&lt;br /&gt;
		/* 5th bit specifies case in ASCII -- &lt;br /&gt;
		 * this is not UTF-8 compatible.&lt;br /&gt;
		 */&lt;br /&gt;
		if ((str[i] &amp;amp; (1 &amp;lt;&amp;lt; 5)) == (1 &amp;lt;&amp;lt; 5))&lt;br /&gt;
		{&lt;br /&gt;
			str[i] &amp;amp;= ~(1 &amp;lt;&amp;lt; 5)&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	SetNativeString(1, str, len+1, false);&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Arrays==&lt;br /&gt;
Working with arrays is very similar to strings.  For example, observe the following native prototype:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/**&lt;br /&gt;
 * Sums an array of numbers and returns the sum.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array     Array of numbers to sum.&lt;br /&gt;
 * @param size      Size of array.&lt;br /&gt;
 * @return          Sum of the array elements.&lt;br /&gt;
 */&lt;br /&gt;
native int SumArray(const int array[], int size);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An implementation of this could look like:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public int Native_SumArray(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	int size = GetNativeCell(2);&lt;br /&gt;
	if (size &amp;lt; 1)&lt;br /&gt;
	{&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	int array[size], total;&lt;br /&gt;
	GetNativeArray(1, array, size);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i &amp;lt; size; i++)&lt;br /&gt;
	{&lt;br /&gt;
		total += array[i];&lt;br /&gt;
	}&lt;br /&gt;
	return total;&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Similarly, there is a &amp;lt;tt&amp;gt;SetNativeArray&amp;lt;/tt&amp;gt;, which is used to alter array contents.&lt;br /&gt;
&lt;br /&gt;
==Variable Arguments==&lt;br /&gt;
Variable arguments are usually used when dealing with [[Format Class Functions (SourceMod Scripting)|format class functions]], however it is also possible to use them for general functionality.  The only trick is that unlike normal parameters, every variable argument parameter is passed by-reference.  This adds no change for arrays and strings, but for floats, handles, numbers, or anything else that fits in a cell, &amp;lt;tt&amp;gt;GetNativeCellRef&amp;lt;/tt&amp;gt; must be used instead.&lt;br /&gt;
&lt;br /&gt;
As an example, let's convert our function from above to use variable arguments:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/**&lt;br /&gt;
 * Sums a list of numbers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param num    First number to use as a base.&lt;br /&gt;
 * @param ...    Any number of additional numbers to add.&lt;br /&gt;
 * @return       Sum of all numbers passed.&lt;br /&gt;
 */&lt;br /&gt;
native int SumParams(int num, ...);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An implementation of this would look like:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public int Native_SumParams(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	int base = GetNativeCell(1);&lt;br /&gt;
	for (int i = 2; i &amp;lt;= numParams; i++)&lt;br /&gt;
	{&lt;br /&gt;
		base += GetNativeCellRef(i);&lt;br /&gt;
	}&lt;br /&gt;
	return base;&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Format Functions==&lt;br /&gt;
It is also possible to create your own [[Format Class Functions (SourceMod Scripting)|format class functions]].  This topic is much more complicated than the previous ones, as the native string formatter allows for many different configurations.  This is mainly for optimization.  Note that a formatting routine deals with two buffers: the input format string, and the output buffer.  &amp;lt;tt&amp;gt;FormatNativeString&amp;lt;/tt&amp;gt;, by default, uses parameter indexes directly so you don't have to copy or locally store any of these buffers.&lt;br /&gt;
&lt;br /&gt;
The most common usage of this is to accept a user-formatted string and to not&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/**&lt;br /&gt;
 * Prints a message with a [DEBUG] prefix to the server.&lt;br /&gt;
 *&lt;br /&gt;
 * @param fmt         Format string.&lt;br /&gt;
 * @param ...         Format arguments.&lt;br /&gt;
 */&lt;br /&gt;
native void DebugPrint(const char[] fmt, any ...);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This could be easily implemented as:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;native int DebugPrint(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	char buffer[1024]; &lt;br /&gt;
	int written;&lt;br /&gt;
&lt;br /&gt;
	FormatNativeString(0, /* Use an output buffer */&lt;br /&gt;
		1, /* Format param */&lt;br /&gt;
		2, /* Format argument #1 */&lt;br /&gt;
		sizeof(buffer), /* Size of output buffer */&lt;br /&gt;
		written, /* Store # of written bytes */&lt;br /&gt;
		buffer /* Use our buffer */&lt;br /&gt;
		);&lt;br /&gt;
&lt;br /&gt;
	PrintToServer(&amp;quot;[DEBUG] %s&amp;quot;, buffer);&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Throwing Errors==&lt;br /&gt;
Often, your native will encounter an unrecoverable error, and you wish to trigger a fatal exception.  This is equivalent to &amp;lt;tt&amp;gt;IPluginContext::ThrowNativeError&amp;lt;/tt&amp;gt;, and will halt the current function execution in the plugin.  The debugger will be invoked and a backtrace will be printed out (if the plugin is in debug mode).  Although the current function is cancelled, the plugin will continue to operate normally afterward.&lt;br /&gt;
&lt;br /&gt;
For example, let's say we have a native that operates on clients.  We want to throw an error if we get a client index that is invalid or disconnected.  We could do this like so:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;public int MyFunction(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	int client = GetNativeCell(1);&lt;br /&gt;
	if (client &amp;lt; 1 || client &amp;gt; MaxClients)&lt;br /&gt;
	{&lt;br /&gt;
		return ThrowNativeError(SP_ERROR_NATIVE, &amp;quot;Invalid client index (%d)&amp;quot;, client);&lt;br /&gt;
	}&lt;br /&gt;
	if (!IsClientConnected(client))&lt;br /&gt;
	{&lt;br /&gt;
		return ThrowNativeError(SP_ERROR_NATIVE, &amp;quot;Client %d is not connected&amp;quot;, client);&lt;br /&gt;
	}&lt;br /&gt;
	/* Code */&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating Natives for Methodmaps==&lt;br /&gt;
Declaring natives for methodmaps is similar to other natives, with a few requirements:&lt;br /&gt;
&lt;br /&gt;
# The &amp;lt;tt&amp;gt;CreateNative&amp;lt;/tt&amp;gt; string argument is in the format &amp;lt;tt&amp;gt;Tag.Function&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# The function is declared as a &amp;quot;member&amp;quot; of the methodmap.&lt;br /&gt;
# The magic &amp;quot;this&amp;quot; parameter is implicitly passed in first.&lt;br /&gt;
&lt;br /&gt;
Here's an example of a shared plugin and its corresponding include file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/* sharedplugin.sp */&lt;br /&gt;
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)&lt;br /&gt;
{&lt;br /&gt;
	CreateNative(&amp;quot;Number.PrintToClient&amp;quot;, Native_PrintNumberToClient);&lt;br /&gt;
	return APLRes_Success;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public int Native_PrintNumberToClient(Handle plugin, int numParams)&lt;br /&gt;
{&lt;br /&gt;
	int number = GetNativeCell(1);&lt;br /&gt;
	int client = GetNativeCell(2);&lt;br /&gt;
&lt;br /&gt;
	PrintToChat(client, &amp;quot;%d&amp;quot;, number);&lt;br /&gt;
	return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* sharedplugin.inc */&lt;br /&gt;
methodmap Number&lt;br /&gt;
{&lt;br /&gt;
	public Number(int number)&lt;br /&gt;
	{&lt;br /&gt;
		return view_as&amp;lt;Number&amp;gt;(number);&lt;br /&gt;
	}&lt;br /&gt;
	public native void PrintToClient(int client);&lt;br /&gt;
}&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Writing_Extensions&amp;diff=10915</id>
		<title>Writing Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Writing_Extensions&amp;diff=10915"/>
		<updated>2020-03-26T19:44:46Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: pawn -&amp;gt; sourcepawn tag&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod's Extension System is a powerful way to greatly enhance the flexibility of your SourceMod plugins.  You can take full advantage of SourceMod's Core, using the interfaces it provides, to create C++ plugins, plugin events, plugin native functions, and shared interfaces.  Extensions can also hook into Metamod:Source.&lt;br /&gt;
&lt;br /&gt;
This article goes into the details of creating a SourceMod Extension.  Knowledge of C++ is required.&lt;br /&gt;
&lt;br /&gt;
=SDK Structure=&lt;br /&gt;
First, download the [[SourceMod SDK]] from the [https://github.com/alliedmodders/sourcemod/releases SourceMod github], and one of the SDKs from the [https://github.com/alliedmodders/hl2sdk hl2sdk github]. The directory structure should contain these folders:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
* hl2sdk-something - One of the HL2 SDKs&lt;br /&gt;
* sourcemod-version - The sourcemod package&lt;br /&gt;
** extensions - Sourcemod Extensions code&lt;br /&gt;
*** curl - Source code to the cURL extension&lt;br /&gt;
*** geoip - Source code to the GeoIP extension&lt;br /&gt;
*** mysql - Source code to the MySQL extension&lt;br /&gt;
** plugins - Source code to all of SourceMod's plugins&lt;br /&gt;
*** include - The include files which document plugin API&lt;br /&gt;
** public - Interface files for SourceMod's Core Interfaces&lt;br /&gt;
*** extensions  - Interfaces that are provided by extensions&lt;br /&gt;
*** '''sample_ext''' - The Sample Extension SDK&lt;br /&gt;
**** extension.cpp - Sample C++ plugin&lt;br /&gt;
**** extension.h - Sample C++ header file&lt;br /&gt;
**** Makefile - Sample C++ plugin compiler&lt;br /&gt;
**** smsdk_config.h - Sample C++ plugin settings&lt;br /&gt;
** sourcepawn - The include/interface files for SourcePawn&lt;br /&gt;
*** compiler - The SourcePawn Compiler&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Starting an Extension=&lt;br /&gt;
For simplicity, this article will assume you are using the SDK base files. Navigate to &amp;lt;code&amp;gt;extensions/public/sample_ext&amp;lt;/code&amp;gt;, and ensure that you can compile your code. If using the command line, &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; should do this, if using Visual Studio, see [[#Setting up Visual Studio|Setting up Visual Studio]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first step of creating your extension is to configure it.  Open the &amp;lt;tt&amp;gt;smsdk_config.h&amp;lt;/tt&amp;gt; file and edit each of the following defines.  Use the information below to guide you.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
*SMEXT_CONF_NAME - The general name for your Extension (should be short).&lt;br /&gt;
*SMEXT_CONF_DESCRIPTION - A short description of what your extension does.&lt;br /&gt;
*SMEXT_CONF_VERSION - A version number string.  By convention, SourceMod uses the four set build number notation, so build 1.2.3.4 means:&lt;br /&gt;
**1 is the &amp;quot;Major&amp;quot; release version.&lt;br /&gt;
**2 is the &amp;quot;Minor&amp;quot; release version.&lt;br /&gt;
**3 is the &amp;quot;Maintenance&amp;quot; or &amp;quot;Revision&amp;quot; version.&lt;br /&gt;
**4 is the &amp;quot;Build,&amp;quot; usually an internal source control number.&lt;br /&gt;
*SMEXT_CONF_AUTHOR - Your name (or whoever/whatever authored the plugin).&lt;br /&gt;
*SMEXT_CONF_URL - The URL/homepage of this extension.&lt;br /&gt;
*SMEXT_CONF_LOGTAG - The logtag your extension will use for SourceMod logging.  By convention, try to keep this under ten characters or so, and to make it all caps.&lt;br /&gt;
*SMEXT_CONF_LICENSE - Right now, the SourceMod Dev Team mandates that 3rd party extensions must be under an Open Source license.  Putting a license abbreviation or very short message here is appropriate.  For more information, see [https://www.sourcemod.net/license.php the SourceMod license].&lt;br /&gt;
*SMEXT_CONF_DATESTRING - You do not need to modify this.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If your plugin requires using SourceHook or Metamod:Source, uncomment this line:&lt;br /&gt;
&amp;lt;code&amp;gt;#define SMEXT_CONF_METAMOD&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, you should change the name of your extension. By convention, your extension's class name should start with a capital letter.&lt;br /&gt;
* First, open &amp;lt;code&amp;gt;extension.h&amp;lt;/code&amp;gt; and change &amp;quot;Sample&amp;quot; in this line:&lt;br /&gt;
&amp;lt;cpp&amp;gt;class Sample : public SDKExtension&amp;lt;/cpp&amp;gt;&lt;br /&gt;
* Next, open &amp;lt;code&amp;gt;extension.cpp&amp;lt;/code&amp;gt; change these two lines:&lt;br /&gt;
&amp;lt;cpp&amp;gt;Sample g_Sample;&lt;br /&gt;
SMEXT_LINK(&amp;amp;g_Sample);&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Visual Studio Users==&lt;br /&gt;
Make sure you change the name of your &amp;lt;tt&amp;gt;.dll&amp;lt;/tt&amp;gt; file.  The naming convention for SourceMod extensions is &amp;lt;tt&amp;gt;name.ext.dll&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; is a short name for your extension.  You are free to change this, but it is highly recommended that you keep the &amp;lt;tt&amp;gt;.ext.dll&amp;lt;/tt&amp;gt; intact.&lt;br /&gt;
&lt;br /&gt;
You can do this by going to &amp;lt;tt&amp;gt;Project&amp;lt;/tt&amp;gt; -&amp;gt; &amp;lt;tt&amp;gt;Properties&amp;lt;/tt&amp;gt; -&amp;gt; &amp;lt;tt&amp;gt;Configuration Properties&amp;lt;/tt&amp;gt; -&amp;gt; &amp;lt;tt&amp;gt;Linker&amp;lt;/tt&amp;gt; -&amp;gt; &amp;lt;tt&amp;gt;General&amp;lt;/tt&amp;gt;.  Set the &amp;lt;tt&amp;gt;Output File&amp;lt;/tt&amp;gt; option appropriately.&lt;br /&gt;
&lt;br /&gt;
==Linux Users==&lt;br /&gt;
Simply edit the &amp;lt;tt&amp;gt;Makefile&amp;lt;/tt&amp;gt; and change the &amp;lt;tt&amp;gt;BINARY&amp;lt;/tt&amp;gt; line near the top.  Make sure you do not add any trailing spaces at the end of the name, or the build won't come out right.&lt;br /&gt;
&lt;br /&gt;
You should now be able to compile a blank extension!&lt;br /&gt;
&lt;br /&gt;
=Creating Native Functions=&lt;br /&gt;
''Main article: [[Natives (SourceMod Development)]]''&lt;br /&gt;
&lt;br /&gt;
Most of the time, an extension exists to add &amp;quot;native functions&amp;quot; to the plugin system.  Native functions are simply the functions that plugins can use in SourceMod.  They are coded in C++ and have a short prototype declaration in an include file.&lt;br /&gt;
&lt;br /&gt;
==Prototyping==&lt;br /&gt;
The first step to creating a native is to &amp;lt;tt&amp;gt;spec it&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;prototype&amp;lt;/tt&amp;gt; it.  This is a simple but often time consuming process, but if you get in the habit of it, your documentation will be much better.  Let's first create a very simply native.  Here is a prototype for it, which we will place in &amp;lt;tt&amp;gt;sample.inc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/**&lt;br /&gt;
 * Returns the square of a number.&lt;br /&gt;
 *&lt;br /&gt;
 * @param num	Number to square.&lt;br /&gt;
 * @return	The square of num.&lt;br /&gt;
 */&lt;br /&gt;
native int SquareNumber(num);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;native&amp;lt;/tt&amp;gt; keyword tells the compiler that this function exists in an outside source.  The comment style is similar to [http://www.stack.nl/~dimitri/doxygen/ doxygen] or [http://java.sun.com/j2se/javadoc/ Javadoc], and is preferred by the SourceMod Development Team.&lt;br /&gt;
&lt;br /&gt;
==Implementing==&lt;br /&gt;
Now that our function is documented, it's time to create it!  Each native function is bound to a C++ function.  The prototype for this function looks like:&lt;br /&gt;
&amp;lt;cpp&amp;gt;cell_t Function(IPluginContext *pContext, const cell_t *params);&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A quick explanation of these types:&lt;br /&gt;
*&amp;lt;tt&amp;gt;cell_t&amp;lt;/tt&amp;gt; - This is a 32bit signed integer, the generic data type for Pawn.&lt;br /&gt;
*&amp;lt;tt&amp;gt;IPluginContext&amp;lt;/tt&amp;gt; - This interface provides Virtual Machine functions for retrieving or modifying memory in the plugin.&lt;br /&gt;
*&amp;lt;tt&amp;gt;params&amp;lt;/tt&amp;gt; - This is the &amp;quot;stack&amp;quot; of parameters that the plugin passed.  It is an array from [0..N] where 0 contains N. This means &amp;lt;tt&amp;gt;params[0]&amp;lt;/tt&amp;gt; contains the number of arguments passed to the native.&lt;br /&gt;
**For example, if one parameter was passed, and the parameter is 25:&lt;br /&gt;
***&amp;lt;tt&amp;gt;params[0]&amp;lt;/tt&amp;gt; == 1&lt;br /&gt;
***&amp;lt;tt&amp;gt;params[1]&amp;lt;/tt&amp;gt; == 25&lt;br /&gt;
**Even though it tells you how many parameters are passed, you do not need to verify this number.  The compiler will always pass the correct number of parameters in.  The only time you need to verify it is for backwards compatibility or variable parameter lists, which will be discussed later.&lt;br /&gt;
&lt;br /&gt;
Now, let's write our native function:&lt;br /&gt;
&amp;lt;cpp&amp;gt;cell_t SquareNumber(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	cell_t number = params[1];&lt;br /&gt;
	return number * number;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Binding==&lt;br /&gt;
Now, the final step is to bind our native.  Natives are bound in ''native lists''.  Each list must be terminated by a &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt; bind.  Example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;const sp_nativeinfo_t MyNatives[] = &lt;br /&gt;
{&lt;br /&gt;
	{&amp;quot;SquareNumber&amp;quot;,	SquareNumber},&lt;br /&gt;
	{NULL,			NULL},&lt;br /&gt;
};&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first column/member is a string containing the name you've assigned to the native.  The second column/member is the C++ function you're binding to.  Here, both contain the same name, but it is certainly possible to bind a function to any valid Pawn function name, and likewise, you can bind one function to more than one name.&lt;br /&gt;
&lt;br /&gt;
Lastly, you must tell Core about your native list.  There are two places that are good to do this.  Whichever you choose, you must uncomment the function in &amp;lt;tt&amp;gt;extension.h&amp;lt;/tt&amp;gt; and implement it in &amp;lt;tt&amp;gt;extension.cpp&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SDK_OnLoad&amp;lt;/tt&amp;gt; - This is called when your extension is first loaded.  If you do not require any outside interfaces, it is safe to add natives here.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SDK_OnAllLoaded&amp;lt;/tt&amp;gt; - This is called when all extensions have been loaded.  This is generally a better place to add natives.&lt;br /&gt;
&lt;br /&gt;
Let's say we choose &amp;lt;tt&amp;gt;SDK_OnAllLoaded&amp;lt;/tt&amp;gt;, we'd then have code like this:&lt;br /&gt;
&amp;lt;cpp&amp;gt;void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	sharesys-&amp;gt;AddNatives(myself, MyNatives);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
''Note: &amp;lt;tt&amp;gt;myself&amp;lt;/tt&amp;gt; is a global variable declared in the SDK.  It is a pointer that identifies your extension.''&lt;br /&gt;
&lt;br /&gt;
For more information on writing natives, see [[Natives (SourceMod Development)]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Creating Events/Forwards=&lt;br /&gt;
Events are an integral part to SourceMod.  An Event is formally called a ''Forward''.  Forwards are functions inside a plugin which are not called by the plugin itself, but are triggered from an external source.  For example, &amp;lt;tt&amp;gt;OnClientConnect&amp;lt;/tt&amp;gt; is a forward which is triggered when a player connects to a server.&lt;br /&gt;
&lt;br /&gt;
There are two major types of forwards:&lt;br /&gt;
*'''Managed''': This forward is global and has a name.  To use this forward, the function must be declared as &amp;lt;tt&amp;gt;public&amp;lt;/tt&amp;gt; inside the user's script.  Any plugin having this public function will receive the event.&lt;br /&gt;
*'''Unmanaged''': This forward is private in nature.  For example, the &amp;lt;tt&amp;gt;HookUserMessage&amp;lt;/tt&amp;gt; native lets users specify a function to be called when a specific user message is sent.  This is done with an unmanaged forward, and adding functions to this forward is not automatic.  In general, function calls for unmanaged forwards are not public, although they can be.&lt;br /&gt;
&lt;br /&gt;
''Note: To enable the Forward interface, you must uncomment the definition &amp;lt;tt&amp;gt;SMEXT_ENABLE_FORWARDSYS&amp;lt;/tt&amp;gt; in smsdk_config.h.''&lt;br /&gt;
==Managed Forwards==&lt;br /&gt;
Let's say we want to create a forward that will be called when a player uses say chat.  For simplicity, let's assume you already have a function that tells you when a player says say chat.  We will just be creating the forward for it.&lt;br /&gt;
&lt;br /&gt;
As we did before, first let's prototype our global forward.  In our include file, we add this:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/**&lt;br /&gt;
 * @brief Called whenever a client says something in chat.&lt;br /&gt;
 *&lt;br /&gt;
 * @param client	Index of the client.&lt;br /&gt;
 * @param text		String containing the say text.&lt;br /&gt;
 * @return 		Plugin_Handled to block text from printing, Plugin_Continue otherwise.&lt;br /&gt;
 */&lt;br /&gt;
forward Action OnPlayerSayChat(int client, const char[] text);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;forward&amp;lt;/tt&amp;gt; keyword tells the compiler that any function having this name must be declared exactly the same.  In a plugin, this would&lt;br /&gt;
&lt;br /&gt;
The next step is to declare your forward somewhere at the top of your &amp;lt;tt&amp;gt;extension.cpp&amp;lt;/tt&amp;gt; file.  This will look like:&lt;br /&gt;
&amp;lt;cpp&amp;gt;IForward *g_pSayChat = NULL&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, re-using our code from above, let's create this forward in &amp;lt;tt&amp;gt;SDK_OnAllLoaded&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;cpp&amp;gt;void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	sharesys-&amp;gt;AddNatives(myself, MyNatives);&lt;br /&gt;
	g_pSayChat = forwards-&amp;gt;CreateForward(&amp;quot;OnPlayerSayChat&amp;quot;, ET_Event, 2, NULL, Param_Cell, Param_String);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanation of parameters:&lt;br /&gt;
*&amp;lt;tt&amp;gt;&amp;quot;OnPlayerSayChat&amp;quot;&amp;lt;/tt&amp;gt; - The name of our forward.&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Event&amp;lt;/tt&amp;gt; - Since forwards can execute multiple functions in multiple scripts, this is one of the ways of specifying what to do with the return value of each function.  &amp;lt;tt&amp;gt;ET_Event&amp;lt;/tt&amp;gt; means &amp;quot;return the highest value, do not allow stops.&amp;quot;  A stop refers to &amp;lt;tt&amp;gt;Pl_Stop&amp;lt;/tt&amp;gt;, which lets a plugin block the rest of the event chain.&lt;br /&gt;
*&amp;lt;tt&amp;gt;2&amp;lt;/tt&amp;gt; - This is the number of parameters our forward will have.&lt;br /&gt;
*&amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt; - Not used in our example.  This lets you pass parameters by array rather than variable arguments.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Cell&amp;lt;/tt&amp;gt; - The first parameter is a cell (integer).&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_String&amp;lt;/tt&amp;gt; - The second parameter is a string.&lt;br /&gt;
&lt;br /&gt;
Now, we write a quick function in our module to call this forward:&lt;br /&gt;
&amp;lt;cpp&amp;gt;/** Fires the say chat event in plugins.  Returns true to allow the text, false to block. */&lt;br /&gt;
bool FireChatEvent(int client, const char *text)&lt;br /&gt;
{&lt;br /&gt;
	if (!g_pSayChat)&lt;br /&gt;
	{&lt;br /&gt;
		return true;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	cell_t result = 0;&lt;br /&gt;
	g_pSayChat-&amp;gt;PushCell(client);&lt;br /&gt;
	g_pSayChat-&amp;gt;PushString(text);&lt;br /&gt;
	g_pSayChat-&amp;gt;Execute(&amp;amp;result);&lt;br /&gt;
	&lt;br /&gt;
	if (result == Pl_Handled)&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, this was pretty simple.  Each parameter is &amp;quot;pushed&amp;quot; one at a time, in ascending order.  First we push the client index as a cell, then the text as a string.  Once done, we execute, and the value will be returned by reference.&lt;br /&gt;
&lt;br /&gt;
Lastly, there is a caveat.  Unlike natives, SourceMod does not automatically clean up forwards for us when are done.  We have to make sure we destroy them.  Uncomment &amp;lt;tt&amp;gt;SDK_OnUnload&amp;lt;/tt&amp;gt; from &amp;lt;tt&amp;gt;extension.h&amp;lt;/tt&amp;gt; and implement it like so:&lt;br /&gt;
&amp;lt;cpp&amp;gt;void Sample::SDK_OnUnload()&lt;br /&gt;
{&lt;br /&gt;
	forwards-&amp;gt;ReleaseForward(g_pSayChat);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unmanaged Forwards==&lt;br /&gt;
Now things get a bit more complicated.  However, unmanaged forwards are essentially the same -- they just give you more flexibility.  Let's consider the managed example with a new twist.  We want to let users add and remove hooks from their plugins, rather than having one global forward.  The standard way to do this is with ''function IDs''.  &lt;br /&gt;
&lt;br /&gt;
Example prototype:&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;typedef SayChatHook = function Action (int client, const char[] text);&lt;br /&gt;
&lt;br /&gt;
native void AddSayChatHook(SayChatHook hook);&lt;br /&gt;
native void RemoveSayChatHook(SayChatHook hook);&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;funcenum&amp;lt;/tt&amp;gt; syntax lets you define all the valid prototypes for your hook.  In this example, the only valid method is a function declared like this (only MyHook can be changed):&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;Action MyHook(int client, const char[] text)&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
How do we make such a beast?  The first step is setting up our forward.&lt;br /&gt;
&amp;lt;cpp&amp;gt;IChangeableForward *g_pSayChat = NULL;&lt;br /&gt;
/* ... */&lt;br /&gt;
void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	g_pSayChat = forwards-&amp;gt;CreateForwardEx(NULL, ET_Hook, 2, NULL, Param_Cell, Param_String); &lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice two big differences.  We now use &amp;lt;tt&amp;gt;IChangeableForward&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;IForward&amp;lt;/tt&amp;gt;, and we use &amp;lt;tt&amp;gt;CreateForwardEx&amp;lt;/tt&amp;gt; instead.  The initial first parameter specifies a name for our forward - we're going to ignore this.&lt;br /&gt;
&lt;br /&gt;
Now, we need to create our natives.  These will be fairly simple:&lt;br /&gt;
&amp;lt;cpp&amp;gt;cell_t AddSayChatHook(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	g_pSayChat-&amp;gt;AddFunction(pContext, static_cast&amp;lt;funcid_t&amp;gt;(params[1]));&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
cell_t RemoveSayChatHook(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	IPluginFunction *pFunction = pContext-&amp;gt;GetFunctionById(static_cast&amp;lt;funcid_t&amp;gt;(params[1]));&lt;br /&gt;
	g_pSayChat-&amp;gt;RemoveFunction(pFunction);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
''Note: These natives must be added -- that step is removed here and explained earlier.''&lt;br /&gt;
&lt;br /&gt;
You do not need to worry about a plugin unloading - Core will automatically remove the functions for you.  Since an &amp;lt;tt&amp;gt;IChangeableForward&amp;lt;/tt&amp;gt; is also an &amp;lt;tt&amp;gt;IForward&amp;lt;/tt&amp;gt;, the &amp;lt;tt&amp;gt;FireChatEvent&amp;lt;/tt&amp;gt; function from earlier does not need to change.  We're done!&lt;br /&gt;
&lt;br /&gt;
==Creating Interfaces==&lt;br /&gt;
Do you want your extension to share an interface?  If so, first you should create an ''interface file''.  This file should contain everything your interface needs - this way other authors can easily reference it.  Your interface must inherit the &amp;lt;tt&amp;gt;SMInterface&amp;lt;/tt&amp;gt; class.  It must also declare two global macros that uniquely identify your interface.  It must also implement two functions: &amp;lt;tt&amp;gt;GetInterfaceName&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;GetInterfaceVersion&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The two defines must start with &amp;lt;tt&amp;gt;SMINTERFACE_&amp;lt;/tt&amp;gt; and end with &amp;lt;tt&amp;gt;_NAME&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;_VERSION&amp;lt;/tt&amp;gt; respectively.  The first must be a string and the second must be an unsigned integer.  This integer represents your interface's version number.  While you are free to use it however you please, by default it should be linearly increased.  If you make breaking changes or change the versioning scheme, you must overload the &amp;lt;tt&amp;gt;IsVersionCompat&amp;lt;/tt&amp;gt; function in &amp;lt;tt&amp;gt;SMInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;#ifndef _INCLUDE_MYINTERFACE_FILE_H_&lt;br /&gt;
#define _INCLUDE_MYINTERFACE_FILE_H_&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;IShareSys.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define SMINTERFACE_MYINTERFACE_NAME	&amp;quot;IMyInterface&amp;quot;&lt;br /&gt;
#define SMINTERFACE_MYINTERFACE_VERSION	1&lt;br /&gt;
&lt;br /&gt;
class IMyInterface : public SourceMod::SMInterface&lt;br /&gt;
{&lt;br /&gt;
public:&lt;br /&gt;
	virtual const char *GetInterfaceName()&lt;br /&gt;
	{&lt;br /&gt;
		return SMINTERFACE_MYINTERFACE_NAME;&lt;br /&gt;
	}&lt;br /&gt;
	virtual unsigned int GetInterfaceVersion()&lt;br /&gt;
	{&lt;br /&gt;
		return SMINTERFACE_MYINTERFACE_VERSION;&lt;br /&gt;
	}&lt;br /&gt;
public:&lt;br /&gt;
	/**&lt;br /&gt;
	 * @brief This function does nothing.&lt;br /&gt;
	 */&lt;br /&gt;
	virtual void DoNothingAtAll() =0;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
#endif //_INCLUDE_MYINTERFACE_FILE_H_&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice, of course, that our interface is ''pure virtual''.  This means it must be implemented in the extension.  Assuming you know C++, this should be fairly straight forward, so let's skip right to how to add this interface to the SourceMod shared system:&lt;br /&gt;
&amp;lt;cpp&amp;gt;bool Sample::SDK_OnLoad(char *error, size_t err_max, bool late)&lt;br /&gt;
{&lt;br /&gt;
	sharesys-&amp;gt;AddInterface(myself, &amp;amp;g_MyInterface);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
''Note: We do this in &amp;lt;tt&amp;gt;SDK_OnLoad()&amp;lt;/tT&amp;gt; instead of &amp;lt;tt&amp;gt;SDK_OnAllLoaded()&amp;lt;/tt&amp;gt;.  Otherwise, an extension might try to search for your interface during &amp;lt;tt&amp;gt;SDK_OnAllLoaded()&amp;lt;/tt&amp;gt;, and it might fail depending on the load order.''&lt;br /&gt;
&lt;br /&gt;
That simple?  Yup!  Now other extensions can use your interface.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Using Interfaces/Other Extensions=&lt;br /&gt;
There are a variety of interfaces that are available, but not loaded by default in the Extension SDK.  These interfaces can be retrieved and used in your extension.&lt;br /&gt;
&lt;br /&gt;
==Core Interfaces==&lt;br /&gt;
If they are provided by Core, getting them is very simple.  Many interfaces can simply be uncommented in &amp;lt;tt&amp;gt;smsdk_config.h&amp;lt;/tt&amp;gt; and they will become usable.  See the &amp;quot;Available Interfaces&amp;quot; list below for the exposure list.&lt;br /&gt;
&lt;br /&gt;
Otherwise, most of the &amp;lt;tt&amp;gt;.h&amp;lt;/tt&amp;gt; interface files in the root of the &amp;lt;tt&amp;gt;public&amp;lt;/tt&amp;gt; folder in the SDK are Core interfaces.  For example, code to use the IPluginManager interface might look like this:&lt;br /&gt;
&amp;lt;cpp&amp;gt;#include &amp;lt;IPluginSys.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
IPluginManager *g_pPlugins = NULL;&lt;br /&gt;
&lt;br /&gt;
bool Sample::SDK_OnLoad(char *error, size_t err_max, bool late)&lt;br /&gt;
{&lt;br /&gt;
	SM_GET_IFACE(PLUGINSYSTEM, g_pPlugins);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where did we get &amp;lt;tt&amp;gt;PLUGINSYSTEM&amp;lt;/tt&amp;gt; from?  Observe the two lines in &amp;lt;tt&amp;gt;IPluginSys.h&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;cpp&amp;gt;#define SMINTERFACE_PLUGINSYSTEM_NAME		&amp;quot;IPluginManager&amp;quot;&lt;br /&gt;
#define SMINTERFACE_PLUGINSYSTEM_VERSION	1&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;SM_GET_IFACE&amp;lt;/tt&amp;gt; macro uses the text in between the &amp;lt;tt&amp;gt;SMINTERFACE_&amp;lt;/tt&amp;gt; and the &amp;lt;tt&amp;gt;_NAME&amp;lt;/tt&amp;gt; characters.  It also uses the version for compatibility checking.  If it can't find the interface, it automatically prints to the error buffer and returns false.&lt;br /&gt;
&lt;br /&gt;
===Default Interfaces===&lt;br /&gt;
There are interfaces which are grabbed by the Extension SDK by default.  You do not need to query for them on load, or even check if they are valid or not.  They are:&lt;br /&gt;
*&amp;lt;tt&amp;gt;IShareSys&amp;lt;/tt&amp;gt; - Exposed as &amp;lt;tt&amp;gt;sharesys&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;IShareSys.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;HANDLESYSTEM&amp;lt;/tt&amp;gt; - Exposed as &amp;lt;tt&amp;gt;handlesys&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;IHandleSys.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SOURCEMOD&amp;lt;/tt&amp;gt; - Exposed as &amp;lt;tt&amp;gt;g_pSM&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;ISourceMod.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;FORWARDMANAGER&amp;lt;/tt&amp;gt; - Exposed as &amp;lt;tt&amp;gt;forwards&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;IForwardSys.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Available Interfaces===&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_ENABLE_FORWARDSYS&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;forwards&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_ENABLE_HANDLESYS&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;handlesys&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_ENABLE_PLAYERHELPERS&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;playerhelpers&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_ENABLE_DBMANAGER&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;dbi&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_ENABLE_GAMECONF&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;gameconfs&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_ENABLE_MEMUTILS&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;memutils&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_ENABLE_GAMEHELPERS&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;gamehelpers&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_ENABLE_TIMERSYS&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;timersys&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_ENABLE_THREADER&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;threader&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==External Interfaces==&lt;br /&gt;
The situation changes if your extension requires ''another extension'', since extensions may load in a completely random order.  The first step is to mark the other extension as a dependency.  Let's say you want to use the &amp;lt;tt&amp;gt;IThreader.h&amp;lt;/tt&amp;gt; interfaces from &amp;lt;tt&amp;gt;threader.ext.dll&amp;lt;/tt&amp;gt;.  First, we declare it as such:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;bool Sample::SDK_OnLoad(char *error, size_t err_max, bool late)&lt;br /&gt;
{&lt;br /&gt;
	sharesys-&amp;gt;AddDependency(myself, &amp;quot;thread.ext&amp;quot;, true, true);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two boolean parameters to &amp;lt;tt&amp;gt;AddDependency&amp;lt;/tt&amp;gt; mean, respectively: &amp;quot;try to automatically load this extension&amp;quot; and &amp;quot;this extension cannot work without the dependency.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Second, we query for the interface in &amp;lt;tt&amp;gt;SDK_OnAllLoaded&amp;lt;/tt&amp;gt;.  Since we don't know when &amp;lt;tt&amp;gt;thread.ext&amp;lt;/tt&amp;gt; will actually be loaded, we have to wait until everything is definitely loaded.&lt;br /&gt;
&amp;lt;cpp&amp;gt;IThreader *g_pThreader = NULL;&lt;br /&gt;
/* ... */&lt;br /&gt;
void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	SM_GET_LATE_IFACE(THREADER, g_pThreader);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Third, we need to find a way to fail if this interface was never found.  The way to do this is by uncommenting &amp;lt;tt&amp;gt;QueryRunning&amp;lt;/tt&amp;gt; from &amp;lt;tt&amp;gt;extension.h&amp;lt;/tt&amp;gt; and implementing it:&lt;br /&gt;
&amp;lt;cpp&amp;gt;bool Sample::QueryRunning(char *error, size_t err_max)&lt;br /&gt;
{&lt;br /&gt;
	SM_CHECK_IFACE(THREADER, g_pThreader);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When SourceMod queries your extension, the macro above will either validate the pointer or return false.  If it returns false, SourceMod marks your extension as failed.&lt;br /&gt;
&lt;br /&gt;
==Caveats==&lt;br /&gt;
===NULL Interfaces===&lt;br /&gt;
There are a few ways that external interfaces can make your code complicated.  The first is simple but a common oversight.  Don't assume interfaces will be okay.  For example, say we want to create a thread once we get the &amp;lt;tt&amp;gt;IThreader&amp;lt;/tt&amp;gt; interface.  Our code should something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	SM_GET_IFACE(THREADER, g_pThreader);&lt;br /&gt;
	&lt;br /&gt;
	if (QueryRunning(NULL, 0))&lt;br /&gt;
	{&lt;br /&gt;
		g_pThreader-&amp;gt;MakeThread(/* stuff */);&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we ''query ourself'' in order to find if it's safe to continue executing code.  We could also have simply checked if &amp;lt;tt&amp;gt;g_pThreader&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt;, but self-querying has a bonus: if your extension continues to do things like hook events or add listeners, you will be preventing your extension from entirely initializing itself while one interface is bad.  Always make sure you have sanity checks like this where needed.&lt;br /&gt;
&lt;br /&gt;
===Dynamic Unloading===&lt;br /&gt;
The second major caveat is that extensions can be dynamically unloaded.  If you specified yourself as having a dependency and that each dependency is required, you will have no problem.  Your extension will be unloaded before the interface is removed, and you can clean up memory/hooks in your &amp;lt;tt&amp;gt;SDK_OnUnload()&amp;lt;/tt&amp;gt; code.  There are two situations where this is a different story.&lt;br /&gt;
&lt;br /&gt;
====Optional Interfaces====&lt;br /&gt;
The first situation is if you are not requiring an extension that contains an interface.  Now, when the extension unloads, your extension will not be unloaded first.  This creates a small problem, as you must clean up without being unloaded.  There are two functions you can implement in your extension class to resolve this, both documented in &amp;lt;tt&amp;gt;IExtensionSys.h&amp;lt;/tt&amp;gt;:&lt;br /&gt;
*&amp;lt;tt&amp;gt;QueryInterfaceDrop&amp;lt;/tt&amp;gt; - Allows you to request unloading when a specific interface is unloaded.  This is the default behavior for all interfaces.  If you want to block this functionality, continue reading.&lt;br /&gt;
*&amp;lt;tt&amp;gt;NotifyInterfaceDrop&amp;lt;/tt&amp;gt; - This is called when an interface is dropped.  If your plugin will not be unloaded, you can use this to clean up any resources on a specific interface being removed.&lt;br /&gt;
&lt;br /&gt;
====Circular Dependencies====&lt;br /&gt;
The second situation is a bit more complicated.  It is possible for two extensions to have circular dependencies.  For example:&lt;br /&gt;
*Extension &amp;quot;A&amp;quot; requires extension &amp;quot;B.&amp;quot;&lt;br /&gt;
*Extension &amp;quot;B&amp;quot; requires extension &amp;quot;A.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If either extension is unloaded, the opposite extension is unloaded normally.  The first extension then receives the interface drop callbacks.  In this situation, it is essential that the &amp;lt;tt&amp;gt;NotifyInterfaceDrop&amp;lt;/tt&amp;gt; function be implemented and used with the circular interface.  Otherwise, you risk crashing when your extension unloads (or at the very least, leaking memory).  Since the actual drop order is undefined, it means both extensions must implement this function to be safe.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Automatic Loading=&lt;br /&gt;
There are two types of automatic loading: Dynamic and Global.  Dynamic loading means your extension is only loaded when a plugin requires it.  Global loading means your extension loads no matter what.&lt;br /&gt;
&lt;br /&gt;
==Dynamic Autoloading==&lt;br /&gt;
Dynamic loading requires that you create an include file for plugins.  Plugins that include your file will automatically load your extension.  This requires implementing the &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; structure found in &amp;lt;tt&amp;gt;core.inc&amp;lt;/tt&amp;gt;.  You must expose the structure as &amp;lt;tt&amp;gt;public&amp;lt;/tt&amp;gt;, and the name must start with &amp;quot;&amp;lt;tt&amp;gt;__ext_&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;sourcepawn&amp;gt;/**&lt;br /&gt;
 * Do not edit below this line!&lt;br /&gt;
 */&lt;br /&gt;
public Extension:__ext_geoip = &lt;br /&gt;
{&lt;br /&gt;
	name = &amp;quot;GeoIP&amp;quot;,&lt;br /&gt;
	file = &amp;quot;geoip.ext&amp;quot;,&lt;br /&gt;
#if defined AUTOLOAD_EXTENSIONS&lt;br /&gt;
	autoload = 1,&lt;br /&gt;
#else&lt;br /&gt;
	autoload = 0,&lt;br /&gt;
#endif&lt;br /&gt;
#if defined REQUIRE_EXTENSIONS&lt;br /&gt;
	required = 1,&lt;br /&gt;
#else&lt;br /&gt;
	required = 0,&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/sourcepawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanations:&lt;br /&gt;
*&amp;lt;b&amp;gt;name&amp;lt;/b&amp;gt;: The name of your module as written in &amp;lt;tt&amp;gt;SMEXT_CONF_NAME&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;b&amp;gt;file&amp;lt;/b&amp;gt;: The platform-inspecific portion of your extension's file name.&lt;br /&gt;
*&amp;lt;b&amp;gt;autoload&amp;lt;/b&amp;gt;: Specifies that your module should always dynamically autoload by default.  You can tweak this to either never autoload or always autoload (without letting the user toggle).&lt;br /&gt;
*&amp;lt;b&amp;gt;required&amp;lt;/b&amp;gt;: Specifies whether or not this extension is '''required''' by your plugin.  If for some reason your extension fails to load (or is not found), the plugin will also fail to load.  This is changeable if you wish to override the default behavior.&lt;br /&gt;
&lt;br /&gt;
You can copy and paste this example, but remember to modify the following portions:&lt;br /&gt;
*&amp;lt;b&amp;gt;__ext_geoip&amp;lt;/b&amp;gt;: Change the &amp;quot;geoip&amp;quot; portion to your own unique variable name.&lt;br /&gt;
*&amp;lt;b&amp;gt;&amp;quot;GeoIP&amp;lt;/b&amp;gt;: Change the GeoIP portion to your extension's name.  This should match the name you chose as &amp;lt;tt&amp;gt;SMEXT_CONF_NAME&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;b&amp;gt;&amp;quot;geoip.ext&amp;quot;&amp;lt;/b&amp;gt;: Change this to your extension's file name, without the .dll/.so portion.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Global Autoloading==&lt;br /&gt;
To have your extension always autoload, you must create a ''.autoload'' file in the &amp;lt;tt&amp;gt;extensions&amp;lt;/tt&amp;gt; folder.  For example, to have the &amp;lt;tt&amp;gt;threader.ext.dll&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;threader.ext.so&amp;lt;/tt&amp;gt; extensions autoload, you'd create the following file in &amp;lt;tt&amp;gt;extensions&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;threader.autoload&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A few notes:&lt;br /&gt;
*This only works for extensions using the .ext.&amp;lt;platform&amp;gt; convention.  SourceMod cuts off the &amp;quot;.autoload&amp;quot; portion of the file, then adds the appropriate extension just as if 'sm exts load' was used.&lt;br /&gt;
*The file does not need to contain anything, it simply needs to exist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Conventions=&lt;br /&gt;
&lt;br /&gt;
==Designing API/Natives==&lt;br /&gt;
*Start interface names with the capital letter 'I'.&lt;br /&gt;
*Use a consistent naming convention.  SourceMod uses [http://msdn2.microsoft.com/en-us/library/ms229002.aspx Microsoft/Pascal] naming.  Avoid Java/Camel casing for both API and natives.&lt;br /&gt;
*When exposing interfaces, make sure your exposure defines start with &amp;lt;tt&amp;gt;SMINTERFACE_&amp;lt;/tt&amp;gt; and end with &amp;lt;tt&amp;gt;_NAME&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;_VERSION&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==External Naming==&lt;br /&gt;
*Logtags (&amp;lt;tt&amp;gt;SMEXT_CONF_LOGTAG&amp;lt;/tt&amp;gt;) should be short names (under 10 characters or so) in all capital letters.&lt;br /&gt;
*Your extension file name should never have &amp;lt;tt&amp;gt;_i486&amp;lt;/tt&amp;gt; or other unnecessary platform-specific notations in its name.&lt;br /&gt;
*Your extension file name should always end in &amp;lt;tt&amp;gt;.ext.so&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;.ext.dll&amp;lt;/tt&amp;gt; depending on the platform.  The &amp;lt;tt&amp;gt;.ext.&amp;lt;/tt&amp;gt; is SourceMod convention.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Setting up Visual Studio=&lt;br /&gt;
&lt;br /&gt;
{{qnotice|It is recommended that you make a copy of the sample_ext project and modify that rather than create your own project, as it will set up most of this for you}}&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Project ==&lt;br /&gt;
&lt;br /&gt;
Instead of manually creating a project, you can make a copy of the sample_ext project and modify it.&lt;br /&gt;
&lt;br /&gt;
The sample_ext project assumes that it is located in a subdirectory inside the SourceMod public directory.  To change this, modify all references to ..\.. to $(SOURCEMOD15)\public and specify the SOURCEMOD15 variable as mentioned in the Optional Environment variables.&lt;br /&gt;
&lt;br /&gt;
The sample_ext projectuses the following environment variables to locate the various source code parts.  To set environment variables:&lt;br /&gt;
&lt;br /&gt;
'''Windows XP''': Start -&amp;gt; Settings -&amp;gt; Control Panel -&amp;gt; System -&amp;gt; Advanced -&amp;gt; Environment Variables&lt;br /&gt;
&lt;br /&gt;
'''Windows Vista/7''': Start -&amp;gt; Control Panel -&amp;gt; System -&amp;gt; Advanced system properties -&amp;gt; Advanced -&amp;gt; Environment Variables&lt;br /&gt;
&lt;br /&gt;
=== Environment Variables ===&lt;br /&gt;
&lt;br /&gt;
The environment variables used are:&lt;br /&gt;
&lt;br /&gt;
* '''MMSOURCE17''': Path to MetaMod: Source source code for version 1.7 or newer. Used to compile SourceMod itself.  &lt;br /&gt;
* '''MMSOURCE18''': Path to MetaMod: Source source code for version 1.8 or newer. Used in SourceMod 1.4 projects.  &lt;br /&gt;
* '''MMSOURCE19''': Path to MetaMod: Source source code for version 1.9 or newer. Used in SourceMod 1.5 projects.  &lt;br /&gt;
* '''HL2SDK''': Path to the Episode 1 SDK  &lt;br /&gt;
* '''HL2SDK-SWARM''': Path to the Alien Swarm SDK  &lt;br /&gt;
* '''HL2SDK-DARKM''': Path to the Dark Messiah SDK  &lt;br /&gt;
* '''HL2SDKCSGO''': Path to the Counter-Strike: Global Offensive SDK  &lt;br /&gt;
* '''HL2SDKCSS''': Path to the Counter-Strike: Source SDK  &lt;br /&gt;
* '''HL2SDKL4D''': Path to the Left 4 Dead SDK  &lt;br /&gt;
* '''HL2SDKL4D2''': Path to the Left 4 Dead 2 SDK  &lt;br /&gt;
* '''HL2SDKOB''': Path to the Orange Box SDK (not Source 2009)  &lt;br /&gt;
* '''HL2SDKOBVALVE''': Path to the Orange Box Valve / Source 2009 SDK (Half-Life 2: Deathmatch, Day of Defeat: Source, Team Fortress 2)&lt;br /&gt;
&lt;br /&gt;
Optional environment variables:&lt;br /&gt;
&lt;br /&gt;
* '''SOURCEMOD15'': Optional path to SourceMod 1.5 or newer source code&lt;br /&gt;
&lt;br /&gt;
==Manually configuring a project==&lt;br /&gt;
&lt;br /&gt;
===Paths===&lt;br /&gt;
'''Visual Studio 2003''': Tools -&amp;gt; Options -&amp;gt; Projects, VC++ Directories&lt;br /&gt;
&lt;br /&gt;
'''Visual Studio 2005''': Tools -&amp;gt; Options -&amp;gt; Projects and Solutions -&amp;gt; VC++ Directories&lt;br /&gt;
&lt;br /&gt;
====Include Paths====&lt;br /&gt;
*SourceMod only:&lt;br /&gt;
**sdk\public\extensions&lt;br /&gt;
**sdk\public\sourcepawn&lt;br /&gt;
**sdk\public&lt;br /&gt;
*SourceMM (Note that sourcemm might be 'trunk' for you):&lt;br /&gt;
**sourcemm\core&lt;br /&gt;
**sourcemm\core\sourcehook&lt;br /&gt;
*HL2SDK:&lt;br /&gt;
**game\shared&lt;br /&gt;
**public\vstdlib&lt;br /&gt;
**public\tier1&lt;br /&gt;
**public\tier0&lt;br /&gt;
**public\engine&lt;br /&gt;
**public&lt;br /&gt;
**dlls&lt;br /&gt;
&lt;br /&gt;
====Link Paths====&lt;br /&gt;
*HL2SDK:&lt;br /&gt;
**lib\public for version 2005&lt;br /&gt;
**lib-vc7\public for version 2003&lt;br /&gt;
&lt;br /&gt;
===Compiler Options===&lt;br /&gt;
&amp;lt;b&amp;gt;Note:&amp;lt;/b&amp;gt; These options are set by default in the sample Extension SDK.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Note:&amp;lt;/b&amp;gt; These options should be set for every build (Release/Debug/others).&lt;br /&gt;
&lt;br /&gt;
For VS 2005, goto Project-&amp;gt;Properties.&lt;br /&gt;
&lt;br /&gt;
*General&lt;br /&gt;
**&amp;lt;tt&amp;gt;Character Set&amp;lt;/tt&amp;gt;: '''Use Multi-Byte Character Set'''&lt;br /&gt;
*C/C++&lt;br /&gt;
**General&lt;br /&gt;
***&amp;lt;tt&amp;gt;Detect 64-bit Portability Issues&amp;lt;/tt&amp;gt;: '''No'''&lt;br /&gt;
**Preprocessor&lt;br /&gt;
***&amp;lt;tt&amp;gt;Preprocessor Defines&amp;lt;/tt&amp;gt;: Add &amp;lt;tt&amp;gt;_CRT_SECURE_NO_DEPRECATE&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;_CRT_NONSTDC_NO_DEPRECATE&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;SOURCEMOD_BUILD&amp;lt;/tt&amp;gt;  and &amp;lt;tt&amp;gt;WIN32&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Code Generation&lt;br /&gt;
***&amp;lt;tt&amp;gt;Runtime Library&amp;lt;/tt&amp;gt;: Multi-threaded or /MT (for Release), Multi-threaded Debug or /MTd (for Debug)&lt;br /&gt;
*Linker&lt;br /&gt;
**General&lt;br /&gt;
***&amp;lt;tt&amp;gt;Output File&amp;lt;/tt&amp;gt;: Change &amp;lt;tt&amp;gt;$(ProjectName)&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;$(ProjectName).ext&amp;lt;/tt&amp;gt;, or use your own custom string.&lt;br /&gt;
**Input&lt;br /&gt;
***&amp;lt;tt&amp;gt;Additional Dependencies&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;tier0.lib tier1.lib vstdlib.lib&amp;lt;/tt&amp;gt; (for SourceMM attached extensions only)&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod]]&lt;br /&gt;
[[Category:SourceMod Development]]&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Format_Class_Functions_(SourceMod_Scripting)&amp;diff=10914</id>
		<title>Format Class Functions (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Format_Class_Functions_(SourceMod_Scripting)&amp;diff=10914"/>
		<updated>2020-03-26T13:50:30Z</updated>

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

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

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

		<summary type="html">&lt;p&gt;Psychonic: typo fix&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{alert|info|&amp;lt;span style&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;&amp;quot;vertical-align: super;&amp;quot;&amp;gt;[[File:Ambox_content_soft.svg|35px]]&amp;lt;/span&amp;gt;{{ns|2}}{{resize|200%|This version is not yet released. The release notes are not final.}}|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|These are just the API changes from AMX Mod X 1.8.2 to AMX Mod X 1.9. Click here for the full [[AMX Mod X 1.9 Release Notes]].|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Hint:|This page includes hidden examples or API reference that you can toggle with {{tt|{{hidden|id=hint|labelonly=yes}}}}.|opt=full-border}}&lt;br /&gt;
{{hidden|id=hint|contentonly=yes|content=🙌 Congratulations for understanding the hint!{{margin|10px|}}}}&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
A large part of the scripting documentation has been improved and an online version with searching capability can be found at https://amxmodx.org/api/.&lt;br /&gt;
&lt;br /&gt;
== Gamedata ==&lt;br /&gt;
&lt;br /&gt;
As stated in the Release Notes, we have now gamedata files to avoid to hard code data related to the game or engine. Such files located in the {{tt|amxmodx/data/gamedata/}} directory.&lt;br /&gt;
&lt;br /&gt;
Gamedata files shipped with AMX Mod X can and will be updated at any time, therefore it is strongly discouraged to edit them manually.&amp;lt;br /&amp;gt;&lt;br /&gt;
To make custom gamedata changes, please use the custom folder under the gamedata directory. All files under this directory are parsed (in an undefined order) after the main files are loaded. They will never be overwritten.&lt;br /&gt;
&lt;br /&gt;
The files structure is currently arranged this way:&lt;br /&gt;
&lt;br /&gt;
{{tt|&lt;br /&gt;
├─ '''common.games'''&lt;br /&gt;
│  ├─ entities.games&lt;br /&gt;
│  │  └─ ''$mod''&lt;br /&gt;
│  │	 ├─ offsets-''$class''.txt&lt;br /&gt;
│  │	 ├─ ...&lt;br /&gt;
│  ├─ gamerules.games&lt;br /&gt;
│  │  └─ ''$mod''&lt;br /&gt;
│  │	 ├─ offsets-''$class''.txt&lt;br /&gt;
│  │	 ├─ ...&lt;br /&gt;
│  ├─ hostages.games&lt;br /&gt;
│  │  └─ ''$mod''&lt;br /&gt;
│  │	 ├─ offsets-''$class''.txt&lt;br /&gt;
│  │	 ├─ ...&lt;br /&gt;
│  ├─ others.games&lt;br /&gt;
│  │  └─ ''$mod''&lt;br /&gt;
│  │	 ├─ offsets-''$class''.txt&lt;br /&gt;
│  │	 ├─ ...&lt;br /&gt;
│  ├─ functions.engine.txt&lt;br /&gt;
│  ├─ globalvars.engine.txt&lt;br /&gt;
│  └─ {{color|#006699|master.games.txt}}&lt;br /&gt;
├─ '''modules.games'''&lt;br /&gt;
│  ├─ {{color|#006699|master.games.txt}}&lt;br /&gt;
│  └─ game.cstrike.txt&lt;br /&gt;
|bgcolor=white}}&lt;br /&gt;
 &lt;br /&gt;
The main directories are:&lt;br /&gt;
* {{tt|'''common.games'''|bgcolor=white}} contains the shared data.&lt;br /&gt;
* {{tt|'''modules.games'''|bgcolor=white}} contains the data per module.&lt;br /&gt;
&lt;br /&gt;
In those directories, you will find:&lt;br /&gt;
* {{tt|{{color|#006699|master.games.txt|bgcolor=white}}|bgcolor=white}} which references all the files to be loaded by the core/modules.&lt;br /&gt;
&lt;br /&gt;
Inside {{tt|'''common.games'''|bgcolor=white}} directory:&lt;br /&gt;
* {{tt|entities.games|bgcolor=white}}, {{tt|entities.games|bgcolor=white}}, {{tt|entities.games|bgcolor=white}} and {{tt|others.games|bgcolor=white}} directories contains the ''$class'' member's offset per-''$mod''. Related to gamerules object but also player, hostage, item and weapons entities.&lt;br /&gt;
* {{tt|functions.engine.txt|bgcolor=white}} contains the symbols/signatures of functions in the engine.&lt;br /&gt;
* {{tt|globalvars.engine.txt|bgcolor=white}} contains the symbols/signatures of global variables in the engine.&lt;br /&gt;
&lt;br /&gt;
Inside {{tt|'''modules.games'''|bgcolor=white}} directory:&lt;br /&gt;
* {{tt|game.cstrike.txt|bgcolor=white}} contains CS-specific data such as the symbol/signatures of functions and others static datas. &lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|More details about the file format can be found in the Quick Guide in [[#Game_Config_Parser]].|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
== Compiler ==&lt;br /&gt;
&lt;br /&gt;
Along a bunch of fixed issues, there are some improvements/features worth to be noted.&lt;br /&gt;
&lt;br /&gt;
=== Emscripten support ===&lt;br /&gt;
&lt;br /&gt;
The AMX Mod X Compiler can now be compiled with [https://kripken.github.io/emscripten-site/ Emscripten] allowing it to run inside of a web browser.&lt;br /&gt;
&lt;br /&gt;
A good example is [https://spider.limetech.io/ Spider], a web-based, entirely client-side, editor and compiler for [Source]Pawn development (by {{user|59029|asherkin}}).&lt;br /&gt;
&lt;br /&gt;
=== Increased Limits ===&lt;br /&gt;
&lt;br /&gt;
Name/function and input line maximum length (in characters) have been increased.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Old value&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | New value&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | Name/Function&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|31|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|63|bgcolor=white}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | Input Line&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|511|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|4095|bgcolor=white}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Magic Globals ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Global&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|__BINARY_NAME__|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | Name of the compiled plugin. Example: {{tt|admin.amxx|bgcolor=none}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|__BINARY_PATH__|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | Absolute path to the compiled plugin. Example: {{tt|/home/hlds/cstrike/addons/amxmodx/plugins/admin.amxx|bgcolor=none}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|__LINE__|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | Current line from the plugin's source code.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note:  Values are populated at compile time.&lt;br /&gt;
&lt;br /&gt;
=== Pragma ===&lt;br /&gt;
&lt;br /&gt;
A new {{tt|&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt;pragma deprecated}} has been added to tell the compiler that this specific {{tt|native|bgcolor=none}}/{{tt|stock|bgcolor=none}} is deprecated. &amp;lt;br /&amp;gt;&lt;br /&gt;
This will issue a warning upon the compilation.&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=pragma_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=pragma_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#pragma deprecated  Some comment here.&lt;br /&gt;
native foo();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At compilation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
[...] warning 233: symbol &amp;quot;foo&amp;quot; is marked as deprecated: Some comment here.&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== String Literal Contatenation ===&lt;br /&gt;
&lt;br /&gt;
This basically allows you to concatenate literal strings and stringizing a parameter in macro substitution ''only'' (so possible breakage is very limited).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Symbol&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | To concatenate&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|+|bgcolor=white}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | To Stringize&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt;|bgcolor=white}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=concat_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=concat_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#define PROJECT_AUTHOR    &amp;quot;AMX Mod X&amp;quot;&lt;br /&gt;
#define PROJECT_COPYRIGHT &amp;quot;Copyright (C) 2017  &amp;quot; + PROJECT_AUTHOR&lt;br /&gt;
&lt;br /&gt;
#define VERSION_MAJOR      &amp;quot;1&amp;quot;&lt;br /&gt;
#define VERSION_MINOR      &amp;quot;9&amp;quot;&lt;br /&gt;
#define VERSION_RELEASE    &amp;quot;0&amp;quot;&lt;br /&gt;
#define VERSION            VERSION_MAJOR + &amp;quot;.&amp;quot; + VERSION_MINOR + &amp;quot;.&amp;quot; + VERSION_RELEASE&lt;br /&gt;
&lt;br /&gt;
#define log(%1)  &amp;quot;logging: &amp;quot; + #%1 + &amp;quot;\n&amp;quot;&lt;br /&gt;
&lt;br /&gt;
foo()&lt;br /&gt;
{&lt;br /&gt;
    server_print(log(hello));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Internal Core Changes ==&lt;br /&gt;
&lt;br /&gt;
=== String Buffer ===&lt;br /&gt;
&lt;br /&gt;
The buffer size AMX Mod X uses internally to retrieve strings has been increased from {{tt|3k}} to {{tt|16k}}.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|A {{tt|MAX_STRING_LENGTH}} define has been added in {{tt|amxconst.inc}}.|opt=full-border}}&lt;br /&gt;
{{alert|info|Note:|By default plugins don't have enough memory available to allocate an array of this size.&amp;lt;br /&amp;gt;You probably should not use this define to actually declare a buffer unless you ''absolutely'' have to.&amp;lt;br /&amp;gt;Look at {{tt|&amp;lt;nowiki&amp;gt;#pragma dynamic&amp;lt;/nowiki&amp;gt;}} to increase a plugins available memory.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
== New Core APIs ==&lt;br /&gt;
&lt;br /&gt;
=== Automatic Config File ===&lt;br /&gt;
&lt;br /&gt;
This provides a system for plugins to automatically generate config files with plugin's cvars which get executed on load. &amp;lt;br /&amp;gt;&lt;br /&gt;
This is done via the {{tt|AutoExecConfig}} native.&lt;br /&gt;
&lt;br /&gt;
Once all configuration files are executed, {{tt|OnConfigsExecuted}} is called. This forward will always be called, even if your plugin had no configs or if it was loaded late.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! Native&lt;br /&gt;
 ! Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|AutoExecConfig|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=AutoExecConfig|header=Specifies that the given config file should be executed after plugin load.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=AutoExecConfig|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Specifies that the given config file should be executed after plugin load.&lt;br /&gt;
 *&lt;br /&gt;
 * @note OnConfigsExecuted() will not be called until the config file has executed,&lt;br /&gt;
 *       but it will be called if the execution fails.&lt;br /&gt;
 * @note The name parameter should not contain dots, otherwise file will not be executed.&lt;br /&gt;
 *&lt;br /&gt;
 * @param autoCreate    If true, and the config file does not exist, such a config&lt;br /&gt;
 *                      file will be automatically created and populated with&lt;br /&gt;
 *                      information from the plugin's registered cvars.&lt;br /&gt;
 * @param name          Name of the config file, excluding the .cfg extension.&lt;br /&gt;
 *                      If empty, &amp;lt;plugin.filename.cfg&amp;gt; is assumed.&lt;br /&gt;
 * @param folder        Folder under plugins/ to use.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native AutoExecConfig(bool:autoCreate = true, const name[] = &amp;quot;&amp;quot;, const folder[] = &amp;quot;&amp;quot;);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! Forward&lt;br /&gt;
 ! Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|OnConfigsExecuted|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=OnConfigsExecuted|header=Called when the map has loaded, and all configs are done executing.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=OnConfigsExecuted|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Called when the map has loaded, and all configs are done executing.&lt;br /&gt;
 * This includes servercfgfile (server.cfg), amxx.cfg, plugin's config, and&lt;br /&gt;
 * per-map config.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This is best place to initialize plugin functions which are based on cvar data.&lt;br /&gt;
 * @note This will always be called once and only once per map.  It will be&lt;br /&gt;
 *       called few seconds after plugin_cfg().&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
forward OnConfigsExecuted();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|OnAutoConfigsBuffered|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=OnAutoConfigsBuffered|header=Called when the map has loaded, right after {{tt|plugin_cfg}} but any time before {{tt|OnConfigsExecuted}}.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=OnAutoConfigsBuffered|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Called when the map has loaded, right after plugin_cfg() but any time&lt;br /&gt;
 * before OnConfigsExecuted.  It's called after amxx.cfg and  all&lt;br /&gt;
 * AutoExecConfig() exec commands have been added to the server command buffer.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This will always be called once and only once per map.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
forward OnAutoConfigsBuffered();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=autoexecconfig_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=autoexecconfig_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    register_plugin(&amp;quot;Hat&amp;quot;, &amp;quot;User&amp;quot;, &amp;quot;1.0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    create_cvar(&amp;quot;mysqlk_database&amp;quot;, &amp;quot;&amp;quot;, .description = &amp;quot;MySQL database&amp;quot;);&lt;br /&gt;
    create_cvar(&amp;quot;mysqlk_host&amp;quot;, &amp;quot;localhost&amp;quot;, .description = &amp;quot;MySQL host, use this to configure various^nthings for your server.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    AutoExecConfig();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That would export a config file that looks like this:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// This file was auto-generated by AMX Mod X (v1.9)&lt;br /&gt;
// Cvars for plugin &amp;quot;Hat&amp;quot; by &amp;quot;User&amp;quot; (hat.amxx, v1.0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// MySQL database&lt;br /&gt;
// -&lt;br /&gt;
// Default: &amp;quot;&amp;quot;&lt;br /&gt;
mysqlk_database &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// MySQL host, use this to configure various&lt;br /&gt;
// things for your server.&lt;br /&gt;
// -&lt;br /&gt;
// Default: &amp;quot;localhost&amp;quot;&lt;br /&gt;
mysqlk_host &amp;quot;localhost&amp;quot;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== DataPack ===&lt;br /&gt;
&lt;br /&gt;
This offers you a way to dynamically store and move around various types of data.&lt;br /&gt;
&lt;br /&gt;
Datapacks provide a way to store and move around arbitrary amounts (and types) of data in AMX Mox X, available from {{tt|datapack.inc}}.&amp;lt;br /&amp;gt;&lt;br /&gt;
Data is packed into a single cell value - the {{tt|DataPack}} handle. This handle can be passed around more easily, can be returned by functions and can simulate advanced concepts like string consummation.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Creating &amp;amp; Disposing}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|CreateDataPack|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=CreateDataPack|header=Creates a new datapack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a new datapack.&lt;br /&gt;
 *&lt;br /&gt;
 * @return  New datapack handle, which must be freed via DestroyDataPack().&lt;br /&gt;
 */&lt;br /&gt;
native DataPack:CreateDataPack();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|DestroyDataPack|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=DestroyDataPack|header=Destroys the datapack and frees its memory.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Destroys the datapack and frees its memory.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          True if disposed, false otherwise&lt;br /&gt;
 */&lt;br /&gt;
native DestroyDataPack(&amp;amp;DataPack:pack);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Resetting}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ResetPack|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=ResetPack|header=Resets the datapack read/write position to the start.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Resets the datapack read/write position to the start.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 * @param clear     If true, clears the contained data&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native ResetPack(DataPack:pack, bool:clear = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Writing data}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|WritePackCell|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=WritePackCell|header=Packs a cell value into a datapack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Packs a cell value into a datapack.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 * @param cell      Cell value to pack&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native WritePackCell(DataPack:pack, any:cell);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|WritePackFloat|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=WritePackFloat|header=Packs a float value into a datapack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Packs a float value into a datapack.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 * @param val       Float value to pack&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native WritePackFloat(DataPack:pack, Float:val);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|WritePackString|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=WritePackString|header=Packs a string into a datapack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Packs a string into a datapack.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 * @param str       String to pack&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Length of copied string&lt;br /&gt;
 * @error           If an invalid handle is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native WritePackString(DataPack:pack, const str[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Reading data}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ReadPackCell|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=ReadPackCell|header=Reads a cell from a Datapack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Reads a cell from a Datapack.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Cell value&lt;br /&gt;
 * @error           If an invalid handle is provided, or not enough data is left&lt;br /&gt;
 *                  in the datapack, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native any:ReadPackCell(DataPack:pack);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ReadPackFloat|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=ReadPackFloat|header=Reads a float from a Datapack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Reads a float from a datapack.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Float value&lt;br /&gt;
 * @error           If an invalid handle is provided, or not enough data is left&lt;br /&gt;
 *                  in the datapack, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native Float:ReadPackFloat(DataPack:pack);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ReadPackString|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=ReadPackString|header=Reads a string from a Datapack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Reads a string from a Datapack.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 * @param buffer    Buffer to copy string to&lt;br /&gt;
 * @param maxlen    Maximum size of buffer&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of cells written to buffer&lt;br /&gt;
 * @error           If an invalid handle is provided, or not enough data is left&lt;br /&gt;
 *                  in the datapack, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native ReadPackString(DataPack:pack, buffer[], maxlen);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Managing position}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GetPackPosition|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=GetPackPosition|header=Returns the datapack read/write position.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns the datapack read/write position.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Position in the datapack, only usable with calls to SetPackPosition&lt;br /&gt;
 * @error           If an invalid handle is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native DataPackPos:GetPackPosition(DataPack:pack);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SetPackPosition|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SetPackPosition|header=Sets the datapack read/write position.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the datapack read/write position.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This should only ever be used with (known to be valid) positions&lt;br /&gt;
 *       returned by GetPackPosition(). It is not possible for plugins to safely&lt;br /&gt;
 *       compute datapack positions.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pack      Datapack handle&lt;br /&gt;
 * @param position  New position to set&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided, or the new position is&lt;br /&gt;
 *                  out of datapack bounds, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native SetPackPosition(DataPack:pack, DataPackPos:position);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=datapack_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=datapack_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    // Creating&lt;br /&gt;
    new const DataPack:pack = CreateDataPack();&lt;br /&gt;
&lt;br /&gt;
    // Writing&lt;br /&gt;
    WritePackCell(pack, refCell);&lt;br /&gt;
    WritePackFloat(pack, refFloat);&lt;br /&gt;
    WritePackString(pack, refString);&lt;br /&gt;
&lt;br /&gt;
    // Reset before reading&lt;br /&gt;
    ResetPack(pack);&lt;br /&gt;
    server_print(&amp;quot;Datapack is readable: %s&amp;quot;, !IsPackEnded(pack) ? &amp;quot;yes&amp;quot; : &amp;quot;no&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    // Reading&lt;br /&gt;
    new cellValue = ReadPackCell(pack);&lt;br /&gt;
    new Float:floatValue = ReadPackFloat(pack);&lt;br /&gt;
    new buffer[32];&lt;br /&gt;
    ReadPackString(pack, buffer, charsmax(buffer));&lt;br /&gt;
    server_print(&amp;quot;cellValue = %d, floatValue = %f, buffer = %s&amp;quot;, cellValue, floatValue, buffer)&lt;br /&gt;
    server_print(&amp;quot;Datapack is no more readable: %s&amp;quot;, IsPackEnded(pack) ? &amp;quot;yes&amp;quot; : &amp;quot;no&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    // Clear all data&lt;br /&gt;
    ResetPack(pack, .clear = true);&lt;br /&gt;
    server_print(&amp;quot;Datapack is empty: %s&amp;quot;, IsPackEnded(pack) ? &amp;quot;yes&amp;quot; : &amp;quot;no&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    // Disposing&lt;br /&gt;
    DestroyDataPack(pack);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Game Config Parser ===&lt;br /&gt;
&lt;br /&gt;
Now we have gamedata files, we strongly encourage any plugins which hardcode static game datas to use the following API.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Loading &amp;amp; Closing file}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|LoadGameConfigFile|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=LoadGameConfigFile|header=Loads a game config file.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Loads a game config file.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The file path must be relative to the 'gamedata' folder under the data folder&lt;br /&gt;
 *       and the extension should be omitted.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          File to load&lt;br /&gt;
 *&lt;br /&gt;
 * @return              A handle to the game config file&lt;br /&gt;
 */&lt;br /&gt;
native GameConfig:LoadGameConfigFile(const file[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|CloseGameConfigFile|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=CloseGameConfigFile|header=Destroys a game config and frees its memory.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Destroys a game config and frees its memory.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The function automatically sets the variable passed to it to 0 to aid&lt;br /&gt;
 *       in preventing accidental usage after destroy.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Game config handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return              1 on success, 0 if an invalid handle was passed in&lt;br /&gt;
 */&lt;br /&gt;
native CloseGameConfigFile(&amp;amp;GameConfig:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Getting value}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GameConfGetOffset|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=GameConfGetOffset|header=Returns an offset value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 *&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Game config handle&lt;br /&gt;
 * @param key           Key to retrieve from the offset section&lt;br /&gt;
 *&lt;br /&gt;
 * @return              An offset, or -1 on failure&lt;br /&gt;
 * @error               Invalid game config handle&lt;br /&gt;
 */&lt;br /&gt;
native GameConfGetOffset(GameConfig:handle, const key[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GameConfGetClassOffset|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=GameConfGetClassOffset|header=Returns an offset value given a classname.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns an offset value given a classname.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Game config handle&lt;br /&gt;
 * @param classname     Class name to match from the offset section&lt;br /&gt;
 * @param key           Key to retrieve from the offset section&lt;br /&gt;
 *&lt;br /&gt;
 * @return              An offset, or -1 on failure&lt;br /&gt;
 * @error               Invalid game config handle&lt;br /&gt;
 */&lt;br /&gt;
native GameConfGetClassOffset(GameConfig:handle, const classname[], const key[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GameConfGetKeyValue|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=GameConfGetKeyValue|header=Gets the value of a key from the &amp;quot;Keys&amp;quot; section.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets the value of a key from the &amp;quot;Keys&amp;quot; section.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Game config handle&lt;br /&gt;
 * @param key           Key to retrieve from the Keys section&lt;br /&gt;
 * @param buffer        Destination string buffer&lt;br /&gt;
 * @param maxlen        Maximum length of output string buffer&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True if key existed, false otherwise&lt;br /&gt;
 * @error               Invalid game config handle&lt;br /&gt;
 */&lt;br /&gt;
native bool:GameConfGetKeyValue(GameConfig:handle, const key[], buffer[], maxlen);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GameConfGetAddress|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=GameConfGetAddress|header=Finds an address calculation in a GameConfig file.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Finds an address calculation in a GameConfig file.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Game config handle&lt;br /&gt;
 * @param name          Name of the property to find&lt;br /&gt;
 *&lt;br /&gt;
 * @return              An address calculated on success, otherwise 0 on failure.&lt;br /&gt;
 * @error               Invalid game config handle&lt;br /&gt;
 */&lt;br /&gt;
native GameConfGetAddress(GameConfig:handle, const name[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Quick guide:|{{hidden|id=gameconfguide|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=gameconfguide|contentonly=yes|content=&lt;br /&gt;
&lt;br /&gt;
{{color|steelblue|'''Config location'''}}&lt;br /&gt;
&lt;br /&gt;
Any default and new gamedata files must be located in {{tt|/amxmodx/data/gamedata/}} directory.&amp;lt;br /&amp;gt;&lt;br /&gt;
You can create your own directories inside as well.&lt;br /&gt;
&lt;br /&gt;
{{color|steelblue|'''Filename format'''}}&lt;br /&gt;
&lt;br /&gt;
The file name must end with {{tt|.txt}} extension, e.g. {{tt|myfile.txt}}&lt;br /&gt;
&lt;br /&gt;
{{color|steelblue|'''Loading a specific file'''}}&lt;br /&gt;
&lt;br /&gt;
The right way to load a file is to provide the filename without {{tt|.txt}} extension.&amp;lt;br /&amp;gt;&lt;br /&gt;
E.g. {{tt|LoadGameConfigFile(&amp;quot;myfile&amp;quot;)}} will try to load {{tt|/data/gamedata/myfile.txt}}.&lt;br /&gt;
&lt;br /&gt;
{{color|steelblue|'''Loading multiple files'''}}&lt;br /&gt;
&lt;br /&gt;
You are able to load several at once via a master file, named {{tt|master.game.txt}}. &amp;lt;br /&amp;gt;&lt;br /&gt;
A master file is basically a way to tell the parser to load any files listed inside and nothing else. &amp;lt;br /&amp;gt;&lt;br /&gt;
You can also specify whether a file should be loaded depending the mod name (such as {{tt|cstrike}}) or engine (dedicated server: {{tt|engine_ds}} or listen server: {{tt|engine_ls}}). &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
├─ gamedata&lt;br /&gt;
│  └─ myfolder&lt;br /&gt;
│	  ├─ myfile1.txt&lt;br /&gt;
│	  ├─ myfile2.txt&lt;br /&gt;
│	  ├─ myfile3.txt&lt;br /&gt;
│	  └─ master.game.txt&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{tt|master.game.txt}}:&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
&amp;quot;Game Master&amp;quot;           // Must start with this.&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;myfile1.txt&amp;quot;       // No option, will be loaded all the time&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;myfile2.txt&amp;quot;       // Will be loaded for both servers&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;engine&amp;quot;  &amp;quot;engine_ds&amp;quot;&lt;br /&gt;
        &amp;quot;engine&amp;quot;  &amp;quot;engine_ls&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;myfile3.txt&amp;quot;       // Will be loaded only if the mod is Counter-Strike.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;game&amp;quot;  &amp;quot;cstrike&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then to load, you only need to provide your directory, e.g. {{tt|LoadGameConfigFile(&amp;quot;myfolder&amp;quot;)}}. &amp;lt;br /&amp;gt;&lt;br /&gt;
This will looks at the {{tt|/gamedata/myfolder/master.game.txt}} file and will load the listed files from there.&lt;br /&gt;
&lt;br /&gt;
{{color|darkblue|'''Config file format'''}}&lt;br /&gt;
&lt;br /&gt;
The config file has a specific format as well.&lt;br /&gt;
This must to start with:&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
&amp;quot;Games&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, you need to tell on what game the date will be loaded.&amp;lt;br /&amp;gt;&lt;br /&gt;
There are different values:&lt;br /&gt;
* {{tt|&amp;quot;&amp;lt;game name&amp;gt;&amp;quot;}}, such as {{tt|cstrike}}&lt;br /&gt;
* {{tt|&amp;quot;*&amp;quot;}} or {{tt|&amp;quot;#default&amp;quot;}} to match any game&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
&amp;quot;Games&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;cstrike&amp;quot;&lt;br /&gt;
    {&lt;br /&gt;
        // Counter-Strike only&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;#default&amp;quot;&lt;br /&gt;
    {&lt;br /&gt;
        // Any game&lt;br /&gt;
        // Note you can create multiple game blocks.&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need to create a block which inherit multiple games or engine, you can achieve it with {{tt|&amp;lt;nowiki&amp;gt;#supported&amp;lt;/nowiki&amp;gt;}} key.&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
&amp;quot;Games&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;#default&amp;quot;	// Must start with this&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;#supported&amp;quot;&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;game&amp;quot;   &amp;quot;cstrike&amp;quot;&lt;br /&gt;
            &amp;quot;game&amp;quot;   &amp;quot;czero&amp;quot;&lt;br /&gt;
&lt;br /&gt;
            &amp;quot;engine&amp;quot;  &amp;quot;engine_ds&amp;quot;  // you can specify the engine as well.&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
        // Data&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{color|darkblue|'''Data Type'''}}&lt;br /&gt;
&lt;br /&gt;
There are 5 different types of datas that you are allowed to store:&lt;br /&gt;
* ''Signature'':&lt;br /&gt;
: Retrieves an address from either a symbol or bytes. E.g. {{tt|@g_pGameRules}} or {{tt|\xDC\x2A\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x56}}&lt;br /&gt;
: Symbol must start with {{tt|@}}.&lt;br /&gt;
: For use with {{tt|GameConfGetAddress}} native.&lt;br /&gt;
* ''Address'':&lt;br /&gt;
: Reads a value from a given address (usually from signature reference)&lt;br /&gt;
: For use with {{tt|GameConfGetAddress}} native.&lt;br /&gt;
* ''Offset'':&lt;br /&gt;
: A platform-dependent value (windows, linux or mac)&lt;br /&gt;
: For use with {{tt|GameConfGetOffset}} native.&lt;br /&gt;
* ''Class Offset'':&lt;br /&gt;
: Same as Offset but can be grouped into a classname&lt;br /&gt;
: For use with {{tt|GameConfGetClassOffset}} native.&lt;br /&gt;
* ''Keyvalue'':&lt;br /&gt;
: simple key associated to a value.&lt;br /&gt;
: For use with {{tt|GameConfGetKeyValue}} native.&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
&amp;quot;Games&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;#default&amp;quot;&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;Signatures&amp;quot;&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;SV_DropClient&amp;quot;&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;library&amp;quot;   &amp;quot;engine&amp;quot; // This can be either &amp;quot;server&amp;quot; (mod), &amp;quot;engine_ds&amp;quot; (dedicated server) or &amp;quot;engine_ls' (listen server)&lt;br /&gt;
                &amp;quot;windows&amp;quot;   &amp;quot;\x55\x8B\x2A\x81\x2A\x2A\x2A\x2A\x2A\x8B\x2A\x2A\x53\x56\x8D&amp;quot;&lt;br /&gt;
                &amp;quot;linux&amp;quot;     &amp;quot;@SV_DropClient&amp;quot;&lt;br /&gt;
                &amp;quot;mac&amp;quot;       &amp;quot;@SV_DropClient&amp;quot; // Note: A symbol must start always with '@'&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            &amp;quot;g_pGameRules&amp;quot;&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;library&amp;quot;   &amp;quot;server&amp;quot;&lt;br /&gt;
                &amp;quot;windows&amp;quot;   &amp;quot;\x8B\x2A\x2A\x2A\x2A\x2A\x85\x2A\x74\x2A\x8B\x2A\xFF\x2A\x2A\xA1&amp;quot; // StartFrame()&lt;br /&gt;
                &amp;quot;linux&amp;quot;     &amp;quot;@g_pGameRules&amp;quot;&lt;br /&gt;
                &amp;quot;mac&amp;quot;       &amp;quot;@g_pGameRules&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;Offsets&amp;quot;&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;something&amp;quot;&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;windows&amp;quot;   &amp;quot;4&amp;quot;&lt;br /&gt;
                &amp;quot;linux&amp;quot;     &amp;quot;2&amp;quot;&lt;br /&gt;
                &amp;quot;mac&amp;quot;       &amp;quot;0&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;Classes&amp;quot;&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;CSomething&amp;quot;&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;Offsets&amp;quot;&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;windows&amp;quot;   &amp;quot;4&amp;quot;&lt;br /&gt;
                    &amp;quot;linux&amp;quot;     &amp;quot;2&amp;quot;&lt;br /&gt;
                    &amp;quot;mac&amp;quot;       &amp;quot;0&amp;quot;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;Addresses&amp;quot;&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;GameRulesPointer&amp;quot; // Gets the address of &amp;quot;g_pGameRules&amp;quot;, adds 2 bytes on windows and 0 byte on linux/mac.&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;signature&amp;quot;  &amp;quot;g_pGameRules&amp;quot;&lt;br /&gt;
&lt;br /&gt;
                &amp;quot;windows&amp;quot;&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;read&amp;quot;   &amp;quot;2&amp;quot;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                &amp;quot;read&amp;quot;  &amp;quot;0&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            &amp;quot;Something&amp;quot; // Gets the address of &amp;quot;SV_DropClient&amp;quot; and adds 5 bytes, on linux platform only.&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;linux&amp;quot;&lt;br /&gt;
                {&lt;br /&gt;
                    signature &amp;quot;SV_DropClient&amp;quot;&lt;br /&gt;
                    &amp;quot;read&amp;quot;    &amp;quot;5&amp;quot;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;Keys&amp;quot;&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;key1&amp;quot;   &amp;quot;value1&amp;quot;&lt;br /&gt;
            &amp;quot;Key2&amp;quot;   &amp;quot;value2&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Hasher ===&lt;br /&gt;
&lt;br /&gt;
Supports several new hash types: CRC32, MD5, SHA*, Keccak*.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|The following API deprecates {{tt|md5}} and {{tt|md5_file}} natives.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|hash_string|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=hash_string|header=Generates a hash value (message digest).|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Generates a hash value (message digest)&lt;br /&gt;
 *&lt;br /&gt;
 * @param string        String to be hashed.&lt;br /&gt;
 * @param type          Type of selected hashing algorithm. See Hash_* constants in amxconst.inc file.&lt;br /&gt;
 * @param output        Output string to store hash in.&lt;br /&gt;
 * @param outputSize    The maximum size of the output string to store hash in.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Number of written bytes.&lt;br /&gt;
 */&lt;br /&gt;
native hash_string(const string[], const HashType:type, output[], const outputSize);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|hash_file|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=hash_file|header=Generates a hash value using the contents of a given file.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Generates a hash value using the contents of a given file&lt;br /&gt;
 *&lt;br /&gt;
 * @param fileName      Path of file to be hashed.&lt;br /&gt;
 * @param type          Type of selected hashing algorithm. See Hash_* constants in amxconst.inc file.&lt;br /&gt;
 * @param output        Output string to store hash in.&lt;br /&gt;
 * @param outputSize    The maximum size of the output string to store hash in.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Number of written bytes.&lt;br /&gt;
 * @error               If the file couldn't be opened, an error is thrown.&lt;br /&gt;
 */&lt;br /&gt;
native hash_file(const fileName[], const HashType:type, output[], const outputSize);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
The available {{tt|HashType}} constants are:&lt;br /&gt;
&lt;br /&gt;
* {{tt|Hash_Crc32}}&lt;br /&gt;
* {{tt|Hash_Md5}}&lt;br /&gt;
* {{tt|Hash_Sha1}}&lt;br /&gt;
* {{tt|Hash_Sha256}}&lt;br /&gt;
* {{tt|Hash_Sha3_224}}&lt;br /&gt;
* {{tt|Hash_Sha3_256}}&lt;br /&gt;
* {{tt|Hash_Sha3_384}}&lt;br /&gt;
* {{tt|Hash_Sha3_512}}&lt;br /&gt;
* {{tt|Hash_Keccak_224}}&lt;br /&gt;
* {{tt|Hash_Keccak_256}}&lt;br /&gt;
* {{tt|Hash_Keccak_384}}&lt;br /&gt;
* {{tt|Hash_Keccak_512}}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=hasher_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=hasher_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    new hash1[32];&lt;br /&gt;
    new const message[] = &amp;quot;Hello World!&amp;quot;;&lt;br /&gt;
    new const length = hash_string(message, Hash_Md5, hash1, charsmax(hash1));&lt;br /&gt;
&lt;br /&gt;
    server_print(&amp;quot;hash1 = %s&amp;quot;, hash1);&lt;br /&gt;
&lt;br /&gt;
    new hash2[32];&lt;br /&gt;
    new const fileName[] = &amp;quot;server.cfg&amp;quot;;&lt;br /&gt;
    new const length = hash_file(message, Hash_Md5, hash2, charsmax(hash2));&lt;br /&gt;
&lt;br /&gt;
    server_print(&amp;quot;hash2 = %s&amp;quot;, hash2);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Stack Structure ===&lt;br /&gt;
&lt;br /&gt;
A stack is a LIFO (last in, first out) dynamic vector of of items.&lt;br /&gt;
&lt;br /&gt;
Stacks provide only two operations:&lt;br /&gt;
* Push, adding an item to the top.&lt;br /&gt;
* Pop, removing an item from the top, in reverse-push order.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|An example is available in the {{tt|testsuite}} directory, see [https://github.com/alliedmodders/amxmodx/blob/master/plugins/testsuite/stacktest.sma stacktest.sma].|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Creating &amp;amp; Destroying}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|CreateStack|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=CreateStack|header=Creates a stack structure.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a stack structure. A stack is a LIFO (last in, first out) vector of&lt;br /&gt;
 * of items. It has O(1) insertion and O(1) removal.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Stacks provide only two operations: Push (adding an item to the top)&lt;br /&gt;
 * 		 and Pop (remove an item from the top, in reverse-push order).&lt;br /&gt;
 * @note The contents of the stack are uniform; i.e. storing a string and then&lt;br /&gt;
 *       retrieving it as an integer is NOT the same as str_to_num()!&lt;br /&gt;
 * @note The &amp;quot;blocksize&amp;quot; determines how many cells each stack slot has, it can&lt;br /&gt;
 *       not be changed after creation.&lt;br /&gt;
 *&lt;br /&gt;
 * @param blocksize     The number of cells each entry in the stack can hold&lt;br /&gt;
 *&lt;br /&gt;
 * @return              New stack Handle, which must be freed via DestroyStack()&lt;br /&gt;
 * @error               If an invalid blocksize is provided an error will be&lt;br /&gt;
 *                      thrown.&lt;br /&gt;
 */&lt;br /&gt;
native Stack:CreateStack(blocksize = 1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|DestroyStack|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=DestroyStack|header=Destroys a stack and frees its memory.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Destroys a stack and frees its memory.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The function automatically sets the variable passed to it to 0 to aid&lt;br /&gt;
 *       in preventing accidental usage after destroy.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Stack to destroy&lt;br /&gt;
 *&lt;br /&gt;
 * @return          1 if the Stack was destroyed, 0 if nothing had to be&lt;br /&gt;
 *                  destroyed (invalid handle)&lt;br /&gt;
 */&lt;br /&gt;
native DestroyStack(&amp;amp;Stack:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Pushing Data}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|PushStackCell|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=PushStackCell|header=Pushes a value onto the end of the stack, adding a new index.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Pushes a value onto the end of the stack, adding a new index.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This may safely be used even if the stack has a blocksize greater than&lt;br /&gt;
 *       1.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Stack handle&lt;br /&gt;
 * @param value     Value to push&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided or the resizing&lt;br /&gt;
 *                  operation runs out of memory, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native PushStackCell(Stack:handle, any:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|PushStackString|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=PushStackString|header=Pushes a string onto the end of a stack, truncating it if it is too long.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Pushes a string onto the end of a stack, truncating it if it is too long.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Stack handle&lt;br /&gt;
 * @param value     String to push&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided or the resizing&lt;br /&gt;
 *                  operation runs out of memory, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native PushStackString(Stack:handle, const value[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|PushStackArray|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=PushStackArray|header=Pushes an array of cells onto the end of a stack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Pushes an array of cells onto the end of a stack. The cells are pushed as a&lt;br /&gt;
 * block (i.e. the entire array takes up one stack slot), rather than pushing&lt;br /&gt;
 * each cell individually.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Stack handle&lt;br /&gt;
 * @param values    Block of values to copy&lt;br /&gt;
 * @param size      If not set, the number of elements copied from the array&lt;br /&gt;
 *                  will be equal to the blocksize, if set higher than the&lt;br /&gt;
 *                  blocksize, the operation will be truncated,&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided or the resizing&lt;br /&gt;
 *                  operation runs out of memory, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native PushStackArray(Stack:handle, const any:values[], size= -1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Poping Data}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|PopStackCell|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=PopStackCell|header=Pops a cell value from a stack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Pops a cell value from a stack.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Stack handle&lt;br /&gt;
 * @param value     Variable to store the value in&lt;br /&gt;
 * @param block     Optionally specify which block to read from (useful if the&lt;br /&gt;
 *                  blocksize is &amp;gt; 0)&lt;br /&gt;
 * @param asChar    Optionally read as a byte instead of a cell&lt;br /&gt;
 *&lt;br /&gt;
 * @return          True on success, false if the stack is empty.&lt;br /&gt;
 * @error           If an invalid handle, invalid block or invalid byte is&lt;br /&gt;
 *                  provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bool:PopStackCell(Stack:handle, &amp;amp;any:value, block = 0, bool:asChar = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|PopStackString|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=PopStackString|header=Pops a string value from a stack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Pops a string value from a stack.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Stack handle&lt;br /&gt;
 * @param buffer        Buffer to copy string to&lt;br /&gt;
 * @param maxlength     Maximum size of the buffer&lt;br /&gt;
 * @param written       Variable to store number of characters copied to&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false if the stack is empty&lt;br /&gt;
 * @error               If an invalid handle is provided an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bool:PopStackString(Stack:handle, buffer[], maxlength, &amp;amp;written = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|PopStackArray|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=PopStackArray|header=Pops an array of cells from a stack.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Pops an array of cells from a stack.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Stack handle&lt;br /&gt;
 * @param buffer    Array to copy value to&lt;br /&gt;
 * @param size      Size of buffer, if not set (-1) assumes the size is equal to&lt;br /&gt;
 *                  the stack blocksize&lt;br /&gt;
 *&lt;br /&gt;
 * @return          True on success, false if the stack is empty&lt;br /&gt;
 * @error           If an invalid handle is provided an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bool:PopStackArray(Stack:handle, any:buffer[], size = -1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Others}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|IsStackEmpty|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=IsStackEmpty|header=Returns if a stack is empty.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns if a stack is empty.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Stack handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          True if empty, false if not empty&lt;br /&gt;
 * @error           If an invalid handle is provided an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bool:IsStackEmpty(Stack:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|PopStack|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=PopStack|header=Pops a value off a stack, ignoring it completely.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Pops a value off a stack, ignoring it completely.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Stack handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          True if a value was popped, false if stack is empty&lt;br /&gt;
 * @error           If an invalid handle is provided an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
stock PopStack(Stack:handle)&lt;br /&gt;
{&lt;br /&gt;
    new value;&lt;br /&gt;
    return PopStackCell(handle, value);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=== Text Parser INI/SMC ===&lt;br /&gt;
&lt;br /&gt;
Event-based text parser to read data in an unified way. It supports INI and SMC (similar to VTF) formats.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|An example is available in the {{tt|testsuite}} directory, see [https://github.com/alliedmodders/amxmodx/blob/master/plugins/testsuite/textparse_test.sma textparse.sma].|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
'''SMC Format'''&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Technical format detail:|{{hidden|id=smc-format|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=smc-format|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * The SMC file format is defined as:&lt;br /&gt;
 *    WHITESPACE: 0x20, \n, \t, \r&lt;br /&gt;
 *    IDENTIFIER: Any ASCII character EXCLUDING &amp;quot;, {, }, ;, //, / *, or WHITESPACE.&lt;br /&gt;
 *    STRING    : Any set of symbols enclosed in quotes.&lt;br /&gt;
 *&lt;br /&gt;
 *    Note: if a STRING does not have quotes, it is parsed as an IDENTIFIER.&lt;br /&gt;
 *&lt;br /&gt;
 * Basic syntax is comprised of SECTIONBLOCKs.&lt;br /&gt;
 *    A SECTIONBLOCK defined as:&lt;br /&gt;
 *&lt;br /&gt;
 *    SECTIONNAME&lt;br /&gt;
 *    {&lt;br /&gt;
 *        OPTION&lt;br /&gt;
 *    }&lt;br /&gt;
 *&lt;br /&gt;
 * OPTION can be repeated any number of times inside a SECTIONBLOCK.&lt;br /&gt;
 * A new line will terminate an OPTION, but there can be more than one OPTION per line.&lt;br /&gt;
 * OPTION is defined any of:&lt;br /&gt;
 *    &amp;quot;KEY&amp;quot;  &amp;quot;VALUE&amp;quot;&lt;br /&gt;
 *    SECTIONBLOCK&lt;br /&gt;
 *&lt;br /&gt;
 * SECTIONNAME, KEY, VALUE, and SINGLEKEY are strings&lt;br /&gt;
 * SECTIONNAME cannot have trailing characters if quoted, but the quotes can be optionally removed.&lt;br /&gt;
 * If SECTIONNAME is not enclosed in quotes, the entire sectionname string is used (minus surrounding whitespace).&lt;br /&gt;
 * If KEY is not enclosed in quotes, the key is terminated at first whitespace.&lt;br /&gt;
 * If VALUE is not properly enclosed in quotes, the entire value string is used (minus surrounding whitespace).&lt;br /&gt;
 * The VALUE may have inner quotes, but the key string may not.&lt;br /&gt;
 *&lt;br /&gt;
 * WHITESPACE should be ignored.&lt;br /&gt;
 * Comments are text occurring inside the following tokens, and should be stripped&lt;br /&gt;
 * unless they are inside literal strings:&lt;br /&gt;
 *    ;&amp;lt;TEXT&amp;gt;&lt;br /&gt;
 *    //&amp;lt;TEXT&amp;gt;&lt;br /&gt;
 *    / *&amp;lt;TEXT&amp;gt; * /&lt;br /&gt;
 *&lt;br /&gt;
 * Example file below:&lt;br /&gt;
 *   &amp;quot;SomeSection&amp;quot;&lt;br /&gt;
 *   {&lt;br /&gt;
 *	      /**&lt;br /&gt;
 *	       * Some comment&lt;br /&gt;
 *         */&lt;br /&gt;
 *	      &amp;quot;Key&amp;quot;		&amp;quot;value&amp;quot;&lt;br /&gt;
 *   }&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! Native&lt;br /&gt;
 ! Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SMC_CreateParser|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SMC_CreateParser|header=Creates a new SMC parser.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=SMC_CreateParser|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Parser invalid code.&lt;br /&gt;
 */&lt;br /&gt;
enum SMCParser&lt;br /&gt;
{&lt;br /&gt;
    Invalid_SMCParser = 0&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Parse result directive.&lt;br /&gt;
 */&lt;br /&gt;
enum SMCResult&lt;br /&gt;
{&lt;br /&gt;
    SMCParse_Continue,          /* Continue parsing */&lt;br /&gt;
    SMCParse_Halt,              /* Stop parsing here */&lt;br /&gt;
    SMCParse_HaltFail           /* Stop parsing and return failure */&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a new SMC parser.&lt;br /&gt;
 * This is used to set parse hooks.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              A new handle to an SMC Parse structure.&lt;br /&gt;
 */&lt;br /&gt;
native SMCParser:SMC_CreateParser();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SMC_DestroyParser|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SMC_DestroyParser|header=Disposes of an SMC parser.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=SMC_DestroyParser|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Disposes of an SMC parser.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True if disposed, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native SMC_DestroyParser(&amp;amp;SMCParser:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SMC_ParseFile|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SMC_ParseFile|header=Parses a config file.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=SMC_ParseFile|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Parses a config file.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        A handle to an SMC Parse structure.&lt;br /&gt;
 * @param file          A string containing the file path.&lt;br /&gt;
 * @param line          An optional by reference cell to store the last line number read.&lt;br /&gt;
 * @param col           An optional by reference cell to store the last column number read.&lt;br /&gt;
 * @param data          An optional handle or value to pass through to callback functions&lt;br /&gt;
 *&lt;br /&gt;
 * @return              An SMCParseError result.&lt;br /&gt;
 * @error               Invalid or corrupt handle.&lt;br /&gt;
 */&lt;br /&gt;
native SMCError:SMC_ParseFile(SMCParser:handle, const file[], &amp;amp;line = 0, &amp;amp;col = 0, any:data = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Parse error codes.&lt;br /&gt;
 */&lt;br /&gt;
enum SMCError&lt;br /&gt;
{&lt;br /&gt;
    SMCError_Okay = 0,          /* No error */&lt;br /&gt;
    SMCError_StreamOpen,        /* Stream failed to open */&lt;br /&gt;
    SMCError_StreamError,       /* The stream died... somehow */&lt;br /&gt;
    SMCError_Custom,            /* A custom handler threw an error */&lt;br /&gt;
    SMCError_InvalidSection1,   /* A section was declared without quotes, and had extra tokens */&lt;br /&gt;
    SMCError_InvalidSection2,   /* A section was declared without any header */&lt;br /&gt;
    SMCError_InvalidSection3,   /* A section ending was declared with too many unknown tokens */&lt;br /&gt;
    SMCError_InvalidSection4,   /* A section ending has no matching beginning */&lt;br /&gt;
    SMCError_InvalidSection5,   /* A section beginning has no matching ending */&lt;br /&gt;
    SMCError_InvalidTokens,     /* There were too many unidentifiable strings on one line */&lt;br /&gt;
    SMCError_TokenOverflow,     /* The token buffer overflowed */&lt;br /&gt;
    SMCError_InvalidProperty1,  /* A property was declared outside of any section */&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SMC_SetParseStart|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SMC_SetParseStart|header=Sets the SMC_ParseStart function of a parse handle.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=SMC_SetParseStart|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the SMC_ParseStart function of a parse handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Below is the prototype of callback:&lt;br /&gt;
 *        -&lt;br /&gt;
 *          Called when parsing is started.&lt;br /&gt;
 *&lt;br /&gt;
 *          @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 *          @param data          Handle or value passed in SMC_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *          @noreturn&lt;br /&gt;
 *&lt;br /&gt;
 *          public OnParseStart(SMCParser:handle, any:data)&lt;br /&gt;
 *        -&lt;br /&gt;
 * @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 * @param func          A ParseStart callback.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error               Invalid or corrupt handle.&lt;br /&gt;
 */&lt;br /&gt;
native SMC_SetParseStart(SMCParser:handle, const func[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SMC_SetParseEnd|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SMC_SetParseEnd|header=Sets the SMC_ParseEnd function of a parse handle.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=SMC_SetParseEnd|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the SMC_ParseEnd function of a parse handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Below is the prototype of callback:&lt;br /&gt;
 *        -&lt;br /&gt;
 *          Called when parsing is halted.&lt;br /&gt;
 *&lt;br /&gt;
 *          @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 *          @param halted        True if abnormally halted, false otherwise.&lt;br /&gt;
 *          @param failed        True if parsing failed, false otherwise.&lt;br /&gt;
 *          @param data          Handle or value passed in SMC_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *          @noreturn&lt;br /&gt;
 *&lt;br /&gt;
 *          public OnParseEnd(SMCParser:handle, bool:halted, bool:failed, any:data)&lt;br /&gt;
 *        -&lt;br /&gt;
 * @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 * @param func          A ParseEnd callback.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error               Invalid or corrupt handle.&lt;br /&gt;
 */&lt;br /&gt;
native SMC_SetParseEnd(SMCParser:handle, const func[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SMC_SetReaders|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SMC_SetReaders|header=Sets the three main reader functions.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=SMC_SetReaders|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the three main reader functions.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Enclosing quotes are always stripped.&lt;br /&gt;
 * @note  Below is the prototype of callbacks:&lt;br /&gt;
 *        -&lt;br /&gt;
 *          NewSection:&lt;br /&gt;
 *              Called when the parser finds a new section or sub-section.&lt;br /&gt;
 *&lt;br /&gt;
 *              @param handle           Handle to an SMC Parse structure.&lt;br /&gt;
 *              @param name             String containing section name.&lt;br /&gt;
 *              @param data             Handle or value passed in SMC_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *              @return                 An SMCResult action to take.&lt;br /&gt;
 *&lt;br /&gt;
 *              public SMCResult:OnNewSection(SMCParser:handle, const name[], any:data)&lt;br /&gt;
 *&lt;br /&gt;
 *          KeyValue:&lt;br /&gt;
 *              Called when the parser finds a new key/value pair.&lt;br /&gt;
 *&lt;br /&gt;
 *              @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 *              @param key           String containing key name.&lt;br /&gt;
 *              @param value         String containing value name.&lt;br /&gt;
 *              @param data          Handle or value passed in SMC_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *              @return              An SMCResult action to take.&lt;br /&gt;
 *&lt;br /&gt;
 *              public SMCResult:OnKeyValue(SMCParser:handle, const key[], const value[], any:data)&lt;br /&gt;
 *&lt;br /&gt;
 *          EndSection:&lt;br /&gt;
 *              Called when the parser finds the end of the current section.&lt;br /&gt;
 *&lt;br /&gt;
 *              @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 *              @param data          Handle or value passed in SMC_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *              @return              An SMCResult action to take.&lt;br /&gt;
 *&lt;br /&gt;
 *              public SMCResult:OnEndSection(SMCParser:handle, any:data)&lt;br /&gt;
 * -&lt;br /&gt;
 * @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 * @param kv            A KeyValue callback.&lt;br /&gt;
 * @param ns            An optional NewSection callback.&lt;br /&gt;
 * @param es            An optional EndSection callback.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native SMC_SetReaders(SMCParser:smc, const kvFunc[], const nsFunc[] = &amp;quot;&amp;quot;, const esFunc[] = &amp;quot;&amp;quot;);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SMC_SetRawLine|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SMC_SetRawLine|header=Sets a raw line reader on an text parser handle.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=SMC_SetRawLine|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a raw line reader on an text parser handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Below is the prototype of callbacks:&lt;br /&gt;
 *        -&lt;br /&gt;
 *          Called whenever a raw line is read.&lt;br /&gt;
 *&lt;br /&gt;
 *          @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 *          @param line          A string containing the raw line from the file.&lt;br /&gt;
 *          @param lineno        The line number it occurs on.&lt;br /&gt;
 *          @param data          Handle or value passed in SMC_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *          @return              An SMCResult action to take.&lt;br /&gt;
 *&lt;br /&gt;
 *          public SMCResult:SMC_RawLine(SMCParser:handle, const line[], lineno, any:data)&lt;br /&gt;
 *        -&lt;br /&gt;
 * @param handle        Handle to an SMC Parse structure.&lt;br /&gt;
 * @param func          A RawLine callback.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native SMC_SetRawLine(SMCParser:handle, const func[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SMC_GetErrorString|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SMC_GetErrorString|header=Gets an error string for an SMCError code.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=SMC_GetErrorString|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets an error string for an SMCError code.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  SMCError_Okay returns false.&lt;br /&gt;
 * @note  SMCError_Custom (which is thrown on SMCParse_HaltFail) returns false.&lt;br /&gt;
 *&lt;br /&gt;
 * @param error         The SMCParseError code.&lt;br /&gt;
 * @param buffer        A string buffer for the error (contents undefined on failure).&lt;br /&gt;
 * @param buf_max       The maximum size of the buffer.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native bool:SMC_GetErrorString(SMCError:error, buffer[], buf_max);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
'''INI Format'''&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Technical format detail:|{{hidden|id=ini-format|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=ini-format|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * The INI file format is defined as:&lt;br /&gt;
 *    WHITESPACE: 0x20, \n, \t, \r&lt;br /&gt;
 *    IDENTIFIER: A-Z a-z 0-9 _ - , + . $ ? /&lt;br /&gt;
 *    STRING    : Any set of symbols&lt;br /&gt;
 *&lt;br /&gt;
 * Basic syntax is comprised of SECTIONs.&lt;br /&gt;
 *    A SECTION is defined as:&lt;br /&gt;
 *    [SECTIONNAME]&lt;br /&gt;
 *    OPTION&lt;br /&gt;
 *    OPTION&lt;br /&gt;
 *    OPTION...&lt;br /&gt;
 *&lt;br /&gt;
 * SECTIONNAME is an IDENTIFIER.&lt;br /&gt;
 *    OPTION can be repeated any number of times, once per line.&lt;br /&gt;
 *    OPTION is defined as one of:&lt;br /&gt;
 *      KEY = &amp;quot;VALUE&amp;quot;&lt;br /&gt;
 *      KEY = VALUE&lt;br /&gt;
 *      KEY&lt;br /&gt;
 *    Where KEY is an IDENTIFIER and VALUE is a STRING.&lt;br /&gt;
 *&lt;br /&gt;
 * WHITESPACE should always be omitted.&lt;br /&gt;
 *    COMMENTS should be stripped, and are defined as text occurring in:&lt;br /&gt;
 *    ;&amp;lt;TEXT&amp;gt;&lt;br /&gt;
 *&lt;br /&gt;
 * Example file below.  Note that the second line is technically invalid.&lt;br /&gt;
 * The event handler must decide whether this should be allowed.&lt;br /&gt;
 *    --FILE BELOW--&lt;br /&gt;
 *    [gaben]&lt;br /&gt;
 *    hi = clams&lt;br /&gt;
 *    bye = &amp;quot;NO CLAMS&amp;quot;&lt;br /&gt;
 *&lt;br /&gt;
 *    [valve]&lt;br /&gt;
 *    cannot&lt;br /&gt;
 *    maintain&lt;br /&gt;
 *    products&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! Native&lt;br /&gt;
 ! Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|INI_CreateParser|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=INI_CreateParser|header=Creates a new SMC parser.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=INI_CreateParser|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Parser invalid code.&lt;br /&gt;
 */&lt;br /&gt;
enum INIParser&lt;br /&gt;
{&lt;br /&gt;
    Invalid_INIParser = 0&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a new INI parser.&lt;br /&gt;
 * This is used to set parse hooks.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              A new handle to an INI Parse structure.&lt;br /&gt;
 */&lt;br /&gt;
native INIParser:INI_CreateParser();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|INI_DestroyParser|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=INI_DestroyParser|header=Disposes of an INI parser.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=INI_DestroyParser|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Disposes of an INI parser.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Handle to an INI Parse structure.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True if disposed, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native INI_DestroyParser(&amp;amp;INIParser:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|INI_ParseFile|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=INI_ParseFile|header=Parses an INI config file.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=INI_ParseFile|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Parses an INI config file.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        A handle to an INI Parse structure.&lt;br /&gt;
 * @param file          A string containing the file path.&lt;br /&gt;
 * @param line          An optional by reference cell to store the last line number read.&lt;br /&gt;
 * @param col           An optional by reference cell to store the last column number read.&lt;br /&gt;
 * @param data          An optional handle or value to pass through to callback functions&lt;br /&gt;
 *&lt;br /&gt;
 * @return              An SMCParseError result.&lt;br /&gt;
 * @error               Invalid or corrupt handle.&lt;br /&gt;
 */&lt;br /&gt;
native bool:INI_ParseFile(INIParser:handle, const file[], &amp;amp;line = 0, &amp;amp;col = 0, any:data = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|INI_ParseStart|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=INI_ParseStart|header=Sets the INI_ParseStart function of a parse handle.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=INI_ParseStart|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the INI_ParseStart function of a parse handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Below is the prototype of callback:&lt;br /&gt;
 *        -&lt;br /&gt;
 *          Called when parsing is started.&lt;br /&gt;
 *&lt;br /&gt;
 *          @param handle        A handle to an INI Parse structure.&lt;br /&gt;
 *          @param data          Handle or value passed in INI_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *          @noreturn&lt;br /&gt;
 *&lt;br /&gt;
 *          public OnParseStart(INIParser:handle, any:data)&lt;br /&gt;
 *        -&lt;br /&gt;
 * @param handle        Handle to an INI Parse structure.&lt;br /&gt;
 * @param func          A ParseStart callback.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error               Invalid or corrupt handle.&lt;br /&gt;
 */&lt;br /&gt;
native INI_SetParseStart(INIParser:handle, const func[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|INI_SetParseEnd|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=INI_SetParseEnd|header=Sets the INI_ParseEnd function of a parse handle.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=INI_SetParseEnd|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the INI_ParseEnd function of a parse handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Below is the prototype of callback:&lt;br /&gt;
 *        -&lt;br /&gt;
 *          Called when parsing is halted.&lt;br /&gt;
 *&lt;br /&gt;
 *          @param handle        A handle to an INI Parse structure.&lt;br /&gt;
 *          @param halted        True if abnormally halted, false otherwise.&lt;br /&gt;
 *          @param data          Handle or value passed in INI_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *          @noreturn&lt;br /&gt;
 *&lt;br /&gt;
 *          public OnParseEnd(INIParser:handle, bool:halted, any:data)&lt;br /&gt;
 *        -&lt;br /&gt;
 * @param handle        Handle to an INI Parse structure.&lt;br /&gt;
 * @param func          A ParseEnd callback.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error               Invalid or corrupt handle.&lt;br /&gt;
 */&lt;br /&gt;
native INI_SetParseEnd(INIParser:handle, const func[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|INI_SetReaders|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=INI_SetReaders|header=Sets the two main reader functions.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=INI_SetReaders|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the two main reader functions.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Below is the prototype of callback:&lt;br /&gt;
 *        -&lt;br /&gt;
 *          NewSection:&lt;br /&gt;
 *              Called when the parser finds a new section.&lt;br /&gt;
 *&lt;br /&gt;
 *              @param handle           Handle to an INI Parse structure.&lt;br /&gt;
 *              @param section          Name of section in between the [ and ] characters.&lt;br /&gt;
 *              @param invalid_tokens   True if invalid tokens were detected in the name.&lt;br /&gt;
 *              @param close_bracket    True if a closing bracket was detected, false otherwise.&lt;br /&gt;
 *              @param extra_tokens     True if extra tokens were detected on the line.&lt;br /&gt;
 *              @param curtok           Contains current token in the line where the section name starts.&lt;br /&gt;
 *                                      You can add to this offset when failing to point to a token.&lt;br /&gt;
 *              @param data             Handle or value passed in INI_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *              @return                 True to keep parsing, false otherwise.&lt;br /&gt;
 *&lt;br /&gt;
 *              public bool:OnNewSection(INIParser:handle, const section[], bool:invalid_tokens, bool:close_bracket, bool:extra_tokens, curtok, any:data)&lt;br /&gt;
 *&lt;br /&gt;
 *          KeyValue:&lt;br /&gt;
 *              Called when the parser finds a new key/value pair.&lt;br /&gt;
 *&lt;br /&gt;
 *              @param handle           Handle to an INI Parse structure.&lt;br /&gt;
 *              @param key              Name of key.&lt;br /&gt;
 *              @param value            String containing value (with quotes stripped, if any).&lt;br /&gt;
 *              @param invalid_tokens   Whether or not the key contained invalid tokens.&lt;br /&gt;
 *              @param equal_token      There was an '=' sign present (in case the value is missing).&lt;br /&gt;
 *              @param quotes           Whether value was enclosed in quotes.&lt;br /&gt;
 *              @param curtok           Contains the token index of the start of the value string.&lt;br /&gt;
 *                                      This can be changed when returning false.&lt;br /&gt;
 *              @param data             Handle or value passed in INI_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *              @return                 True to keep parsing, false otherwise.&lt;br /&gt;
 *&lt;br /&gt;
 *              public bool:OnKeyValue(INIParser:handle, const key[], const value[], bool:invalid_tokens, bool:equal_token, bool:quotes, curtok, any:data)&lt;br /&gt;
 *        -&lt;br /&gt;
 * @param handle        Handle to an INI Parse structure.&lt;br /&gt;
 * @param kv            A KeyValue callback.&lt;br /&gt;
 * @param ns            An optional NewSection callback.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native INI_SetReaders(INIParser:smc, const kvFunc[], const nsFunc[] = &amp;quot;&amp;quot; );&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|INI_SetRawLine|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=INI_SetRawLine|header=Sets a raw line reader on an INI parser handle.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=INI_SetRawLine|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a raw line reader on an INI parser handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Below is the prototype of callback:&lt;br /&gt;
 *        -&lt;br /&gt;
 *          Called whenever a raw line is read.&lt;br /&gt;
 *&lt;br /&gt;
 *          @param handle       The INI Parse handle.&lt;br /&gt;
 *          @param line         Contents of line.&lt;br /&gt;
 *          @param lineno       The line number it occurs on.&lt;br /&gt;
 *          @param curtok       Pointer to optionally store failed position in string.&lt;br /&gt;
 *          @param data         Handle or value passed in INI_ParseFile&lt;br /&gt;
 *&lt;br /&gt;
 *          @return             True to keep parsing, false otherwise.&lt;br /&gt;
 *&lt;br /&gt;
 *          public bool:OnRawLine(INIParser:smc, const line[], lineno, curtok, any:data)&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Handle to an INI Parse structure.&lt;br /&gt;
 * @param func          A RawLine callback.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native INI_SetRawLine(INIParser:handle, const func[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
== Existing core APIs additions ==&lt;br /&gt;
&lt;br /&gt;
=== Client ===&lt;br /&gt;
&lt;br /&gt;
''' Behavior changes '''&lt;br /&gt;
&lt;br /&gt;
* The following natives can now be used on connecting players: {{tt|find_player}}, {{tt|get_players}} and {{tt|engclient_print}} (console only).&lt;br /&gt;
* {{tt|set_user_rendering}} default {{tt|color}} and {{tt|amount}} are now set to 0 to follow game behavior.&lt;br /&gt;
&lt;br /&gt;
''' (Dis)connection '''&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|The {{tt|client_disconnect}} forward is deprecated in favor of {{tt|client_disconnected}}.&amp;lt;br /&amp;gt;This will be called in some additional cases that {{tt|client_disconnect}} doesn't cover, most notably when a client aborts the connection process. &amp;lt;br /&amp;gt;It is guaranteed to pair with the {{tt|client_connect}} forward.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! Forward&lt;br /&gt;
 ! Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|client_connectex|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=client_connectex|header=Called when a client is connecting.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Called when a client is connecting.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This forward is called too early to do anything that directly affects&lt;br /&gt;
 *       the client.&lt;br /&gt;
 *&lt;br /&gt;
 * @param id        Client index&lt;br /&gt;
 * @param name      Client name&lt;br /&gt;
 * @param ip        Client ip address with port&lt;br /&gt;
 * @param reason    A reason that will be displayed when player gets rejected (can be overwritten)&lt;br /&gt;
 *&lt;br /&gt;
 * @return          PLUGIN_CONTINUE to let a client join to the server&lt;br /&gt;
 *                  PLUGIN_HANDLED or higher to prevent a client to join&lt;br /&gt;
 */&lt;br /&gt;
forward client_connectex(id, const name[], const ip[], reason[128]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|client_disconnected|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=client_disconnected|header=Called when a client is disconnected from the server.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Called when a client is disconnected from the server.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This will be called in some additional cases that client_disconnect doesn't cover,&lt;br /&gt;
 *       most notably when a client aborts the connection process. It is guaranteed to pair&lt;br /&gt;
 *       with the client_connect() forward.&lt;br /&gt;
 * @note When this fires the player entity is still valid (e.g. is_user_connected(id) will&lt;br /&gt;
 *       return true), but no networked commands will reach the client.&lt;br /&gt;
 *&lt;br /&gt;
 * @param id         Client index&lt;br /&gt;
 * @param drop       If true, the game has explicitly dropped the client&lt;br /&gt;
 * @param message    If drop is true, a writable buffer containing the disconnect info message&lt;br /&gt;
 * @param maxlen     Maximum size of buffer&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
forward client_disconnected(id, bool:drop, message[], maxlen);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|client_remove|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=client_remove|header=Called when a client entity has been removed from the server.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Called when a client entity has been removed from the server.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This fires after the client_disconnected() forward, when the player entity has been&lt;br /&gt;
 *       removed (e.g. is_user_connected(id) will return false).&lt;br /&gt;
 *&lt;br /&gt;
 * @param id         Client index&lt;br /&gt;
 * @param drop       If true, the game has explicitly dropped the client&lt;br /&gt;
 * @param message    If drop is true, contains the disconnect info message&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
forward client_remove(id, bool:drop, const message[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' New Natives &amp;amp; Stocks '''&lt;br /&gt;
&lt;br /&gt;
For the sake of better understanding and readability, {{tt|find_player}} and {{tt|get_players}} have now their counterparts which use the flags {{hidden|id=find-get-players|labelonly=yes}} as name constants instead of letter. It is encouraged to use them instead.&lt;br /&gt;
&lt;br /&gt;
{{hidden|id=find-get-players|contentonly=yes|content=&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * FindPlayerFlags constants for find_player_ex()&lt;br /&gt;
 */&lt;br /&gt;
enum FindPlayerFlags (&amp;lt;&amp;lt;= 1)&lt;br /&gt;
{&lt;br /&gt;
	FindPlayer_None = 0,           // None&lt;br /&gt;
	FindPlayer_MatchName = 1,      // Match with name&lt;br /&gt;
	FindPlayer_MatchNameSubstring, // Match with name substring&lt;br /&gt;
	FindPlayer_MatchAuthId,        // Match with authid&lt;br /&gt;
	FindPlayer_MatchIP,            // Match with ip&lt;br /&gt;
	FindPlayer_MatchTeam,          // Match with team name&lt;br /&gt;
	FindPlayer_ExcludeDead,        // Do not include dead clients&lt;br /&gt;
	FindPlayer_ExcludeAlive,       // Do not include alive clients&lt;br /&gt;
	FindPlayer_ExcludeBots,        // Do not include bots&lt;br /&gt;
	FindPlayer_ExcludeHuman,       // Do not include human clients&lt;br /&gt;
	FindPlayer_LastMatched,        // Return last matched client instead of the first&lt;br /&gt;
	FindPlayer_MatchUserId,        // Match with userid&lt;br /&gt;
	FindPlayer_CaseInsensitive,    // Match case insensitively&lt;br /&gt;
	FindPlayer_IncludeConnecting   // Include connecting clients&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! Native &amp;amp; Stock&lt;br /&gt;
 ! Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|find_player_ex|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=find_player_ex|header=Finds a player given a filter.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Find a player given a filter.&lt;br /&gt;
 *&lt;br /&gt;
 * @note If matching by userid, do not also specify FindPlayer_MatchName, FindPlayer_MatchNameSubstring&lt;br /&gt;
 *       or FindPlayer_MatchAuthId, or the function may not return a correct result.&lt;br /&gt;
 *&lt;br /&gt;
 * @param flags     Filtering flags (enum FindPlayerFlags); valid flags are:&lt;br /&gt;
 *                    FindPlayer_MatchName - match with name&lt;br /&gt;
 *                    FindPlayer_MatchNameSubstring - match with name substring&lt;br /&gt;
 *                    FindPlayer_MatchAuthId - match with authid&lt;br /&gt;
 *                    FindPlayer_MatchIP - match with ip&lt;br /&gt;
 *                    FindPlayer_MatchTeam - match with team name&lt;br /&gt;
 *                    FindPlayer_ExcludeDead - do not include dead clients&lt;br /&gt;
 *                    FindPlayer_ExcludeAlive - do not include alive clients&lt;br /&gt;
 *                    FindPlayer_ExcludeBots - do not include bots&lt;br /&gt;
 *                    FindPlayer_ExcludeHuman - do not include human clients&lt;br /&gt;
 *                    FindPlayer_LastMatched - return last matched client instead of the first&lt;br /&gt;
 *                    FindPlayer_MatchUserId - match with userid&lt;br /&gt;
 *                    FindPlayer_CaseInsensitive - match case insensitively&lt;br /&gt;
 *                    FindPlayer_IncludeConnecting - include connecting clients&lt;br /&gt;
 * @param ...       String to match against (integer if FindPlayer_MatchUserId is specified)&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Client index, or 0 if no client was found&lt;br /&gt;
 */&lt;br /&gt;
native find_player_ex(FindPlayerFlags:flags, ...);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_players_ex|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_players_ex|header=Stores a filtered list of client indexes to an array.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Stores a filtered list of client indexes to an array.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Example retrieving all alive CTs:&lt;br /&gt;
 *       get_players_ex(players, num, GetPlayers_ExcludeDead | GetPlayers_MatchTeam, &amp;quot;CT&amp;quot;)&lt;br /&gt;
 *&lt;br /&gt;
 * @param players   Array to store indexes to&lt;br /&gt;
 * @param num       Variable to store number of indexes to&lt;br /&gt;
 * @param flags     Optional filtering flags (enum GetPlayersFlags); valid flags are:&lt;br /&gt;
 *                    GetPlayers_None - No filter (Default)&lt;br /&gt;
 *                    GetPlayers_ExcludeDead - do not include dead clients&lt;br /&gt;
 *                    GetPlayers_ExcludeAlive - do not include alive clients&lt;br /&gt;
 *                    GetPlayers_ExcludeBots - do not include bots&lt;br /&gt;
 *                    GetPlayers_ExcludeHuman - do not include human clients&lt;br /&gt;
 *                    GetPlayers_MatchTeam - match with team&lt;br /&gt;
 *                    GetPlayers_MatchNameSubstring - match with part of name&lt;br /&gt;
 *                    GetPlayers_CaseInsensitive - match case insensitive&lt;br /&gt;
 *                    GetPlayers_ExcludeHLTV - do not include HLTV proxies&lt;br /&gt;
 *                    GetPlayers_IncludeConnecting - include connecting clients&lt;br /&gt;
 * @param team      String to match against if the &amp;quot;e&amp;quot; or &amp;quot;f&amp;quot; flag is specified&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
stock get_players_ex(players[MAX_PLAYERS], &amp;amp;num, GetPlayersFlags:flags = GetPlayers_None, const team[] = &amp;quot;&amp;quot;)&lt;br /&gt;
{&lt;br /&gt;
    new strFlags[10];&lt;br /&gt;
    get_flags(_:flags, strFlags, charsmax(strFlags));&lt;br /&gt;
    get_players(players, num, strFlags, team);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=cvar_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=cvar_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
findPlayer()&lt;br /&gt;
{&lt;br /&gt;
    new const dead_player = find_player_ex(FindPlayer_MatchName | FindPlayer_ExcludeAlive, &amp;quot;egg&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
getPlayer()&lt;br /&gt;
{&lt;br /&gt;
    new playersList[MAX_PLAYERS], playersCount;&lt;br /&gt;
    get_players_ex(playersList, playersCount, GetPlayers_ExcludeDead | GetPlayers_MatchTeam, &amp;quot;CT&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' New params '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | parameter&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|user_silentkill|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|flag|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=user_silentkill|header=If nonzero, the death will not affect the client's score.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
stock user_silentkill(index, flag = 1)&lt;br /&gt;
{&lt;br /&gt;
    static msgid = 0;&lt;br /&gt;
    new msgblock;&lt;br /&gt;
    if (!msgid)&lt;br /&gt;
    {&lt;br /&gt;
        msgid = get_user_msgid(&amp;quot;DeathMsg&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    msgblock = get_msg_block(msgid);&lt;br /&gt;
    set_msg_block(msgid, BLOCK_ONCE);&lt;br /&gt;
    user_kill(index, flag);&lt;br /&gt;
    set_msg_block(msgid, msgblock);&lt;br /&gt;
&lt;br /&gt;
    return 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Forward&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | parameter&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|client_authorized|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|authid|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=client_authorized|header=Client auth|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
forward client_authorized(id, const authid[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=== Command ===&lt;br /&gt;
&lt;br /&gt;
''' Callback '''&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|amxclient_cmd|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=amxclient_cmd|header=Executes a command from the client without actually sending it to the client's DLL. &amp;lt;br /&amp;gt;Similar to {{tt|engclient_cmd|bgcolor=white}} with the difference this triggers plugin command hooks.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=amxclient_cmd|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Execute a command from the client without actually sending it to the client's&lt;br /&gt;
 * DLL. This triggers plugin command hooks.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This emulates a client command on the server side, and is an excellent&lt;br /&gt;
 *       tool to force a client to do certain actions related to the game.&lt;br /&gt;
 * @note The command has to stand alone in the command parameter, only add&lt;br /&gt;
 *       arguments using the designated parameters.&lt;br /&gt;
 * @note Commands emulated using this function will trigger other plugin's&lt;br /&gt;
 *       command hooks. For an alternative that doesn't, see engclient_cmd()&lt;br /&gt;
 *&lt;br /&gt;
 * @param index         Client index, use 0 to execute from all clients&lt;br /&gt;
 * @param command       Client command to execute on&lt;br /&gt;
 * @param arg1          Optional command arguments&lt;br /&gt;
 * @param arg2          Optional command arguments&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If a single client is specified and the index is not within&lt;br /&gt;
 *                  the range of 1 to MaxClients, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native amxclient_cmd(index, const command[], const arg1[] = &amp;quot;&amp;quot;, const arg2[] = &amp;quot;&amp;quot;);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Arguments conversion'''&lt;br /&gt;
&lt;br /&gt;
Convenient natives to convert directly from a string to an integer or float value.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|read_argv_int|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=read_argv_int|header=Retrieves argument of client command as integer value.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=read_argv_int|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves argument of client command as integer value.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Should only be used inside of the client_command() forward.&lt;br /&gt;
 *&lt;br /&gt;
 * @param id        Argument index starting from 1&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Integer value&lt;br /&gt;
 */&lt;br /&gt;
native read_argv_int(id);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|read_argv_float|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=read_argv_float|header=Retrieves argument of client command as float value.|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=read_argv_float|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves argument of client command as float value.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Should only be used inside of the client_command() forward.&lt;br /&gt;
 *&lt;br /&gt;
 * @param id        Argument index starting from 1&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Float value&lt;br /&gt;
 */&lt;br /&gt;
native Float:read_argv_float(id);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=read_argv_int-ex|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=read_argv_int-ex|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    register_clcmd(&amp;quot;set_level&amp;quot;, &amp;quot;@OnSetLevel&amp;quot;, .info = &amp;quot;&amp;lt;value&amp;gt; - Sets a custom level&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@OnSetLevel(const client, const command_level, const command_id)&lt;br /&gt;
{&lt;br /&gt;
    new const value = read_argv_int(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' Translatable description '''&lt;br /&gt;
&lt;br /&gt;
In order to encourage the translations of command's description, a new parameter is available.&amp;lt;br /&amp;gt;&lt;br /&gt;
This is useful for use with the {{tt|amx_help}} client command for example.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | parameter&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|register_clcmd|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|register_concmd|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|register_srvcmd|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|info_ml|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=register_cmd|header=If true, the parameter {{tt|info|bgcolor=white}} will be looked up as multilingual key.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Registers a callback to be called when the client executes a command from the&lt;br /&gt;
 * console.&lt;br /&gt;
 *&lt;br /&gt;
 * @note For a list of possible access flags, see the ADMIN_* constants in&lt;br /&gt;
 *       amxconst.inc&lt;br /&gt;
 * @note Opting in to FlagManager enables the admin privileges to be overwritten&lt;br /&gt;
 *       by the end user via the cmdaccess.ini config file.&lt;br /&gt;
 * @note Automatic detection for FlagManager will only include a command if it&lt;br /&gt;
 *       has required privileges (flags is not -1) and it is not a command&lt;br /&gt;
 *       starting with &amp;quot;say&amp;quot;.&lt;br /&gt;
 *&lt;br /&gt;
 * @param client_cmd    Command to register&lt;br /&gt;
 * @param function      Callback function&lt;br /&gt;
 * @param flags         Admin privilege flags required&lt;br /&gt;
 * @param info          Command description&lt;br /&gt;
 * @param FlagManager   0 opts out of flag manager, 1 opts in, -1 selects&lt;br /&gt;
 *                      automatically&lt;br /&gt;
 * @param info_ml       If true, the parameter &amp;quot;info&amp;quot; will be looked up as multilingual key&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Command id, 0 on failure&lt;br /&gt;
 * @error               If an invalid callback function is specified, an error&lt;br /&gt;
 *                      will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native register_clcmd(const client_cmd[], const function[], flags = -1, const info[] = &amp;quot;&amp;quot;, FlagManager = -1, bool:info_ml = false);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Registers a callback to be called when the client or server executes a&lt;br /&gt;
 * command from the console.&lt;br /&gt;
 *&lt;br /&gt;
 * @note For a list of possible access flags, see the ADMIN_* constants in&lt;br /&gt;
 *       amxconst.inc&lt;br /&gt;
 * @note Opting in to FlagManager enables the admin privileges to be overwritten&lt;br /&gt;
 *       by the end user via the cmdaccess.ini config file.&lt;br /&gt;
 * @note Automatic detection for FlagManager will only include a command if it&lt;br /&gt;
 *       has required privileges (flags is not -1) and it is not a command&lt;br /&gt;
 *       starting with &amp;quot;say&amp;quot;.&lt;br /&gt;
 *&lt;br /&gt;
 * @param client_cmd    Command to register&lt;br /&gt;
 * @param function      Callback function&lt;br /&gt;
 * @param flags         Admin privilege flags required&lt;br /&gt;
 * @param info          Command description&lt;br /&gt;
 * @param FlagManager   0 opts out of flag manager, 1 opts in, -1 selects&lt;br /&gt;
 *                      automatically&lt;br /&gt;
 * @param info_ml       If true, the parameter &amp;quot;info&amp;quot; will be looked up as multilingual key&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Command id, 0 on failure&lt;br /&gt;
 * @error               If an invalid callback function is specified, an error&lt;br /&gt;
 *                      will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native register_concmd(const cmd[], const function[], flags = -1, const info[] = &amp;quot;&amp;quot;, FlagManager = -1, bool:info_ml = false);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Registers a callback to be called when the server executes a command from the&lt;br /&gt;
 * console.&lt;br /&gt;
 *&lt;br /&gt;
 * @note For a list of possible access flags, see the ADMIN_* constants in&lt;br /&gt;
 *       amxconst.inc&lt;br /&gt;
 *&lt;br /&gt;
 * @param client_cmd    Command to register&lt;br /&gt;
 * @param function      Callback function&lt;br /&gt;
 * @param flags         Admin privilege flags required&lt;br /&gt;
 * @param info          Command description&lt;br /&gt;
 * @param info_ml       If true, the parameter &amp;quot;info&amp;quot; will be looked up as multilingual key&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Command id, 0 on failure&lt;br /&gt;
 * @error               If an invalid callback function is specified, an error&lt;br /&gt;
 *                      will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native register_srvcmd(const server_cmd[], const function[], flags = -1, const info[] = &amp;quot;&amp;quot;, bool:info_ml = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=trans-cmd|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=trans-cmd|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
[en]&lt;br /&gt;
MY_KEY = Hello world!&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    register_clcmd(&amp;quot;my_command&amp;quot;, &amp;quot;OnMyCommand&amp;quot;, ADMIN_CFG, &amp;quot;MY_KEY&amp;quot;, .info_ml = true);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Cvar ===&lt;br /&gt;
&lt;br /&gt;
In order to manage cvars more easily, several new cvar features have been added.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|A cvar managed at least once is now cached internally, for faster lookup, that's it.|opt=full-border}}&lt;br /&gt;
{{alert|info|Note:|The cvar API is now moved to its own {{tt|cvars.inc|bgcolor=none}} include file.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
''' Hooking '''&lt;br /&gt;
&lt;br /&gt;
You can now hook when a cvar value has changed.  This allows plugins to react to cases where other plugins or clients change a cvar's value.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! Native&lt;br /&gt;
 ! Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|hook_cvar_change|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=hook_cvar_change|header=To create a hook|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=hook_cvar_change|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a hook for when a cvar's value is changed.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Changing the cvar value from within this forward can lead to infinite&lt;br /&gt;
 *       recursion and should be avoided.&lt;br /&gt;
 * @note The callback will be called in the following manner:&lt;br /&gt;
 *&lt;br /&gt;
 * public cvar_change_callback(pcvar, const old_value[], const new_value[])&lt;br /&gt;
 *&lt;br /&gt;
 *   pcvar         - Pointer to cvar that was changed&lt;br /&gt;
 *   old_value     - Buffer containing the previous value of the cvar&lt;br /&gt;
 *   new_value     - Buffer containing the new value of the cvar&lt;br /&gt;
 *&lt;br /&gt;
 * The return value is ignored&lt;br /&gt;
 *&lt;br /&gt;
 * @param pcvar     Pointer to cvar&lt;br /&gt;
 * @param callback  Name of callback function&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Callback handle that can be used with&lt;br /&gt;
 *                  [disable|enable]_cvar_hook&lt;br /&gt;
 * @error           If an invalid cvar pointer or callback function is provided,&lt;br /&gt;
 *                  an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native cvarhook:hook_cvar_change(pcvar, const callback[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|disable_cvar_hook|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=disable_cvar_hook|header=To disable a hook|labelpos=left|labelonly=yes}}&lt;br /&gt;
{{hidden|id=disable_cvar_hook|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Disables a cvar hook, stopping it from being called.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Use the handle returned by hook_cvar_change as the parameter here.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Forward to disable&lt;br /&gt;
 * @error           If an invalid hook handle is provided, an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native disable_cvar_hook(cvarhook:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|enable_cvar_hook|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=enable_cvar_hook|header=To enable a hook|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Enables a cvar hook, restoring it to being called.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Use the handle returned by hook_cvar_change as the parameter here.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Forward to enable&lt;br /&gt;
 * @error           If an invalid hook handle is provided, an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native enable_cvar_hook(cvarhook:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=cvar_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=cvar_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
new cvarhook:CvarHandle;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    CvarHandle = hook_cvar_change(get_cvar_pointer(&amp;quot;mp_timelimit&amp;quot;), &amp;quot;@OnTimelimitChange&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    register_concmd(&amp;quot;enable_hook&amp;quot; , &amp;quot;@OnConsoleCommand_EnableHook&amp;quot;);&lt;br /&gt;
    register_concmd(&amp;quot;disable_hook&amp;quot;, &amp;quot;@OnConsoleCommand_DisableHook&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@OnTimelimitChange(const pointer, const old_value[], const new_value[])&lt;br /&gt;
{&lt;br /&gt;
    server_print(&amp;quot;mp_timelimit: %s -&amp;gt; %s&amp;quot;, old_value, new_value);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@OnClientCommand_EnableHook()&lt;br /&gt;
{&lt;br /&gt;
    enable_cvar_hook(CvarHandle);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@OnClientCommand_DisableHook()&lt;br /&gt;
{&lt;br /&gt;
    disable_cvar_hook(CvarHandle);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' Binding '''&lt;br /&gt;
&lt;br /&gt;
There are situations where you don't need to hook/manage a cvar value and you would wish to not deal with cvar pointers. &amp;lt;br /&amp;gt;&lt;br /&gt;
You can now bind a cvar's value to a global variable. This means that variable value will be always up to date.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 ! Native&lt;br /&gt;
 ! Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|bind_pcvar_num|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=bind_pcvar_num|header=To bind an integer|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Binds a cvar's integer value to a global variable. The variable will then&lt;br /&gt;
 * always contain the current cvar value as it is automatically kept up to date.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The variable *has* to be a global or a static variable. Local variables&lt;br /&gt;
 *       created within functions can not be used for technical reasons.&lt;br /&gt;
 * @note Variables can not be bound to multiple cvars.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pcvar     Pointer to cvar&lt;br /&gt;
 * @param var       Global variable to keep updated&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid cvar pointer or variable is provided, an error&lt;br /&gt;
 *                  will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bind_pcvar_num(pcvar, &amp;amp;any:var);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|bind_pcvar_float|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=bind_pcvar_float|header=To bind a float|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Binds a cvar's float value to a global variable. The variable will then&lt;br /&gt;
 * always contain the current cvar value as it is automatically kept up to date.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The variable *has* to be a global or a static variable. Local variables&lt;br /&gt;
 *       created within functions can not be used for technical reasons.&lt;br /&gt;
 * @note Variables can not be bound to multiple cvars.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pcvar     Pointer to cvar&lt;br /&gt;
 * @param var       Global variable to keep updated&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid cvar pointer or variable is provided, an error&lt;br /&gt;
 *                  will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bind_pcvar_float(pcvar, &amp;amp;Float:var);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|bind_pcvar_string|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=bind_pcvar_string|header=To bind a string|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Binds a cvar's string value to a global array. The array will then&lt;br /&gt;
 * always contain the current cvar value as it is automatically kept up to date.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The array *has* to be a global or a static array. Local arrays&lt;br /&gt;
 *       created within functions can not be used for technical reasons.&lt;br /&gt;
 * @note Arrays can not be bound to multiple cvars.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pcvar     Pointer to cvar&lt;br /&gt;
 * @param var       Global array to keep updated&lt;br /&gt;
 * @param varlen    Maximum length of string array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid cvar pointer or variable is provided, an error&lt;br /&gt;
 *                  will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bind_pcvar_string(pcvar, any:var[], varlen);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=bind_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=bind_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
new CvarTimelimit;&lt;br /&gt;
new Float:CvarBuyTime;&lt;br /&gt;
new CvarSomething[32];&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    bind_pcvar_num(get_cvar_pointer(&amp;quot;mp_timelimit&amp;quot;), CvarTimelimit);&lt;br /&gt;
    bind_pcvar_float(get_cvar_pointer(&amp;quot;mp_buytime&amp;quot;), CvarBuyTime);&lt;br /&gt;
    bind_pcvar_string(register_cvar(&amp;quot;amx_something&amp;quot;, &amp;quot;something&amp;quot;), CvarSomething, charsmax(CvarSomething));&lt;br /&gt;
&lt;br /&gt;
    server_print(&amp;quot;mp_timelimit  current value: %d&amp;quot;, CvarTimelimit);&lt;br /&gt;
    server_print(&amp;quot;mp_buytime    current value: %f&amp;quot;, CvarBuyTime);&lt;br /&gt;
    server_print(&amp;quot;amx_something current value: %s&amp;quot;, CvarSomething);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' Boundary '''&lt;br /&gt;
&lt;br /&gt;
Having a better control over a cvar's value, we can enforce the value to be in a defined boundary.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! Description&lt;br /&gt;
 ! Native&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_pcvar_bounds|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_pcvar_bounds|header=To get a boundary|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves the specified value boundary of a cvar.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pcvar     Pointer to cvar&lt;br /&gt;
 * @param type      Type of boundary to retrieve&lt;br /&gt;
 * @param value     Variable to store the specified boundary to&lt;br /&gt;
 *&lt;br /&gt;
 * @return          True if the cvar has a boundary set, false otherwise&lt;br /&gt;
 * @error           If an invalid cvar pointer or boundary type is provided,&lt;br /&gt;
 *                  an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bool:get_pcvar_bounds(pcvar, CvarBounds:type, &amp;amp;Float:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|set_pcvar_bounds|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=set_pcvar_bounds|header=To set a boundary|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the specified boundary of a cvar.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pcvar     Pointer to cvar&lt;br /&gt;
 * @param type      Type of boundary to set&lt;br /&gt;
 * @param set       If true the cvar boundary will be set, otherwise it will be&lt;br /&gt;
 *                  removed (value is ignored)&lt;br /&gt;
 * @param value     Floating point value to use as the boundary&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid cvar pointer or boundary type is provided, an&lt;br /&gt;
 *                  error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_pcvar_bounds(pcvar, CvarBounds:type, bool:set, Float:value = 0.0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|{{tt|CvarBounds|bgcolor=none}} has the following values:&lt;br /&gt;
* {{tt|CvarBound_Upper}}&lt;br /&gt;
* {{tt|CvarBound_Lower}}|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=bounds_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=bounds_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    new const pointer = register_cvar(&amp;quot;amx_leet&amp;quot;, &amp;quot;1337&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    // Defines min and max value&lt;br /&gt;
    set_pcvar_bounds(pointer, CvarBound_Lower, .set = true, 0.0);&lt;br /&gt;
    set_pcvar_bounds(pointer, CvarBound_Upper, .set = true, 42.0);&lt;br /&gt;
&lt;br /&gt;
    // Current value should be &amp;quot;42&amp;quot;.&lt;br /&gt;
    server_print(&amp;quot;amx_something current value: %f&amp;quot;, get_pcvar_float(pointer));&lt;br /&gt;
&lt;br /&gt;
    // Removes the lower bound.&lt;br /&gt;
    set_pcvar_bounds(pointer, CvarBound_Lower, .set = false);&lt;br /&gt;
&lt;br /&gt;
    new Float:value;&lt;br /&gt;
&lt;br /&gt;
    if (get_pcvar_bounds(pointer, CvarBound_Upper, value))&lt;br /&gt;
    {&lt;br /&gt;
        server_print(&amp;quot;amx_something should have an upper bound: %f&amp;quot;, value);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!get_pcvar_bounds(pointer, CvarBound_Upper, value))&lt;br /&gt;
    {&lt;br /&gt;
        server_print(&amp;quot;amx_something should not have an lower bound);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' Constant '''&lt;br /&gt;
&lt;br /&gt;
A missing {{tt|FCVAR_NOEXTRAWHITEPACE}} flag has been added.&amp;lt;br /&amp;gt;&lt;br /&gt;
It automatically strips trailing/leading white space from the string value.&lt;br /&gt;
&lt;br /&gt;
''' Creating '''&lt;br /&gt;
&lt;br /&gt;
A new {{tt|create_cvar}} {{hidden|id=create_cvar|labelonly=yes}} native has been added, similar to {{tt|register_cvar|bgcolor=none}} but with two new features:&lt;br /&gt;
{{hidden|id=create_cvar|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a new cvar for the engine.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This has the same effect as register_cvar() but provides more options.&lt;br /&gt;
 * @note For a list of possible cvar flags see FCVAR_* constants above.&lt;br /&gt;
 * @note If an already existing cvar is registered it will not be duplicated.&lt;br /&gt;
 *       The default value is only set when the cvar is registered for the very&lt;br /&gt;
 *       first time since the server was started. Cvar bounds are overwritten&lt;br /&gt;
 *       by the create_cvar() call just as if they were re-set using&lt;br /&gt;
 *       set_pcvar_bounds().&lt;br /&gt;
 * @note The returned cvar pointer should be used with the get_pcvar_* and&lt;br /&gt;
 *       set_pcvar_* set of functions.&lt;br /&gt;
 *&lt;br /&gt;
 * @param name          Cvar name&lt;br /&gt;
 * @param string        Default cvar value&lt;br /&gt;
 * @param flags         Optional bitsum of flags specifying cvar behavior&lt;br /&gt;
 * @param description   Optional description of the cvar&lt;br /&gt;
 * @param has_min       Optional boolean that specifies if the cvar has a&lt;br /&gt;
 *                      minimum value&lt;br /&gt;
 * @param min_val       Minimum floating point value&lt;br /&gt;
 * @param has_max       Optional boolean that specifies if the cvar has a&lt;br /&gt;
 *                      maximum value&lt;br /&gt;
 * @param max_val       Maximum floating point value&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Unique cvar pointer&lt;br /&gt;
 * @error               If invalid bounds are provided (min_val &amp;gt; max_val or&lt;br /&gt;
 *                      vice versa), an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native create_cvar(const name[], const string[], flags = FCVAR_NONE, const description[] = &amp;quot;&amp;quot;, bool:has_min = false, Float:min_val = 0.0, bool:has_max = false, Float:max_val = 0.0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | ''Description''&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | Similar to command, you can explain shorlty what does the cvar. The message can be retrieved with {{tt|get_plugins_cvar|bgcolor=white}} and can be read from {{tt|amxx cvars|bgcolor=white}} detailed output. &amp;lt;br /&amp;gt; The description is used with {{tt|AutoExecConfig|bgcolor=white}} for example.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | ''Boudary''&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | You can set directly a boudary, either a minimum value, a maximum value or both.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=creeate_cvar_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=creeate_cvar_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    create_cvar(&amp;quot;amx_something1&amp;quot;, &amp;quot;1&amp;quot;, FCVAR_NONE, &amp;quot;My description here&amp;quot;, true, 1.0, true, 42.0);&lt;br /&gt;
    create_cvar(&amp;quot;amx_something2&amp;quot;, &amp;quot;2&amp;quot;, .description = &amp;quot;My description here&amp;quot;, .has_min = true, min_val = 1.0, .has_max = true, .max_val = 42.0);&lt;br /&gt;
    create_cvar(&amp;quot;amx_something3&amp;quot;, &amp;quot;3&amp;quot;, .has_min = true, min_val = 1.0);&lt;br /&gt;
    create_cvar(&amp;quot;amx_something4&amp;quot;, &amp;quot;4&amp;quot;, .has_max = true, max_val = 42.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' Command '''&lt;br /&gt;
&lt;br /&gt;
The {{tt|amxx cvars}} shows now more informations about a cvar state.&lt;br /&gt;
Here an example of output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Managed cvars:&lt;br /&gt;
       NAME                     VALUE                    PLUGIN             HOOKED   MIN     MAX&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 [  1] amx_mode                 1                        admin.amxx         no       -       -&lt;br /&gt;
 [  2] amx_password_field       _pw                      admin.amxx         no       -       -&lt;br /&gt;
 [  3] amx_default_access       z                        admin.amxx         no       -       -&lt;br /&gt;
 [  4] amx_vote_ratio           0.02                     admin.amxx         no       -       -&lt;br /&gt;
 [  5] amx_something            something                test-hook.amxx     yes      -       -&lt;br /&gt;
 [  6] amx_leet                 42                       test-bounds.amxx   no       0.00    42.00&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can show further details if you specify a cvar or index from the table: {{tt|amxx cvars &amp;lt;index or cvar name&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
amxx cvars 6&lt;br /&gt;
&lt;br /&gt;
Cvar details :&lt;br /&gt;
&lt;br /&gt;
 Cvar name   : amx_leet&lt;br /&gt;
 Value       : 42&lt;br /&gt;
 Def. value  : 1337&lt;br /&gt;
 Description :&lt;br /&gt;
 Flags       : FCVAR_EXTDLL&lt;br /&gt;
&lt;br /&gt;
 STATUS        PLUGIN                     INFOS&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Registered    test-bounds.amxx           -&lt;br /&gt;
 Min value     test-bounds.amxx           0.000000&lt;br /&gt;
 Max value     test-bounds.amxx           42.000000&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''' Others '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_pcvar_bool|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_pcvar_bool|header=Returns an boolean value from a cvar via direct pointer access.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns an boolean value from a cvar via direct pointer access.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pcvar     Pointer to cvar to retrieve value from&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Cvar value, converted to bool&lt;br /&gt;
 * @error           If an invalid cvar pointer is provided, an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bool:get_pcvar_bool(pcvar);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|set_pcvar_bool|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=set_pcvar_bool|header=Sets a boolean value to a cvar via direct pointer access.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a boolean value to a cvar via direct pointer access.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pcvar     Pointer to cvar to set value of&lt;br /&gt;
 * @param num       Value to set cvar to&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid cvar pointer is provided, an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_pcvar_bool(pcvar, bool:num);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=== CellArray ===&lt;br /&gt;
&lt;br /&gt;
A bunch of natives have been added to complete the existing API. You are now able to:&lt;br /&gt;
* Clone an array&lt;br /&gt;
* Resize an array&lt;br /&gt;
* Find a value or string inside an array&lt;br /&gt;
* Control more precisely how the data is retrieved/saved&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|Arrays are heterogeneous. This means you can save different data types into a list. &amp;lt;br/&amp;gt;A good example is the Stack Structure API which is actually based on Array (internal library, that's it).|opt=full-border}}&lt;br /&gt;
{{alert|info|Note:|Initially the {{tt|reserved|bgcolor=none}} parameter in {{tt|ArrayCreate|bgcolor=none}} was intended to create blank entries that would immediately be usable with {{tt|ArrayGet/Set|bgcolor=white}} functions. &amp;lt;br /&amp;gt; This functionality was never working as intended, and can now be achieved using {{tt|ArrayResize|bgcolor=none}}.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Cloning '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ArrayClone|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=ArrayClone|header=Clones an array.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Clones an array, returning a new handle with the same size and data.&lt;br /&gt;
 *&lt;br /&gt;
 * @param which         Array handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Handle to the cloned array on success, 0 otherwise&lt;br /&gt;
 * @error               If an invalid handle is provided an error will be&lt;br /&gt;
 *                      thrown.&lt;br /&gt;
 */&lt;br /&gt;
native Array:ArrayClone(Array:which);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=array_cloning_ex|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=array_cloning_ex|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    new Array:list = ArrayCreate();&lt;br /&gt;
&lt;br /&gt;
    ArrayPushCell(list, 1);&lt;br /&gt;
    ArrayPushCell(list, 2);&lt;br /&gt;
    ArrayPushCell(list, 3);&lt;br /&gt;
&lt;br /&gt;
    new Array:clone_list = ArrayClone(list);&lt;br /&gt;
&lt;br /&gt;
    //&lt;br /&gt;
&lt;br /&gt;
    ArrayDestroy(clone_list);&lt;br /&gt;
    ArrayDestroy(list);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' Resizing '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ArrayResize|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=ArrayResize|header=Resizes an array.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Resizes an array.&lt;br /&gt;
 *&lt;br /&gt;
 * @note If the size is smaller than the current array size the array is&lt;br /&gt;
 *       truncated and data lost.&lt;br /&gt;
 *&lt;br /&gt;
 * @param which         Array handle&lt;br /&gt;
 * @param newsize       New size&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error               If an invalid handle is provided or the resizing&lt;br /&gt;
 *                      operation runs out of memory, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bool:ArrayResize(Array:which, newsize);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=array_resize_ex|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=array_resize_ex|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    new Array:list = ArrayCreate(.cellsize = 1, .reserved = 3);&lt;br /&gt;
&lt;br /&gt;
    ArrayPushCell(list, 1);&lt;br /&gt;
    ArrayPushCell(list, 2);&lt;br /&gt;
    ArrayPushCell(list, 3);&lt;br /&gt;
&lt;br /&gt;
    new const count = ArraySize(list);&lt;br /&gt;
&lt;br /&gt;
    ArrayResize( list, count + 1); // Add a new allocated and available slot&lt;br /&gt;
    ArraySetCell(list, count, 4);  // Notice you can use directly ArraySet&lt;br /&gt;
&lt;br /&gt;
    server_print(&amp;quot;Last value = %d, Cloned list size = %d&amp;quot;, ArrayGetCell(list, count), ArraySize(list)); // Should be 4.&lt;br /&gt;
&lt;br /&gt;
    ArrayDestroy(list);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' Finding a value '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ArrayFindValue|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=ArrayFindValue|header=Searches through the array and returns the index of the first occurence of the specified value.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Searches through the array and returns the index of the first occurence of&lt;br /&gt;
 * the specified value.&lt;br /&gt;
 *&lt;br /&gt;
 * @param which         Array handle&lt;br /&gt;
 * @param item          Value to search for&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Array index on success, -1 if the value can't be found&lt;br /&gt;
 * @error               If an invalid handle is provided an error will be&lt;br /&gt;
 *                      thrown.&lt;br /&gt;
 */&lt;br /&gt;
native ArrayFindValue(Array:which, any:item);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ArrayFindString|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=ArrayFindString|header= Searches through the array and returns the index of the first occurence of the specified string.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Searches through the array and returns the index of the first occurence of&lt;br /&gt;
 * the specified string.&lt;br /&gt;
 *&lt;br /&gt;
 * @param which         Array handle&lt;br /&gt;
 * @param item          String to search for&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Array index on success, -1 if the string can't be found&lt;br /&gt;
 * @error               Invalid handle.&lt;br /&gt;
 */&lt;br /&gt;
native ArrayFindString(Array:which, const item[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=array_find_ex|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=array_find_ex|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    new Array:list = ArrayCreate(.cellsize = 16);&lt;br /&gt;
&lt;br /&gt;
    ArrayPushString(list, &amp;quot;something&amp;quot;);&lt;br /&gt;
    ArrayPushString(list, &amp;quot;is&amp;quot;);&lt;br /&gt;
    ArrayPushCell(list, 42);&lt;br /&gt;
    ArrayPushString(list, &amp;quot;hidden&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    new index = ArrayFindValue(list, 42);&lt;br /&gt;
    server_print(&amp;quot;Cell index = %d&amp;quot;, index); // should be 2&lt;br /&gt;
&lt;br /&gt;
    index = ArrayFindString(list, &amp;quot;hidden&amp;quot;);&lt;br /&gt;
    server_print(&amp;quot;String index = %d&amp;quot;, index); // should be 3&lt;br /&gt;
&lt;br /&gt;
    ArrayDestroy(list);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Sorting '''&lt;br /&gt;
&lt;br /&gt;
Along two new {{tt|ArraySort}} and {{tt|SortADTArray}} natives, there is also a new {{tt|Sort_Random}} method.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ArraySortEx|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=ArraySortEx|header=A faster version of {{tt|ArraySort|bgcolor=none}}.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * A faster version of ArraySort, the sorting algorithm then uses the custom&lt;br /&gt;
 * comparison function to sort the data.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The advantage of this function is that the data of the elements being&lt;br /&gt;
 *       compared is directly passed to the function, instead of the item&lt;br /&gt;
 *       indexes that are passed by ArraySort. This removes the need for calling&lt;br /&gt;
 *       ArrayGet[Cell|String|Array] every time before being able to compare the&lt;br /&gt;
 *       elements.&lt;br /&gt;
 *&lt;br /&gt;
 * @note For Arrays with a cellsize of 1 (used for storing integers and floats),&lt;br /&gt;
 *       the function is called in the following manner:&lt;br /&gt;
 *&lt;br /&gt;
 * public MySortFunc(Array:array, elem1, elem2, const data[], data_size)&lt;br /&gt;
 *&lt;br /&gt;
 *   array           - Array handle in its current un-sorted state&lt;br /&gt;
 *   elem1, elem2    - Current element pair being compared&lt;br /&gt;
 *   data[]          - Extra data array passed to the sort func&lt;br /&gt;
 *   data_size       - Size of extra data&lt;br /&gt;
 *&lt;br /&gt;
 * @note For Arrays with a cellsize larger than 1 (used for storing arrays and&lt;br /&gt;
 *       strings), the function is called in the following manner:&lt;br /&gt;
 *&lt;br /&gt;
 * public MySortFunc(Array:array, elem1[], elem2[], const data[], data_size)&lt;br /&gt;
 *&lt;br /&gt;
 *   array               - Array handle in its current un-sorted state&lt;br /&gt;
 *   elem1[], elem2[]    - Current element pair being compared&lt;br /&gt;
 *   data[]              - Extra data array passed to the sort func&lt;br /&gt;
 *   data_size           - Size of extra data&lt;br /&gt;
 *&lt;br /&gt;
 *&lt;br /&gt;
 * @note The comparison function should return:&lt;br /&gt;
 *         -1 if elem1 should go before elem2&lt;br /&gt;
 *          0 if elem1 and elem2 are equal&lt;br /&gt;
 *          1 if elem1 should go after elem2&lt;br /&gt;
 *&lt;br /&gt;
 * @note All parameters after item2 are optional and do not need to be specified&lt;br /&gt;
 *       and used.&lt;br /&gt;
 * @note Unlike the sorting.inc version, the array passed to the callback is not&lt;br /&gt;
 *       in mid-sorted state.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array         Array handle&lt;br /&gt;
 * @param comparefunc   Callback function used for comparison&lt;br /&gt;
 * @param data          Extra data that is passed through to the callback&lt;br /&gt;
 * @param data_size     Size of extra data&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error               If an invalid handle or an invalid callback is provided&lt;br /&gt;
 *                      an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native ArraySortEx(Array:array, const comparefunc[], data[]=&amp;quot;&amp;quot;, data_size=0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SortADTArray|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SortADTArray|header=To sort directly with a sort method.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sort an ADT Array. Specify the type as Integer, Float, or String.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array			Array Handle to sort&lt;br /&gt;
 * @param order			Sort order to use, same as other sorts.&lt;br /&gt;
 * @param type			Data type stored in the ADT Array&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native SortADTArray(Array:array, SortMethod:order, SortType:type);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
{{alert|info|Note:|{{tt|SortMethod|bgcolor=none}} has the following values:&lt;br /&gt;
* {{tt|Sort_Ascending}}&lt;br /&gt;
* {{tt|Sort_Descending}}&lt;br /&gt;
* {{tt|Sort_Random}}|opt=full-border}}&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' New params '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | parameter&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ArrayGetArray|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|ArraySetArray|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|ArrayPushArray|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|size|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=new_size_param|header=Controls the number of elements to use.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param size          If not set, assumes the buffer size is equal to the&lt;br /&gt;
 *                      cellsize. Otherwise, the specified size is used.&lt;br /&gt;
 */&lt;br /&gt;
native ArrayGetArray(Array:which, item, any:output[], size = -1);&lt;br /&gt;
native ArraySetArray(Array:which, item, const any:input[], size =-1);&lt;br /&gt;
native ArrayPushArray(Array:which, const any:input[], size = -1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|ArrayGetCell|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|ArraySetCell|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|achar|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|block|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=new_blockaschar_param|header=Specifies which block and retrieves a value as byte.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param block         If the array has a cellsize &amp;gt;1 this optionally specifies&lt;br /&gt;
 *                      which block to read from&lt;br /&gt;
 * @param asChar        If true reads the value as a byte instead of a cell&lt;br /&gt;
 */&lt;br /&gt;
native any:ArrayGetCell(Array:which, item, block = 0, bool:asChar = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=== CellTrie ===&lt;br /&gt;
&lt;br /&gt;
The word &amp;quot;''Trie''&amp;quot; in this API is historical. As of AMX Mod X 1.9, tries have been internally replaced with hash tables, which have {{tt|O(1)|bgcolor=none}} insertion time instead of {{tt|O(n)|bgcolor=none}}. &amp;lt;br /&amp;gt;&lt;br /&gt;
As consequence, the API has been completed and you can now:&lt;br /&gt;
* Get a trie size&lt;br /&gt;
* Control more precisely the data on insertion/retrieval&lt;br /&gt;
* Iterate over a trie&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|Tries are heterogeneous. This means you can save different data types into a list.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
''' Getting size '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieGetSize|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieGetSize|header=Returns the number of entries in a hash map.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns the number of entries in a hash map.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Map handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of elements in the hash map&lt;br /&gt;
 * @error           If an invalid handle is provided an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native TrieGetSize(Trie:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Iterating '''&lt;br /&gt;
&lt;br /&gt;
There are two ways to iterate over a trie:&lt;br /&gt;
* ''Snapshots''&lt;br /&gt;
: As the name suggested, it will duplicate the whole set of keys (only) into a separate list. Any changes to the original list will not affect the snapshot. &amp;lt;br /&amp;gt; It's an expensive operation, but can be stored.&lt;br /&gt;
&lt;br /&gt;
:{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieSnapshotCreate|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieSnapshotCreate|header=Creates a snapshot of all keys in a hash map.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a snapshot of all keys in a hash map. If the map is changed&lt;br /&gt;
 * afterwards,  the changes are not reflected in the snapshot.&lt;br /&gt;
 * Keys are not sorted.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Map handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          New map snapshot handle, which must be freed via&lt;br /&gt;
 *                  TrieSnapshotDestroy()&lt;br /&gt;
 * @error           If an invalid handle is provided an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native Snapshot:TrieSnapshotCreate(Trie:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieSnapshotLength|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieSnapshotLength|header=Returns the number of keys in a map snapshot.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns the number of keys in a map snapshot. Note that this may be&lt;br /&gt;
 * different from the size of the map, since the map can change after the&lt;br /&gt;
 * snapshot of its keys was taken.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Map snapshot handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of keys&lt;br /&gt;
 * @error           If an invalid handle is provided an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native TrieSnapshotLength(Snapshot:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieSnapshotGetKey|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieSnapshotGetKey|header= Retrieves the key string of a given key in a map snapshot.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves the key string of a given key in a map snapshot.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Map snapshot handle&lt;br /&gt;
 * @param index     Key index (starting from 0)&lt;br /&gt;
 * @param buffer    String buffer&lt;br /&gt;
 * @param maxlength Maximum buffer length&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of bytes written to the buffer&lt;br /&gt;
 * @error           If an invalid handle is provided an error will be&lt;br /&gt;
 *                  thrown. or index out of range&lt;br /&gt;
 */&lt;br /&gt;
native TrieSnapshotGetKey(Snapshot:handle, index, buffer[], maxlength);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieSnapshotDestroy|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieSnapshotDestroy|header= Retrieves the key string of a given key in a map snapshot.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Destroys a map snapshot and frees its memory.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The function automatically sets the variable passed to it to 0 to aid&lt;br /&gt;
 *       in preventing accidental usage after destroy.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Map snapshot handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return          1 on success, 0 if an invalid handle was passed in&lt;br /&gt;
 */&lt;br /&gt;
native TrieSnapshotDestroy(&amp;amp;Snapshot:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
:{{alert|info|Note:|The keys are not sorted.|opt=full-border}}&lt;br /&gt;
:{{alert|success|Example:|{{hidden|id=trie_example_snap|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=trie_example_snap|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    new Trie:list = TrieCreate();&lt;br /&gt;
    {&lt;br /&gt;
        TrieSetString(list, &amp;quot;adventure&amp;quot;, &amp;quot;time!&amp;quot;);&lt;br /&gt;
        TrieSetString(list, &amp;quot;butterflies&amp;quot;, &amp;quot;bees&amp;quot;);&lt;br /&gt;
        TrieSetString(list, &amp;quot;egg&amp;quot;, &amp;quot;egg&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    new Snapshot:keys = TrieSnapshotCreate(list);&lt;br /&gt;
    {&lt;br /&gt;
        new const length = TrieSnapshotLength(keys);&lt;br /&gt;
        new key[32];&lt;br /&gt;
&lt;br /&gt;
        for (new const i = 0; i &amp;lt; length; ++i)&lt;br /&gt;
        {&lt;br /&gt;
            TrieSnapshotGetKey(keys, i, buffer, charmax(buffer));&lt;br /&gt;
            server_print(&amp;quot;buffer = %s&amp;quot;, buffer);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    TrieSnapshotDestroy(keys);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* ''Iterator''&lt;br /&gt;
: A contrario, Iterators are designed to be short-lived and not stored, and creating them is very cheap. &amp;lt;br /&amp;gt; Reading data from an iterator is just as fast as reading directly from the map.&amp;lt;br /&amp;gt; This is useful if you just need to iterate (or eventually updating values of existing keys, which is allowed)&lt;br /&gt;
&lt;br /&gt;
:{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieIterCreate|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieIterCreate|header=Creates an iterator for a map.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates an iterator for a map. It provides iterative read-only access to the&lt;br /&gt;
 * maps contents.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Removing or adding keys to the underlying map will invalidate all its&lt;br /&gt;
 *       iterators. Updating values of existing keys is allowed and the changes&lt;br /&gt;
 *       will be immediately reflected in the iterator.&lt;br /&gt;
 * @note Iterators are designed to be short-lived and not stored, and creating&lt;br /&gt;
 *       them is very cheap. Reading data from an iterator is just as fast as&lt;br /&gt;
 *       reading directly from the map.&lt;br /&gt;
 * @note Just like in snapshots the keys are not sorted.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              New iterator handle, which must be freed via TrieIterDestroy().&lt;br /&gt;
 * @error               Invalid Handle&lt;br /&gt;
 */&lt;br /&gt;
native TrieIter:TrieIterCreate(Trie:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieIterEnded|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieIterEnded|header= Returns if the iterator has reached its end and no more data can be read.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns if the iterator has reached its end and no more data can be read.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Iterator handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True if iterator has reached the end, false otherwise&lt;br /&gt;
 * @error               Invalid Handle&lt;br /&gt;
 *                      Iterator has been closed (underlying map destroyed)&lt;br /&gt;
 *                      Iterator is outdated&lt;br /&gt;
 */&lt;br /&gt;
native bool:TrieIterEnded(TrieIter:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieIterNext|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieIterNext|header=Advances the iterator to the next key/value pair if one is available.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Advances the iterator to the next key/value pair if one is available.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Iterator handle&lt;br /&gt;
 *&lt;br /&gt;
 * @error               Invalid Handle&lt;br /&gt;
 *                      Iterator has been closed (underlying map destroyed)&lt;br /&gt;
 *                      Iterator is outdated&lt;br /&gt;
 */&lt;br /&gt;
native TrieIterNext(TrieIter:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieIterGetKey|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieIterGetKey|header=Retrieves the key the iterator currently points to.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves the key the iterator currently points to.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Iterator handle.&lt;br /&gt;
 * @param key           Buffer to store the current key in.&lt;br /&gt;
 * @param outputsize    Maximum size of string buffer.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Nnumber of bytes written to the buffer&lt;br /&gt;
 * @error               Invalid handle&lt;br /&gt;
 *                      Iterator has been closed (underlying map destroyed)&lt;br /&gt;
 *                      Iterator is outdated&lt;br /&gt;
 */&lt;br /&gt;
native TrieIterGetKey(TrieIter:handle, key[], outputsize);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieIterGetSize|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieIterGetSize|header=Retrieves the number of elements in the underlying map.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves the number of elements in the underlying map.&lt;br /&gt;
 *&lt;br /&gt;
 * @note When used on a valid iterator this is exactly the same as calling TrieGetSize on the map directly.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Iterator handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Number of elements in the map&lt;br /&gt;
 * @error               Invalid handle&lt;br /&gt;
 *                      Iterator has been closed (underlying map destroyed)&lt;br /&gt;
 *                      Iterator is outdated&lt;br /&gt;
 */&lt;br /&gt;
native TrieIterGetSize(TrieIter:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieIterGetCell|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieIterGetCell|header=Retrieves a value at the current position of the iterator.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves a value at the current position of the iterator.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Iterator handle&lt;br /&gt;
 * @param value         Variable to store value in&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false if the iterator is empty or the current&lt;br /&gt;
 *                      value is an array or a string.&lt;br /&gt;
 * @error               Invalid handle&lt;br /&gt;
 *                      Iterator has been closed (underlying map destroyed)&lt;br /&gt;
 *                      Iterator is outdated&lt;br /&gt;
 */&lt;br /&gt;
native bool:TrieIterGetCell(TrieIter:handle, &amp;amp;any:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieIterGetString|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieIterGetString|header=Retrieves a string at the current position of the iterator.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves a string at the current position of the iterator.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Iterator handle&lt;br /&gt;
 * @param buffer        Buffer to store the string in&lt;br /&gt;
 * @param outputsize    Maximum size of string buffer&lt;br /&gt;
 * @param size          Optional parameter to store the number of bytes written to the buffer.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false if the iterator is empty or the current value&lt;br /&gt;
 *                      is not a string.&lt;br /&gt;
 * @error               Invalid handle&lt;br /&gt;
 *                      Invalid buffer size&lt;br /&gt;
 *                      Iterator has been closed (underlying map destroyed)&lt;br /&gt;
 *                      Iterator is outdated&lt;br /&gt;
 */&lt;br /&gt;
native bool:TrieIterGetString(TrieIter:handle, buffer[], outputsize, &amp;amp;size = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieIterGetArray|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieIterGetArray|header=Retrieves an array at the current position of the iterator.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves an array at the current position of the iterator.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle        Iterator handle&lt;br /&gt;
 * @param buffer        Buffer to store the array&lt;br /&gt;
 * @param outputsize    Maximum size of buffer&lt;br /&gt;
 * @param size          Optional parameter to store the number of bytes written to the buffer&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false if the iterator is empty or the current&lt;br /&gt;
 *                      value is not an array.&lt;br /&gt;
 * @error               Invalid handle&lt;br /&gt;
 *                      Invalid buffer size&lt;br /&gt;
 *                      Iterator has been closed (underlying map destroyed)&lt;br /&gt;
 *                      Iterator is outdated&lt;br /&gt;
 */&lt;br /&gt;
native bool:TrieIterGetArray(TrieIter:handle, any:array[], outputsize, &amp;amp;size = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieIterDestroy|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=TrieIterDestroy|header=Destroys an iterator handle.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Destroys an iterator handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Iterator handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          True on success, false if the value was never set.&lt;br /&gt;
 */&lt;br /&gt;
native TrieIterDestroy(&amp;amp;TrieIter:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
:{{alert|info|Note:|The keys are not sorted.|opt=full-border}}&lt;br /&gt;
:{{alert|success|Example:|{{hidden|id=trie_example_iter|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=trie_example_iter|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    new Trie:list = TrieCreate();&lt;br /&gt;
    {&lt;br /&gt;
        TrieSetString(list, &amp;quot;adventure&amp;quot;, &amp;quot;time!&amp;quot;);&lt;br /&gt;
        TrieSetString(list, &amp;quot;butterflies&amp;quot;, &amp;quot;bees&amp;quot;);&lt;br /&gt;
        TrieSetString(list, &amp;quot;hello&amp;quot;, &amp;quot;world!&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    new TrieIter:iter = TrieIterCreate(list);&lt;br /&gt;
    {&lt;br /&gt;
        new key[32], key_length;&lt;br /&gt;
        new value[32], value_length;&lt;br /&gt;
&lt;br /&gt;
        while (!TrieIterEnded(iter))&lt;br /&gt;
        {&lt;br /&gt;
            key_length = TrieIterGetKey(iter, key, charsmax(key));&lt;br /&gt;
            TrieIterGetString(iter, value, charsmax(value), value_length);&lt;br /&gt;
&lt;br /&gt;
            server_print(&amp;quot;%s (%d) -&amp;gt; %s (%d)&amp;quot;, key, key_length, value, value_length);&lt;br /&gt;
&lt;br /&gt;
            // Should throw an error&lt;br /&gt;
            // TrieSetString(t, &amp;quot;monkey&amp;quot;, &amp;quot;island&amp;quot;);&lt;br /&gt;
            // TrieDeleteKey(t, &amp;quot;full&amp;quot;);&lt;br /&gt;
            // TrieClear(t);&lt;br /&gt;
&lt;br /&gt;
            TrieIterNext(iter);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    TrieIterDestroy(iter);&lt;br /&gt;
&lt;br /&gt;
    TrieDestroy(list);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' New params '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | parameter&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieSetString|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|TrieSetArray|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|replace|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=trie_new_replace_param|header=Makes operation fail if key already set.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param replace   If false the operation will fail if the key is already set&lt;br /&gt;
 */&lt;br /&gt;
native TrieSetCell(Trie:handle, const key[], any:value, bool:replace = true);&lt;br /&gt;
native TrieSetString(Trie:handle, const key[], const value[], bool:replace = true);&lt;br /&gt;
native TrieSetArray(Trie:handle, const key[], const any:buffer[], size, bool:replace = true);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|TrieGetString|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|TrieGetArray|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|size|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=trie_new_size_param|header=Returns the number of bytes written in the buffer.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param size          Optional variable to store the number of cells written&lt;br /&gt;
 *                      to the array in&lt;br /&gt;
 */&lt;br /&gt;
native bool:TrieGetString(Trie:handle, const key[], output[], outputsize, &amp;amp;size = 0);&lt;br /&gt;
native bool:TrieGetArray(Trie:handle, const key[], any:output[], outputsize, &amp;amp;size = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=== Event ===&lt;br /&gt;
&lt;br /&gt;
''' New natives '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|register_event_ex|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=register_event_ex|header=Registers a function to be called on a given game event.&amp;lt;br /&amp;gt;A wrapper of {{tt|register_event|bgcolor=whit}} using flags as strings.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Registers a function to be called on a given game event.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Examples for event conditions:&lt;br /&gt;
 *       &amp;quot;2=c4&amp;quot; - Second parameter of message must be the string &amp;quot;c4&amp;quot;&lt;br /&gt;
 *       &amp;quot;3&amp;gt;10&amp;quot; - Third parameter of message must be greater than 10&lt;br /&gt;
 *       &amp;quot;3!4&amp;quot; - Third parameter of message must not be equal to 4&lt;br /&gt;
 *       &amp;quot;2&amp;amp;Buy&amp;quot; - Second parameter of message must contain &amp;quot;Buy&amp;quot; substring&lt;br /&gt;
 *       &amp;quot;2!Buy&amp;quot; - Second parameter of message must not equal &amp;quot;Buy&amp;quot;&lt;br /&gt;
 * @note Due to a long-standing bug that would break compatibility with older&lt;br /&gt;
 *       plugins, the client id should be checked for alive/dead state if using&lt;br /&gt;
 *       flags &amp;quot;d&amp;quot; or &amp;quot;e&amp;quot;.&lt;br /&gt;
 * @note If multiple conditions are specified for a single parameter, only one&lt;br /&gt;
 *       of them has to hold true for the event function to be called.&lt;br /&gt;
 *&lt;br /&gt;
 * @param event     Name of event that should be hooked&lt;br /&gt;
 * @param function  Name of callback function&lt;br /&gt;
 * @param flags     Flags used for filtering events (enum RegisterEventFlags); the valid flags are:&lt;br /&gt;
 *                    RegisterEvent_Global - Global event (sent to every client)&lt;br /&gt;
 *                    RegisterEvent_Single - Event sent to single client&lt;br /&gt;
 *                    RegisterEvent_OnceForMultiple - Call only once when repeated to multiple clients&lt;br /&gt;
 *                    RegisterEvent_OnlyDead - Call only if sent to dead client&lt;br /&gt;
 *                    RegisterEvent_OnlyAlive - Call only if sent to alive client&lt;br /&gt;
 *                    RegisterEvent_OnlyHuman - Call only if sent to human client (RegisterEvent_Single required)&lt;br /&gt;
 *                    RegisterEvent_OnlyBots - Call only if sent to bot (RegisterEvent_Single required)&lt;br /&gt;
 * @param cond      Condition string used for filtering events, built as:&lt;br /&gt;
 *                  &amp;quot;&amp;lt;argument number&amp;gt;&amp;lt;comparison operator&amp;gt;&amp;lt;value&amp;gt;&amp;quot;&lt;br /&gt;
 *                  Argument number is the argument position to be filtered&lt;br /&gt;
 *                  The comparison operator may be:&lt;br /&gt;
 *                    &amp;quot;=&amp;quot; for equality comparison (all argument types)&lt;br /&gt;
 *                    &amp;quot;!&amp;quot; for inequality comparison (all argument types)&lt;br /&gt;
 *                    &amp;quot;&amp;amp;&amp;quot; for bitwise and (int argument) or substring&lt;br /&gt;
 *                        comparison (string argument)&lt;br /&gt;
 *                    &amp;quot;&amp;lt;&amp;quot; for less than comparison (int/float arguments)&lt;br /&gt;
 *                    &amp;quot;&amp;gt;&amp;quot; for greater than comparison (int/float arguments)&lt;br /&gt;
 *                  The argument is compared to the specified value accordingly&lt;br /&gt;
 * @param ...       Any number of additional conditions&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Event handle&lt;br /&gt;
 * @error           If an invalid event name or callback function is provided,&lt;br /&gt;
 *                  an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native register_event_ex(const event[], const function[], RegisterEventFlags:flags, const cond[] = &amp;quot;&amp;quot;, ...);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|enable_event|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|disable_event|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=enable_event|header=Enables a function hook of a game event which has been previously registered with {{tt|register_event|bgcolor=white}} or {{tt|register_event_ex|bgcolor=white}}.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Enables a function hook of a game event which has been previously registered with register_event and register_event_ex().&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Value returned from register_event() or register_event_ex()&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native enable_event(handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=enable-disable_event|header=Disables a function hook of a game event which has been previously registered with {{tt|register_event|bgcolor=white}} or {{tt|register_event_ex|bgcolor=white}}.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Disables a function hook of a game event which has been previously registered with register_event and register_event_ex().&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Value returned from register_event() or register_event_ex()&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native disable_event(handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|enable_logevent|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|disable_logevent|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=enable_logevent|header=Enables a function hook of a game log event which has been previously registered with {{tt|register_logevent|bgcolor=white}}.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Enables a function hook of a game log event which has been previously registered with register_logevent().&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Value returned from register_logevent()&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native enable_logevent(handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=enable-disable_logevent|header=Disables a function hook of a game log event which has been previously registered with {{tt|register_logevent|bgcolor=white}}.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Disables a function hook of a game log event which has been previously registered with register_logevent().&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle    Value returned from register_logevent()&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid handle is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native disable_logevent(handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' New flags '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | flags&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|register_event|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|&amp;quot;f&amp;quot;|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|&amp;quot;g&amp;quot;|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=register_event_flags|header=Call only if sent to human client (&amp;quot;b&amp;quot; flag required)&amp;lt;br /&amp;gt;Call only if sent to bot (&amp;quot;b&amp;quot; flag required).|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Registers a function to be called on a given game event.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Please consider using register_event_ex() instead which allows you to&lt;br /&gt;
 *       use named constants for flags instead of letters.&lt;br /&gt;
 * @note Examples for event conditions:&lt;br /&gt;
 *       &amp;quot;2=c4&amp;quot; - Second parameter of message must be the string &amp;quot;c4&amp;quot;&lt;br /&gt;
 *       &amp;quot;3&amp;gt;10&amp;quot; - Third parameter of message must be greater than 10&lt;br /&gt;
 *       &amp;quot;3!4&amp;quot; - Third parameter of message must not be equal to 4&lt;br /&gt;
 *       &amp;quot;2&amp;amp;Buy&amp;quot; - Second parameter of message must contain &amp;quot;Buy&amp;quot; substring&lt;br /&gt;
 *       &amp;quot;2!Buy&amp;quot; - Second parameter of message must not equal &amp;quot;Buy&amp;quot;&lt;br /&gt;
 * @note Due to a long-standing bug that would break compatibility with older&lt;br /&gt;
 *       plugins, the client id should be checked for alive/dead state if using&lt;br /&gt;
 *       flags &amp;quot;d&amp;quot; or &amp;quot;e&amp;quot;.&lt;br /&gt;
 * @note If multiple conditions are specified for a single parameter, only one&lt;br /&gt;
 *       of them has to hold true for the event function to be called.&lt;br /&gt;
 *&lt;br /&gt;
 * @param event     Name of event that should be hooked&lt;br /&gt;
 * @param function  Name of callback function&lt;br /&gt;
 * @param flags     Flags used for filtering events, the valid flags are:&lt;br /&gt;
 *                  &amp;quot;a&amp;quot; - Global event (sent to every client)&lt;br /&gt;
 *                  &amp;quot;b&amp;quot; - Event sent to single client&lt;br /&gt;
 *                  &amp;quot;c&amp;quot; - Call only once when repeated to multiple clients&lt;br /&gt;
 *                  &amp;quot;d&amp;quot; - Call only if sent to dead client&lt;br /&gt;
 *                  &amp;quot;e&amp;quot; - Call only if sent to alive client&lt;br /&gt;
 *                  &amp;quot;f&amp;quot; - Call only if sent to human client (&amp;quot;b&amp;quot; flag required)&lt;br /&gt;
 *                  &amp;quot;g&amp;quot; - Call only if sent to bot (&amp;quot;b&amp;quot; flag required)&lt;br /&gt;
 * @param cond      Condition string used for filtering events, built as:&lt;br /&gt;
 *                  &amp;quot;&amp;lt;argument number&amp;gt;&amp;lt;comparison operator&amp;gt;&amp;lt;value&amp;gt;&amp;quot;&lt;br /&gt;
 *                  Argument number is the argument position to be filtered&lt;br /&gt;
 *                  The comparison operator may be:&lt;br /&gt;
 *                    - &amp;quot;=&amp;quot; for equality comparison (all argument types)&lt;br /&gt;
 *                    - &amp;quot;!&amp;quot; for inequality comparison (all argument types)&lt;br /&gt;
 *                    - &amp;quot;&amp;amp;&amp;quot; for bitwise and (int argument) or substring&lt;br /&gt;
 *                      comparison (string argument)&lt;br /&gt;
 *                    - &amp;quot;&amp;lt;&amp;quot; for less than comparison (int/float arguments)&lt;br /&gt;
 *                    - &amp;quot;&amp;gt;&amp;quot; for greater than comparison (int/float arguments)&lt;br /&gt;
 *                  The argument is compared to the specified value accordingly&lt;br /&gt;
 * @param ...       Any number of additional conditions&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Event handle&lt;br /&gt;
 * @error           If an invalid event name or callback function is provided,&lt;br /&gt;
 *                  an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native register_event(const event[], const function[], const flags[], const cond[] = &amp;quot;&amp;quot;, ...);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== File ===&lt;br /&gt;
&lt;br /&gt;
'''Valve FileSystems '''&lt;br /&gt;
&lt;br /&gt;
Thanks to the [https://github.com/alliedmodders/hlsdk/blob/master/public/FileSystem.h IFileSystem] interface from HLSDK, we are now able to make more operations possible with files via Valve File System through Valve search paths (example: download directory). &amp;lt;br /&amp;gt;&lt;br /&gt;
This is handy when you want to deal with files which are not necessary existing directly in the game directory.&lt;br /&gt;
&lt;br /&gt;
Not all natives are concerned. This features some new natives and enhanced others existing ones with small quality of life changes.&lt;br /&gt;
&lt;br /&gt;
''' Valve Paths '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Path ID&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GAME|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | All paths related to current mod, including fallback. Depending settings, it includes: {{tt|&amp;lt;gamedir&amp;gt;_lv|bgcolor=none}}/{{tt|_addon|bgcolor=none}}/{{tt|_language|bgcolor=none}}/{{tt|_hd|bgcolor=none}} and {{tt|&amp;lt;gamedir&amp;gt;|bgcolor=none}} itself.&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GAMECONFIG|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | The default writable directory: {{tt|&amp;lt;gamedir&amp;gt;|bgcolor=none}}.&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GAMEDOWNLOAD|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | The download directory: {{tt|&amp;lt;gamedir&amp;gt;_download|bgcolor=none}}.&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GAME_FALLBACK|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | All paths related to fallback game, same as {{tt|GAME|bgcolor=none}} (example: {{tt|czero|bgcolor=none}} has {{tt|cstrike|bgcolor=none}} as fallback. Others mods have usually the default game {{tt|valve|bgcolor=none}}, including {{tt|cstrike|bgcolor=none}}).&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|DEFAULTGAME|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | All paths related to the default game which is ''valve'', same as {{tt|GAME|bgcolor=none}}.&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|BASE|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | The base path where server is installed.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Native Support '''&lt;br /&gt;
&lt;br /&gt;
Some natives supports partially Valve FS, where a path ID can't be provided and this will search in all paths instead.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | parameter&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|delete_file|bgcolor=white}} {{tt|unlink|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|file_exists|bgcolor=white}} ''partially''&amp;lt;br /&amp;gt;{{tt|dir_exists|bgcolor=white}} ''partially''&amp;lt;br /&amp;gt;{{tt|file_size|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|fopen|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|mkdir|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|open_dir|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|use_valve_fs|bgcolor=white}} &amp;lt;br /&amp;gt;{{tt|valve_path_id|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=native_fs|header=Uses the Valve file system via a search path from gameinfo.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @note Registered paths ID are (in priority order) :&lt;br /&gt;
 *         GAME           All paths related to current mod, including fallback&lt;br /&gt;
 *                        Depending settings, it includes: &amp;lt;gamedir&amp;gt;_lv/_addon/_&amp;lt;language&amp;gt;/_hd&lt;br /&gt;
 *                        and &amp;lt;gamedir&amp;gt; itself&lt;br /&gt;
 *         GAMECONFIG     The default writable directory (&amp;lt;gamedir&amp;gt;)&lt;br /&gt;
 *         GAMEDOWNLOAD   The download directory (&amp;lt;gamedir&amp;gt;_download)&lt;br /&gt;
 *         GAME_FALLBACK  All paths related to fallback game, same as GAME&lt;br /&gt;
 *         DEFAULTGAME    All paths related to the default game which is &amp;quot;valve&amp;quot;, same as GAME&lt;br /&gt;
 *         BASE           The base path where server is installed&lt;br /&gt;
 *&lt;br /&gt;
 *         Note that some paths are non-writable. It includes all &amp;lt;gamedir&amp;gt;_* (expect _download)&lt;br /&gt;
 *         and DEFAULTGAME. Any file inside a non-writable path will be ignored if you try to open&lt;br /&gt;
 *         it in writing mode.&lt;br /&gt;
 *&lt;br /&gt;
 * @param use_valve_fs  If true, the Valve file system will be used instead&lt;br /&gt;
 *                      This can be used to finred files existing in valve&lt;br /&gt;
 *                      search paths, rather than solely files existing directly&lt;br /&gt;
 *                      in the gamedir.&lt;br /&gt;
 * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Some natives are not adjusted because not exposed by Valve FS:&lt;br /&gt;
* {{tt|rename_file}}&lt;br /&gt;
* {{tt|rmdir}}&lt;br /&gt;
&lt;br /&gt;
''' New Natives '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|FileReadInt8|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|FileReadUint8|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|FileReadInt16|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|FileReadUint16|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|FileReadInt32|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=FileRead|header=Reads a single value from a file. &amp;lt;br /&amp;gt; More sane and better designed natives to read a single value (proper type, unsigned byte/short support and returns 1 or 0).|labelpos=left|content=&lt;br /&gt;
 &amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Reads a single int8 (byte) from a file. The returned value is sign-&lt;br /&gt;
 * extended to an int32.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          Handle to the file&lt;br /&gt;
 * @param data          Variable to store the data read&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false on failure&lt;br /&gt;
 */&lt;br /&gt;
native bool:FileReadInt8(file, &amp;amp;any:data);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reads a single uint8 (unsigned byte) from a file. The returned value is&lt;br /&gt;
 * zero-extended to an int32.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          Handle to the file&lt;br /&gt;
 * @param data          Variable to store the data read&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false on failure&lt;br /&gt;
 */&lt;br /&gt;
native bool:FileReadUint8(file, &amp;amp;any:data);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reads a single int16 (short) from a file. The value is sign-extended to&lt;br /&gt;
 * an int32.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          Handle to the file&lt;br /&gt;
 * @param data          Variable to store the data read&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false on failure&lt;br /&gt;
 */&lt;br /&gt;
native bool:FileReadInt16(file, &amp;amp;any:data);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reads a single unt16 (unsigned short) from a file. The value is zero-&lt;br /&gt;
 * extended to an int32.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          Handle to the file&lt;br /&gt;
 * @param data          Variable to store the data read&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false on failure&lt;br /&gt;
 */&lt;br /&gt;
native bool:FileReadUint16(file, &amp;amp;any:data);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reads a single int32 (int/cell) from a file.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          Handle to the file&lt;br /&gt;
 * @param data          Variable to store the data read&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false on failure&lt;br /&gt;
 */&lt;br /&gt;
native bool:FileReadInt32(file, &amp;amp;any:data);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|FileWriteInt8|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|FileWriteInt16|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|FileWriteInt32|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=FileWrite|header=Writes a single value from a file. &amp;lt;br /&amp;gt; More sane and better designed natives to write a single value (proper type, unsigned byte/short support and returns 1 or 0).|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Writes a single int8 (byte) to a file.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          Handle to the file&lt;br /&gt;
 * @param data          Data to write (truncated to an int8)&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false on failure&lt;br /&gt;
 */&lt;br /&gt;
native bool:FileWriteInt8(file, any:data);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Writes a single int16 (short) to a file.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          Handle to the file&lt;br /&gt;
 * @param data          Data to write (truncated to an int16)&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false on failure&lt;br /&gt;
 */&lt;br /&gt;
native bool:FileWriteInt16(file, any:data);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Writes a single int32 (int/cell) to a file.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          Handle to the file&lt;br /&gt;
 * @param data          Data to write&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false on failure&lt;br /&gt;
 */&lt;br /&gt;
native bool:FileWriteInt32(file, any:data);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GetFileTime|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=GetFileTime|header=Returns a file timestamp as a unix timestamp. |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * File time modes for use with GetFileTime().&lt;br /&gt;
 */&lt;br /&gt;
enum FileTimeType&lt;br /&gt;
{&lt;br /&gt;
    FileTime_LastAccess,    /* Last access (not available on FAT) */&lt;br /&gt;
    FileTime_Created,       /* Creation (not available on FAT) */&lt;br /&gt;
    FileTime_LastChange,    /* Last modification */&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Returns a file timestamp as a unix timestamp.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          File name&lt;br /&gt;
 * @param tmode         Time mode, see FileTime_* constants&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Returns a file timestamp as a unix timestamp&lt;br /&gt;
 */&lt;br /&gt;
native GetFileTime(const file[], FileTimeType:tmode);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SetFilePermissions|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SetFilePermissions|header=Changes a file or directories permissions.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Changes a file or directories permissions.&lt;br /&gt;
 *&lt;br /&gt;
 * @param path          Path to the file&lt;br /&gt;
 * @param mode          Permissions to set, see FPERM_* constants&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True on success, false otherwise&lt;br /&gt;
 */&lt;br /&gt;
native bool:SetFilePermissions(const path[], mode);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
'''New params'''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | parameter&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|fputs|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|null_term|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=fputs|header=True to append NULL terminator, false otherwise.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Writes a line of text to a text file.&lt;br /&gt;
 *&lt;br /&gt;
 * @param file          Handle to the file&lt;br /&gt;
 * @param text          String to write&lt;br /&gt;
 * @param null_term     True to append NULL terminator, false otherwise&lt;br /&gt;
 *&lt;br /&gt;
 * @return              0 on success, -1 otherwise&lt;br /&gt;
 */&lt;br /&gt;
native fputs(file, const text[], bool:null_term = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|mkdir|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|mode |bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=mkdir|header=Permissions (default is o=rx,g=rx,u=rwx). &amp;lt;br /&amp;gt;Note that folders must have the execute bit set on Linux. &amp;lt;br /&amp;gt;On Windows, the mode is ignored.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a directory.&lt;br /&gt;
 *&lt;br /&gt;
 * @param path          Path to create&lt;br /&gt;
 * @param mode          Permissions (default is o=rx,g=rx,u=rwx).  Note that folders must have&lt;br /&gt;
 *                      the execute bit set on Linux.  On Windows, the mode is ignored.&lt;br /&gt;
 * @param use_valve_fs  If true, the Valve file system will be used instead&lt;br /&gt;
 *                      This can be used to create folders in the game's&lt;br /&gt;
 *                      Valve search paths, rather than directly in the gamedir.&lt;br /&gt;
 * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for default&lt;br /&gt;
 *                      In this case, mode is ignored&lt;br /&gt;
 *&lt;br /&gt;
 * @return              0 on success, -1 otherwise&lt;br /&gt;
 */&lt;br /&gt;
native mkdir(const dirname[], mode = FPERM_DIR_DEFAULT, bool:use_valve_fs = false, const valve_path_id[] = &amp;quot;GAMECONFIG&amp;quot;);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|open_dir|bgcolor=white}} &amp;lt;br /&amp;gt; {{tt|next_file|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|type|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=open_dir-next_file|header=Optional variable to store the file type.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Opens a directory/folder for contents enumeration.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Directories are closed with close_dir().&lt;br /&gt;
 *&lt;br /&gt;
 * @param dir           Path to open.&lt;br /&gt;
 * @param firstfile     String buffer to hold first file name&lt;br /&gt;
 * @param length        Maximum size of the string buffer&lt;br /&gt;
 * @param type          Optional variable to store the file type&lt;br /&gt;
 * @param use_valve_fs  If true, the Valve file system will be used instead.&lt;br /&gt;
 *                      This can be used to find files existing in any of&lt;br /&gt;
 *                      the Valve search paths, rather than solely files&lt;br /&gt;
 *                      existing directly in the gamedir.&lt;br /&gt;
 * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Handle to the directory, 0 otherwise&lt;br /&gt;
 */&lt;br /&gt;
native open_dir(dir[], firstfile[], length, &amp;amp;FileType:type = FileType_Unknown, bool:use_valve_fs = false, const valve_path_id[] = &amp;quot;GAME&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reads the next directory entry as a local filename.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Contents of buffers are undefined when returning false.&lt;br /&gt;
 * @note Both the '.' and '..' automatic directory entries will be retrieved for Windows and Linux.&lt;br /&gt;
 *&lt;br /&gt;
 * @param dirh          Handle to a directory&lt;br /&gt;
 * @param buffer        String buffer to hold directory name&lt;br /&gt;
 * @param length        Maximum size of string buffer&lt;br /&gt;
 * @param type          Optional variable to store the file type. FileType_* constants&lt;br /&gt;
 *&lt;br /&gt;
 * @return              1 on success, 0 if there are no more files to read.&lt;br /&gt;
 */&lt;br /&gt;
native next_file(dirh, buffer[], length, &amp;amp;FileType:type = FileType_Unknown);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Others '''&lt;br /&gt;
&lt;br /&gt;
There are as well some minor additions or changes:&lt;br /&gt;
&lt;br /&gt;
* Added a new define {{tt|PLATFORM_MAX_PATH}} {{hidden|id=platform_max_path|labelonly=yes}} to represent a maximum path length.&lt;br /&gt;
{{hidden|id=platform_max_path|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Maximum path length.&lt;br /&gt;
 */&lt;br /&gt;
#define PLATFORM_MAX_PATH  256&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* Added {{tt|any:}} tag to some natives.&lt;br /&gt;
* {{tt|read_dir}}: {{tt|outlen|bgcolor=none}} parameter is now optional.&lt;br /&gt;
* {{tt|read_file}}: {{tt|txtlen|bgcolor=none}} parameter is now optional. Adjusted as well buffer to 2048 to match buffer size in {{tt|write_file|bgcolor=none}}.&lt;br /&gt;
* {{tt|file_size}}: Fixed potential issue with old compiled plugin which doesn't have the flag parameter. Added {{tt|FSOPT_*|bgcolor=none}} {{hidden|id=fsopt_constants|labelonly=yes}} constants as well for use with this flag parameter.&lt;br /&gt;
{{hidden|id=fsopt_constants|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Options for use with file_size() flag parameter.&lt;br /&gt;
 */&lt;br /&gt;
#define FSOPT_BYTES_COUNT  0  /* Returns the file size in number of bytes */&lt;br /&gt;
#define FSOPT_LINES_COUNT  1  /* Returns how many lines there are in this file */&lt;br /&gt;
#define FSOPT_END_WITH_LF  2  /* Returns whether the last line is '\n' */&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== General ===&lt;br /&gt;
&lt;br /&gt;
''' Constant '''&lt;br /&gt;
&lt;br /&gt;
* Added {{tt|DMG_GRENADE}} constant (Counter-Strike only)&lt;br /&gt;
* Added missing {{tt|SVC_}} messages ({{pr|amxx|223}})&lt;br /&gt;
** {{tt|SVC_RESOURCELOCATION}}&lt;br /&gt;
** {{tt|SVC_SENDCVARVALUE}}&lt;br /&gt;
** {{tt|SVC_SENDCVARVALUE2}}&lt;br /&gt;
&lt;br /&gt;
''' Forward '''&lt;br /&gt;
&lt;br /&gt;
* Added {{tt|FP_VAL_BYREF}} to pass values by reference in forwards.&lt;br /&gt;
* {{tt|ExecuteForward}} can now be called without the need to create variable for returned value.&lt;br /&gt;
&lt;br /&gt;
''' Others '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|has_map_ent_class|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=has_map_ent_class|header=Returns if a map contains at least one entity with the provided class name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns if a map contains at least one entity with the provided class name.&lt;br /&gt;
 *&lt;br /&gt;
 * @param classname     Entity classname to match&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True if an entity is found, false otherwise&lt;br /&gt;
 */&lt;br /&gt;
native bool:has_map_ent_class(const classname[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|engine_changelevel|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=engine_changelevel|header=Changes the map.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|This has the same behavior as using the &amp;quot;changelevel&amp;quot; server command, but will also trigger the {{tt|server_changelevel|bgcolor=white}} forward in AMXX plugins.&amp;lt;br /&amp;gt;&lt;br /&gt;
It will also notify any Metamod plugins that are hooking the {{tt|pfnChangeLevel|bgcolor=white}} function.|opt=full-border}}&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Changes the map.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This calls the pfnChangelLevel engine function.&lt;br /&gt;
 * @note  This has the same behavior as using the &amp;quot;changelevel&amp;quot; server command,&lt;br /&gt;
 *        but will also trigger the server_changelevel() forward in AMXX&lt;br /&gt;
 *        plugins. It will also notify any Metamod plugins that are hooking&lt;br /&gt;
 *        the pfnChangeLevel function.&lt;br /&gt;
 *&lt;br /&gt;
 * @param map   Map name to change to&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native engine_changelevel(const map[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|RequestFrame|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=RequestFrame|header=Creates a single use hook for the next frame.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a single use hook for the next frame.&lt;br /&gt;
 *&lt;br /&gt;
 * @param callback      Function to be executed on the next frame.&lt;br /&gt;
 * @param data          Optional data to be passed to the callback function.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                Callback function prototype:&lt;br /&gt;
 *                          public function(data)&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native RequestFrame(const callback[], any:data = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|set_task_ex|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=set_task_ex|header=Calls a function after a specified time has elapsed.&lt;br /&gt;
&lt;br /&gt;
 {{alert|info|Note:|Similar to {{tt|set_task|bgcolor=white}} but it allows you to use named constants for flags instead of letters.|opt=full-border}}&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * SetTaskFlags constants for set_task_ex()&lt;br /&gt;
 */&lt;br /&gt;
enum SetTaskFlags (&amp;lt;&amp;lt;= 1)&lt;br /&gt;
{&lt;br /&gt;
    SetTask_Once = 0,          // None; execute callback after the specified amount of time (Default)&lt;br /&gt;
    SetTask_RepeatTimes = 1,   // Repeat timer a set amount of times&lt;br /&gt;
    SetTask_Repeat,            // Loop indefinitely until timer is stopped&lt;br /&gt;
    SetTask_AfterMapStart,     // Time interval is treated as absolute time after map start&lt;br /&gt;
    SetTask_BeforeMapChange    // Time interval is treated as absolute time before map change&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Calls a function after a specified time has elapsed.&lt;br /&gt;
 *&lt;br /&gt;
 * @param time          Time interval to assign&lt;br /&gt;
 * @param function      Function to execute&lt;br /&gt;
 * @param id            Task id to assign&lt;br /&gt;
 * @param parameter     Data to pass through to callback&lt;br /&gt;
 * @param len           Size of data&lt;br /&gt;
 * @param flags         Optional flags (enum SetTaskFlags); valid flags are:&lt;br /&gt;
 *                        SetTask_Once - Execute callback once (Default)&lt;br /&gt;
 *                        SetTask_RepeatTimes - repeat timer a set amount of times&lt;br /&gt;
 *                        SetTask_Repeat - loop indefinitely until timer is stopped&lt;br /&gt;
 *                        SetTask_AfterMapStart - time interval is treated as absolute&lt;br /&gt;
 *                            time after map start&lt;br /&gt;
 *                        SetTask_BeforeMapChange - time interval is treated as absolute&lt;br /&gt;
 *                            time before map change&lt;br /&gt;
 * @param repeat        If the SetTask_RepeatTimes flag is set, the task will be repeated this&lt;br /&gt;
 *                      many times&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error               If an invalid callback function is provided, an error is&lt;br /&gt;
 *                      thrown.&lt;br /&gt;
 */&lt;br /&gt;
stock set_task_ex(Float:time, const function[], id = 0, const any:parameter[] = &amp;quot;&amp;quot;, len = 0, SetTaskFlags:flags = SetTask_Once, repeat = 0)&lt;br /&gt;
{&lt;br /&gt;
    new strFlags[2]; // There should never be a need to set more than 1 flag&lt;br /&gt;
    get_flags(_:flags, strFlags, charsmax(strFlags));&lt;br /&gt;
    set_task(time, function, id, parameter, len, strFlags, repeat);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' XS '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|xs_vec_len_2d|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=xs_vec_len_2d|header=Computes the length of a 2D vector.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Computes the length of a 2D vector.&lt;br /&gt;
 *&lt;br /&gt;
 * @param vec           The vector to compute the length of.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              The length of the input vector.&lt;br /&gt;
 */&lt;br /&gt;
stock Float:xs_vec_len_2d(const Float:vec[])&lt;br /&gt;
{&lt;br /&gt;
    return xs_sqrt(vec[0]*vec[0] + vec[1]*vec[1]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|xs_vec_distance|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=xs_vec_distance|header=Computes the distance between two vectors (points).|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Computes the distance between two vectors (points).&lt;br /&gt;
 *&lt;br /&gt;
 * @param vec1          First vector.&lt;br /&gt;
 * @param vec2          Second vector.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              The distance between two vectors.&lt;br /&gt;
 */&lt;br /&gt;
stock Float:xs_vec_distance(const Float:vec1[], const Float:vec2[])&lt;br /&gt;
{&lt;br /&gt;
    return xs_sqrt((vec1[0]-vec2[0]) * (vec1[0]-vec2[0]) +&lt;br /&gt;
                   (vec1[1]-vec2[1]) * (vec1[1]-vec2[1]) +&lt;br /&gt;
                   (vec1[2]-vec2[2]) * (vec1[2]-vec2[2]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|xs_vec_distance_2d|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=xs_vec_distance_2d|header=Computes the distance between two 2D vectors (points).|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Computes the distance between two 2D vectors (points).&lt;br /&gt;
 * &lt;br /&gt;
 * @param vec1          First vector.&lt;br /&gt;
 * @param vec2          Second vector.&lt;br /&gt;
 * &lt;br /&gt;
 * @return              The distance between two vectors.&lt;br /&gt;
 */&lt;br /&gt;
stock Float:xs_vec_distance_2d(const Float:vec1[], const Float:vec2[])&lt;br /&gt;
{&lt;br /&gt;
    return xs_sqrt((vec1[0]-vec2[0]) * (vec1[0]-vec2[0]) +&lt;br /&gt;
                   (vec1[1]-vec2[1]) * (vec1[1]-vec2[1]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|xs_vec_add_scaled|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=xs_vec_add_scaled|header=Adds the second vector scaled by a scalar to the first.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Adds the second vector scaled by a scalar to the first.&lt;br /&gt;
 *&lt;br /&gt;
 * @param in1           Vector to add to.&lt;br /&gt;
 * @param in2           Vector to scale and add.&lt;br /&gt;
 * @param scalar        Scalar to scale the second vector with.&lt;br /&gt;
 * @param out           The output vector. Can be one of the input vectors.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
stock xs_vec_add_scaled(const Float:in1[], const Float:in2[], Float:scalar, Float:out[])&lt;br /&gt;
{&lt;br /&gt;
    out[0] = in1[0] + in2[0] * scalar;&lt;br /&gt;
    out[1] = in1[1] + in2[1] * scalar;&lt;br /&gt;
    out[2] = in1[2] + in2[2] * scalar;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|xs_vec_sub_scaled|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=xs_vec_sub_scaled|header=Subtracts the second vector scaled by a scalar from the first one.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Subtracts the second vector scaled by a scalar from the first one.&lt;br /&gt;
 *&lt;br /&gt;
 * @param in1           Vector to subtract from.&lt;br /&gt;
 * @param in2           Vector to scale and subtract.&lt;br /&gt;
 * @param scalar        Scalar to scale the second vector with.&lt;br /&gt;
 * @param out           The output vector. Can be one of the input vectors.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
stock xs_vec_sub_scaled(const Float:in1[], const Float:in2[], Float:scalar, Float:out[])&lt;br /&gt;
{&lt;br /&gt;
    out[0] = in1[0] - in2[0] * scalar;&lt;br /&gt;
    out[1] = in1[1] - in2[1] * scalar;&lt;br /&gt;
    out[2] = in1[2] - in2[2] * scalar;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Menu ===&lt;br /&gt;
&lt;br /&gt;
''' Timeout '''&lt;br /&gt;
&lt;br /&gt;
Timeout is now added to newmenus, working similar to those of {{tt|show_menu}}.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a menu is acted upon after the specified timeout has run out it will pass a new {{tt|MENU_TIMEOUT}} status code into the menu handler. &amp;lt;br /&amp;gt;&lt;br /&gt;
Actions are: &lt;br /&gt;
* player disconnect&lt;br /&gt;
* selecting an item, &lt;br /&gt;
* cancelling/destroying the menu in the plugin, &lt;br /&gt;
* sending a different menu or using {{tt|get_user_menu}} on a player with an open menu.&lt;br /&gt;
&lt;br /&gt;
Just like with the old menus timeouts are not actively polled, and {{tt|MENU_TIMEOUT}} is not guaranteed to fire directly after the time has run out. &amp;lt;br /&amp;gt;&lt;br /&gt;
Also {{tt|get_user_menu}} will detect timeouts and reset the menu flags, which is why it also has to trigger the callback.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|An example is available at {{pr|amxx|21}}.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | parameter&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|menu_display|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|time|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=menu_display|header=If &amp;gt;=0 menu will timeout after this many seconds.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Displays a menu to one client.  This should never be called from a handler &lt;br /&gt;
 * when the item is less than 0 (i.e. calling this from a cancelled menu will &lt;br /&gt;
 * result in an error).&lt;br /&gt;
 *&lt;br /&gt;
 * Starting with 1.8.3 this allows to specify a menu timeout similar to the &lt;br /&gt;
 * show_menu native. If the menu exists on the client past the timeout *any* &lt;br /&gt;
 * further action will send the MENU_TIMEOUT status code to the menu handler.&lt;br /&gt;
 * That includes actions which would otherwise send MENU_EXIT, such as the&lt;br /&gt;
 * client selecting an item or disconnecting and calling menu_cancel or &lt;br /&gt;
 * menu_destroy on a live menu.&lt;br /&gt;
 *&lt;br /&gt;
 * @param id			Client index.&lt;br /&gt;
 * @param menu			Menu resource identifier.&lt;br /&gt;
 * @param page			Page to start from (starting from 0).&lt;br /&gt;
 * @param time			If &amp;gt;=0 menu will timeout after this many seconds&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error				Invalid menu resource or client index.&lt;br /&gt;
 */&lt;br /&gt;
native menu_display(id, menu, page=0, time=-1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' New native &amp;amp; stock '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|menu_addblank2|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=menu_addblank2|header=Adds a blank line to a menu, always shifting the numbering down.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|This fixes an unexpected behavior with the original ones when slot param is set to 1|opt=full-border}}&lt;br /&gt;
|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Adds a blank line to a menu, always shifting the numbering down.&lt;br /&gt;
 * &lt;br /&gt;
 * This will add a special item to create a blank line. It will affect the menu&lt;br /&gt;
 * item count and pagination. These items can be modified later but will ignore &lt;br /&gt;
 * access and item callback results.&lt;br /&gt;
 * &lt;br /&gt;
 * Only available in 1.8.3 and above.&lt;br /&gt;
 * &lt;br /&gt;
 * @param menu          Menu resource identifier.&lt;br /&gt;
 * &lt;br /&gt;
 * @return              1 on success, 0 on failure.&lt;br /&gt;
 * @error               Invalid menu resource.&lt;br /&gt;
 *                      Too many items on non-paginated menu (max is 10)&lt;br /&gt;
 */&lt;br /&gt;
native menu_addblank2( menu );&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|reset_menu|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=reset_menu|header=Resets the client's menu.&lt;br /&gt;
|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Resets the client's menu.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This is a wrapper around show_menu() for the sake of readability.&lt;br /&gt;
 *&lt;br /&gt;
 * @param index     Client to reset menu of, 0 to reset all clients&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
stock reset_menu(index)&lt;br /&gt;
{&lt;br /&gt;
    show_menu(index, 0, &amp;quot;&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' New properties '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Property&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|MEXIT_FORCE|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Forces a proper exit button on unpaginated menus&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|MPROP_SHOWPAGE|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Whether to show the page number in menu title&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|MEXIT_FORCE|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Function to be called on Back and Next&lt;br /&gt;
&lt;br /&gt;
Prototype of callback:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Called when parsing is halted.&lt;br /&gt;
&lt;br /&gt;
@param id        Playeer's index&lt;br /&gt;
@param status    Either MENU_BACK or MENU_MORE&lt;br /&gt;
&lt;br /&gt;
public function(id, status);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
{{alert|info|Note:|An example is available in the {{tt|testsuite}} directory, see [https://github.com/alliedmodders/amxmodx/blob/master/plugins/testsuite/menu_page_callback_test.sma menu_page_callback_test.sma].|opt=full-border}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Others '''&lt;br /&gt;
&lt;br /&gt;
* {{tt|menu_item_getinfo}}'s arguments are now optional&lt;br /&gt;
* {{tt|show_menu]}} native is allowed to send empty text&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Message ===&lt;br /&gt;
&lt;br /&gt;
''' New natives '''&lt;br /&gt;
&lt;br /&gt;
The float version of {{tt|message_begin}}, {{tt|write_angle}}, {{tt|write_coord_f}}, {{tt|emessage_begin}}, {{tt|ewrite_coord}} and {{tt|ewrite_angle}}:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|message_begin_f|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|write_angle_f|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|write_coord_f|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=message_begin_f|header=Marks the beginning of a client message.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Marks the beginning of a client message.&lt;br /&gt;
 *&lt;br /&gt;
 * @note You may generate menus, smoke, shockwaves, thunderlights,&lt;br /&gt;
 *       intermission and many other messages.&lt;br /&gt;
 * @note For a list of HL game events, visit https://wiki.alliedmods.net/Half-Life_1_Game_Events&lt;br /&gt;
 * @note For a list of HL engine messages, visit https://wiki.alliedmods.net/Half-Life_1_Engine_Messages&lt;br /&gt;
 * @note You may also refer to the messages_const.inc file for examples.&lt;br /&gt;
 * @note This function is the same as message_begin(), but the origin&lt;br /&gt;
 *       argument accepts only float values in this one.&lt;br /&gt;
 * @note Each message starts with a message_begin() or message_begin_f() function&lt;br /&gt;
 *       and ends with message_end(). The specific message arguments go in between&lt;br /&gt;
 *       these two by using the write_*() functions found in messages.inc.&lt;br /&gt;
 *&lt;br /&gt;
 * @param dest        Destination type (see MSG_* constants in messages_const.inc)&lt;br /&gt;
 * @param msg_type    Message id&lt;br /&gt;
 * @param origin      Message origin&lt;br /&gt;
 * @param player      Client index receiving the message or 0 for all clients&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error             If an invalid message id is specified or an invalid number&lt;br /&gt;
 *                    of parameters is passed, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native message_begin_f(dest, msg_type, const Float:origin[3] = {0.0,0.0,0.0}, player = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=write_angle_f|header=Writes an angle entry to a message using a float value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Writes an angle entry to a message using a float value.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This function should only be used in between a message_begin()&lt;br /&gt;
 *       or message_begin_f() and a message_end() function. Trying to use&lt;br /&gt;
 *       it outside of these functions will crash the server immediately.&lt;br /&gt;
 *&lt;br /&gt;
 * @param x           Angle to write&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native write_angle_f(Float:x);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=write_coord_f|header=Writes a coordinate entry to a message using a float value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Writes a coordinate entry to a message using a float value.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This function should only be used in between a message_begin()&lt;br /&gt;
 *       or message_begin_f() and a message_end() function. Trying to use&lt;br /&gt;
 *       it outside of these functions will crash the server immediately.&lt;br /&gt;
 *&lt;br /&gt;
 * @param x           Coordinate to write&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native write_coord_f(Float:x);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|zmessage_begin_f|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|ewrite_coord_f|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|ewrite_angle_f|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=emessage_begin_f|header=Marks the beginning of a client message.|labelpos=left|content=&lt;br /&gt;
/**&lt;br /&gt;
 * Marks the beginning of a client message.&lt;br /&gt;
 *&lt;br /&gt;
 * @note You may generate menus, smoke, shockwaves, thunderlights,&lt;br /&gt;
 *       intermission and many other messages.&lt;br /&gt;
 * @note For a list of HL game events, visit https://wiki.alliedmods.net/Half-Life_1_Game_Events&lt;br /&gt;
 * @note For a list of HL engine messages, visit https://wiki.alliedmods.net/Half-Life_1_Engine_Messages&lt;br /&gt;
 * @note You may also refer to the messages_const.inc file for examples.&lt;br /&gt;
 * @note This function is the same as message_begin_f(), except that the messages&lt;br /&gt;
 *       sent with this one are also sent to all other AMXX and Metamod plugins.&lt;br /&gt;
 *       This means that if you send one of these messages, other plugins will&lt;br /&gt;
 *       be notified of that message, which was previously impossible.&lt;br /&gt;
 * @note BE CAREFUL! Using this incorrectly, or not for its intended purpose,&lt;br /&gt;
 *       could cause infinite recursion or something just as bad!&lt;br /&gt;
 * @note This function is the same as emessage_begin(), but the origin&lt;br /&gt;
 *       argument accepts only float values in this one.&lt;br /&gt;
 * @note Each message starts with a emessage_begin() or emessage_begin_f() function&lt;br /&gt;
 *       and ends with emessage_end(). The specific message arguments go in between&lt;br /&gt;
 *       these two by using the ewrite_*() functions found in messages.inc.&lt;br /&gt;
 *&lt;br /&gt;
 * @param dest        Destination type (see MSG_* constants in messages_const.inc)&lt;br /&gt;
 * @param msg_type    Message id&lt;br /&gt;
 * @param origin      Message origin&lt;br /&gt;
 * @param player      Client index receiving the message or 0 for all clients&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error             If an invalid message id is specified or an invalid number&lt;br /&gt;
 *                    of parameters is passed, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native emessage_begin_f(dest, msg_type, const Float:origin[3] = {0.0,0.0,0.0}, player = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=ewrite_coord_f|header=Writes a coordinate entry to a message using a float value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Writes a coordinate entry to a message using a float value.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This function should only be used in between a emessage_begin()&lt;br /&gt;
 *       or emessage_begin_f() and a emessage_end() function. Trying to use&lt;br /&gt;
 *       it outside of these functions will crash the server immediately.&lt;br /&gt;
 *&lt;br /&gt;
 * @param x           Coordinate to write&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native ewrite_coord_f(Float:x);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=ewrite_angle_f|header=Writes an angle entry to a message using a float value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Writes an angle entry to a message using a float value.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This function should only be used in between a emessage_begin()&lt;br /&gt;
 *       or emessage_begin_f() and a emessage_end() function. Trying to use&lt;br /&gt;
 *       it outside of these functions will crash the server immediately.&lt;br /&gt;
 *&lt;br /&gt;
 * @param x           Angle to write&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native ewrite_angle_f(Float:x);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 {| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|client_print_color|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=client_print_color|header=Sends colored chat messages to clients.&lt;br /&gt;
 {{alert|info|Note:|Counter-strike only.|opt=full-border}}|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sends colored chat messages to clients.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This only works in Counter-Strike 1.6 and Condition Zero.&lt;br /&gt;
 * @note The colors can be modified inside of the format string using special&lt;br /&gt;
 *       characters. These characters can be included using the escape character&lt;br /&gt;
 *          green           x04   ; use location color from this point forward&lt;br /&gt;
 *          red/blue/grey   x03   ; use team color from this point forward&lt;br /&gt;
 *          red/blue/grey   x02   ; use team color to the end of the client name&lt;br /&gt;
 *                                ; This only works at the start of the string,&lt;br /&gt;
 *                                ; and precludes using other control characters&lt;br /&gt;
 *          default         x01   ; use default color from this point forward&lt;br /&gt;
 * @note The team color is defined by the sender's index. Alternatively, a&lt;br /&gt;
 *       specific team color can be enforced using the print_team_* constants in&lt;br /&gt;
 *       amxconst.inc&lt;br /&gt;
 * @note Usage examples:&lt;br /&gt;
 *       client_print_color(id, print_team_red, &amp;quot;^4Green ^3Red ^1Default&amp;quot;)&lt;br /&gt;
 *       client_print_color(id, id2, &amp;quot;^4Green ^3id2's team color, ^1Default&amp;quot;)&lt;br /&gt;
 * @note Including colors in ML can be done using the same escaping method:&lt;br /&gt;
 *       EXAMPLE_ML_KEY = ^4Green ^3Team color ^1Default&lt;br /&gt;
 * @note This functions return value behaves differently depending on what is&lt;br /&gt;
 *       used as the client index: If 0 is specified, then the function will&lt;br /&gt;
 *       return 0 if nothing has been sent (no client connected). If either a&lt;br /&gt;
 *       single client is specified, or there is at least one client connected,&lt;br /&gt;
 *       the number of printed characters will refer to the message that is sent&lt;br /&gt;
 *       last, to the client with the highest index.&lt;br /&gt;
 *&lt;br /&gt;
 * @param index     Client index, use 0 to display to all clients&lt;br /&gt;
 * @param sender    Client index used as the message sender&lt;br /&gt;
 * @param fmt       Formatting rules&lt;br /&gt;
 * @param ...       Variable number of formatting parameters&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of printed characters&lt;br /&gt;
 * @error           If a single client is specified and the index is not within&lt;br /&gt;
 *                  the range of 1 to MaxClients, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native client_print_color(index, sender, const message[], any:...);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|set_dhudmessage|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|show_dhudmessage|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=set_dhudmessage|header= Sets display parameters for director hudmessages.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets display parameters for director hudmessages.&lt;br /&gt;
 *&lt;br /&gt;
 * @note For the hudmessage coordinates x and y, -1.0 will center the message&lt;br /&gt;
 *       on the respective axis.&lt;br /&gt;
 * @note These parameters stay until the next call to set_dhudmessage overwrites&lt;br /&gt;
 *       them. Multiple calls to show_dhudmessage will therefore re-use the same&lt;br /&gt;
 *       parameters. The parameters are not stored per-plugin, so other plugins&lt;br /&gt;
 *       can overwrite them.&lt;br /&gt;
 *&lt;br /&gt;
 * @param red           Red component of hudmessage color&lt;br /&gt;
 * @param green         Green component of hudmessage color&lt;br /&gt;
 * @param blue          Blue component of hudmessage color&lt;br /&gt;
 * @param x             Location of the message on the x axis in percent&lt;br /&gt;
 * @param y             Location of the message on the y axis in percent&lt;br /&gt;
 * @param effects       Display effect&lt;br /&gt;
 * @param fxtime        Duration of the effect&lt;br /&gt;
 * @param holdtime      Time the message stays on screen&lt;br /&gt;
 * @param fadeintime    Time it takes the message to fully appear (fade-in)&lt;br /&gt;
 * @param fadeouttime   Time it takes the message to fully disappear (fade-out)&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native set_dhudmessage(red = 200, green = 100, blue = 0, Float:x = -1.0, Float:y = 0.35, effects = 0, Float:fxtime = 6.0, Float:holdtime = 12.0, Float:fadeintime = 0.1, Float:fadeouttime = 0.2);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=show_dhudmessage|header=Displays a director message on the client HUD.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Displays a director message on the client HUD.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Use set_dhudmessage to define how the message should look on screen.&lt;br /&gt;
 * @note Unlike the classic HUD message, which is channel-based, director&lt;br /&gt;
 *       messages are stack-based. You can have up to 8 messages displaying at&lt;br /&gt;
 *       once. If more are added, they will be overwritten in the order they were&lt;br /&gt;
 *       sent. There is no way to clear a specific message.&lt;br /&gt;
 * @note The message has a maximum length of 128 characters which this function&lt;br /&gt;
 *       will automatically enforce.&lt;br /&gt;
 * @note This functions return value behaves differently depending on what is&lt;br /&gt;
 *       used as the client index: If 0 is specified, then the function will&lt;br /&gt;
 *       return 0 if nothing has been sent (no client connected). If either a&lt;br /&gt;
 *       single client is specified, or there is at least one client connected,&lt;br /&gt;
 *       the number of printed characters will refer to the message that is sent&lt;br /&gt;
 *       last, to the client with the highest index.&lt;br /&gt;
 *&lt;br /&gt;
 * @param index     Client index, use 0 to display to all clients&lt;br /&gt;
 * @param message   Formatting rules&lt;br /&gt;
 * @param ...       Variable number of formatting parameters&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of printed characters&lt;br /&gt;
 * @error           If a single client is specified and the index is not within&lt;br /&gt;
 *                  the range of 1 to MaxClients, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native show_dhudmessage(index, const message[], any:...);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|elog_message|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=elog_message|header=Logs a message hookable by plugins to the current server log file.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Logs a message hookable by plugins to the current server log file.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The log will include a timestamp with the message.&lt;br /&gt;
 * @note The message can be hooked using &amp;quot;register_logevent&amp;quot;.&lt;br /&gt;
 *&lt;br /&gt;
 * @param string    Formatting rules&lt;br /&gt;
 * @param ...       Variable number of formatting parameters&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of printed characters&lt;br /&gt;
 */&lt;br /&gt;
native elog_message(const message[], any:...);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|client_printex|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=client_printex|header=Sends a predefined text message to player.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sends a predefined text message to player.&lt;br /&gt;
 * Predefined texts are default game messages which will be translated&lt;br /&gt;
 * to player's game language, e.g. #Game_join_ct.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Set index to 0 to send text globally.&lt;br /&gt;
 *&lt;br /&gt;
 * @note There does not necessarily have to be a total of 6 arguments.&lt;br /&gt;
 *       It will depend if message takes arguments, e.g.:&lt;br /&gt;
 *         client_printex(id, print_chat, &amp;quot;#Game_join_ct&amp;quot;, &amp;quot;Pimp Daddy&amp;quot;)&lt;br /&gt;
 *         client_printex(id, print_chat, &amp;quot;1&amp;quot;, &amp;quot;#Game_radio&amp;quot;, &amp;quot;Pimp Daddy&amp;quot;, &amp;quot;Hello world!&amp;quot;)&lt;br /&gt;
 *&lt;br /&gt;
 * @param index         Index of the player, use 0 to send to all players.&lt;br /&gt;
 * @param type          The message destination. See print_* constants.&lt;br /&gt;
 * @param msg_name      The custom or predefined message to send.&lt;br /&gt;
 * @param msg_param1    Optional message argument.&lt;br /&gt;
 * @param msg_param2    Optional message argument.&lt;br /&gt;
 * @param msg_param3    Optional message argument.&lt;br /&gt;
 * @param msg_param4    Optional message argument.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
stock client_printex(index, type, const msg_name[], const msg_param1[] = &amp;quot;&amp;quot;, const msg_param2[] = &amp;quot;&amp;quot;, const msg_param3[] = &amp;quot;&amp;quot;, const msg_param4[] = &amp;quot;&amp;quot;)&lt;br /&gt;
{&lt;br /&gt;
    new ch = msg_name[0];&lt;br /&gt;
&lt;br /&gt;
    // If not a predefined message, we don't care about it and forward directly to client_print.&lt;br /&gt;
    // Special case for radio message. msg_name is an index, msg_param1 #Game_radio*, etc. Checking index should be enough.&lt;br /&gt;
    if (ch != '#' &amp;amp;&amp;amp; (type != print_radio || !strtol(msg_name)))&lt;br /&gt;
    {&lt;br /&gt;
        return client_print(index, type, msg_name, msg_param1, msg_param2, msg_param3, msg_param4);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Even if message starts with '#', we should check its length for safety.&lt;br /&gt;
    new length = strlen(msg_name);&lt;br /&gt;
&lt;br /&gt;
    // If string is larger than expected, we forward to client_print which will cut message properly.&lt;br /&gt;
    // This means also this can't be a predefined game message.&lt;br /&gt;
    //   Max console length: 128 = \n (126) + \0 (127)&lt;br /&gt;
    //   Max SayText length: 192 = \n (190) + \0 (191)&lt;br /&gt;
    if ((length &amp;gt; 126 &amp;amp;&amp;amp; (print_notify &amp;lt;= type &amp;lt;= print_console)) &lt;br /&gt;
    || ( length &amp;gt; 190 &amp;amp;&amp;amp; (print_chat   &amp;lt;= type &amp;lt;= print_radio)))&lt;br /&gt;
    {&lt;br /&gt;
        return client_print(index, type, msg_name, msg_param1, msg_param2, msg_param3, msg_param4);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    static msgTextMsg; &lt;br /&gt;
    if (!msgTextMsg) &lt;br /&gt;
    { &lt;br /&gt;
        msgTextMsg = get_user_msgid(&amp;quot;TextMsg&amp;quot;); &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    message_begin(index &amp;gt; 0 ? MSG_ONE_UNRELIABLE : MSG_BROADCAST, msgTextMsg, {0,0,0}, index);&lt;br /&gt;
    write_byte(type);&lt;br /&gt;
    write_string(msg_name);&lt;br /&gt;
    if (msg_param1[0]) { write_string(msg_param1); }&lt;br /&gt;
    if (msg_param2[0]) { write_string(msg_param2); }&lt;br /&gt;
    if (msg_param3[0]) { write_string(msg_param3); }&lt;br /&gt;
    if (msg_param4[0]) { write_string(msg_param4); }&lt;br /&gt;
    message_end();&lt;br /&gt;
    &lt;br /&gt;
    return 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Others '''&lt;br /&gt;
&lt;br /&gt;
* Added {{tt|MSG_INIT}} support in {{tt|message_begin}} native&lt;br /&gt;
* Set {{tt|set_hudmessage}} default channel to {{tt|-1}} to reflect auto-channeling support&lt;br /&gt;
&lt;br /&gt;
=== String ===&lt;br /&gt;
&lt;br /&gt;
* Constants and stocks from {{tt|string.inc}} have been moved in their own files {{tt|string_const.inc}} and {{tt|string_stocks.inc}}.&lt;br /&gt;
* {{tt|strlen}} has been moved from {{tt|core.inc}} to {{tt|string.inc}}.&lt;br /&gt;
* {{tt|strbreak}} is now replaced by a backwards compatibility stock.&lt;br /&gt;
&lt;br /&gt;
''' Conversion '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|strtol|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=strtol|header=Parses the {{tt|string|bgcolor=white}} interpreting its content as an integral number of the specified  {{tt|base|bgcolor=white}}, which is returned as integer value. &amp;lt;br /&amp;gt;The function also sets the value of {{tt|endPos|bgcolor=white}} to point to the position of the first character after the number.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Parses the 'string' interpreting its content as an integral number of the specified 'base', &lt;br /&gt;
 * which is returned as integer value. The function also sets the value of 'endPos' to point &lt;br /&gt;
 * to the position of the first character after the number.&lt;br /&gt;
 * &lt;br /&gt;
 * This is the same as C++ strtol function with a difference on second param.&lt;br /&gt;
 * &lt;br /&gt;
 * The function first discards as many whitespace characters as necessary until the first &lt;br /&gt;
 * non-whitespace character is found. Then, starting from this character, takes as many &lt;br /&gt;
 * characters as possible that are valid following a syntax that depends on the 'base' parameter,&lt;br /&gt;
 * and interprets them as a numerical value. Finally, a position of the first character following&lt;br /&gt;
 * the integer representation in 'string' is stored in 'endPos'.&lt;br /&gt;
 * &lt;br /&gt;
 * If the value of 'base' is zero, the syntax expected is similar to that of integer constants, &lt;br /&gt;
 * which is formed by a succession of :&lt;br /&gt;
 *    An optional sign character (+ or -)&lt;br /&gt;
 *    An optional prefix indicating octal or hexadecimal base (&amp;quot;0&amp;quot; or &amp;quot;0x&amp;quot;/&amp;quot;0X&amp;quot; respectively)&lt;br /&gt;
 *    A sequence of decimal digits (if no base prefix was specified) or either octal or hexadecimal digits if a specific prefix is present&lt;br /&gt;
 *&lt;br /&gt;
 * If the 'base' value is between 2 and 36, the format expected for the integral number is a succession &lt;br /&gt;
 * of any of the valid digits and/or letters needed to represent integers of the specified radix &lt;br /&gt;
 * (starting from '0' and up to 'z'/'Z' for radix 36). The sequence may optionally be preceded by &lt;br /&gt;
 * a sign (either + or -) and, if base is 16, an optional &amp;quot;0x&amp;quot; or &amp;quot;0X&amp;quot; prefix.&lt;br /&gt;
 *&lt;br /&gt;
 * If the first sequence of non-whitespace characters in 'string' is not a valid integral number&lt;br /&gt;
 * as defined above, or if no such sequence exists because either 'string' is empty or it contains&lt;br /&gt;
 * only whitespace characters, no conversion is performed.&lt;br /&gt;
 *&lt;br /&gt;
 * @param string    The string to parse.&lt;br /&gt;
 * @param endPos    The position of the first character following the number.&lt;br /&gt;
 *                  On success and when containing only numbers, position is at the end of string, meaning equal to 'string' length.&lt;br /&gt;
 *                  On failure, position is sets always to 0.&lt;br /&gt;
 * @param base      The numerical base (radix) that determines the valid characters and their interpretation.&lt;br /&gt;
 *                  If this is 0, the base used is determined by the format in the sequence.&lt;br /&gt;
 * @return          On success, the function returns the converted integral number as integer value.&lt;br /&gt;
 *                  If no valid conversion could be performed, a zero value is returned.&lt;br /&gt;
 *                  If the value read is out of the range of representable values by a cell, &lt;br /&gt;
 *                  the function returns 'cellmin' or 'cellmax'.&lt;br /&gt;
 */&lt;br /&gt;
native strtol(const string[], &amp;amp;endPos = 0, base = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|strtof|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=strtof|header=Parses the {{tt|string|bgcolor=white}} interpreting its content as an floating point number and returns its value as a float. &amp;lt;br /&amp;gt;The function also sets the value of {{tt|endPos|bgcolor=white}} to point to the position of the first character after the number.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Parses the 'string' interpreting its content as an floating point number and returns its value as a float.&lt;br /&gt;
 * The function also sets the value of 'endPos' to point to the position of the first character after the number.&lt;br /&gt;
 * &lt;br /&gt;
 * This is the same as C++ strtod function with a difference on second param.&lt;br /&gt;
 * &lt;br /&gt;
 * The function first discards as many whitespace characters as necessary until the first &lt;br /&gt;
 * non-whitespace character is found. Then, starting from this character, takes as many &lt;br /&gt;
 * characters as possible that are valid and interprets them as a numerical value. &lt;br /&gt;
 * Finally, a position of the first character following the float representation in 'string' &lt;br /&gt;
 * is stored in 'endPos'.&lt;br /&gt;
 * &lt;br /&gt;
 * If the first sequence of non-whitespace characters in 'string' is not a valid float number&lt;br /&gt;
 * as defined above, or if no such sequence exists because either 'string' is empty or it contains&lt;br /&gt;
 * only whitespace characters, no conversion is performed.&lt;br /&gt;
 *&lt;br /&gt;
 * @param string    The string to parse.&lt;br /&gt;
 * @param endPos    The position of the first character following the number.&lt;br /&gt;
 *                  On success and when containing only numbers, position is at the end of string, meaning equal to 'string' length.&lt;br /&gt;
 *                  On failure, position is sets always to 0.&lt;br /&gt;
 * @return          On success, the function returns the converted floating point number as float value.&lt;br /&gt;
 *                  If no valid conversion could be performed, a zero value is returned.&lt;br /&gt;
 */&lt;br /&gt;
native Float:strtof(const string[], &amp;amp;endPos = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Format specifier '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Specifier&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|%b|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Binary digits in the value&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|%n|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Requires a client index. Expands to a string containing the player's name. &amp;lt;br /&amp;gt;If the client index is 0, the string will be: {{tt|Console}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|%N|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Requires a client index. Expands to {{tt|1&amp;lt;2&amp;gt;&amp;lt;3&amp;gt;&amp;lt;4&amp;gt;}} where {{tt|1}} is the player's name, {{tt|2}} is the player's userid, {{tt|3}} is the player's SteamID, and {{tt|4}} the player's team name. &amp;lt;br /&amp;gt;If the client index is 0, the string will be: {{tt|Console&amp;lt;0&amp;gt;&amp;lt;Console&amp;gt;&amp;lt;Console&amp;gt;}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|%l|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Translates a phrase from a key. Similar to {{tt|%L}} with the difference it will use the client's index set internally by the function.&amp;lt;br /&amp;gt;This is only allowed in functions which act directly on one or more clients.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|To complement this, a new {{hidden|id=SetGlobalTransTarget|labelonly=yes}} {{tt|SetGlobalTransTarget|bgcolor=white}} native to set the current index has been added.&amp;lt;br /&amp;gt;&lt;br /&gt;
This is useful to be used before with natives which are not player-oriented&amp;quot;, like a bunch of {{tt|formatex|bgcolor=whitet}}.|opt=full-border}}&lt;br /&gt;
{{hidden|id=SetGlobalTransTarget|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the global language target.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This is useful for creating functions&lt;br /&gt;
 *       that will be compatible with the %l format specifier. Note that invalid&lt;br /&gt;
 *       indexes can be specified but the error will occur during translation,&lt;br /&gt;
 *       not during this function call.&lt;br /&gt;
 *&lt;br /&gt;
 * @param client    Client index or LANG_SERVER&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native SetGlobalTransTarget(client);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=trans-l|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=trans-l|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
client_print(index, print_chat, &amp;quot;%L&amp;quot;, index, &amp;quot;EGG&amp;quot;);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
can be now&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
client_print(index, print_chat, &amp;quot;%l&amp;quot;, &amp;quot;EGG&amp;quot;);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Formatting '''&lt;br /&gt;
&lt;br /&gt;
* {{tt|set_fail_state}} has now the ability to format a text.&lt;br /&gt;
* A new native for simple inline formatting:&lt;br /&gt;
:{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|fmt|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=fmt|header=Formats and returns a string according to the AMX Mod X format rules.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|This should only be used for simple inline formatting like in the above example. &amp;lt;br /&amp;gt;Avoid using this function to store strings into variables as an additional copying step is required.|opt=full-border}}&lt;br /&gt;
{{alert|info|Note:|The buffer size is defined by {{tt|MAX_FMT_LENGTH}}.|opt=full-border}}&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=menu_additem-ex|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=menu_additem-ex|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
menu_additem(menu, fmt(&amp;quot;My first %s&amp;quot;, &amp;quot;item&amp;quot;))&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Formats and returns a string according to the AMX Mod X format rules&lt;br /&gt;
 * (see documentation).&lt;br /&gt;
 *&lt;br /&gt;
 * @note Example: menu_additem(menu, fmt(&amp;quot;My first %s&amp;quot;, &amp;quot;item&amp;quot;)).&lt;br /&gt;
 * @note This should only be used for simple inline formatting like in the above example.&lt;br /&gt;
 *       Avoid using this function to store strings into variables as an additional&lt;br /&gt;
 *       copying step is required.&lt;br /&gt;
 * @note The buffer size is defined by MAX_FMT_LENGTH.&lt;br /&gt;
 *&lt;br /&gt;
 * @param format        Formatting rules.&lt;br /&gt;
 * @param ...           Variable number of format parameters.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Formatted string&lt;br /&gt;
 */&lt;br /&gt;
native [MAX_FMT_LENGTH]fmt(const format[], any:...);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Others '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|strtok2|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=strtok2|header=Breaks a string in two by token.&lt;br /&gt;
 &lt;br /&gt;
{{alert|info|Note:|This function has been added due to {{tt|strtok}} being buggy in some situations.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
 {{alert|info|Trim flags:|{{hidden|id=trim-flags|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=trim-flags|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Below are the trim flags for strtok2&lt;br /&gt;
 *&lt;br /&gt;
 * You can specify how the left and right buffers will&lt;br /&gt;
 * be trimmed by strtok2. LTRIM trims spaces from the&lt;br /&gt;
 * left side. RTRIM trims from the right side.&lt;br /&gt;
 *&lt;br /&gt;
 * The defines TRIM_INNER, TRIM_OUTER and TRIM_FULL are&lt;br /&gt;
 * shorthands for commonly used flag combinations.&lt;br /&gt;
 *&lt;br /&gt;
 * When the initial string is trimmed, using TRIM_INNER&lt;br /&gt;
 * for all subsequent strtok2 calls will ensure that left&lt;br /&gt;
 * and right are always trimmed from both sides.&lt;br /&gt;
 *&lt;br /&gt;
 * Examples:&lt;br /&gt;
 * str1[] = &amp;quot;  This is  *  some text  &amp;quot;&lt;br /&gt;
 * strtok2(str1, left, 24, right, 24, '*', TRIM_FULL)&lt;br /&gt;
 *  left will be &amp;quot;This is&amp;quot;, right will be &amp;quot;some text&amp;quot;&lt;br /&gt;
 *&lt;br /&gt;
 * str2[] = &amp;quot;  Here is  |  an  | example  &amp;quot;&lt;br /&gt;
 * trim(str2)&lt;br /&gt;
 * strtok2(str2, left, 24, right, 24, '|', TRIM_INNER)&lt;br /&gt;
 *  left will be &amp;quot;Here is&amp;quot;, right will be &amp;quot;an  | example&amp;quot;&lt;br /&gt;
 * strtok2(right, left, 24, right, 24, '|', TRIM_INNER)&lt;br /&gt;
 *  left will be &amp;quot;an&amp;quot;, right will be &amp;quot;example&amp;quot;&lt;br /&gt;
 *&lt;br /&gt;
 * str3[] = &amp;quot;  One  -  more  &amp;quot;&lt;br /&gt;
 * strtok2(str3, left, 24, right, 24, '-', TRIM_OUTER)&lt;br /&gt;
 *  left will be &amp;quot;One  &amp;quot;, right will be &amp;quot;  more&amp;quot;&lt;br /&gt;
 *&lt;br /&gt;
 * str4[] = &amp;quot;  Final  .  example  &amp;quot;&lt;br /&gt;
 * strtok2(str4, left, 24, right, 24, '.', LTRIM_LEFT|LTRIM_RIGHT)&lt;br /&gt;
 *  left will be &amp;quot;Final  &amp;quot;, right will be &amp;quot;example  &amp;quot;&lt;br /&gt;
*/&lt;br /&gt;
#define LTRIM_LEFT (1&amp;lt;&amp;lt;0)&lt;br /&gt;
#define RTRIM_LEFT (1&amp;lt;&amp;lt;1)&lt;br /&gt;
#define LTRIM_RIGHT (1&amp;lt;&amp;lt;2)&lt;br /&gt;
#define RTRIM_RIGHT (1&amp;lt;&amp;lt;3)&lt;br /&gt;
&lt;br /&gt;
#define TRIM_INNER RTRIM_LEFT|LTRIM_RIGHT&lt;br /&gt;
#define TRIM_OUTER LTRIM_LEFT|RTRIM_RIGHT&lt;br /&gt;
#define TRIM_FULL TRIM_OUTER|TRIM_INNER&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Breaks a string in two by token.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 *&lt;br /&gt;
 * @param text			String to tokenize&lt;br /&gt;
 * @param left			Buffer to store left half&lt;br /&gt;
 * @param llen			Size of left buffer&lt;br /&gt;
 * @param right			Buffer to store right half&lt;br /&gt;
 * @param rlen			Size of right buffer&lt;br /&gt;
 * @param token			Token to split by&lt;br /&gt;
 * @param trim			Flags for trimming behavior, see above&lt;br /&gt;
 *&lt;br /&gt;
 * @return				Returns position of token in string if found, &lt;br /&gt;
 *						-1 if token was not found&lt;br /&gt;
 */&lt;br /&gt;
native strtok2(const text[], left[], const llen, right[], const rlen, const token = ' ', const trim = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|explode_string|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=explode_string|header=Breaks a string into pieces and stores each piece into an array of buffers.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Breaks a string into pieces and stores each piece into an array of buffers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param text              The string to split.&lt;br /&gt;
 * @param split             The string to use as a split delimiter.&lt;br /&gt;
 * @param buffers           An array of string buffers (2D array).&lt;br /&gt;
 * @param maxStrings        Number of string buffers (first dimension size).&lt;br /&gt;
 * @param maxStringLength   Maximum length of each string buffer.&lt;br /&gt;
 * @param copyRemainder     False (default) discard excess pieces, true to ignore&lt;br /&gt;
 *                          delimiters after last piece.&lt;br /&gt;
 * @return                  Number of strings retrieved.&lt;br /&gt;
 */&lt;br /&gt;
stock explode_string(const text[], const split[], buffers[][], maxStrings, maxStringLength, bool:copyRemainder = false)&lt;br /&gt;
{&lt;br /&gt;
    new reloc_idx, idx, total;&lt;br /&gt;
&lt;br /&gt;
    if (maxStrings &amp;lt; 1 || !split[0])&lt;br /&gt;
    {&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    while ((idx = split_string(text[reloc_idx], split, buffers[total], maxStringLength)) != -1)&lt;br /&gt;
    {&lt;br /&gt;
        reloc_idx += idx;&lt;br /&gt;
        if (++total == maxStrings)&lt;br /&gt;
        {&lt;br /&gt;
            if (copyRemainder)&lt;br /&gt;
            {&lt;br /&gt;
                copy(buffers[total-1], maxStringLength, text[reloc_idx-idx]);&lt;br /&gt;
            }&lt;br /&gt;
            return total;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    copy(buffers[total++], maxStringLength, text[reloc_idx]);&lt;br /&gt;
&lt;br /&gt;
    return total;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|implode_strings|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=implode_strings|header=Joins an array of strings into one string, with a {{tt|join|bgcolor=white}} string inserted in between each given string.&amp;lt;br /&amp;gt;This function complements {{tt|explode_string|bgcolor=white}}.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Joins an array of strings into one string, with a &amp;quot;join&amp;quot; string inserted in&lt;br /&gt;
 * between each given string.  This function complements ExplodeString.&lt;br /&gt;
 *&lt;br /&gt;
 * @param strings       An array of strings.&lt;br /&gt;
 * @param numStrings    Number of strings in the array.&lt;br /&gt;
 * @param join          The join string to insert between each string.&lt;br /&gt;
 * @param buffer        Output buffer to write the joined string to.&lt;br /&gt;
 * @param maxLength     Maximum length of the output buffer.&lt;br /&gt;
 * @return              Number of bytes written to the output buffer.&lt;br /&gt;
 */&lt;br /&gt;
stock implode_strings(const strings[][], numStrings, const join[], buffer[], maxLength)&lt;br /&gt;
{&lt;br /&gt;
    new total, length, part_length;&lt;br /&gt;
    new join_length = strlen(join);&lt;br /&gt;
&lt;br /&gt;
    for (new i=0; i&amp;lt;numStrings; i++)&lt;br /&gt;
    {&lt;br /&gt;
        length = copy(buffer[total], maxLength-total, strings[i]);&lt;br /&gt;
        total += length;&lt;br /&gt;
&lt;br /&gt;
        if (length &amp;lt; part_length)&lt;br /&gt;
        {&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (i != numStrings - 1)&lt;br /&gt;
        {&lt;br /&gt;
            length = copy(buffer[total], maxLength-total, join);&lt;br /&gt;
            total += length;&lt;br /&gt;
&lt;br /&gt;
            if (length &amp;lt; join_length)&lt;br /&gt;
            {&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return total;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' UTF-8 '''&lt;br /&gt;
&lt;br /&gt;
An effort has been made to provide UTF-8 safety for formatting-capable functions.&lt;br /&gt;
This includes precision with {{tt|%s}} e.g. {{tt|%.12s}}.&lt;br /&gt;
&lt;br /&gt;
Few specific functions have been updated as well:&lt;br /&gt;
&lt;br /&gt;
* {{tt|console_print}}&lt;br /&gt;
* {{tt|client_print}}, {{tt|client_print_color}}&lt;br /&gt;
* {{tt|get_user_name}}&lt;br /&gt;
* {{tt|get_concmd}}, {{tt|get_clcmd}}, {{tt|get_srvcmd}}&lt;br /&gt;
* {{tt|get_cvar_string}}, {{tt|get_pcvar_string}}&lt;br /&gt;
* {{tt|format_time}}&lt;br /&gt;
* {{tt|read_data}}&lt;br /&gt;
* {{tt|get_localinfo}}&lt;br /&gt;
* {{tt|read_argv}}, {{tt|read_args}}&lt;br /&gt;
* {{tt|read_logdata}}, {{tt|read_logargv}}&lt;br /&gt;
* {{tt|get_module}}&lt;br /&gt;
* {{tt|read_file}}&lt;br /&gt;
* {{tt|fgets}}&lt;br /&gt;
* {{tt|ReadPackString}}&lt;br /&gt;
* {{tt|ArrayGetString}}&lt;br /&gt;
* {{tt|TrieGetString}}&lt;br /&gt;
* {{tt|strtok}}, {{tt|strtok2}}&lt;br /&gt;
* {{tt|strbreak}}&lt;br /&gt;
* {{tt|isdigit}}, {{tt|isalnum}}, {{tt|isspace}}, {{tt|isalpha}}&lt;br /&gt;
&lt;br /&gt;
UTF-8 support has been added in the following functions:&lt;br /&gt;
&lt;br /&gt;
* {{tt|containi}}&lt;br /&gt;
* {{tt|strfind}} (with ignorecase set)&lt;br /&gt;
* {{tt|strcmp}} (with ignorecase set)&lt;br /&gt;
* {{tt|strncmp}} (with ignorecase set)&lt;br /&gt;
* {{tt|equali}}&lt;br /&gt;
* {{tt|replace_string}} (with ignorecase set)&lt;br /&gt;
* {{tt|replace_stringex}} (with ignorecase set)&lt;br /&gt;
* {{tt|get_players}} (with name and ignorecase flags set)&lt;br /&gt;
* {{tt|find_player}} (with name and ignorecase flags set)&lt;br /&gt;
&lt;br /&gt;
New natives have been added:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|is_char_upper|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|is_char_lower|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|is_char_mb|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=is_char_upper|header=Returns whether an alphabetic character is uppercase.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns whether an alphabetic character is uppercase.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 * @note Multi-byte characters will always return false.&lt;br /&gt;
 *&lt;br /&gt;
 * @param ch			Character to test.&lt;br /&gt;
 * @return				True if character is uppercase, otherwise false.&lt;br /&gt;
 */&lt;br /&gt;
native bool:is_char_upper(ch);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=is_char_lower|header=Returns whether an alphabetic character is lowercase.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns whether an alphabetic character is lowercase.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 * @note Multi-byte characters will always return false.&lt;br /&gt;
 *&lt;br /&gt;
 * @param ch			Character to test.&lt;br /&gt;
 * @return				True if character is lowercase, otherwise false.&lt;br /&gt;
 */&lt;br /&gt;
native bool:is_char_lower(ch);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=is_char_mb|header=Returns if a character is multi-byte or not.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns if a character is multi-byte or not.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 *&lt;br /&gt;
 * @param ch			Character to test.&lt;br /&gt;
 * @return				0 for a normal 7-bit ASCII character,&lt;br /&gt;
 *						otherwise number of bytes in multi-byte character.&lt;br /&gt;
 */&lt;br /&gt;
native is_char_mb(ch);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|is_string_category|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=is_string_category|header=Checks if the input string conforms to the category specified by the flags.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Checks if the input string conforms to the category specified by the flags.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This function can be used to check if the code points in a string are part&lt;br /&gt;
 *       of a category. Valid flags are part of the UTF8C_* list of defines.&lt;br /&gt;
 *       The category for a code point is defined as part of the entry in&lt;br /&gt;
 *       UnicodeData.txt, the data file for the Unicode code point database.&lt;br /&gt;
 * @note Flags parameter must be a combination of UTF8C_* flags or a single UTF8C_IS* flag.&lt;br /&gt;
 *       In order to main backwards compatibility with POSIX functions like `isdigit`&lt;br /&gt;
 *       and `isspace`, compatibility flags have been provided. Note, however, that&lt;br /&gt;
 *       the result is only guaranteed to be correct for code points in the Basic&lt;br /&gt;
 *       Latin range, between U+0000 and 0+007F. Combining a compatibility flag with&lt;br /&gt;
 *       a regular category flag will result in undefined behavior.&lt;br /&gt;
 * @note The function is greedy. This means it will try to match as many code&lt;br /&gt;
 *       points with the matching category flags as possible and return the offset in&lt;br /&gt;
 *       the input in bytes.&lt;br /&gt;
 *&lt;br /&gt;
 * @param input         The string to check&lt;br /&gt;
 * @param input_size    Size of the string, use 1 to check one character regardless its size&lt;br /&gt;
 * @param flags         Requested category, see UTF8C_* flags&lt;br /&gt;
 * @param output_size   Number of bytes in the input that conform to the specified&lt;br /&gt;
 *                      category flags&lt;br /&gt;
 * @return              True if the whole input of `input_size` conforms to the specified&lt;br /&gt;
 *                      category flags, false otherwise&lt;br /&gt;
 */&lt;br /&gt;
native bool:is_string_category(const input[], input_size, flags, &amp;amp;output_size = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_char_bytes|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_char_bytes|header=Returns the number of bytes a character is using.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Returns the number of bytes a character is using.  This is&lt;br /&gt;
 * for multi-byte characters (UTF-8).  For normal ASCII characters,&lt;br /&gt;
 * this will return 1.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 *&lt;br /&gt;
 * @param source		Source input string.&lt;br /&gt;
 * @return				Number of bytes the current character uses.&lt;br /&gt;
 */&lt;br /&gt;
native get_char_bytes(const source[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|mb_strotolower|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|mb_strtoupper|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|mb_ucfirst|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|mb_strtotitle|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=mb_strotolower|header=Performs a multi-byte safe (UTF-8) conversion of all chars in string to lower case.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Performs a multi-byte safe (UTF-8) conversion of all chars in string to lower case.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Although most code points can be converted in-place, there are notable&lt;br /&gt;
 *       exceptions and the final length can vary.&lt;br /&gt;
 * @note Case mapping is not reversible. That is, toUpper(toLower(x)) != toLower(toUpper(x)).&lt;br /&gt;
 *&lt;br /&gt;
 * @param string		The string to convert.&lt;br /&gt;
 * @param maxlength		Optional size of the buffer. If 0, the length of the original string&lt;br /&gt;
 *                      will be used instead.&lt;br /&gt;
 *&lt;br /&gt;
 * @return				Number of bytes written.&lt;br /&gt;
 */&lt;br /&gt;
native mb_strtolower(string[], maxlength = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=mb_strtoupper|header=Performs a multi-byte safe (UTF-8) conversion of all chars in string to upper case.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Performs a multi-byte safe (UTF-8) conversion of all chars in string to upper case.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Although most code points can be converted in-place, there are notable&lt;br /&gt;
 *       exceptions and the final length can vary.&lt;br /&gt;
 * @note Case mapping is not reversible. That is, toUpper(toLower(x)) != toLower(toUpper(x)).&lt;br /&gt;
 *&lt;br /&gt;
 * @param string		The string to convert.&lt;br /&gt;
 * @param maxlength		Optional size of the buffer. If 0, the length of the original string&lt;br /&gt;
 *                      will be used instead.&lt;br /&gt;
 *&lt;br /&gt;
 * @return				Number of bytes written.&lt;br /&gt;
 */&lt;br /&gt;
native mb_strtoupper(string[], maxlength = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=mb_ucfirst|header=Performs a multi-byte safe (UTF-8) conversion of a string's first character to upper case.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Performs a multi-byte safe (UTF-8) conversion of a string's first character to upper case.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Although most code points can be converted in-place, there are notable&lt;br /&gt;
 *       exceptions and the final length can vary.&lt;br /&gt;
 *&lt;br /&gt;
 * @param string		The string to convert.&lt;br /&gt;
 * @param maxlength		Optional size of the buffer. If 0, the length of the original string&lt;br /&gt;
 *                      will be used instead.&lt;br /&gt;
 *&lt;br /&gt;
 * @return				Number of bytes written.&lt;br /&gt;
 */&lt;br /&gt;
native mb_ucfirst(string[], maxlength = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=mb_strtotitle|header=Performs a multi-byte safe (UTF-8) conversion of all chars in string to title case.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Performs a multi-byte safe (UTF-8) conversion of all chars in string to title case.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Although most code points can be converted in-place, there are notable&lt;br /&gt;
 *       exceptions and the final length can vary.&lt;br /&gt;
 * @note Any type of punctuation can break up a word, even if this is&lt;br /&gt;
 *       not grammatically valid. This happens because the titlecasing algorithm&lt;br /&gt;
 *       does not and cannot take grammar rules into account.&lt;br /&gt;
 * @note Examples:&lt;br /&gt;
 *         The running man                      | The Running Man&lt;br /&gt;
 *	       NATO Alliance                        | Nato Alliance&lt;br /&gt;
 *	       You're amazing at building libraries | You'Re Amazing At Building Libraries&lt;br /&gt;
 *&lt;br /&gt;
 * @param string		The string to convert.&lt;br /&gt;
 * @param maxlength		Optional size of the buffer. If 0, the length of the original string&lt;br /&gt;
 *                      will be used instead.&lt;br /&gt;
 *&lt;br /&gt;
 * @return				Number of bytes written.&lt;br /&gt;
 */&lt;br /&gt;
native mb_strtotitle(string[], maxlength = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|replace_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|replace_stringex|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=replace_string|header=Given a string, replaces all occurrences of a search string with a replacement string.&lt;br /&gt;
 &lt;br /&gt;
{{alert|info|Note:|Similar to {{tt|replace_all|bgcolor=white}} stock, but implemented as native and with different algorithm.&amp;lt;br /&amp;gt;&lt;br /&gt;
This native doesn't error on bad buffer size and will smartly cut off the string in a way that pushes old data out.|opt=full-border}}&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Given a string, replaces all occurrences of a search string with a &lt;br /&gt;
 * replacement string.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Similar to replace_all() stock, but implemented as native and &lt;br /&gt;
 *       with different algorithm. This native doesn't error on bad &lt;br /&gt;
 *       buffer size and will smartly cut off the string in a way &lt;br /&gt;
 *       that pushes old data out.&lt;br /&gt;
 *	&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 * @note This supports multi-byte characters (UTF-8) on case insensitive comparison.&lt;br /&gt;
 *&lt;br /&gt;
 * @param text			String to perform search and replacements on.&lt;br /&gt;
 * @param maxlength		Maximum length of the string buffer.&lt;br /&gt;
 * @param search		String to search for.&lt;br /&gt;
 * @param replace		String to replace the search string with.&lt;br /&gt;
 * @param caseSensitive	If true (default), search is case sensitive.&lt;br /&gt;
 *&lt;br /&gt;
 * @return				Number of replacements that were performed.&lt;br /&gt;
 */&lt;br /&gt;
native replace_string(text[], maxlength, const search[], const replace[], bool:caseSensitive = true);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=replace_string|header=Given a string, replaces the first occurrence of a search string with a replacement string.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|Similar to {{tt|replace|bgcolor=white}} native, but implemented as native and with different algorithm.&amp;lt;br /&amp;gt;&lt;br /&gt;
This native doesn't error on bad buffer size and will smartly cut off the string in a way that pushes old data out.|opt=full-border}}&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Given a string, replaces the first occurrence of a search string with a &lt;br /&gt;
 * replacement string.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Similar to replace() native, but implemented with more options and &lt;br /&gt;
 *       with different algorithm. This native doesn't error on bad &lt;br /&gt;
 *       buffer size and will smartly cut off the string in a way &lt;br /&gt;
 *       that pushes old data out.&lt;br /&gt;
 *	&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 * @note This supports multi-byte characters (UTF-8) on case insensitive comparison.&lt;br /&gt;
 *&lt;br /&gt;
 * @param text			String to perform search and replacements on.&lt;br /&gt;
 * @param maxlength		Maximum length of the string buffer.&lt;br /&gt;
 * @param search		String to search for.&lt;br /&gt;
 * @param replace		String to replace the search string with.&lt;br /&gt;
 * @param searchLen		If higher than -1, its value will be used instead of&lt;br /&gt;
 *						a strlen() call on the search parameter.&lt;br /&gt;
 * @param replaceLen	If higher than -1, its value will be used instead of&lt;br /&gt;
 *						a strlen() call on the replace parameter.&lt;br /&gt;
 * @param caseSensitive	If true (default), search is case sensitive.&lt;br /&gt;
 *&lt;br /&gt;
 * @return				Index into the buffer (relative to the start) from where&lt;br /&gt;
 *						the last replacement ended, or -1 if no replacements were&lt;br /&gt;
 *						made.&lt;br /&gt;
 */&lt;br /&gt;
native replace_stringex(text[], maxlength, const search[], const replace[], searchLen = -1, replaceLen = -1, bool:caseSensitive = true);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|strncmp|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=strncmp|header=Compares two strings parts lexographically.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Compares two strings parts lexographically.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 * @note This supports multi-byte characters (UTF-8) on case insensitive comparison.&lt;br /&gt;
 *&lt;br /&gt;
 * @param string1		First string (left).&lt;br /&gt;
 * @param string2		Second string (right).&lt;br /&gt;
 * @param num			Number of characters to compare.&lt;br /&gt;
 * @param ignorecase	If true, comparison is case insensitive.&lt;br /&gt;
 *						If false (default), comparison is case sensitive.&lt;br /&gt;
 * @return				-1 if string1 &amp;lt; string2&lt;br /&gt;
 *						0 if string1 == string2&lt;br /&gt;
 *						1 if string1 &amp;gt; string2&lt;br /&gt;
 */&lt;br /&gt;
native strncmp(const string1[], const string2[], num, bool:ignorecase = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
New stocks:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|char_to_upper|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=char_to_upper|header=Returns an uppercase character to a lowercase character.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns an uppercase character to a lowercase character.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 *&lt;br /&gt;
 * @param chr           Characer to convert.&lt;br /&gt;
 * @return              Lowercase character on success,&lt;br /&gt;
 *                      no change on failure.&lt;br /&gt;
 */&lt;br /&gt;
stock char_to_upper(chr)&lt;br /&gt;
{&lt;br /&gt;
    if (is_char_lower(chr))&lt;br /&gt;
    {&lt;br /&gt;
        return (chr &amp;amp; ~(1&amp;lt;&amp;lt;5));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return chr;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|char_to_lower|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=char_to_lower|header=Returns a lowercase character to an uppercase character.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns a lowercase character to an uppercase character.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Only available in 1.8.3 and above.&lt;br /&gt;
 *&lt;br /&gt;
 * @param chr           Characer to convert.&lt;br /&gt;
 * @return              Uppercase character on success,&lt;br /&gt;
 *                      no change on failure.&lt;br /&gt;
 */&lt;br /&gt;
stock char_to_lower(chr)&lt;br /&gt;
{&lt;br /&gt;
    if (is_char_upper(chr))&lt;br /&gt;
    {&lt;br /&gt;
        return (chr | (1&amp;lt;&amp;lt;5));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return chr;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
== Existing module APIs additions ==&lt;br /&gt;
&lt;br /&gt;
=== AMXX SDK ===&lt;br /&gt;
&lt;br /&gt;
the following functions have been added:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Function&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|MF_SetAmxStringUTF8Char}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Sets UTF-8 string from char* input&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|MF_SetAmxStringUTF8Cell}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Sets UTF-8 string from cell* input&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|MF_GetAmxStringNull}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Gets string with {{tt|NULL_STRING}} support&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|MF_GetAmxVectorNull}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Gets a vector with {{tt|NULL_VECTOR}} support&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|MF_GetConfigManager}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | Gets the config manager for use with gamedata files&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== CStrike ===&lt;br /&gt;
&lt;br /&gt;
All hardcoded game datas are now moved to its own gamedata file located in {{tt|data/gamedata/modules.games/game.cstrike.txt}}.&amp;lt;br /&amp;gt;&lt;br /&gt;
See [[AMX_Mod_X_1.9_Release_Notes#Gamedata]] for more information.&lt;br /&gt;
&lt;br /&gt;
''' Constant '''&lt;br /&gt;
&lt;br /&gt;
Numerous constants from the game have added. See the [https://github.com/alliedmodders/amxmodx/blob/master/plugins/include/cstrike_const.inc cstrike_const.inc].&lt;br /&gt;
&lt;br /&gt;
Additionally for two natives:&lt;br /&gt;
* {{tt|CS_NORESET}} constant for use with {{tt|cs_set_user_team}} for skipping the model reset&lt;br /&gt;
* {{tt|TRAIN_*}} {{hidden|id=constants_cs|labelonly=yes}} constants for use with {{tt|cs_get_user_driving}}&lt;br /&gt;
&lt;br /&gt;
{{hidden|id=constants_cs|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Train status values&lt;br /&gt;
 */&lt;br /&gt;
#define TRAIN_ACTIVE  0x80&lt;br /&gt;
#define TRAIN_NEW     0xc0&lt;br /&gt;
&lt;br /&gt;
#define TRAIN_OFF     0x00&lt;br /&gt;
#define TRAIN_NEUTRAL 0x01&lt;br /&gt;
#define TRAIN_SLOW    0x02&lt;br /&gt;
#define TRAIN_MEDIUM  0x03&lt;br /&gt;
#define TRAIN_FAST    0x04&lt;br /&gt;
#define TRAIN_BACK    0x05&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Entity '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_create_entity|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_create_entity|header=Creates an entity using Counter-Strike's custom CreateNamedEntity wrapper.&lt;br /&gt;
 &lt;br /&gt;
{{alert|info|Note:|Unlike other mods CS keeps track of entities using a custom hashtable.&amp;lt;br /&amp;gt;&lt;br /&gt;
This function adds entities to this hashtable, providing benefits over the default CreateNamedEntity (used by {{tt|create_entity|bgcolor=white}} for example):&lt;br /&gt;
* Storing entities in a hashtable allows CS to improve classname lookup	performance compared to functions like FindEntityByString (used by {{tt|find_ent_by_class|bgcolor=white}} for example) that usually have to loop through all entities incrementally.&lt;br /&gt;
* As CS exclusively uses the hashtable for classname lookup, entities created using the default engine functions will not be found by the game. &amp;lt;br /&amp;gt;For example &amp;quot;weaponbox&amp;quot; entities are supposed to be automatically cleaned up on round restart but are not considered if they have not been added to the hashtable.|opt=full-border}}&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates an entity using Counter-Strike's custom CreateNamedEntity wrapper.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike other mods CS keeps track of entities using a custom hashtable.&lt;br /&gt;
 *       This function adds entities to this hashtable, providing benefits over&lt;br /&gt;
 *       the default CreateNamedEntity (used by create_entity() for example):&lt;br /&gt;
 *       - Storing entities in a hashtable allows CS to improve classname lookup&lt;br /&gt;
 *         performance compared to functions like FindEntityByString (used by&lt;br /&gt;
 *         find_ent_by_class() for example) that usually have to loop&lt;br /&gt;
 *         through all entities incrementally.&lt;br /&gt;
 *       - As CS exclusively uses the hashtable for classname lookup, entities&lt;br /&gt;
 *         created using the default engine functions will not be found by the&lt;br /&gt;
 *         game. For example &amp;quot;weaponbox&amp;quot; entities are supposed to be&lt;br /&gt;
 *         automatically cleaned up on round restart but are not considered if&lt;br /&gt;
 *         they have not been added to the hashtable.&lt;br /&gt;
 * @note The faster hashtable lookup can be utilized with cs_find_ent_by_class()&lt;br /&gt;
 * @note When creating an entity the classname has to be valid in the mod, as&lt;br /&gt;
 *       the engine needs to link the entity to an existing class internally.&lt;br /&gt;
 *       The classname string that is stored in the entvar struct&lt;br /&gt;
 *       (EV_SZ_classname) is separate from this association and can later be&lt;br /&gt;
 *       freely changed to serve other purposes.&lt;br /&gt;
 *&lt;br /&gt;
 * @param classname     Entity class name&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Index of the created entity (&amp;gt; 0), 0 otherwise&lt;br /&gt;
 */&lt;br /&gt;
native cs_create_entity(const classname[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_find_ent_by_class|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|cs_find_ent_by_owner|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_find_ent_by_class|header=Finds an entity in the world using Counter-Strike's custom FindEntityByString wrapper.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Finds an entity in the world using Counter-Strike's custom FindEntityByString&lt;br /&gt;
 * wrapper.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike other mods CS keeps track of entities using a custom hashtable.&lt;br /&gt;
 *       This function utilizes the hasthable and allows for considerably faster&lt;br /&gt;
 *       classname lookup compared to the default FindEntityByString (used by&lt;br /&gt;
 *       find_ent_by_class() for example).&lt;br /&gt;
 * @note This exclusively considers entities in the hashtable, created by the&lt;br /&gt;
 *       game itself, using cs_create_entity(), or added via cs_set_ent_class().&lt;br /&gt;
 *&lt;br /&gt;
 * @param start_index   Entity index to start searching from. -1 to start from&lt;br /&gt;
 *                      the first entity&lt;br /&gt;
 * @param classname     Classname to search for&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Entity index &amp;gt; 0 if found, 0 otherwise&lt;br /&gt;
 */&lt;br /&gt;
native cs_find_ent_by_class(start_index, const classname[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=cs_find_ent_by_owner|header=Finds an entity in the world using Counter-Strike's custom FindEntityByString wrapper, matching by owner. |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Finds an entity in the world using Counter-Strike's custom FindEntityByString&lt;br /&gt;
 * wrapper, matching by owner.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike other mods CS keeps track of entities using a custom hashtable.&lt;br /&gt;
 *       This function utilizes the hasthable and allows for considerably faster&lt;br /&gt;
 *       classname lookup compared to the default FindEntityByString (used by&lt;br /&gt;
 *       find_ent_by_owner() for example).&lt;br /&gt;
 * @note This exclusively considers entities in the hashtable, created by the&lt;br /&gt;
 *       game itself, using cs_create_entity(), or added via cs_set_ent_class().&lt;br /&gt;
 *&lt;br /&gt;
 * @param start_index   Entity index to start searching from. -1 to start from&lt;br /&gt;
 *                      the first entity&lt;br /&gt;
 * @param classname     Classname to search for&lt;br /&gt;
 * @param owner         Entity index to search for entity's owner&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Entity index &amp;gt; 0 if found, 0 otherwise&lt;br /&gt;
 */&lt;br /&gt;
native cs_find_ent_by_owner(start_index, const classname[], owner);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{alert|info|Note:|Those functions utilize the hasthable and allows for considerably faster classname lookup compared to the default FindEntityByString (used by {{tt|find_ent_by_class|bgcolor=white}} for example).&amp;lt;br /&amp;gt;&lt;br /&gt;
 This exclusively considers entities in the hashtable, created by the game itself, using {{tt|cs_create_entity|bgcolor=white}}, or added via {{tt|cs_set_ent_class|bgcolor=white}}).|opt=full-border}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_set_ent_class|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_set_ent_class|header=Sets a custom classname of an entity.&lt;br /&gt;
 &lt;br /&gt;
 {{alert|info|Note:|This function adds or updates the classname in the hasthable as well.&amp;lt;br /&amp;gt;This is useful for use with {{tt|cs_find_ent_by_class|bgcolor=white}} and {{tt|cs_find_ent_by_owner|bgcolor=white}}.|opt=full-border}}&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a custom classname of an entity.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike other mods CS keeps track of entities using a custom hashtable.&lt;br /&gt;
 *       This function adds or updates the classname in the hasthable as well.&lt;br /&gt;
 *       This is useful for use with cs_find_ent_by_class() and cs_find_ent_by_owner().&lt;br /&gt;
 *&lt;br /&gt;
 * @param index         Entity index&lt;br /&gt;
 * @param classname     Classname to update for&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native cs_set_ent_class(index, const classname[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Buying '''&lt;br /&gt;
&lt;br /&gt;
You can now easily detect when an item is being purchased.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Forward&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|CS_OnBuyAttempt|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=CS_OnBuyAttempt|header=Called when a client attempts to purchase an item.&lt;br /&gt;
 &lt;br /&gt;
{{alert|info|Note:|This is called immediately when the client issues a buy command.&amp;lt;br/&amp;gt;The game has not yet checked if the client can actually buy the weapon.|opt=full-border}}&lt;br /&gt;
 &lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Called when a client attempts to purchase an item.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This is called immediately when the client issues a buy command. The&lt;br /&gt;
 *       game has not yet checked if the client can actually buy the weapon.&lt;br /&gt;
 * @note For a list of possible item ids see the CSI_* constants.&lt;br /&gt;
 *&lt;br /&gt;
 * @param index     Client index&lt;br /&gt;
 * @param item      Item id&lt;br /&gt;
 *&lt;br /&gt;
 * @return          PLUGIN_CONTINUE to let the buy attempt continue&lt;br /&gt;
 *                  PLUGIN_HANDLED to block the buy attempt&lt;br /&gt;
 */&lt;br /&gt;
forward CS_OnBuyAttempt(index, item);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|CS_OnBuy|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=CS_OnBuy|header=Called when a client purchases an item.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|This is called right before the user receives the item and before the money is deducted from their cash reserves.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Called when a client purchases an item.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This is called right before the user receives the item and before the&lt;br /&gt;
 *       money is deducted from their cash reserves.&lt;br /&gt;
 * @note For a list of possible item ids see the CSI_* constants.&lt;br /&gt;
 *&lt;br /&gt;
 * @param index     Client index&lt;br /&gt;
 * @param item      Item id&lt;br /&gt;
 *&lt;br /&gt;
 * @return          PLUGIN_CONTINUE to let the buy continue&lt;br /&gt;
 *                  PLUGIN_HANDLED to block the buy&lt;br /&gt;
 */&lt;br /&gt;
forward CS_OnBuy(index, item);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|For a list of possible item ids see the {{tt|CSI_*}} {{hidden|id=csi_|labelonly=yes}} constants|opt=full-border}}&lt;br /&gt;
{{hidden|id=csi_|contentonly=yes|content=&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Constants used for the CS_OnBuy() and CS_OnBuyAttempt() forwards.&lt;br /&gt;
 *&lt;br /&gt;
 * @note While these mostly overlap with the CSW_* constants the CSI_* constants&lt;br /&gt;
 *       contain custom AMXX values that do not correspond to any real value in&lt;br /&gt;
 *       the game. The CSI_* constants should therefore be used for consistency.&lt;br /&gt;
 */&lt;br /&gt;
#define CSI_NONE                CSW_NONE&lt;br /&gt;
#define CSI_P228                CSW_P228&lt;br /&gt;
#define CSI_GLOCK               CSW_GLOCK  // Unused by game, See CSI_GLOCK18.&lt;br /&gt;
#define CSI_SCOUT               CSW_SCOUT&lt;br /&gt;
#define CSI_HEGRENADE           CSW_HEGRENADE&lt;br /&gt;
#define CSI_XM1014              CSW_XM1014&lt;br /&gt;
#define CSI_C4                  CSW_C4&lt;br /&gt;
#define CSI_MAC10               CSW_MAC10&lt;br /&gt;
#define CSI_AUG                 CSW_AUG&lt;br /&gt;
#define CSI_SMOKEGRENADE        CSW_SMOKEGRENADE&lt;br /&gt;
#define CSI_ELITE               CSW_ELITE&lt;br /&gt;
#define CSI_FIVESEVEN           CSW_FIVESEVEN&lt;br /&gt;
#define CSI_UMP45               CSW_UMP45&lt;br /&gt;
#define CSI_SG550               CSW_SG550&lt;br /&gt;
#define CSI_GALIL               CSW_GALIL&lt;br /&gt;
#define CSI_FAMAS               CSW_FAMAS&lt;br /&gt;
#define CSI_USP                 CSW_USP&lt;br /&gt;
#define CSI_GLOCK18             CSW_GLOCK18&lt;br /&gt;
#define CSI_P228                 CSW_AWP&lt;br /&gt;
#define CSI_MP5NAVY             CSW_MP5NAVY&lt;br /&gt;
#define CSI_M249                CSW_M249&lt;br /&gt;
#define CSI_M3                  CSW_M3&lt;br /&gt;
#define CSI_M4A1                CSW_M4A1&lt;br /&gt;
#define CSI_TMP                 CSW_TMP&lt;br /&gt;
#define CSI_G3SG1               CSW_G3SG1&lt;br /&gt;
#define CSI_FLASHBANG           CSW_FLASHBANG&lt;br /&gt;
#define CSI_DEAGLE              CSW_DEAGLE&lt;br /&gt;
#define CSI_SG552               CSW_SG552&lt;br /&gt;
#define CSI_AK47                CSW_AK47&lt;br /&gt;
#define CSI_KNIFE               CSW_KNIFE&lt;br /&gt;
#define CSI_P90                 CSW_P90&lt;br /&gt;
#define CSI_SHIELDGUN           CSW_SHIELDGUN   // The real CS value, use CSI_SHELD instead.&lt;br /&gt;
#define CSI_VEST                CSW_VEST        // Custom&lt;br /&gt;
#define CSI_VESTHELM            CSW_VESTHELM    // Custom&lt;br /&gt;
#define CSI_DEFUSER             33              // Custom&lt;br /&gt;
#define CSI_NVGS                34              // Custom&lt;br /&gt;
#define CSI_SHIELD              35              // Custom - The value passed by the forward, more convenient for plugins.&lt;br /&gt;
#define CSI_PRIAMMO             36              // Custom&lt;br /&gt;
#define CSI_SECAMMO             37              // Custom&lt;br /&gt;
#define CSI_MAX_COUNT           38&lt;br /&gt;
#define CSI_LAST_WEAPON         CSW_LAST_WEAPON&lt;br /&gt;
&lt;br /&gt;
#define CSI_ALL_WEAPONS         CSW_ALL_WEAPONS&lt;br /&gt;
#define CSI_ALL_PISTOLS         CSW_ALL_PISTOLS&lt;br /&gt;
#define CSI_ALL_SHOTGUNS        CSW_ALL_SHOTGUNS&lt;br /&gt;
#define CSI_ALL_SMGS            CSW_ALL_SMGS&lt;br /&gt;
#define CSI_ALL_RIFLES          CSW_ALL_RIFLES&lt;br /&gt;
#define CSI_ALL_SNIPERRIFLES    CSW_ALL_SNIPERRIFLES&lt;br /&gt;
#define CSI_ALL_MACHINEGUNS     CSW_ALL_MACHINEGUNS&lt;br /&gt;
#define CSI_ALL_GRENADES        CSW_ALL_GRENADES&lt;br /&gt;
#define CSI_ALL_ARMORS          CSW_ALL_ARMORS&lt;br /&gt;
#define CSI_ALL_GUNS            CSW_ALL_GUNS&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=array_cloning_ex|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=array_cloning_ex|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;cstrike&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public CS_OnBuyAttempt(index, item)&lt;br /&gt;
{&lt;br /&gt;
    if (item == CSI_AWP)&lt;br /&gt;
    {&lt;br /&gt;
        client_print(index, print_chat, &amp;quot;You tried to buy an AWP.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        return PLUGIN_HANDLED; // &amp;lt;-- Use this to block a buying&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public CS_OnBuy(index, item)&lt;br /&gt;
{&lt;br /&gt;
    if (item == CSI_DEAGLE)&lt;br /&gt;
    {&lt;br /&gt;
        client_print(index, print_chat, &amp;quot;You just bought a deagle and you're about to receive it.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''' Items info '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_get_user_weapon_entity|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_get_user_weapon_entity|header=Returns active weapon entity.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns active weapon entity.&lt;br /&gt;
 *&lt;br /&gt;
 * @param playerIndex   Player index&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Weapon entity index on success or 0 if there is no active weapon&lt;br /&gt;
 * @error               If the client index is not within the range of 1 to&lt;br /&gt;
 *                      maxClients, or the client is not connected, an error will be&lt;br /&gt;
 *                      thrown.&lt;br /&gt;
 */&lt;br /&gt;
native cs_get_user_weapon_entity(playerIndex);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_get_user_weapon|bgcolor=white}} &lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_get_user_weapon_entity|header=Returns weapon index of the active weapon.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|More reliable than {{tt|get_user_weapon|bgcolor=white}}.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns weapon index of the active weapon.&lt;br /&gt;
 *&lt;br /&gt;
 * @note More reliable than get_user_weapon.&lt;br /&gt;
 *&lt;br /&gt;
 * @param playerIndex   Player index&lt;br /&gt;
 * @param clip          Optional variable to store clip ammo to&lt;br /&gt;
 * @param ammo          Optional variable to store backpack ammo to&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Weapon index on success or 0 if there is no active weapon&lt;br /&gt;
 * @error               If the client index is not within the range of 1 to&lt;br /&gt;
 *                      maxClients, or the client is not connected, an error will be&lt;br /&gt;
 *                      thrown.&lt;br /&gt;
 */&lt;br /&gt;
native cs_get_user_weapon(playerIndex, &amp;amp;clip = 0, &amp;amp;ammo = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_get_item_id|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_get_item_id|header=Returns the item id associated with an item name and its aliases.&lt;br /&gt;
 &lt;br /&gt;
{{alert|info|Note:|The item name is case sensitive an can be with or without {{tt|weapon_|bgcolor=white}} and {{tt|item_|bgcolor=white}} prefixes. This can be a command alias as well.&amp;lt;br /&amp;gt;&lt;br /&gt;
Values examples: {{tt|ak47|bgcolor=white}}, {{tt|weapon_ak47|bgcolor=white}}, {{tt|kevlar|bgcolor=white}}, {{tt|item_kevlar|bgcolor=white}}, {{tt|vest|bgcolor=white}}, {{tt|bullpup|bgcolor=white}}, ...|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns the item id associated with an item name and its aliases.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The item name is case sensitive an can be with or without &lt;br /&gt;
 *       weapon_ and item_ prefixes. This can be a command alias as well.&lt;br /&gt;
 *       Values examples: ak47, weapon_ak47, kevlar, item_kevlar, vest, bullpup, ...&lt;br /&gt;
 *&lt;br /&gt;
 * @param name          Alias or classname&lt;br /&gt;
 * @param classid       If item is a weapon, variable to store the associated &lt;br /&gt;
 *                      weapon class id in (CS_WEAPONCLASS_* constants)&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Item id (CSI_* constants)&lt;br /&gt;
 */&lt;br /&gt;
native any:cs_get_item_id(const name[], &amp;amp;CsWeaponClassType:classid = CS_WEAPONCLASS_NONE);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_get_translated_item_alias|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_get_translated_item_alias|header=Returns an item name associated with a command alias.&lt;br /&gt;
 &lt;br /&gt;
{{alert|info|Note:|The alias is case sensitive.|opt=full-border}}&lt;br /&gt;
{{alert|info|Note:|If not an alias to a weapon, buffer will be set with the original alias.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns an item name associated with a command alias.&lt;br /&gt;
 *&lt;br /&gt;
 * @note The alias is case sensitive.&lt;br /&gt;
 * @note If not an alias to a weapon, buffer will be set with the original alias.&lt;br /&gt;
 *&lt;br /&gt;
 * @param alias         Alias name&lt;br /&gt;
 * @param itemname      Buffer to store item name to&lt;br /&gt;
 * @param maxlength     Maximum buffer size&lt;br /&gt;
 *&lt;br /&gt;
 * @return              True if alias is translated, false otherwise&lt;br /&gt;
 */&lt;br /&gt;
native bool:cs_get_translated_item_alias(const alias[], itemname[], maxlength);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_get_item_alias|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_get_item_alias|header=Returns the alias name associated with an item index.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns the alias name associated with an item index.&lt;br /&gt;
 *&lt;br /&gt;
 * @param itemid          Item id (CSI_* constants)&lt;br /&gt;
 * @param name            Buffer to store alias name to&lt;br /&gt;
 * @param name_maxlen     Maximum buffer size&lt;br /&gt;
 * @param altname         Optional buffer to store if available alternative alias name to&lt;br /&gt;
 * @param altname_maxlen  Maximum buffer size&lt;br /&gt;
 *&lt;br /&gt;
 * @return                True if alias is found, false otherwise&lt;br /&gt;
 */&lt;br /&gt;
native bool:cs_get_item_alias(itemid, name[], name_maxlen, altname[] = &amp;quot;&amp;quot;, altname_maxlen = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_get_weapon_info|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_get_weapon_info|header=Returns some information about a weapon.&lt;br /&gt;
 &lt;br /&gt;
{{alert|info|Note:|The alias is case sensitive.|opt=full-border}}&lt;br /&gt;
{{alert|info|Note:|If not an alias to a weapon, buffer will be set with the original alias.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Weapon info types for use with cs_get_weapon_info().&lt;br /&gt;
 */&lt;br /&gt;
enum CsWeaponInfo&lt;br /&gt;
{&lt;br /&gt;
	CS_WEAPONINFO_COST          = 0,&lt;br /&gt;
	CS_WEAPONINFO_CLIP_COST     = 1,&lt;br /&gt;
	CS_WEAPONINFO_BUY_CLIP_SIZE = 2,&lt;br /&gt;
	CS_WEAPONINFO_GUN_CLIP_SIZE = 3,&lt;br /&gt;
	CS_WEAPONINFO_MAX_ROUNDS    = 4,&lt;br /&gt;
	CS_WEAPONINFO_AMMO_TYPE     = 5,&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Returns some information about a weapon.&lt;br /&gt;
 *&lt;br /&gt;
 * @param weapon_id     Weapon id, see CSW_* constants&lt;br /&gt;
 * @param type          Info type, see CS_WEAPONINFO_* constants&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Weapon information value&lt;br /&gt;
 * @error               If weapon_id and type are out of bound, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native any:cs_get_weapon_info(weapon_id, CsWeaponInfo:type);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_get_weapon_class|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_get_weapon_class|header=Returns a weapon class id associated with a weapon id.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns a weapon class id associated with a weapon id.&lt;br /&gt;
 *&lt;br /&gt;
 * @param weapon_id     Weapon id (CSI_* constants)&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Weapon class id (CS_WEAPONCLASS_* constants)&lt;br /&gt;
 */&lt;br /&gt;
stock CsWeaponClassType:cs_get_weapon_class(weapon_id)&lt;br /&gt;
{&lt;br /&gt;
	new CsWeaponClassType:type = CS_WEAPONCLASS_NONE;&lt;br /&gt;
&lt;br /&gt;
	if (cs_is_valid_itemid(weapon_id, .weapon_only = true) || weapon_id == CSI_SHIELD)&lt;br /&gt;
	{&lt;br /&gt;
		switch (weapon_id)&lt;br /&gt;
		{&lt;br /&gt;
			case CSI_SHIELDGUN, CSI_SHIELD: &lt;br /&gt;
			{&lt;br /&gt;
				type = CS_WEAPONCLASS_PISTOL;&lt;br /&gt;
			}&lt;br /&gt;
			case CSI_KNIFE: &lt;br /&gt;
			{&lt;br /&gt;
				type = CS_WEAPONCLASS_KNIFE;&lt;br /&gt;
			}&lt;br /&gt;
			default:&lt;br /&gt;
			{&lt;br /&gt;
				new const bits = (1 &amp;lt;&amp;lt; weapon_id);&lt;br /&gt;
&lt;br /&gt;
				if(bits &amp;amp; CSI_ALL_PISTOLS)&lt;br /&gt;
				{&lt;br /&gt;
					type = CS_WEAPONCLASS_PISTOL;&lt;br /&gt;
				}&lt;br /&gt;
				else if(bits &amp;amp; CSI_ALL_GRENADES)&lt;br /&gt;
				{&lt;br /&gt;
					type = CS_WEAPONCLASS_GRENADE;&lt;br /&gt;
				}&lt;br /&gt;
				else if(bits &amp;amp; CSI_ALL_SMGS)&lt;br /&gt;
				{&lt;br /&gt;
					type = CS_WEAPONCLASS_SUBMACHINEGUN;&lt;br /&gt;
				}&lt;br /&gt;
				else if(bits &amp;amp; CSI_ALL_SHOTGUNS)&lt;br /&gt;
				{&lt;br /&gt;
					type = CS_WEAPONCLASS_SHOTGUN;&lt;br /&gt;
				}&lt;br /&gt;
				else if(bits &amp;amp; CSI_ALL_MACHINEGUNS)&lt;br /&gt;
				{&lt;br /&gt;
					type = CS_WEAPONCLASS_MACHINEGUN;&lt;br /&gt;
				}&lt;br /&gt;
				else if(bits &amp;amp; CSI_ALL_RIFLES)&lt;br /&gt;
				{&lt;br /&gt;
					type = CS_WEAPONCLASS_RIFLE;&lt;br /&gt;
				}&lt;br /&gt;
				else if(bits &amp;amp; CSI_ALL_SNIPERRIFLES)&lt;br /&gt;
				{&lt;br /&gt;
					type = CS_WEAPONCLASS_SNIPERRIFLE;&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return type;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_is_valid_itemid|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_is_valid_itemid|header=Checks whether an item id is not out of bounds.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Checks whether an item id is not out of bounds.&lt;br /&gt;
 *&lt;br /&gt;
 * @param id           Item id (CSI_* constants) &lt;br /&gt;
 * @param weapon_only  If true, only the real weapon ids will be checked,&lt;br /&gt;
 *                     including shield as well &lt;br /&gt;
 *&lt;br /&gt;
 * @return             True if item id is valid, false otherwise&lt;br /&gt;
 */&lt;br /&gt;
stock bool:cs_is_valid_itemid(id, bool:weapon_only = false)&lt;br /&gt;
{&lt;br /&gt;
	if (id &amp;lt;= CSI_NONE)&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (id &amp;gt; CSI_LAST_WEAPON &amp;amp;&amp;amp; id != CSI_SHIELDGUN &amp;amp;&amp;amp; weapon_only)&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (id &amp;gt;= CSI_MAX_COUNT)&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' New params '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Forward&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Parameter&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_set_user_deaths|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|scoreboard|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=CS_OnBuyAttempt|header=If true the scoreboard will be updated to reflect the new value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets client's deaths.&lt;br /&gt;
 *&lt;br /&gt;
 * @param index         Client index&lt;br /&gt;
 * @param newdeaths     New value to set&lt;br /&gt;
 * @param scoreboard    If true the scoreboard will be updated to reflect the new value.&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error               If the client index is not within the range of 1 to&lt;br /&gt;
 *                      MaxClients, or the client is not connected, an error&lt;br /&gt;
 *                      will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native cs_set_user_deaths(index, newdeaths, bool:scoreboard = true);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_get_armoury_type|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|cs_set_armoury_type|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|count|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_getset_armoury_type|header=Optional variable to store in the number of times that an item can be retrieved from the same entity before being hidden.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns the armoury entity's weapon id.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Not all weapon ids are supported by Counter-Strike, an armoury entity&lt;br /&gt;
 *       can not be a pistol, a knife or a bomb for exmaple. The full list is:&lt;br /&gt;
 *          CSW_SCOUT, CSW_HEGRENADE, CSW_XM1014, CSW_MAC10, CSW_AUG,&lt;br /&gt;
 *          CSW_SMOKEGRENADE, CSW_AWP, CSW_MP5NAVY, CSW_M249, CSW_M3, CSW_M4A1,&lt;br /&gt;
 *          CSW_TMP, CSW_G3SG1, CSW_VEST, CSW_VESTHELM, CSW_FLASHBANG,&lt;br /&gt;
 *          CSW_SG552, CSW_AK47, CSW_P90&lt;br /&gt;
 *&lt;br /&gt;
 * @param index     Armoury entity index&lt;br /&gt;
 * @param count     Optional variable to store in the number of times that an item can be retrieved  &lt;br /&gt;
 *                  from the same entity before being hidden&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Weapon id&lt;br /&gt;
 * @error           If a non-armoury entity is provided, an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native cs_get_armoury_type(index, &amp;amp;count = 1);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the amoury entity type.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Not all weapon ids are supported by Counter-Strike, an armoury entity&lt;br /&gt;
 *       can not be a pistol, a knife or a bomb for exmaple. The full list is:&lt;br /&gt;
 *          CSW_SCOUT, CSW_HEGRENADE, CSW_XM1014, CSW_MAC10, CSW_AUG,&lt;br /&gt;
 *          CSW_SMOKEGRENADE, CSW_AWP, CSW_MP5NAVY, CSW_M249, CSW_M3, CSW_M4A1,&lt;br /&gt;
 *          CSW_TMP, CSW_G3SG1, CSW_VEST, CSW_VESTHELM, CSW_FLASHBANG,&lt;br /&gt;
 *          CSW_SG552, CSW_AK47, CSW_P90&lt;br /&gt;
 * @note This does not update the entity model.&lt;br /&gt;
 * @note On restart, entity is always unhidden and the count is restored (this can not be below 1).&lt;br /&gt;
 *&lt;br /&gt;
 * @param index     Armoury entity index&lt;br /&gt;
 * @param type      Weapon id&lt;br /&gt;
 * @param count     Number of times that an item can be retrieved from &lt;br /&gt;
 *                  the same entity before being hidden&lt;br /&gt;
 *                  If zero, the entity is hidden&lt;br /&gt;
 *                  If below zero, nothing is set&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If a non-armoury entity is provided, an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native cs_set_armoury_type(index, type, count = -1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|cs_set_user_model|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|update_index|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=cs_set_user_model|header= If true, the modelindex is updated as well.&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|Updating modelindex is useful for custom models which don't have the same structure as the default ones (hitbox, etc..).&amp;lt;br /&amp;gt;Model must be precached before|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the client's player model.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This is not a one-time set. The CStrike module will remember the&lt;br /&gt;
 *       selected model and try to prevent attempts at changing the player&lt;br /&gt;
 *       model, or immediately re-apply it if necessary.&lt;br /&gt;
 * @note Updating modelindex is useful for custom models which don't have &lt;br /&gt;
 *       the same structure as the default ones (hitbox, etc..). Model must &lt;br /&gt;
 *       be precached before.&lt;br /&gt;
 *&lt;br /&gt;
 * @param index           Client index&lt;br /&gt;
 * @param model           Model name&lt;br /&gt;
 * @param update_index    If true, the modelindex is updated as well&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error                 If the client index is not within the range of 1 to&lt;br /&gt;
 *                        MaxClients, the client is not connected, the provided&lt;br /&gt;
 *                        model is empty, or if modeindex is updated and the &lt;br /&gt;
 *                        provided model is not precached, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native cs_set_user_model(index, const model[], bool:update_index = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Others '''&lt;br /&gt;
&lt;br /&gt;
* Hostage natives will work now with {{tt|monster_scientist}} entity (alias of {{tt|hostage_entity}})&lt;br /&gt;
* {{tt|cs_get_user_armor}} {{armortype}} parameter is now optional&lt;br /&gt;
* {{tt|cs_set_weapon_silen}} {{draw_animation}} has a new value of 2 which follows game behavior to properly draw the animation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Engine ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Entity '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|entity_intersects|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=entity_intersects|header=Returns if two entities bounding boxes intersect by comparing their absolute minimum and maximum origins.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns if two entities bounding boxes intersect by comparing their absolute&lt;br /&gt;
 * minimum and maximum origins.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index 1&lt;br /&gt;
 * @param other     Entity index 2&lt;br /&gt;
 *&lt;br /&gt;
 * @return          True if entities intersect, false otherwise&lt;br /&gt;
 * @error           If an invalid entity index is provided, an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native bool:entity_intersects(entity, other);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|set_ent_rendering|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=set_ent_rendering|header=Sets rendering options of an entity.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets rendering options of an entity.&lt;br /&gt;
 *&lt;br /&gt;
 * @note For a list of valid rendering effects see the kRenderFx* constants in&lt;br /&gt;
 *       amxconst.inc&lt;br /&gt;
 * @note For a list of valid rendering modes see the kRender* constants in&lt;br /&gt;
 *       amxconst.inc&lt;br /&gt;
 * @note Rendering amount has different meanings depending on the rendering&lt;br /&gt;
 *       effect and mode used on the entity.&lt;br /&gt;
 *&lt;br /&gt;
 * @param index     Entity index&lt;br /&gt;
 * @param fx        Rendering effect&lt;br /&gt;
 * @param r         Red component of rendering color&lt;br /&gt;
 * @param g         Green component of rendering color&lt;br /&gt;
 * @param b         Blue component of rendering color&lt;br /&gt;
 * @param render    Rendering mode&lt;br /&gt;
 * @param amount    Rendering amount&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid entity index is provided, an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_ent_rendering(index, fx = kRenderFxNone, r = 0, g = 0, b = 0, render = kRenderNormal, amount = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Hook '''&lt;br /&gt;
&lt;br /&gt;
You can now unregister hooks from: {{tt|register_impulse}}, {{tt|register_think}} and {{tt|register_touch}}.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Forward&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|unregister_impulse|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=unregister_impulse|header=Removes a previously registered impulse hook.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Removes a previously registered impulse hook.&lt;br /&gt;
 *&lt;br /&gt;
 * @param registerid    Impulse forward id&lt;br /&gt;
 *&lt;br /&gt;
 * @return              1 on success, 0 if nothing was removed&lt;br /&gt;
 */&lt;br /&gt;
native unregister_impulse(registerid);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|unregister_think|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=unregister_think|header=Removes a previously registered think hook.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Removes a previously registered think hook.&lt;br /&gt;
 *&lt;br /&gt;
 * @param registerid    Think forward id&lt;br /&gt;
 *&lt;br /&gt;
 * @return              1 on success, 0 if nothing was removed&lt;br /&gt;
 */&lt;br /&gt;
native unregister_think(registerid);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|unregister_touch|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=unregister_touch|header=Removes a previously registered touch hook.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Removes a previously registered touch hook.&lt;br /&gt;
 *&lt;br /&gt;
 * @param registerid    Touch forward id&lt;br /&gt;
 *&lt;br /&gt;
 * @return              1 on success, 0 if nothing was removed&lt;br /&gt;
 */&lt;br /&gt;
native unregister_touch(registerid);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Miscellaneous '''&lt;br /&gt;
&lt;br /&gt;
* {{tt|is_visible}} is now working on player.&lt;br /&gt;
* {{tt|set_ent_rendering}} is new working on non-players entities.&lt;br /&gt;
* {{tt|get_info_keybuffer}} can now retrieve local key buffer (i.e. using {{tt|-1}}).&lt;br /&gt;
* {{tt|trace_hull}} gets a new {{tt|end}} destination parameter to make it useful.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Safer Natives '''&lt;br /&gt;
&lt;br /&gt;
Safer natives which returns {{tt|-1}} if not entity found instead of {{tt|0}}0 which is a valid value (worldspawn).&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_global_edict2|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_global_edict2|header=Safe version of {{tt|get_global_edict}}.&amp;lt;br /&amp;gt;Returns a edict type value from the server globals.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns a edict type value from the server globals.&lt;br /&gt;
 *&lt;br /&gt;
 * @note For a list of valid edict type entries, see the GL_* constants in&lt;br /&gt;
 *       engine_const.inc under the &amp;quot;Edict&amp;quot; section.&lt;br /&gt;
 * @note This native returns -1 as a safe error value if the edict retrieved is&lt;br /&gt;
 *       an invalid entity. Otherwise it is identical to get_global_edict().&lt;br /&gt;
 *&lt;br /&gt;
 * @param variable  Entry to retrieve from&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Value of specified entry&lt;br /&gt;
 * @error           If an invalid entry is provided, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native get_global_edict2(variable);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
  |-&lt;br /&gt;
  | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|entity_get_edict2|bgcolor=white}}&lt;br /&gt;
  | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=entity_get_edict2|header=Safe version of {{tt|entity_get_edict}}.&amp;lt;br /&amp;gt;Returns an edict type value from an entities entvar struct.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns an edict type value from an entities entvar struct.&lt;br /&gt;
 *&lt;br /&gt;
 * @note For a list of valid edict type entries, see the EV_ENT_* constants in&lt;br /&gt;
 *       engine_const.inc&lt;br /&gt;
 * @note This native returns -1 as a safe error value if the edict retrieved&lt;br /&gt;
 *       from the entvar is an invalid entity. Otherwise it is identical to&lt;br /&gt;
 *       entity_get_edict().&lt;br /&gt;
 *&lt;br /&gt;
 * @param iIndex    Entity index&lt;br /&gt;
 * @param iKey      Entry to retrieve from&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Entity index in specified entry, -1 if the edict in the&lt;br /&gt;
 *                  entvar is not a valid entity or an invalid entry was&lt;br /&gt;
 *                  specified&lt;br /&gt;
 * @error           If an invalid entity index is provided, an error will be&lt;br /&gt;
 *                  thrown.&lt;br /&gt;
 */&lt;br /&gt;
native entity_get_edict2(iIndex, iKey);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Usercmd '''&lt;br /&gt;
&lt;br /&gt;
* {{tt|get_usercmd}} and {{tt|set_usercmd}} are now working and can be used in {{tt|client_cmdStart}} forward.&lt;br /&gt;
&lt;br /&gt;
:{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Forward&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|client_cmdStart|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=client_cmdStart|header=Called for CmdStart() on a client.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Called for CmdStart() on a client.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Use [get|set]_usercmd() to read and modify information in the usercmd&lt;br /&gt;
 *       struct.&lt;br /&gt;
 *&lt;br /&gt;
 * @param id    Client index&lt;br /&gt;
 *&lt;br /&gt;
 * @return      PLUGIN_CONTINUE to ignore, PLUGIN_HANDLED or higher to block&lt;br /&gt;
 */&lt;br /&gt;
forward client_cmdStart(id);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fakemeta ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' KVD '''&lt;br /&gt;
&lt;br /&gt;
This allows the creation of new KVD structures that can be used with Hamsandwich ({{tt|Ham_Keyvalue}}).&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|create_kvd|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|free_kvd|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=create_kvd|header=Creates a {{tt|KeyValueData}} handle.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates a KeyValueData handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Handles should be freed using free_kvd().&lt;br /&gt;
 *&lt;br /&gt;
 * @return		New KeyValueData handle&lt;br /&gt;
 */&lt;br /&gt;
native create_kvd();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=free_kvd|header=Frees a {{tt|KeyValueData}} handle.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Frees a KeyValueData handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @param kvd_handle	KeyValueData handle&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native free_kvd(kvd_handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Entity's Private Data (gamedata)'''&lt;br /&gt;
&lt;br /&gt;
This is now possible to manage value from an entity's private data based off a class and member name.&amp;lt;br /&amp;gt;&lt;br /&gt;
The related gamedata files are located in {{tt|data/gamedata/common.games/entities.games}} directory.&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=get_gamerules_int-ex|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=get_gamerules_int-ex|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
foo()&lt;br /&gt;
{&lt;br /&gt;
    new const item = get_ent_data_entity(&amp;quot;CBasePlayer&amp;quot;, &amp;quot;m_pActiveItem&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_ent_data|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_ent_data|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_ent_data|header=Retrieves an integer value from an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves an integer value from an entity's private data based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       integer, boolean, short, character, pointer, structure, class,&lt;br /&gt;
 *       stringint and function. Unsigned variants (if applicable) are supported&lt;br /&gt;
 *       and will be converted automatically.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Integer value&lt;br /&gt;
 * @error           If an invalid entity is provided, either class or member is&lt;br /&gt;
 *                  empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native any:get_ent_data(entity, const class[], const member[], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_ent_data|header=Sets an integer value to an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets an integer value to an entity's private data based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       integer, boolean, short, character, pointer, stringint and function.&lt;br /&gt;
 *       Unsigned variants (if applicable) are supported and will be converted&lt;br /&gt;
 *       automatically.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Value to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid entity is provided, either class or member is&lt;br /&gt;
 *                  empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_ent_data(entity, const class[], const member[], any:value, element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_ent_data_float|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_ent_data_float|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_ent_data_float|header=Retrieves an float value from an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves a float value from an entity's private data based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Float value&lt;br /&gt;
 * @error           If an invalid entity is provided, either class or member is&lt;br /&gt;
 *                  empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native Float:get_ent_data_float(entity, const class[], const member[], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_ent_data_float|header=Sets an float value to an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a float value to an entity's private data based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Value to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid entity is provided, either class or member is&lt;br /&gt;
 *                  empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_ent_data_float(entity, const class[], const member[], Float:value, element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_ent_data_vector|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_ent_data_vector|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_ent_data_vector|header=Retrieves a vector from an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves a vector from an entity's private data based off a class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Vector buffer to store data in&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid entity is provided, either class or member is&lt;br /&gt;
 *                  empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native get_ent_data_vector(entity, const class[], const member[], Float:value[3], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_ent_data_vector|header=Sets a vector to an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a vector to an entity's private data based off a class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Vector to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid entity is provided, either class or member is&lt;br /&gt;
 *                  empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_ent_data_vector(entity, const class[], const member[], Float:value[3], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_ent_data_entity|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_ent_data_entity|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_ent_data_entity|header=Retrieves an entity index from an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves an entity index from an entity's private data based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       classptr, entvars, edict and ehandle.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Entity index if found, -1 otherwise&lt;br /&gt;
 * @error           If an invalid entity is provided, either class or member is&lt;br /&gt;
 *                  empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native get_ent_data_entity(entity, const class[], const member[], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_ent_data_entity|header=Sets an entity index to an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets an entity index to an entity's private data based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       classptr, entvars, edict and ehandle.&lt;br /&gt;
 * @note Pass -1 as value to act as C++ NULL.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Entity index to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If an invalid entity or value is provided, either class or member&lt;br /&gt;
 *                  is empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_ent_data_entity(entity, const class[], const member[], value, element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_ent_data_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_ent_data_string|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_ent_data_string|header=Retrieves a string from an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves a string from an entity's private data based off a class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       string, stringptr.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Buffer to store data in&lt;br /&gt;
 * @param maxlen    Maximum size of the buffer&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of cells written to buffer&lt;br /&gt;
 * @error           If an invalid entity is provided, either class or member is&lt;br /&gt;
 *                  empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native get_ent_data_string(entity, const class[], const member[], value[], maxlen, element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_ent_data_string|header=Sets a string to an entity's private data based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a string to an entity's private data based off a class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class&lt;br /&gt;
 *       member offset into the plugin, this native instead retrieves the&lt;br /&gt;
 *       necessary offset from the AMXX gamedata files at runtime, based on the&lt;br /&gt;
 *       provided class and member name.&lt;br /&gt;
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter&lt;br /&gt;
 *       offset and typing checks.&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       string, stringptr.&lt;br /&gt;
 *&lt;br /&gt;
 * @param entity    Entity index&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     String to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of cells written to buffer&lt;br /&gt;
 * @error           If an invalid entity is provided, either class or member is&lt;br /&gt;
 *                  empty, no offset is found or an invalid offset is retrieved,&lt;br /&gt;
 *                  or the data type does not match, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_ent_data_string(entity, const class[], const member[], const value[], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_ent_data_size|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_ent_data_size|header=Retrieves the size of array of n entity class member.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves the size of array of n entity class member.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Size of array (in elements), otherwise 1 if member is not an array&lt;br /&gt;
 * @error           If either class or member is empty, no offset is found or an invalid&lt;br /&gt;
 *                  offset is retrieved, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native get_ent_data_size(const class[], const member[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|find_ent_data_info|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=find_ent_data_info|header=Finds a offset based off an entity class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Finds a offset based off an entity class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param type      Optional variable to store member type in (FIELD_* constants)&lt;br /&gt;
 * @param arraysize Optional variable to store array size in, if member is an array&lt;br /&gt;
 * @param unsigned  Optional variable to store whether member is unsigned (short and char types only)&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Class member offset&lt;br /&gt;
 * @error           If either class or member is empty, no offset is found or an invalid&lt;br /&gt;
 *                  offset is retrieved, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native find_ent_data_info(const class[], const member[], &amp;amp;FieldType:type = FIELD_NONE, &amp;amp;arraysize = 0, &amp;amp;bool:unsigned = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Entity's Private Data '''&lt;br /&gt;
&lt;br /&gt;
While it's encouraged to use the new natives based off gamedata, this completes the list with new data types supported: edict, bool, byte, short and ehandle.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_pdata_ent|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_pdata_ent|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_pdata_ent|header=Tries to retrieve an edict pointer from an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Tries to retrieve an edict pointer from an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable.  Unlike get_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * get_pdata_ent searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _Offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index		Entity index.&lt;br /&gt;
 * @param _offset		Offset to search.&lt;br /&gt;
 * @param _linuxdiff	Linux difference.&lt;br /&gt;
 * @param _macdiff		Mac OS X difference.&lt;br /&gt;
 * @return				-2 if an invalid entity was found.&lt;br /&gt;
 *						-1 if an empty entity was found.&lt;br /&gt;
 * 						Otherwise, an entity index is returned.&lt;br /&gt;
 */&lt;br /&gt;
native get_pdata_ent(_index, _offset, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_pdata_ent|header=Sets an edict pointer to an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets an edict pointer to an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable.  Unlike set_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * set_pdata_ent searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _value        Value to set.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              1 on success.&lt;br /&gt;
 */&lt;br /&gt;
native set_pdata_ent(_index, _offset, _value, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_pdata_bool|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_pdata_bool|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_pdata_bool|header=Returns a boolean from an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns a boolean from an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable. Unlike get_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * get_pdata_bool searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              An boolean value is returned.&lt;br /&gt;
 */&lt;br /&gt;
native bool:get_pdata_bool(_index, _offset, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_pdata_bool|header=Sets a boolean to an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a boolean to an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable. Unlike set_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * set_pdata_bool searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _value        Value to set.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              1 on success.&lt;br /&gt;
 */&lt;br /&gt;
native set_pdata_bool(_index, _offset, bool:_value, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_pdata_byte|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_pdata_byte|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_pdata_byte|header=Returns a byte value from an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns a byte value from an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable. Unlike get_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * get_pdata_byte searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              A byte value is returned.&lt;br /&gt;
 */&lt;br /&gt;
native get_pdata_byte(_index, _offset, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_pdata_byte|header=Sets a byte value to an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a byte value to an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable. Unlike set_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * set_pdata_byte searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _value        Value to set.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              1 on success.&lt;br /&gt;
 */&lt;br /&gt;
native set_pdata_byte(_index, _offset, _value, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_pdata_short|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_pdata_short|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_pdata_short|header=Returns a short value from an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns a short value from an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable. Unlike get_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * get_pdata_short searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              A short value is returned.&lt;br /&gt;
 */&lt;br /&gt;
native get_pdata_short(_index, _offset, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_pdata_short|header=Sets a short value to an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a short value to an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable.  Unlike set_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * set_pdata_short searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _value        Value to set.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              1 on success.&lt;br /&gt;
 */&lt;br /&gt;
native set_pdata_short(_index, _offset, _value, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_pdata_vector|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_pdata_vector|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_pdata_vector|header=Returns a vector from an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns a vector from an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable. Unlike get_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * get_pdata_vector searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _output       Vector returned by reference.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              1 on success.&lt;br /&gt;
 */&lt;br /&gt;
native get_pdata_vector(_index, _offset, Float:_output[3], _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_pdata_vector|header=Sets a vector to an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a vector to an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable.  Unlike set_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * set_pdata_vector searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _Offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _origin       Value to set.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              1 on success.&lt;br /&gt;
 */&lt;br /&gt;
native set_pdata_vector(_index, _offset, Float:_origin[3], _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_pdata_ehandle|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_pdata_ehandle|bgcolor=white}}&lt;br /&gt;
| style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_pdata_ehandle|header=Tries to retrieve an edict (entity encapsulation) pointer from an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Tries to retrieve an edict (entity encapsulation) pointer from an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable.  Unlike get_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * get_pdata_ehandle searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              -2 if an invalid entity was found.&lt;br /&gt;
 *                      -1 if an empty entity was found.&lt;br /&gt;
 *                      0 if serialnumber is not matching.&lt;br /&gt;
 *                      Otherwise, an entity index is returned.&lt;br /&gt;
 */&lt;br /&gt;
native get_pdata_ehandle(_index, _offset, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_pdata_ehandle|header=Sets an edict (entity encapsulation) pointer to an entity's private data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets an edict (entity encapsulation) pointer to an entity's private data.&lt;br /&gt;
 *&lt;br /&gt;
 * This function is byte-addressable.  Unlike set_pdata_int() which searches in byte increments of 4,&lt;br /&gt;
 * set_pdata_ehandle searches in increments of 1.&lt;br /&gt;
 *&lt;br /&gt;
 * _linuxdiff value is what to add to the _offset for linux servers.&lt;br /&gt;
 * _macdiff value is what to add to the _offset for os x servers.&lt;br /&gt;
 *&lt;br /&gt;
 * A log error is thrown on invalid _index and _Offset.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _index        Entity index.&lt;br /&gt;
 * @param _offset       Offset to search.&lt;br /&gt;
 * @param _value        Value to set.&lt;br /&gt;
 * @param _linuxdiff    Linux difference.&lt;br /&gt;
 * @param _macdiff      Mac OS X difference.&lt;br /&gt;
 * @return              1 on success.&lt;br /&gt;
 */&lt;br /&gt;
native set_pdata_ehandle(_index, _offset, _value, _linuxdiff = 20, _macdiff = 20);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Gamerules '''&lt;br /&gt;
&lt;br /&gt;
You have now the ability to manage a value using the gamerules object based off a class and member name.&amp;lt;br /&amp;gt;&lt;br /&gt;
The gamedata files are located in {{tt|/data/gamedata/common.games/gamerules.games}} directory.&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Example:|{{hidden|id=get_gamerules_int-ex|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=get_gamerules_int-ex|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
foo()&lt;br /&gt;
{&lt;br /&gt;
    new const score = get_gamerules_int(&amp;quot;CHalfLifeMultiplay&amp;quot;, &amp;quot;m_iNumCTWins&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_gamerules_int|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_gamerules_int|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_gamerules_int|header=Retrieves an integer value from the gamerules object based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves an integer value from the gamerules object based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       integer, boolean, short, character, pointer, structure, class,&lt;br /&gt;
 *       stringint and function. Unsigned variants (if applicable) are supported&lt;br /&gt;
 *       and will be converted automatically.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Integer value&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native any:get_gamerules_int(const class[], const member[], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_gamerules_int|header=Sets an integer value to the gamerules objecta based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets an integer value to the gamerules objecta based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       integer, boolean, short, character, pointer, stringint and function.&lt;br /&gt;
 *       Unsigned variants (if applicable) are supported and will be converted&lt;br /&gt;
 *       automatically.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Value to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_gamerules_int(const class[], const member[], any:value, element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_gamerules_float|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_gamerules_float|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_gamerules_float|header=Retrieves a float value from the gamerules object based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves a float value from the gamerules object based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Float value&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native Float:get_gamerules_float(const class[], const member[], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_gamerules_float|header=Sets an float value to the gamerules objecta based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a float value to the gamerules object based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Value to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_gamerules_float(const class[], const member[], Float:value, element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_gamerules_vector|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_gamerules_vector|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_gamerules_vector|header=Retrieves a vector from the gamerules object based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves a vector from the gamerules object based off a class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Vector buffer to store data in&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native get_gamerules_vector(const class[], const member[], Float:value[3], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_gamerules_vector|header=Sets a vector to the gamerules objecta based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a vector to the gamerules object based off a class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Vector to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_gamerules_vector(const class[], const member[], Float:value[3], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_gamerules_entity|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_gamerules_entity|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_gamerules_entity|header=Retrieves an entity index from the gamerules object based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves an entity index from the gamerules object based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       classptr, entvars, edict and ehandle.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Entity index if found, -1 otherwise&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native get_gamerules_entity(const class[], const member[], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_gamerules_entity|header=Sets an entity index to the gamerules objecta based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets an entity index to the gamerules object based off a class&lt;br /&gt;
 * and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       classptr, entvars, edict and ehandle.&lt;br /&gt;
 * @note Pass -1 as value to act as C++ NULL.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Entity index to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_gamerules_entity(const class[], const member[], value, element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_gamerules_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|set_gamerules_string|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_gamerules_string|header=Retrieves a string from the gamerules object based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves a string from the gamerules object based off a class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       string, stringptr.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     Buffer to store data in&lt;br /&gt;
 * @param maxlen    Maximum size of the buffer&lt;br /&gt;
 * @param element   Element to retrieve (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of cells written to buffer&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native get_gamerules_string(const class[], const member[], value[], maxlen, element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=set_gamerules_string|header=Sets a string to the gamerules objecta based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a string to the gamerules object based off a class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @note This native is used to access the following (C++/engine) data types:&lt;br /&gt;
 *       string, stringptr.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param value     String to set&lt;br /&gt;
 * @param element   Element to set (starting from 0) if member is an array&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Number of cells written to buffer&lt;br /&gt;
 * @error           If member is empty, no offset is found or an invalid offset&lt;br /&gt;
 *                  is retrieved, or the data type does not match, an error will&lt;br /&gt;
 *                  be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native set_gamerules_string(const class[], const member[], const value[], element = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_gamerules_size|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_gamerules_size|header=Retrieves the size of array of a gamerules class member.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Retrieves the size of array of a gamerules class member.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Size of array (in elements), otherwise 1 if member is not an array&lt;br /&gt;
 * @error           If either class or member is empty, no offset is found or an invalid&lt;br /&gt;
 *                  offset is retrieved, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native get_gamerules_size(const class[], const member[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|find_gamerules_info|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=find_gamerules_info|header=Finds a gamerules offset based off a class and member name.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Finds a gamerules offset based off a class and member name.&lt;br /&gt;
 *&lt;br /&gt;
 * @param class     Class name&lt;br /&gt;
 * @param member    Member name&lt;br /&gt;
 * @param type      Optional variable to store member type in (FIELD_* constants)&lt;br /&gt;
 * @param arraysize Optional variable to store array size in, if member is an array&lt;br /&gt;
 * @param unsigned  Optional variable to store whether member is unsigned (short and char types only)&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Class member offset&lt;br /&gt;
 * @error           If either class or member is empty, no offset is found or an invalid&lt;br /&gt;
 *                  offset is retrieved, an error will be thrown.&lt;br /&gt;
 */&lt;br /&gt;
native find_gamerules_info(const class[], const member[], &amp;amp;FieldType:type = FIELD_NONE, &amp;amp;arraysize = 0, &amp;amp;bool:unsigned = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|get_field_basetype|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=get_field_basetype|header=Returns the data field base type based off a specific field type.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns the data field base type based off a specific field type.&lt;br /&gt;
 *&lt;br /&gt;
 * @note From an AMXX plugin perspective, the (C++/engine) data types can be grouped&lt;br /&gt;
 *       in five base types: integer, float, vector, entity and string. This stock is&lt;br /&gt;
 *       essentially for convenience and debug purpose.&lt;br /&gt;
 *&lt;br /&gt;
 * @param type      Class member type (FIELD_* constants)&lt;br /&gt;
 * @param type_name Optional buffer to store base type name in&lt;br /&gt;
 * @param maxlen    Maximum size of the buffer&lt;br /&gt;
 *&lt;br /&gt;
 * @return          Base field type (BASEFIELD_* constants)&lt;br /&gt;
 */&lt;br /&gt;
stock BaseFieldType:get_field_basetype(FieldType:type, type_name[] = &amp;quot;&amp;quot;, maxlen = 0)&lt;br /&gt;
{&lt;br /&gt;
    static const baseFieldTypeNames[BaseFieldType][] =&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;none&amp;quot;,&lt;br /&gt;
        &amp;quot;integer&amp;quot;,&lt;br /&gt;
        &amp;quot;float&amp;quot;,&lt;br /&gt;
        &amp;quot;vector&amp;quot;,&lt;br /&gt;
        &amp;quot;entity&amp;quot;,&lt;br /&gt;
        &amp;quot;string&amp;quot;,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    new BaseFieldType:baseType = BASEFIELD_NONE;&lt;br /&gt;
&lt;br /&gt;
    switch (type)&lt;br /&gt;
    {&lt;br /&gt;
        case FIELD_INTEGER, FIELD_STRINGINT, FIELD_SHORT  , FIELD_CHARACTER,&lt;br /&gt;
             FIELD_CLASS  , FIELD_STRUCTURE, FIELD_POINTER, FIELD_FUNCTION,&lt;br /&gt;
             FIELD_BOOLEAN:&lt;br /&gt;
        {&lt;br /&gt;
            baseType = BASEFIELD_INTEGER;&lt;br /&gt;
        }&lt;br /&gt;
        case FIELD_FLOAT:&lt;br /&gt;
        {&lt;br /&gt;
            baseType = BASEFIELD_FLOAT;&lt;br /&gt;
        }&lt;br /&gt;
        case FIELD_VECTOR:&lt;br /&gt;
        {&lt;br /&gt;
            baseType = BASEFIELD_VECTOR;&lt;br /&gt;
        }&lt;br /&gt;
        case FIELD_CLASSPTR, FIELD_ENTVARS, FIELD_EDICT, FIELD_EHANDLE:&lt;br /&gt;
        {&lt;br /&gt;
            baseType = BASEFIELD_ENTITY;&lt;br /&gt;
        }&lt;br /&gt;
        case FIELD_STRINGPTR, FIELD_STRING:&lt;br /&gt;
        {&lt;br /&gt;
            baseType = BASEFIELD_STRING;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (maxlen &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        copy(type_name, maxlen, baseFieldTypeNames[baseType]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return baseType;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Miscellaneous '''&lt;br /&gt;
&lt;br /&gt;
* {{tt|get/set_pdata_cbase}} can now be used at map end whereas player's private datas are still valid.&lt;br /&gt;
* {{tt|EngFunc_PlayBackEvent}} can now receive a null invoker.&lt;br /&gt;
* {{tt|KeyValueData}} usage is now compatible with Hamsandwich module.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== GeoIP ===&lt;br /&gt;
&lt;br /&gt;
''' Library '''&lt;br /&gt;
&lt;br /&gt;
The module uses the new {{tt|MaxMind GeoIP2 API|bgcolor=none}}. The relevant advantages are:&lt;br /&gt;
* Should be more precise&lt;br /&gt;
* Data is localized (current supported languages: {{tt|de}}, {{tt|en}}, {{tt|es}}, {{tt|fr}}, {{tt|ja}}, {{tt|ru}}, {{tt|pt-BR}}, {{tt|zh-CN}})&lt;br /&gt;
&lt;br /&gt;
If you want further information, see [https://dev.maxmind.com/geoip/geoip2/whats-new-in-geoip2/ What’s New in GeoIP2].&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|{{TT|GeoIP.dat}} is replaced with {{TT|GeoLite2-Country.mmdb}} (default, [http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz downloadable]) or {{TT|GeoLite2-City.mmdb}} ([http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz downloadable]).|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
''' Command '''&lt;br /&gt;
&lt;br /&gt;
A {{tt|geoip}} command is available for troubleshooting: {{tt|geoip &amp;lt;command&amp;gt; [argument]}}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Command&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|version|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip-version|header=Displays the geoip database metadata such as the current loaded database and its version.|labelpos=left|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
  Database metadata&lt;br /&gt;
    Node count:    3998109&lt;br /&gt;
    Record size:   28 bits&lt;br /&gt;
    IP version:    IPv6&lt;br /&gt;
    Binary format: 2.0&lt;br /&gt;
    Build epoch:   1501721259 (2017-08-03 00:47:39 UTC)&lt;br /&gt;
    Type:          GeoLite2-City&lt;br /&gt;
    Languages:     de en es fr ja pt-BR ru zh-CN&lt;br /&gt;
    Description:&lt;br /&gt;
      en:   GeoLite2 City database&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|dump &amp;lt;ip&amp;gt; [output file]|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip-dump||header=Dumps all data from an IP address formatted in a JSON-ish fashion. &amp;lt;br /&amp;gt;An output file is mod-based and if not provided, it will print in the console.||labelpos=left|content=&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
* GEOIP2 DATA EXAMPLE:&lt;br /&gt;
*&lt;br /&gt;
* {&lt;br /&gt;
*   &amp;quot;city&amp;quot;:  {&lt;br /&gt;
*       &amp;quot;confidence&amp;quot;:  25,&lt;br /&gt;
*       &amp;quot;geoname_id&amp;quot;: 54321,&lt;br /&gt;
*       &amp;quot;names&amp;quot;:  {&lt;br /&gt;
*           &amp;quot;de&amp;quot;:    &amp;quot;Los Angeles&amp;quot;,&lt;br /&gt;
*           &amp;quot;en&amp;quot;:    &amp;quot;Los Angeles&amp;quot;,&lt;br /&gt;
*           &amp;quot;es&amp;quot;:    &amp;quot;Los Ýngeles&amp;quot;,&lt;br /&gt;
*           &amp;quot;fr&amp;quot;:    &amp;quot;Los Angeles&amp;quot;,&lt;br /&gt;
*           &amp;quot;ja&amp;quot;:    &amp;quot;ロサンゼルス市&amp;quot;,&lt;br /&gt;
*           &amp;quot;pt-BR&amp;quot;:  &amp;quot;Los Angeles&amp;quot;,&lt;br /&gt;
*           &amp;quot;ru&amp;quot;:    &amp;quot;Лоѝ-Ннджелеѝ&amp;quot;,&lt;br /&gt;
*           &amp;quot;zh-CN&amp;quot;: &amp;quot;洛杉矶&amp;quot;&lt;br /&gt;
*       }&lt;br /&gt;
*   },&lt;br /&gt;
*   &amp;quot;continent&amp;quot;:  {&lt;br /&gt;
*       &amp;quot;code&amp;quot;:       &amp;quot;NA&amp;quot;,&lt;br /&gt;
*       &amp;quot;geoname_id&amp;quot;: 123456,&lt;br /&gt;
*       &amp;quot;names&amp;quot;:  {&lt;br /&gt;
*           &amp;quot;de&amp;quot;:    &amp;quot;Nordamerika&amp;quot;,&lt;br /&gt;
*           &amp;quot;en&amp;quot;:    &amp;quot;North America&amp;quot;,&lt;br /&gt;
*           &amp;quot;es&amp;quot;:    &amp;quot;América del Norte&amp;quot;,&lt;br /&gt;
*           &amp;quot;fr&amp;quot;:    &amp;quot;Amérique du Nord&amp;quot;,&lt;br /&gt;
*           &amp;quot;ja&amp;quot;:    &amp;quot;北アメリカ&amp;quot;,&lt;br /&gt;
*           &amp;quot;pt-BR&amp;quot;: &amp;quot;América do Norte&amp;quot;,&lt;br /&gt;
*           &amp;quot;ru&amp;quot;:    &amp;quot;Севернаѝ Нмерика&amp;quot;,&lt;br /&gt;
*           &amp;quot;zh-CN&amp;quot;: &amp;quot;北美洲&amp;quot;&lt;br /&gt;
*&lt;br /&gt;
*       }&lt;br /&gt;
*   },&lt;br /&gt;
*   &amp;quot;country&amp;quot;:  {&lt;br /&gt;
*       &amp;quot;confidence&amp;quot;:  75,&lt;br /&gt;
*       &amp;quot;geoname_id&amp;quot;: &amp;quot;6252001&amp;quot;,&lt;br /&gt;
*       &amp;quot;iso_code&amp;quot;:    &amp;quot;US&amp;quot;,&lt;br /&gt;
*       &amp;quot;names&amp;quot;:  {&lt;br /&gt;
*           &amp;quot;de&amp;quot;:     &amp;quot;USA&amp;quot;,&lt;br /&gt;
*           &amp;quot;en&amp;quot;:     &amp;quot;United States&amp;quot;,&lt;br /&gt;
*           &amp;quot;es&amp;quot;:     &amp;quot;Estados Unidos&amp;quot;,&lt;br /&gt;
*           &amp;quot;fr&amp;quot;:     &amp;quot;États-Unis&amp;quot;,&lt;br /&gt;
*           &amp;quot;ja&amp;quot;:     &amp;quot;アメリカ坈衆国&amp;quot;,&lt;br /&gt;
*           &amp;quot;pt-BR&amp;quot;:  &amp;quot;Estados Unidos&amp;quot;,&lt;br /&gt;
*           &amp;quot;ru&amp;quot;:     &amp;quot;СШН&amp;quot;,&lt;br /&gt;
*           &amp;quot;zh-CN&amp;quot;:  &amp;quot;美国&amp;quot;&lt;br /&gt;
*       }&lt;br /&gt;
*   },&lt;br /&gt;
*   &amp;quot;location&amp;quot;:  {&lt;br /&gt;
*       &amp;quot;accuracy_radius&amp;quot;:   20,&lt;br /&gt;
*       &amp;quot;latitude&amp;quot;:          37.6293,&lt;br /&gt;
*       &amp;quot;longitude&amp;quot;:         -122.1163,&lt;br /&gt;
*       &amp;quot;metro_code&amp;quot;:        807,&lt;br /&gt;
*       &amp;quot;time_zone&amp;quot;:         &amp;quot;America/Los_Angeles&amp;quot;&lt;br /&gt;
*   },&lt;br /&gt;
*   &amp;quot;postal&amp;quot;: {&lt;br /&gt;
*       &amp;quot;code&amp;quot;:       &amp;quot;90001&amp;quot;,&lt;br /&gt;
*       &amp;quot;confidence&amp;quot;: 10&lt;br /&gt;
*   },&lt;br /&gt;
*   &amp;quot;registered_country&amp;quot;:  {&lt;br /&gt;
*       &amp;quot;geoname_id&amp;quot;: &amp;quot;6252001&amp;quot;,&lt;br /&gt;
*       &amp;quot;iso_code&amp;quot;:    &amp;quot;US&amp;quot;,&lt;br /&gt;
*       &amp;quot;names&amp;quot;:  {&lt;br /&gt;
*           &amp;quot;de&amp;quot;:     &amp;quot;USA&amp;quot;,&lt;br /&gt;
*           &amp;quot;en&amp;quot;:     &amp;quot;United States&amp;quot;,&lt;br /&gt;
*           &amp;quot;es&amp;quot;:     &amp;quot;Estados Unidos&amp;quot;,&lt;br /&gt;
*           &amp;quot;fr&amp;quot;:     &amp;quot;États-Unis&amp;quot;,&lt;br /&gt;
*           &amp;quot;ja&amp;quot;:     &amp;quot;アメリカ坈衆国&amp;quot;,&lt;br /&gt;
*           &amp;quot;pt-BR&amp;quot;:  &amp;quot;Estados Unidos&amp;quot;,&lt;br /&gt;
*           &amp;quot;ru&amp;quot;:     &amp;quot;СШН&amp;quot;,&lt;br /&gt;
*           &amp;quot;zh-CN&amp;quot;:  &amp;quot;美国&amp;quot;&lt;br /&gt;
*       }&lt;br /&gt;
*   },&lt;br /&gt;
*   &amp;quot;represented_country&amp;quot;:  {&lt;br /&gt;
*      &amp;quot;geoname_id&amp;quot;: &amp;quot;6252001&amp;quot;,&lt;br /&gt;
*       &amp;quot;iso_code&amp;quot;:    &amp;quot;US&amp;quot;,&lt;br /&gt;
*       &amp;quot;names&amp;quot;:  {&lt;br /&gt;
*           &amp;quot;de&amp;quot;:     &amp;quot;USA&amp;quot;,&lt;br /&gt;
*           &amp;quot;en&amp;quot;:     &amp;quot;United States&amp;quot;,&lt;br /&gt;
*           &amp;quot;es&amp;quot;:     &amp;quot;Estados Unidos&amp;quot;,&lt;br /&gt;
*           &amp;quot;fr&amp;quot;:     &amp;quot;États-Unis&amp;quot;,&lt;br /&gt;
*           &amp;quot;ja&amp;quot;:     &amp;quot;アメリカ坈衆国&amp;quot;,&lt;br /&gt;
*           &amp;quot;pt-BR&amp;quot;:  &amp;quot;Estados Unidos&amp;quot;,&lt;br /&gt;
*           &amp;quot;ru&amp;quot;:     &amp;quot;СШН&amp;quot;,&lt;br /&gt;
*           &amp;quot;zh-CN&amp;quot;:  &amp;quot;美国&amp;quot;&lt;br /&gt;
*       },&lt;br /&gt;
*       &amp;quot;type&amp;quot;: &amp;quot;military&amp;quot;&lt;br /&gt;
*   },&lt;br /&gt;
*   &amp;quot;subdivisions&amp;quot;:  [&lt;br /&gt;
*       {&lt;br /&gt;
*           &amp;quot;confidence&amp;quot;:  50,&lt;br /&gt;
*           &amp;quot;geoname_id&amp;quot;: 5332921,&lt;br /&gt;
*           &amp;quot;iso_code&amp;quot;:    &amp;quot;CA&amp;quot;,&lt;br /&gt;
*           &amp;quot;names&amp;quot;:  {&lt;br /&gt;
*               &amp;quot;de&amp;quot;:    &amp;quot;Kalifornien&amp;quot;,&lt;br /&gt;
*               &amp;quot;en&amp;quot;:    &amp;quot;California&amp;quot;,&lt;br /&gt;
*               &amp;quot;es&amp;quot;:    &amp;quot;California&amp;quot;,&lt;br /&gt;
*               &amp;quot;fr&amp;quot;:    &amp;quot;Californie&amp;quot;,&lt;br /&gt;
*               &amp;quot;ja&amp;quot;:    &amp;quot;カリフォルニア&amp;quot;,&lt;br /&gt;
*               &amp;quot;ru&amp;quot;:    &amp;quot;Калифорниѝ&amp;quot;,&lt;br /&gt;
*               &amp;quot;zh-CN&amp;quot;: &amp;quot;加州&amp;quot;&lt;br /&gt;
*           }&lt;br /&gt;
*       }&lt;br /&gt;
*   ],&lt;br /&gt;
*   &amp;quot;traits&amp;quot;: {&lt;br /&gt;
*       &amp;quot;autonomous_system_number&amp;quot;:      &amp;quot;1239&amp;quot;,&lt;br /&gt;
*       &amp;quot;autonomous_system_organization&amp;quot;: &amp;quot;Linkem IR WiMax Network&amp;quot;,&lt;br /&gt;
*       &amp;quot;domain&amp;quot;:                        &amp;quot;example.com&amp;quot;,&lt;br /&gt;
*       &amp;quot;is_anonymous_proxy&amp;quot;:            true,&lt;br /&gt;
*       &amp;quot;is_transparent_proxy&amp;quot;:          true,&lt;br /&gt;
*       &amp;quot;isp&amp;quot;:                           &amp;quot;Linkem spa&amp;quot;,&lt;br /&gt;
*       &amp;quot;ip_address&amp;quot;:                    &amp;quot;1.2.3.4&amp;quot;,&lt;br /&gt;
*       &amp;quot;organization&amp;quot;:                  &amp;quot;Linkem IR WiMax Network&amp;quot;,&lt;br /&gt;
*       &amp;quot;user_type&amp;quot;:                     &amp;quot;traveler&amp;quot;,&lt;br /&gt;
*   },&lt;br /&gt;
*   &amp;quot;maxmind&amp;quot;: {&lt;br /&gt;
*       &amp;quot;queries_remaining&amp;quot;:            &amp;quot;54321&amp;quot;&lt;br /&gt;
*   }&lt;br /&gt;
* }&lt;br /&gt;
*/&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
''' Deprecated natives '''&lt;br /&gt;
&lt;br /&gt;
{{tt|geoip_country}} has been marked as deprecated in favor of {{tt|geoip_country_ex}}. &amp;lt;br /&amp;gt;&lt;br /&gt;
Hardcoding the maximum buffer length and returning &amp;quot;error&amp;quot; if nothing is found, were not quite the good idea.&lt;br /&gt;
&lt;br /&gt;
''' New natives '''&lt;br /&gt;
&lt;br /&gt;
The natives which can output localized data, have a new {{tt|id}} {{hidden|id=new_id_param|labelonly=yes}} parameter in order to retrieve data into the player's language.&lt;br /&gt;
{{hidden|id=new_id_param|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param id        An optional player's index in order to return the result&lt;br /&gt;
 *                  in the player's language, if supported.&lt;br /&gt;
 *                  -1: the default language, which is english.&lt;br /&gt;
 *                   0: the server language. You can use LANG_SERVER define.&lt;br /&gt;
 *                 &amp;gt;=1: the player's language.&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Database&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Localized&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_country_ex|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | Country / City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✓&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_country_ex|labelonly=yes}} Looks up the full country name.&lt;br /&gt;
{{hidden|id=geoip_country_ex|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Looks up the full country name for the given IP address.&lt;br /&gt;
 *&lt;br /&gt;
 * @param ip        The IP address to lookup.&lt;br /&gt;
 * @param result    The result of the geoip lookup.&lt;br /&gt;
 * @param len       The maximum length of the result buffer.&lt;br /&gt;
 * @param id        An optional player's index in order to return the result&lt;br /&gt;
 *                  in the player's language, if supported.&lt;br /&gt;
 *                  -1: the default language, which is english.&lt;br /&gt;
 *                   0: the server language. You can use LANG_SERVER define.&lt;br /&gt;
 *                 &amp;gt;=1: the player's language.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The result length on successful lookup, 0 otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native geoip_country_ex(const ip[], result[], len, id = -1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_city|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✓&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_city|labelonly=yes}} Returns the (localized) city name.&lt;br /&gt;
{{hidden|id=geoip_city|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Look up the full city name for the given IP address.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This native requires GeoIP City database, which can be retrieved from:&lt;br /&gt;
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)&lt;br /&gt;
 *&lt;br /&gt;
 * @param ip        The IP address to look up.&lt;br /&gt;
 * @param result    The result of the geoip look up.&lt;br /&gt;
 * @param len       The maximum length of the result buffer.&lt;br /&gt;
 * @param id        An optional player's index in order to return the result&lt;br /&gt;
 *                  in the player's language, if supported.&lt;br /&gt;
 *                  -1: the default language, which is english.&lt;br /&gt;
 *                   0: the server language. You can use LANG_SERVER define.&lt;br /&gt;
 *                 &amp;gt;=1: the player's language.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The result length on successful lookup, 0 otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native geoip_city(const ip[], result[], len, id = -1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 style=&amp;quot;padding: 0;&amp;quot; |&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_continent_code|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✗&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_continent_code|labelonly=yes}} Returns the continent code. Example: {{tt|EU}} (Europe)&lt;br /&gt;
{{hidden|id=geoip_continent_code|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Looks up the continent code for a given IP address.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This native requires GeoIP City database, which can be retrieved from:&lt;br /&gt;
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)&lt;br /&gt;
 * @note  The code can be retrieved as integer (See CONTINENT_* constants.) or string (2 characters).&lt;br /&gt;
 * @note  Possible continent codes are AF, AN, AS, EU, NA, OC, SA for&lt;br /&gt;
 *        Africa(1), Antarctica(2), Asia(3), Europe(4), North America(5), Oceania(6), South America(7).&lt;br /&gt;
 *&lt;br /&gt;
 * @param ip        The IP address to look up.&lt;br /&gt;
 * @param result    The result of the geoip look up.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The continent id on successful lookup, 0 otherwise.&lt;br /&gt;
 */&lt;br /&gt;
enum Continent&lt;br /&gt;
{&lt;br /&gt;
    CONTINENT_UNKNOWN = 0,&lt;br /&gt;
    CONTINENT_AFRICA,&lt;br /&gt;
    CONTINENT_ANTARCTICA,&lt;br /&gt;
    CONTINENT_ASIA,&lt;br /&gt;
    CONTINENT_EUROPE,&lt;br /&gt;
    CONTINENT_NORTH_AMERICA,&lt;br /&gt;
    CONTINENT_OCEANIA,&lt;br /&gt;
    CONTINENT_SOUTH_AMERICA,&lt;br /&gt;
};&lt;br /&gt;
native Continent:geoip_continent_code(const ip[], result[3]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_continent_name|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✓&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_continent_name|labelonly=yes}} Returns the (localized) continent name. Example: {{tt|Europe}}&lt;br /&gt;
{{hidden|id=geoip_continent_name|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Look up the full continent name for the given IP address.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This native requires GeoIP City database, which can be retrieved from:&lt;br /&gt;
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)&lt;br /&gt;
 *&lt;br /&gt;
 * @param ip        The IP address to look up.&lt;br /&gt;
 * @param result    The result of the geoip look up.&lt;br /&gt;
 * @param len       The maximum length of the result buffer.&lt;br /&gt;
 * @param id        An optional player's index in order to return the result&lt;br /&gt;
 *                  in the player's language, if supported.&lt;br /&gt;
 *                  -1: the default language, which is english.&lt;br /&gt;
 *                   0: the server language. You can use LANG_SERVER define.&lt;br /&gt;
 *                 &amp;gt;=1: the player's language.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The result length on successful lookup, 0 otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native geoip_continent_name(const ip[], result[], len, id = -1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 style=&amp;quot;padding: 0;&amp;quot; |&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_region_code|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✗&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_region_code|labelonly=yes}} Returns a region code.&lt;br /&gt;
{{hidden|id=geoip_region_code|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Look up the region/state code for the given IP address.&lt;br /&gt;
 * e.g. &amp;quot;US-OH&amp;quot;, &amp;quot;DE-HH&amp;quot;, IT-82, &amp;quot;FR-U&amp;quot;, etc.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This native requires GeoIP City database, which can be retrieved from:&lt;br /&gt;
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)&lt;br /&gt;
 *&lt;br /&gt;
 * @param ip        The IP address to look up.&lt;br /&gt;
 * @param result    The result of the geoip look up.&lt;br /&gt;
 * @param len       The maximum length of the result buffer.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The result length on successful lookup, 0 otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native geoip_region_code(const ip[], result[], len);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_region_name|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✓&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_region_name|labelonly=yes}} Returns a (localized) region name.&lt;br /&gt;
{{hidden|id=geoip_region_name|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Look up the full region/state name for the given IP address.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This native requires GeoIP City database, which can be retrieved from:&lt;br /&gt;
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)&lt;br /&gt;
 *&lt;br /&gt;
 * @param ip        The IP address to look up.&lt;br /&gt;
 * @param result    The result of the geoip look up.&lt;br /&gt;
 * @param len       The maximum length of the result buffer.&lt;br /&gt;
 * @param id        An optional player's index in order to return the result&lt;br /&gt;
 *                  in the player's language, if supported.&lt;br /&gt;
 *                  -1: the default language, which is english.&lt;br /&gt;
 *                   0: the server language. You can use LANG_SERVER define.&lt;br /&gt;
 *                 &amp;gt;=1: the player's language.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The result length on successful lookup, 0 otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native geoip_region_name(const ip[], result[], len, id = -1);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 style=&amp;quot;padding: 0;&amp;quot; |&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_latitude|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✗&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_latitude|labelonly=yes}} Returns a city's latitude.&lt;br /&gt;
{{hidden|id=geoip_latitude|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Look up the city's latitude for the given IP address.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This native requires GeoIP City database, which can be retrieved from:&lt;br /&gt;
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)&lt;br /&gt;
 *&lt;br /&gt;
 * @param ip        The IP address to look up.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The result of the geoip look up, 0 if latitude is not found.&lt;br /&gt;
 */&lt;br /&gt;
native Float:geoip_latitude(const ip[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_longitude|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✗&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_longitude|labelonly=yes}} Returns a city's longitude.&lt;br /&gt;
{{hidden|id=geoip_longitude|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Look up the city's longitude for the given IP address.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This native requires GeoIP City database, which can be retrieved from:&lt;br /&gt;
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)&lt;br /&gt;
 *&lt;br /&gt;
 * @param ip        The IP address to look up.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The result of the geoip look up, 0 if longitude is not found.&lt;br /&gt;
 */&lt;br /&gt;
native Float:geoip_longitude(const ip[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_distance|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✗&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_distance|labelonly=yes}} Calculates the distance between geographical coordinates.&lt;br /&gt;
{{hidden|id=geoip_distance|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Calculate the distance between geographical coordinates, latitude and longitude.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This native requires GeoIP City database, which can be retrieved from:&lt;br /&gt;
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)&lt;br /&gt;
 *&lt;br /&gt;
 * @param lat1      The first IP latitude.&lt;br /&gt;
 * @param lon1      The first IP longitude.&lt;br /&gt;
 * @param lat2      The second IP latitude.&lt;br /&gt;
 * @param lon2      The second IP longitude.&lt;br /&gt;
 * @param system    The system of measurement, 0 = Metric(kilometers) or 1 = English(miles).&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The distance as result in specified system of measurement.&lt;br /&gt;
 */&lt;br /&gt;
#define SYSTEM_METRIC   0 // kilometers&lt;br /&gt;
#define SYSTEM_IMPERIAL 1 // statute miles&lt;br /&gt;
&lt;br /&gt;
native Float:geoip_distance(Float:lat1, Float:lon1, Float:lat2, Float:lon2, system = SYSTEM_METRIC);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 style=&amp;quot;padding: 0;&amp;quot; |&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|geoip_timezone|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | City&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align:center;&amp;quot; | ✗&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=geoip_timezone|labelonly=yes}} Returns a full time zone. Example: {{tt|Europe/Paris}}&lt;br /&gt;
{{hidden|id=geoip_timezone|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Look up the full time zone for the given IP address.&lt;br /&gt;
 * e.g. America/Los_Angeles, Europe/Paris.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  This native requires GeoIP City database, which can be retrieved from:&lt;br /&gt;
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)&lt;br /&gt;
 *&lt;br /&gt;
 * @param ip        The IP address to look up.&lt;br /&gt;
 * @param result    The result of the geoip look up.&lt;br /&gt;
 * @param len       The maximum length of the result buffer.&lt;br /&gt;
 *&lt;br /&gt;
 * @return          The result length on successful lookup, 0 otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native geoip_timezone(const ip[], result[], len);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Hamsandwich ===&lt;br /&gt;
&lt;br /&gt;
''' Games support '''&lt;br /&gt;
&lt;br /&gt;
The following games are now supported:&lt;br /&gt;
* Deathmatch Classic&lt;br /&gt;
* Adrenaline Gamer&lt;br /&gt;
* Opposing Forces&lt;br /&gt;
&lt;br /&gt;
The following games have been updated to their latest version:&lt;br /&gt;
* Sven Coop v5.13&lt;br /&gt;
&lt;br /&gt;
''' ItemInfo structure '''&lt;br /&gt;
&lt;br /&gt;
A new set of functions have added to manage the {{{tt|ItemInfo}} structure.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|CreateHamItemInfo|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=CreateHamItemInfo|header=Creates an ItemInfo handle. &amp;lt;br /&amp;gt;The handle can be used in {{tt|GetHamItemInfo|bgcolor=white}} and {{tt|SetHamItemInfo|bgcolor=white}}.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates an ItemInfo handle.  This value should never be altered.&lt;br /&gt;
 * The handle can be used in Get/SetHamItemInfo.&lt;br /&gt;
 *&lt;br /&gt;
 * NOTE: You must call FreeHamItemInfo() on every handle made with CreateHamItemInfo().&lt;br /&gt;
 *&lt;br /&gt;
 * @return			A new ItemInfo handle.&lt;br /&gt;
 */&lt;br /&gt;
native CreateHamItemInfo();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|FreeHamItemInfo|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=FreeHamItemInfo|header=Frees an ItemIndo handle created with {{tt|CreateHamItemInfo|bgcolor=white}}.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Frees an ItemIndo handle created with CreateHamItemInfo().  Do not call&lt;br /&gt;
 * this more than once per handle, or on handles not created through&lt;br /&gt;
 * CreateHamItemInfo().&lt;br /&gt;
 *&lt;br /&gt;
 * @param itemInfo_handle	ItemInfo handle created via CreateHamItemInfo().&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native FreeHamItemInfo(itemInfo_handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|GetHamItemInfo|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|SetHamItemInfo|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=GetHamItemInfo|header=Gets a parameter on the fly of the current hook.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a parameter on the fly of the current hook.&lt;br /&gt;
 * Use this on parameters that are iteminfo result handles.&lt;br /&gt;
 *&lt;br /&gt;
 * @param iteminfo_handle	Item info handle.&lt;br /&gt;
 * @param type				Item info type. See HamItemInfo constants.&lt;br /&gt;
 */&lt;br /&gt;
native GetHamItemInfo(iteminfo_handle, HamItemInfo:type, any:...);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=SetHamItemInfo|header=Sets a parameter on the fly of the current hook.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a parameter on the fly of the current hook.&lt;br /&gt;
 * Use this on parameters that are iteminfo result handles.&lt;br /&gt;
 *&lt;br /&gt;
 * @param iteminfo_handle	Item info handle.&lt;br /&gt;
 * @param type				Item info type. See HamItemInfo_ constants.&lt;br /&gt;
 */&lt;br /&gt;
native SetHamItemInfo(iteminfo_handle, HamItemInfo:type, any:...);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SetHamParamItemInfo|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SetHamParamItemInfo|header=Sets a parameter on the fly of the current hook.  This has no effect in post hooks.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a parameter on the fly of the current hook.  This has no effect in post hooks.&lt;br /&gt;
 * Use this on parameters that are trace result handles.&lt;br /&gt;
 *&lt;br /&gt;
 * @param which				Which parameter to change.  Starts at 1, and works up from the left to right.  1 is always &amp;quot;this&amp;quot;.&lt;br /&gt;
 * @param iteminfo_handle	The value to change it to.&lt;br /&gt;
 */&lt;br /&gt;
native SetHamParamItemInfo(which, iteminfo_handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Miscellaneous '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SetParamEntity2|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SetParamEntity2|header=Sets a parameter on the fly of the current hook.  This has no effect in post hooks&lt;br /&gt;
{{alert|info|Note:| Same as {{tt|SetHamParamEntity|bgcolor=white}} except the changes made by this native are reflected in the corresponding post forward.|opt=full-border}}&lt;br /&gt;
 .|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a parameter on the fly of the current hook.  This has no effect in post hooks.&lt;br /&gt;
 * Use this on parameters that are entities.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Same as SetHamParamEntity except the changes made by this native are reflected in the corresponding post forward.&lt;br /&gt;
 *&lt;br /&gt;
 * @param which				Which parameter to change.  Starts at 1, and works up from the left to right.  1 is always &amp;quot;this&amp;quot;.&lt;br /&gt;
 * @param value				The value to change it to.&lt;br /&gt;
 */&lt;br /&gt;
native SetHamParamEntity2(which, value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Special bot '''&lt;br /&gt;
&lt;br /&gt;
{{tt|RegisterHam}} has now the ability to register a bot without {{tt|player}} classname.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Parameter&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|RegisterHam|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|specialbot|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=RegisterHam|header=Whether or not to enable support for bot without &amp;quot;player&amp;quot; classname.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Hooks the virtual table for the specified entity class.&lt;br /&gt;
 * An example would be: RegisterHam(Ham_TakeDamage, &amp;quot;player&amp;quot;, &amp;quot;player_hurt&amp;quot;);&lt;br /&gt;
 * Look at the Ham enum for parameter lists.&lt;br /&gt;
 *&lt;br /&gt;
 * @param function		The function to hook.&lt;br /&gt;
 * @param EntityClass	The entity classname to hook.&lt;br /&gt;
 * @param callback		The forward to call.&lt;br /&gt;
 * @param post			Whether or not to forward this in post.&lt;br /&gt;
 * @param specialbot	Whether or not to enable support for bot without &amp;quot;player&amp;quot; classname.&lt;br /&gt;
 * @return 				Returns a handle to the forward.  Use EnableHamForward/DisableHamForward to toggle the forward on or off.&lt;br /&gt;
 */&lt;br /&gt;
native HamHook:RegisterHam(Ham:function, const EntityClass[], const Callback[], Post=0, bool:specialbot = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
For convenience a stock to make more intuitive registering a function on &amp;quot;player&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|RegisterHamPlayer|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=RegisterHamPlayer|header=Hooks the virtual table for the player class.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Hooks the virtual table for the player class.&lt;br /&gt;
 * An example would be: RegisterHam(Ham_TakeDamage, &amp;quot;player_hurt&amp;quot;);&lt;br /&gt;
 * Look at the Ham enum for parameter lists.&lt;br /&gt;
 *&lt;br /&gt;
 * @param function		The function to hook.&lt;br /&gt;
 * @param callback		The forward to call.&lt;br /&gt;
 * @param post			Whether or not to forward this in post.&lt;br /&gt;
 * @return 				Returns a handle to the forward.  Use EnableHamForward/DisableHamForward to toggle the forward on or off.&lt;br /&gt;
 */&lt;br /&gt;
stock HamHook:RegisterHamPlayer(Ham:function, const Callback[], Post=0)&lt;br /&gt;
{&lt;br /&gt;
    return RegisterHam(function, &amp;quot;player&amp;quot;, Callback, Post, true);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Virtual function '''&lt;br /&gt;
&lt;br /&gt;
A lot of missing virtual functions have been added for all games.&amp;lt;br /&amp;gt;&lt;br /&gt;
Some of the existing common functions have been renamed because they are mod-dependent.&lt;br /&gt;
&lt;br /&gt;
Short overview:&lt;br /&gt;
* {{hidden|id=v-common|labelonly=yes}} Common&lt;br /&gt;
{{hidden|id=v-common|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_ChangeYaw&lt;br /&gt;
Ham_HasHumanGibs&lt;br /&gt;
Ham_HasAlienGibs&lt;br /&gt;
Ham_FadeMonster&lt;br /&gt;
Ham_GibMonster&lt;br /&gt;
Ham_BecomeDead&lt;br /&gt;
Ham_IRelationship&lt;br /&gt;
Ham_PainSound&lt;br /&gt;
Ham_ReportAIState&lt;br /&gt;
Ham_MonsterInitDead&lt;br /&gt;
Ham_Look&lt;br /&gt;
Ham_BestVisibleEnemy&lt;br /&gt;
Ham_FInViewCone&lt;br /&gt;
Ham_FVecInViewCone&lt;br /&gt;
Ham_GetDeathActivity&lt;br /&gt;
Ham_Item_GetItemInfo&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* {{hidden|id=v-common-2|labelonly=yes}} Common (not supported by Counter-Strike, The Specialists and Natural Selection mods)&lt;br /&gt;
{{hidden|id=v-common-2|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_RunAI,&lt;br /&gt;
Ham_MonsterThink,&lt;br /&gt;
Ham_MonsterInit,&lt;br /&gt;
Ham_CheckLocalMove,&lt;br /&gt;
Ham_Move,&lt;br /&gt;
Ham_MoveExecute,&lt;br /&gt;
Ham_ShouldAdvanceRoute,&lt;br /&gt;
Ham_GetStoppedActivity,&lt;br /&gt;
Ham_Stop,&lt;br /&gt;
Ham_CheckRangeAttack1,&lt;br /&gt;
Ham_CheckRangeAttack2,&lt;br /&gt;
Ham_CheckMeleeAttack1,&lt;br /&gt;
Ham_CheckMeleeAttack2,&lt;br /&gt;
Ham_ScheduleChange,&lt;br /&gt;
Ham_CanPlaySequence,&lt;br /&gt;
Ham_CanPlaySentence,&lt;br /&gt;
Ham_PlaySentence,&lt;br /&gt;
Ham_PlayScriptedSentence,&lt;br /&gt;
Ham_SentenceStop,&lt;br /&gt;
Ham_GetIdealState,&lt;br /&gt;
Ham_SetActivity,&lt;br /&gt;
Ham_CheckEnemy,&lt;br /&gt;
Ham_FTriangulate,&lt;br /&gt;
Ham_SetYawSpeed,&lt;br /&gt;
Ham_BuildNearestRoute,&lt;br /&gt;
Ham_FindCover,&lt;br /&gt;
Ham_CoverRadius,&lt;br /&gt;
Ham_FCanCheckAttacks,&lt;br /&gt;
Ham_CheckAmmo,&lt;br /&gt;
Ham_IgnoreConditions,&lt;br /&gt;
Ham_FValidateHintType,&lt;br /&gt;
Ham_FCanActiveIdle,&lt;br /&gt;
Ham_ISoundMask,&lt;br /&gt;
Ham_HearingSensitivity,&lt;br /&gt;
Ham_BarnacleVictimBitten,&lt;br /&gt;
Ham_BarnacleVictimReleased,&lt;br /&gt;
Ham_PrescheduleThink,&lt;br /&gt;
Ham_DeathSound,&lt;br /&gt;
Ham_AlertSound,&lt;br /&gt;
Ham_IdleSound,&lt;br /&gt;
Ham_StopFollowing,&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* {{hidden|id=v-cs|labelonly=yes}} Specific to Counter-Strike&lt;br /&gt;
{{hidden|id=v-cs|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_CS_Item_IsWeapon&lt;br /&gt;
Ham_CS_Weapon_SendWeaponAnim&lt;br /&gt;
Ham_CS_Player_ResetMaxSpeed&lt;br /&gt;
Ham_CS_Player_IsBot&lt;br /&gt;
Ham_CS_Player_GetAutoaimVector&lt;br /&gt;
Ham_CS_Player_Blind&lt;br /&gt;
Ham_CS_Player_OnTouchingWeapon&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* {{hidden|id=v-dod|labelonly=yes}} Specific to Day Of Defeat&lt;br /&gt;
{{hidden|id=v-dod|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_DOD_SetScriptReset&lt;br /&gt;
Ham_DOD_Item_SpawnDeploy&lt;br /&gt;
Ham_DOD_Item_SetDmgTime&lt;br /&gt;
Ham_DOD_Item_DropGren&lt;br /&gt;
Ham_DOD_Weapon_IsUseable&lt;br /&gt;
Ham_DOD_Weapon_Aim&lt;br /&gt;
Ham_DOD_Weapon_flAim&lt;br /&gt;
Ham_DOD_Weapon_RemoveStamina&lt;br /&gt;
Ham_DOD_Weapon_ChangeFOV&lt;br /&gt;
Ham_DOD_Weapon_ZoomOut&lt;br /&gt;
Ham_DOD_Weapon_ZoomIn&lt;br /&gt;
Ham_DOD_Weapon_GetFOV&lt;br /&gt;
Ham_DOD_Weapon_PlayerIsWaterSniping&lt;br /&gt;
Ham_DOD_Weapon_UpdateZoomSpeed&lt;br /&gt;
Ham_DOD_Weapon_Special&lt;br /&gt;
Ham_DOD_Weapon_SendWeaponAnim&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* {{hidden|id=v-esf|labelonly=yes}} Specific to Earth's Special Forces&lt;br /&gt;
{{hidden|id=v-esf|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_ESF_IsFighter&lt;br /&gt;
Ham_ESF_IsBuddy&lt;br /&gt;
Ham_ESF_EmitSound&lt;br /&gt;
Ham_ESF_EmitNullSound&lt;br /&gt;
Ham_ESF_IncreaseStrength&lt;br /&gt;
Ham_ESF_IncreasePL&lt;br /&gt;
Ham_ESF_SetPowerLevel&lt;br /&gt;
Ham_ESF_SetMaxPowerLevel&lt;br /&gt;
Ham_ESF_StopAniTrigger&lt;br /&gt;
Ham_ESF_StopFly&lt;br /&gt;
Ham_ESF_HideWeapon&lt;br /&gt;
Ham_ESF_ClientRemoveWeapon&lt;br /&gt;
Ham_ESF_SendClientsCustomModel&lt;br /&gt;
Ham_ESF_CanTurbo&lt;br /&gt;
Ham_ESF_CanPrimaryFire&lt;br /&gt;
Ham_ESF_CanSecondaryFire&lt;br /&gt;
Ham_ESF_CanStopFly&lt;br /&gt;
Ham_ESF_CanBlock&lt;br /&gt;
Ham_ESF_CanRaiseKi&lt;br /&gt;
Ham_ESF_CanRaiseStamina&lt;br /&gt;
Ham_ESF_CanTeleport&lt;br /&gt;
Ham_ESF_CanStartFly&lt;br /&gt;
Ham_ESF_CanStartPowerup&lt;br /&gt;
Ham_ESF_CanJump&lt;br /&gt;
Ham_ESF_CanWallJump&lt;br /&gt;
Ham_ESF_IsSuperJump&lt;br /&gt;
Ham_ESF_IsMoveBack&lt;br /&gt;
Ham_ESF_CheckWallJump&lt;br /&gt;
Ham_ESF_EnableWallJump&lt;br /&gt;
Ham_ESF_DisableWallJump&lt;br /&gt;
Ham_ESF_ResetWallJumpVars&lt;br /&gt;
Ham_ESF_GetWallJumpAnim&lt;br /&gt;
Ham_ESF_GetWallJumpAnim2&lt;br /&gt;
Ham_ESF_SetWallJumpAnimation&lt;br /&gt;
Ham_ESF_SetFlyMoveType&lt;br /&gt;
Ham_ESF_IsFlyMoveType&lt;br /&gt;
Ham_ESF_IsWalkMoveType&lt;br /&gt;
Ham_ESF_SetWalkMoveType&lt;br /&gt;
Ham_ESF_DrawChargeBar&lt;br /&gt;
Ham_ESF_StartBlock&lt;br /&gt;
Ham_ESF_StopBlock&lt;br /&gt;
Ham_ESF_StartFly&lt;br /&gt;
Ham_ESF_GetMaxSpeed&lt;br /&gt;
Ham_ESF_SetAnimation&lt;br /&gt;
Ham_ESF_PlayAnimation&lt;br /&gt;
Ham_ESF_GetMoveForward&lt;br /&gt;
Ham_ESF_GetMoveRight&lt;br /&gt;
Ham_ESF_GetMoveUp&lt;br /&gt;
Ham_ESF_AddBlindFX&lt;br /&gt;
Ham_ESF_RemoveBlindFX&lt;br /&gt;
Ham_ESF_DisablePSBar&lt;br /&gt;
Ham_ESF_AddBeamBoxCrosshair&lt;br /&gt;
Ham_ESF_RemoveBeamBoxCrosshair&lt;br /&gt;
Ham_ESF_DrawPSWinBonus&lt;br /&gt;
Ham_ESF_DrawPSBar&lt;br /&gt;
Ham_ESF_LockCrosshair&lt;br /&gt;
Ham_ESF_UnLockCrosshair&lt;br /&gt;
Ham_ESF_RotateCrosshair&lt;br /&gt;
Ham_ESF_UnRotateCrosshair&lt;br /&gt;
Ham_ESF_WaterMove&lt;br /&gt;
Ham_ESF_CheckTimeBasedDamage&lt;br /&gt;
Ham_ESF_DoesSecondaryAttack&lt;br /&gt;
Ham_ESF_DoesPrimaryAttack&lt;br /&gt;
Ham_ESF_RemoveSpecialModes&lt;br /&gt;
Ham_ESF_StopTurbo&lt;br /&gt;
Ham_ESF_TakeBean&lt;br /&gt;
Ham_ESF_GetPowerLevel&lt;br /&gt;
Ham_ESF_RemoveAllOtherWeapons&lt;br /&gt;
Ham_ESF_StopSwoop&lt;br /&gt;
Ham_ESF_SetDeathAnimation&lt;br /&gt;
Ham_ESF_SetModel&lt;br /&gt;
Ham_ESF_AddAttacks&lt;br /&gt;
Ham_ESF_EmitClassSound&lt;br /&gt;
Ham_ESF_CheckLightning&lt;br /&gt;
Ham_ESF_FreezeControls&lt;br /&gt;
Ham_ESF_UnFreezeControls&lt;br /&gt;
Ham_ESF_UpdateKi&lt;br /&gt;
Ham_ESF_UpdateHealth&lt;br /&gt;
Ham_ESF_GetTeleportDir&lt;br /&gt;
Ham_ESF_Weapon_HolsterWhenMeleed&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* {{hidden|id=v-ns|labelonly=yes}} Specific to Natural Selection&lt;br /&gt;
{{hidden|id=v-ns|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_NS_SetBoneController&lt;br /&gt;
Ham_NS_SaveDataForReset&lt;br /&gt;
Ham_NS_GetHull&lt;br /&gt;
Ham_NS_GetMaxWalkSpeed&lt;br /&gt;
Ham_NS_SetTeamID&lt;br /&gt;
Ham_NS_GetEffectivePlayerClass&lt;br /&gt;
Ham_NS_GetAuthenticationMask&lt;br /&gt;
Ham_NS_EffectivePlayerClassChanged&lt;br /&gt;
Ham_NS_NeedsTeamUpdate&lt;br /&gt;
Ham_NS_SendTeamUpdate&lt;br /&gt;
Ham_NS_SendWeaponUpdate&lt;br /&gt;
Ham_NS_InitPlayerFromSpawn&lt;br /&gt;
Ham_NS_PackDeadPlayerItems&lt;br /&gt;
Ham_NS_GetAnimationForActivity&lt;br /&gt;
Ham_NS_StartObserver&lt;br /&gt;
Ham_NS_StopObserver&lt;br /&gt;
Ham_NS_GetAdrenalineFactor&lt;br /&gt;
Ham_NS_GiveNamedItem&lt;br /&gt;
Ham_NS_Suicide&lt;br /&gt;
Ham_NS_GetCanUseWeapon&lt;br /&gt;
Ham_NS_Weapon_GetWeaponPrimeTime&lt;br /&gt;
Ham_NS_Weapon_PrimeWeapon&lt;br /&gt;
Ham_NS_Weapon_GetIsWeaponPrimed&lt;br /&gt;
Ham_NS_Weapon_GetIsWeaponPriming&lt;br /&gt;
Ham_NS_Weapon_DefaultDeploy&lt;br /&gt;
Ham_NS_Weapon_DefaultReload&lt;br /&gt;
Ham_NS_Weapon_GetDeployTime&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* {{hidden|id=v-sc|labelonly=yes}} Specific to Sven Coop&lt;br /&gt;
{{hidden|id=v-sc|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_SC_GetClassification&lt;br /&gt;
Ham_SC_IsMonster&lt;br /&gt;
Ham_SC_IsPhysX&lt;br /&gt;
Ham_SC_IsPointEntity&lt;br /&gt;
Ham_SC_IsMachine&lt;br /&gt;
Ham_SC_CriticalRemove&lt;br /&gt;
Ham_SC_UpdateOnRemove&lt;br /&gt;
Ham_SC_FVisible&lt;br /&gt;
Ham_SC_FVisibleFromPos&lt;br /&gt;
Ham_SC_IsFacing&lt;br /&gt;
Ham_SC_GetPointsForDamage&lt;br /&gt;
Ham_SC_GetDamagePoints&lt;br /&gt;
Ham_SC_OnCreate&lt;br /&gt;
Ham_SC_OnDestroy&lt;br /&gt;
Ham_SC_IsValidEntity&lt;br /&gt;
Ham_SC_ShouldFadeOnDeath&lt;br /&gt;
Ham_SC_SetupFriendly&lt;br /&gt;
Ham_SC_ReviveThink&lt;br /&gt;
Ham_SC_Revive&lt;br /&gt;
Ham_SC_StartMonster&lt;br /&gt;
Ham_SC_CheckRangeAttack1_Move&lt;br /&gt;
Ham_SC_CheckRangeAttack2_Move&lt;br /&gt;
Ham_SC_CheckMeleeAttack1_Move&lt;br /&gt;
Ham_SC_CheckMeleeAttack2_Move&lt;br /&gt;
Ham_SC_CheckTankUsage&lt;br /&gt;
Ham_SC_SetGaitActivity&lt;br /&gt;
Ham_SC_FTriangulate&lt;br /&gt;
Ham_SC_FTriangulateExtension&lt;br /&gt;
Ham_SC_FindCoverGrenade&lt;br /&gt;
Ham_SC_FindCoverDistance&lt;br /&gt;
Ham_SC_FindAttackPoint&lt;br /&gt;
Ham_SC_FValidateCover&lt;br /&gt;
Ham_SC_NoFriendlyFire1&lt;br /&gt;
Ham_SC_NoFriendlyFire2&lt;br /&gt;
Ham_SC_NoFriendlyFire3&lt;br /&gt;
Ham_SC_NoFriendlyFireToPos&lt;br /&gt;
Ham_SC_FVisibleGunPos&lt;br /&gt;
Ham_SC_FInBulletCone&lt;br /&gt;
Ham_SC_CallGibMonster&lt;br /&gt;
Ham_SC_CheckTimeBasedDamage&lt;br /&gt;
Ham_SC_IsMoving&lt;br /&gt;
Ham_SC_IsPlayerFollowing&lt;br /&gt;
Ham_SC_StartPlayerFollowing&lt;br /&gt;
Ham_SC_StopPlayerFollowing&lt;br /&gt;
Ham_SC_UseSound&lt;br /&gt;
Ham_SC_UnUseSound&lt;br /&gt;
Ham_SC_RideMonster&lt;br /&gt;
Ham_SC_CheckAndApplyGenericAttacks&lt;br /&gt;
Ham_SC_CheckScared&lt;br /&gt;
Ham_SC_CheckCreatureDanger&lt;br /&gt;
Ham_SC_CheckFallDamage&lt;br /&gt;
Ham_SC_CheckRevival&lt;br /&gt;
Ham_SC_MedicCallSound&lt;br /&gt;
Ham_SC_TakeHealth,&lt;br /&gt;
Ham_SC_TakeArmor,&lt;br /&gt;
Ham_SC_GiveAmmo,&lt;br /&gt;
Ham_SC_CheckAttacker,&lt;br /&gt;
Ham_SC_Player_IsConnected,&lt;br /&gt;
Ham_SC_Player_MenuInputPerformed&lt;br /&gt;
Ham_SC_Player_IsMenuInputDone&lt;br /&gt;
Ham_SC_Player_SpecialSpawn&lt;br /&gt;
Ham_SC_Player_IsValidInfoEntity&lt;br /&gt;
Ham_SC_Player_LevelEnd&lt;br /&gt;
Ham_SC_Player_VoteStarted&lt;br /&gt;
Ham_SC_Player_CanStartNextVote&lt;br /&gt;
Ham_SC_Player_Vote&lt;br /&gt;
Ham_SC_Player_HasVoted&lt;br /&gt;
Ham_SC_Player_ResetVote&lt;br /&gt;
Ham_SC_Player_LastVoteInput&lt;br /&gt;
Ham_SC_Player_InitVote&lt;br /&gt;
Ham_SC_Player_TimeToStartNextVote&lt;br /&gt;
Ham_SC_Player_ResetView&lt;br /&gt;
Ham_SC_Player_GetLogFrequency&lt;br /&gt;
Ham_SC_Player_LogPlayerStats&lt;br /&gt;
Ham_SC_Player_DisableCollisionWithPlayer&lt;br /&gt;
Ham_SC_Player_EnableCollisionWithPlayer&lt;br /&gt;
Ham_SC_Player_CanTouchPlayer&lt;br /&gt;
Ham_SC_Item_Materialize&lt;br /&gt;
Ham_SC_Weapon_BulletAccuracy&lt;br /&gt;
Ham_SC_Weapon_TertiaryAttack&lt;br /&gt;
Ham_SC_Weapon_BurstSupplement&lt;br /&gt;
Ham_SC_Weapon_GetP_Model&lt;br /&gt;
Ham_SC_Weapon_GetW_Model&lt;br /&gt;
Ham_SC_Weapon_GetV_Model&lt;br /&gt;
Ham_SC_Weapon_PrecacheCustomModels&lt;br /&gt;
Ham_SC_Weapon_IsMultiplayer&lt;br /&gt;
Ham_SC_Weapon_FRunfuncs&lt;br /&gt;
Ham_SC_Weapon_SetFOV&lt;br /&gt;
Ham_SC_Weapon_FCanRun&lt;br /&gt;
Ham_SC_Weapon_CustomDecrement&lt;br /&gt;
Ham_SC_Weapon_SetV_Model&lt;br /&gt;
Ham_SC_Weapon_SetP_Model&lt;br /&gt;
Ham_SC_Weapon_ChangeWeaponSkin&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* {{hidden|id=v-opf|labelonly=yes}} Specific to Opposing Force&lt;br /&gt;
{{hidden|id=v-opf|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_OPF_MySquadTalkMonsterPointer&lt;br /&gt;
Ham_OPF_WeaponTimeBase&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* {{hidden|id=v-tfc|labelonly=yes}} Specific to Team Fortress Classic&lt;br /&gt;
{{hidden|id=v-tfc|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_TFC_DB_GetItemName&lt;br /&gt;
Ham_TFC_IsTriggered&lt;br /&gt;
Ham_TFC_Killed&lt;br /&gt;
Ham_TFC_RadiusDamage&lt;br /&gt;
Ham_TFC_RadiusDamage2&lt;br /&gt;
Ham_TFC_Weapon_GetNextAttackDelay&lt;br /&gt;
Ham_TFC_Weapon_SendWeaponAnim&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
* {{hidden|id=v-ts|labelonly=yes}} Specific to The Specialists&lt;br /&gt;
{{hidden|id=v-ts|contentonly=yes|content=&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
Ham_TS_Weapon_AlternateAttack&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/alliedmodders/amxmodx/blob/master/plugins/include/ham_const.inc#L1182 ham_const.inc] for a full list (it starts from line 1182).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== MySQL ===&lt;br /&gt;
&lt;br /&gt;
''' Connectivity '''&lt;br /&gt;
&lt;br /&gt;
To improve the connectivity, few features have been added.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Feature&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | ''Reconnection''&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | This has MySQL automatically reconnects if times out or loses connection through {{tt|MYSQL_OPT_RECONNECT|bgcolor=white}} option.&amp;lt;br /&amp;gt; This should prevent &amp;quot;MySQL server has gone away&amp;quot; errors after a while.&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | ''Timeout''&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | This establishes a default read/write timeout for MySQL connectivity through {{tt|MYSQL_OPT_CONNECT_TIMEOUT|bgcolor=white}} option. &amp;lt;br /&amp;gt;A new option to set globally the timeout (60s by default) can be found in {{tt|core.ini|bgcolor=white}} {{hidden|id=mysql_timeout|labelonly=yes}} and a new {{tt|amx_sql_timeout|bgcolor=white}} cvar in {{tt|sql.cfg|bgcolor=white}} {{hidden|id=cvar_timeout|labelonly=yes}}.&lt;br /&gt;
{{hidden|id=mysql_timeout|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
; MySQL default timeout&lt;br /&gt;
mysql_timeout 60&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=cvar_timeout|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
amx_sql_timeout &amp;quot;60&amp;quot;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Miscellaneous '''&lt;br /&gt;
&lt;br /&gt;
* Module threading has been updated to be more responsive. This should help in reducing potential hang up in situations such as on change map or lost connection.&lt;br /&gt;
&lt;br /&gt;
''' Character Set '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|MySQL_SetCharset|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=MySQL_SetCharset|header=Sets the character set of the current connection.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the character set of the current connection.&lt;br /&gt;
 * Like SET NAMES .. in mysql, but stays after connection problems.&lt;br /&gt;
 *&lt;br /&gt;
 * If a connection tuple is supplied, this should be called before SQL_Connect or SQL_ThreadQuery.&lt;br /&gt;
 * Also note the change will remain until you call this function with another value.&lt;br /&gt;
 * This native does nothing in SQLite.&lt;br /&gt;
 *&lt;br /&gt;
 * Example: &amp;quot;utf8&amp;quot;, &amp;quot;latin1&amp;quot;&lt;br /&gt;
 *&lt;br /&gt;
 * @param h					Database or connection tuple Handle.&lt;br /&gt;
 * @param charset			The character set string to change to.&lt;br /&gt;
 * @return					True, if character set was changed, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native bool:SQL_SetCharset(Handle:h, const charset[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== RegEx ===&lt;br /&gt;
&lt;br /&gt;
''' Library '''&lt;br /&gt;
&lt;br /&gt;
The internal {{texttip|PCRE|Perl Compatible Regular Expressions}} library version has been updated from {{tt|6.4|bgcolor=none}} to {{tt|8.35|bgcolor=none}} and has been compiled with UTF-8 support. &amp;lt;br /&amp;gt;&lt;br /&gt;
If you are interested, see the [https://github.com/alliedmodders/amxmodx/blob/master/tools/pcre/ChangeLog changelog].&lt;br /&gt;
&lt;br /&gt;
''' Miscellaneous '''&lt;br /&gt;
&lt;br /&gt;
* {{tt|regex_subtr}}: The internal static buffer has been increased to match the same size as core and has been made UTF-8 safe.&lt;br /&gt;
* The maximum number of sub-patterns has been increased from {{tt|30|bgcolor=none}} to {{tt|150|bgcolor=none}}.&lt;br /&gt;
&lt;br /&gt;
''' New Natives &amp;amp; Stocks '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|regex_compile_ex|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=regex_compile_ex|header=Precompiles a regular expression. &lt;br /&gt;
 &lt;br /&gt;
 {{alert|info|Note:|Similar as {{tt|regex_compile/_c|bgcolor=white}} but with the differences that you can use directly {{tt|PCRE_*|bgcolor=white}} {{hidden|id=pcre_flags|labelonly=yes}} flags and the error parameter is an integer associated to {{tt|REGEX_ERROR_*|bgcolor=white}} {{hidden|id=regex_errors|labelonly=yes}} flags.|opt=full-border}}&lt;br /&gt;
 &lt;br /&gt;
|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Precompiles a regular expression.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Use this if you intend on using the same expression multiple times.&lt;br /&gt;
 *        Pass the regex handle returned here to regex_match_c() to check for matches.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Unlike regex_compile(), this allows you to use PCRE flags directly.&lt;br /&gt;
 *&lt;br /&gt;
 * @param pattern       The regular expression pattern.&lt;br /&gt;
 * @param flags         General flags for the regular expression, see PCRE_* defines.&lt;br /&gt;
 * @param error         Error message encountered, if applicable.&lt;br /&gt;
 * @param maxLen        Maximum string length of the error buffer.&lt;br /&gt;
 * @param errcode       Regex type error code encountered, if applicable. See REGEX_ERROR_* defines.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              Valid regex handle (&amp;gt; 0) on success, or -1 on failure.&lt;br /&gt;
 */&lt;br /&gt;
native Regex:regex_compile_ex(const pattern[], flags = 0, error[]= &amp;quot;&amp;quot;, maxLen = 0, &amp;amp;errcode = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=pcre_flags|contentonly=yes|content=&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Flags for compiling regex expressions.&lt;br /&gt;
 * These come directly from the pcre library and can be used in regex_compile_ex.&lt;br /&gt;
 */&lt;br /&gt;
#define PCRE_CASELESS           0x00000001  /* Ignore Case */&lt;br /&gt;
#define PCRE_MULTILINE          0x00000002  /* Multilines (affects ^ and $ so that they match the start/end of a line rather than matching the start/end of the string). */&lt;br /&gt;
#define PCRE_DOTALL             0x00000004  /* Single line (affects . so that it matches any character, even new line characters). */&lt;br /&gt;
#define PCRE_EXTENDED           0x00000008  /* Pattern extension (ignore whitespace and # comments). */&lt;br /&gt;
#define PCRE_ANCHORED           0x00000010  /* Force pattern anchoring. */&lt;br /&gt;
#define PCRE_DOLLAR_ENDONLY     0x00000020  /* $ not to match newline at end. */&lt;br /&gt;
#define PCRE_UNGREEDY           0x00000200  /* Invert greediness of quantifiers */&lt;br /&gt;
#define PCRE_NOTEMPTY           0x00000400  /* An empty string is not a valid match. */&lt;br /&gt;
#define PCRE_UTF8               0x00000800  /* Use UTF-8 Chars */&lt;br /&gt;
#define PCRE_NO_UTF8_CHECK      0x00002000  /* Do not check the pattern for UTF-8 validity (only relevant if PCRE_UTF8 is set) */&lt;br /&gt;
#define PCRE_NEVER_UTF          0x00010000  /* Lock out interpretation of the pattern as UTF-8 */&lt;br /&gt;
#define PCRE_FIRSTLINE          0x00040000  /* Force matching to be before newline */&lt;br /&gt;
#define PCRE_DUPNAMES           0x00080000  /* Allow duplicate names for subpattern */&lt;br /&gt;
#define PCRE_NEWLINE_CR         0x00100000  /* Specify that a newline is indicated by a single character CR           )                            */&lt;br /&gt;
#define PCRE_NEWLINE_CRLF       0x00300000  /* specify that a newline is indicated by the two-character CRLF sequence )  Overrides the default     */&lt;br /&gt;
#define PCRE_NEWLINE_ANY        0x00400000  /* Specify that any Unicode newline sequence should be recognized.        )  newline definition (LF)   */&lt;br /&gt;
#define PCRE_NEWLINE_ANYCRLF    0x00500000  /* Specify that any of CR, LF and CRLF sequences should be recognized     )                            */&lt;br /&gt;
#define PCRE_UCP                0x20000000  /* Change the way PCRE processes \B, \b, \D, \d, \S, \s, \W, \w etc. to use Unicode properties */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=regex_errors|contentonly=yes|content=&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Regex expression error codes.&lt;br /&gt;
 * This can be used with regex_compile_ex and regex_match_ex.&lt;br /&gt;
 */&lt;br /&gt;
enum /*RegexError*/&lt;br /&gt;
{&lt;br /&gt;
    REGEX_ERROR_NONE           =  0,    /* No error */&lt;br /&gt;
    REGEX_ERROR_NOMATCH        = -1,    /* No match was found */&lt;br /&gt;
    REGEX_ERROR_NULL           = -2,&lt;br /&gt;
    REGEX_ERROR_BADOPTION      = -3,&lt;br /&gt;
    REGEX_ERROR_BADMAGIC       = -4,&lt;br /&gt;
    REGEX_ERROR_UNKNOWN_OPCODE = -5,&lt;br /&gt;
    REGEX_ERROR_NOMEMORY       = -6,&lt;br /&gt;
    REGEX_ERROR_NOSUBSTRING    = -7,&lt;br /&gt;
    REGEX_ERROR_MATCHLIMIT     = -8,&lt;br /&gt;
    REGEX_ERROR_CALLOUT        = -9,    /* Never used by PCRE itself */&lt;br /&gt;
    REGEX_ERROR_BADUTF8        = -10,&lt;br /&gt;
    REGEX_ERROR_BADUTF8_OFFSET = -11,&lt;br /&gt;
    REGEX_ERROR_PARTIAL        = -12,&lt;br /&gt;
    REGEX_ERROR_BADPARTIAL     = -13,&lt;br /&gt;
    REGEX_ERROR_INTERNAL       = -14,&lt;br /&gt;
    REGEX_ERROR_BADCOUNT       = -15,&lt;br /&gt;
    REGEX_ERROR_DFA_UITEM      = -16,&lt;br /&gt;
    REGEX_ERROR_DFA_UCOND      = -17,&lt;br /&gt;
    REGEX_ERROR_DFA_UMLIMIT    = -18,&lt;br /&gt;
    REGEX_ERROR_DFA_WSSIZE     = -19,&lt;br /&gt;
    REGEX_ERROR_DFA_RECURSE    = -20,&lt;br /&gt;
    REGEX_ERROR_RECURSIONLIMIT = -21,&lt;br /&gt;
    REGEX_ERROR_NULLWSLIMIT    = -22,   /* No longer actually used */&lt;br /&gt;
    REGEX_ERROR_BADNEWLINE     = -23,&lt;br /&gt;
    REGEX_ERROR_BADOFFSET      = -24,&lt;br /&gt;
    REGEX_ERROR_SHORTUTF8      = -25,&lt;br /&gt;
    REGEX_ERROR_RECURSELOOP    = -26,&lt;br /&gt;
    REGEX_ERROR_JIT_STACKLIMIT = -27,&lt;br /&gt;
    REGEX_ERROR_BADMODE        = -28,&lt;br /&gt;
    REGEX_ERROR_BADENDIANNESS  = -29,&lt;br /&gt;
    REGEX_ERROR_DFA_BADRESTART = -30,&lt;br /&gt;
    REGEX_ERROR_JIT_BADOPTION  = -31,&lt;br /&gt;
    REGEX_ERROR_BADLENGTH      = -32,&lt;br /&gt;
    REGEX_ERROR_UNSET          = -33&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|regex_match_all|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|regex_match_all_c|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=regex_match_all|header=Matches a string against a regular (compiled) expression pattern, matching all occurrences of the pattern inside the string. &lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|This is similar to using the {{tt|g|bgcolor=white}} flag in perl regex.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Matches a string against a regular expression pattern, matching all occurrences of the&lt;br /&gt;
 * pattern inside the string. This is similar to using the &amp;quot;g&amp;quot; flag in perl regex.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  If you intend on using the same regular expression pattern&lt;br /&gt;
 *        multiple times, consider using regex_compile and regex_match_ex&lt;br /&gt;
 *        instead of making this function reparse the expression each time.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Flags only exist in amxmodx 1.8 and later.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  You should free the returned handle with regex_free()&lt;br /&gt;
 *        when you are done extracting all of the substrings.&lt;br /&gt;
 *&lt;br /&gt;
 * @param string        The string to check.&lt;br /&gt;
 * @param pattern       The regular expression pattern.&lt;br /&gt;
 * @param flags         General flags for the regular expression, see PCRE_* defines.&lt;br /&gt;
 * @param error         Error message encountered, if applicable.&lt;br /&gt;
 * @param maxLen        Maximum string length of the error buffer.&lt;br /&gt;
 * @param errcode       Regex type error code encountered, if applicable. See REGEX_ERROR_* defines.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              -2 = Matching error (error code is stored in ret)&lt;br /&gt;
 *                      -1 = Error in pattern (error message and offset # in error and ret)&lt;br /&gt;
 *                       0 = No match.&lt;br /&gt;
 *                      &amp;gt;1 = Handle for getting more information (via regex_substr)&lt;br /&gt;
 */&lt;br /&gt;
native Regex:regex_match_all(const string[], const pattern[], flags = 0, error[]= &amp;quot;&amp;quot;, maxLen = 0, &amp;amp;errcode = 0);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Matches a string against a pre-compiled regular expression pattern, matching all&lt;br /&gt;
 * occurrences of the pattern inside the string. This is similar to using the &amp;quot;g&amp;quot; flag&lt;br /&gt;
 * in perl regex.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  You should free the returned handle (with regex_free())&lt;br /&gt;
 *        when you are done with this pattern.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  Use the regex handle passed to this function to extract&lt;br /&gt;
 *        matches with regex_substr().&lt;br /&gt;
 *&lt;br /&gt;
 * @param pattern       The regular expression pattern.&lt;br /&gt;
 * @param string        The string to check.&lt;br /&gt;
 * @param ret           Error code, if applicable, or number of results on success.&lt;br /&gt;
 *                      See REGEX_ERROR_* defines.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              -2 = Matching error (error code is stored in ret)&lt;br /&gt;
 *                       0 = No match.&lt;br /&gt;
 *                      &amp;gt;1 = Number of results.&lt;br /&gt;
 */&lt;br /&gt;
native regex_match_all_c(const string[], Regex:pattern, &amp;amp;ret = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|regex_match_simple|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=regex_match_simple|header=Matches a string against a regular expression pattern. Useful if you need to use the pattern one time.}|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Matches a string against a regular expression pattern.&lt;br /&gt;
 *&lt;br /&gt;
 * @note  If you intend on using the same regular expression pattern&lt;br /&gt;
 *        multiple times, consider using compile regex_compile_ex and regex_match*&lt;br /&gt;
 *        instead of making this function reparse the expression each time.&lt;br /&gt;
 *&lt;br /&gt;
 * @param str           The string to check.&lt;br /&gt;
 * @param pattern       The regular expression pattern.&lt;br /&gt;
 * @param flags         General flags for the regular expression.&lt;br /&gt;
 * @param error         Error message, if applicable.&lt;br /&gt;
 * @param maxLen        Maximum length of the error buffer.&lt;br /&gt;
 * @param errcode       Regex type error code encountered, if applicable. See REGEX_ERROR_* defines.&lt;br /&gt;
 *&lt;br /&gt;
 * @return              -2 = Matching error (error code is stored in ret)&lt;br /&gt;
 *                      -1 = Pattern error (error code is stored in ret)&lt;br /&gt;
 *                       0 = No match.&lt;br /&gt;
 *                      &amp;gt;1 = Number of results.&lt;br /&gt;
 */&lt;br /&gt;
stock regex_match_simple(const str[], const pattern[], flags = 0, error[]= &amp;quot;&amp;quot;, maxLen = 0, &amp;amp;errcode = 0)&lt;br /&gt;
{&lt;br /&gt;
    new Regex:regex = regex_compile_ex(pattern, flags, error, maxLen, errcode);&lt;br /&gt;
    if (regex &amp;lt; REGEX_OK)&lt;br /&gt;
    {&lt;br /&gt;
        return -1;&lt;br /&gt;
    }&lt;br /&gt;
    new substrings = regex_match_c(str, regex);&lt;br /&gt;
    regex_free(regex);&lt;br /&gt;
    return substrings;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Socket ===&lt;br /&gt;
&lt;br /&gt;
* WinSock is now update from version {{tt|1.1|bgcolor=white}} to {{tt|2.2|bgcolor=white}}&lt;br /&gt;
* Natives won't be registered if WinSock can't be started&lt;br /&gt;
&lt;br /&gt;
''' Improvements '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Parameter&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=socket_open|labelonly=yes}} {{tt|socket_open|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|_flags|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | &lt;br /&gt;
The following flags are additive:&lt;br /&gt;
* {{tt|SOCK_NON_BLOCKING|bgcolor=white}}: if set, the socket will be on nonblocking mode&lt;br /&gt;
* {{tt|SOCK_LIBC_ERRORS|bgcolor=white}}: f set, the new libc errors will be seen on {{tt|_error|bgcolor=white}}&lt;br /&gt;
&lt;br /&gt;
{{hidden|id=socket_open|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Error reporting&lt;br /&gt;
 */&lt;br /&gt;
#define SOCK_ERROR_OK               0 /* No error */&lt;br /&gt;
#define SOCK_ERROR_CREATE_SOCKET    1 /* Couldn't create a socket */&lt;br /&gt;
#define SOCK_ERROR_SERVER_UNKNOWN   2 /* Server unknown */&lt;br /&gt;
#define SOCK_ERROR_WHILE_CONNECTING 3 /* Error while connecting */&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Connects to the given node and service via TCP/UDP.&lt;br /&gt;
 *&lt;br /&gt;
 * @note There's 2 types of error reporting on this function that you can use.&lt;br /&gt;
 * @note Default error codes:&lt;br /&gt;
 *       0 - No error&lt;br /&gt;
 *       1 - Error while creating socket&lt;br /&gt;
 *       2 - Couldn't resolve hostname&lt;br /&gt;
 *       3 - Couldn't connect&lt;br /&gt;
 * @note New, more expressive libc error codes:&lt;br /&gt;
 *       https://www.gnu.org/software/libc/manual/html_node/Error-Codes.html&lt;br /&gt;
 *       https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/errno.h&lt;br /&gt;
 *       https://msdn.microsoft.com/en-us/library/ms740668.aspx&lt;br /&gt;
 *&lt;br /&gt;
 * @note The currently available bit flags are:&lt;br /&gt;
 *       - SOCK_NON_BLOCKING : if set, the socket will be on nonblocking mode&lt;br /&gt;
 *       - SOCK_LIBC_ERRORS : if set, the new libc errors will be seen on _error&lt;br /&gt;
 *&lt;br /&gt;
 * @note If no flags are set, the behaviour of the function will not be modified.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Multiple flags may be set at the same time using the | operator. &lt;br /&gt;
 *       For example, SOCK_NON_BLOCKING|SOCK_LIBC_ERRORS will create a nonblocking socket with libc error codes.&lt;br /&gt;
 *&lt;br /&gt;
 * @note If you're creating a new nonblocking socket, _hostname should be numeric to avoid calling the &lt;br /&gt;
 *       name resolution server and potentially blocking the call.&lt;br /&gt;
 *&lt;br /&gt;
 * @note If the socket is a nonblocking one, the returned socket descriptor may be still connecting and &lt;br /&gt;
 *       further checks should be done with socket_is_writable() before trying to send data.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _hostname    Node to connect to&lt;br /&gt;
 * @param _port        Service to connect to&lt;br /&gt;
 * @param _protocol    Connect via SOCKET_TCP or SOCKET_UDP&lt;br /&gt;
 * @param _error       Set an error code here if anything goes wrong&lt;br /&gt;
 * @param _flags       Optional bit flags that change the behaviour of the function&lt;br /&gt;
 *&lt;br /&gt;
 * @return             A socket descriptor (a positive integer) on success&lt;br /&gt;
 *                     -1 on failure&lt;br /&gt;
*/&lt;br /&gt;
native socket_open(const _hostname[], _port, _protocol = SOCKET_TCP, &amp;amp;_error, _flags = 0);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|An example is available at [https://github.com/alliedmodders/amxmodx/pull/301#issuecomment-204794080 PR 301]|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
''' New natives '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|socket_is_writable|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=socket_is_writable|header=Checks if a socket is marked as writable.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Checks if a socket is marked as writable.&lt;br /&gt;
 *&lt;br /&gt;
 * @note Use this function to check if a nonblocking socket is ready to be used.&lt;br /&gt;
 * @note Set _timeout to 0 avoid blocking the call.&lt;br /&gt;
 * @note An UDP socket is always writable.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _socket    Socket descriptor&lt;br /&gt;
 * @param _timeout   Amount of time to block the call waiting for the socket to be marked as writable or&lt;br /&gt;
 *                   for the timeout to expire, in µSeconds (1 sec = 1000000 µsec)&lt;br /&gt;
 *&lt;br /&gt;
 * @return           1 if the socket is marked as writable&lt;br /&gt;
 *                   0 otherwise&lt;br /&gt;
 */&lt;br /&gt;
native socket_is_writable(_socket, _timeout = 100000);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|socket_is_readable|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=socket_is_readable|header=Checks if a socket is marked as readable.&lt;br /&gt;
&lt;br /&gt;
 {{alert|info|Note:|This function is an alias of {{tt|socket_change}} which is now deprecated.|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
 |labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Checks if a socket is marked as readable.&lt;br /&gt;
 *&lt;br /&gt;
 * @note You can use this function to make sure there's something on the socket and avoid a blocking call.&lt;br /&gt;
 * @note Set _timeout to 0 avoid blocking the call.&lt;br /&gt;
 * @note A socket will become readable if there's any data or an EOF.&lt;br /&gt;
 *&lt;br /&gt;
 * @param _socket    Socket descriptor&lt;br /&gt;
 * @param _timeout   Amount of time to block the call waiting for the socket to be marked as readable or&lt;br /&gt;
 *                   for the timeout to expire, in µSeconds (1 sec = 1000000 µsec)&lt;br /&gt;
 *&lt;br /&gt;
 * @return           1 if the socket is marked as readable&lt;br /&gt;
 *                   0 otherwise&lt;br /&gt;
 */&lt;br /&gt;
native socket_is_readable(_socket, _timeout = 100000);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== SQLite ===&lt;br /&gt;
&lt;br /&gt;
''' Library '''&lt;br /&gt;
&lt;br /&gt;
The SQLite library version has been updated from {{tt|3.3.13|bgcolor=none}} to {{tt|3.8.8.2|bgcolor=none}}. &amp;lt;br /&amp;gt;&lt;br /&gt;
If you are interested, see the [https://www.sqlite.org/changes.html changelog].&lt;br /&gt;
&lt;br /&gt;
''' Character Set '''&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Stock&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|SQL_SetCharset|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=SQL_SetCharset|header=Sets the character set of the current connection.|labelpos=left||content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets the character set of the current connection.&lt;br /&gt;
 * Like SET NAMES .. in mysql, but stays after connection problems.&lt;br /&gt;
 *&lt;br /&gt;
 * If a connection tuple is supplied, this should be called before SQL_Connect or SQL_ThreadQuery.&lt;br /&gt;
 * Also note the change will remain until you call this function with another value.&lt;br /&gt;
 * This native does nothing in SQLite.&lt;br /&gt;
 *&lt;br /&gt;
 * Example: &amp;quot;utf8&amp;quot;, &amp;quot;latin1&amp;quot;&lt;br /&gt;
 *&lt;br /&gt;
 * @param h					Database or connection tuple Handle.&lt;br /&gt;
 * @param charset			The character set string to change to.&lt;br /&gt;
 * @return					True, if character set was changed, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
native bool:SQL_SetCharset(Handle:h, const charset[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
''' Miscellaneous '''&lt;br /&gt;
&lt;br /&gt;
* The {{tt|queuetime}} value is now properly passed to the {{tt|SQL_ThreadQuery|bgcolor=none}} callback.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== New module ==&lt;br /&gt;
&lt;br /&gt;
=== JSON ===&lt;br /&gt;
&lt;br /&gt;
A JSON module is now part of the official AMX Mod X package.&lt;br /&gt;
&lt;br /&gt;
Essentially:&lt;br /&gt;
* Supports decoding and encoding (also with pretty format)&lt;br /&gt;
* Relies on Parson, which is lighweight and simple JSON library written in C&lt;br /&gt;
* Supports dot notation (Values can be accessed by typing objectA.objectB.value)&lt;br /&gt;
* Allows us to iterate through arrays and objects&lt;br /&gt;
&lt;br /&gt;
{{alert|info|Note:|Examples are available on [https://github.com/alliedmodders/amxmodx/pull/379 Github] an in the {{tt|testsuite}} directory, see [https://github.com/alliedmodders/amxmodx/blob/master/plugins/testsuite/textparse_test.sma textparse.sma].|opt=full-border}}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Native&lt;br /&gt;
 ! style=&amp;quot;padding: 0.4em;&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|General}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_parse|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_parse|header=Parses JSON string or a file that contains JSON.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Parses JSON string or a file that contains JSON.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @param string            String to parse&lt;br /&gt;
 * @param is_file           True to treat string param as filename, false otherwise&lt;br /&gt;
 * @param with_comments     True if parsing JSON includes comments (it will ignore them), false otherwise&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSONValue if error occurred&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_parse(const string[], bool:is_file = false, bool:with_comments = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_equals|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_equals|header=Checks if the first value is the same as the second one.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Checks if the first value is the same as the second one.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value1            JSON handle&lt;br /&gt;
 * @param value2            JSON handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if they are the same, false otherwise&lt;br /&gt;
 * @error                   If passed value is not a valid handle&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_equals(const JSON:value1, const JSON:value2);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_validate|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_validate|header=Validates json by checking if object have identically named fields with matching types.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Validates json by checking if object have identically named&lt;br /&gt;
 * fields with matching types.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Schema {&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;, &amp;quot;age&amp;quot;:0} will validate&lt;br /&gt;
 *                          {&amp;quot;name&amp;quot;:&amp;quot;Joe&amp;quot;, &amp;quot;age&amp;quot;:25} and {&amp;quot;name&amp;quot;:&amp;quot;Joe&amp;quot;, &amp;quot;age&amp;quot;:25, &amp;quot;gender&amp;quot;:&amp;quot;m&amp;quot;},&lt;br /&gt;
 *                          but not {&amp;quot;name&amp;quot;:&amp;quot;Joe&amp;quot;} or {&amp;quot;name&amp;quot;:&amp;quot;Joe&amp;quot;, &amp;quot;age&amp;quot;:&amp;quot;Cucumber&amp;quot;}.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    In case of arrays, only first value in schema&lt;br /&gt;
 *                          is checked against all values in tested array.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Empty objects ({}) validate all objects,&lt;br /&gt;
 *                          empty arrays ([]) validate all arrays,&lt;br /&gt;
 *                          null validates values of every type.&lt;br /&gt;
 *&lt;br /&gt;
 * @param schema            JSON handle&lt;br /&gt;
 * @param value             JSON handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if passed value is valid, false otherwise&lt;br /&gt;
 * @error                   If a schema handle or value handle is invalid&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_validate(const JSON:schema, const JSON:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_get_parent|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_get_parent|header=Gets value's parent handle.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets value's parent handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                  Parent's handle needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value           JSON handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                Parent's handle&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_get_parent(const JSON:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_get_type|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_get_type|header=Gets JSON type of passed value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets JSON type of passed value.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             JSON handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON type (JSONType constants)&lt;br /&gt;
 * @error                   If a value handle is invalid&lt;br /&gt;
 */&lt;br /&gt;
native JSONType:json_get_type(const JSON:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_init_object|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_init_array|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_init_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_init_number|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_init_real|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_init_bool|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_init_object|header=Inits an empty object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Inits an empty object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_init_object();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_init_array|header=Inits an empty array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Inits an empty array.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_init_array();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_init_string|header=Inits string data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Inits string data.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             String that the handle will be initialized with&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_init_string(const value[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_init_number|header=Inits a number.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Inits a number.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             Integer number that the handle will be initialized with&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_init_number(value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_init_real|header=Inits a real number.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Inits a real number.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             Real number that the handle will be initialized with&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_init_real(Float:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_init_bool|header=Inits a boolean value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Inits a boolean value.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             Boolean value that the handle will be initialized with&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_init_bool(bool:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_init_null|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_init_null|header=Inits a null.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Inits a null.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_init_null();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_deep_copy|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_deep_copy|header=Creates deep copy of passed value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Creates deep copy of passed value.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             JSON handle to be copied&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 * @error                   If passed value is not a valid handle&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_deep_copy(const JSON:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_free|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_free|header=Frees handle.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Frees handle.&lt;br /&gt;
 *&lt;br /&gt;
 * @param handle            JSON handle to be freed&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid handle&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_free(&amp;amp;JSON:handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_get_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_get_number|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_get_real|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_get_bool|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_get_string|header=Gets string data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets string data.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             JSON handle&lt;br /&gt;
 * @param buffer            Buffer to copy string to&lt;br /&gt;
 * @param maxlen            Maximum size of the buffer&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  The number of cells written to the buffer&lt;br /&gt;
 * @error                   If passed value is not a valid handle&lt;br /&gt;
 */&lt;br /&gt;
native json_get_string(const JSON:value, buffer[], maxlen);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_get_number|header=Gets a number.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a number.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             JSON handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Number&lt;br /&gt;
 * @error                   If passed value is not a valid handle&lt;br /&gt;
 */&lt;br /&gt;
native json_get_number(const JSON:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_get_real|header=Gets a real number.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a real number.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             JSON handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Real number&lt;br /&gt;
 * @error                   If passed value is not a valid handle&lt;br /&gt;
 */&lt;br /&gt;
native Float:json_get_real(const JSON:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_get_bool|header=Gets a boolean value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a boolean value.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             JSON handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Boolean value&lt;br /&gt;
 * @error                   If passed value is not a valid handle&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_get_bool(const JSON:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Array}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_array_get_value|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_get_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_get_number|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_get_real|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_get_bool|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_get_count|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_array_get_value|header=Gets a value from the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a value from the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array (starting from 0)&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_array_get_value(const JSON:array, index);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_get_string|header=Gets string data from the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets string data from the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array (starting from 0)&lt;br /&gt;
 * @param buffer            Buffer to copy string to&lt;br /&gt;
 * @param maxlen            Maximum size of the buffer&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  The number of cells written to the buffer&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native json_array_get_string(const JSON:array, index, buffer[], maxlen);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_get_number|header=Gets a number from the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a number from the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array (starting from 0)&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  The number as integer&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native json_array_get_number(const JSON:array, index);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_get_real|header=Gets a real number from the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a real number from the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array (starting from 0)&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  The number as float&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native Float:json_array_get_real(const JSON:array, index);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_get_bool|header=Gets a boolean value from the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a boolean value from the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array (starting from 0)&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Boolean value&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_get_bool(const JSON:array, index);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_get_count|header=Gets count of the elements in the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets count of the elements in the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Number of elements in the array&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native json_array_get_count(const JSON:array);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_array_replace_value|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_replace_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_replace_number|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_replace_real|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_replace_bool|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_replace_null|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_array_replace_value|header=Replaces an element in the array with value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Replaces an element in the array with value.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array to be replaced&lt;br /&gt;
 * @param value             JSON handle to set&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_replace_value(JSON:array, index, const JSON:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_replace_string|header=Replaces an element in the array with string data.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Replaces an element in the array with string data.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array to be replaced&lt;br /&gt;
 * @param string            String to copy&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_replace_string(JSON:array, index, const string[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_replace_number|header=Replaces an element in the array with number.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Replaces an element in the array with number.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array to be replaced&lt;br /&gt;
 * @param number            Number to set&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_replace_number(JSON:array, index, number);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_replace_real|header=Replaces an element in the array with real number.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Replaces an element in the array with real number.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array to be replaced&lt;br /&gt;
 * @param number            Real number to set&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_replace_real(JSON:array, index, Float:number);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_replace_bool|header=Replaces an element in the array with boolean value.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Replaces an element in the array with boolean value.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array to be replaced&lt;br /&gt;
 * @param boolean           Boolean value to set&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_replace_bool(JSON:array, index, bool:boolean);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_replace_null|header=Replaces an element in the array with null.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Replaces an element in the array with null.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array to be replaced&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_replace_null(JSON:array, index);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_array_append_value|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_append_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_append_number|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_append_real|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_append_bool|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_array_append_null|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_arrayjson_array_append_value_replace_null|header=Appends a value in the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Appends a value in the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param value             JSON handle to set&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_append_value(JSON:array, const JSON:value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_append_string|header=Appends string data in the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Appends string data in the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param string            String to copy&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_append_string(JSON:array, const string[]);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_append_number|header=Appends a number in the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Appends a number in the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param number            Number to set&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_append_number(JSON:array, number);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_append_real|header=Appends a real number in the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Appends a real number in the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param number            Real number to set&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_append_real(JSON:array, Float:number);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_append_bool|header=Appends a boolean value in the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Appends a boolean value in the array.Appends a boolean value in the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param boolean           Boolean value to set&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_append_bool(JSON:array, bool:boolean);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_array_append_null|header=Appends a null in the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Appends a null in the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_append_null(JSON:array);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_array_remove|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_array_remove|header=Removes an element from the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Removes an element from the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Order of values in array may change during execution.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 * @param index             Position in the array (starting from 0)&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_remove(JSON:array, index);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_array_clear|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_array_clear|header=Removes all elements from the array.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Removes all elements from the array.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array             Array handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid array&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_array_clear(JSON:array);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Object}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_object_get_value|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_get_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_get_number|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_get_real|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_get_bool|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_object_get_value|header=Gets a value from the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a value from the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  JSON handle, Invalid_JSON if error occurred&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_object_get_value(const JSON:object, const name[], bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_get_string|header=Gets string data from the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets string data from the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param buffer            Buffer to copy string to&lt;br /&gt;
 * @param maxlen            Maximum size of the buffer&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  The number of cells written to the buffer&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native json_object_get_string(const JSON:object, const name[], buffer[], maxlen, bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_get_number|header=Gets a number from the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a number from the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Number&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native json_object_get_number(const JSON:object, const name[], bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_get_real|header=Gets a real number from the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a real number from the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Real number&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native Float:json_object_get_real(const JSON:object, const name[], bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_get_bool|header=Gets a boolean value from the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a boolean value from the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Boolean value&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_get_bool(const JSON:object, const name[], bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_object_get_count|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_get_name|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_object_get_count|header=Gets count of the keys in the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets count of the keys in the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Keys count&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native json_object_get_count(const JSON:object);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_get_name|header=Gets name of the object's key.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets name of the object's key.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param index             Position from which get key name&lt;br /&gt;
 * @param buffer            Buffer to copy string to&lt;br /&gt;
 * @param maxlen            Maximum size of the buffer&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  The number of cells written to the buffer&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native json_object_get_name(const JSON:object, index, buffer[], maxlen);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_object_get_value_at|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_object_get_value_at|header=Gets a value at the specified position from the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets a value at the specified position from the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    Needs to be freed using json_free() native.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param index             Position from which get key name&lt;br /&gt;
 * @param buffer            Buffer to copy string to&lt;br /&gt;
 * @param maxlen            Maximum size of the buffer&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  The number of cells written to the buffer&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native JSON:json_object_get_value_at(const JSON:object, index);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_object_has_value|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_object_has_value|header=Checks if the object has a value with a specific name and type.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Checks if the object has a value with a specific name and type.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param type              Type of value, if JSONError type will not be checked&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if has, false if not&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_has_value(const JSON:object, const name[], JSONType:type = JSONError, bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_object_set_value|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_set_string|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_set_number|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_set_real|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_set_bool|bgcolor=white}}&amp;lt;br /&amp;gt;{{tt|json_object_set_null|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_object_set_value|header=Sets a value in the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a value in the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 * @note                    It also removes the old value if any.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param value             JSON handle to set&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_set_value(JSON:object, const name[], const JSON:value, bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_set_string|header=Sets string data in the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets string data in the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 * @note                    It also removes the old value if any.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param string            String to copy&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_set_string(JSON:object, const name[], const string[], bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_set_number|header=Sets a number in the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a number in the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 * @note                    It also removes the old value if any.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param number            Number to set&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_set_number(JSON:object, const name[], number, bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_set_real|header=Sets a real number in the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a real number in the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 * @note                    It also removes the old value if any.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param number            Real number to set&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_set_real(JSON:object, const name[], Float:number, bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_set_bool|header=Sets a boolean value in the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a boolean value in the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 * @note                    It also removes the old value if any.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param boolean           Boolean value to set&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_set_bool(JSON:object, const name[], bool:boolean, bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{hidden|id=json_object_set_null|header=Sets a null in the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Sets a null in the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 * @note                    It also removes the old value if any.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_set_null(JSON:object, const name[], bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_object_remove|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_object_remove|header=Removes a key and its value in the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Removes a key and its value in the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @note                    If dot notation is used some values may be inaccessible&lt;br /&gt;
 *                          because valid names in JSON can contain dots.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 * @param name              Key name&lt;br /&gt;
 * @param dot_not           True to use dot notation, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_remove(JSON:object, const name[], bool:dot_not = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_object_clear|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_object_clear|header=Removes all keys and their values in the object.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Removes all keys and their values in the object.&lt;br /&gt;
 *&lt;br /&gt;
 * @param object            Object handle&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid object&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_object_clear(JSON:object);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em; text-align: center; background-color: white;&amp;quot; colspan=&amp;quot;2&amp;quot; | {{color|steelblue|Serialization}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_serial_size|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_serial_size|header=Gets size of serialization.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Gets size of serialization.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             JSON handle&lt;br /&gt;
 * @param pretty            True to count size for pretty format, false to not&lt;br /&gt;
 * @param null_byte         True to include null byte, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  Size of serialized string&lt;br /&gt;
 * @error                   If passed handle is not a valid value&lt;br /&gt;
 */&lt;br /&gt;
native json_serial_size(const JSON:value, bool:pretty = false, bool:null_byte = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_serial_to_string|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_serial_to_string|header=Copies serialized string to the buffer.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Copies serialized string to the buffer.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             JSON handle&lt;br /&gt;
 * @param buffer            Buffer to copy string to&lt;br /&gt;
 * @param maxlen            Maximum size of the buffer&lt;br /&gt;
 * @param pretty            True to format pretty JSON string, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  The number of cells written to the buffer&lt;br /&gt;
 * @error                   If passed handle is not a valid value&lt;br /&gt;
 */&lt;br /&gt;
native json_serial_to_string(const JSON:value, buffer[], maxlen, bool:pretty = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{tt|json_serial_to_file|bgcolor=white}}&lt;br /&gt;
 | style=&amp;quot;padding: 0.4em;&amp;quot; | {{hidden|id=json_serial_to_file|header=Copies serialized string to the file.|labelpos=left|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Copies serialized string to the file.&lt;br /&gt;
 *&lt;br /&gt;
 * @param value             JSON handle&lt;br /&gt;
 * @param file              Path to the file&lt;br /&gt;
 * @param pretty            True to format pretty JSON string, false to not&lt;br /&gt;
 *&lt;br /&gt;
 * @return                  True if succeed, false otherwise&lt;br /&gt;
 * @error                   If passed handle is not a valid value&lt;br /&gt;
 */&lt;br /&gt;
native bool:json_serial_to_file(const JSON:value, const file[], bool:pretty = false);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
{{alert|success|Constants &amp;amp; Macros:|{{hidden|id=json_example|labelonly=yes}}|opt=full-border}}&lt;br /&gt;
{{hidden|id=json_example|contentonly=yes|content=&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * JSON types&lt;br /&gt;
 */&lt;br /&gt;
enum JSONType&lt;br /&gt;
{&lt;br /&gt;
    JSONError   = -1,&lt;br /&gt;
    JSONNull    = 1,&lt;br /&gt;
    JSONString  = 2,&lt;br /&gt;
    JSONNumber  = 3,&lt;br /&gt;
    JSONObject  = 4,&lt;br /&gt;
    JSONArray   = 5,&lt;br /&gt;
    JSONBoolean = 6&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * JSON invalid handle&lt;br /&gt;
 */&lt;br /&gt;
enum JSON&lt;br /&gt;
{&lt;br /&gt;
    Invalid_JSON = -1&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Helper macros for checking type&lt;br /&gt;
 */&lt;br /&gt;
#define json_is_object(%1)   (%1 != Invalid_JSON &amp;amp;&amp;amp; json_get_type(%1) == JSONObject)&lt;br /&gt;
#define json_is_array(%1)    (%1 != Invalid_JSON &amp;amp;&amp;amp; json_get_type(%1) == JSONArray)&lt;br /&gt;
#define json_is_string(%1)   (%1 != Invalid_JSON &amp;amp;&amp;amp; json_get_type(%1) == JSONString)&lt;br /&gt;
#define json_is_number(%1)   (%1 != Invalid_JSON &amp;amp;&amp;amp; json_get_type(%1) == JSONNumber)&lt;br /&gt;
#define json_is_bool(%1)     (%1 != Invalid_JSON &amp;amp;&amp;amp; json_get_type(%1) == JSONBoolean)&lt;br /&gt;
#define json_is_null(%1)     (%1 != Invalid_JSON &amp;amp;&amp;amp; json_get_type(%1) == JSONNull)&lt;br /&gt;
#define json_is_true(%1)     (%1 != Invalid_JSON &amp;amp;&amp;amp; json_is_bool(%1) &amp;amp;&amp;amp; json_get_bool(%1))&lt;br /&gt;
#define json_is_false(%1)    (%1 != Invalid_JSON &amp;amp;&amp;amp; json_is_bool(%1) &amp;amp;&amp;amp; !json_get_bool(%1))&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Events_(SourceMod_Scripting)&amp;diff=10163</id>
		<title>Events (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Events_(SourceMod_Scripting)&amp;diff=10163"/>
		<updated>2016-05-05T23:00:55Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Rewriting Events */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:''To view all the events, click [[Game Events (Source)|here]].''&lt;br /&gt;
&lt;br /&gt;
Events are short, named messages sent by the server.  Although they are used for internal message passing, they are also networked to clients.&lt;br /&gt;
&lt;br /&gt;
All event natives are found in &amp;lt;tt&amp;gt;scripting/include/events.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Events are documented in &amp;lt;tt&amp;gt;.res&amp;lt;/tt&amp;gt; files under a mod's &amp;lt;tt&amp;gt;resource&amp;lt;/tt&amp;gt; folder.  The &amp;quot;default&amp;quot; events are located in &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;hl2/resource/serverevents.res&amp;lt;/tt&amp;gt;.  Mods can extend these events with their own.  &lt;br /&gt;
&lt;br /&gt;
For example, let's look at &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; from &amp;lt;tt&amp;gt;hl2/resource/gameevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID who died				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID who killed&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Counter-Strike:Source extends this definition in &amp;lt;tt&amp;gt;cstrike/resource/modevents.res&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;player_death&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;userid&amp;quot;	&amp;quot;short&amp;quot;   	// user ID who died				&lt;br /&gt;
	&amp;quot;attacker&amp;quot;	&amp;quot;short&amp;quot;	 	// user ID who killed&lt;br /&gt;
	&amp;quot;weapon&amp;quot;	&amp;quot;string&amp;quot; 	// weapon name killer used &lt;br /&gt;
	&amp;quot;headshot&amp;quot;	&amp;quot;bool&amp;quot;		// signals a headshot&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the event is structured in the following format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;name&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;key1&amp;quot;	&amp;quot;valueType1&amp;quot;&lt;br /&gt;
	&amp;quot;key2&amp;quot;	&amp;quot;valueType2&amp;quot;&lt;br /&gt;
	...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Sending Events=&lt;br /&gt;
Events are very easy to send.  For example, let's say we want to send a death message using the &amp;lt;tt&amp;gt;player_death&amp;lt;/tt&amp;gt; event from above.  For Counter-Strike:Source, this would look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;void SendDeathMessage(int attacker, int victim, const char[] weapon, bool headshot)&lt;br /&gt;
{&lt;br /&gt;
	Event event = CreateEvent(&amp;quot;player_death&amp;quot;);&lt;br /&gt;
	if (event == null)&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	event.SetInt(&amp;quot;userid&amp;quot;, GetClientUserId(victim));&lt;br /&gt;
	event.SetInt(&amp;quot;attacker&amp;quot;, GetClientUserId(attacker));&lt;br /&gt;
	event.SetString(&amp;quot;weapon&amp;quot;, weapon);&lt;br /&gt;
	event.SetBool(&amp;quot;headshot&amp;quot;, headshot);&lt;br /&gt;
	event.Fire();&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
*You don't need to call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; does this for us.&lt;br /&gt;
*Even though &amp;quot;userid&amp;quot; and &amp;quot;attacker&amp;quot; are shorts, we set them as ints.  The term &amp;quot;short&amp;quot; is only used to tell the engine how many bytes of the integer are needed to be networked.&lt;br /&gt;
*It is possible for event creation to fail; this can happen if the event does not exist, or nothing is hooking the event.  Thus, you should always make sure &amp;lt;tt&amp;gt;CreateEvent&amp;lt;/tt&amp;gt; calls return a valid Event handle.&lt;br /&gt;
*Most events use client userids instead of client indexes.&lt;br /&gt;
*By default, &amp;lt;tt&amp;gt;FireEvent()&amp;lt;/tt&amp;gt; broadcasts messages to clients.  This can be prevented by passing &amp;lt;tt&amp;gt;dontBroadcast&amp;lt;/tt&amp;gt; as true.&lt;br /&gt;
&lt;br /&gt;
=Hooking Events=&lt;br /&gt;
When hooking an event, there are three modes to choose from:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; - Hook the event before it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; - Hook the event after it is fired.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Post_NoCopy&amp;lt;/tt&amp;gt; - Hook the event, but do not save any of its information (special optimization).&lt;br /&gt;
&lt;br /&gt;
Hooking an event is usually done for one of the following goals.  To get an idea of which mode to use, see the list below each goal:&lt;br /&gt;
*Blocking the event (preventing it from being fired)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Rewriting the event (changing its parameters)&lt;br /&gt;
**'''Always &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
*Acting upon the event (doing something once the event is completed)&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt;''' if your action must come before the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;''' if your action must come after the mod's action.&lt;br /&gt;
**'''&amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt;''' if your action is &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; and only requires the event name.&lt;br /&gt;
&lt;br /&gt;
As always, you do not need to unhook events when your plugin unloads.  They are automatically removed.&lt;br /&gt;
&lt;br /&gt;
==Blocking Events==&lt;br /&gt;
Blocking events is the easiest thing to do.  Let's say we want to block death events that are headshots:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	if (event.GetBool(&amp;quot;headshot&amp;quot;))&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Handled;&lt;br /&gt;
	}&lt;br /&gt;
	return Plugin_Continue;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Blocking events does not necessarily block actions like damaging players.&lt;br /&gt;
&lt;br /&gt;
==Rewriting Events==&lt;br /&gt;
Rewriting events is just as easy -- events can be modified in pre hooks.  For example, say we want to remove headshots from all events:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath, EventHookMode_Pre);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	event.SetBool(&amp;quot;headshot&amp;quot;, false);&lt;br /&gt;
	return Plugin_Continue;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Post Hooks==&lt;br /&gt;
Post hooks are default, and will usually be the most common usage.  For example, say we want to print a message to every client that dies:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;player_death&amp;quot;, Event_PlayerDeath);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	char weapon[64];&lt;br /&gt;
	int victimId = event.GetInt(&amp;quot;userid&amp;quot;);&lt;br /&gt;
	int attackerId = event.GetInt(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
	bool headshot = event.GetBool(&amp;quot;headshot&amp;quot;);&lt;br /&gt;
	event.GetString(&amp;quot;weapon&amp;quot;, weapon, sizeof(weapon));&lt;br /&gt;
&lt;br /&gt;
	char name[64];&lt;br /&gt;
	int victim = GetClientOfUserId(victimId);&lt;br /&gt;
	int attacker = GetClientOfUserId(attackerId);&lt;br /&gt;
	GetClientName(attacker, name, sizeof(name));&lt;br /&gt;
&lt;br /&gt;
	PrintToConsole(victim,&lt;br /&gt;
		&amp;quot;You were killed by \&amp;quot;%s\&amp;quot; (weapon \&amp;quot;%s\&amp;quot;) (headshot \&amp;quot;%d\&amp;quot;)&amp;quot;,&lt;br /&gt;
		name,&lt;br /&gt;
		weapon,&lt;br /&gt;
		headshot);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will print a message to a player's console telling them who killed them, with what weapon, and whether it was a headshot or not.&lt;br /&gt;
&lt;br /&gt;
Note that the return value for post hooks is ignored, so the &amp;lt;tt&amp;gt;Action&amp;lt;/tt&amp;gt; tag is not needed.&lt;br /&gt;
&lt;br /&gt;
==PostNoCopy Hooks==&lt;br /&gt;
Lastly, there are some hooks where the only piece of information needed is the name of the event.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; is a special optimization for this case.  When transitioning from &amp;lt;tt&amp;gt;Pre&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt;, SourceMod must duplicate the event and all of its key/value pairs.  &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; prevents that sequence from happening.&lt;br /&gt;
&lt;br /&gt;
For example, let's say we want to find when a certain sequence of events is called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	HookEvent(&amp;quot;game_newmap&amp;quot;, GameEvents, EventHookMode_PostNoCopy);&lt;br /&gt;
	HookEvent(&amp;quot;game_start&amp;quot;, GameEvents, EventHookMode_PostNoCopy);&lt;br /&gt;
	HookEvent(&amp;quot;game_end&amp;quot;, GameEvents, EventHookMode_PostNoCopy);&lt;br /&gt;
	HookEvent(&amp;quot;game_message&amp;quot;, GameEvents, EventHookMode_PostNoCopy);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void GameEvents(Event event, const char[] name, bool dontBroadcast)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Event has been fired (event \&amp;quot;%s\&amp;quot;) (nobcast \&amp;quot;%d\&amp;quot;)&amp;quot;, name, dontBroadcast);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that like normal &amp;lt;tt&amp;gt;Post&amp;lt;/tt&amp;gt; hooks, there is no return value needed.  However, the &amp;lt;tt&amp;gt;event&amp;lt;/tt&amp;gt; parameter for &amp;lt;tt&amp;gt;PostNoCopy&amp;lt;/tt&amp;gt; will '''always''' be equal to &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt;.  Thus, the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; parameter must be used instead of &amp;lt;tt&amp;gt;event.GetName&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=10098</id>
		<title>Compiling libprotobuf</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=10098"/>
		<updated>2016-01-09T14:47:12Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Undo revision 10097 by Psychonic (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Examples for compiling a 32-bit libprotobuf and other protobuf libraries using the protobuf-2.5.0 source.&lt;br /&gt;
&lt;br /&gt;
''For Dota 2, replace version 2.5.0 with 2.6.1.''&lt;br /&gt;
&lt;br /&gt;
''Also note that the Protobuf source has moved to [http://www.github.com/google/protobuf GitHub]. Some of the below links may be outdated.''&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
The following was tested on Windows 8.1 with Visual Studio 2013. Not all projects built after conversion, but only libprotobuf and dependencies were necessary.&lt;br /&gt;
&lt;br /&gt;
* Download protobuf-2.5.0.zip from https://code.google.com/p/protobuf/downloads/list&lt;br /&gt;
* Extract and navigate to protobuf-2.5.0/vsprojects/&lt;br /&gt;
* Open protobuf.sln in the version of Visual Studio corresponding with the VC abi version that you wish to compile for.&lt;br /&gt;
* Walk through project conversion steps if necessary.&lt;br /&gt;
* Right-click the libprotobuf project and choose properties.&lt;br /&gt;
* In Configuration Properties &amp;gt; C/C++ -&amp;gt; Code Generation, set Runtime Library to /MT for Release or /MTd for Debug.&lt;br /&gt;
* If building the Debug configuration, also add _ITERATOR_DEBUG_LEVEL=0 in Configuration Properties &amp;gt; C/C++ &amp;gt; Preprocessor &amp;gt; Preprocessor Defintions&lt;br /&gt;
* Right-click the libprotobuf project and choose Build.&lt;br /&gt;
&lt;br /&gt;
libprotobuf.lib will be in Release/ or Debug/, depending on build configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (32-bit host)==&lt;br /&gt;
The following was tested on Debian 6 (Lenny) 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure CXXFLAGS=&amp;quot;-g3 -ggdb3&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (64-bit host)==&lt;br /&gt;
This hasn't been tested, but ''should'' work on most or all 64-bit distributions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Mac==&lt;br /&gt;
The following was tested on OS X 10.7 (Lion) and ensures that the outputted binaries are 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-DNDEBUG -m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=10097</id>
		<title>Compiling libprotobuf</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=10097"/>
		<updated>2016-01-08T13:37:37Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Examples for compiling a 32-bit libprotobuf and other protobuf libraries using the protobuf-2.5.0 source.&lt;br /&gt;
&lt;br /&gt;
''For Dota 2, replace version 2.5.0 with 2.6.1.''&lt;br /&gt;
&lt;br /&gt;
''Also note that the Protobuf source has moved to [http://www.github.com/google/protobuf GitHub]. Some of the below links may be outdated.''&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
The following was tested on Windows 8.1 with Visual Studio 2013. Not all projects built after conversion, but only libprotobuf and dependencies were necessary.&lt;br /&gt;
&lt;br /&gt;
* Download protobuf-2.5.0.zip from https://code.google.com/p/protobuf/downloads/list&lt;br /&gt;
* Extract and navigate to protobuf-2.5.0/vsprojects/&lt;br /&gt;
* Open protobuf.sln in the version of Visual Studio corresponding with the VC abi version that you wish to compile for.&lt;br /&gt;
* Walk through project conversion steps if necessary.&lt;br /&gt;
* Right-click the libprotobuf project and choose properties.&lt;br /&gt;
* In Configuration Properties &amp;gt; C/C++ -&amp;gt; Code Generation, set Runtime Library to /MT for Release or /MTd for Debug.&lt;br /&gt;
* If building the Debug configuration, also add _ITERATOR_DEBUG_LEVEL=0 in Configuration Properties &amp;gt; C/C++ &amp;gt; Preprocessor &amp;gt; Preprocessor Defintions&lt;br /&gt;
* Right-click the libprotobuf project and choose Build.&lt;br /&gt;
&lt;br /&gt;
libprotobuf.lib will be in Release/ or Debug/, depending on build configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (32-bit host)==&lt;br /&gt;
The following was tested on Debian 6 (Lenny) 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure CFLAGS=&amp;quot;-fvisibility=hidden&amp;quot; CXXFLAGS=&amp;quot;-g3 -ggdb3&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (64-bit host)==&lt;br /&gt;
This hasn't been tested, but ''should'' work on most or all 64-bit distributions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32 -DNDEBUG -fvisibility=hidden&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32 -fvisibility=hidden&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Mac==&lt;br /&gt;
The following was tested on OS X 10.7 (Lion) and ensures that the outputted binaries are 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-DNDEBUG -m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-m32 -fvisibility=hidden&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Writing_Multi-Game_SourceMod_Plugins&amp;diff=10062</id>
		<title>Writing Multi-Game SourceMod Plugins</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Writing_Multi-Game_SourceMod_Plugins&amp;diff=10062"/>
		<updated>2015-11-22T13:25:23Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Detecting Fake Deaths */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Different Source games tend to have different quirks.  This page discusses the more common quirks you'll run into.&lt;br /&gt;
&lt;br /&gt;
== Detecting the current game ==&lt;br /&gt;
&lt;br /&gt;
In order to use what you learn from this document, you will need to detect which game the plugin is running on.&lt;br /&gt;
&lt;br /&gt;
To detect the current game, use the GetEngineVersion() function, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;new EngineVersion:g_EngineVersion;&lt;br /&gt;
&lt;br /&gt;
// In OnPluginStart&lt;br /&gt;
    g_EngineVersion = GetEngineVersion();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This isn't always necessary for games that use different events, but it's still a good idea.&lt;br /&gt;
&lt;br /&gt;
== Round Start ==&lt;br /&gt;
&lt;br /&gt;
Most plugin writers assume that hooking [[Generic Source Events#round_start|round_start]] will make things work on all games.  Those plugin writers would be wrong.&lt;br /&gt;
&lt;br /&gt;
Several games use other events instead or have behavior that needs to be taken into account.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Game&lt;br /&gt;
! Fires round_start?&lt;br /&gt;
! Alternate Event&lt;br /&gt;
| Extra Quirks&lt;br /&gt;
|-&lt;br /&gt;
| Half-Life 2: DeathMatch&lt;br /&gt;
| Yes&lt;br /&gt;
| [[Half-Life 2: Deathmatch Events#teamplay_round_start|teamplay_round_start]]&lt;br /&gt;
| teamplay_round_start is only fired for Team Deathmatch&lt;br /&gt;
|-&lt;br /&gt;
| Day of Defeat: Source&lt;br /&gt;
| No&lt;br /&gt;
| [[Day of Defeat: Source Events#dod_round_start|dod_round_start]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| Team Fortress 2&lt;br /&gt;
| No&lt;br /&gt;
| [[Team Fortress 2 Events#teamplay_round_start|teamplay_round_start]]&lt;br /&gt;
| '''full_reset''' will be false if this is not the first round of a multi-round map. In Arena mode, the [[Team Fortress 2 Events#arena_round_start|arena_round_start]] event fires when players can start moving.&lt;br /&gt;
|-&lt;br /&gt;
| Counter-Strike: Global Offensive&lt;br /&gt;
| Yes&lt;br /&gt;
|&lt;br /&gt;
| round_start is fired during warmup round&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Round End ==&lt;br /&gt;
&lt;br /&gt;
[[Generic Source Events#round_end|round_end]], like round_start, isn't the same across all games.&lt;br /&gt;
&lt;br /&gt;
Most of the time, '''winner''' is the team ID of the winning team: 0 for stalemate, 2 for team 1 (Combine, Allies, Terrorists, RED, or Survivors), or 3 for team 2 (Rebels, Axis, Counter-Terrorists, BLU, or Infected).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Game&lt;br /&gt;
! Fires round_end?&lt;br /&gt;
! Alternate Event&lt;br /&gt;
! Extra Quirks&lt;br /&gt;
|-&lt;br /&gt;
| Half-Life 2: DeathMatch&lt;br /&gt;
| Yes&lt;br /&gt;
|&lt;br /&gt;
| winner is a userid for Deathmatch or a team ID for Team Deathmatch&lt;br /&gt;
|-&lt;br /&gt;
| Day of Defeat: Source&lt;br /&gt;
| No&lt;br /&gt;
| [[Day of Defeat: Source Events#dod_round_win|dod_round_win]]&lt;br /&gt;
| '''team''' is the winning team.&lt;br /&gt;
|-&lt;br /&gt;
| Team Fortress 2&lt;br /&gt;
| No&lt;br /&gt;
| See next section&lt;br /&gt;
| See next section&lt;br /&gt;
|-&lt;br /&gt;
| Nuclear Dawn&lt;br /&gt;
| No&lt;br /&gt;
| [[Nuclear Dawn Events#round_win|round_win]]&lt;br /&gt;
| '''team''' is the winning team. '''type''' is the win reason.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Team Fortress 2 ===&lt;br /&gt;
&lt;br /&gt;
Round End is so complicated in Team Fortress 2 that I'm giving it its own section.  TF2 has not just one, but ''four'' different events for round end.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Game Mode&lt;br /&gt;
! Event&lt;br /&gt;
| Quirks&lt;br /&gt;
|-&lt;br /&gt;
| All&lt;br /&gt;
| [[Team Fortress 2 Events#teamplay_round_win|teamplay_round_win]]&lt;br /&gt;
| '''team''' is the winning team. '''winreason''' was only [https://github.com/ValveSoftware/Source-1-Games/issues/1269#issuecomment-24618786 recently fixed] and its meaning depends on the game mode.&lt;br /&gt;
|-&lt;br /&gt;
| All but Arena or MvM&lt;br /&gt;
| [[Team Fortress 2 Events#teamplay_win_panel|teamplay_win_panel]]&lt;br /&gt;
| Win Panel screen, includes each team's score and the scores of the top 3 players. '''winning_team''' is the winning team. '''winreason''' includes captured all points, time ran out, captured flags, etc...&lt;br /&gt;
|-&lt;br /&gt;
| Arena&lt;br /&gt;
| [[Team Fortress 2 Events#arena_win_panel|arena_win_panel]]&lt;br /&gt;
| Arena Win Panel screen, includes each team's score and the scores of the top 3 players for each team. '''winning_team''' is the winning team. '''winreason''' can ''only'' be killed all players on the other team and captured point.&lt;br /&gt;
|-&lt;br /&gt;
| MvM&lt;br /&gt;
| [[Team Fortress 2 Events#pve_win_panel|pve_win_panel]]&lt;br /&gt;
| MvM Win Panel screen. '''winning_team''' is the winning team. Most data is not present in this event and is instead interpolated from the CTFPlayerResource netprops.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== player_death ==&lt;br /&gt;
All games appear to use the player_death event, but the fields available to each game vary radically.&lt;br /&gt;
&lt;br /&gt;
The quirks you need to know about are:&lt;br /&gt;
&lt;br /&gt;
=== Detecting Fake Deaths ===&lt;br /&gt;
&lt;br /&gt;
Team Fortress 2 introduced the concept of fake deaths.  In order to detect if a death was fake, you need to do something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
// At top of file&lt;br /&gt;
#include &amp;lt;tf2_stocks&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// in player_death hook&lt;br /&gt;
   new bool:bFake = g_EngineVersion == Engine_TF2 &amp;amp;&amp;amp; (GetEventInt(event, &amp;quot;death_flags&amp;quot;) &amp;amp; TF_DEATHFLAG_DEADRINGER);&lt;br /&gt;
   // if bFake is true, the it was a fake death&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Detecting Headshots ==&lt;br /&gt;
&lt;br /&gt;
Not all games support headshots, but those that do have them done differently.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== player_death ===&lt;br /&gt;
&lt;br /&gt;
Headshots can be detected in player_death similarly to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
// At top of file&lt;br /&gt;
#include &amp;lt;tf2_stocks&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// in player_death hook&lt;br /&gt;
    new bool:bHeadshot;&lt;br /&gt;
&lt;br /&gt;
    switch (g_EngineVersion)&lt;br /&gt;
    {&lt;br /&gt;
        case Engine_CSS, Engine_CSGO, Engine_L4D, Engine_L4D2:&lt;br /&gt;
        {&lt;br /&gt;
            bHeadshot = GetEventBool(event, &amp;quot;headshot&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        case Engine_TF2:&lt;br /&gt;
        {&lt;br /&gt;
            bHeadshot = GetEventInt(event, &amp;quot;customkill&amp;quot;) == TF_CUSTOM_HEADSHOT;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (bHeadshot)&lt;br /&gt;
    {&lt;br /&gt;
        // This was a headshot, do something&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unfortunately, some games don't appear to track headshots for death (Half-Life 2: DeathMatch for example).&lt;br /&gt;
&lt;br /&gt;
=== player_hurt ===&lt;br /&gt;
player_hurt is a bit trickier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// At top of file&lt;br /&gt;
#include &amp;lt;tf2_stocks&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define HITGROUP_HEAD 1&lt;br /&gt;
&lt;br /&gt;
// in player_hurt hook&lt;br /&gt;
    new bool:bHeadshot;&lt;br /&gt;
&lt;br /&gt;
    switch (g_EngineVersion)&lt;br /&gt;
    {&lt;br /&gt;
        case Engine_CSS, Engine_CSGO, Engine_DODS, Engine_L4D, Engine_L4D2:&lt;br /&gt;
        {&lt;br /&gt;
            bHeadshot = GetEventInt(event, &amp;quot;hitgroup&amp;quot;) == HITGROUP_HEAD;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        case Engine_TF2:&lt;br /&gt;
        {&lt;br /&gt;
            bHeadshot = GetEventInt(event, &amp;quot;custom&amp;quot;) == TF_CUSTOM_HEADSHOT;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
     &lt;br /&gt;
    if (bHeadshot)&lt;br /&gt;
    {&lt;br /&gt;
        // This was a headshot, do something&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, more games support detecting if a shot was a headshot in player_hurt than player_death.&lt;br /&gt;
&lt;br /&gt;
=== SDKHooks TraceAttack and OnTakeDamage ===&lt;br /&gt;
&lt;br /&gt;
Headshots can be detected by TraceAttack or OnTakeDamage depending on the game.&lt;br /&gt;
&lt;br /&gt;
Note: Changing damage and returning Plugin_Changed for either event will change the damage the player takes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
// At top of file&lt;br /&gt;
#include &amp;lt;sdkhooks&amp;gt;&lt;br /&gt;
#define HITGROUP_HEAD 1&lt;br /&gt;
&lt;br /&gt;
public OnClientPutInServer(client)&lt;br /&gt;
{&lt;br /&gt;
    switch (g_EngineVersion)&lt;br /&gt;
    {&lt;br /&gt;
        case Engine_CSS, Engine_CSGO, Engine_DODS, Engine_L4D, Engine_L4D2:&lt;br /&gt;
        {&lt;br /&gt;
            SDKHook(client, SDKHook_TraceAttack, TraceAttack);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        case Engine_TF2:&lt;br /&gt;
        {&lt;br /&gt;
            SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:TraceAttack(victim, &amp;amp;attacker, &amp;amp;inflictor, &amp;amp;Float:damage, &amp;amp;damagetype, &amp;amp;ammotype, hitbox, hitgroup)&lt;br /&gt;
{&lt;br /&gt;
    new bool:bHeadshot = hitgroup == HITGROUP_HEAD;&lt;br /&gt;
&lt;br /&gt;
    if (bHeadshot)&lt;br /&gt;
    {&lt;br /&gt;
        // This was a headshot, do something.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return Plugin_Continue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:OnTakeDamage(victim, &amp;amp;attacker, &amp;amp;inflictor, &amp;amp;Float:damage, &amp;amp;damagetype, &amp;amp;weapon,&lt;br /&gt;
		Float:damageForce[3], Float:damagePosition[3], damagecustom)&lt;br /&gt;
&lt;br /&gt;
    new bool:bHeadshot = damagecustom == TF_CUSTOM_HEADSHOT;&lt;br /&gt;
     &lt;br /&gt;
    if (bHeadshot)&lt;br /&gt;
    {&lt;br /&gt;
        // This was a headshot, do something&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return Plugin_Continue;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.2_Release_Notes&amp;diff=9920</id>
		<title>SourceMod 1.7.2 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.2_Release_Notes&amp;diff=9920"/>
		<updated>2015-05-30T13:19:36Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod 1.7.2 is a bugfix release, further stabilizing the 1.7 branch.&lt;br /&gt;
&lt;br /&gt;
For the full SourceMod 1.7 release notes, [[SourceMod 1.7.0 Release Notes|click here]].&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
User Changes:&lt;br /&gt;
&lt;br /&gt;
*Updated game compatibility for the latest CS:GO updates.&lt;br /&gt;
*Fixed potential crash when using SDKTools GameRules_* natives. ({{pr|330}}) (yed).&lt;br /&gt;
*Fixed regression in v1.7.0 causing admin-sql-threaded plugin to not properly load admins. ({{bz|6365}}) ({{pr|342}}).&lt;br /&gt;
*Fixed leak in plugin heap memory that could lead to &amp;quot;Not enough space on the heap&amp;quot; error. ({{bz|6370}}).&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.2_Release_Notes&amp;diff=9919</id>
		<title>SourceMod 1.7.2 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.2_Release_Notes&amp;diff=9919"/>
		<updated>2015-05-30T13:18:53Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Created page with &amp;quot;SourceMod 1.7.2 is a bugfix release, further stabilizing the 1.7 branch.  For the full SourceMod 1.7 release notes, click here.  =Changelog=...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod 1.7.2 is a bugfix release, further stabilizing the 1.7 branch.&lt;br /&gt;
&lt;br /&gt;
For the full SourceMod 1.7 release notes, [[SourceMod 1.7.0 Release Notes|click here]].&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
User Changes:&lt;br /&gt;
&lt;br /&gt;
*Updated game compatibility for the latest CS:GO updates.&lt;br /&gt;
*Fixed potential crash when using SDKTools GameRules_* natives. (PR 330) (yed).&lt;br /&gt;
*Fixed regression in v1.7.0 causing admin-sql-threaded plugin to not properly load admins. (bug 6365) (PR 342).&lt;br /&gt;
*Fixed leak in plugin heap memory that could lead to &amp;quot;Not enough space on the heap&amp;quot; error. (bug 6370).&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_Release_Notes&amp;diff=9918</id>
		<title>SourceMod Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_Release_Notes&amp;diff=9918"/>
		<updated>2015-05-30T13:18:02Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[SourceMod]] Release notes for each release:&lt;br /&gt;
&lt;br /&gt;
*[[SourceMod 1.7.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.7.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.7.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.6.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.6.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.6.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.6.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.5.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.5.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.5.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.5.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.7 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.6 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.5 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.4 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.8 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.7 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.6 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.5 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.4 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.4 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.1.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.1.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.1.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.4 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.0 Release Notes]]&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Required_Versions_(SourceMod)&amp;diff=9910</id>
		<title>Required Versions (SourceMod)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Required_Versions_(SourceMod)&amp;diff=9910"/>
		<updated>2015-05-21T22:17:18Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: ur&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As Valve updates their games, new fixes get added to Metamod:Source and SourceMod. This page is to document the current ''minimum'' required version for specific games.  If a specific snapshot isn't needed, please put Current Stable (for MM:S 1.10.x or SM 1.6.x releases) or Current Development (for MM:S 1.11.0 or 1.7.0 snapshots).&lt;br /&gt;
&lt;br /&gt;
Current Stable MM:S version: '''1.10.4'''&amp;lt;br&amp;gt;&lt;br /&gt;
Current Stable SM version: '''1.7.1'''&lt;br /&gt;
&lt;br /&gt;
Current Development MM:S versions: '''1.11.0''' git builds&amp;lt;br&amp;gt;&lt;br /&gt;
Current Development SM versions: '''1.8.0''' git builds&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Specific Metamod:Source versions and Current Development refer to [http://www.sourcemm.net/snapshots Metamod:Source snapshots].&amp;lt;br /&amp;gt;&lt;br /&gt;
Specific SourceMod versions and Current Development refer to [http://www.sourcemod.net/snapshots.php SourceMod snapshots].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Game&lt;br /&gt;
! Metamod:Source Version&lt;br /&gt;
! SourceMod Version&lt;br /&gt;
! Extras&lt;br /&gt;
|-&lt;br /&gt;
| Alien Swarm&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Black Mesa Source&lt;br /&gt;
| 1.10.5-git934&lt;br /&gt;
| 1.8.0-git5424&lt;br /&gt;
|-&lt;br /&gt;
| Blade Symphony&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Bloody Good Time&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Contagion&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Counter-Strike: Source&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Counter-Strike: Global Offensive&lt;br /&gt;
| 1.10.5-git937&lt;br /&gt;
| 1.7.1-git5200&lt;br /&gt;
| As of 2015/05/15, all SourceMod extensions need to be recompiled against the latest hl2sdk-csgo (and libstdc++).&lt;br /&gt;
|-&lt;br /&gt;
| Dark Messiah of Might &amp;amp;amp; Magic&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Day of Defeat: Source&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| DOTA 2&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
| [https://forums.alliedmods.net/showthread.php?t=209965 Dota 2 Fixups] 2.1.3 Required&lt;br /&gt;
|-&lt;br /&gt;
| EYE: Divine Cybermancy&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Half-Life 2: DeatchMatch&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Insurgency (2014)&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Left 4 Dead&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
| [http://www.sourcemm.net/vdf Manually Generated metamod.vdf] Required&lt;br /&gt;
|-&lt;br /&gt;
| Left 4 Dead 2&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Nuclear Dawn&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Source 2006 Mods&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Mods: Insurgency: Modern Infantry Combat mod version&lt;br /&gt;
|-&lt;br /&gt;
| Source 2007 Mods&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|-&lt;br /&gt;
| Source 2013 Mods&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Mods: Fistful of Frags, No More Room in Hell&lt;br /&gt;
|-&lt;br /&gt;
| Team Fortress 2&lt;br /&gt;
| Current Stable&lt;br /&gt;
| Current Stable&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.1_Release_Notes&amp;diff=9900</id>
		<title>SourceMod 1.7.1 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.1_Release_Notes&amp;diff=9900"/>
		<updated>2015-04-18T20:02:24Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod 1.7.1 has a few additions but is mostly a bugfix release, further stabilizing the 1.7 branch.&lt;br /&gt;
&lt;br /&gt;
'''Due to some logic errors, for any plugins that were compiled with the 1.7.0 SourcePawn compiler, it is highly recommended to recompile them with the new 1.7.1 compiler.'''&lt;br /&gt;
&lt;br /&gt;
For the full SourceMod 1.7 release notes, [[SourceMod 1.7.0 Release Notes|click here]].&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
User Changes:&lt;br /&gt;
&lt;br /&gt;
*Updated game compatibility for CS:GO, TF2, Dota 2, Insurgency, and Fortress Forever.&lt;br /&gt;
*Fixed regression causing crash in games that do not support radio menus (PR 286) (Peace-Maker).&lt;br /&gt;
*Fixed sm_rename not working on some games, including CS:S and CS:GO (PR 313).&lt;br /&gt;
*Fixed some core.cfg values being ignored on start (PR 322).&lt;br /&gt;
*Fixed crash when plugins close a menu handle during menu draw (PR 268)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Developer Changes:&lt;br /&gt;
&lt;br /&gt;
*Added tagged TF2_SetClientTeam to provide symmetry to TF2_GetClientTeam (PR 267) (Wliu).&lt;br /&gt;
*Added block parameter to FindValueInArray native (PR 213) (splewis).&lt;br /&gt;
*Added explicit return types to forwards missing them to avoid future compatibility issues (PR 294).&lt;br /&gt;
*Added new SetClientName native to reliably change a player's name on any game (PR 313).&lt;br /&gt;
*Fixed tag mismatch warning when using SQLite_UseDatabase (bug 6310) (PR 262) (VoiDeD).&lt;br /&gt;
*Fixed not actually being able to block CS_OnCSWeaponDrop (bug 6334) (PR 316).&lt;br /&gt;
*Fixed DirExists to throw an error when passed empty string (PR 315).&lt;br /&gt;
*Fixed ReadUint16 on File methodmap throwing &amp;quot;not bound&amp;quot; error (PR 265).&lt;br /&gt;
*Fixed various include docs (PR 288) (PR 290) (PR 295).&lt;br /&gt;
*Fixed issues with declaring variable on same line after array (SP PR 7) (Peace-Maker).&lt;br /&gt;
*Fixed debug info for multidimensional strings not being written to smx (SP PR 8) (Peace-Maker).&lt;br /&gt;
*Fixed issues with nesting methodmap calls (bug 6329) (SP PR 11) (SP PR 13).&lt;br /&gt;
*Improved diagnostic given when function prototype doesn't match an existing definition (PR 291) (VoiDeD).&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.1_Release_Notes&amp;diff=9899</id>
		<title>SourceMod 1.7.1 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.1_Release_Notes&amp;diff=9899"/>
		<updated>2015-04-18T20:00:56Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod 1.7.1 has a few additions but is mostly a bugfix release, further stabilizing the 1.7 branch.&lt;br /&gt;
&lt;br /&gt;
'''Due to some logic errors in the 1.7.0 SourcePawn compiler, it is highly recommend to recompile any plugins compiled with it with the new 1.7.1 compiler.'''&lt;br /&gt;
&lt;br /&gt;
For the full SourceMod 1.7 release notes, [[SourceMod 1.7.0 Release Notes|click here]].&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
User Changes:&lt;br /&gt;
&lt;br /&gt;
*Updated game compatibility for CS:GO, TF2, Dota 2, Insurgency, and Fortress Forever.&lt;br /&gt;
*Fixed regression causing crash in games that do not support radio menus (PR 286) (Peace-Maker).&lt;br /&gt;
*Fixed sm_rename not working on some games, including CS:S and CS:GO (PR 313).&lt;br /&gt;
*Fixed some core.cfg values being ignored on start (PR 322).&lt;br /&gt;
*Fixed crash when plugins close a menu handle during menu draw (PR 268)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Developer Changes:&lt;br /&gt;
&lt;br /&gt;
*Added tagged TF2_SetClientTeam to provide symmetry to TF2_GetClientTeam (PR 267) (Wliu).&lt;br /&gt;
*Added block parameter to FindValueInArray native (PR 213) (splewis).&lt;br /&gt;
*Added explicit return types to forwards missing them to avoid future compatibility issues (PR 294).&lt;br /&gt;
*Added new SetClientName native to reliably change a player's name on any game (PR 313).&lt;br /&gt;
*Fixed tag mismatch warning when using SQLite_UseDatabase (bug 6310) (PR 262) (VoiDeD).&lt;br /&gt;
*Fixed not actually being able to block CS_OnCSWeaponDrop (bug 6334) (PR 316).&lt;br /&gt;
*Fixed DirExists to throw an error when passed empty string (PR 315).&lt;br /&gt;
*Fixed ReadUint16 on File methodmap throwing &amp;quot;not bound&amp;quot; error (PR 265).&lt;br /&gt;
*Fixed various include docs (PR 288) (PR 290) (PR 295).&lt;br /&gt;
*Fixed issues with declaring variable on same line after array (SP PR 7) (Peace-Maker).&lt;br /&gt;
*Fixed debug info for multidimensional strings not being written to smx (SP PR 8) (Peace-Maker).&lt;br /&gt;
*Fixed issues with nesting methodmap calls (bug 6329) (SP PR 11) (SP PR 13).&lt;br /&gt;
*Improved diagnostic given when function prototype doesn't match an existing definition (PR 291) (VoiDeD).&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.1_Release_Notes&amp;diff=9898</id>
		<title>SourceMod 1.7.1 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.1_Release_Notes&amp;diff=9898"/>
		<updated>2015-04-18T19:52:08Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Created page with &amp;quot;SourceMod 1.7.1 has a few additions but is mostly a minor bugfix release, quashing regressions from 1.7.0.  '''Due to some logic errors in the 1.7.0 SourcePawn compiler, it is...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod 1.7.1 has a few additions but is mostly a minor bugfix release, quashing regressions from 1.7.0.&lt;br /&gt;
&lt;br /&gt;
'''Due to some logic errors in the 1.7.0 SourcePawn compiler, it is highly recommend to recompile any plugins compiled with it with the new 1.7.1 compiler.'''&lt;br /&gt;
&lt;br /&gt;
For the full SourceMod 1.7 release notes, [[SourceMod 1.7.0 Release Notes|click here]].&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
User Changes:&lt;br /&gt;
&lt;br /&gt;
*Updated game compatibility for CS:GO, TF2, Dota 2, Insurgency, and Fortress Forever.&lt;br /&gt;
*Fixed regression causing crash in games that do not support radio menus (PR 286) (Peace-Maker).&lt;br /&gt;
*Fixed sm_rename not working on some games, including CS:S and CS:GO (PR 313).&lt;br /&gt;
*Fixed some core.cfg values being ignored on start (PR 322).&lt;br /&gt;
*Fixed crash when plugins close a menu handle during menu draw (PR 268)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Developer Changes:&lt;br /&gt;
&lt;br /&gt;
*Added tagged TF2_SetClientTeam to provide symmetry to TF2_GetClientTeam (PR 267) (Wliu).&lt;br /&gt;
*Added block parameter to FindValueInArray native (PR 213) (splewis).&lt;br /&gt;
*Added explicit return types to forwards missing them to avoid future compatibility issues (PR 294).&lt;br /&gt;
*Added new SetClientName native to reliably change a player's name on any game (PR 313).&lt;br /&gt;
*Fixed tag mismatch warning when using SQLite_UseDatabase (bug 6310) (PR 262) (VoiDeD).&lt;br /&gt;
*Fixed not actually being able to block CS_OnCSWeaponDrop (bug 6334) (PR 316).&lt;br /&gt;
*Fixed DirExists to throw an error when passed empty string (PR 315).&lt;br /&gt;
*Fixed ReadUint16 on File methodmap throwing &amp;quot;not bound&amp;quot; error (PR 265).&lt;br /&gt;
*Fixed various include docs (PR 288) (PR 290) (PR 295).&lt;br /&gt;
*Fixed issues with declaring variable on same line after array (SP PR 7) (Peace-Maker).&lt;br /&gt;
*Fixed debug info for multidimensional strings not being written to smx (SP PR 8) (Peace-Maker).&lt;br /&gt;
*Fixed issues with nesting methodmap calls (bug 6329) (SP PR 11) (SP PR 13).&lt;br /&gt;
*Improved diagnostic given when function prototype doesn't match an existing definition (PR 291) (VoiDeD).&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_Release_Notes&amp;diff=9897</id>
		<title>SourceMod Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_Release_Notes&amp;diff=9897"/>
		<updated>2015-04-18T19:49:23Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[SourceMod]] Release notes for each release:&lt;br /&gt;
&lt;br /&gt;
*[[SourceMod 1.7.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.7.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.6.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.6.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.6.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.6.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.5.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.5.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.5.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.5.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.7 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.6 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.5 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.4 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.4.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.8 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.7 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.6 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.5 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.4 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.3.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.4 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.2.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.1.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.1.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.1.0 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.4 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.3 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.2 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.1 Release Notes]]&lt;br /&gt;
*[[SourceMod 1.0.0 Release Notes]]&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Releasing_Products&amp;diff=9895</id>
		<title>Releasing Products</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Releasing_Products&amp;diff=9895"/>
		<updated>2015-04-04T13:45:41Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Updating the SourceMod Site */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is an internal page for doing AlliedModders product releases.&lt;br /&gt;
&lt;br /&gt;
=Making Builds=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Once you are '''absolutely sure''' the product is ready for a release...&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Jump to a Linux system, check out the source tree.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Update the changelog (&amp;lt;tt&amp;gt;changelog.txt&amp;lt;/tt&amp;gt; for SourceMod, &amp;lt;tt&amp;gt;support/changelog.txt&amp;lt;/tt&amp;gt; for Metamod:Source).&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit the build_type file and change the &amp;quot;dev&amp;quot; string to &amp;quot;rel&amp;quot; (&amp;lt;tt&amp;gt;tools/buildbot/build_type&amp;lt;/tt&amp;gt; for SourceMod, &amp;lt;tt&amp;gt;support/buildbot/build_type&amp;lt;/tt&amp;gt; for Metamod:Source).&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit &amp;lt;tt&amp;gt;product.version&amp;lt;/tt&amp;gt; to remove the -dev tag.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Commit and push the changes.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Push.  Watch the waterfall page until builds are complete.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Post-Build Work=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Grab the binaries from the drop site ([http://metamodsource.net/mmsdrop/ MM:S drop site], [http://sourcemod.net/smdrop/ SourceMod drop site]).  It will be the latest package.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Install the packages on both Linux and Windows.  '''MAKE SURE THE VERSIONS ARE CORRECT.  THERE SHOULD BE NO -dev TAG.'''&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Metamod:Source checks:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
meta version&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
SourceMod checks:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sm plugins list&lt;br /&gt;
sm exts list&lt;br /&gt;
sm version&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;If the versions are not correct, do not release.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;For SourceMod, you need to add the language translation packs and update the GeoLite Country data file.  &lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
  '''If this is a major release (1.X.0), there is no prior pack.  Make one:'''&lt;br /&gt;
  &amp;lt;ol&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Extract both the tar.gz and zip files to separate folders.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Visit the [http://www.sourcemod.net/translator/?go=translate&amp;amp;op=status translator status page].&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Click &amp;quot;export languages.cfg&amp;quot; - save the new version to &amp;lt;tt&amp;gt;addons/sourcemod/configs/&amp;lt;/tt&amp;gt;, overwriting the old one.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Click &amp;quot;export&amp;quot; next to each language that is finished.  Extract the folder to &amp;lt;tt&amp;gt;addons/sourcemod/translations/&amp;lt;/tt&amp;gt;.  For example, if you extract Spanish, you should have &amp;lt;tt&amp;gt;addons/sourcemod/translations/es/&amp;lt;/tt&amp;gt; complete with ML files.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Download the latest GeoLite Country binary file from http://dev.maxmind.com/geoip/geolite&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Extract the GeoIP.dat and replace the existing copy in addons/sourcemod/configs/geoip&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Repackage the folders using the correct compression types (.tar.gz for Linux, .zip for Windows and Mac).&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;If this is a minor release (1.X.Y where Y != 0), there is already a prior pack.  Add it in:&amp;lt;/b&amp;gt;&lt;br /&gt;
  &amp;lt;ol&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Extract both the tar.gz and zip files to separate folders.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Download the last major release from the same branch as this release.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Copy the &amp;lt;tt&amp;gt;addons/sourcemod/configs/languages.cfg&amp;lt;/tt&amp;gt; file from the old release over the new one.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Copy the &amp;lt;tt&amp;gt;addons/sourcemod/translations/&amp;lt;/tt&amp;gt; sub-folders from the old release over to the new one.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Download the latest GeoLite Country binary file from http://dev.maxmind.com/geoip/geolite&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Extract the GeoIP.dat and replace the existing copy in addons/sourcemod/configs/geoip&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Repackage the folders using the correct compression types (.tar.gz for Linux, .zip for Windows).&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;The build is done!&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Releasing to Mirrors=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Log into web01 as yourself.  Upload your final builds to your home directory.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/scripts/amjump mirror&lt;br /&gt;
cd /scripts/mirror&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Copy your final builds from your home directory into the mirror folder.  Rename them to release names, for example: &amp;lt;tt&amp;gt;sourcemod-1.1.2-windows.zip&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;mmsource-1.8.0-linux-tar.gz&amp;lt;/tt&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Mirror distribution is done with the following command:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mirror.pl &amp;lt;projectID&amp;gt; &amp;lt;releaseName&amp;gt; &amp;lt;file&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Metamod:Source's ID is 4, SourceMod's ID is 2.  For example, these commands mirrored the Metamod:Source 1.8.7 release:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mirror.pl 4 1.8.7 mmsource-1.8.7-linux.tar.gz&lt;br /&gt;
./mirror.pl 4 1.8.7 mmsource-1.8.7-windows.zip&lt;br /&gt;
./mirror.pl 4 1.8.7 mmsource-1.8.7-mac.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These commands mirrored the SourceMod 1.4.0 release:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mirror.pl 2 1.4.0 sourcemod-1.4.0-linux.tar.gz&lt;br /&gt;
./mirror.pl 2 1.4.0 sourcemod-1.4.0-windows.zip&lt;br /&gt;
./mirror.pl 2 1.4.0 sourcemod-1.4.0-mac.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Type &amp;lt;tt&amp;gt;exit&amp;lt;/tt&amp;gt; to get back to your user account.  You're done!&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Cleaning up the Tree=&lt;br /&gt;
It's time to make sure the tree is set for future development.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Run &amp;lt;tt&amp;gt;git tag&amp;lt;/tt&amp;gt; on the last revision of the release.  Usually this is the changeset that bumped versions, and usually this is the branch &amp;lt;tt&amp;gt;tip&amp;lt;/tt&amp;gt;. After you have tagged the changeset, push the tag upstream.  For example, Metamod:Source:&lt;br /&gt;
&amp;lt;pre&amp;gt;git tag -a mmsource-1.7.2 -m &amp;quot;Metamod:Source 1.7.2&amp;quot;&lt;br /&gt;
git push origin mmsource-1.7.2&amp;lt;/pre&amp;gt;&lt;br /&gt;
SourceMod:&lt;br /&gt;
&amp;lt;pre&amp;gt;git tag -a sourcemod-1.1.2 -m &amp;quot;SourceMod 1.1.2&amp;quot;&lt;br /&gt;
git push origin sourcemod-1.1.2&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Bump the minor version in &amp;lt;tt&amp;gt;product.version&amp;lt;/tt&amp;gt;. Don't forget to add -dev.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Change the &amp;lt;tt&amp;gt;tools/buildbot/build_type&amp;lt;/tt&amp;gt; (SourceMod) or &amp;lt;tt&amp;gt;support/buildbot/build_type&amp;lt;/tt&amp;gt; (Metamod:Source) contents back to &amp;quot;dev&amp;quot;.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Commit and push.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Updating the SourceMod Site=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Visit a [http://wiki.alliedmods.net/SourceMod_Release_Notes Release Notes] page.  Copy the contents, make a new one for your specific release.  Update the changelog, relnote anything big and important.  Link back to it from the &amp;quot;main&amp;quot; relnotes page.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Jump to the sourcemod account by logging into web01 as yourself:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/scripts/amjump sourcemod&lt;br /&gt;
cd /groups/sourcemod&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit the &amp;lt;tt&amp;gt;public_html/downloads.php&amp;lt;/tt&amp;gt; file with your favorite text editor.  Edit all instances of the old version with the new one.  Make sure to get every link, including relnotes.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Update ~/compiler-1.x to the latest minor version, where x is the major version number.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;If a new major version, update vbcompiler.php on the SourceMod site to set the new default and as an explicit check to allow the former default version.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Run &amp;lt;tt&amp;gt;~/scripts/purge_old_builds.pl&amp;lt;/tt&amp;gt;, then edit its entry for 1.x.y, where x = this major release, and y = the new minor version.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Exit out of the sourcemod account.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;If a new major version, find someone with access to edit the forums if not yourself, and have the new compiler version added to editpost.php and newthread.php for the dropdown when editing plugin posts.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;&amp;lt;s&amp;gt;Find someone with access to the smdocs user if not yourself, and have the api docs updated by logging in as smdocs, navigating to ~/scripts/sync_api, replace the contents of the build directory with the new SM release, and run the run.sh script.&amp;lt;/s&amp;gt; TODO: How do we update new api site?&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Post news.  If you deviate from normal style, don't forget links for downloads, upgrading, and relnotes.  It also helps to say &amp;quot;this is backwards compatible&amp;quot; because users will always ask.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Updating the Metamod:Source Site=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Jump to the alliedmodders account by logging into web01 as yourself:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/scripts/amjump alliedmodders&lt;br /&gt;
cd /groups/alliedmodders/hub/amhub&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit the &amp;lt;tt&amp;gt;mmsource.py&amp;lt;/tt&amp;gt; file with your favorite text editor. Update the &amp;lt;tt&amp;gt;latest&amp;lt;/tt&amp;gt; version number in the &amp;lt;tt&amp;gt;downloads&amp;lt;/tt&amp;gt; function.  If this is a new major release (1.X.0), update the &amp;lt;tt&amp;gt;stable&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;devel&amp;lt;/tt&amp;gt; version numbers in the &amp;lt;tt&amp;gt;downloads&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;snapshots&amp;lt;/tt&amp;gt; functions.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit the &amp;lt;tt&amp;gt;templates/mmsource/navbar.html&amp;lt;/tt&amp;gt; file and replace all instances of the old version with the new one.&lt;br /&gt;
 &amp;lt;li&amp;gt;Run the following command:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch ../run/apache.wsgi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Post news.  Do this by making a post in [https://forums.alliedmods.net/forumdisplay.php?f=124 this forum], which is private.  LOOK AT OLDER POSTS - you need to write valid XHTML!&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Exit out of the alliedmodders account.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Updating Translations=&lt;br /&gt;
This section applies to SourceMod major releases. In order to update the translator tool, shell in as the &amp;quot;sourcemod&amp;quot; user. Find the /scripts/translation folder in the sourcemod group homedir. Run the following steps:&lt;br /&gt;
* cd sourcemod&lt;br /&gt;
* git pull&lt;br /&gt;
* cd ..&lt;br /&gt;
* ./sync_lang_files.pl sourcemod/translations&lt;br /&gt;
&lt;br /&gt;
Any languages with a non-green status will not be exported, so a few weeks before a release it is a good idea to post news asking for translators.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourcePawn_Transitional_Syntax&amp;diff=9836</id>
		<title>SourcePawn Transitional Syntax</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourcePawn_Transitional_Syntax&amp;diff=9836"/>
		<updated>2015-03-22T12:43:44Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Constructors and Destructors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__FORCETOC__&lt;br /&gt;
We would like to give our users a more modern language. Pawn is showing its age; manual memory management, buffers, tags, and lack of object-oriented API are very frustrating. We can't solve everything all at once, but we can begin to take steps in the right direction.&lt;br /&gt;
&lt;br /&gt;
SourceMod 1.7 introduces a ''Transitional API''. It is built on a new ''Transitional Syntax'' in SourcePawn, which is a set of language tools to make Pawn feel more modern. In particular, it allows developers to use older APIs in an object-oriented manner, without breaking compatibility. Someday, if and when SourcePawn can become a full-fledged modern language, the transitional API will making porting efforts very minimal.&lt;br /&gt;
&lt;br /&gt;
The transitional API has the following major features and changes:&lt;br /&gt;
* New Declarators - A cleaner way of declaring variables, similar to Java and C#.&lt;br /&gt;
* Methodmaps - Object-oriented wrappers around older APIs.&lt;br /&gt;
* Real Types - SourcePawn now has &amp;quot;int&amp;quot;, &amp;quot;float&amp;quot;, &amp;quot;bool&amp;quot;, &amp;quot;void&amp;quot;, and &amp;quot;char&amp;quot; as real types.&lt;br /&gt;
* &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; - A new, general keyword to replace &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=New Declarators=&lt;br /&gt;
Developers familiar with pawn will recognize Pawn's original declaration style:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
new Float:x = 5.0;&lt;br /&gt;
new y = 7;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the transitional syntax, this can be reworded as:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
float x = 5.0;&lt;br /&gt;
int y = 7;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following builtin tags now have types:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Float:&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;bool:&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;bool&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;_:&amp;lt;/tt&amp;gt; (or no tag) is &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;String:&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;char&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;void&amp;lt;/tt&amp;gt; can now be used as a return type for functions.&lt;br /&gt;
&lt;br /&gt;
===Rationale===&lt;br /&gt;
In the old style, tagged variables are not real types. &amp;lt;tt&amp;gt;Float:x&amp;lt;/tt&amp;gt; does not indicate a float-typed variable, it indicates a 32-bit &amp;quot;cell&amp;quot; &amp;lt;i&amp;gt;tagged&amp;lt;/i&amp;gt; as a float. It is possible to remove the tag or change the tag, which while flexible, is dangerous and confusing. The syntax itself is also problematic. The parser does not have the ability to identify characters in between the tag name and the colon. Internally, the compiler cannot represent values that are not exactly 32-bit.&lt;br /&gt;
&lt;br /&gt;
The takeaway message is: there is no sensible way to represent a concept like &amp;quot;int64&amp;quot; or &amp;quot;X is a type that represents an array of floats&amp;quot;. The tagging grammar makes it too awkward, and the compiler itself is incapable of attaching such information to a tag. We can't fix that right away, but we can begin to deprecate the tag system via a more normal declaration syntax.&lt;br /&gt;
&lt;br /&gt;
An easy example to see why this is necessary, is the weirdness in expressing something like this with tags:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
native float[3] GetEntOrigin();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Note on the &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt; tag:'' The introduction of &amp;lt;tt&amp;gt;char&amp;lt;/tt&amp;gt; might initially seem confusing. The reason for this is that in the future, we would like to introduce a true &amp;quot;string&amp;quot; type that acts as an object, like strings in most other languages. The existing behavior in Pawn is an array of characters, which is much lower-level. The renaming clarifies what the type really is, and leaves the door open for better types in the future.&lt;br /&gt;
&lt;br /&gt;
==Arrays==&lt;br /&gt;
The new style of declaration disambiguates between two kinds of arrays. Pawn has ''indeterminate arrays'', where the size is not known, and ''determinate arrays'', where the size is known. We refer to these as &amp;quot;dynamic&amp;quot; and &amp;quot;fixed-length&amp;quot; arrays, respectively.&lt;br /&gt;
&lt;br /&gt;
'''A fixed-length array is declared by placing brackets after a variable name'''. For example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
int CachedStuff[1000];&lt;br /&gt;
int PlayerData[MAXPLAYERS + 1] = { 0, ... };&lt;br /&gt;
int Weapons[] = { WEAPON_AK47, WEAPON_GLOCK, WEAPON_KNIFE };&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In these examples, the array size is fixed. The size is known ahead of time and cannot change. When using brackets in this position, the array size must be specified, either via an explicit size or inferred from an initial value.&lt;br /&gt;
&lt;br /&gt;
A dynamic-length array has the brackets '''before the variable name''', that is, '''after the type'''. The most common case is when specifying functions that take an array as input:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
native void SetPlayerName(int player, const char[] name);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, we are specifying that the length of &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; is not always known - it could be anything.&lt;br /&gt;
&lt;br /&gt;
Dynamic arrays can also be created in local scopes. For example,&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void FindPlayers()&lt;br /&gt;
{&lt;br /&gt;
  int[] players = new int[MaxClients + 1];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This allocates a new array of the given size and places a reference in &amp;lt;tt&amp;gt;players&amp;lt;/tt&amp;gt;. The memory is automatically freed when no longer in use.&lt;br /&gt;
&lt;br /&gt;
It is illegal to initialize a fixed-length array with an indeterminate array, and it is illegal to initialize a dynamic array with a fixed-array. It is also illegal to specify a fixed size on a dynamic length array.&lt;br /&gt;
&lt;br /&gt;
For the most part, this does not change existing Pawn semantics. It is simply new syntax intended to clarify the way arrays work.&lt;br /&gt;
&lt;br /&gt;
===Rationale===&lt;br /&gt;
In the original syntax, there was a subtle difference in array declaration:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
new array1[MAXPLAYERS + 1];&lt;br /&gt;
new array2[MaxClents + 1];&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, &amp;lt;tt&amp;gt;array1&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;array2&amp;lt;/tt&amp;gt; are very different types: the first is an &amp;lt;tt&amp;gt;int[65]&amp;lt;/tt&amp;gt; and the latter is an &amp;lt;tt&amp;gt;int[]&amp;lt;/tt&amp;gt;. However, there is no syntactic difference: the compiler has to deduce whether the size expression is constant to determine the type. The new syntax clearly and explicitly disambiguates these cases, so in the future when we introduce fully dynamic and flexible arrays, we're less likely to break existing code.&lt;br /&gt;
&lt;br /&gt;
This may result in some confusion. Hopefully won't matter long term, as once we have true dynamic arrays, fixed arrays will become much less useful and more obscure.&lt;br /&gt;
&lt;br /&gt;
The rationale for restricting initializers is similar. Once we have true dynamic arrays, the restrictions will be lifted. In the meantime, we need to make sure we're limited to semantics that won't have subtle differences in the future.&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
float x = 5.0;    // Replacement for Float&lt;br /&gt;
int y = 4;        // Replacement for new&lt;br /&gt;
char name[32];    // Replacement for String&lt;br /&gt;
&lt;br /&gt;
void DoStuff(float x, int y, char[] name, int length) {&lt;br /&gt;
  Format(name, length, &amp;quot;%f %d&amp;quot;, x, y);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==View As==&lt;br /&gt;
A new operator is available for reinterpreting the bits in a value as another type. This operator is called &amp;lt;tt&amp;gt;view_as&amp;lt;/tt&amp;gt;. It is not a safe cast, in that, it can transform one type to another even if the actual value does not conform to either.&lt;br /&gt;
&lt;br /&gt;
In pre-transitional syntax, this was called &amp;quot;retagging&amp;quot;. Retagging does not support new-style types, which is why this operator has been introduced. Example of before and after code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
// Before:&lt;br /&gt;
float x = Float:array.Get(i);&lt;br /&gt;
&lt;br /&gt;
// After:&lt;br /&gt;
float y = view_as&amp;lt;float&amp;gt;(array.Get(i));&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is worth reiterating that this is not a cast. If the value in the array is not a float, then when &amp;quot;viewed as&amp;quot; a float it will probably look very odd.&lt;br /&gt;
&lt;br /&gt;
==Grammar==&lt;br /&gt;
The new and old declaration grammar is below. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
return-type ::= return-old | return-new&lt;br /&gt;
return-new ::= type-expr new-dims?        // Note, dims not yet supported.&lt;br /&gt;
return-old ::= old-dims? label?&lt;br /&gt;
&lt;br /&gt;
argdecl ::= arg-old | arg-new&lt;br /&gt;
arg-new ::= &amp;quot;const&amp;quot;? type-expr '&amp;amp;'? symbol old-dims? ('=' arg-init)?&lt;br /&gt;
arg-old ::= &amp;quot;const&amp;quot;? tags? '&amp;amp;'? symbol old-dims? ('=' arg-init)?&lt;br /&gt;
&lt;br /&gt;
vardecl ::= var-old | var-new&lt;br /&gt;
var-new ::= var-new-prefix type-expr symbol old-dims?&lt;br /&gt;
var-new-prefix ::= &amp;quot;static&amp;quot; | &amp;quot;const&amp;quot;&lt;br /&gt;
var-old ::= var-old-prefix tag? symbol old-dims?&lt;br /&gt;
var-old-prefix ::= &amp;quot;new&amp;quot; | &amp;quot;decl&amp;quot; | &amp;quot;static&amp;quot; | &amp;quot;const&amp;quot;&lt;br /&gt;
&lt;br /&gt;
global ::= global-old | global-new&lt;br /&gt;
global-new ::= storage-class* type-expr symbol old-dims?&lt;br /&gt;
global-old ::= storage-class* tag? symbol old-dims?&lt;br /&gt;
&lt;br /&gt;
storage-class ::= &amp;quot;public&amp;quot; | &amp;quot;static&amp;quot; | &amp;quot;const&amp;quot; | &amp;quot;stock&amp;quot;&lt;br /&gt;
&lt;br /&gt;
type-expr ::= (builtin-type | symbol) new-dims?&lt;br /&gt;
builtin-type ::= &amp;quot;void&amp;quot;&lt;br /&gt;
               | &amp;quot;int&amp;quot;&lt;br /&gt;
               | &amp;quot;float&amp;quot;&lt;br /&gt;
               | &amp;quot;char&amp;quot;&lt;br /&gt;
               | &amp;quot;bool&amp;quot;&lt;br /&gt;
&lt;br /&gt;
tags ::= tag-vector | tag&lt;br /&gt;
tag-vector ::= '{' symbol (',' symbol)* '}' ':'&lt;br /&gt;
tag ::= label&lt;br /&gt;
&lt;br /&gt;
new-dims ::= ('[' ']')*&lt;br /&gt;
old-dims ::= ('[' expr? ']')+&lt;br /&gt;
&lt;br /&gt;
label ::= symbol ':'&lt;br /&gt;
symbol ::= [A-Za-z_]([A-Za-z0-9_]*)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also note, there is no equivalent of &amp;lt;tt&amp;gt;decl&amp;lt;/tt&amp;gt; in the new declarator syntax. &amp;lt;tt&amp;gt;decl&amp;lt;/tt&amp;gt; is considered to be dangerous and unnecessary. If an array's zero initialization is too costly, consider making it static or global.&lt;br /&gt;
&lt;br /&gt;
=Methodmaps=&lt;br /&gt;
==Introduction==&lt;br /&gt;
Methodmaps are simple: they attach methods onto an enum. For example, here is our legacy API for Handles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
native CloneHandle(Handle handle);&lt;br /&gt;
native CloseHandle(Handle handle);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a good example of our legacy API. Using it generally looks something like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle array = CreateAdtArray();&lt;br /&gt;
PushArrayCell(array, 4);&lt;br /&gt;
CloseHandle(array);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gross! A Methodmap can clean it up by attaching functions to the &amp;lt;tt&amp;gt;Handle&amp;lt;/tt&amp;gt; tag, like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
methodmap Handle {&lt;br /&gt;
    public Clone() = CloneHandle;&lt;br /&gt;
    public Close() = CloseHandle;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, our earlier array code can start to look object-oriented:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle array = CreateAdtArray();&lt;br /&gt;
PushArrayCell(array, 4);&lt;br /&gt;
array.Close();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With a full methodmap for Arrays, for example,&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
methodmap ArrayList &amp;lt; Handle&lt;br /&gt;
{&lt;br /&gt;
  public native ArrayList(); // constructor&lt;br /&gt;
  public native void Push(any value);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We can write even more object-like code:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
ArrayList array = new ArrayList();&lt;br /&gt;
array.Push(4);&lt;br /&gt;
delete array;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Note: the official API does not expose methods on raw Handles.)&lt;br /&gt;
&lt;br /&gt;
==Inheritance==&lt;br /&gt;
The Handle system has a &amp;quot;weak&amp;quot; hierarchy. All handles can be passed to &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt;, but only AdtArray handles can be passed to functions like &amp;lt;tt&amp;gt;PushArrayCell&amp;lt;/tt&amp;gt;. This hierarchy is not enforced via tags (unfortunately), but instead by run-time checks. Methodmaps allow us to make individual handle types object-oriented, while also moving type-checks into the compiler.&lt;br /&gt;
&lt;br /&gt;
For example, here is a transitional API for arrays:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
native AdtArray CreateAdtArray();&lt;br /&gt;
&lt;br /&gt;
methodmap AdtArray &amp;lt; Handle {&lt;br /&gt;
    public PushCell() = PushArrayCell;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;CreateAdtArray&amp;lt;/tt&amp;gt; now returns &amp;lt;tt&amp;gt;AdtArray&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;Handle&amp;lt;/tt&amp;gt;. Normally that would break older code, but since &amp;lt;tt&amp;gt;AdtArray&amp;lt;/tt&amp;gt; inherits from &amp;lt;tt&amp;gt;Handle&amp;lt;/tt&amp;gt;, there is a special rule in the type system that allows coercing an &amp;lt;tt&amp;gt;AdtArray&amp;lt;/tt&amp;gt; to a &amp;lt;tt&amp;gt;Handle&amp;lt;/tt&amp;gt; (but not vice versa).&lt;br /&gt;
&lt;br /&gt;
Now, the API looks much more object-oriented:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
AdtArray array = CreateAdtArray();&lt;br /&gt;
array.PushCell(4);&lt;br /&gt;
array.Close();&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Inline Methods==&lt;br /&gt;
Methodmaps can declare inline methods and accessors. Inline methods can be either natives or Pawn functions. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
methodmap AdtArray {&lt;br /&gt;
    public native void PushCell(value);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example requires that an &amp;quot;AdtArray.PushCell&amp;quot; native exists somewhere in SourceMod. It has a magic initial parameter called &amp;quot;this&amp;quot;, so the signature will look something like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
native void AdtArray.PushCell(AdtArray this, value);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Of course, this exact signature will not appear in an include file - it's the signature that the C++ implementation should expect, however.)&lt;br /&gt;
&lt;br /&gt;
It's also possible to define new functions without a native:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
methodmap AdtArray {&lt;br /&gt;
    public native void PushCell(value);&lt;br /&gt;
&lt;br /&gt;
    public void PushCells(list[], count) {&lt;br /&gt;
        for (int i = 0; i &amp;lt; count; i++) {&lt;br /&gt;
            this.PushCell(i);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lastly, we can also define accessors. or example,&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
methodmap AdtArray {&lt;br /&gt;
    property int Size {&lt;br /&gt;
        public get() = GetArraySize;&lt;br /&gt;
    }&lt;br /&gt;
    property bool Empty {&lt;br /&gt;
        public get() {&lt;br /&gt;
            return this.Size == 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    property int Capacity {&lt;br /&gt;
        public native get();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first accessor simply assigns an existing function as an accessor for &amp;quot;Size&amp;quot;. The second accessor is an inline method with an implicit &amp;quot;this&amp;quot; parameter. The third accessor will bind to a native with the following name and signature:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
native int AdtArray.Capacity.get(AdtArray this);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Setters are also supported. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
methodmap Player {&lt;br /&gt;
    property int Health {&lt;br /&gt;
        public native get();&lt;br /&gt;
        public native set(int health);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Custom Tags==&lt;br /&gt;
Methodmaps don't have to be used with Handles. It is possible to define custom methodmaps on new or existing tags. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
methodmap AdminId {&lt;br /&gt;
    public int Rights() {&lt;br /&gt;
        return GetAdminFlags(this);&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, for example, it is possible to do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;GetPlayerAdmin(id).Rights()&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Constructors and Destructors==&lt;br /&gt;
Methodmaps can also define constructors and destructors, which is useful if they are intended to behave like actual objects. For example,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
methodmap AdtArray {&lt;br /&gt;
    public AdtArray(blocksize = 1);&lt;br /&gt;
    public ~AdtArray();&lt;br /&gt;
    public void PushCell(value);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now AdtArrays can be used in a fully object-oriented style:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
AdtArray array = new AdtArray();&lt;br /&gt;
array.PushCell(10);&lt;br /&gt;
array.PushCell(20);&lt;br /&gt;
array.PushCell(30);&lt;br /&gt;
delete array;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Caveats==&lt;br /&gt;
There are a few caveats to methodmaps:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;CloseHandle() is not yet gone. It is required to call &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; on any object that previously would have required CloseHandle().&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;There can be only one methodmap for a tag.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;When using existing natives, the first parameter of the native must coerce to the tag of the methodmap. Tag mismatches of the &amp;quot;this&amp;quot; parameter will result in an error. Not a warning!&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Methodmaps can only be defined on tags. Pawn has some ways of creating actual types (like via &amp;lt;tt&amp;gt;struct&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;class&amp;lt;/tt&amp;gt;). Methodmaps cannot be created on those types.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Methodmaps do not have strong typing. For example, it is still possible to perform &amp;quot;illegal&amp;quot; casts like &amp;lt;tt&amp;gt;Float:CreateAdtArray()&amp;lt;/tt&amp;gt;. This is necessary for backwards compatibility, so methodmap values can flow into natives like &amp;lt;tt&amp;gt;PrintToServer&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;CreateTimer&amp;lt;/tt&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;It is not possible to inherit from anything other than another previously declared methodmap.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Methodmaps can only be defined over scalars - that is, the &amp;quot;this&amp;quot; parameter can never be an array. This means they cannot be used for enum-structs.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Destructors can only be native. When we are able to achieve garbage collection, destructors will be removed.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;The signatures of methodmaps must use the new declaration syntax.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Methodmaps must be declared before they are used.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Grammar==&lt;br /&gt;
The grammar for methodmaps is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
visibility ::= &amp;quot;public&amp;quot;&lt;br /&gt;
method-args ::= arg-new* &amp;quot;...&amp;quot;?&lt;br /&gt;
&lt;br /&gt;
methodmap ::= &amp;quot;methodmap&amp;quot; symbol? { methodmap-item* } term&lt;br /&gt;
methodmap-item ::=&lt;br /&gt;
           visibility &amp;quot;~&amp;quot;? symbol &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; &amp;quot;=&amp;quot; symbol term&lt;br /&gt;
         | visibility &amp;quot;native&amp;quot; type-expr &amp;quot;~&amp;quot;? symbol methodmap-symbol &amp;quot;(&amp;quot; method-args &amp;quot;)&amp;quot; term&lt;br /&gt;
         | visibility type-expr symbol &amp;quot;(&amp;quot; method-args &amp;quot;)&amp;quot; func-body term&lt;br /&gt;
         | &amp;quot;property&amp;quot; type-expr symbol { property-decl } term&lt;br /&gt;
property-func ::= &amp;quot;get&amp;quot; | &amp;quot;set&amp;quot;&lt;br /&gt;
property-decl ::= visibility property-impl&lt;br /&gt;
property-impl ::=&lt;br /&gt;
           &amp;quot;native&amp;quot; property-func &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; term&lt;br /&gt;
         | property-func &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; func-body term&lt;br /&gt;
         | property-func &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; &amp;quot;=&amp;quot; symbol&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Typedefs=&lt;br /&gt;
&lt;br /&gt;
Function tags and function enums have been deprecated in favor of a more modern syntax. Currently, they can still only create tag names for functions. Future versions will support arbitrary types. The syntax is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
typedef ::= &amp;quot;typedef&amp;quot; symbol &amp;quot;=&amp;quot; full-type-expr term&lt;br /&gt;
full-type-expr ::= &amp;quot;(&amp;quot; type-expr &amp;quot;)&amp;quot;&lt;br /&gt;
                 | type-expr&lt;br /&gt;
type-expr ::= &amp;quot;function&amp;quot; type-name &amp;quot;(&amp;quot; typedef-args? &amp;quot;)&amp;quot;&lt;br /&gt;
typedef-args ::= &amp;quot;...&amp;quot;&lt;br /&gt;
               | typedef-arg (&amp;quot;, &amp;quot; &amp;quot;...&amp;quot;)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that typedefs only support new-style types. For example,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
functag public Action:SrvCmd(args);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Becomes...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
typedef SrvCmd = function Action (int args);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Enforcing new syntax=&lt;br /&gt;
&lt;br /&gt;
You can enforce the new syntax in 1.7 by using &amp;lt;pawn&amp;gt;#pragma newdecls required&amp;lt;/pawn&amp;gt; ontop of your code, after the includes (or else current 1.7 includes which contain old syntax will be read with new-syntax rules).&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9811</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9811"/>
		<updated>2015-02-04T23:52:22Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Overview=&lt;br /&gt;
&lt;br /&gt;
For users, SourceMod 1.7.0 is not much difference from an incremental release. Game compatibility is updated, some bugs are fixed, etc. Additionally, as some games switch to a newer Steam Id format, both the old and new can be used interchangeably in admin configs and commands.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For plugin developers, SourceMod 1.7.0 is a huge first step toward improving the SourcePawn language. A new, backwards-compatible [[SourcePawn Transitional Syntax]] has been added. With it come many new API additions and improvements. See the notes below for the full scoop.&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Updated game compatibility for TF2, CS:GO, and Dota 2.*&lt;br /&gt;
* Fixed regression in SM 1.6.3 causing load failure on games older than Orangebox. ({{pr|237}})*&lt;br /&gt;
* Rewrote internal Steam auth ID handling ({{pr|147}}, {{pr|153}}, {{pr|155}}, {{pr|162}}, {{pr|204}}, {{pr|210}}, {{pr|222}}, {{pr|246}}).&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* Added default timeout for MySQL connections to avoid hangs. ({{pr|248}}).&lt;br /&gt;
* Fixed &amp;lt;tt&amp;gt;sm plugins refresh&amp;lt;/tt&amp;gt; not actually refreshing updated plugins like map change does ({{pr|257}}).&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates ({{pr|220}}).&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows ({{pr|163}}).&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing ({{pr|236}}).&lt;br /&gt;
* Changed default sm_trigger_show ConVar value to 0 / disabled.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* Added Blocked hook type to SDKHooks ({{pr|119}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Added OnTakeDamage_Alive hook type to SDKHooks ({{pr|149}}).&lt;br /&gt;
* Many more File natives now support Valve FS ({{pr|120}}, {{pr|169}}, {{pr|178}}).&lt;br /&gt;
* Added SetFilePermissions native ({{pr|43}}) ({{user|9967|hlstriker}}).&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters ({{pr|164}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Exposed engine Message_DetermineMulticastRecipients as GetClientsInRange native. ({{pr|234}}).&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error ({{pr|74}}).&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface ({{pr|127}}).&lt;br /&gt;
* Fixed IThreader threads leaking if they're not joined. ({{bz|3460}}, {{pr|241}})&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile ({{pr|217}}).&lt;br /&gt;
* Fixed FindFlagChar returning false when passing AdminFlag_Custom6 ({{bz|6248}}, {{pr|203}}).&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt ({{pr|83}}).&lt;br /&gt;
* Doubled maximum handle count per plugin to 32,768 ({{pr|215}}), (Thordin).&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields ({{pr|157}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf) ({{pr|54}}).&lt;br /&gt;
* Added command to dump profiler output ({{pr|128}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Fixed ICommandLine and related features being reported as unavailable on Dark Messiah.*&lt;br /&gt;
* Fixed OnPlayerRunCommand forward in SDKTools being unavailable on Dark Messiah.*&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; These items are still new since SourceMod 1.6.3, but also exist in the unreleased 1.6.4-dev version.&lt;br /&gt;
&lt;br /&gt;
=Developer Notes=&lt;br /&gt;
&lt;br /&gt;
The biggest change for developers in SourceMod 1.7 is the new [[SourcePawn Transitional Syntax]], which adds some object-oriented capabilities to our API. The documentation on the transitional syntax has a comprehensive specification for all the changes, including examples.&lt;br /&gt;
&lt;br /&gt;
If you want a very brief takeaway, here are the four new features to keep in mind:&lt;br /&gt;
# Declarations can now be written like in C# or Java. This is the new preferred syntax and will allow us to improve the language faster in the future. In newer declarations, &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt; is renamed to &amp;lt;tt&amp;gt;char&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Float&amp;lt;/tt&amp;gt; is renamed to &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# Instead of &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;, there is a new &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; keyword.&lt;br /&gt;
# Instead of explicit tags, there is now a &amp;lt;tt&amp;gt;view_as&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/tt&amp;gt; expression that is preferred.&lt;br /&gt;
# Instead of &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt;, you can now use the new &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; keyword.&lt;br /&gt;
&lt;br /&gt;
We also note here some specific cases where compatibility with older scripts has been broken. These are source-level compatibility changes only - SourceMod will continue to run scripts compiled with SourceMod 1.6 and earlier.&lt;br /&gt;
&lt;br /&gt;
# '''Coercing function types is now a warning.''' For example, passing a &amp;lt;tt&amp;gt;Function&amp;lt;/tt&amp;gt;-tagged value to &amp;lt;tt&amp;gt;any&amp;lt;/tt&amp;gt;, and then returning it as an &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;. The ability to coerce function types to plain values is a serious impediment to future improvements to SourcePawn. It is now a warning, and will be an error in a future version of SourcePawn.&lt;br /&gt;
# '''decl is deprecated'''. For new-style declarations, the &amp;lt;tt&amp;gt;decl&amp;lt;/tt&amp;gt; keyword is not (and never will be) available. New-style declarations are always zeroed. For huge arrays in a critical path (such as a player loop in &amp;lt;tt&amp;gt;OnGameFrame&amp;lt;/tt&amp;gt;), users should first estimate the time spent per-frame zeroing such arrays and then decide if they need to be hoisted outside the loop or made to be static.&lt;br /&gt;
# '''Multiple tag support has been removed.''' Previously, it was possible to specify multiple tags on an argument. For example, &amp;lt;tt&amp;gt;{Float,bool}:param&amp;lt;/tt&amp;gt;. This syntax is no longer available.&lt;br /&gt;
# '''&amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; can no longer be used on indeterminate arrays.''' Previously, &amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; on an indeterminate array (an array whose size is not statically known) was a warning. It is now an error.&lt;br /&gt;
# '''Reserved keywords'''. We have taken the opportunity to reserve a number of keywords for future versions of SourcePawn. They don't do anything, and they have no semantics. They are only reserved now to mitigate any potential problems if we do need them in the future. They are: &amp;lt;tt&amp;gt;acquire&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;as&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;builtin&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;catch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;cast_to&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;double&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;explicit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;finally&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;foreach&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;implicit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;import&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;int8&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;int16&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;int32&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;int64&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;intn&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;namespace&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;object&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;package&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;private&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;protected&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;readonly&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sealed&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;throw&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;try&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;typeof&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uint8&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uint16&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uint32&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uint64&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uintn&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;union&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;variant&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;with&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# '''&amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; no longer has magic meaning as a default argument expression.''' Previously, &amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; as a default argument expression would bind to the variable at its callsite, rather than the argument in parameter scope. This allowed users to create functions that did not seem to require an explicit size parameter alongside an array. This feature was buggy, so it has been removed, alongside similar magic binding for &amp;lt;tt&amp;gt;tagof&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;cellsof&amp;lt;/tt&amp;gt; in default argument expressions.&lt;br /&gt;
# '''&amp;lt;tt&amp;gt;String[]&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;any&amp;lt;/tt&amp;gt; no longer coerce'''. Previously, it was possible to coerce a character array to an &amp;lt;tt&amp;gt;any&amp;lt;/tt&amp;gt; array, or vice-versa. This cast was unsafe because the storage widths of each array value are different (one normal array is four bytes per slot, and a character is one byte per slot). This coercion is now illegal.&lt;br /&gt;
# '''Using &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;void&amp;lt;/tt&amp;gt; as a tag is now a warning.'''&lt;br /&gt;
# '''Enums cannot be retagged.''' Previously, enums could be retagged - for example, &amp;lt;tt&amp;gt;enum X:Y { ...&amp;lt;/tt&amp;gt;. This is no longer allowed.&lt;br /&gt;
# '''The implicit-int tag cannot be used as an enum tag.''' It is now illegal to use &amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt; as an enum name or label.&lt;br /&gt;
# '''Dynamically sized arrays are now indeterminate.''' Previously, an array could be declared as a mix of fixed-size and dynamic-sized dimensions. Now, all dimensions are considered indeterminate if any one dimension is dynamic-sized. This means &amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; may not work in complex array use.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9810</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9810"/>
		<updated>2015-02-04T22:50:30Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* User Changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
For users, SourceMod 1.7.0 is not much difference from an incremental release. Game compatibility is updated, some bugs are fixed, etc. Additionally, as some games switch to a newer Steam Id format, both the old and new can be used interchangeably in admin configs and commands.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For plugin developers, SourceMod 1.7.0 is a huge first step toward improving the SourcePawn language. A new, backwards-compatible [[SourcePawn Transitional Syntax]] has been added. With it come many new API additions and improvements. See the notes below for the full scoop.&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Updated game compatibility for TF2, CS:GO, and Dota 2.*&lt;br /&gt;
* Fixed regression in SM 1.6.3 causing load failure on games older than Orangebox. ({{pr|237}})*&lt;br /&gt;
* Rewrote internal Steam auth ID handling ({{pr|147}}, {{pr|153}}, {{pr|155}}, {{pr|162}}, {{pr|204}}, {{pr|210}}, {{pr|222}}, {{pr|246}}).&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* Added default timeout for MySQL connections to avoid hangs. ({{pr|248}}).&lt;br /&gt;
* Fixed &amp;lt;tt&amp;gt;sm plugins refresh&amp;lt;/tt&amp;gt; not actually refreshing updated plugins like map change does ({{pr|257}}).&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates ({{pr|220}}).&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows ({{pr|163}}).&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing ({{pr|236}}).&lt;br /&gt;
* Changed default sm_trigger_show ConVar value to 0 / disabled.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* Added Blocked hook type to SDKHooks ({{pr|119}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Added OnTakeDamage_Alive hook type to SDKHooks ({{pr|149}}).&lt;br /&gt;
* Many more File natives now support Valve FS ({{pr|120}}, {{pr|169}}, {{pr|178}}).&lt;br /&gt;
* Added SetFilePermissions native ({{pr|43}}) ({{user|9967|hlstriker}}).&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters ({{pr|164}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Exposed engine Message_DetermineMulticastRecipients as GetClientsInRange native. ({{pr|234}}).&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error ({{pr|74}}).&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface ({{pr|127}}).&lt;br /&gt;
* Fixed IThreader threads leaking if they're not joined. ({{bz|3460}}, {{pr|241}})&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile ({{pr|217}}).&lt;br /&gt;
* Fixed FindFlagChar returning false when passing AdminFlag_Custom6 ({{bz|6248}}, {{pr|203}}).&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt ({{pr|83}}).&lt;br /&gt;
* Doubled maximum handle count per plugin to 32,768 ({{pr|215}}), (Thordin).&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields ({{pr|157}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf) ({{pr|54}}).&lt;br /&gt;
* Added command to dump profiler output ({{pr|128}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Fixed ICommandLine and related features being reported as unavailable on Dark Messiah.*&lt;br /&gt;
* Fixed OnPlayerRunCommand forward in SDKTools being unavailable on Dark Messiah.*&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; These items are still new since SourceMod 1.6.3, but also exist in the unreleased 1.6.4-dev version.&lt;br /&gt;
&lt;br /&gt;
=Developer Notes=&lt;br /&gt;
&lt;br /&gt;
The biggest change for developers in SourceMod 1.7 is the new [[SourcePawn Transitional Syntax]], which adds some object-oriented capabilities to our API. The documentation on the transitional syntax has a comprehensive specification for all the changes, including examples.&lt;br /&gt;
&lt;br /&gt;
If you want a very brief takeaway, here are the four new features to keep in mind:&lt;br /&gt;
# Declarations can now be written like in C# or Java. This is the new preferred syntax and will allow us to improve the language faster in the future. In newer declarations, &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt; is renamed to &amp;lt;tt&amp;gt;char&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Float&amp;lt;/tt&amp;gt; is renamed to &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# Instead of &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;, there is a new &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; keyword.&lt;br /&gt;
# Instead of explicit tags, there is now a &amp;lt;tt&amp;gt;view_as&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/tt&amp;gt; expression that is preferred.&lt;br /&gt;
# Instead of &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt;, you can now use the new &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; keyword.&lt;br /&gt;
&lt;br /&gt;
We also note here some specific cases where compatibility with older scripts has been broken. These are source-level compatibility changes only - SourceMod will continue to run scripts compiled with SourceMod 1.6 and earlier.&lt;br /&gt;
&lt;br /&gt;
# '''Coercing function types is now a warning.''' For example, passing a &amp;lt;tt&amp;gt;Function&amp;lt;/tt&amp;gt;-tagged value to &amp;lt;tt&amp;gt;any&amp;lt;/tt&amp;gt;, and then returning it as an &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;. The ability to coerce function types to plain values is a serious impediment to future improvements to SourcePawn. It is now a warning, and will be an error in a future version of SourcePawn.&lt;br /&gt;
# '''decl is deprecated'''. For new-style declarations, the &amp;lt;tt&amp;gt;decl&amp;lt;/tt&amp;gt; keyword is not (and never will be) available. New-style declarations are always zeroed. For huge arrays in a critical path (such as a player loop in &amp;lt;tt&amp;gt;OnGameFrame&amp;lt;/tt&amp;gt;), users should first estimate the time spent per-frame zeroing such arrays and then decide if they need to be hoisted outside the loop or made to be static.&lt;br /&gt;
# '''Multiple tag support has been removed.''' Previously, it was possible to specify multiple tags on an argument. For example, &amp;lt;tt&amp;gt;{Float,bool}:param&amp;lt;/tt&amp;gt;. This syntax is no longer available.&lt;br /&gt;
# '''&amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; can no longer be used on indeterminate arrays.''' Previously, &amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; on an indeterminate array (an array whose size is not statically known) was a warning. It is now an error.&lt;br /&gt;
# '''Reserved keywords'''. We have taken the opportunity to reserve a number of keywords for future versions of SourcePawn. They don't do anything, and they have no semantics. They are only reserved now to mitigate any potential problems if we do need them in the future. They are: &amp;lt;tt&amp;gt;acquire&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;as&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;builtin&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;catch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;cast_to&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;double&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;explicit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;finally&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;foreach&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;implicit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;import&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;int8&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;int16&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;int32&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;int64&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;intn&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;let&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;namespace&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;object&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;package&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;private&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;protected&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;readonly&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sealed&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;throw&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;try&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;typeof&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uint8&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uint16&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uint32&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uint64&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;uintn&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;union&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;variant&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;with&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# '''&amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; no longer has magic meaning as a default argument expression.''' Previously, &amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; as a default argument expression would bind to the variable at its callsite, rather than the argument in parameter scope. This allowed users to create functions that did not seem to require an explicit size parameter alongside an array. This feature was buggy, so it has been removed, alongside similar magic binding for &amp;lt;tt&amp;gt;tagof&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;cellsof&amp;lt;/tt&amp;gt; in default argument expressions.&lt;br /&gt;
# '''&amp;lt;tt&amp;gt;String[]&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;any&amp;lt;/tt&amp;gt; no longer coerce'''. Previously, it was possible to coerce a character array to an &amp;lt;tt&amp;gt;any&amp;lt;/tt&amp;gt; array, or vice-versa. This cast was unsafe because the storage widths of each array value are different (one normal array is four bytes per slot, and a character is one byte per slot). This coercion is now illegal.&lt;br /&gt;
# '''Using &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;void&amp;lt;/tt&amp;gt; as a tag is now a warning.'''&lt;br /&gt;
# '''Enums cannot be retagged.''' Previously, enums could be retagged - for example, &amp;lt;tt&amp;gt;enum X:Y { ...&amp;lt;/tt&amp;gt;. This is no longer allowed.&lt;br /&gt;
# '''The implicit-int tag cannot be used as an enum tag.''' It is now illegal to use &amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt; as an enum name or label.&lt;br /&gt;
# '''Dynamically sized arrays are now indeterminate.''' Previously, an array could be declared as a mix of fixed-size and dynamic-sized dimensions. Now, all dimensions are considered indeterminate if any one dimension is dynamic-sized. This means &amp;lt;tt&amp;gt;sizeof&amp;lt;/tt&amp;gt; may not work in complex array use.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9797</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9797"/>
		<updated>2015-02-03T20:34:11Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
For users, SourceMod 1.7.0 is not much difference from an incremental release. Game compatibility is updated, some bugs are fixed, etc. Additionally, as some games switch to a newer Steam Id format, both the old and new can be used interchangeably in admin configs and commands.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For plugin developers, SourceMod 1.7.0 is a huge first step toward improving the SourcePawn language. A new, backwards-compatible [[SourcePawn Transitional Syntax]] has been added. With it come many new API additions and improvements. See the notes below for the full scoop.&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Updated game compatibility for TF2, CS:GO, and Dota 2.*&lt;br /&gt;
* Fixed regression in SM 1.6.3 causing load failure on games older than Orangebox. ({{pr|237}})*&lt;br /&gt;
* Rewrote internal Steam auth ID handling ({{pr|147}}, {{pr|153}}, {{pr|155}}, {{pr|162}}, {{pr|204}}, {{pr|210}}, {{pr|222}}, {{pr|246}}).&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* Added default timeout for MySQL connections to avoid hangs. ({{pr|248}}).&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates ({{pr|220}}).&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows ({{pr|163}}).&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing ({{pr|236}}).&lt;br /&gt;
* Changed default sm_trigger_show ConVar value to 0 / disabled.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* Added Blocked hook type to SDKHooks ({{pr|119}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Added OnTakeDamage_Alive hook type to SDKHooks ({{pr|149}}).&lt;br /&gt;
* Many more File natives now support Valve FS ({{pr|120}}, {{pr|169}}, {{pr|178}}).&lt;br /&gt;
* Added SetFilePermissions native ({{pr|43}}) ({{user|9967|hlstriker}}).&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters ({{pr|164}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Exposed engine Message_DetermineMulticastRecipients as GetClientsInRange native. ({{pr|234}}).&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error ({{pr|74}}).&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface ({{pr|127}}).&lt;br /&gt;
* Fixed IThreader threads leaking if they're not joined. ({{bz|3460}}, {{pr|241}})&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile ({{pr|217}}).&lt;br /&gt;
* Fixed FindFlagChar returning false when passing AdminFlag_Custom6 ({{bz|6248}}, {{pr|203}}).&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt ({{pr|83}}).&lt;br /&gt;
* Doubled maximum handle count per plugin to 32,768 ({{pr|215}}), (Thordin).&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields ({{pr|157}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf) ({{pr|54}}).&lt;br /&gt;
* Added command to dump profiler output ({{pr|128}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Fixed ICommandLine and related features being reported as unavailable on Dark Messiah.*&lt;br /&gt;
* Fixed OnPlayerRunCommand forward in SDKTools being unavailable on Dark Messiah.*&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; These items are still new since SourceMod 1.6.3, but also exist in the unreleased 1.6.4-dev version.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9796</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9796"/>
		<updated>2015-02-03T20:33:55Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Overview */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
For users, SourceMod 1.7.0 is not much difference from an incremental release. Game compatibility is updated, some bugs are fixed, etc. Additionally, as some games switch to a newer Steam Id format, both the old and new can be used interchangeably in admin configs and commands.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For plugin developers, SourceMod 1.7.0 is a huge first step toward improving the SourcePawn language. A new, backwards-compatible [[SourcePawn Transitional Syntax]] has been added. With it come many new API additions and improvements. See the notes below for the full scoop.&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Updated game compatibility for TF2, CS:GO, and Dota 2.*&lt;br /&gt;
* Fixed regression in SM 1.6.3 causing load failure on games older than Orangebox. ({{pr|237}})*&lt;br /&gt;
* Rewrote internal Steam auth ID handling ({{pr|147}}, {{pr|153}}, {{pr|155}}, {{pr|162}}, {{pr|204}}, {{pr|210}}, {{pr|222}}, {{pr|246}}).&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* Added default timeout for MySQL connections to avoid hangs. ({{pr|248}}).&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates ({{pr|220}}).&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows ({{pr|163}}).&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing ({{pr|236}}).&lt;br /&gt;
* Changed default sm_trigger_show ConVar value to 0 / disabled.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* Added Blocked hook type to SDKHooks ({{pr|119}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Added OnTakeDamage_Alive hook type to SDKHooks ({{pr|149}}).&lt;br /&gt;
* Many more File natives now support Valve FS ({{pr|120}}, {{pr|169}}, {{pr|178}}).&lt;br /&gt;
* Added SetFilePermissions native ({{pr|43}}) ({{user|9967|hlstriker}}).&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters ({{pr|164}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Exposed engine Message_DetermineMulticastRecipients as GetClientsInRange native. ({{pr|234}}).&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error ({{pr|74}}).&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface ({{pr|127}}).&lt;br /&gt;
* Fixed IThreader threads leaking if they're not joined. ({{bz|3460}}, {{pr|241}})&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile ({{pr|217}}).&lt;br /&gt;
* Fixed FindFlagChar returning false when passing AdminFlag_Custom6 ({{bz|6248}}, {{pr|203}}).&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt ({{pr|83}}).&lt;br /&gt;
* Doubled maximum handle count per plugin to 32,768 ({{pr|215}}), (Thordin).&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields ({{pr|157}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf) ({{pr|54}}).&lt;br /&gt;
* Added command to dump profiler output ({{pr|128}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Fixed ICommandLine and related features being reported as unavailable on Dark Messiah.*&lt;br /&gt;
* Fixed OnPlayerRunCommand forward in SDKTools being unavailable on Dark Messiah.*&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; These items are still new since SourceMod 1.6.3, but also exist in the unreleased 1.6.4-dev version.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9795</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9795"/>
		<updated>2015-02-03T20:33:19Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
For users, SourceMod 1.7.0 is not much difference from an incremental release. Game compatibility is updated, some bugs are fixed, etc. Additionally, as some games switch to a newer Steam Id format, both the old and new can be used interchangeably in admin configs and commands.&lt;br /&gt;
&lt;br /&gt;
For plugin developers, SourceMod 1.7.0 is a huge first step toward improving the SourcePawn language. A new, backwards-compatible [[SourcePawn Transitional Syntax]] has been added. With it come many new API additions and improvements. See the notes below for the full scoop.&lt;br /&gt;
&lt;br /&gt;
SourceMod 1.7.0 &lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Updated game compatibility for TF2, CS:GO, and Dota 2.*&lt;br /&gt;
* Fixed regression in SM 1.6.3 causing load failure on games older than Orangebox. ({{pr|237}})*&lt;br /&gt;
* Rewrote internal Steam auth ID handling ({{pr|147}}, {{pr|153}}, {{pr|155}}, {{pr|162}}, {{pr|204}}, {{pr|210}}, {{pr|222}}, {{pr|246}}).&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* Added default timeout for MySQL connections to avoid hangs. ({{pr|248}}).&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates ({{pr|220}}).&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows ({{pr|163}}).&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing ({{pr|236}}).&lt;br /&gt;
* Changed default sm_trigger_show ConVar value to 0 / disabled.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* Added Blocked hook type to SDKHooks ({{pr|119}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Added OnTakeDamage_Alive hook type to SDKHooks ({{pr|149}}).&lt;br /&gt;
* Many more File natives now support Valve FS ({{pr|120}}, {{pr|169}}, {{pr|178}}).&lt;br /&gt;
* Added SetFilePermissions native ({{pr|43}}) ({{user|9967|hlstriker}}).&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters ({{pr|164}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Exposed engine Message_DetermineMulticastRecipients as GetClientsInRange native. ({{pr|234}}).&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error ({{pr|74}}).&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface ({{pr|127}}).&lt;br /&gt;
* Fixed IThreader threads leaking if they're not joined. ({{bz|3460}}, {{pr|241}})&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile ({{pr|217}}).&lt;br /&gt;
* Fixed FindFlagChar returning false when passing AdminFlag_Custom6 ({{bz|6248}}, {{pr|203}}).&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt ({{pr|83}}).&lt;br /&gt;
* Doubled maximum handle count per plugin to 32,768 ({{pr|215}}), (Thordin).&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields ({{pr|157}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf) ({{pr|54}}).&lt;br /&gt;
* Added command to dump profiler output ({{pr|128}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Fixed ICommandLine and related features being reported as unavailable on Dark Messiah.*&lt;br /&gt;
* Fixed OnPlayerRunCommand forward in SDKTools being unavailable on Dark Messiah.*&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; These items are still new since SourceMod 1.6.3, but also exist in the unreleased 1.6.4-dev version.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9794</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9794"/>
		<updated>2015-02-03T20:16:23Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Changelog */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Updated game compatibility for TF2, CS:GO, and Dota 2.*&lt;br /&gt;
* Fixed regression in SM 1.6.3 causing load failure on games older than Orangebox. ({{pr|237}})*&lt;br /&gt;
* Rewrote internal Steam auth ID handling ({{pr|147}}, {{pr|153}}, {{pr|155}}, {{pr|162}}, {{pr|204}}, {{pr|210}}, {{pr|222}}, {{pr|246}}).&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* Added default timeout for MySQL connections to avoid hangs. ({{pr|248}}).&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates ({{pr|220}}).&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows ({{pr|163}}).&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing ({{pr|236}}).&lt;br /&gt;
* Changed default sm_trigger_show ConVar value to 0 / disabled.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* Added Blocked hook type to SDKHooks ({{pr|119}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Added OnTakeDamage_Alive hook type to SDKHooks ({{pr|149}}).&lt;br /&gt;
* Many more File natives now support Valve FS ({{pr|120}}, {{pr|169}}, {{pr|178}}).&lt;br /&gt;
* Added SetFilePermissions native ({{pr|43}}) ({{user|9967|hlstriker}}).&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters ({{pr|164}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Exposed engine Message_DetermineMulticastRecipients as GetClientsInRange native. ({{pr|234}}).&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error ({{pr|74}}).&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface ({{pr|127}}).&lt;br /&gt;
* Fixed IThreader threads leaking if they're not joined. ({{bz|3460}}, {{pr|241}})&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile ({{pr|217}}).&lt;br /&gt;
* Fixed FindFlagChar returning false when passing AdminFlag_Custom6 ({{bz|6248}}, {{pr|203}}).&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt ({{pr|83}}).&lt;br /&gt;
* Doubled maximum handle count per plugin to 32,768 ({{pr|215}}), (Thordin).&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields ({{pr|157}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf) ({{pr|54}}).&lt;br /&gt;
* Added command to dump profiler output ({{pr|128}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Fixed ICommandLine and related features being reported as unavailable on Dark Messiah.*&lt;br /&gt;
* Fixed OnPlayerRunCommand forward in SDKTools being unavailable on Dark Messiah.*&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; These items are still new since SourceMod 1.6.3, but also exist in the unreleased 1.6.4-dev version.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9793</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9793"/>
		<updated>2015-02-03T20:07:44Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Changelog */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Updated game compatibility for TF2, CS:GO, and Dota 2.*&lt;br /&gt;
* Fixed regression in SM 1.6.3 causing load failure on games older than Orangebox. ({{pr|237}})*&lt;br /&gt;
* Rewrote internal Steam auth ID handling ({{pr|147}}, {{pr|153}}, {{pr|155}}, {{pr|162}}, {{pr|204}}, {{pr|210}}, {{pr|222}}, {{pr|246}}).&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates ({{pr|220}}).&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows ({{pr|163}}).&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing ({{pr|236}}).&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* Added Blocked hook type to SDKHooks ({{pr|119}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Added OnTakeDamage_Alive hook type to SDKHooks ({{pr|149}}).&lt;br /&gt;
* Many more File natives now support Valve FS ({{pr|120}}, {{pr|169}}, {{pr|178}}).&lt;br /&gt;
* Added SetFilePermissions native ({{pr|43}}) ({{user|9967|hlstriker}}).&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters ({{pr|164}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Exposed engine Message_DetermineMulticastRecipients as GetClientsInRange native. ({{pr|234}}).&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error ({{pr|74}}).&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface ({{pr|127}}).&lt;br /&gt;
* Fixed IThreader threads leaking if they're not joined. ({{bz|3460}}, {{pr|241}})&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile ({{pr|217}}).&lt;br /&gt;
* Fixed FindFlagChar returning false when passing AdminFlag_Custom6 ({{bz|6248}}, {{pr|203}}).&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt ({{pr|83}}).&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields ({{pr|157}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf) ({{pr|54}}).&lt;br /&gt;
* Added command to dump profiler output ({{pr|128}}) ({{user|49537|VoiDeD}}).&lt;br /&gt;
* Fixed ICommandLine and related features being reported as unavailable on Dark Messiah.*&lt;br /&gt;
* Fixed OnPlayerRunCommand forward in SDKTools being unavailable on Dark Messiah.*&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; These items are still new since SourceMod 1.6.3, but also exist in the unreleased 1.6.4-dev version.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9792</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9792"/>
		<updated>2015-02-03T19:24:43Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Developer Changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Rewrote internal Steam auth ID handling&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates.&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows.&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* SDKHooks - Added Blocked and OnTakeDamage_Alive hook types.&lt;br /&gt;
* Many more File natives now support Valve FS.&lt;br /&gt;
* Added SetFilePermissions native.&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters.&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error.&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface.&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile.&lt;br /&gt;
* Fixed FindFlagChar returning false when passing AdminFlag_Custom6 ({{bz|6248}}, {{pr|203}}).&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt.&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields.&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf).&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9791</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9791"/>
		<updated>2015-02-03T19:22:53Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Developer Changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Rewrote internal Steam auth ID handling&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates.&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows.&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* SDKHooks - Added Blocked and OnTakeDamage_Alive hook types.&lt;br /&gt;
* Many more File natives now support Valve FS.&lt;br /&gt;
* Added SetFilePermissions native.&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters.&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error.&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface.&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile.&lt;br /&gt;
* Fixed FindFlagChar returning false when passing AdminFlag_Custom6 ({{bz|6248}}).&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt.&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields.&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf).&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9782</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9782"/>
		<updated>2015-01-23T20:45:38Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* User Changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Rewrote internal Steam auth ID handling&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* SDKTools' gamerules gamedata is now far less likely to break on updates.&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows.&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* SDKHooks - Added Blocked and OnTakeDamage_Alive hook types.&lt;br /&gt;
* Many more File natives now support Valve FS.&lt;br /&gt;
* Added SetFilePermissions native.&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters.&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error.&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface.&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile.&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt.&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields.&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf).&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9781</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9781"/>
		<updated>2015-01-23T20:43:57Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Developer Changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Rewrote internal Steam auth ID handling&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* SDKTools' gamerules gamedata is now less likely to break on updates.&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows.&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** New methodmap-based APIs have been added for many existing functions and handle types.&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* SDKHooks - Added Blocked and OnTakeDamage_Alive hook types.&lt;br /&gt;
* Many more File natives now support Valve FS.&lt;br /&gt;
* Added SetFilePermissions native.&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters.&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error.&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface.&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile.&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt.&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields.&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf).&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9780</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9780"/>
		<updated>2015-01-23T20:42:24Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Rewrote internal Steam auth ID handling&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* SDKTools' gamerules gamedata is now less likely to break on updates.&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows.&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]]!&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* SDKHooks - Added Blocked and OnTakeDamage_Alive hook types.&lt;br /&gt;
* Many more File natives now support Valve FS.&lt;br /&gt;
* Added SetFilePermissions native.&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters.&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error.&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface.&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile.&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt.&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields.&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf).&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9779</id>
		<title>SourceMod 1.7.0 Release Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=SourceMod_1.7.0_Release_Notes&amp;diff=9779"/>
		<updated>2015-01-23T20:40:27Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Created page with &amp;quot;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''  =Changelog=  ===User Changes=== * Rewrote internal Steam a...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This page is still a work-in-progress, incomplete and barely edited, as SourceMod 1.7 has not been released yet''&lt;br /&gt;
&lt;br /&gt;
=Changelog=&lt;br /&gt;
&lt;br /&gt;
===User Changes===&lt;br /&gt;
* Rewrote internal Steam auth ID handling&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins.cfg&amp;lt;/tt&amp;gt; now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.&lt;br /&gt;
** &amp;lt;tt&amp;gt;admins-simple.ini&amp;lt;/tt&amp;gt; now supports Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
** Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.&lt;br /&gt;
* SDKTools' gamerules gamedata is now less likely to break on updates.&lt;br /&gt;
* Fixed crash with sm_dump_admcache on Windows.&lt;br /&gt;
* Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing.&lt;br /&gt;
&lt;br /&gt;
===Developer Changes===&lt;br /&gt;
&lt;br /&gt;
* Added new [[SourcePawn Transitional Syntax]].&lt;br /&gt;
** [https://sm.alliedmods.net/new-api New work-in-progress API doc page].&lt;br /&gt;
* SDKHooks - Added Blocked and OnTakeDamage_Alive hook types.&lt;br /&gt;
* Many more File natives now support Valve FS.&lt;br /&gt;
* Added SetFilePermissions native.&lt;br /&gt;
* Added API for iterating StringMaps (formerly &amp;quot;tries&amp;quot;).&lt;br /&gt;
* Added natives for accessing command line parameters.&lt;br /&gt;
* CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error.&lt;br /&gt;
* GetClientAuthString is now deprecated. Use [https://sm.alliedmods.net/new-api/clients/GetClientAuthId GetClientAuthId] instead.&lt;br /&gt;
* Added OnCoreMapEnd to extension interface.&lt;br /&gt;
* TFHoliday updates no longer require a plugin recompile.&lt;br /&gt;
* Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt.&lt;br /&gt;
* Added support for custom default values with GetEvent* natives, rather than using &amp;quot;&amp;quot;/0 for unset fields.&lt;br /&gt;
* Removed old profiler, and added new, pluggable profiler (with hooks to VProf).&lt;br /&gt;
* SourceMod now uses some C++11 and has newer compiler requirements.&lt;br /&gt;
* Added --disable-auto-versioning option to ambuild configure script.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Building_AMX_Mod_X&amp;diff=9778</id>
		<title>Building AMX Mod X</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Building_AMX_Mod_X&amp;diff=9778"/>
		<updated>2015-01-23T14:50:43Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: Fix path to configure.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AMX Mod X is a large project, but we've tried to make it as easy to build as possible. The directions here will step you through the entire process.&lt;br /&gt;
&lt;br /&gt;
=Requirements=&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Install Visual Studio or Visual C++ 2010 or higher. Express editions should work fine. If you use 2013 or higher, make sure to get the &amp;quot;Desktop&amp;quot; version: [http://www.visualstudio.com/downloads/download-visual-studio-vs#d-express-windows-desktop Visual Studio Express 2013 for Desktop].&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Install [http://git-scm.com/ Git]. Make sure that you select the option that adds Git to PATH.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Next, you will need to start an environment capable of running Python and interacting with the Visual Studio compiler. There are two ways to do this.&lt;br /&gt;
 &amp;lt;ul&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Use [https://wiki.mozilla.org/MozillaBuild MozillaBuild]. MozillaBuild comes with Python, Mercurial, and a unix-like shell.&lt;br /&gt;
   &amp;lt;ol&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Install MozillaBuild.&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Navigate to &amp;lt;tt&amp;gt;C:\mozilla-build&amp;lt;/tt&amp;gt; and run the batch file corresponding to your Visual Studio version. For example, &amp;lt;tt&amp;gt;start-msvc10.bat&amp;lt;/tt&amp;gt; for Visual Studio 2010 (10.0). Do not run an x64 version.&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Add Git to MozillaBuild's &amp;lt;tt&amp;gt;PATH&amp;lt;/tt&amp;gt;. The easiest way to do this is to enter the following commands:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo &amp;quot;export PATH=\$PATH:/c/Program\ Files\ \(x86\)/Git/bin&amp;quot; &amp;gt;&amp;gt; ~/.profile&lt;br /&gt;
source ~/.profile&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
    &amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;/ol&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Or, you can manually set up a shell.&lt;br /&gt;
   &amp;lt;ol&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Install [http://mercurial.selenic.com/ Mercurial].&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Install [http://python.org/ Python] 2.7. It will install to C:\Python27 by default. (Version 3.4 will work, but is not recommended for compatibility with other tools).&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Add Python to your &amp;lt;tt&amp;gt;PATH&amp;lt;/tt&amp;gt; variable. Go to Control Panel, System, Advanced, Environment Variables. Add &amp;lt;tt&amp;gt;C:\Python27;C:\Python27\Scripts&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;PATH&amp;lt;/tt&amp;gt; (or wherever your Python install is).&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Under Start, Programs, Microsoft Visual Studio, select the &amp;quot;Visual Studio Tools&amp;quot; folder and run &amp;quot;Visual Studio Command Prompt&amp;quot;. Alternately, open a normal command prompt and run &amp;lt;tt&amp;gt;&amp;quot;C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\vcvars.bat&amp;quot;&amp;lt;/tt&amp;gt;. Substitute your Visual Studio version if needed.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;/ol&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that AMX Mod X also has Visual Studio project files. These can be used for local development, however, they are not maintained nor are they used for official builds.&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Install Git, via either system packages or from the [http://git-scm.com/ Git] distribution.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Install either the GNU C Compiler or the Clang compiler. On Debian/Ubuntu, the following commands will give you everything:&lt;br /&gt;
  &amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get install gcc g++ clang&lt;br /&gt;
  &amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;If building on a 64-bit system, a few additional packages may be required. For example on Debian/Ubuntu they are:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get install ia32-libs&lt;br /&gt;
sudo apt-get install lib32z1 lib32z1-dev&lt;br /&gt;
sudo apt-get install libc6-dev-i386 libc6-i386&lt;br /&gt;
sudo apt-get install gcc-multilib g++-multilib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Mac OS X==&lt;br /&gt;
Mac OS X 10.7 or higher is required to build, however, AMX Mod X will work on versions as early as 10.5.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Install the Xcode Command Line Tools.&lt;br /&gt;
  &amp;lt;ul&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;For OS X 10.9 or higher, run the command below in Terminal and click the Install button in the window that appears.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
xcode-select --install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
    &amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;For earlier versions of OS X, download and install Xcode from the App Store. Launch Xcode and then navigate to Preferences -&amp;gt; Downloads -&amp;gt; Components -&amp;gt; Command Line Tools -&amp;gt; Install. If you have recently upgraded Xcode, you will need to perform this step again. AMX Mod X cannot build without Xcode's command line tools.&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Dependencies=&lt;br /&gt;
Building AMX Mod X requires AMBuild, Metamod, the Half-Life SDK, and optionally MySQL 5. If you're using Linux, OS X, or Windows with MozillaBuild, you download and run the following script to get everything:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://raw2.github.com/alliedmodders/amxmodx/master/support/checkout-deps.sh&lt;br /&gt;
bash checkout-deps.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will download everything required into &amp;lt;tt&amp;gt;amxmodx&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;hlsdk&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;metamod-am&amp;lt;/tt&amp;gt;. If AMBuild is not installed, it will also download it into &amp;lt;tt&amp;gt;ambuild&amp;lt;/tt&amp;gt;, and prompt you for your password to install it.&lt;br /&gt;
&lt;br /&gt;
If for some reason this script doesn't work, or you can't use it, you can get AMX Mod X and its dependencies like so:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/alliedmodders/ambuild&lt;br /&gt;
git clone https://github.com/alliedmodders/metamod-hl1&lt;br /&gt;
git clone https://github.com/alliedmodders/hlsdk&lt;br /&gt;
git clone https://github.com/alliedmodders/amxmodx&lt;br /&gt;
cd ambuild&lt;br /&gt;
python setup.py install     # May need sudo or root on Linux/OS X&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Configuring=&lt;br /&gt;
&lt;br /&gt;
The first time you are building AMX Mod X, you must ''configure'' the build. First create a build folder, and then run &amp;lt;tt&amp;gt;configure.py&amp;lt;/tt&amp;gt;. For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir build&lt;br /&gt;
cd build&lt;br /&gt;
python ../configure.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is safe to reconfigure over an old build. However, it's probably a bad idea to configure inside a random, non-empty folder.&lt;br /&gt;
&lt;br /&gt;
There are a few extra options you can pass to &amp;lt;tt&amp;gt;configure&amp;lt;/tt&amp;gt;:&lt;br /&gt;
*--enable-debug - Compile with symbols and debug checks/assertions.&lt;br /&gt;
*--enable-optimize - Compile with optimizations.&lt;br /&gt;
*--no-mysql - If you didn't install MySQL, you can choose not to build the extension.&lt;br /&gt;
&lt;br /&gt;
=Building=&lt;br /&gt;
&lt;br /&gt;
To build AMX Mod X, simply navigate to your build folder and type &amp;lt;tt&amp;gt;ambuild&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd build&lt;br /&gt;
ambuild&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternately, you can specify the path of the build folder:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ambuild build&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The full package layouts that would be shipped for release are in the &amp;lt;tt&amp;gt;package&amp;lt;/tt&amp;gt; folder of the build.&lt;br /&gt;
&lt;br /&gt;
[[Category:Documentation (AMX Mod X)]]&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=9775</id>
		<title>Compiling libprotobuf</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=9775"/>
		<updated>2015-01-21T14:07:20Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Examples for compiling a 32-bit libprotobuf and other protobuf libraries using the protobuf-2.5.0 source.&lt;br /&gt;
&lt;br /&gt;
''For Dota 2, replace version 2.5.0 with 2.6.1.''&lt;br /&gt;
&lt;br /&gt;
''Also note that the Protobuf source has moved to [http://www.github.com/google/protobuf GitHub]. Some of the below links may be outdated.''&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
The following was tested on Windows 8.1 with Visual Studio 2013. Not all projects built after conversion, but only libprotobuf and dependencies were necessary.&lt;br /&gt;
&lt;br /&gt;
* Download protobuf-2.5.0.zip from https://code.google.com/p/protobuf/downloads/list&lt;br /&gt;
* Extract and navigate to protobuf-2.5.0/vsprojects/&lt;br /&gt;
* Open protobuf.sln in the version of Visual Studio corresponding with the VC abi version that you wish to compile for.&lt;br /&gt;
* Walk through project conversion steps if necessary.&lt;br /&gt;
* Right-click the libprotobuf project and choose properties.&lt;br /&gt;
* In Configuration Properties &amp;gt; C/C++ -&amp;gt; Code Generation, set Runtime Library to /MT for Release or /MTd for Debug.&lt;br /&gt;
* If building the Debug configuration, also add _ITERATOR_DEBUG_LEVEL=0 in Configuration Properties &amp;gt; C/C++ &amp;gt; Preprocessor &amp;gt; Preprocessor Defintions&lt;br /&gt;
* Right-click the libprotobuf project and choose Build.&lt;br /&gt;
&lt;br /&gt;
libprotobuf.lib will be in Release/ or Debug/, depending on build configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (32-bit host)==&lt;br /&gt;
The following was tested on Debian 6 (Lenny) 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure CXXFLAGS=&amp;quot;-g3 -ggdb3&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (64-bit host)==&lt;br /&gt;
This hasn't been tested, but ''should'' work on most or all 64-bit distributions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Mac==&lt;br /&gt;
The following was tested on OS X 10.7 (Lion) and ensures that the outputted binaries are 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-DNDEBUG -m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=9774</id>
		<title>Compiling libprotobuf</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=9774"/>
		<updated>2015-01-21T14:07:09Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: GRAMMAR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Examples for compiling a 32-bit libprotobuf and other protobuf libraries using the protobuf-2.5.0 source.&lt;br /&gt;
&lt;br /&gt;
''For Dota 2, replace version 2.5.0 with 2.6.1.''&lt;br /&gt;
&lt;br /&gt;
''Also note that the Protobuf source has moved to [http://www.github.com/google/protobuf link GitHub]. Some of the below links may be outdated.''&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
The following was tested on Windows 8.1 with Visual Studio 2013. Not all projects built after conversion, but only libprotobuf and dependencies were necessary.&lt;br /&gt;
&lt;br /&gt;
* Download protobuf-2.5.0.zip from https://code.google.com/p/protobuf/downloads/list&lt;br /&gt;
* Extract and navigate to protobuf-2.5.0/vsprojects/&lt;br /&gt;
* Open protobuf.sln in the version of Visual Studio corresponding with the VC abi version that you wish to compile for.&lt;br /&gt;
* Walk through project conversion steps if necessary.&lt;br /&gt;
* Right-click the libprotobuf project and choose properties.&lt;br /&gt;
* In Configuration Properties &amp;gt; C/C++ -&amp;gt; Code Generation, set Runtime Library to /MT for Release or /MTd for Debug.&lt;br /&gt;
* If building the Debug configuration, also add _ITERATOR_DEBUG_LEVEL=0 in Configuration Properties &amp;gt; C/C++ &amp;gt; Preprocessor &amp;gt; Preprocessor Defintions&lt;br /&gt;
* Right-click the libprotobuf project and choose Build.&lt;br /&gt;
&lt;br /&gt;
libprotobuf.lib will be in Release/ or Debug/, depending on build configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (32-bit host)==&lt;br /&gt;
The following was tested on Debian 6 (Lenny) 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure CXXFLAGS=&amp;quot;-g3 -ggdb3&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (64-bit host)==&lt;br /&gt;
This hasn't been tested, but ''should'' work on most or all 64-bit distributions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Mac==&lt;br /&gt;
The following was tested on OS X 10.7 (Lion) and ensures that the outputted binaries are 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-DNDEBUG -m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=9773</id>
		<title>Compiling libprotobuf</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Compiling_libprotobuf&amp;diff=9773"/>
		<updated>2015-01-21T14:06:51Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Examples for compiling a 32-bit libprotobuf and other protobuf libraries using the protobuf-2.5.0 source.&lt;br /&gt;
&lt;br /&gt;
''For Dota 2, replacing version 2.5.0 with 2.6.1.''&lt;br /&gt;
&lt;br /&gt;
''Also note that the Protobuf source has moved to [http://www.github.com/google/protobuf link GitHub]. Some of the below links may be outdated.''&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
The following was tested on Windows 8.1 with Visual Studio 2013. Not all projects built after conversion, but only libprotobuf and dependencies were necessary.&lt;br /&gt;
&lt;br /&gt;
* Download protobuf-2.5.0.zip from https://code.google.com/p/protobuf/downloads/list&lt;br /&gt;
* Extract and navigate to protobuf-2.5.0/vsprojects/&lt;br /&gt;
* Open protobuf.sln in the version of Visual Studio corresponding with the VC abi version that you wish to compile for.&lt;br /&gt;
* Walk through project conversion steps if necessary.&lt;br /&gt;
* Right-click the libprotobuf project and choose properties.&lt;br /&gt;
* In Configuration Properties &amp;gt; C/C++ -&amp;gt; Code Generation, set Runtime Library to /MT for Release or /MTd for Debug.&lt;br /&gt;
* If building the Debug configuration, also add _ITERATOR_DEBUG_LEVEL=0 in Configuration Properties &amp;gt; C/C++ &amp;gt; Preprocessor &amp;gt; Preprocessor Defintions&lt;br /&gt;
* Right-click the libprotobuf project and choose Build.&lt;br /&gt;
&lt;br /&gt;
libprotobuf.lib will be in Release/ or Debug/, depending on build configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (32-bit host)==&lt;br /&gt;
The following was tested on Debian 6 (Lenny) 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure CXXFLAGS=&amp;quot;-g3 -ggdb3&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Linux (64-bit host)==&lt;br /&gt;
This hasn't been tested, but ''should'' work on most or all 64-bit distributions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=i686-pc-linux-gnu CFLAGS=&amp;quot;-m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Mac==&lt;br /&gt;
The following was tested on OS X 10.7 (Lion) and ensures that the outputted binaries are 32-bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz&lt;br /&gt;
tar -xvzf protobuf-2.5.0.tar.gz&lt;br /&gt;
cd protobuf-2.5.0&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-DNDEBUG -m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -DNDEBUG&amp;quot; LDFLAGS=-m32&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a debug build, replace &amp;lt;tt&amp;gt;./configure&amp;lt;/tt&amp;gt; with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./configure --build=x86-apple-darwin ABI=standard CFLAGS=&amp;quot;-m32&amp;quot; CXXFLAGS=&amp;quot;-m32 -g3 -ggdb3&amp;quot; LDFLAGS=-m32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will also override protobuf's default CXXFLAGS of &amp;lt;tt&amp;gt;-DNDEBUG&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The library will be in src/.libs/&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Releasing_Products&amp;diff=9748</id>
		<title>Releasing Products</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Releasing_Products&amp;diff=9748"/>
		<updated>2014-11-25T17:56:59Z</updated>

		<summary type="html">&lt;p&gt;Psychonic: /* Post-Build Work */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is an internal page for doing AlliedModders product releases.&lt;br /&gt;
&lt;br /&gt;
=Making Builds=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Once you are '''absolutely sure''' the product is ready for a release...&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Jump to a Linux system, check out the source tree.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Update the changelog (&amp;lt;tt&amp;gt;changelog.txt&amp;lt;/tt&amp;gt; for SourceMod, &amp;lt;tt&amp;gt;support/changelog.txt&amp;lt;/tt&amp;gt; for Metamod:Source).&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit the build_type file and change the &amp;quot;dev&amp;quot; string to &amp;quot;rel&amp;quot; (&amp;lt;tt&amp;gt;tools/buildbot/build_type&amp;lt;/tt&amp;gt; for SourceMod, &amp;lt;tt&amp;gt;support/buildbot/build_type&amp;lt;/tt&amp;gt; for Metamod:Source).&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit &amp;lt;tt&amp;gt;product.version&amp;lt;/tt&amp;gt; to remove the -dev tag.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Commit and push the changes.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Push.  Watch the waterfall page until builds are complete.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Post-Build Work=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Grab the binaries from the drop site ([http://metamodsource.net/mmsdrop/ MM:S drop site], [http://sourcemod.net/smdrop/ SourceMod drop site]).  It will be the latest package.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Install the packages on both Linux and Windows.  '''MAKE SURE THE VERSIONS ARE CORRECT.  THERE SHOULD BE NO -dev TAG.'''&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Metamod:Source checks:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
meta version&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
SourceMod checks:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sm plugins list&lt;br /&gt;
sm exts list&lt;br /&gt;
sm version&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;If the versions are not correct, do not release.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;For SourceMod, you need to add the language translation packs and update the GeoLite Country data file.  &lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
  '''If this is a major release (1.X.0), there is no prior pack.  Make one:'''&lt;br /&gt;
  &amp;lt;ol&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Extract both the tar.gz and zip files to separate folders.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Visit the [http://www.sourcemod.net/translator/?go=translate&amp;amp;op=status translator status page].&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Click &amp;quot;export languages.cfg&amp;quot; - save the new version to &amp;lt;tt&amp;gt;addons/sourcemod/configs/&amp;lt;/tt&amp;gt;, overwriting the old one.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Click &amp;quot;export&amp;quot; next to each language that is finished.  Extract the folder to &amp;lt;tt&amp;gt;addons/sourcemod/translations/&amp;lt;/tt&amp;gt;.  For example, if you extract Spanish, you should have &amp;lt;tt&amp;gt;addons/sourcemod/translations/es/&amp;lt;/tt&amp;gt; complete with ML files.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Download the latest GeoLite Country binary file from http://dev.maxmind.com/geoip/geolite&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Extract the GeoIP.dat and replace the existing copy in addons/sourcemod/configs/geoip&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Repackage the folders using the correct compression types (.tar.gz for Linux, .zip for Windows and Mac).&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;If this is a minor release (1.X.Y where Y != 0), there is already a prior pack.  Add it in:&amp;lt;/b&amp;gt;&lt;br /&gt;
  &amp;lt;ol&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Extract both the tar.gz and zip files to separate folders.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Download the last major release from the same branch as this release.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Copy the &amp;lt;tt&amp;gt;addons/sourcemod/configs/languages.cfg&amp;lt;/tt&amp;gt; file from the old release over the new one.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Copy the &amp;lt;tt&amp;gt;addons/sourcemod/translations/&amp;lt;/tt&amp;gt; sub-folders from the old release over to the new one.&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Download the latest GeoLite Country binary file from http://dev.maxmind.com/geoip/geolite&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Extract the GeoIP.dat and replace the existing copy in addons/sourcemod/configs/geoip&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Repackage the folders using the correct compression types (.tar.gz for Linux, .zip for Windows).&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;The build is done!&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Releasing to Mirrors=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Log into web01 as yourself.  Upload your final builds to your home directory.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/scripts/amjump mirror&lt;br /&gt;
cd /scripts/mirror&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Copy your final builds from your home directory into the mirror folder.  Rename them to release names, for example: &amp;lt;tt&amp;gt;sourcemod-1.1.2-windows.zip&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;mmsource-1.8.0-linux-tar.gz&amp;lt;/tt&amp;gt;.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Mirror distribution is done with the following command:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mirror.pl &amp;lt;projectID&amp;gt; &amp;lt;releaseName&amp;gt; &amp;lt;file&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Metamod:Source's ID is 4, SourceMod's ID is 2.  For example, these commands mirrored the Metamod:Source 1.8.7 release:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mirror.pl 4 1.8.7 mmsource-1.8.7-linux.tar.gz&lt;br /&gt;
./mirror.pl 4 1.8.7 mmsource-1.8.7-windows.zip&lt;br /&gt;
./mirror.pl 4 1.8.7 mmsource-1.8.7-mac.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These commands mirrored the SourceMod 1.4.0 release:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./mirror.pl 2 1.4.0 sourcemod-1.4.0-linux.tar.gz&lt;br /&gt;
./mirror.pl 2 1.4.0 sourcemod-1.4.0-windows.zip&lt;br /&gt;
./mirror.pl 2 1.4.0 sourcemod-1.4.0-mac.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Type &amp;lt;tt&amp;gt;exit&amp;lt;/tt&amp;gt; to get back to your user account.  You're done!&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Cleaning up the Tree=&lt;br /&gt;
It's time to make sure the tree is set for future development.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Run &amp;lt;tt&amp;gt;git tag&amp;lt;/tt&amp;gt; on the last revision of the release.  Usually this is the changeset that bumped versions, and usually this is the branch &amp;lt;tt&amp;gt;tip&amp;lt;/tt&amp;gt;. After you have tagged the changeset, push the tag upstream.  For example, Metamod:Source:&lt;br /&gt;
&amp;lt;pre&amp;gt;git tag -a mmsource-1.7.2 -m &amp;quot;Metamod:Source 1.7.2&amp;quot;&lt;br /&gt;
git push origin mmsource-1.7.2&amp;lt;/pre&amp;gt;&lt;br /&gt;
SourceMod:&lt;br /&gt;
&amp;lt;pre&amp;gt;git tag -a sourcemod-1.1.2 -m &amp;quot;SourceMod 1.1.2&amp;quot;&lt;br /&gt;
git push origin sourcemod-1.1.2&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Bump the minor version in &amp;lt;tt&amp;gt;product.version&amp;lt;/tt&amp;gt;. Don't forget to add -dev.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Change the &amp;lt;tt&amp;gt;tools/buildbot/build_type&amp;lt;/tt&amp;gt; (SourceMod) or &amp;lt;tt&amp;gt;support/buildbot/build_type&amp;lt;/tt&amp;gt; (Metamod:Source) contents back to &amp;quot;dev&amp;quot;.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Commit and push.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Updating the SourceMod Site=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Visit a [http://wiki.alliedmods.net/SourceMod_Release_Notes Release Notes] page.  Copy the contents, make a new one for your specific release.  Update the changelog, relnote anything big and important.  Link back to it from the &amp;quot;main&amp;quot; relnotes page.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Jump to the sourcemod account by logging into web01 as yourself:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/scripts/amjump sourcemod&lt;br /&gt;
cd /groups/sourcemod&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit the &amp;lt;tt&amp;gt;public_html/downloads.php&amp;lt;/tt&amp;gt; file with your favorite text editor.  Edit all instances of the old version with the new one.  Make sure to get every link, including relnotes.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Update ~/compiler-1.x to the latest minor version, where x is the major version number.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Run &amp;lt;tt&amp;gt;~/scripts/purge_old_builds.pl&amp;lt;/tt&amp;gt;, then edit its entry for 1.x.y, where x = this major release, and y = the new minor version.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Exit out of the sourcemod account.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;If a new major version, find someone with access to edit the forums if not yourself, and have the new compiler version added to editpost.php and newthread.php for the dropdown when editing plugin posts.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Find someone with access to the smdocs user if not yourself, and have the api docs updated by logging in as smdocs, navigating to ~/scripts/sync_api, replace the contents of the build directory with the new SM release, and run the run.sh script.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Post news.  If you deviate from normal style, don't forget links for downloads, upgrading, and relnotes.  It also helps to say &amp;quot;this is backwards compatible&amp;quot; because users will always ask.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Updating the Metamod:Source Site=&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Jump to the alliedmodders account by logging into web01 as yourself:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/scripts/amjump alliedmodders&lt;br /&gt;
cd /groups/alliedmodders/hub/amhub&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit the &amp;lt;tt&amp;gt;mmsource.py&amp;lt;/tt&amp;gt; file with your favorite text editor. Update the &amp;lt;tt&amp;gt;latest&amp;lt;/tt&amp;gt; version number in the &amp;lt;tt&amp;gt;downloads&amp;lt;/tt&amp;gt; function.  If this is a new major release (1.X.0), update the &amp;lt;tt&amp;gt;stable&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;devel&amp;lt;/tt&amp;gt; version numbers in the &amp;lt;tt&amp;gt;downloads&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;snapshots&amp;lt;/tt&amp;gt; functions.&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Edit the &amp;lt;tt&amp;gt;templates/mmsource/navbar.html&amp;lt;/tt&amp;gt; file and replace all instances of the old version with the new one.&lt;br /&gt;
 &amp;lt;li&amp;gt;Run the following command:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch ../run/apache.wsgi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Post news.  Do this by making a post in [https://forums.alliedmods.net/forumdisplay.php?f=124 this forum], which is private.  LOOK AT OLDER POSTS - you need to write valid XHTML!&amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Exit out of the alliedmodders account.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Updating Translations=&lt;br /&gt;
This section applies to SourceMod major releases. In order to update the translator tool, shell in as the &amp;quot;sourcemod&amp;quot; user. Find the /scripts/translation folder in the sourcemod group homedir. Run the following steps:&lt;br /&gt;
* cd sourcemod&lt;br /&gt;
* git pull&lt;br /&gt;
* cd ..&lt;br /&gt;
* ./sync_lang_files.pl sourcemod/translations&lt;br /&gt;
&lt;br /&gt;
Any languages with a non-green status will not be exported, so a few weeks before a release it is a good idea to post news asking for translators.&lt;/div&gt;</summary>
		<author><name>Psychonic</name></author>
		
	</entry>
</feed>