<?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=Kristi</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=Kristi"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/Kristi"/>
	<updated>2026-05-28T15:16:27Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Optimizing_Plugins_(AMX_Mod_X_Scripting)&amp;diff=10449</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=10449"/>
		<updated>2017-08-30T21:30:43Z</updated>

		<summary type="html">&lt;p&gt;Kristi: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LanguageSwitch}}&lt;br /&gt;
&lt;br /&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;
} else if (team == TEAM_SPECTATOR) {&lt;br /&gt;
    //...code&lt;br /&gt;
}&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;
===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, &amp;quot;h&amp;quot;)&lt;br /&gt;
for (new i=0; i&amp;lt;num; i++)&lt;br /&gt;
{&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 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;
   team = get_user_team(player)&lt;br /&gt;
   set_user_frags(player, 0)&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 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_num(&amp;quot;amx_gaben&amp;quot;, get_cvar_num(&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_num(AMX_GABEN, get_cvar_num(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_num(AMX_GABEN, get_cvar_num(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_num(AMX_GABEN, get_cvar_num(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, charsmax(buffer), &amp;quot;%s&amp;quot;, buffer);&lt;br /&gt;
formatex(buffer, charsmax(buffer), buffer);&lt;br /&gt;
formatex(buffer, charsmax(buffer), &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>Kristi</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Button_constants_(AMX_Mod_X)&amp;diff=10448</id>
		<title>Button constants (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Button_constants_(AMX_Mod_X)&amp;diff=10448"/>
		<updated>2017-08-30T20:56:45Z</updated>

		<summary type="html">&lt;p&gt;Kristi: /* Constants */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LanguageSwitch}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
Button constants are generally used to determine when an entity is doing a certain action, such as jumping, attacking, or moving. This is used because +/- commands cannot be hooked by the HL engine (if they are made by the HL engine).&lt;br /&gt;
&lt;br /&gt;
For example, this would work:&lt;br /&gt;
&amp;lt;pawn&amp;gt;register_concmd(&amp;quot;+explode&amp;quot;,&amp;quot;explode&amp;quot;);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
However this would not:&lt;br /&gt;
&amp;lt;pawn&amp;gt;register_concmd(&amp;quot;+attack&amp;quot;,&amp;quot;hook_attack&amp;quot;);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Constants==&lt;br /&gt;
&lt;br /&gt;
A full list of constants can be found [http://amxmodx.org/api/hlsdk_const#pev-entity-pev-button-or-pev-entity-pev-oldbuttons-values/ here].&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
If, for example, it is desired to check when a player is attacking, one would use the following:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;engine&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Attack Test&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Hawk552&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public client_PreThink(id)&lt;br /&gt;
{&lt;br /&gt;
	if(entity_get_int(id,EV_INT_BUTTON) &amp;amp; IN_ATTACK)&lt;br /&gt;
	{&lt;br /&gt;
		// do something&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how this uses the &amp;amp; operator, rather than the &amp;amp;&amp;amp; operator. This is because a bit value is returned, and the &amp;amp; operator checks if a bit value is contained in another bit value.&lt;br /&gt;
&lt;br /&gt;
To set an entity's button, the same type of idea can be implemented:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;engine&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Attack Test&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Hawk552&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public client_PreThink(id)&lt;br /&gt;
{&lt;br /&gt;
	entity_set_int(id,EV_INT_button,IN_ATTACK);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This sets the client's attack flag to ''on'' every time a frame is rendered. &lt;br /&gt;
&lt;br /&gt;
To get an entity's buttons, and then ommit a certain button, one would use the following:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;engine&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Attack Test&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Hawk552&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public client_PreThink(id)&lt;br /&gt;
{&lt;br /&gt;
	entity_set_int(id,EV_INT_button,entity_get_int(id,EV_INT_button) &amp;amp; ~IN_ATTACK);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Say, for example, during a certain time, the client is jumping and attacking at the same time. In this case, the entity_get_int(id,EV_INT_button) function would return IN_ATTACK and IN_JUMP. Using the ~ operator removes the certain bit value, making it into merely IN_JUMP.&lt;br /&gt;
&lt;br /&gt;
There are many more ways to use button constants, and not all must be used on players. They are simply more commonly implemented when dealing with players.&lt;br /&gt;
&lt;br /&gt;
[[Category:Scripting (AMX Mod X)]]&lt;/div&gt;</summary>
		<author><name>Kristi</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=HamSandwich_General_Usage_(AMX_Mod_X)&amp;diff=10447</id>
		<title>HamSandwich General Usage (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=HamSandwich_General_Usage_(AMX_Mod_X)&amp;diff=10447"/>
		<updated>2017-08-30T20:42:05Z</updated>

		<summary type="html">&lt;p&gt;Kristi: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== About Ham Sandwich ==&lt;br /&gt;
Ham Sandwich is a module that provides additional hooking and function calling capabilities to [[AMX Mod X]].&lt;br /&gt;
&lt;br /&gt;
Instead of hooking and executing Half-Life engine calls, like the modules FakeMeta and Engine do, this hooks and executes virtual function calls.&lt;br /&gt;
&lt;br /&gt;
=== What is a virtual function? ===&lt;br /&gt;
A virtual function is a member function of a class in C++.  In the case of Ham Sandwich, the virtual function would be a member function of a game entity.  The virtual functions deal with various events in game, such as damage, and using entities.&lt;br /&gt;
&lt;br /&gt;
Unlike normal member functions, virtual functions can be changed by class derivatives.  For example, a typical hierarchy of entities in Half-Life game dlls look something like this:&lt;br /&gt;
 CBaseEntity&lt;br /&gt;
    CBaseAnimating&lt;br /&gt;
       CBaseMonster&lt;br /&gt;
          CZombie&lt;br /&gt;
          CHeadCrab&lt;br /&gt;
          CBarnacle&lt;br /&gt;
          CBasePlayer&lt;br /&gt;
             CBot&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now for example, if CBaseEntity has the virtual function called &amp;quot;FunctionA&amp;quot;, and that function does nothing.  But, CBarnacle also declares the function &amp;quot;FunctionA&amp;quot;, and instead of doing nothing it causes the barnacle to die.&lt;br /&gt;
&lt;br /&gt;
If something like this were to be executed:&lt;br /&gt;
 CBaseEntity *ent=GET_PRIVATE(entity);&lt;br /&gt;
  ent-&amp;gt;FunctionA();&lt;br /&gt;
&lt;br /&gt;
And the entity were a barnacle, the barnacle would die.  If the entity was a zombie, nothing would happen.&lt;br /&gt;
&lt;br /&gt;
=== What are some limitations? ===&lt;br /&gt;
&lt;br /&gt;
Dealing with virtual functions have a couple minor drawbacks.&lt;br /&gt;
==== Custom Entities ====&lt;br /&gt;
Hooking virtual functions, such as TakeDamage, that get called on custom entities is a little bit awkward.&lt;br /&gt;
&lt;br /&gt;
Because of the way where classes derive, and they get their own virtual table for each class, the type of class that the game dll allocates will be whatever gets hooked for a particular hook.&lt;br /&gt;
&lt;br /&gt;
For example, say you have a plugin like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;fakemeta&amp;gt;&lt;br /&gt;
#include &amp;lt;hamsandwich&amp;gt;&lt;br /&gt;
&lt;br /&gt;
new myStr;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    myStr = engfunc( EngFunc_AllocString, &amp;quot;info_target&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
    register_clcmd( &amp;quot;make_entity&amp;quot;, &amp;quot;cmdMakeEntity&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
    RegisterHam(Ham_TakeDamage, &amp;quot;MyEntityClass&amp;quot;, &amp;quot;damageHook&amp;quot;); // Error!&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public cmdMakeEntity( id )&lt;br /&gt;
{&lt;br /&gt;
    new ent = engfunc( EngFunc_CreateEntity, myStr );&lt;br /&gt;
    set_pev( ent, pev_classname, &amp;quot;MyEntityClass&amp;quot; );&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
That will not work, because the class &amp;quot;MyEntityClass&amp;quot; is not native to the gamedll.  Instead, you would need to hook TakeDamage for &amp;quot;info_target&amp;quot;, and do some form of parsing on the entities that get passed to it (such as checking classname), if you want to deal with custom entity hooking.&lt;br /&gt;
&lt;br /&gt;
==== End of Chain Derivatives ====&lt;br /&gt;
The normal way virtual functions get called is by a virtual table that resides somewhere in the class.  A magical index is assigned to each function, and then it looks up the function pointer inside of the virtual table, and executes the required function.&lt;br /&gt;
&lt;br /&gt;
However, compilers are smart enough to optimize away the virtual function lookup if it knows two things about a call:&lt;br /&gt;
* The exact class type of the entity.&lt;br /&gt;
* That the entity is not derived any further.&lt;br /&gt;
&lt;br /&gt;
An example would be using the hierarchy shown earlier.  If, inside of &amp;lt;code&amp;gt;CBot::TakeDamage&amp;lt;/code&amp;gt; a call to the virtual function &amp;lt;code&amp;gt;CBot::Killed&amp;lt;/code&amp;gt; is made, most compilers will optimize the virtual function lookup out, so that &amp;lt;code&amp;gt;CBot::TakeDamage&amp;lt;/code&amp;gt; would then directly call &amp;lt;code&amp;gt;CBot::Killed&amp;lt;/code&amp;gt;.  This means that the hook would never be called.&lt;br /&gt;
&lt;br /&gt;
Fortunately, these instances are kind of rare.&lt;br /&gt;
&lt;br /&gt;
==== Config File Requirements ====&lt;br /&gt;
Every hook and every &amp;lt;code&amp;gt;ExecuteHam()&amp;lt;/code&amp;gt; call requires an entry for the function which the scripter is attempting to hook or execute.  The function needs to be in the amxmodx/configs/hamdata.ini config file, under the game mod and operating system.&lt;br /&gt;
&lt;br /&gt;
If a function that the script attempts to hook or call is not configured in the hamdata.ini file, then the module will cause the plugin to cease operation, as this is a fatal error.&lt;br /&gt;
&lt;br /&gt;
The fatal errors can be filtered out by including a forward in the script called &amp;lt;code&amp;gt;HamFilter&amp;lt;/code&amp;gt;.  This is similar to native/module filters available inside of the core of amxmodx, whenever a fatal error occurs, it will pass along the parameters to &amp;lt;code&amp;gt;HamFilter&amp;lt;/code&amp;gt;, and if &amp;lt;code&amp;gt;HamFilter&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;PLUGIN_HANDLED&amp;lt;/code&amp;gt;, the error will be ignored (but the attempted hook or execution will not take place).  If the forward does not exist, or if it returns something other than &amp;lt;code&amp;gt;PLUGIN_HANDLED&amp;lt;/code&amp;gt;, the plugin will fail.&lt;br /&gt;
&lt;br /&gt;
An example layout for HamFilter:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public HamFilter(Ham:which, HamError:err, const reason[])&lt;br /&gt;
{&lt;br /&gt;
    // Ignore an unconfigured ns_awardkill&lt;br /&gt;
    if (which == Ham_NS_AwardKill &amp;amp;&amp;amp; err == HAM_FUNC_NOT_CONFIGURED)&lt;br /&gt;
    {&lt;br /&gt;
        return PLUGIN_HANDLED;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // We absolutely need to be able to use cs_roundrespawn!&lt;br /&gt;
    // If we can't, then the plugin cannot continue.&lt;br /&gt;
    if (which == Ham_CS_RoundRespawn)&lt;br /&gt;
    {&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Additionally, you can check to see if a function is valid to execute or hook by using the &amp;lt;code&amp;gt;IsHamValid()&amp;lt;/code&amp;gt; native.  The validity of a function is determined when the module is first loaded, and it will never change, so if you want to check it, there is no need to do so before every execute.&lt;br /&gt;
&lt;br /&gt;
== Supported Mods ==&lt;br /&gt;
=== Mostly Supported ===&lt;br /&gt;
These mods have a very large list of functions that are usable in the module. &lt;br /&gt;
* Counter-Strike 1.6&lt;br /&gt;
* Condition Zero&lt;br /&gt;
* Day of Defeat&lt;br /&gt;
* Team Fortress Classic&lt;br /&gt;
* The Specialists&lt;br /&gt;
* Natural-Selection&lt;br /&gt;
&lt;br /&gt;
=== Weakly Supported ===&lt;br /&gt;
Because these mods do not contain a Linux binary, they are much harder to disassemble.&lt;br /&gt;
* Sven-Coop&lt;br /&gt;
* Earth's Special Forces&lt;br /&gt;
&lt;br /&gt;
== Hooking Functions ==&lt;br /&gt;
The big feature for Ham Sandwich is the ability to hook virtual functions.&lt;br /&gt;
&lt;br /&gt;
=== Creating the Hook ===&lt;br /&gt;
Creating a hook is a lot like creating a hook in Fakemeta.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;hamsandwich&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    RegisterHam(Ham_TakeDamage, &amp;quot;player&amp;quot;, &amp;quot;player_hurt&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public player_hurt(this, inflictor, attacker, Float:damage, damagebits)&lt;br /&gt;
{&lt;br /&gt;
    // Stuff...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This creates a basic hook which is called any time a player takes damage.  Look in '''ham_const.inc''' for forward parameters for each hook.&lt;br /&gt;
&lt;br /&gt;
Like Fakemeta, there is a hidden last parameter.  Set it to 1 to do post hooking.&lt;br /&gt;
&lt;br /&gt;
=== Blocking the Hook ===&lt;br /&gt;
Like Fakemeta and Engine, it is possible to stop a function from being called.  This is called '''superceding'''.&lt;br /&gt;
&lt;br /&gt;
Blocking in Ham Sandwich is identical to how it is accomplished in Fakemeta.  In each hook, you return one of four special values:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;HAM_IGNORED&amp;lt;/code&amp;gt; - Nothing happened, the call continues.&lt;br /&gt;
* &amp;lt;code&amp;gt;HAM_HANDLED&amp;lt;/code&amp;gt; - You did something, but the call continues.&lt;br /&gt;
* &amp;lt;code&amp;gt;HAM_OVERRIDE&amp;lt;/code&amp;gt; - The call will still be executed, but instead you will change the return value.&lt;br /&gt;
* &amp;lt;code&amp;gt;HAM_SUPERCEDE&amp;lt;/code&amp;gt; - The call is not executed, and you use your return value, if applicable.&lt;br /&gt;
&lt;br /&gt;
You can use the native &amp;lt;code&amp;gt;GetHamReturnStatus()&amp;lt;/code&amp;gt; to check the current return status of the hook.&lt;br /&gt;
&lt;br /&gt;
=== Return Values ===&lt;br /&gt;
You can get or change the return values for all the hooks available in Ham Sandwich.  Look in '''ham_const.inc''' for a list of all hooks and their return values.&lt;br /&gt;
&lt;br /&gt;
These natives will get any ''modified'' return values.&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
* native GetHamReturnInteger(&amp;amp;output);&lt;br /&gt;
* native GetHamReturnFloat(&amp;amp;Float:output);&lt;br /&gt;
* native GetHamReturnVector(Float:output[3]);&lt;br /&gt;
* native GetHamReturnEntity(&amp;amp;output);&lt;br /&gt;
* native GetHamReturnString(output[], size);&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These natives will get the ''original'' return value from the function.&lt;br /&gt;
Note that this is '''only''' valid to call in a post hook, it will be undefined to call it at any other time.&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
* native GetOrigHamReturnInteger(&amp;amp;output);&lt;br /&gt;
* native GetOrigHamReturnFloat(&amp;amp;Float:output);&lt;br /&gt;
* native GetOrigHamReturnVector(Float:output[3]);&lt;br /&gt;
* native GetOrigHamReturnEntity(&amp;amp;output);&lt;br /&gt;
* native GetOrigHamReturnString(output[], size);&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These natives will change the return value to whatever you please.&lt;br /&gt;
Note that this will have no effect on the actual return value from the function '''unless''' the return status of the hook is &amp;lt;code&amp;gt;HAM_OVERRIDE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;HAM_SUPERCEDE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
* native SetHamReturnInteger(value);&lt;br /&gt;
* native SetHamReturnFloat(Float:value);&lt;br /&gt;
* native SetHamReturnVector(const Float:value[3]);&lt;br /&gt;
* native SetHamReturnEntity(value);&lt;br /&gt;
* native SetHamReturnString(const value[]);&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Changing Hook Parameters ===&lt;br /&gt;
One feature available in Ham Sandwich that is not available in FakeMeta is the ability to change all parameters on the fly for each hook.&lt;br /&gt;
&lt;br /&gt;
This means that, for example, if you wanted to make a plugin that halved all damage players take, you would do something like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;hamsandwich&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
    RegisterHam(Ham_TakeDamage, &amp;quot;player&amp;quot;, &amp;quot;player_hurt&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public player_hurt(this, inflictor, attacker, Float:damage, damagebits)&lt;br /&gt;
{&lt;br /&gt;
    // Player will now take half damage&lt;br /&gt;
    SetHamParamFloat(4, damage / 2.0);&lt;br /&gt;
    return HAM_HANDLED;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All hooks after the one you change them in will see the modified values.  Hooks are executed in the order in which they are registered.&lt;br /&gt;
&lt;br /&gt;
All available parameter changing natives are:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
* native SetHamParamInteger(which, value);&lt;br /&gt;
* native SetHamParamFloat(which, Float:value);&lt;br /&gt;
* native SetHamParamVector(which, const Float:value[3]);&lt;br /&gt;
* native SetHamParamEntity(which, value);&lt;br /&gt;
* native SetHamParamString(which, const output[]);&lt;br /&gt;
* native SetHamParamTraceResult(which, tr_handle);&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Disabling Hooks ===&lt;br /&gt;
&lt;br /&gt;
Similar to how FakeMeta allows for unregistering of hooks with &amp;lt;code&amp;gt;unregister_forward()&amp;lt;/code&amp;gt;, HamSandwich will allow you to disable and enable hooks whenever you want.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;RegisterHam()&amp;lt;/code&amp;gt; function will return a handle (tagged with &amp;lt;code&amp;gt;HamHook&amp;lt;/code&amp;gt;).  You can then make subsequent calls to &amp;lt;code&amp;gt;DisableHamForward()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;EnableHamForward()&amp;lt;/code&amp;gt; with the handle to stop it from forwarding, or enable its forwards again.&lt;br /&gt;
&lt;br /&gt;
There is no way to completely unregister the hooks (until map change), as deleting a hook is a delicate process.&lt;/div&gt;</summary>
		<author><name>Kristi</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Building_AMX_Mod_X&amp;diff=10446</id>
		<title>Building AMX Mod X</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Building_AMX_Mod_X&amp;diff=10446"/>
		<updated>2017-08-30T19:27:19Z</updated>

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