<?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=Belsebub</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=Belsebub"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/Belsebub"/>
	<updated>2026-05-25T21:58:54Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Base_Plugins_(SourceMod)&amp;diff=5796</id>
		<title>Base Plugins (SourceMod)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Base_Plugins_(SourceMod)&amp;diff=5796"/>
		<updated>2008-05-03T20:15:42Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: fixed broken link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__FORCETOC__&lt;br /&gt;
The following is a full list of [[SourceMod]]'s base plugins and the purpose of each one.&lt;br /&gt;
&lt;br /&gt;
Plugins with a bold name are safe to be used in [[War_Mode_(SourceMod)|War Mode]], as they do not contain anything that could be considered abusive or unfair.&lt;br /&gt;
&lt;br /&gt;
=Default Plugins=&lt;br /&gt;
{| style=&amp;quot;width:600px;&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
 |- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
 |Plugin&lt;br /&gt;
 |Purpose&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | '''admin-flatfile'''&lt;br /&gt;
 | Loads admins from the admin configuration files.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | '''adminhelp'''&lt;br /&gt;
 | Provides the sm_help command (lists other commands and their syntax).&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | '''adminmenu'''&lt;br /&gt;
 | Provides the admin menu API and core features.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | antiflood&lt;br /&gt;
 | Prevents clients from spamming messagemode/chat.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | '''basebans'''&lt;br /&gt;
 | Provides basic banning commands and menu options.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | basechat&lt;br /&gt;
 | Provides commands and menu options for managing player's abilities to use voice chat or say chat.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | basecomm&lt;br /&gt;
 | Provides functionality for tweaking how players can communicate (in comparison to sv_alltalk).&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | '''basecommands'''&lt;br /&gt;
 | Provides basic administrative commands unrelated to player abuse (for example, map changing, kicking, and cvar changing).&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | basetriggers&lt;br /&gt;
 | Provides automated responses to phrases such as &amp;quot;nextmap&amp;quot;, &amp;quot;thetime&amp;quot;, and &amp;quot;timeleft&amp;quot;.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | basevotes&lt;br /&gt;
 | Provides basic voting commands, such as map voting.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | funcommands&lt;br /&gt;
 | Provides &amp;quot;fun&amp;quot; commands, like slapping.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | funvotes&lt;br /&gt;
 | Provides votes based on basefuncommands.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | '''nextmap'''&lt;br /&gt;
 | Allows admins or other plugins to dynamically alter or retrieve the effective mapcycle.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | reservedslots&lt;br /&gt;
 | Allows the server to have slots that are reserved for administrators (or privileged people), to ensure prioritized entry.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=Extra Plugins=&lt;br /&gt;
The following plugins are in the &amp;lt;tt&amp;gt;addons/sourcemod/plugins/disabled&amp;lt;/tt&amp;gt; folder by default, and must be moved out of that folder to be enabled.&lt;br /&gt;
&lt;br /&gt;
If a plugin has cvars, you can load it once to generate its config file in &amp;lt;tt&amp;gt;cfg/sourcemod&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;width:600px;&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
 |- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
 |Plugin File&lt;br /&gt;
 |Purpose&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | '''admin-sql-prefetch'''&lt;br /&gt;
 | Loads admins from an SQL database as a big lump every mapchange.  If enabled, &amp;lt;tt&amp;gt;admin-sql-threaded&amp;lt;/tt&amp;gt; must be disabled; see [[SQL_Admins_(SourceMod)|SQL Admins]].&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | '''admin-sql-threaded'''&lt;br /&gt;
 | Loads admins from an SQL database dynamically as each admin connects.  If enabled, &amp;lt;tt&amp;gt;admin-sql-prefetch&amp;lt;/tt&amp;gt; must be disabled; see [[SQL_Admins_(SourceMod)|SQL Admins]].&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | mapchooser&lt;br /&gt;
 | Provides an automated system for players to vote for map changes.  If enabled, &amp;lt;tt&amp;gt;rockthevote&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;randomcycle&amp;lt;/tt&amp;gt; should be disabled.  Cvars are generated in &amp;lt;tt&amp;gt;plugin.mapchooser.cfg&amp;lt;/tt&amp;gt;.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | randomcycle&lt;br /&gt;
 | Randomizes the map cycle.  If enabled, &amp;lt;tt&amp;gt;mapchooser&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;rockthevote&amp;lt;/tt&amp;gt; should be disabled.  Cvars are generated in &amp;lt;tt&amp;gt;plugin.randomcycle.cfg&amp;lt;/tt&amp;gt;.&lt;br /&gt;
 |- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
 | rockthevote&lt;br /&gt;
 | Provides a player-initiated system for players to vote for map changes.  If enabled, &amp;lt;tt&amp;gt;mapchooser&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;randomcycle&amp;lt;/tt&amp;gt; should be disabled.  Cvars are generated in &amp;lt;tt&amp;gt;plugin.rtv.cfg&amp;lt;/tt&amp;gt;.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Documentation]]&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=AMX_Mod_X_1.75_Scripting_Changes&amp;diff=3077</id>
		<title>AMX Mod X 1.75 Scripting Changes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=AMX_Mod_X_1.75_Scripting_Changes&amp;diff=3077"/>
		<updated>2006-06-10T20:26:18Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The AMX Mod X 1.75 release made important changes.  While backwards compatibility was kept, intended functionality shifted in esoteric areas that will affect some plugins.  Reading this article is highly recommended.&lt;br /&gt;
&lt;br /&gt;
=Module Requirement System=&lt;br /&gt;
As part of the new Automatic Module Loading, the old &amp;lt;tt&amp;gt;#pragma library&amp;lt;/tt&amp;gt; has been deprecated.  You must now use:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#pragma reqlib &amp;lt;library&amp;gt;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This means &amp;quot;require library&amp;quot;.  Plugins still compiled with &amp;lt;tt&amp;gt;#pragma library&amp;lt;/tt&amp;gt; will still fail on load if the given module is not found.  However, core will try to load each module given the rules below under &amp;quot;Automatic Module Loading&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Auto Plugin Files=&lt;br /&gt;
With the introduction of callfunc and register_native, many people now distribute plugins in large sets.  To make this easier on users, you can now distribute an &amp;quot;extended plugin file.&amp;quot;  For example, say you have five plugins in a set.  Normally, you would have to ask the user to write each name into plugins.ini, like so:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 file1.amxx   ;file1&lt;br /&gt;
 file2.amxx   ;file2&lt;br /&gt;
 file3.amxx   ;file3&lt;br /&gt;
 file4.amxx   ;file4&lt;br /&gt;
 file5.amxx   ;file5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With AMX Mod X 1.75, any file in the configs folder which follows a certain name pattern will be auto-loaded as an additional plugins.ini file.  The pattern is: plugins-*.ini.  &lt;br /&gt;
&lt;br /&gt;
For example, you could distribute &amp;lt;tt&amp;gt;plugins-carmod.ini&amp;lt;/tt&amp;gt; as:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;put a semi-colon to disable a plugin&lt;br /&gt;
cars_honda.amxx  &lt;br /&gt;
cars_toyota.amxx&lt;br /&gt;
cars_ford.amxx&lt;br /&gt;
cars_bmw.amxx&lt;br /&gt;
cars_gaben.amxx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This way, you can easily distribute an extractable install, rather than giving the user overcomplicated instructions.  Furthermore, the file is easily disabled by simply modifying the name (for example, &amp;quot;disabled-carmod.ini&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Automatic Module Loading=&lt;br /&gt;
==Overview==&lt;br /&gt;
As of AMX Mod X 1.75, there is a new, powerful automatic module loading system.  That means that &amp;lt;tt&amp;gt;modules.ini&amp;lt;/tt&amp;gt; is largely deprecated for general use.  Instead, modules are loaded as plugins need them.  This is done dynamically by core before plugins are even loaded, without the need to patch &amp;lt;tt&amp;gt;modules.ini&amp;lt;/tt&amp;gt; and then change the map.&lt;br /&gt;
&lt;br /&gt;
Modules can now define &amp;quot;Libraries&amp;quot; and &amp;quot;Library Classes&amp;quot;.  A library is a specific identifier that should match the filename of the module.  For example, Engine's defined library is &amp;quot;engine&amp;quot;.  FakeMeta's library is &amp;quot;fakemeta&amp;quot;, and so on.&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;library class&amp;quot; defines membership to a set of modules.  For example, CSX has the library name &amp;quot;csx&amp;quot;, but it is part of the library class &amp;quot;xstats&amp;quot;.  Library classes are also used for DBI and SQLX.  This is very useful for being able to require one module type of any implementation.&lt;br /&gt;
&lt;br /&gt;
==New API==&lt;br /&gt;
===Compiler Pragmas===&lt;br /&gt;
This is expanded with a number of new &amp;lt;tt&amp;gt;#pragma&amp;lt;/tt&amp;gt; directives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma reqlib &amp;amp;lt;library&amp;gt;&amp;lt;/tt&amp;gt; - Requires that a given library must be loaded.&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma reqclass &amp;amp;lt;libclass&amp;gt;&amp;lt;/tt&amp;gt; - Requires that a given library class must be loaded.&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma loadlib &amp;amp;lt;library&amp;gt;&amp;lt;/tt&amp;gt; - Automatically attempts to load a given library (see more info below).&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma expectlib &amp;amp;lt;library1&amp;gt; &amp;amp;lt;library2&amp;gt;&amp;lt;/tt&amp;gt; - If the first library is not loaded, the second one will be attempted to load (not very useful).&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma expectclass &amp;amp;lt;class&amp;gt; &amp;amp;lt;library&amp;gt;&amp;lt;/tt&amp;gt; - If the expected class is not found, the given library will be attempted to load.  This is useful for defining a default module to be loaded with a given class of modules.&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma defclasslib &amp;amp;lt;class&amp;gt; &amp;amp;lt;library&amp;gt;&amp;lt;/tt&amp;gt; - Same as &amp;lt;tt&amp;gt;expectclass&amp;lt;/tt&amp;gt;, however, &amp;lt;tt&amp;gt;defclasslib&amp;lt;/tt&amp;gt; waits until all expectations are resolved.  This lets plugins override defaults by adding their own expectations.&lt;br /&gt;
&lt;br /&gt;
===Module Filtering===&lt;br /&gt;
The module_filter prototype now includes a second parameter, which tells you whether the requirement is a class or library.&lt;br /&gt;
&lt;br /&gt;
Furthermore, module_exists has been deprecated for LibraryExists().&lt;br /&gt;
&lt;br /&gt;
==How it Works==&lt;br /&gt;
The precise order of events is as follows:&lt;br /&gt;
*When the first entity is spawned, AMX Mod X loads all unloaded modules in &amp;lt;tt&amp;gt;modules.ini&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*After &amp;lt;tt&amp;gt;modules.ini&amp;lt;/tt&amp;gt; is parsed, &amp;lt;tt&amp;gt;plugins.ini&amp;lt;/tt&amp;gt; is read.  Each file is mapped into a cache.&lt;br /&gt;
*The cache is previewed.&lt;br /&gt;
**First, the &amp;quot;library&amp;quot; table is read.  This table is read for backwards compatibility with AMX Mod X 1.71 and prior.  Each entry is read as a module file shortname, and the module is loaded if it exists.  &lt;br /&gt;
**Next, the &amp;quot;pubtags&amp;quot; table is read.  Each entry is decoded to one of the special #pragma commands.&lt;br /&gt;
***All loadlib commands are executed, and the modules loaded.&lt;br /&gt;
***All expect commands are executed.&lt;br /&gt;
***All defclasslib commands are executed.&lt;br /&gt;
*AMX Mod X then waits until ServerActivate is called.&lt;br /&gt;
*All plugins are loaded.  If the plugin is in the cache, the cache is read instead.  For each plugin...&lt;br /&gt;
**The library table is read.  For each library that is both nonexistant and unhandled by a module filter, the plugin fails to load.&lt;br /&gt;
**The pubtags table is read.  For each reqlib and reqclass entry that are both nonexistant and unhandled by a module filter, the plugin fails to load.&lt;br /&gt;
*The plugin cache is invalidated and the server is considered &amp;quot;loaded&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=SQLX=&lt;br /&gt;
==Introduction==&lt;br /&gt;
SQLX is a new Database API that supercedes DBI.  Its main feature is that you can load two SQLX modules at once, whereas you cannot with DBI.  It also supports threaded queries, which let you process data without interrupting gameplay from a bad network connection.&lt;br /&gt;
&lt;br /&gt;
These additions come at a hefty price.  The SQLX API is significantly more complex than DBI.  Although some might find it easier to use due to its simpler error checking and iteration, it requires more manual memory management and has less simple abstraction.  Furthermore, taking advantage of the new &amp;lt;tt&amp;gt;SQL_ThreadQuery&amp;lt;/tt&amp;gt; native will require nothing short of a rewrite for most plugins, as it is ''asynchronous'' instead of ''synchronous''.  Because of this, the new SQLX modules also implement the old DBI functionality, for both backwards compatibility and for plugin developers familiar with the old API.  All three APIs - SQL-threaded, SQL-non-threaded, and DBI, are still fully supported.&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
Since SQLX is an expansive API, showing a single plugin of its usage would be difficult.  It is highly recommended that users interested in the new API look at the [http://cvs.tcwonline.org/viewvc.cgi/amxmodx/plugins/testsuite/sqlxtest.sma?view=log SQLxTest] plugin, which compares two different DBI methods and both SQL methods of querying a database.  It is highly useful for both regression testing and for getting an idea of how the API works.&lt;br /&gt;
&lt;br /&gt;
The most important concept of SQLX is &amp;quot;Handles,&amp;quot; which are a precursor to a system planned for SourceMod.  Handles are datatypes that store internal information that you should not modify.  Whenever you create a handle, you must also free it, with &amp;lt;tt&amp;gt;SQL_FreeHandle&amp;lt;/tt&amp;gt;().&lt;br /&gt;
&lt;br /&gt;
==Native Overview==&lt;br /&gt;
The basic natives of SQLX are:&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_MakeDbTuple&amp;lt;/tt&amp;gt; (or simple stock version, &amp;lt;tt&amp;gt;SQL_MakeStdTuple&amp;lt;/tt&amp;gt;) - This creates a variable that holds information about a database.  It does not connect to the database.  This is so you don't have to keep retrieving cvar info on every connection.  You do not have to free these handles, although it is a good idea if you create them dynamically.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_Connect&amp;lt;/tt&amp;gt; - Connects to a database and returns a new Handle, or &amp;lt;tt&amp;gt;Empty_Handle&amp;lt;/tt&amp;gt; on failure.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_PrepareQuery&amp;lt;/tt&amp;gt; - Prepares a query for execution, and returns a new Handle to the query.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_Execute&amp;lt;/tt&amp;gt; - Executes a prepared query, and returns 0 on failure (1 on success).&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_MoreResults&amp;lt;/tt&amp;gt; - Returns 1 if there are more results in the query result queue, 0 if none.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_ReadResult&amp;lt;/tt&amp;gt; - Reads the current row result by the column's numerical index, similar to dbi_field/dbi_result.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_NextRow&amp;lt;/tt&amp;gt; - Advances to the next result row.  '''Compatibility Warning''': This does not need to be called first! Unlike &amp;lt;tt&amp;gt;dbi_nextrow&amp;lt;/tt&amp;gt;, the query is automatically at the first row.  If you call &amp;lt;tt&amp;gt;SQL_NextRow&amp;lt;/tt&amp;gt; before &amp;lt;tt&amp;gt;SQL_ReadResult&amp;lt;/tt&amp;gt;, your are actually skipping a row.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_FreeHandle&amp;lt;/tt&amp;gt; - Frees a Handle.  You must do this or else memory will leak.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SQL_ThreadQuery&amp;lt;/tt&amp;gt; - Places a query and connection info into a threaded queue.  In another thread, the connection is established, the query is executed, and the connection is dropped.  The query results are then posted back into the main thread and given to the plugin on the next server-frame.  &lt;br /&gt;
**Note that while powerful, the mechanism is very simplistic.  Similar to &amp;lt;tt&amp;gt;set_task&amp;lt;/tt&amp;gt;, you must differentiate multiple queries having the same callback by packing binary data into an array.  Furthermore, you can only make one query at a time, since the queue is &amp;quot;push one, resolve one, pop one.&amp;quot;  If you plan on making five queries in a row in order to get aggregate information about a player, you must make each of these five queries in separate stages, and you must also take into account asynchronous factors such as the player dropping during the middle of a query.  (One way to do this is to pack the player's authid and client index into the callback data and verify it when the query finishes.)&lt;br /&gt;
&lt;br /&gt;
=New Natives / Native Changes=&lt;br /&gt;
==Register Message==&lt;br /&gt;
The &amp;lt;tt&amp;gt;register_message&amp;lt;/tt&amp;gt; set of natives, including &amp;lt;tt&amp;gt;get/set_msg_block&amp;lt;/tt&amp;gt;, has been moved to Core.  This is to facilitate users who prefer to use FakeMeta, and like the simplicity and speed of using Engine's message interception functions.  &lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
This change is backwards compatible.&lt;br /&gt;
&lt;br /&gt;
==Argument Formatting==&lt;br /&gt;
The &amp;lt;tt&amp;gt;format_args&amp;lt;/tt&amp;gt; function is now replaced with a much faster, more compatible &amp;lt;tt&amp;gt;vformat&amp;lt;/tt&amp;gt; function.  Its usage is slightly different (read the include file, &amp;lt;tt&amp;gt;string.inc&amp;lt;/tt&amp;gt;), but it accepts %L, whereas format_args does not.  A quick example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;debugprint(const fmt[], ...)&lt;br /&gt;
{&lt;br /&gt;
   static temp[2048]&lt;br /&gt;
   vformat(temp, sizeof(temp)-1, fmt, 2)&lt;br /&gt;
   log_message(&amp;quot;[DEBUG] %s&amp;quot;, temp)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Other Core Natives==&lt;br /&gt;
*&amp;lt;tt&amp;gt;register_plugin&amp;lt;/tt&amp;gt; - Now returns a plugin id.&lt;br /&gt;
*&amp;lt;tt&amp;gt;get_amxx_verstring&amp;lt;/tt&amp;gt; - Returns the AMX Mod X version string.&lt;br /&gt;
*&amp;lt;tt&amp;gt;get_weaponid&amp;lt;/tt&amp;gt; - Gets a weapon id from a weapon name.&lt;br /&gt;
&lt;br /&gt;
==FakeMeta==&lt;br /&gt;
===New Natives===&lt;br /&gt;
*&amp;lt;tt&amp;gt;get_orig_retval&amp;lt;/tt&amp;gt; - Gets the original return value of an engine or game DLL function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;copy_infokey_buffer&amp;lt;/tt&amp;gt; - Copies the given infobuffer pointer into output buffer.&lt;br /&gt;
*&amp;lt;tt&amp;gt;get/set_cd&amp;lt;/tt&amp;gt; - Gets or sets members of a clientdata data structure (used with UpdateClientData).&lt;br /&gt;
*&amp;lt;tt&amp;gt;get/set_es&amp;lt;/tt&amp;gt; - Gets or sets members of an entity_state data structure (used with AddToFullPack).&lt;br /&gt;
*&amp;lt;tt&amp;gt;get/set_uc&amp;lt;/tt&amp;gt; - Gets or sets members of a usecmd data structure (used with CmdStart).&lt;br /&gt;
&lt;br /&gt;
===New Engine/GameDLL Functions===&lt;br /&gt;
The &amp;lt;tt&amp;gt;register_forward&amp;lt;/tt&amp;gt; native now allows for hooking a number of new functions from the engine or game DLL including:&lt;br /&gt;
*&amp;lt;tt&amp;gt;UpdateClientData&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;AddToFullPack&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;CmdStart&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;CmdEnd&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;CreateInstBaselines&amp;lt;/tt&amp;gt; - Game DLL function&lt;br /&gt;
*&amp;lt;tt&amp;gt;CreateInstBaseline&amp;lt;/tt&amp;gt; - Engine function&lt;br /&gt;
*&amp;lt;tt&amp;gt;CreateBaseline&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;GetInfoKeyBuffer&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;AlertMessage&amp;lt;/tt&amp;gt; - This now can be called via &amp;lt;tt&amp;gt;engfunc&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;ClientPrintf&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These functions can also be called via &amp;lt;tt&amp;gt;engfunc&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;dllfunc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Breaking Changes===&lt;br /&gt;
Using &amp;lt;tt&amp;gt;engfunc&amp;lt;/tt&amp;gt; in order to call &amp;lt;tt&amp;gt;EngFunc_InfoKeyValue&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;EngFunc_SetKeyValue&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;EngFunc_SetClientKeyValue&amp;lt;/tt&amp;gt; now requires passing an infobuffer pointer. An infobuffer pointer can be obtained by calling &amp;lt;tt&amp;gt;EngFunc_GetInfoKeyBuffer&amp;lt;/tt&amp;gt;. For example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;some_function(id, name[])&lt;br /&gt;
{&lt;br /&gt;
   new infokey = engfunc(EngFunc_GetInfoKeyBuffer, id)&lt;br /&gt;
   engfunc(EngFunc_SetClientKeyValue, id, infokey, &amp;quot;model&amp;quot;, name)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you hook ClientUserInfoChanged via Fakemeta, an infobuffer pointer is now also forwarded to your function in addition to the client id.&lt;br /&gt;
&lt;br /&gt;
==Cstrike==&lt;br /&gt;
*&amp;lt;tt&amp;gt;cs_get_user_mapzones&amp;lt;/tt&amp;gt; - Returns bitwise flags of where on the map a player is located such as buy zone, bomb site, hostage rescue zone, VIP safety zone, and escape zone.&lt;br /&gt;
*&amp;lt;tt&amp;gt;cs_set_user_vip&amp;lt;/tt&amp;gt; - Now takes two additional (but optional) parameters for determining whether or not the player model and scoreboard get updated.&lt;br /&gt;
&lt;br /&gt;
==New Stocks==&lt;br /&gt;
===Engine===&lt;br /&gt;
*&amp;lt;tt&amp;gt;IsInWorld&amp;lt;/tt&amp;gt; - Checks if an entity is within the bounds of the world (from HLSDK).&lt;br /&gt;
&lt;br /&gt;
===FakeMeta===&lt;br /&gt;
*&amp;lt;tt&amp;gt;DF_UpdateClientData&amp;lt;/tt&amp;gt; - Calls UpdateClientData game DLL function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;DF_AddToFullPack&amp;lt;/tt&amp;gt; - Calls AddToFullPack game DLL function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;DF_CmdStart&amp;lt;/tt&amp;gt; - Calls CmdStart game DLL function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;DF_CmdEnd&amp;lt;/tt&amp;gt; - Calls CmdEnd game DLL function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;DF_CreateBaseline&amp;lt;/tt&amp;gt; - Calls CreateBaseline game DLL function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;DF_CreateInstBaselines&amp;lt;/tt&amp;gt; - Calls CreateInstancedBaselines game DLL function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;EF_CreateInstBaseline&amp;lt;/tt&amp;gt; - Calls CreateInstancedBaseline engine function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;EF_GetInfoKeyBuffer&amp;lt;/tt&amp;gt; - Calls GetInfoKeyBuffer engine function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;EF_ClientPrintf&amp;lt;/tt&amp;gt; - Calls ClientPrintf engine function.&lt;br /&gt;
&lt;br /&gt;
==New Constants==&lt;br /&gt;
Various sound constants (&amp;lt;tt&amp;gt;SND_SPAWNING&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;SND_STOP&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;SND_CHANGE_VOL&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;SND_CHANGE_PITCH&amp;lt;/tt&amp;gt;) from the HL SDK as well as a constant for pi were added to &amp;lt;tt&amp;gt;amxconst.inc&amp;lt;/tt&amp;gt;. &amp;lt;tt&amp;gt;TE_*&amp;lt;/tt&amp;gt; (temp entity) message constants have also been added which will automatically be included with &amp;lt;tt&amp;gt;#include &amp;lt;amxmodx&amp;gt;&amp;lt;/tt&amp;gt;. And finally, a new &amp;lt;tt&amp;gt;hlsdk_const.inc&amp;lt;/tt&amp;gt; file has been added that contains many more constants from the SDK. This is automatically included with &amp;lt;tt&amp;gt;#include &amp;lt;engine&amp;gt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;#include &amp;lt;fakemeta&amp;gt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Module API=&lt;br /&gt;
The AMX Mod X module API received a small overhaul for 1.75.&lt;br /&gt;
&lt;br /&gt;
==Versioning/Interface Additions==&lt;br /&gt;
The internal module interface version is 4.  However, modules from M/SDK 3 will still load.  &lt;br /&gt;
&lt;br /&gt;
M/SDK Version 4 modules have two new members of public information: the library string, and the library class string.  These contain comma delimited names of whatever libraries or library classes the module would like to be registered.&lt;br /&gt;
&lt;br /&gt;
For backwards compatibility, M/SDK Version 4 modules have an automatically empty library class string, and a library string equal to the logtag string.&lt;br /&gt;
&lt;br /&gt;
==New Callbacks==&lt;br /&gt;
Modules can now be informed of when plugins are about to be unloaded, and when plugins have been fully unloaded.  This means that modules don't have to hook ServerActivate and ServerActivate_Post (implementation dependent), don't need to be loaded by Metamod, and don't need to detach simply to release resources.&lt;br /&gt;
&lt;br /&gt;
==New Functions==&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_GetLocalInfo&amp;lt;/tt&amp;gt; - Intended for modules using LOCALINFO, which required a Metamod attachment.  This is equal to AMX Mod X's core function &amp;lt;tt&amp;gt;get_localinfo&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_OverrideNatives&amp;lt;/tt&amp;gt; - Given a native list, this specifies that any other module already providing these natives will no longer provide them.  This was added to force backwards compatibility between SQLITE and MySQLX.  Usage is not recommended.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_FindLibrary&amp;lt;/tt&amp;gt; - Essentially the same function as LibraryExists() for plugins.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_AddLibraries&amp;lt;/tt&amp;gt; - Adds a comma delimited list of libraries or library classes.  You must specify a &amp;quot;parent&amp;quot; pointer that identifies the module.  This is easily accomplished by taking the address of any static variable.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_RemoveLibraries&amp;lt;/tt&amp;gt; - Removes all library entries with the given parent pointer.  This is useful if your module adds custom entries not in its defined list.  &lt;br /&gt;
&lt;br /&gt;
==MSVC8 Compatibility==&lt;br /&gt;
M/SDK Version 4 now contains preprocessor definitions for compatibility with Microsoft's Visual Studio 2005/8.0 (provided by [[User:Damaged Soul|Damaged Soul]]).  These macros can be turned off in the &amp;lt;tt&amp;gt;moduleconfig.h&amp;lt;/tt&amp;gt; file by uncommenting the definition of &amp;lt;tt&amp;gt;NO_MSVC8_AUTO_COMPAT&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Minor Changes=&lt;br /&gt;
==Compiler Defines==&lt;br /&gt;
Since &amp;lt;tt&amp;gt;__DATE__&amp;lt;/tt&amp;gt; was fixed in 1.75, the macro &amp;lt;tt&amp;gt;__TIME__&amp;lt;/tt&amp;gt; was also added.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Full Changelog=&lt;br /&gt;
This changelog is tentative.  Developers will be editing it as things are changed.&lt;br /&gt;
&lt;br /&gt;
* Core Changes&lt;br /&gt;
** Modules are now automatically loaded by detecting plugin usage.&lt;br /&gt;
*** modules.ini is now primarily deprecated, except for SQL and unsupported libraries.&lt;br /&gt;
** Rewrote SQLX modules (again).  You can now load multiple SQL modules and toggle them per-plugin.&lt;br /&gt;
*** Added new SQL API called SQLX.  DBI was kept backwards-compatible.&lt;br /&gt;
*** Added new function to thread SQL queries (which prevents lag from a bad connection).&lt;br /&gt;
** Fixed some very small memory leaks.&lt;br /&gt;
** Fixed binary logging building wrong on Linux.&lt;br /&gt;
** Fixed some debugging crashes.&lt;br /&gt;
** Fixed serious bug when creating plugin_pause/plugin_unpause forwards.&lt;br /&gt;
** Fixed serious crash bug involving set_hudmessage and plugins using high hudchannels.&lt;br /&gt;
** Added natives:&lt;br /&gt;
*** fputs()&lt;br /&gt;
*** get_weaponid()&lt;br /&gt;
*** rename_file()&lt;br /&gt;
*** vformat()&lt;br /&gt;
** Any file starting with &amp;quot;plugins-&amp;quot; and ending in &amp;quot;.ini&amp;quot; will now be treated as an extended plugins file.  This is useful for distributing sets of plugins separately, and easily disabling them with a name change.&lt;br /&gt;
&lt;br /&gt;
* Fakemeta Changes&lt;br /&gt;
** Added new hookable/callable functions:&lt;br /&gt;
*** AddToFullPack&lt;br /&gt;
*** AlertMessage&lt;br /&gt;
*** ClientPrintf&lt;br /&gt;
*** ClientUserInfoChanged&lt;br /&gt;
*** CmdEnd&lt;br /&gt;
*** CmdStart&lt;br /&gt;
*** CreateBaseline&lt;br /&gt;
*** CreateInstancedBaseline&lt;br /&gt;
*** GetInfoKeyBuffer&lt;br /&gt;
*** InfoKeyValue&lt;br /&gt;
*** UpdateClientData&lt;br /&gt;
*** SetClientKeyValue&lt;br /&gt;
*** SetKeyValue&lt;br /&gt;
** Added new natives:&lt;br /&gt;
*** copy_infokey_buffer&lt;br /&gt;
*** get_orig_retval&lt;br /&gt;
** Fixed various trace bugs in FakeMeta with certain natives.&lt;br /&gt;
** Fixed some unhooking on server-deactivate problems in FakeMeta.&lt;br /&gt;
&lt;br /&gt;
* Scripting Changes:&lt;br /&gt;
** Added __DATE__ and __TIME__ auto-macros to the compiler.&lt;br /&gt;
** Added many HLSDK constants and improved include organization.&lt;br /&gt;
** Added new compiler #pragma directives for using the module autoloading system.&lt;br /&gt;
** Added cs_get_user_mapzones (thanks VEN!).&lt;br /&gt;
** Added IsInWorld() stock (thanks Twilight Suzuka!).&lt;br /&gt;
** Added nvault_remove().&lt;br /&gt;
** Moved various natives from Engine and into Core:&lt;br /&gt;
*** register_message&lt;br /&gt;
*** get_msg_args&lt;br /&gt;
*** get/set_msg_arg_type&lt;br /&gt;
*** get/set_msg_arg_int&lt;br /&gt;
*** get/set_msg_arg_float&lt;br /&gt;
*** get/set_msg_arg_string&lt;br /&gt;
*** get_msg_origin&lt;br /&gt;
*** get/set_msg_block&lt;br /&gt;
*** velocity_by_aim&lt;br /&gt;
*** vector_to_angle&lt;br /&gt;
*** angle_vector&lt;br /&gt;
*** vector_length&lt;br /&gt;
*** vector_distance&lt;br /&gt;
*** precache_generic&lt;br /&gt;
** Dynamic natives that are paused now also pause parent plugins (with an error).&lt;br /&gt;
** register_plugin() now returns the plugin ID.&lt;br /&gt;
** Fixed a corruption bug in strip_user_weapons().&lt;br /&gt;
** Fixed a bug in set_view() (thanks jtp10181!).&lt;br /&gt;
** Fixed is_in_viewcone() always returning 0.&lt;br /&gt;
** Fixed is_visible causing a crash, improved accuracy.&lt;br /&gt;
** Fixed a crash bug in get_tr2() (thanks Orangutanz!).&lt;br /&gt;
** Fixed cs_get_user_buyzone() returning existence in other areas.&lt;br /&gt;
** Fixed a rare floatround() bug where values ending strictly in .5 were IEEE rounded.&lt;br /&gt;
** Fixed a bug where removing the current parent task could damage the task queue.&lt;br /&gt;
** Fixed a bug in get_entity_visibility (thanks VEN!).&lt;br /&gt;
** Removed non-existant take_damage() entry.&lt;br /&gt;
** Expanded XS Stock Library with addition of xs_vec_make2d.&lt;br /&gt;
** Expanded usage of cs_set_user_vip().&lt;br /&gt;
** Improved get_brush_entity_origin() and ViewContents (thanks Orangutanz!).&lt;br /&gt;
&lt;br /&gt;
* Plugin Changes:&lt;br /&gt;
** Added amx_showrcon command to show rcon results in admincmd.sma.&lt;br /&gt;
** Added weapon restriction compatibility for bots in CS (KWo).&lt;br /&gt;
** Added admin identifier (asterisk which is red if colors are available) to all menus with a user list.&lt;br /&gt;
** Upgraded admin.sma to the new SQLX API.&lt;br /&gt;
** Fixed a bug in amx_reloadadmins not giving admins new access.&lt;br /&gt;
** Fixed a weapon restriction exploit in restmenu.sma.&lt;br /&gt;
** Fixed an HTML exploit in /top15 displaying player names.&lt;br /&gt;
** Fixed various and plentiful amx_addadmin bugs.&lt;br /&gt;
** Fixed telemenu.sma not letting you teleport yourself (thanks jtp10181!).&lt;br /&gt;
** Fixed a bug with adminslots.sma lowering the slots by 1.&lt;br /&gt;
** Fixed overlapping hud messages with miscstats.&lt;br /&gt;
&lt;br /&gt;
* Module API Changes:&lt;br /&gt;
** Added and fixed module API for inter-module communication.&lt;br /&gt;
** Added native overriding and replacing to module API.&lt;br /&gt;
** Added plugin unloading/unloaded callbacks to module API.&lt;br /&gt;
** Added MSVC8 project files to most CVS projects.&lt;br /&gt;
&lt;br /&gt;
* Configuration Changes:&lt;br /&gt;
** Added amx_sql_type cvar to sql.cfg.&lt;br /&gt;
** Re-organized and simplified modules.ini.&lt;br /&gt;
** Error logging can now be redirected to separate logs.&lt;br /&gt;
** Fixed modules.ini parsing bugs and simplified parsing.&lt;br /&gt;
** Fixed a double entry in cvars.ini.&lt;br /&gt;
&lt;br /&gt;
* Other Changes:&lt;br /&gt;
** Added a Bulgarian translation (thanks lubb!).&lt;br /&gt;
** Added a leetspeak translation (thanks, I think, Twilight Suzuka!).&lt;br /&gt;
** Improved FTP option of the graphical installer.&lt;br /&gt;
** Updated the GeoIP library to June.&lt;br /&gt;
** Updated PCRE from v6.1 to v6.4.&lt;br /&gt;
** Updated sqLite from 3.3.4 to 3.3.5.&lt;br /&gt;
** Fixed a steam account path bug in the installer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AMX Mod X]]&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Advanced_Scripting_(AMX_Mod_X)&amp;diff=2942</id>
		<title>Advanced Scripting (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Advanced_Scripting_(AMX_Mod_X)&amp;diff=2942"/>
		<updated>2006-05-20T15:24:21Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article will briefly summarize some of the more advanced topics of [[:Category:Scripting (AMX Mod X)|AMX Mod X Scripting]].&lt;br /&gt;
&lt;br /&gt;
=Tasks=&lt;br /&gt;
&lt;br /&gt;
Tasks are timers that let you run code at an interval, either once or repeated. They are useful for things like waiting a few seconds, setting objects to destroy themselves, or just repeating a task over and over.&lt;br /&gt;
&lt;br /&gt;
A task can be set in a number of different ways. The actual function is set_task():&lt;br /&gt;
&amp;lt;pawn&amp;gt;set_task(Float:time,const function[],id = 0,parameter[]=&amp;quot;&amp;quot;,len = 0,flags[]=&amp;quot;&amp;quot;, repeat = 0)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The parameters break down as such:&lt;br /&gt;
&lt;br /&gt;
* Float:time - Interval of timer in seconds (minimum 0.1 seconds)&lt;br /&gt;
* function[] - A string that contains the public function to run on the timer&lt;br /&gt;
* id - A unique id to assign to the task&lt;br /&gt;
* parameter - An array contain data to send to the timer function&lt;br /&gt;
* len - Size of the array to send to the timer function&lt;br /&gt;
* flags - One of the following:&lt;br /&gt;
** &amp;quot;a&amp;quot; - Repeat task a specified number of times&lt;br /&gt;
** &amp;quot;b&amp;quot; - Loop task infinitely&lt;br /&gt;
** &amp;quot;c&amp;quot; - do task on time after a map timeleft&lt;br /&gt;
** &amp;quot;d&amp;quot; - do task on time before a map timeleft&lt;br /&gt;
* repeat - If flags is &amp;quot;a&amp;quot;, specifies the number of times to repeat the task&lt;br /&gt;
&lt;br /&gt;
An example of a task is below. It will slap a specified player 5 times, once per second.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;//the timed function receives the parameter array and its task id&lt;br /&gt;
public slapTask(params[], id)&lt;br /&gt;
{&lt;br /&gt;
   new player = params[0]&lt;br /&gt;
   user_slap(player, 5)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public start_slapping(id)&lt;br /&gt;
{&lt;br /&gt;
   new params[1]&lt;br /&gt;
   params[0] = id&lt;br /&gt;
   //we don't need a specific id&lt;br /&gt;
   set_task(1.0, &amp;quot;slapTask&amp;quot;, 0, params, 1, &amp;quot;a&amp;quot;, 5)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that if you specify 0 for parameter length, then the task function should look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public slapTask(id)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Menus=&lt;br /&gt;
&lt;br /&gt;
Menus are HUD messages that give a player a choice of options to select. They are quite messy to deal with but can be very useful for things like voting and command selection.&lt;br /&gt;
&lt;br /&gt;
Menus must be registered by two things - a set of &amp;quot;keys&amp;quot; that tells how many options to register and a string which identifies the menu as unique. This string must appear in the beginning of every menu you want to trigger your function. When you display a menu, you can show it to one or more players. Once they hit a key, the result of their key press will be sent to the function you registered the menu to.&lt;br /&gt;
&lt;br /&gt;
For our example, we'll make a menu that displays a list of guns: AK47, M4A1, or AWP, to a player. Whichever he selects, he will be given.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmisc&amp;gt;&lt;br /&gt;
#include &amp;lt;fun&amp;gt;&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    register_plugin(&amp;quot;Menu Demo&amp;quot;, &amp;quot;1.0&amp;quot;, &amp;quot;BAILOPAN&amp;quot;)&lt;br /&gt;
    new keys = MENU_KEY_0|MENU_KEY_1|MENU_KEY_2&lt;br /&gt;
    register_menucmd(register_menuid(&amp;quot;Which Weapon?&amp;quot;), keys, &amp;quot;giveWeapon&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Two commands are apparent here - register_menuid and register_menucmd. register_menuid registers a short phrase that will appear at the beginning of the menu, then returns an id. This id is the first parameter to register_menucmd. The second parameter to register_menucmd is the key configuration. Our menu will have three options, so we've added three menu keys in. In actuality, these are bitwise flags totalling &amp;quot;7&amp;quot;, but that's not important. The last parameter is the public function that will handle the menu results.&lt;br /&gt;
&lt;br /&gt;
Next, how do we show the menu? Let's make a quick console command: &amp;quot;giveme&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    register_plugin(&amp;quot;Menu Demo&amp;quot;, &amp;quot;1.0&amp;quot;, &amp;quot;BAILOPAN&amp;quot;)&lt;br /&gt;
    new keys = MENU_KEY_0|MENU_KEY_1|MENU_KEY_2&lt;br /&gt;
    register_menucmd(register_menuid(&amp;quot;Which Weapon?&amp;quot;), keys, &amp;quot;giveWeapon&amp;quot;)&lt;br /&gt;
    register_clcmd(&amp;quot;giveme&amp;quot;, &amp;quot;showWeaponMenu&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
register_clcmd is similar to register_concmd, except it only takes two parameters. It's used to register any command a client can use (except for special ones, like +attack).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;//The clcmd function will just give us the player id&lt;br /&gt;
public showWeaponMenu(id)&lt;br /&gt;
{&lt;br /&gt;
    new menu[192]&lt;br /&gt;
    new keys = MENU_KEY_0|MENU_KEY_1|MENU_KEY_2&lt;br /&gt;
&lt;br /&gt;
    format(menu, 191, &amp;quot;Which Weapon?^n^n1. AK47^n2. M4A1^n3. AWP&amp;quot;)&lt;br /&gt;
    show_menu(id, keys, menu)&lt;br /&gt;
    return PLUGIN_HANDLED&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//Our menu function will get the player id and the key they pressed&lt;br /&gt;
public giveWeapon(id, key)&lt;br /&gt;
{&lt;br /&gt;
    //key will start at zero&lt;br /&gt;
    if (key == 0)&lt;br /&gt;
    {&lt;br /&gt;
         give_item(id, &amp;quot;weapon_ak47&amp;quot;)&lt;br /&gt;
    } else if (key == 1) {&lt;br /&gt;
         give_item(id, &amp;quot;weapon_m4a1&amp;quot;)&lt;br /&gt;
    } else if (key == 2) {&lt;br /&gt;
         give_item(id, &amp;quot;weapon_awp&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we're done! The format line may be a little confusing. The &amp;quot;^n&amp;quot; means &amp;quot;new line&amp;quot;, so the menu looks nicely formatted. You can use other modifiers in VGUI2 mods, such as &amp;quot;\w&amp;quot; for white text, &amp;quot;\r&amp;quot; for red text, and &amp;quot;\y&amp;quot; for yellow text. When a player types the command, he will see the menu. When he hits a key, the giveWeapon function will receive his id and the key number he pressed. Then he will get a gun corresponding to what he chose.&lt;br /&gt;
&lt;br /&gt;
=Events/Messages=&lt;br /&gt;
&lt;br /&gt;
For this demonstration, we're going to extend the above example. Every time a player respawns, he will be shown the menu to choose a weapon (note - we're ignoring other things like blocking buying and removing buyzones, this is just a demonstration).&lt;br /&gt;
&lt;br /&gt;
Messages are a way for Half-Life clients to talk to servers, and vice versa. They are specially formatted lists of parameters. For example, the message &amp;quot;DeathMsg&amp;quot; (message id 83) has three parameters: Attacker (byte), Victim (byte), and Weapon (string). You can either capture messages or send them. Here, we'll do a simple demonstration of both. First let's make it so a user gets their gun menu when they spawn.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    register_plugin(&amp;quot;Menu Demo&amp;quot;, &amp;quot;1.0&amp;quot;, &amp;quot;BAILOPAN&amp;quot;)&lt;br /&gt;
    new keys = MENU_KEY_0|MENU_KEY_1|MENU_KEY_2&lt;br /&gt;
    register_menucmd(register_menuid(&amp;quot;Which Weapon?&amp;quot;), keys, &amp;quot;giveWeapon&amp;quot;)&lt;br /&gt;
    //flags - b means &amp;quot;sent to one target&amp;quot;, e means &amp;quot;target is alive&amp;quot;&lt;br /&gt;
    //this event is sent when a player spawns&lt;br /&gt;
    register_event(&amp;quot;ResetHUD&amp;quot;, &amp;quot;hook_hud&amp;quot;, &amp;quot;be&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public hook_hud(id)&lt;br /&gt;
{&lt;br /&gt;
    //since we specify no parameters to the task,&lt;br /&gt;
    //the task id will be given to the function&lt;br /&gt;
    //this is useful because we can reuse our old&lt;br /&gt;
    //show menu function which takes an id&lt;br /&gt;
    set_task(0.2, &amp;quot;showWeaponMenu&amp;quot;, id)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we've set a small delay when we receive the message - this is to make sure that the user has had time to respawn. register_event can take more parameters in order to help restrict the event you catch - for example only matching certain parameters. You can read more about this in the function reference.&lt;br /&gt;
&lt;br /&gt;
Now, let's say we want to figure out when a player has died...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    register_plugin(&amp;quot;Message Demo&amp;quot;, &amp;quot;1.0&amp;quot;, &amp;quot;BAILOPAN&amp;quot;)&lt;br /&gt;
    //this message informs everyone of a death, so we use&lt;br /&gt;
    // flag &amp;quot;a&amp;quot; - global event&lt;br /&gt;
    register_event(&amp;quot;DeathMsg&amp;quot;, &amp;quot;hook_death&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public hook_death()&lt;br /&gt;
{&lt;br /&gt;
    new Killer = read_data(1) //get the first message parameter&lt;br /&gt;
    new Victim = read_data(2) //get the second message parameter&lt;br /&gt;
    new headshot = read_data(3) //was this a headshot?&lt;br /&gt;
    new weapon[32]&lt;br /&gt;
    read_data(4, weapon, 31)  //get the weapon name&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, let's say we want to make a simple function for generating a death message:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;stock make_deathMsg(Killer, Victim, const weapon[])&lt;br /&gt;
{&lt;br /&gt;
    //message_begin starts a message.  NEVER start two messages at once.&lt;br /&gt;
    //MSG_ALL means send the message to everyone&lt;br /&gt;
    //get_user_msgid returns the id of a message name&lt;br /&gt;
    //{0,0,0} is the origin vector - not used here&lt;br /&gt;
    //0 is the target - no specific target here&lt;br /&gt;
    message_begin(MSG_ALL, get_user_msgid(&amp;quot;DeathMsg&amp;quot;), {0,0,0}, 0) &lt;br /&gt;
    write_byte(Killer)&lt;br /&gt;
    write_byte(Victim)&lt;br /&gt;
    write_string(weapon)&lt;br /&gt;
    message_end()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To find more about messages, consult the HLSDK, AMX Mod X forums, HL-related programming sites, or other plugins. To list the messages a mod has, type &amp;quot;meta game&amp;quot; in the server console (with metamod loaded). You can also use register_message, the more advanced message disection method found in the Engine module.&lt;br /&gt;
&lt;br /&gt;
=Catching Log Messages=&lt;br /&gt;
&lt;br /&gt;
Catching log messages is not used heavily any more, but it's still good to know how to do it. As log messages are sent by the mod, AMX Mod X will be able to catch them and let you hook them. For our example, let's give everyone $16,000 on round start.&lt;br /&gt;
&lt;br /&gt;
The log messages for rounds are sent like this: World triggered &amp;quot;Round_Start&amp;quot;. AMX Mod X will consider &amp;quot;World_triggered&amp;quot; as the first parameter and &amp;quot;Round_Start&amp;quot; as the second parameter. So:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;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;Log Demo&amp;quot;, &amp;quot;1.0&amp;quot;, &amp;quot;BAILOPAN&amp;quot;)&lt;br /&gt;
    //this will filter for two parameters&lt;br /&gt;
    //roundstart is the public function&lt;br /&gt;
    register_logevent(&amp;quot;roundstart&amp;quot;, 2, &amp;quot;0=World triggered&amp;quot;, &amp;quot;1=Round_Start&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public roundstart()&lt;br /&gt;
{&lt;br /&gt;
    //set a small delay to make sure everyone spawns&lt;br /&gt;
    set_task(1.0, &amp;quot;roundDelay&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public roundDelay(taskId)&lt;br /&gt;
{&lt;br /&gt;
    new players[32], num&lt;br /&gt;
    get_players(players, num)&lt;br /&gt;
    new i&lt;br /&gt;
    for (i=0; i&amp;lt;num; i++)&lt;br /&gt;
    {&lt;br /&gt;
         cs_set_user_money(players[i], 16000)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also read specific log parameters with read_logdata(), which can only be used inside the &amp;quot;plugin_log()&amp;quot; forward:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;//receives all log messages&lt;br /&gt;
public plugin_log()&lt;br /&gt;
{&lt;br /&gt;
    new data[32]&lt;br /&gt;
    read_logdata(data, 31)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Multi-Lingual Support=&lt;br /&gt;
&lt;br /&gt;
Adding multi-lingual support to a plugin can be difficult, but it's usually worth it if you have clients who are willing to translate your strings into their native language.&lt;br /&gt;
&lt;br /&gt;
The first step is to identify what needs to be translated. Say you have a call like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;new score = get_score()&lt;br /&gt;
client_print(id, print_chat, &amp;quot;[AMXX] Your score is %d&amp;quot;, score)&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a good candidate for being multi-lingual. First, create a .txt file (preferrably named after your plugin) and store it in addons\amxmodx\data\lang\. Let's use &amp;quot;myplugin.txt&amp;quot; for the example. For each language, add an entry to the file. Entries are set up as 'keys', which are matched to 'translation strings'. Observe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;(addons\amxmodx\data\lang\myplugin.txt)&lt;br /&gt;
&lt;br /&gt;
[en]&lt;br /&gt;
SCORE_MSG = Your score is %d&lt;br /&gt;
&lt;br /&gt;
[de]&lt;br /&gt;
SCORE_MSG = Ihr Spielergebnis ist %d&lt;br /&gt;
&lt;br /&gt;
[es]&lt;br /&gt;
SCORE_MSG = Su cuenta es %d&lt;br /&gt;
&lt;br /&gt;
[fr]&lt;br /&gt;
SCORE_MSG = Votre score est %d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, in plugin_init(), you must register the language keys:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    ...&lt;br /&gt;
    //assumes placed in amxmodx\data\lang&lt;br /&gt;
    register_dictionary(&amp;quot;myplugin.txt&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, here comes the hard part. AMX Mod X's Multi-Lingual API is built into the format() style routines. For anything that looks like or uses format()-style strings, you can use the ML API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;    client_print(id, print_chat, &amp;quot;[AMXX] %L&amp;quot;, id, &amp;quot;SCORE_MSG&amp;quot;, get_score())&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's break this down. For each %L that appears, we need at least two parameters. The first parameter is the TARGET. This must be a player id, LANG_SERVER (meaning show in the server's native language), or LANG_PLAYER. LANG_PLAYER is a special modifier that should only be used when sending a message to all players - it means &amp;quot;show in every player's native language&amp;quot;. The second parameter is the key string that identifies the language phrase to translate. Lastly, if the translated string requires any parameters itself (ours needs %d, one integer), that must be added as well.&lt;br /&gt;
&lt;br /&gt;
You can get very complicated designs with this, but it's recommended that you keep things simple for clarity. Here is a final example using a global message to all players, assuming the key HELLO is properly translated in all the languages available:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;    client_print(0, print_chat, &amp;quot;[AMXX] %L&amp;quot;, LANG_PLAYER, &amp;quot;HELLO&amp;quot;)&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=SQL Support=&lt;br /&gt;
&lt;br /&gt;
SQL support has greatly improved in AMX Mod X. There is a common set of natives that work with a single driver, so as long as one (and only one) SQL module is loaded, the SQL (or DBI) natives will work. Here is a short primer on how to use the DBI natives:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;//Create a connection&lt;br /&gt;
	new Sql:mysql = dbi_connect(&amp;quot;localhost&amp;quot;, &amp;quot;dvander&amp;quot;, &amp;quot;pass&amp;quot;, &amp;quot;dbase&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
//If the connection is less than 1, it is bad	&lt;br /&gt;
	if (mysql &amp;lt; SQL_OK) {&lt;br /&gt;
		new err[255]&lt;br /&gt;
		new errNum = dbi_error(mysql, err, 254)&lt;br /&gt;
		server_print(&amp;quot;error1: %s|%d&amp;quot;, err, errNum)&lt;br /&gt;
		return 1&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	server_print(&amp;quot;Connection handle: %d&amp;quot;, mysql)&lt;br /&gt;
//Run a query&lt;br /&gt;
	new Result:ret = dbi_query(mysql, &amp;quot;INSERT INTO config (keyname, val) VALUES ('amx', 'yes')&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
//If the query is less than 0, it failed	&lt;br /&gt;
	if (ret &amp;lt; RESULT_NONE) {&lt;br /&gt;
		new err[255]&lt;br /&gt;
		new errNum = dbi_error(mysql, err, 254)&lt;br /&gt;
		server_print(&amp;quot;error2: %s|%d&amp;quot;, err, errNum)&lt;br /&gt;
		return 1&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
//Do a select query	&lt;br /&gt;
	new Result:res = dbi_query(mysql, &amp;quot;SELECT * FROM config&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
//If the query is greater than 0, you got a handle to the result set	&lt;br /&gt;
	if (res &amp;lt;= RESULT_NONE) {&lt;br /&gt;
		new err[255]&lt;br /&gt;
		new errNum = dbi_error(mysql, err, 254)&lt;br /&gt;
		server_print(&amp;quot;error3: %s|%d&amp;quot;, err, errNum)&lt;br /&gt;
		return 1&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	server_print(&amp;quot;Result handle: %d&amp;quot;, res)&lt;br /&gt;
&lt;br /&gt;
//Loop through the result set	&lt;br /&gt;
	while (res &amp;amp;&amp;amp; dbi_nextrow(res)&amp;gt;0) {&lt;br /&gt;
		new qry[32]&lt;br /&gt;
//Get the column/field called &amp;quot;keyname&amp;quot; from the result set&lt;br /&gt;
		dbi_result(res, &amp;quot;keyname&amp;quot;, qry, 32)&lt;br /&gt;
		server_print(&amp;quot;result: %s&amp;quot;, qry)&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
//Free the result set	&lt;br /&gt;
	dbi_free_result(res)&lt;br /&gt;
&lt;br /&gt;
//Close the connection	&lt;br /&gt;
	ret = dbi_close(mysql)&lt;br /&gt;
	if (ret &amp;lt;= RESULT_NONE) {&lt;br /&gt;
		new err[255]&lt;br /&gt;
		new errNum = dbi_error(mysql, err, 254)&lt;br /&gt;
		server_print(&amp;quot;error4: %s|%d&amp;quot;, err, errNum)&lt;br /&gt;
		return 1&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Regular Expressions=&lt;br /&gt;
&lt;br /&gt;
Regular Expressions let you describe ways in which to break down strings. They are extremely powerful. AMX Mod X uses the Perl Compatible RE library, you can read the specifics at their site. AMX Mod X offers regular expressions with the regex_amxx module. Here is a short example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;regex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    register_plugin(&amp;quot;Regex&amp;quot;, &amp;quot;1.0&amp;quot;, &amp;quot;BAILOPAN&amp;quot;)&lt;br /&gt;
    register_srvcmd(&amp;quot;amx_regex&amp;quot;, &amp;quot;cmdtest&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public cmdtest()&lt;br /&gt;
{&lt;br /&gt;
    new str[] = &amp;quot;It's Walky!&amp;quot;&lt;br /&gt;
    //this pattern will match any string which contains&lt;br /&gt;
    // two groupings of characters separated by a space&lt;br /&gt;
    // the two groupings are substrings 1 and 2&lt;br /&gt;
    new pattern[] = &amp;quot;(.+) (.+)&amp;quot;&lt;br /&gt;
    &lt;br /&gt;
    new num, error[128]&lt;br /&gt;
    //str = string&lt;br /&gt;
    //pattern = pattern to use&lt;br /&gt;
    //num = special return case code&lt;br /&gt;
    //error = if there's an error, it will go here&lt;br /&gt;
    //127 - error's max length&lt;br /&gt;
    new Regex:re = regex_match(str, pattern, num, error, 127)&lt;br /&gt;
&lt;br /&gt;
    server_print(&amp;quot;Result=%d, num=%d, error=%s&amp;quot;, re, num, error)    &lt;br /&gt;
&lt;br /&gt;
    //REGEX_OK means there was a match&lt;br /&gt;
    if (re &amp;gt;= REGEX_OK)&lt;br /&gt;
    {&lt;br /&gt;
        new str2[64]&lt;br /&gt;
        new i&lt;br /&gt;
        //since it returned REGEX_OK, num has&lt;br /&gt;
        // the number of substrings matched by the pattern.&lt;br /&gt;
        //the first substring (0) seems to match the whole string.&lt;br /&gt;
        for (i=0; i&amp;lt;num; i++)&lt;br /&gt;
        {&lt;br /&gt;
            regex_substr(re, i, str2, 63)&lt;br /&gt;
            server_print(&amp;quot;Substring %d: %s&amp;quot;, i, str2)&lt;br /&gt;
        }&lt;br /&gt;
        //the regular expression matcher uses memory.&lt;br /&gt;
        //you must free it if you get REGEX_OK&lt;br /&gt;
        //This will also set re to 0.&lt;br /&gt;
        regex_free(re)&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //note the invalid regular expression pattern&lt;br /&gt;
    //this will return REGEX_PATTERN_FAIL, -1&lt;br /&gt;
    re = regex_match(&amp;quot;Bruno the Bandit&amp;quot;, &amp;quot;.+(]&amp;quot;, num, error, 127)&lt;br /&gt;
    &lt;br /&gt;
    server_print(&amp;quot;Result=%d, num=%d, error=%s&amp;quot;, re, num, error)&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you compile and run this script (amx_regex in server console) you will see the following output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Result=1, num=3, error=&lt;br /&gt;
Substring 0: It's Walky!&lt;br /&gt;
Substring 1: It's&lt;br /&gt;
Substring 2: Walky!&lt;br /&gt;
Result=-1, num=4, error=missing ) &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the third parameter to &amp;quot;regex_match()&amp;quot; is special. It's either the number of substrings, a match error code, or a pattern error position (depending on the return value).&lt;br /&gt;
&lt;br /&gt;
=Entities=&lt;br /&gt;
&lt;br /&gt;
Entities are basically any dynamic structure in Half-Life. Players, weapons, grenades, and other little objects laying around are entities. They have a unique &amp;quot;entity id&amp;quot; which you can use to change their values.&lt;br /&gt;
&lt;br /&gt;
I won't go into this too deeply as it's a complicated subject, but the Engine module features natives that let you modify the properties of entities, or search for entities in game by their class/owner (class is the type of entity, such as &amp;quot;player&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
For this example, we'll make an entity that looks like a fake player holding a gun.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;	//create a basic entity&lt;br /&gt;
	entid = create_entity(&amp;quot;info_target&amp;quot;)&lt;br /&gt;
	//set its classname&lt;br /&gt;
	entity_set_string(entid, EV_SZ_classname, &amp;quot;some_guy&amp;quot;)&lt;br /&gt;
	//set its model&lt;br /&gt;
	entity_set_model(entid, &amp;quot;models/w_suit.mdl&amp;quot;)&lt;br /&gt;
	new Float:Vec[3] = {0.0,0.0,0.0}&lt;br /&gt;
	//set its origin &lt;br /&gt;
	entity_set_origin(entid, Vec)&lt;br /&gt;
	//set some basic properties&lt;br /&gt;
	entity_set_int(entid, EV_INT_solid, 1)&lt;br /&gt;
	entity_set_int(entid, EV_INT_movetype, 6)&lt;br /&gt;
	//create the weapon - thanks to pimp_daddy!&lt;br /&gt;
	entWeapon = create_entity(&amp;quot;info_target&amp;quot;)&lt;br /&gt;
	entity_set_string(entWeapon, EV_SZ_classname, weapString)&lt;br /&gt;
	//set to follow&lt;br /&gt;
	entity_set_int(entWeapon, EV_INT_movetype, MOVETYPE_FOLLOW)&lt;br /&gt;
	entity_set_int(entWeapon, EV_INT_solid, SOLID_NOT)&lt;br /&gt;
	entity_set_edict(entWeapon, EV_ENT_aiment, entid)&lt;br /&gt;
	entity_set_model(entWeapon, &amp;quot;models/p_m4a1.mdl&amp;quot;) &lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also change other basic things, such as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;//how set_user_armor() works in the fun module&lt;br /&gt;
stock set_armor(player, Float:value)&lt;br /&gt;
{&lt;br /&gt;
    entity_set_int(player, EV_FL_armorvalue, value)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=FakeMeta=&lt;br /&gt;
&lt;br /&gt;
FakeMeta is the next generation of Half-Life scripting. It essentially lets you write MetaMod plugins in Pawn. It is extremely powerful, and for this reason, it won't really be covered here. This is just to tell you what it is capable of.&lt;br /&gt;
&lt;br /&gt;
* Engine/DLL Calls&lt;br /&gt;
**There are two types of functions in the HL namespace - Engine functions and DLL functions (DLL functions are ones the game/mod library must export). Both of these can be called using the FakeMeta module using the dllfunc() and engfunc() natives. The parameters are directly passed on to MetaMod, so be careful! You could easily crash a server doing the wrong thing.&lt;br /&gt;
* Engine/DLL Hooks&lt;br /&gt;
**As stated above, HL provides Engine and DLL functions. You can also hook/supercede these calls using register_forward. You can supercede these calls using fm_return() and return PLUGIN_HANDLED. Again, make sure you know what you are doing. Malformed hooks will cause crashes.&lt;br /&gt;
* Easy entity manipulation&lt;br /&gt;
**FakeMeta replaces Engine's entity__() function with a natives called &amp;quot;pev()&amp;quot; and &amp;quot;set_pev()&amp;quot;. They are a bit easier to use. For more information see the fakemeta includes.&lt;br /&gt;
* Private Offset Hacking&lt;br /&gt;
**Private offsets are offsets into a block of memory called &amp;quot;pvPrivateData&amp;quot;. The right offsets can often modify game-specific features, such as money in Counter-Strike, or resources in Natural-Selection. However, the wrong offsets can cause game crashes.&lt;br /&gt;
&lt;br /&gt;
[[Category:Scripting (AMX Mod X)]]&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Sample_Plugins_(Metamod:Source)&amp;diff=2933</id>
		<title>Sample Plugins (Metamod:Source)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Sample_Plugins_(Metamod:Source)&amp;diff=2933"/>
		<updated>2006-05-16T06:01:52Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: Reverted edit of Venusparkle85&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This guide briefly explains about and how to compile the sample plugins for SourceMM.&lt;br /&gt;
&lt;br /&gt;
=Sample Plugins=&lt;br /&gt;
==stub_mm==&lt;br /&gt;
This plugin is a bare-minimum example of what you need to build a [[SourceMM]] plugin. It implements the ISmmPlugin class, exposes it as a DLL, and nothing more. As a single example, it also hooks ServerActivate in IServerGameDLL. &amp;quot;Stub&amp;quot; was designed such that a developer could open it and quickly modify it to begin a plugin.&lt;br /&gt;
&lt;br /&gt;
*meta_hooks.h - Definition of main hooks&lt;br /&gt;
*stub_mm.cpp - Main plugin file and implementation&lt;br /&gt;
*stub_mm.h - Main plugin header&lt;br /&gt;
&lt;br /&gt;
==sample_mm==&lt;br /&gt;
This plugin attempts to recreate all of the functionality a Server Plugin has. Server Plugins receive twelve callbacks, three of which are GameDLL overridable. In order to replicate this functionality, sample_mm hooks eleven of the callbacks as either post or pre handlers. Furthermore, it also demonstrates how to build a CallClass for calling original functions. Every hook produces a log message so you can see when events occur.&lt;br /&gt;
&lt;br /&gt;
Sample_mm fully replicates every callback a Server Plugin is capable of receiving, except for NetworkIDValidated. This callback has no known representation in the engine, is not very useful, and can be replicated easily with GameFrame() (in the future, we might demonstrate this). If you are having trouble porting a Server Plugin over, or are wondering how you can keep the same features, this plugin will show you where to start.&lt;br /&gt;
&lt;br /&gt;
*meta_hooks.h - Definition of main hooks&lt;br /&gt;
*SamplePlugin.cpp - Main plugin file and implementation&lt;br /&gt;
*SamplePLugin.h - Main plugin header&lt;br /&gt;
&lt;br /&gt;
=Where to Get=&lt;br /&gt;
You can find the source code to the sample plugins in either the source code package or [http://www.tcwonline.org/cgi-bin/viewcvs.cgi/sourcemm/ CVS]. They are located in the main source code folder in &amp;quot;stub_mm&amp;quot; and &amp;quot;sample_mm&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Compiling=&lt;br /&gt;
==Windows==&lt;br /&gt;
These plugins have been compiled and tested with Microsoft Visual Studio 7.1 (.NET 2003). Before you compile, you must have these directories in your include options. To set these, go to Tools, Options, Projects, VC++ Directories.&lt;br /&gt;
&lt;br /&gt;
*From the Include Files menu, add these HL2SDK paths:&lt;br /&gt;
**public&lt;br /&gt;
**public/dlls&lt;br /&gt;
**public/engine&lt;br /&gt;
**public/tier0&lt;br /&gt;
**public/tier1&lt;br /&gt;
**public/vstdlib&lt;br /&gt;
**tier1&lt;br /&gt;
*From the Library Files menu, add these HL2SDK paths:&lt;br /&gt;
**lib/public&lt;br /&gt;
*From the Include Files menu, add these SourceMM paths:&lt;br /&gt;
**sourcemm&lt;br /&gt;
**sourcemm/sourcehook&lt;br /&gt;
**sourcemm/sourcemm&lt;br /&gt;
&lt;br /&gt;
You can then open the .vcproj project file. Go to Build, Set Active Configuration, and select Release. You can then select Build from the Build menu, which will produce a .dll file in the Release folder in the project folder.&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
To build on Linux, you must have a copy of Source Dedicated Server installed. Open the project Makefile and edit the following lines at the top:&lt;br /&gt;
&lt;br /&gt;
*SRCDS - Location of main srcds installation&lt;br /&gt;
*SMM_ROOT - Location of folder containing sourcemm and sourcehook&lt;br /&gt;
*HL2SDK - Location of HL2SDK&lt;br /&gt;
&lt;br /&gt;
Once done, you can just type &amp;quot;make&amp;quot; to run the build scripts. The binary will appear in ./Release/. &lt;br /&gt;
&lt;br /&gt;
[[Category:Documentation (SourceMM)]]&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=AMX_Mod_X_1.75_Scripting_Changes&amp;diff=2921</id>
		<title>AMX Mod X 1.75 Scripting Changes</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=AMX_Mod_X_1.75_Scripting_Changes&amp;diff=2921"/>
		<updated>2006-05-13T18:50:01Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: gaben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The AMX Mod X 1.75 release made important changes.  While backwards compatibility was kept, intended functionality shifted in esoteric areas that will affect some plugins.  Reading this article is highly recommended.&lt;br /&gt;
&lt;br /&gt;
=Module Requirement System=&lt;br /&gt;
As part of the new Automatic Module Loading, the old &amp;lt;tt&amp;gt;#pragma library&amp;lt;/tt&amp;gt; has been deprecated.  You must now use:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#pragma reqlib &amp;lt;library&amp;gt;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This means &amp;quot;require library&amp;quot;.  Plugins still compiled with &amp;lt;tt&amp;gt;#pragma library&amp;lt;/tt&amp;gt; will still fail on load if the given module is not found.  However, core will try to load each module given the rules below under &amp;quot;Automatic Module Loading&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Automatic Module Loading=&lt;br /&gt;
==Overview==&lt;br /&gt;
As of AMX Mod X 1.75, there is a new, powerful automatic module loading system.  That means that &amp;lt;tt&amp;gt;modules.ini&amp;lt;/tt&amp;gt; is largely deprecated for general use.  Instead, modules are loaded as plugins need them.  This is done dynamically by core before plugins are even loaded, without the need to patch &amp;lt;tt&amp;gt;modules.ini&amp;lt;/tt&amp;gt; and then change the map.&lt;br /&gt;
&lt;br /&gt;
Modules can now define &amp;quot;Libraries&amp;quot; and &amp;quot;Library Classes&amp;quot;.  A library is a specific identifier that should match the filename of the module.  For example, Engine's defined library is &amp;quot;engine&amp;quot;.  FakeMeta's library is &amp;quot;fakemeta&amp;quot;, and so on.&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;library class&amp;quot; defines membership to a set of modules.  For example, CSX has the library name &amp;quot;csx&amp;quot;, but it is part of the library class &amp;quot;xstats&amp;quot;.  Library classes are also used for DBI and SQLX.  This is very useful for being able to require one module type of any implementation.&lt;br /&gt;
&lt;br /&gt;
==New API==&lt;br /&gt;
===Compiler Pragmas===&lt;br /&gt;
This is expanded with a number of new &amp;lt;tt&amp;gt;#pragma&amp;lt;/tt&amp;gt; directives:&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma reqlib &amp;amp;lt;library&amp;gt;&amp;lt;/tt&amp;gt; - Requires that a given library must be loaded.&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma reqclass &amp;amp;lt;libclass&amp;gt;&amp;lt;/tt&amp;gt; - Requires that a given library class must be loaded.&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma loadlib &amp;amp;lt;library&amp;gt;&amp;lt;/tt&amp;gt; - Automatically attempts to load a given library (see more info below).&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma expectlib &amp;amp;lt;library1&amp;gt; &amp;amp;lt;library2&amp;gt;&amp;lt;/tt&amp;gt; - If the first library is not loaded, the second one will be attempted to load (not very useful).&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma expectclass &amp;amp;lt;class&amp;gt; &amp;amp;lt;library&amp;gt;&amp;lt;/tt&amp;gt; - If the expected class is not found, the given library will be attempted to load.  This is useful for defining a default module to be loaded with a given class of modules.&lt;br /&gt;
*&amp;lt;tt&amp;gt;#pragma defclasslib &amp;amp;lt;class&amp;gt; &amp;amp;lt;library&amp;gt;&amp;lt;/tt&amp;gt; - Same as &amp;lt;tt&amp;gt;expectclass&amp;lt;/tt&amp;gt;, however, &amp;lt;tt&amp;gt;defclasslib&amp;lt;/tt&amp;gt; waits until all expectations are resolved.  This lets plugins override defaults by adding their own expectations.&lt;br /&gt;
&lt;br /&gt;
===Module Filtering===&lt;br /&gt;
The module_filter prototype now includes a second parameter, which tells you whether the requirement is a class or library.&lt;br /&gt;
&lt;br /&gt;
Furthermore, module_exists has been deprecated for LibraryExists().&lt;br /&gt;
&lt;br /&gt;
==How it Works==&lt;br /&gt;
The precise order of events is as follows:&lt;br /&gt;
*When the first entity is spawned, AMX Mod X loads all unloaded modules in &amp;lt;tt&amp;gt;modules.ini&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*After &amp;lt;tt&amp;gt;modules.ini&amp;lt;/tt&amp;gt; is parsed, &amp;lt;tt&amp;gt;plugins.ini&amp;lt;/tt&amp;gt; is read.  Each file is mapped into a cache.&lt;br /&gt;
*The cache is previewed.&lt;br /&gt;
**First, the &amp;quot;library&amp;quot; table is read.  This table is read for backwards compatibility with AMX Mod X 1.71 and prior.  Each entry is read as a module file shortname, and the module is loaded if it exists.  &lt;br /&gt;
**Next, the &amp;quot;pubtags&amp;quot; table is read.  Each entry is decoded to one of the special #pragma commands.&lt;br /&gt;
***All loadlib commands are executed, and the modules loaded.&lt;br /&gt;
***All expect commands are executed.&lt;br /&gt;
***All defclasslib commands are executed.&lt;br /&gt;
*AMX Mod X then waits until ServerActivate is called.&lt;br /&gt;
*All plugins are loaded.  If the plugin is in the cache, the cache is read instead.  For each plugin...&lt;br /&gt;
**The library table is read.  For each library that is both nonexistant and unhandled by a module filter, the plugin fails to load.&lt;br /&gt;
**The pubtags table is read.  For each reqlib and reqclass entry that are both nonexistant and unhandled by a module filter, the plugin fails to load.&lt;br /&gt;
*The plugin cache is invalidated and the server is considered &amp;quot;loaded&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Register message=&lt;br /&gt;
The register_message set of natives, including g/set_msg_block, has been moved to Core.  This is to facilitate users who prefer to use FakeMeta, and like the simplicity and speed of using Engine's message interception functions.  &lt;br /&gt;
&lt;br /&gt;
This change is backwards compatible.&lt;br /&gt;
&lt;br /&gt;
=Module API=&lt;br /&gt;
The AMX Mod X module API received a small overhaul for 1.75.&lt;br /&gt;
&lt;br /&gt;
==Versioning/Interface Additions==&lt;br /&gt;
The internal module interface version is 4.  However, modules from M/SDK 3 will still load.  &lt;br /&gt;
&lt;br /&gt;
M/SDK Version 4 modules have two new members of public information: the library string, and the library class string.  These contain comma delimited names of whatever libraries or library classes the module would like to be registered.&lt;br /&gt;
&lt;br /&gt;
For backwards compatibility, M/SDK Version 4 modules have an automatically empty library class string, and a library string equal to the logtag string.&lt;br /&gt;
&lt;br /&gt;
==New Callbacks==&lt;br /&gt;
Modules can now be informed of when plugins are about to be unloaded, and when plugins have been fully unloaded.  This means that modules don't have to hook ServerActivate and ServerActivate_Post (implementation dependent), don't need to be loaded by Metamod, and don't need to detach simply to release resources.&lt;br /&gt;
&lt;br /&gt;
==New Functions==&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_GetLocalInfo&amp;lt;/tt&amp;gt; - Intended for modules using LOCALINFO, which required a Metamod attachment.  This is equal to AMX Mod X's core function &amp;lt;tt&amp;gt;get_localinfo&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_OverrideNatives&amp;lt;/tt&amp;gt; - Given a native list, this specifies that any other module already providing these natives will no longer provide them.  This was added to force backwards compatibility between SQLITE and MySQLX.  Usage is not recommended.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_FindLibrary&amp;lt;/tt&amp;gt; - Essentially the same function as LibraryExists() for plugins.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_AddLibraries&amp;lt;/tt&amp;gt; - Adds a comma delimited list of libraries or library classes.  You must specify a &amp;quot;parent&amp;quot; pointer that identifies the module.  This is easily accomplished by taking the address of any static variable.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MF_RemoveLibraries&amp;lt;/tt&amp;gt; - Removes all library entries with the given parent pointer.  This is useful if your module adds custom entries not in its defined list.  &lt;br /&gt;
&lt;br /&gt;
==MSVC8 Compatibility==&lt;br /&gt;
M/SDK Version 4 now contains preprocessor definitions for compatibility with Microsoft's Visual Studio 2005/8.0 (provided by [[User:Damaged Soul|Damaged Soul]]).  These macros can be turned off in the &amp;lt;tt&amp;gt;moduleconfig.h&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
=Minor Changes=&lt;br /&gt;
==Compiler Defines==&lt;br /&gt;
Since &amp;lt;tt&amp;gt;__DATE__&amp;lt;/tt&amp;gt; was fixed in 1.75, the macro &amp;lt;tt&amp;gt;__TIME__&amp;lt;/tt&amp;gt; was also added.&lt;br /&gt;
&lt;br /&gt;
==Argument Formatting==&lt;br /&gt;
The &amp;lt;tt&amp;gt;format_args&amp;lt;/tt&amp;gt; function is now replaced with a much faster, more compatible &amp;lt;tt&amp;gt;vformat&amp;lt;/tt&amp;gt; function.  Its usage is slightly different (read the include file, &amp;lt;tt&amp;gt;string.inc&amp;lt;/tt&amp;gt;), but it accepts %L, whereas format_args does not.  A quick example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;debugprint(const fmt[], ...)&lt;br /&gt;
{&lt;br /&gt;
   static temp[2048]&lt;br /&gt;
   vformat(temp, sizeof(temp)-1, fmt, 2)&lt;br /&gt;
   log_message(&amp;quot;[DEBUG] %s&amp;quot;, temp)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AMX Mod X]]&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Sample_Plugins_(Metamod:Source)&amp;diff=2827</id>
		<title>Sample Plugins (Metamod:Source)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Sample_Plugins_(Metamod:Source)&amp;diff=2827"/>
		<updated>2006-03-30T16:35:13Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: Reverted edit of Dayve&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This guide briefly explains about and how to compile the sample plugins for SourceMM.&lt;br /&gt;
&lt;br /&gt;
=Sample Plugins=&lt;br /&gt;
==stub_mm==&lt;br /&gt;
This plugin is a bare-minimum example of what you need to build a [[SourceMM]] plugin. It implements the ISmmPlugin class, exposes it as a DLL, and nothing more. As a single example, it also hooks ServerActivate in IServerGameDLL. &amp;quot;Stub&amp;quot; was designed such that a developer could open it and quickly modify it to begin a plugin.&lt;br /&gt;
&lt;br /&gt;
*meta_hooks.h - Definition of main hooks&lt;br /&gt;
*stub_mm.cpp - Main plugin file and implementation&lt;br /&gt;
*stub_mm.h - Main plugin header&lt;br /&gt;
&lt;br /&gt;
==sample_mm==&lt;br /&gt;
This plugin attempts to recreate all of the functionality a Server Plugin has. Server Plugins receive twelve callbacks, three of which are GameDLL overridable. In order to replicate this functionality, sample_mm hooks eleven of the callbacks as either post or pre handlers. Furthermore, it also demonstrates how to build a CallClass for calling original functions. Every hook produces a log message so you can see when events occur.&lt;br /&gt;
&lt;br /&gt;
Sample_mm fully replicates every callback a Server Plugin is capable of receiving, except for NetworkIDValidated. This callback has no known representation in the engine, is not very useful, and can be replicated easily with GameFrame() (in the future, we might demonstrate this). If you are having trouble porting a Server Plugin over, or are wondering how you can keep the same features, this plugin will show you where to start.&lt;br /&gt;
&lt;br /&gt;
*meta_hooks.h - Definition of main hooks&lt;br /&gt;
*SamplePlugin.cpp - Main plugin file and implementation&lt;br /&gt;
*SamplePLugin.h - Main plugin header&lt;br /&gt;
&lt;br /&gt;
=Where to Get=&lt;br /&gt;
You can find the source code to the sample plugins in either the source code package or [http://www.tcwonline.org/cgi-bin/viewcvs.cgi/sourcemm/ CVS]. They are located in the main source code folder in &amp;quot;stub_mm&amp;quot; and &amp;quot;sample_mm&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Compiling=&lt;br /&gt;
==Windows==&lt;br /&gt;
These plugins have been compiled and tested with Microsoft Visual Studio 7.1 (.NET 2003). Before you compile, you must have these directories in your include options. To set these, go to Tools, Options, Projects, VC++ Directories.&lt;br /&gt;
&lt;br /&gt;
*From the Include Files menu, add these HL2SDK paths:&lt;br /&gt;
**public&lt;br /&gt;
**public/dlls&lt;br /&gt;
**public/engine&lt;br /&gt;
**public/tier0&lt;br /&gt;
**public/tier1&lt;br /&gt;
**public/vstdlib&lt;br /&gt;
**tier1&lt;br /&gt;
*From the Library Files menu, add these HL2SDK paths:&lt;br /&gt;
**lib/public&lt;br /&gt;
*From the Include Files menu, add these SourceMM paths:&lt;br /&gt;
**sourcemm&lt;br /&gt;
**sourcemm/sourcehook&lt;br /&gt;
**sourcemm/sourcemm&lt;br /&gt;
&lt;br /&gt;
You can then open the .vcproj project file. Go to Build, Set Active Configuration, and select Release. You can then select Build from the Build menu, which will produce a .dll file in the Release folder in the project folder.&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
To build on Linux, you must have a copy of Source Dedicated Server installed. Open the project Makefile and edit the following lines at the top:&lt;br /&gt;
&lt;br /&gt;
*SRCDS - Location of main srcds installation&lt;br /&gt;
*SMM_ROOT - Location of folder containing sourcemm and sourcehook&lt;br /&gt;
*HL2SDK - Location of HL2SDK&lt;br /&gt;
&lt;br /&gt;
Once done, you can just type &amp;quot;make&amp;quot; to run the build scripts. The binary will appear in ./Release/. &lt;br /&gt;
&lt;br /&gt;
[[Category:Documentation (SourceMM)]]&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Metamod:Source_Development&amp;diff=2824</id>
		<title>Metamod:Source Development</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Metamod:Source_Development&amp;diff=2824"/>
		<updated>2006-03-28T09:55:35Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: added a missing )&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article is an introduction to [[SourceMM]] coding.  &lt;br /&gt;
&lt;br /&gt;
{{qnotice|The majority of this documentation should be merged or moved into an article about [[SourceHook]].}}&lt;br /&gt;
&lt;br /&gt;
{{qnotice|This article probably needs some better formatting.}}&lt;br /&gt;
&lt;br /&gt;
=Requirements=&lt;br /&gt;
You must have the Valve [[HL2SDK]], available from your [[Steam]] Menu. For Windows, you must have [[Microsoft Visual Studio]] 7.0 or 7.1 (we have not tried 6.0). For [[Linux]], Valve requires you use at least [[GCC]] 3.4.1. You should also have a copy of the [[Metamod:Source]] source code, available [http://www.sourcemm.net/ here] (sourcemm/sourcehook and sourcemm/sourcemm).&lt;br /&gt;
&lt;br /&gt;
For [[Microsoft Visual Studio]], you should make sure that you have the following HL2SDK paths in your include settings (Tools -&amp;gt; Options -&amp;gt; Projects, VC++ Directories, Include Files), as well as the &amp;quot;sourcehook&amp;quot; and &amp;quot;sourcemm&amp;quot; folders:&lt;br /&gt;
*dlls&lt;br /&gt;
*public&lt;br /&gt;
*public\vstdlib&lt;br /&gt;
*public\tier1&lt;br /&gt;
*public\tier0&lt;br /&gt;
*public\engine&lt;br /&gt;
*public\dlls&lt;br /&gt;
*tier1&lt;br /&gt;
*lib\public (this should be in your Library Paths!)&lt;br /&gt;
&lt;br /&gt;
=Plugin API=&lt;br /&gt;
In order to write a plugin, you must implement the ISmmPlugin interface, similar to IServerPluginCallbacks. Each Metamod:Source release has a minimum required interface version and a current version. The minimum version is guaranteed to be upward compatible to the current, however, it may be lacking some features.&lt;br /&gt;
&lt;br /&gt;
Once you've implemented the interface, you must also have a global singleton of your plugin available. There are a few macros to assist you in properly exposing the interface as a DLL and setting up the API states.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|PLUGIN_GLOBALVARS}}() - Place in header. Declares the global variables that some API calls require (such as g_SHPtr and g_PLAPI).&lt;br /&gt;
*{{bcode|PLUGIN_EXPOSE}}(class, singleton) - Place in .cpp file. Declares the external CreateInterface function which exposes the API.&lt;br /&gt;
*{{bcode|PLUGIN_SAVEVARS}}() - Use first thing in ISmmPlugin::Load(), saves the global variables sent from SourceMM.&lt;br /&gt;
&lt;br /&gt;
The actual plugin API you must implement as of this writing is version 004. To see a description of each of the functions, you can view the doxygen information here. Note that the Load, Unload, Pause, and Unpause functions allow you to refuse the action and copy an error message (you should check to make sure error is not NULL - it can be).&lt;br /&gt;
&lt;br /&gt;
=SourceHook (Hooking)=&lt;br /&gt;
SourceHook is the engine used to intercept function calls, much like Metamod. The difference with SourceHook is that it can intercept any virtual function in any class that, at compile time, you have the header for. SourceHook has the following steps of operation:&lt;br /&gt;
&lt;br /&gt;
* Declare the prototype of the function you are going to hook. This generates compile-time code that is able to pinpoint exactly how to go about hooking the function.&lt;br /&gt;
* Hook the function - as a member function of another class or a regular static function.&lt;br /&gt;
* Before the hooked function is called, all of the &amp;quot;pre&amp;quot; hook handlers attached to it are called. Each hook can set a special flag, the highest of which is chosen as a final operation. This flag specifies whether the original function should be called or not.&lt;br /&gt;
* Once all the hooks have been called, SourceHook decides whether to call the original function. Another set of hooks are called directly after, called &amp;quot;post&amp;quot; hook handlers. You can specify whether each hook is a post or pre hook - it simply changes whether it's called before or after the original call is made.&lt;br /&gt;
* After you are done using a hook, you can safely remove it.&lt;br /&gt;
&lt;br /&gt;
For example, let's say you wanted to intercept log messages in VEngineServer. Observe the prototype:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
virtual void		LogPrint( const char *msg ) = 0;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a virtual, public function of a class we have an instance of (let's say in IVEngineServer *m_Engine) and that we have the header for. It can be intercepted.&lt;br /&gt;
&lt;br /&gt;
The first step is to figure out how to declare its prototype to SourceHook. This function is void, and has one parameter. The declaration macro follows these formats:&lt;br /&gt;
&lt;br /&gt;
*{{bcode|SH_DECL_HOOK}}n - n is the number of parameters&lt;br /&gt;
**The parameters are: Class name, member function name, attributes, overloaded?, the return type, and a list of the parameter types.&lt;br /&gt;
*{{bcode|SH_DECL_HOOKn_void}} - n is the number of parameters&lt;br /&gt;
**_void specifies that the function does not return a value. The format is the same as above except the &amp;quot;return type&amp;quot; parameter is missing.&lt;br /&gt;
*'''Note:''' Not covered here are the SH_DECL_HOOKn[_void]_vafmt hooks. These can hook string-formattable variable argument lists. You do not pass the string format or ellipses parameter. SourceHook will automatically format the string for your hook.&lt;br /&gt;
&lt;br /&gt;
Our macro will look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, 0, const char *);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This line must appear outside of a function. It means &amp;quot;Declare a hook prototype for LogPrint in IVEngineServer, which is a void function that has one parameter, which is a const char *&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Next we must actually hook the function. You can do this wherever you want to begin the interception. The two macros for hooking look like this:&lt;br /&gt;
&lt;br /&gt;
*{{bcode|SH_ADD_HOOK_STATICFUNC}}(class, memberfunction, instance_pointer, handler, post) Hooks a virtual function to a static/global function.&lt;br /&gt;
**class - The name of the class&lt;br /&gt;
**memberfunction - The name of the member function&lt;br /&gt;
**instance - A pointer to an instance of the class&lt;br /&gt;
**handler - Your function that will be called on hooking&lt;br /&gt;
**post - true for post operation, false for pre operation&lt;br /&gt;
*{{bcode|SH_ADD_HOOK_MEMFUNC}}(class, memberfunction, instance, myinstance, myfunction, post) Hooks a virtual function to a member function of another class.&lt;br /&gt;
**class - The name of the class&lt;br /&gt;
**memberfunction - The name of the member function&lt;br /&gt;
**instance - An pointer to an instance of the class&lt;br /&gt;
**myinstance - A pointer to an instance of the class that has the handler member function&lt;br /&gt;
**myfunction - The name of the handler member function in your class&lt;br /&gt;
**post - true for post operation, false for pre-operation&lt;br /&gt;
&lt;br /&gt;
Let's continue with the example. To hook LogPrint to a function in your class, CMetaHooks (instance, g_MetaHooks), you would use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_ADD_HOOK_MEMFUNC(IVEngineServer, LogPrint, m_Engine, &amp;amp;g_MetaHooks, &amp;amp;CMetaHooks::LogPrint, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To remove the hook (either once it will no longer be unused, or at unload time):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, m_Engine &amp;amp;g_MetaHooks, &amp;amp;CMetaHooks::LogPrint, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, your function contents will look something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void CMetaHooks::LogPrint(const char *msg)&lt;br /&gt;
{&lt;br /&gt;
	//Code here&lt;br /&gt;
	RETURN_META(MRES_IGNORED);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note this return statement. This style of returning is similar to Metamod's, where you can set four different flags to indicate how you would like SourceHook to proceed. In Metamod, this return statement was required. In SourceMM, it is only required if you wish to set a return state other than MRES_IGNORED.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|MRES_IGNORED}} - No states were changed, act as though nothing happened. Original function is still called.&lt;br /&gt;
*{{bcode|MRES_HANDLED}} - Something changed, but the original function was still called. This can be used to tell another plugin that you did something.&lt;br /&gt;
*{{bcode|MRES_OVERRIDE}} - The original function will still be called, but your return value will override whatever it returns.&lt;br /&gt;
*{{bcode|MRES_SUPERCEDE}} - The original function is not called, and your return value will be what is returned to the caller.&lt;br /&gt;
&lt;br /&gt;
Note, that if you need to return a value, there is another macro. For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RETURN_META_VALUE(MRES_SUPERCEDE, value);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is required for non-void functions, athough the return value is ignored using MRES_IGNORED or MRES_HANDLED.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can hook to static member functions which has a slightly easier syntax. The DECL_HOOK line does not change. To add the hook:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_ADD_HOOK_STATICFUNC(IVEngineServer, LogPrint, m_Engine, LogPrint_handler, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removing the hook:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_REMOVE_HOOK_STATICFUNC(IVEngineServer, LogPrint, m_Engine, LogPrint_handler, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Declaring the handler:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void LogPrint_handler(const char *msg)&lt;br /&gt;
{&lt;br /&gt;
	//Code here&lt;br /&gt;
	RETURN_META(MRES_IGNORED);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that vafmt functions hooked with SourceHook assume that the vafmt is for a printf style string, and that the vafmt occurs at the end. When setting the parameters, you do not include the '...' notation, and SourceHook will vafmt the input string for you (meaning you also don't specify ... in your hooked function).&lt;br /&gt;
&lt;br /&gt;
=Calling Original Functions=&lt;br /&gt;
Often it will be necessary for you to call a function that's hooked, however, you don't want the hooks to be included in the calling. For example, if you want to entirely supercede a function and call it yourself from within a hook. To do this, you must request a call class. This is similar to MDLL_x() from Metamod for Half-Life 1.&lt;br /&gt;
&lt;br /&gt;
Continuing with the above example, let's say we want to supercede the original call and log a different message. Assume we also have the pointer m_Engine which is a &amp;lt;tt&amp;gt;IVEngineServer *&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
SourceHook::CallClass&amp;lt;IVEngineServer&amp;gt; *Engine_CC = SH_GET_CALLCLASS(m_Engine);&lt;br /&gt;
&lt;br /&gt;
SH_CALL(Engine_CC, &amp;amp;IVEngineServer::LogPrint)(&amp;quot;This is a log message!\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
//When you are done with the pointer..&lt;br /&gt;
SH_RELEASE_CALLCLASS(Engine_CC);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because of the complex nature of inheritance, instance pointers, and vtables, this syntax can be quite daunting. You may wish to make macros for specific functions or classes you use quite often, to reduce the amount of typing. For example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
//Assuming you have a global pointer g_Engine...&lt;br /&gt;
#define ENGCALL(func) SH_CALL(g_Engine, &amp;amp;IVEngineServer::func)&lt;br /&gt;
&lt;br /&gt;
//Then you can do:&lt;br /&gt;
ENGCALL(LogPrint)(&amp;quot;This is a test!&amp;quot;);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The syntax of calling class construction is:&lt;br /&gt;
*&amp;lt;tt&amp;gt;SourceHook::CallClass&amp;lt;class&amp;gt; *ptr = SH_GET_CALLCLASS(instance);&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Returns an object which allows you to call the original function. Class is the name of the class which is the target, instance is an instance of that class.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_CALL(cc_ptr, &amp;amp;class::func)([params])&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Pass the pointer returned from SH_GET_CALLCLASS as cc_ptr. The target function you call must be passed as a pointer-to-member-function, which takes the form &amp;amp;Class::Function as seen in previous examples. You must then complete the function call by adding a parenthetical parameter expression, even for void functions, which would be ().&lt;br /&gt;
&lt;br /&gt;
=Other Macros=&lt;br /&gt;
All of the macros take g_PLAPI as the first parameter. For more information on this, see the global variables section.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|META_CONPRINT}}(const char *msg)&lt;br /&gt;
*{{bcode|META_CONPRINTF}}(const char *fmt, ...)&lt;br /&gt;
**These two functions are recommended over Msg() for printing to the server console. Msg() does not relay commands back through rcon, and as of this writing Valve does not expose the function which does. To be able to display text through the rcon console (much like HL1), you should use these functions. If SourceMM is unable to extract the function properly, it will automatically default to Msg.&lt;br /&gt;
*{{bcode|META_LOG}}(g_PLAPI, const char *msg, ...)&lt;br /&gt;
**Logs a message through IVEngineServer::LogPrint(). A newline is automatically added, and msg is formatted as a sprintf() style string.&lt;br /&gt;
*{{bcode|META_REGCVAR}}(var)&lt;br /&gt;
**Registers a ConCommandBase pointer through SourceMM. The correct way to use this is to create an IConCommandBaseAccessor, and inside RegisterConCommandBase, call the macro on the given ConComandBase. This will ensure that SourceMM correctly detects and unloads your cvars and concommands at the appopriate time. Otherwise, unloading your plugin will cause a crash.&lt;br /&gt;
*{{bcode|META_UNREGCVAR}}(var)&lt;br /&gt;
**Unregisters a ConCommandBase pointer. This is not needed if you have set up your IConCommandBaseAccessor correctly (and called ConCommandBaseMngr::OneTimeInit()).&lt;br /&gt;
&lt;br /&gt;
=Events System=&lt;br /&gt;
The Events System is based on IMetamodListener. By implementing the IMetamodListener class and using g_SMAPI-&amp;gt;AddListener, you can watch for certain, low-traffic events. These events are split into three categories:&lt;br /&gt;
&lt;br /&gt;
*Plugin Events let you listen for plugin pauses and unloads. This is important if you're relying on information from another plugin, as you can handle cases where a live plugin has become invalid.&lt;br /&gt;
*Game Events are simple events that SourceMM is already hooking and makes available. These are LevelShutdown and LevelInit right now.&lt;br /&gt;
*Query Events occur when a factory is used. The four main factories (Engine, GameDLL, FileSystem, and Physics) are all overridable. You should simply return a non-NULL result to override, and fill the return code with IFACE_OK if available. There is no way to handle the case of two plugins overriding right now. The final factory is the Metamod Factory, which is the factory that Metamod:Source adds to the runtime space for plugins. By default, it only contains the interfaces for the PluginManager and SourceHook. Plugins can use this to add new interfaces. Other plugins request these interfaces through g_SMAPI-&amp;gt;MetaFactory().&lt;br /&gt;
&lt;br /&gt;
=Global Variables=&lt;br /&gt;
These global variables are saved by PLUGIN_EXPOSE and PLUGIN_SAVEVARS. They are declared with PLUGIN_GLOBALVARS.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|g_PLAPI}}&lt;br /&gt;
**ISmmPlugin * pointer to your global class singleton.&lt;br /&gt;
*{{bcode|g_PLID}}&lt;br /&gt;
**The internal PluginId of your plugin.&lt;br /&gt;
*{{bcode|g_SHPtr}}&lt;br /&gt;
**The SourceHook::ISourceHook * pointer to SourceHook's interface.&lt;br /&gt;
*{{bcode|g_SMAPI}}&lt;br /&gt;
**The ISmmAPI * pointer to SourceMM's interface.&lt;br /&gt;
&lt;br /&gt;
=Compiling=&lt;br /&gt;
To see more about compiling, see the Sample Plugin Compiling section.&lt;br /&gt;
&lt;br /&gt;
Modifying the default Makefiles for your own projects:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;OPT_FLAGS&amp;lt;/tt&amp;gt; - Optimization flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;DEBUG_FLAGS&amp;lt;/tt&amp;gt; - Debug flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;CPP&amp;lt;/tt&amp;gt; - C++ Compiler&lt;br /&gt;
*&amp;lt;tt&amp;gt;OBJECTS&amp;lt;/tt&amp;gt; - List of C++ files to compile&lt;br /&gt;
*&amp;lt;tt&amp;gt;LINK&amp;lt;/tt&amp;gt; - Linker Options&lt;br /&gt;
*&amp;lt;tt&amp;gt;CFLAGS&amp;lt;/tt&amp;gt; - Base Compiler Flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;BINARY&amp;lt;/tt&amp;gt; - Output Binary Name&lt;br /&gt;
&lt;br /&gt;
Makefile commands:&lt;br /&gt;
&lt;br /&gt;
*clean - Cleans all build files&lt;br /&gt;
*debug - Builds debug version&lt;br /&gt;
&lt;br /&gt;
=1.1 Changes - Late Loading, Events=&lt;br /&gt;
SourceMM 1.1 changed quite a few things internally, and externally made many breaking changes. These include:&lt;br /&gt;
&lt;br /&gt;
*ISmmPlugin::Load() has removed the factory list parameter (the factory system was replaced with the event system). Also, a boolean parameter was added, specifying whether the plugin was loaded late or not.&lt;br /&gt;
*ISmmPlugin::Load() is now called BEFORE DLLInit(), rather than after. This means it might not have all information it needs -- for example, IGameEvents won't be parsed yet. You will need to do things like this in ISmmPlugin:AllPluginsLoaded() instead, as it is guaranteed to occur when all DLLs are initialized.&lt;br /&gt;
*ISmmPlugin now has default functions -- you don't have to implement all of them.&lt;br /&gt;
*SourceHook was modified to use interfaces rather than straight struct pointers. This breaking changes will ensure that future SourceHook modifications do not break older plugins.&lt;br /&gt;
*SourceHook was modified to be re-entrant.&lt;br /&gt;
*SourceHook now has a tiny template library with it. This removes the necessity to link against libstdc++.so.*, which harms binary compatibility across linux distributions.&lt;br /&gt;
*SourceMM's GameDLL code was completely rewritten. It will now work with newer mods much easier, and issues like the DoD:S release will be much easier to deal with (if at all). It also removes a few important speed bottlenecks.&lt;br /&gt;
*An events system was added.&lt;br /&gt;
&lt;br /&gt;
=1.2 Changes - Changing Parameters, Manual Hooking=&lt;br /&gt;
SourceMM 1.2 now supports changing the parameters in a hook chain. For example, say the GameDLL has a function called IGameDLL::PrintString(const char *str). You can hook this, let it continue, but change the &amp;quot;str&amp;quot; parameter passed in to the rest of the hooks and the GameDLL. To do this, use the following macros:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;RETURN_META_NEWPARAMS&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;RETURN_META_VALUE_NEWPARAMS&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
class ISomething&lt;br /&gt;
{&lt;br /&gt;
   virtual void Function1(int num) =0;&lt;br /&gt;
   virtual bool Function2(bool what, int hi) =0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyHook1(int num)&lt;br /&gt;
{&lt;br /&gt;
   //if num is 0, &lt;br /&gt;
   // we will change the num parameter in the rest of the hooks, and the gamedll, to be 1.&lt;br /&gt;
   if (num == 0)&lt;br /&gt;
       RETURN_META_NEWPARAMS(MRES_IGNORED, &amp;amp;ISomething::Function1, (1))&lt;br /&gt;
   RETURN_META(MRES_SUPERCEDE);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bool MyHook2(bool what, int hi)&lt;br /&gt;
{&lt;br /&gt;
   //change the &amp;quot;what&amp;quot; and &amp;quot;hi&amp;quot; parameters to be false and 3 respectively&lt;br /&gt;
   //also, return true, but specify that the value is ignored&lt;br /&gt;
   RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &amp;amp;ISomething::Function2, (false, 3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
SourceHook also supports manual hooking of functions. This means you must know the virtual table index, the virtual table offset (for polymorphism), and the &amp;quot;this&amp;quot; pointer offset. Luckily, the polymorphic offsets are usually zero. This type of hook is ideal when supporting different ABI, for example, across different gamedlls. The API is almost identical:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_DECL_MANUALHOOKn[_void|_vafamt]&amp;lt;/tt&amp;gt; -&lt;br /&gt;
**Declares the manual hook. A unique name must be given to each manual hook.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_[ADD|REMOVE]_MANUALHOOK_[STATIC|MEM]FUNC&amp;lt;/tt&amp;gt; -&lt;br /&gt;
**Adds or removes a static or member function hook on a manually declared hook.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_MANUALHOOK_RECONFIGURE&amp;lt;/tt&amp;gt; - &lt;br /&gt;
**Reconfigures the indexes and offsets of a manual hook.&lt;br /&gt;
&lt;br /&gt;
An example is below, using the ISomething class from above.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
SH_DECL_MANUALHOOK2(_M_Function1, 1, 0, 0, bool, bool, int);&lt;br /&gt;
&lt;br /&gt;
void OnLoad(ISomething *pSomething)&lt;br /&gt;
{&lt;br /&gt;
	//we reference the static function by its unique handle we gave it&lt;br /&gt;
	//the parameters are otherwise the same - this pointer, hook handler, and post/non-post&lt;br /&gt;
	SH_ADD_MANUALHOOK_STATICFUNC(_M_Function1, pSomething, MyHook1, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void OnUnload(ISomething *pSomething)&lt;br /&gt;
{&lt;br /&gt;
	SH_REMOVE_MANUALHOOK_STATICFUNC(_M_Function1, pSomething, MyHook1, false);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more examples of the above features, you can look in SourceHook CVS's [http://www.tcwonline.org/cgi-bin/viewcvs.cgi/sourcemm/sourcehook/test/ test suite], which demonstrates a variety of hooking scenarios.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceHook]]&lt;br /&gt;
[[Category:Documentation (SourceMM)]]&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Troubleshooting_AMX_Mod_X&amp;diff=2736</id>
		<title>Troubleshooting AMX Mod X</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Troubleshooting_AMX_Mod_X&amp;diff=2736"/>
		<updated>2006-03-15T16:38:00Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: removed HzK's edit&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:AMX_Mod_X]]&lt;br /&gt;
If something goes wrong with your AMX Mod X installation, it's usually a problem someone else before has had.  This FAQ shows some of the more common problems with steps to solving them.&lt;br /&gt;
&lt;br /&gt;
=Plugin Problems=&lt;br /&gt;
==Loading Errors==&lt;br /&gt;
{{qa|What does &amp;quot;function not found&amp;quot; mean?}}&lt;br /&gt;
'''A:''' This means a function the plugin uses could not be found.  Most likely you forgot to enable a module that the plugin uses.  Check the plugin's documentation, then see [[Configuring AMX Mod X#Modules|Configuring Modules]].&lt;br /&gt;
&lt;br /&gt;
{{qa|What does &amp;quot;module required for plugin&amp;quot; mean?}}&lt;br /&gt;
'''A:''' See above question.  If you get this error, it should also tell you exactly which module you need to enable.&lt;br /&gt;
&lt;br /&gt;
{{qa|What does &amp;quot;Run time error ... debug not enabled&amp;quot; mean?}}&lt;br /&gt;
'''A:''' This means an internal error occured in the plugin.  To enable debug mode, and report the problem to the author, add the word &amp;quot;debug&amp;quot; after the plugin's entry in amxmodx/plugins/plugins.ini.  For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;myplugin.amxx debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more information, see [[Debugging Plugins (AMX Mod X)|Debugging Plugins]].&lt;br /&gt;
&lt;br /&gt;
{{qa|I have debug enabled and I still get run time errors!}}&lt;br /&gt;
'''A:''' Copy and paste the runtime errors and give them to the plugin author.  If the errors occur in official AMX Mod X plugins, make a bug report.&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Metamod:Source_Development&amp;diff=2735</id>
		<title>Metamod:Source Development</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Metamod:Source_Development&amp;diff=2735"/>
		<updated>2006-03-15T16:37:10Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: removed Phettachu's edit&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article is an introduction to [[SourceMM]] coding.  &lt;br /&gt;
&lt;br /&gt;
{{qnotice|The majority of this documentation should be merged or moved into an article about [[SourceHook]].}}&lt;br /&gt;
&lt;br /&gt;
{{qnotice|This article probably needs some better formatting.}}&lt;br /&gt;
&lt;br /&gt;
=Requirements=&lt;br /&gt;
You must have the Valve [[HL2SDK]], available from your [[Steam]] Menu. For Windows, you must have [[Microsoft Visual Studio]] 7.0 or 7.1 (we have not tried 6.0). For [[Linux]], Valve requires you use at least [[GCC]] 3.4.1. You should also have a copy of the [[Metamod:Source]] source code (sourcemm/sourcehook and sourcemm/sourcemm).&lt;br /&gt;
&lt;br /&gt;
For [[Microsoft Visual Studio]], you should make sure that you have the following HL2SDK paths in your include settings (Tools -&amp;gt; Options -&amp;gt; Projects, VC++ Directories, Include Files), as well as the &amp;quot;sourcehook&amp;quot; and &amp;quot;sourcemm&amp;quot; folders:&lt;br /&gt;
*dlls&lt;br /&gt;
*public&lt;br /&gt;
*public\vsdtlib&lt;br /&gt;
*public\tier1&lt;br /&gt;
*public\tier0&lt;br /&gt;
*public\engine&lt;br /&gt;
*public\dlls&lt;br /&gt;
*tier1&lt;br /&gt;
*lib\public (this should be in your Library Paths!)&lt;br /&gt;
&lt;br /&gt;
=Plugin API=&lt;br /&gt;
In order to write a plugin, you must implement the ISmmPlugin interface, similar to IServerPluginCallbacks. Each Metamod:Source release has a minimum required interface version and a current version. The minimum version is guaranteed to be upward compatible to the current, however, it may be lacking some features.&lt;br /&gt;
&lt;br /&gt;
Once you've implemented the interface, you must also have a global singleton of your plugin available. There are a few macros to assist you in properly exposing the interface as a DLL and setting up the API states.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|PLUGIN_GLOBALVARS}}() - Place in header. Declares the global variables that some API calls require (such as g_SHPtr and g_PLAPI).&lt;br /&gt;
*{{bcode|PLUGIN_EXPOSE}}(class, singleton) - Place in .cpp file. Declares the external CreateInterface function which exposes the API.&lt;br /&gt;
*{{bcode|PLUGIN_SAVEVARS}}() - Use first thing in ISmmPlugin::Load(), saves the global variables sent from SourceMM.&lt;br /&gt;
&lt;br /&gt;
The actual plugin API you must implement as of this writing is version 004. To see a description of each of the functions, you can view the doxygen information here. Note that the Load, Unload, Pause, and Unpause functions allow you to refuse the action and copy an error message (you should check to make sure error is not NULL - it can be).&lt;br /&gt;
&lt;br /&gt;
=SourceHook (Hooking)=&lt;br /&gt;
SourceHook is the engine used to intercept function calls, much like Metamod. The difference with SourceHook is that it can intercept any virtual function in any class that, at compile time, you have the header for. SourceHook has the following steps of operation:&lt;br /&gt;
&lt;br /&gt;
* Declare the prototype of the function you are going to hook. This generates compile-time code that is able to pinpoint exactly how to go about hooking the function.&lt;br /&gt;
* Hook the function - as a member function of another class or a regular static function.&lt;br /&gt;
* Before the hooked function is called, all of the &amp;quot;pre&amp;quot; hook handlers attached to it are called. Each hook can set a special flag, the highest of which is chosen as a final operation. This flag specifies whether the original function should be called or not.&lt;br /&gt;
* Once all the hooks have been called, SourceHook decides whether to call the original function. Another set of hooks are called directly after, called &amp;quot;post&amp;quot; hook handlers. You can specify whether each hook is a post or pre hook - it simply changes whether it's called before or after the original call is made.&lt;br /&gt;
* After you are done using a hook, you can safely remove it.&lt;br /&gt;
&lt;br /&gt;
For example, let's say you wanted to intercept log messages in VEngineServer. Observe the prototype:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
virtual void		LogPrint( const char *msg ) = 0;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a virtual, public function of a class we have an instance of (let's say in IVEngineServer *m_Engine) and that we have the header for. It can be intercepted.&lt;br /&gt;
&lt;br /&gt;
The first step is to figure out how to declare its prototype to SourceHook. This function is void, and has one parameter. The declaration macro follows these formats:&lt;br /&gt;
&lt;br /&gt;
*{{bcode|SH_DECL_HOOK}}n - n is the number of parameters&lt;br /&gt;
**The parameters are: Class name, member function name, attributes, overloaded?, the return type, and a list of the parameter types.&lt;br /&gt;
*{{bcode|SH_DECL_HOOKn_void}} - n is the number of parameters&lt;br /&gt;
**_void specifies that the function does not return a value. The format is the same as above except the &amp;quot;return type&amp;quot; parameter is missing.&lt;br /&gt;
*'''Note:''' Not covered here are the SH_DECL_HOOKn[_void]_vafmt hooks. These can hook string-formattable variable argument lists. You do not pass the string format or ellipses parameter. SourceHook will automatically format the string for your hook.&lt;br /&gt;
&lt;br /&gt;
Our macro will look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, 0, const char *);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This line must appear outside of a function. It means &amp;quot;Declare a hook prototype for LogPrint in IVEngineServer, which is a void function that has one parameter, which is a const char *&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Next we must actually hook the function. You can do this wherever you want to begin the interception. The two macros for hooking look like this:&lt;br /&gt;
&lt;br /&gt;
*{{bcode|SH_ADD_HOOK_STATICFUNC}}(class, memberfunction, instance_pointer, handler, post Hooks a virtual function to a static/global function.&lt;br /&gt;
**class - The name of the class&lt;br /&gt;
**memberfunction - The name of the member function&lt;br /&gt;
**instance - A pointer to an instance of the class&lt;br /&gt;
**handler - Your function that will be called on hooking&lt;br /&gt;
**post - true for post operation, false for pre operation&lt;br /&gt;
*{{bcode|SH_ADD_HOOK_MEMFUNC}}(class, memberfunction, instance, myinstance, myfunction, post) Hooks a virtual function to a member function of another class.&lt;br /&gt;
**class - The name of the class&lt;br /&gt;
**memberfunction - The name of the member function&lt;br /&gt;
**instance - An pointer to an instance of the class&lt;br /&gt;
**myinstance - A pointer to an instance of the class that has the handler member function&lt;br /&gt;
**myfunction - The name of the handler member function in your class&lt;br /&gt;
**post - true for post operation, false for pre-operation&lt;br /&gt;
&lt;br /&gt;
Let's continue with the example. To hook LogPrint to a function in your class, CMetaHooks (instance, g_MetaHooks), you would use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_ADD_HOOK_MEMFUNC(IVEngineServer, LogPrint, m_Engine, &amp;amp;g_MetaHooks, &amp;amp;CMetaHooks::LogPrint, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To remove the hook (either once it will no longer be unused, or at unload time):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, m_Engine &amp;amp;g_MetaHooks, &amp;amp;CMetaHooks::LogPrint, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, your function contents will look something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void CMetaHooks::LogPrint(const char *msg)&lt;br /&gt;
{&lt;br /&gt;
	//Code here&lt;br /&gt;
	RETURN_META(MRES_IGNORED);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note this return statement. This style of returning is similar to Metamod's, where you can set four different flags to indicate how you would like SourceHook to proceed. In Metamod, this return statement was required. In SourceMM, it is only required if you wish to set a return state other than MRES_IGNORED.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|MRES_IGNORED}} - No states were changed, act as though nothing happened. Original function is still called.&lt;br /&gt;
*{{bcode|MRES_HANDLED}} - Something changed, but the original function was still called. This can be used to tell another plugin that you did something.&lt;br /&gt;
*{{bcode|MRES_OVERRIDE}} - The original function will still be called, but your return value will override whatever it returns.&lt;br /&gt;
*{{bcode|MRES_SUPERCEDE}} - The original function is not called, and your return value will be what is returned to the caller.&lt;br /&gt;
&lt;br /&gt;
Note, that if you need to return a value, there is another macro. For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RETURN_META_VALUE(MRES_SUPERCEDE, value);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is required for non-void functions, athough the return value is ignored using MRES_IGNORED or MRES_HANDLED.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can hook to static member functions which has a slightly easier syntax. The DECL_HOOK line does not change. To add the hook:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_ADD_HOOK_STATICFUNC(IVEngineServer, LogPrint, m_Engine, LogPrint_handler, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removing the hook:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_REMOVE_HOOK_STATICFUNC(IVEngineServer, LogPrint, m_Engine, LogPrint_handler, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Declaring the handler:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void LogPrint_handler(const char *msg)&lt;br /&gt;
{&lt;br /&gt;
	//Code here&lt;br /&gt;
	RETURN_META(MRES_IGNORED);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that vafmt functions hooked with SourceHook assume that the vafmt is for a printf style string, and that the vafmt occurs at the end. When setting the parameters, you do not include the '...' notation, and SourceHook will vafmt the input string for you (meaning you also don't specify ... in your hooked function).&lt;br /&gt;
&lt;br /&gt;
=Calling Original Functions=&lt;br /&gt;
Often it will be necessary for you to call a function that's hooked, however, you don't want the hooks to be included in the calling. For example, if you want to entirely supercede a function and call it yourself from within a hook. To do this, you must request a call class. This is similar to MDLL_x() from Metamod for Half-Life 1.&lt;br /&gt;
&lt;br /&gt;
Continuing with the above example, let's say we want to supercede the original call and log a different message. Assume we also have the pointer m_Engine which is a &amp;lt;tt&amp;gt;IVEngineServer *&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
SourceHook::CallClass&amp;lt;IVEngineServer&amp;gt; *Engine_CC = SH_GET_CALLCLASS(m_Engine);&lt;br /&gt;
&lt;br /&gt;
SH_CALL(Engine_CC, &amp;amp;IVEngineServer::LogPrint)(&amp;quot;This is a log message!\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
//When you are done with the pointer..&lt;br /&gt;
SH_RELEASE_CALLCLASS(Engine_CC);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because of the complex nature of inheritance, instance pointers, and vtables, this syntax can be quite daunting. You may wish to make macros for specific functions or classes you use quite often, to reduce the amount of typing. For example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
//Assuming you have a global pointer g_Engine...&lt;br /&gt;
#define ENGCALL(func) SH_CALL(g_Engine, &amp;amp;IVEngineServer::func)&lt;br /&gt;
&lt;br /&gt;
//Then you can do:&lt;br /&gt;
ENGCALL(LogPrint)(&amp;quot;This is a test!&amp;quot;);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The syntax of calling class construction is:&lt;br /&gt;
*&amp;lt;tt&amp;gt;SourceHook::CallClass&amp;lt;class&amp;gt; *ptr = SH_GET_CALLCLASS(instance);&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Returns an object which allows you to call the original function. Class is the name of the class which is the target, instance is an instance of that class.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_CALL(cc_ptr, &amp;amp;class::func)([params])&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Pass the pointer returned from SH_GET_CALLCLASS as cc_ptr. The target function you call must be passed as a pointer-to-member-function, which takes the form &amp;amp;Class::Function as seen in previous examples. You must then complete the function call by adding a parenthetical parameter expression, even for void functions, which would be ().&lt;br /&gt;
&lt;br /&gt;
=Other Macros=&lt;br /&gt;
All of the macros take g_PLAPI as the first parameter. For more information on this, see the global variables section.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|META_CONPRINT}}(const char *msg)&lt;br /&gt;
*{{bcode|META_CONPRINTF}}(const char *fmt, ...)&lt;br /&gt;
**These two functions are recommended over Msg() for printing to the server console. Msg() does not relay commands back through rcon, and as of this writing Valve does not expose the function which does. To be able to display text through the rcon console (much like HL1), you should use these functions. If SourceMM is unable to extract the function properly, it will automatically default to Msg.&lt;br /&gt;
*{{bcode|META_LOG}}(g_PLAPI, const char *msg, ...)&lt;br /&gt;
**Logs a message through IVEngineServer::LogPrint(). A newline is automatically added, and msg is formatted as a sprintf() style string.&lt;br /&gt;
*{{bcode|META_REGCVAR}}(var)&lt;br /&gt;
**Registers a ConCommandBase pointer through SourceMM. The correct way to use this is to create an IConCommandBaseAccessor, and inside RegisterConCommandBase, call the macro on the given ConComandBase. This will ensure that SourceMM correctly detects and unloads your cvars and concommands at the appopriate time. Otherwise, unloading your plugin will cause a crash.&lt;br /&gt;
*{{bcode|META_UNREGCVAR}}(var)&lt;br /&gt;
**Unregisters a ConCommandBase pointer. This is not needed if you have set up your IConCommandBaseAccessor correctly (and called ConCommandBaseMngr::OneTimeInit()).&lt;br /&gt;
&lt;br /&gt;
=Events System=&lt;br /&gt;
The Events System is based on IMetamodListener. By implementing the IMetamodListener class and using g_SMAPI-&amp;gt;AddListener, you can watch for certain, low-traffic events. These events are split into three categories:&lt;br /&gt;
&lt;br /&gt;
*Plugin Events let you listen for plugin pauses and unloads. This is important if you're relying on information from another plugin, as you can handle cases where a live plugin has become invalid.&lt;br /&gt;
*Game Events are simple events that SourceMM is already hooking and makes available. These are LevelShutdown and LevelInit right now.&lt;br /&gt;
*Query Events occur when a factory is used. The four main factories (Engine, GameDLL, FileSystem, and Physics) are all overridable. You should simply return a non-NULL result to override, and fill the return code with IFACE_OK if available. There is no way to handle the case of two plugins overriding right now. The final factory is the Metamod Factory, which is the factory that Metamod:Source adds to the runtime space for plugins. By default, it only contains the interfaces for the PluginManager and SourceHook. Plugins can use this to add new interfaces. Other plugins request these interfaces through g_SMAPI-&amp;gt;MetaFactory().&lt;br /&gt;
&lt;br /&gt;
=Global Variables=&lt;br /&gt;
These global variables are saved by PLUGIN_EXPOSE and PLUGIN_SAVEVARS. They are declared with PLUGIN_GLOBALVARS.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|g_PLAPI}}&lt;br /&gt;
**ISmmPlugin * pointer to your global class singleton.&lt;br /&gt;
*{{bcode|g_PLID}}&lt;br /&gt;
**The internal PluginId of your plugin.&lt;br /&gt;
*{{bcode|g_SHPtr}}&lt;br /&gt;
**The SourceHook::ISourceHook * pointer to SourceHook's interface.&lt;br /&gt;
*{{bcode|g_SMAPI}}&lt;br /&gt;
**The ISmmAPI * pointer to SourceMM's interface.&lt;br /&gt;
&lt;br /&gt;
=Compiling=&lt;br /&gt;
To see more about compiling, see the Sample Plugin Compiling section.&lt;br /&gt;
&lt;br /&gt;
Modifying the default Makefiles for your own projects:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;OPT_FLAGS&amp;lt;/tt&amp;gt; - Optimization flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;DEBUG_FLAGS&amp;lt;/tt&amp;gt; - Debug flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;CPP&amp;lt;/tt&amp;gt; - C++ Compiler&lt;br /&gt;
*&amp;lt;tt&amp;gt;OBJETS&amp;lt;/tt&amp;gt; - List of C++ files to compile&lt;br /&gt;
*&amp;lt;tt&amp;gt;LINK&amp;lt;/tt&amp;gt; - Linker Options&lt;br /&gt;
*&amp;lt;tt&amp;gt;CFLAGS&amp;lt;/tt&amp;gt; - Base Compiler Flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;BINARY&amp;lt;/tt&amp;gt; - Output Binary Name&lt;br /&gt;
&lt;br /&gt;
Makefile commands:&lt;br /&gt;
&lt;br /&gt;
*clean - Cleans all build files&lt;br /&gt;
*debug - Builds debug version&lt;br /&gt;
&lt;br /&gt;
=1.1 Changes - Late Loading, Events=&lt;br /&gt;
SourceMM 1.1 changed quite a few things internally, and externally made many breaking changes. These include:&lt;br /&gt;
&lt;br /&gt;
*ISmmPlugin::Load() has removed the factory list parameter (the factory system was replaced with the event system). Also, a boolean parameter was added, specifying whether the plugin was loaded late or not.&lt;br /&gt;
*ISmmPlugin::Load() is now called BEFORE DLLInit(), rather than after. This means it might not have all information it needs -- for example, IGameEvents won't be parsed yet. You will need to do things like this in ISmmPlugin:AllPluginsLoaded() instead, as it is guaranteed to occur when all DLLs are initialized.&lt;br /&gt;
*ISmmPlugin now has default functions -- you don't have to implement all of them.&lt;br /&gt;
*SourceHook was modified to use interfaces rather than straight struct pointers. This breaking changes will ensure that future SourceHook modifications do not break older plugins.&lt;br /&gt;
*SourceHook was modified to be re-entrant.&lt;br /&gt;
*SourceHook now has a tiny template library with it. This removes the necessity to link against libstdc++.so.*, which harms binary compatibility across linux distributions.&lt;br /&gt;
*SourceMM's GameDLL code was completely rewritten. It will now work with newer mods much easier, and issues like the DoD:S release will be much easier to deal with (if at all). It also removes a few important speed bottlenecks.&lt;br /&gt;
*An events system was added.&lt;br /&gt;
&lt;br /&gt;
=1.2 Changes - Changing Parameters, Manual Hooking=&lt;br /&gt;
SourceMM 1.2 now supports changing the parameters in a hook chain. For example, say the GameDLL has a function called IGameDLL::PrintString(const char *str). You can hook this, let it continue, but change the &amp;quot;str&amp;quot; parameter passed in to the rest of the hooks and the GameDLL. To do this, use the following macros:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;RETURN_META_NEWPARAMS&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;RETURN_META_VALUE_NEWPARAMS&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
class ISomething&lt;br /&gt;
{&lt;br /&gt;
   virtual void Function1(int num) =0;&lt;br /&gt;
   virtual bool Function2(bool what, int hi) =0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyHook1(int num)&lt;br /&gt;
{&lt;br /&gt;
   //if num is 0, &lt;br /&gt;
   // we will change the num parameter in the rest of the hooks, and the gamedll, to be 1.&lt;br /&gt;
   if (num == 0)&lt;br /&gt;
       RETURN_META_NEWPARAMS(MRES_IGNORED, &amp;amp;ISomething::Function1, (1))&lt;br /&gt;
   RETURN_META(MRES_SUPERCEDE);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bool MyHook2(bool what, int hi)&lt;br /&gt;
{&lt;br /&gt;
   //change the &amp;quot;what&amp;quot; and &amp;quot;hi&amp;quot; parameters to be false and 3 respectively&lt;br /&gt;
   //also, return true, but specify that the value is ignored&lt;br /&gt;
   RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &amp;amp;ISomething::Function2, (false, 3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
SourceHook also supports manual hooking of functions. This means you must know the virtual table index, the virtual table offset (for polymorphism), and the &amp;quot;this&amp;quot; pointer offset. Luckily, the polymorphic offsets are usually zero. This type of hook is ideal when supporting different ABI, for example, across different gamedlls. The API is almost identical:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_DECL_MANUALHOOKn[_void|_vafamt]&amp;lt;/tt&amp;gt; -&lt;br /&gt;
**Declares the manual hook. A unique name must be given to each manual hook.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_[ADD|REMOVE]_MANUALHOOK_[STATIC|MEM]FUNC&amp;lt;/tt&amp;gt; -&lt;br /&gt;
**Adds or removes a static or member function hook on a manually declared hook.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_MANUALHOOK_RECONFIGURE&amp;lt;/tt&amp;gt; - &lt;br /&gt;
**Reconfigures the indexes and offsets of a manual hook.&lt;br /&gt;
&lt;br /&gt;
An example is below, using the ISomething class from above.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
SH_DECL_MANUALHOOK2(_M_Function1, 1, 0, 0, bool, bool, int);&lt;br /&gt;
&lt;br /&gt;
void OnLoad(ISomething *pSomething)&lt;br /&gt;
{&lt;br /&gt;
	//we reference the static function by its unique handle we gave it&lt;br /&gt;
	//the parameters are otherwise the same - this pointer, hook handler, and post/non-post&lt;br /&gt;
	SH_ADD_MANUALHOOK_STATICFUNC(_M_Function1, pSomething, MyHook1, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void OnUnload(ISomething *pSomething)&lt;br /&gt;
{&lt;br /&gt;
	SH_REMOVE_MANUALHOOK_STATICFUNC(_M_Function1, pSomething, MyHook1, false);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more examples of the above features, you can look in SourceHook CVS's [http://www.tcwonline.org/cgi-bin/viewcvs.cgi/sourcemm/sourcehook/test/ test suite], which demonstrates a variety of hooking scenarios.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceHook]]&lt;br /&gt;
[[Category:Documentation (SourceMM)]]&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Metamod&amp;diff=2730</id>
		<title>Metamod</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Metamod&amp;diff=2730"/>
		<updated>2006-03-12T14:45:20Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: removed Bbz's changes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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>Belsebub</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Optimizing_Plugins_(AMX_Mod_X_Scripting)&amp;diff=2724</id>
		<title>Optimizing Plugins (AMX Mod X Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Optimizing_Plugins_(AMX_Mod_X_Scripting)&amp;diff=2724"/>
		<updated>2006-03-10T16:46:53Z</updated>

		<summary type="html">&lt;p&gt;Belsebub: changed all 1.65 to 1.70&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
[[Admin-Mod]] and [[AMX Mod X]] became very popular because of their easy to use scripting language.  However, the words &amp;quot;scripting language&amp;quot; come with a lot of loaded preconceptions.  Most people assume that because it's scripted:&lt;br /&gt;
*You can't possibly make it any faster&lt;br /&gt;
*It's pre-compiled, so it's already quite fast&lt;br /&gt;
*Details don't matter, as it's only &amp;quot;scripting&amp;quot; anyway&lt;br /&gt;
&lt;br /&gt;
Especially, with [[Pawn]] (formerly Small), none of these are true.  The compiler, in fact, is very poor at optimizing, and you can '''greatly''' increase the speed and efficiency of your plugins by keeping a few rules in mind.  Remember - it's more important to minimize instructions than it is to minimize lines of code.&lt;br /&gt;
&lt;br /&gt;
===Terms===&lt;br /&gt;
To read this document, you will need to understand a few concepts beforehand:&lt;br /&gt;
*&amp;lt;tt&amp;gt;BRANCHING&amp;lt;/tt&amp;gt; - When the processor takes a different path of code.  For example, to call a function or to use an if statement, the processor will &amp;quot;branch&amp;quot;.  Modern processors attempt to predict pathways with &amp;quot;branch prediction&amp;quot;, but it's best to avoid branching a lot if possible.&lt;br /&gt;
*&amp;lt;tt&amp;gt;STACK ALLOCATION&amp;lt;/tt&amp;gt; - In Pawn, all local data is stored on the stack, a big chunk of continuous memory.  Whenever you create a variable on the stack, it is automatically written with zeroes.&lt;br /&gt;
*&amp;lt;tt&amp;gt;HEAP ALLOCATION&amp;lt;/tt&amp;gt; - In Pawn, temporary data that needs to be referenced by a native is stored on the heap, another area of contiguous, but less restrictive memory.&lt;br /&gt;
*&amp;lt;tt&amp;gt;DATA SECTION&amp;lt;/tt&amp;gt; - This is an area of memory built into your .amxx file.  In fact, it &amp;quot;becomes&amp;quot; the heap at load time.  All your strings and arrays are hardcoded into this area.&lt;br /&gt;
*&amp;lt;tt&amp;gt;EXPENSIVENESS&amp;lt;/tt&amp;gt; - To be &amp;quot;expensive&amp;quot; in computer science means an operation requires a lot of CPU processing.  It usually does not refer to memory size, only to processing cycles and time.  Addition is inexpensive, floating power operations are expensive.  However, both are inexpensive in comparison to writing a file.  An inexpensive operation can also be called &amp;quot;cheap&amp;quot;.&lt;br /&gt;
*&amp;lt;tt&amp;gt;BIG-OH NOTATION&amp;lt;/tt&amp;gt; - O(*) notation refers to the expensiveness of an algorithm.  If something is O(n), it occurs in linear time -- meaning that for N items, it will complete relative to N.  O(N^2) means with N items, it will complete relative to N^2.  O(1) means &amp;quot;constant time&amp;quot; - no matter what N is, it will run in the same amount of time.&lt;br /&gt;
&lt;br /&gt;
==Compiler Optimizations==&lt;br /&gt;
These optimizations have to do with changing how your code is compiled.  While the syntax may remain the same, you are not only increasing compile time, but increasing your plugin's efficiency and speed at run time.&lt;br /&gt;
&lt;br /&gt;
===Always Save Results===&lt;br /&gt;
Observe the example code snippet below:&lt;br /&gt;
&amp;lt;pawn&amp;gt;if (get_user_team(player) == TEAM_T)&lt;br /&gt;
{&lt;br /&gt;
    //...code&lt;br /&gt;
} else if (get_user_team(player) == TEAM_CT) {&lt;br /&gt;
    //...code&lt;br /&gt;
} else if (get_user_team(player) == TEAM_SPECTATOR) {&lt;br /&gt;
    //...code&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This is a mild example of &amp;quot;cache your results&amp;quot;.  When the compiler generates assembly for this code, it will (in pseudo code) generate:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Notice the problem?  We have called &amp;lt;tt&amp;gt;get_user_team&amp;lt;/tt&amp;gt; an extra two times than necessary.  The result doesn't change, so we can save it.  Observe:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new team = get_user_team(player)&lt;br /&gt;
if (team == TEAM_T)&lt;br /&gt;
{&lt;br /&gt;
    //...code&lt;br /&gt;
} else if (team == TEAM_CT) {&lt;br /&gt;
    //...code&lt;br /&gt;
} //...etc&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Now, the compiler will only generate this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If &amp;lt;tt&amp;gt;get_user_team&amp;lt;/tt&amp;gt; were an expensive operation (it's relatively cheap), we would have recalculated the entire result each branch of the &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; case.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Switch instead of If===&lt;br /&gt;
If you can, you should use &amp;lt;tt&amp;gt;switch&amp;lt;/tt&amp;gt; cases instead of &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;.  This is because for an if statement, the compiler must branch to each consecutive &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; case.  Using the example from above, observe the switch version:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new team = get_user_team(player)&lt;br /&gt;
switch (team)&lt;br /&gt;
{&lt;br /&gt;
  case TEAM_T:&lt;br /&gt;
     //code...&lt;br /&gt;
  case TEAM_CT:&lt;br /&gt;
     //code...&lt;br /&gt;
  case TEAM_SPECTATOR:&lt;br /&gt;
     //code...&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This will generate what's called a &amp;quot;case table&amp;quot;.  Rather than worm through displaced &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; tests, the compiler generates a table of possible values, which the virtual machine knows to browse through:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE&lt;br /&gt;
  COMPARE&lt;br /&gt;
  COMPARE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Don't Re-index Arrays===&lt;br /&gt;
A common practice in Small is to &amp;quot;save space&amp;quot; by re-indexing arrays.  There are a few myths behind this, such as saving memory, assuming the compiler does it for you, or readability.  Fact: none of these are true.  Observe the code below:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new players[32], num, team&lt;br /&gt;
get_players(players, num)&lt;br /&gt;
for (new i=0; i&amp;lt;num; i++)&lt;br /&gt;
{&lt;br /&gt;
   if (!is_user_connected(players[i]))&lt;br /&gt;
      continue;&lt;br /&gt;
   team = get_user_team(players[i])&lt;br /&gt;
   set_user_frags(players[i], 0)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
For this, the compiler generates code similar to:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
:LOOP_BEGIN&lt;br /&gt;
   LOAD i&lt;br /&gt;
   LOAD players&lt;br /&gt;
   CALC&lt;br /&gt;
   LOAD players[i]&lt;br /&gt;
   CALL is_user_connected&lt;br /&gt;
   LOAD i&lt;br /&gt;
   LOAD players&lt;br /&gt;
   CALC&lt;br /&gt;
   LOAD players[i]&lt;br /&gt;
   CALL get_user_team&lt;br /&gt;
   LOAD i&lt;br /&gt;
   LOAD players&lt;br /&gt;
   CALC&lt;br /&gt;
   LOAD players[i]&lt;br /&gt;
   CALL set_user_frags&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See what happened?  The compiler does not cache array indexing.  Because we've used &amp;lt;tt&amp;gt;players[i]&amp;lt;/tt&amp;gt; each time, every instance generates 4-6 (or more) instructions which load &amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt;, the address of &amp;lt;tt&amp;gt;players&amp;lt;/tt&amp;gt;, computes the final location, and then grabs the data out of memory.  It is much faster to do:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new player&lt;br /&gt;
for (new i=0; i&amp;lt;num; i++)&lt;br /&gt;
{&lt;br /&gt;
   player = players[i]&lt;br /&gt;
   if (!is_user_connected(player))&lt;br /&gt;
      continue;&lt;br /&gt;
   team = get_user_team(player)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Not only is this more readable, but look at how much cruft we've shaved off the compiler's generated code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
:LOOP_BEGIN&lt;br /&gt;
   LOAD i&lt;br /&gt;
   LOAD players&lt;br /&gt;
   CALC&lt;br /&gt;
   LOAD players[i]&lt;br /&gt;
   STORE player&lt;br /&gt;
   CALL is_user_connected&lt;br /&gt;
   LOAD player&lt;br /&gt;
   CALL get_user_team&lt;br /&gt;
   LOAD player&lt;br /&gt;
   CALL set_user_frags&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In a large loop you can drastically reduce codesize in this manner.&lt;br /&gt;
&lt;br /&gt;
===Global vs Local and Variables in Loops===&lt;br /&gt;
It is important to realize that every variable in [[Pawn]] is automatically zeroed.  For global variables, they are static and permanent, thus they are zeroed when your plugin is loaded.  Variables in functions, however, must be zeroed dynamically.  This is a slow and tedious operation, and you should not only avoid relying on it when necessary, but you should keep that fact in mind when using arrays.&lt;br /&gt;
&lt;br /&gt;
[[Arrays]] in [[Pawn]] are &amp;quot;cells&amp;quot; of data.  Each cell is four or eight bytes, depending on whether your processor is 32bit or 64bit.  To create an array of 4096 cells, for example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new array[4096]&amp;lt;/pawn&amp;gt;&lt;br /&gt;
The compiler generates code to manually zero every single one of the 16,384 bytes in that location.  Normally, this isn't too bad -- but it can be absolutely deadly in a function which is called quite often.  For example, &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt; is called on every [[server tick]] in [[AMX Mod X]].  To declare an array of that size in &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt; is highly unnecessary.  Instead, you can take advantage of the fact that not only are globals free of charge, but &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt; does not need to be re-entrant.  That is, you will never call &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt; inside of &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt;, so making the variable global will not bring up the problem of one instance of the function overwriting data from another instance of the same function.  Observe:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new g_serverframe_array[4096]&lt;br /&gt;
public server_frame()&lt;br /&gt;
{&lt;br /&gt;
  //...code that uses g_serverframe_array&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This will execute conseridably faster.  You can do this with smaller arrays too.&lt;br /&gt;
&lt;br /&gt;
Likewise, it is equally important to avoid declaring arrays inside of loops.  Consider the following block of code:&lt;br /&gt;
&amp;lt;pawn&amp;gt;for (new i=0; i&amp;lt;num; i++)&lt;br /&gt;
{&lt;br /&gt;
   new message[255], name[32], player&lt;br /&gt;
   player = players[i]&lt;br /&gt;
   get_user_name(player, name, 31)&lt;br /&gt;
   format(message, 254, &amp;quot;Hello, %s&amp;quot;, name)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
If there are 32 players, this loop will actually resize and zero out over 1K of memory thirty two times in a row.  Not good!  However, on the other hand, it's nice that the message is zeroed out for us each time.  &amp;lt;tt&amp;gt;Tip:&amp;lt;/tt&amp;gt; you often only need to zero out the first character of a string.  This will make the entire string empty.  The code below is much more efficient:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new message[255], name[32], player&lt;br /&gt;
for (new i=0; i&amp;lt;num; i++)&lt;br /&gt;
{&lt;br /&gt;
   player = players[i]&lt;br /&gt;
   name[0] = '^0'&lt;br /&gt;
   message[0] = '^0'&lt;br /&gt;
   get_user_name(player, name, 31)&lt;br /&gt;
   format(message, 254, &amp;quot;Hello, %s&amp;quot;, name)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This has the effect of safely making the string empty beforehand, as well as largely reducing a lot of run-time overhead.&lt;br /&gt;
&lt;br /&gt;
===Static vs Global===&lt;br /&gt;
An alternative to global variables is static variables, which are internally the same but easier to work with for programming.&lt;br /&gt;
&lt;br /&gt;
A variable declared with the keyword &amp;quot;static&amp;quot; instead of &amp;quot;new&amp;quot; operates in the same way a global does (it is created only once) but the variable is local to the function; this means the code is much easier to read, while drastically improving speed just like a global variable.  Example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;stock SomeBigFunction()&lt;br /&gt;
{&lt;br /&gt;
   static gaben[255];&lt;br /&gt;
   format(gaben, &amp;quot;%L&amp;quot;, LANG_SERVER, &amp;quot;STUFF&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has the same effect as declaring &amp;lt;tt&amp;gt;gaben&amp;lt;/tt&amp;gt; as global, except only &amp;lt;tt&amp;gt;SomeBigFunction&amp;lt;/tt&amp;gt; can use it.  &lt;br /&gt;
&lt;br /&gt;
{{qnotice|Be careful of re-entrancy!}}&lt;br /&gt;
When a variable is static, it has the same re-entrancy problems of a global variable.  That means, if your function might be called recursively, or twice in the same stack frame, you should not use static variables.  This is most often the case for API provided to other plugins or helper functions.  Triggered events are usually never called twice on the same execution chain.&lt;br /&gt;
&lt;br /&gt;
===Constant variables===&lt;br /&gt;
You can declare a variable &amp;quot;constant&amp;quot; by adding the &amp;quot;const&amp;quot; keyword before the variable name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;new const AMX_GABEN[] = &amp;quot;amx_gaben&amp;quot;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this does is prevents the variable from being changed; essentially, you've locked the variable to a certain value. In this way, a constant can offer a type safe method of simplifying code, unlike a define, which is not type safe.&lt;br /&gt;
&lt;br /&gt;
In addition, constant variables are often optimized out, resulting in quicker and smaller code.&lt;br /&gt;
&lt;br /&gt;
===For Loop Comparisons===&lt;br /&gt;
A common mistake is to write code like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new string[256] = &amp;quot;something long&amp;quot;&lt;br /&gt;
for (new i=0; i&amp;lt;strlen(string); i++)&lt;br /&gt;
   //...code&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This plays off a similar principle from before: cache results.  The compiler will actually recompute your string length on each iteration of the loop.  This will have even worse effects if your string changes mid-loop.  A more sensible method is:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new string[256] = &amp;quot;something long&amp;quot;&lt;br /&gt;
new len = strlen(string)&lt;br /&gt;
for (new i=0; i&amp;lt;len; i++)&lt;br /&gt;
   //...code&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Tips and Tricks==&lt;br /&gt;
===Lookup Tables===&lt;br /&gt;
Precompute what can be precomputed.  For example, say you have a mapping of weapon indices to names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;if (weapon == CSW_AK47)&lt;br /&gt;
   copy(name, len, &amp;quot;weapon_ak47&amp;quot;)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Ignoring the fact that we have &amp;lt;tt&amp;gt;get_weapon_name&amp;lt;/tt&amp;gt; in [[AMX Mod X]], this is inefficient.  We could precompute this result in a table:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new g_WeaponNamesTable[TOTAL_WEAPONS][] = {&lt;br /&gt;
   //..0 to CSW_AK47-1&lt;br /&gt;
   &amp;quot;weapon_ak47&amp;quot;,&lt;br /&gt;
   //..CSW_AK47+1 to TOTAL_WEAPONS-1&lt;br /&gt;
};&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Perfect Hashing===&lt;br /&gt;
:TODO: explain this&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Local Strings===&lt;br /&gt;
The [[Pawn]] compiler does not optimize the DATA section, which stores all hardcoded strings and global arrays.  If you reference the same hardcoded string 500 times in your plugin, it will appear 500 different times.  If this seems bad enough, it actually does this with all strings.  For example, the empty string (&amp;quot;&amp;quot;) appears everywhere in the include files, usually used as a default parameter to many natives.  This too is copied into the data section for each unique reference.  &lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;set_cvar_string(&amp;quot;amx_gaben&amp;quot;, get_cvar_string(&amp;quot;amx_gaben&amp;quot;) + 1)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This will create two copies of &amp;quot;amx_gaben&amp;quot; in the DATA section.  While this doesn't really hurt, it does increase the size of your plugin.  &lt;br /&gt;
&lt;br /&gt;
Similarly, this has the same problem:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#define AMX_GABEN &amp;quot;amx_gaben&amp;quot;&lt;br /&gt;
set_cvar_string(AMX_GABEN, get_cvar_string(AMX_GABEN) + 1)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
The only way to avoid this mess is to use global variables.  As stated earlier, they're basically free storage.&lt;br /&gt;
&amp;lt;pawn&amp;gt;new AMX_GABEN[] = &amp;quot;amx_gaben&amp;quot;&lt;br /&gt;
set_cvar_string(AMX_GABEN, get_cvar_string(AMX_GABEN) + 1)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, while not necessary, this will reduce your plugin's size in memory and on disk.  If you're already using defines, you can make this switch easily.&lt;br /&gt;
&lt;br /&gt;
In order to prevent this from changing, you may want to declare it constant:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;new const AMX_GABEN[] = &amp;quot;amx_gaben&amp;quot;&lt;br /&gt;
set_cvar_string(AMX_GABEN, get_cvar_string(AMX_GABEN) + 1)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now it is a perfectly safe method of storage.&lt;br /&gt;
&lt;br /&gt;
==Faster Natives==&lt;br /&gt;
AMX Mod X replaces many of the old AMX Mod natives with faster versions.  Read below to discover them.&lt;br /&gt;
&lt;br /&gt;
===Cvar Pointers===&lt;br /&gt;
As of AMX Mod X 1.70, you can cache &amp;quot;cvar pointers&amp;quot;.  These are direct accesses to cvars, rather than named access.  This is a critical optimization which is dozens of times faster.  For example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new g_enabled = register_cvar(&amp;quot;csdm_enabled&amp;quot;, &amp;quot;1&amp;quot;)&lt;br /&gt;
//OR&lt;br /&gt;
new g_enabled = get_cvar_pointer(&amp;quot;csdm_enabled&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
stock SetCSDM(num)&lt;br /&gt;
   set_pcvar_num(g_enabled, num)&lt;br /&gt;
&lt;br /&gt;
stock GetCSDM()&lt;br /&gt;
   return get_pcvar_num(g_enabled)&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
All of the cvar* functions (except for set_cvar_string) are mapped to [get|set]_pcvar_*.  You can get a cached cvar pointer with get_cvar_pointer() or register_cvar().&lt;br /&gt;
&lt;br /&gt;
===FormatEX===&lt;br /&gt;
As of AMX Mod X 1.70, there is an ultra high-speed version of format() called formatex().  It skips copy-back checking, unlike format().  formatex() cannot be used if a source input is the same as the output buffer.  For example, these are invalid:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new buffer[255]&lt;br /&gt;
formatex(buffer, 254, &amp;quot;%s&amp;quot;, buffer);&lt;br /&gt;
formatex(buffer, 254, buffer);&lt;br /&gt;
formatex(buffer, 254, &amp;quot;%d %s&amp;quot;, buffer[2]);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It should be noted that format() will behave the same as formatex() if it detects that there will be no copy-back needed.  However, formatex() does not check this, and thus is slightly faster for situations where the coder is sure of its usage.&lt;br /&gt;
&lt;br /&gt;
===File Writing===&lt;br /&gt;
As of AMX Mod X 1.70, there are new natives for file writing.  Read_file and write_file are O(n^2) functions for consecutive read/writes.  fopen(), fgets(), fputs(), and fclose() are O(n) (or better) depending on how you use them.&lt;br /&gt;
&lt;br /&gt;
[[Category:Scripting (AMX Mod X)]]&lt;/div&gt;</summary>
		<author><name>Belsebub</name></author>
		
	</entry>
</feed>