<?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=Zor</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=Zor"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/Zor"/>
	<updated>2026-05-28T10:09:47Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5515</id>
		<title>Module Writing (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5515"/>
		<updated>2007-12-26T20:22:41Z</updated>

		<summary type="html">&lt;p&gt;Zor: /* Developing Module */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AMX Mod X Modules are written in C or C++ (the API is C compatible).&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
So you want to be a module developer for Amxmodx!  Well its not too hard.  I will be doing this in Windows as I dont have a Linux box to frick around with at the moment.  So, windows only at this point, a Linux version will be forthcoming!&lt;br /&gt;
&lt;br /&gt;
== Necessary Files ==&lt;br /&gt;
Well first we need to gather up the neccessary files for your computer.  The first thing you need to know, its NOT complicated.  If you can script in pawn, you can program in C/C++!&lt;br /&gt;
&lt;br /&gt;
=== Metamod ===&lt;br /&gt;
As we all know metamod is the backbone of the whole thing, without this all mods for and HL game would not be possible unless we programmed it ourselves!  So many thanks to willday for the development of Metamod, and for BAILOPAN and his crew helping to maintain and update it!  Hats off to all!  Ok so now onto the file gathering!  First thing is first we need to goto Metamod: [http://metamod.org/ metamod.org] from there we need to gather up 2 SDK's.&lt;br /&gt;
&lt;br /&gt;
==== HL-SDK ====&lt;br /&gt;
The Half Life SDK is the first thing in the list to gather up!  We can get this at the same spot that we will be gathering up metamod!  So we click on the SDK Link or goto:  [http://metamod.sourceforge.net/files/sdk/ Here].  From here we need to grab the HLSDK, preferably the one that has been tweeked out for Metamod.  So we are looking for this:&lt;br /&gt;
&lt;br /&gt;
 hlsdk-2.3-p3.zip                - The Standard SDK v2.3 with various fixes and&lt;br /&gt;
                                   updates, that Metamod is compiled against.&lt;br /&gt;
                                   Files are in DOS format.&lt;br /&gt;
&lt;br /&gt;
So lets grab the [http://metamod.sourceforge.net/files/sdk/hlsdk-2.3-p3.zip hlsdk-2.3-p3.zip] first!  Once this is done you will need to extract this to your Hard Drive.  What we will be doing is extracting these files to the following directory, these will be arbitray directories for ease of the document so dont sweat it once you proficient you can move them around :-)  Ok so extract the files to the following directory: c:\sdk_files\&lt;br /&gt;
&lt;br /&gt;
==== Metamod SDK ====&lt;br /&gt;
Ok, so we have the HL-SDK we now need to Metamod SDK.  So we need to go back to the root of Metamod &lt;br /&gt;
[http://metamod.org/ here] and then click on the  v1.xx Sourcecode zip to get the latest SDK from Sourceforge, you can get that file from the best location for you or for a quick link click [http://prdownloads.sourceforge.net/metamod/metamod-1.19-win.src.zip?download metamod-1.xx-win.src.zip] to get the files.&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx SDK ==== &lt;br /&gt;
Now we need to grab the last of the SDK's so we can go carry on.  First we need to goto the Amxmodx Website so that we can get to the SDK via the Downloads area and SVN!  [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx.tar.gz?root=amxmodx&amp;amp;view=tar Amxmodx SDK].&lt;br /&gt;
&lt;br /&gt;
==== Unix2Dos the Files ====&lt;br /&gt;
So, once you have all the files we need to fix them up a bit.  One of the things that will become bothersome later is the Unix File Format that HLSDK / Metamod has, its suppose to be Windows, but its not, so we need to convert the files, soooo...we will use the following tutorial to fix this [[GnuWin32]] Once you have that setup you can use the following to repair all files easily [http://wiki.dodplugins.net/images/6/61/Repair.rar Repair.bat].&lt;br /&gt;
&lt;br /&gt;
== Compiler GUI ==&lt;br /&gt;
Now that we have all the SDK files we will need to get the Compiler.  The one that we will be using will be the Microsoft Visual 2005 Express Edition.  &lt;br /&gt;
&lt;br /&gt;
=== Visual C++ 2005 Express Edition ===&lt;br /&gt;
First thing you need to do is grab the web install files:  [http://go.microsoft.com/fwlink/?LinkId=51410&amp;amp;clcid=0x409 Visual C++ 2005 Express Edition] if you want to grab the network install you should grab the following: [http://msdn.microsoft.com/vstudio/express/support/install/ Network Install Files], for network install either grab the [http://go.microsoft.com/fwlink/?linkid=54766 Image File] or the [http://go.microsoft.com/fwlink/?linkid=57034 ISO File] your choice. Ok so now your have the iso/img file you need to either burn it or use a Virtual CD/DVD to install it.  I wont go into detail on this as its pretty simple, but make sure that you only install the Graphical IDE, if you want to you can install the Microsoft MSDN 2005 Express Edition, these are the help files that you can access by hitting F1 once in the GUI, if you haven't downloaded them, thats fine it will connect you to the Online version of them instead.&lt;br /&gt;
&lt;br /&gt;
=== Platform SDK ===&lt;br /&gt;
The platform SDK is a needed piece of kit, without it we wont be able to compile.  You will need to grab it from this site: [http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/ Platform SDK Site].  Specifically you need to grab proper file for your architecture, goto the above page and scroll down to the Files in This Download section.  Download the file that you need and install it.  Make sure to do a custom install unless you dont mind a bunch of crap on your computer.  You want to have only the following items installed:&lt;br /&gt;
&lt;br /&gt;
 Microsoft Windows Core SDK&lt;br /&gt;
 Microsoft Direct Show SDK&lt;br /&gt;
 Microsoft Media Services SDK&lt;br /&gt;
&lt;br /&gt;
=== .NET SDK ===&lt;br /&gt;
Next we need to grab the Dot Net install and the Dot Net SDK.  You can grab the [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=262d25e3-f589-4842-8157-034d1e7cf3a3&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2fa%2fa%2fc%2faac39226-8825-44ce-90e3-bf8203e74006%2fdotnetfx.exe dotnet.1.1.exe] and install it.  Next you will need the .NET SDK, you can grapple [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=9B3A2CA6-3647-4070-9F41-A333C6B9181D&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f5%2f2%2f0%2f5202f918-306e-426d-9637-d7ee26fbe507%2fsetup.exe dotnet.1.1.sdk.exe]  Once these are installed your good to start up the GUI.&lt;br /&gt;
&lt;br /&gt;
== Setting up the GUI ==&lt;br /&gt;
Ok, so now we start up Visual C++, click on Start-&amp;gt;Program Files-&amp;gt;Visual C++ 2005 Express Edition-&amp;gt;Microsoft Visual C++ 2005 Express Edition duh...but just in case :-) allow it to go through the initialization and start up.  Once its started up you will need to do the following:&lt;br /&gt;
&lt;br /&gt;
 Click Tools-&amp;gt;Options&lt;br /&gt;
[[Image:options.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Now expand the Projects and Solutions are by clicking on the + symbol to the left of the name.&lt;br /&gt;
[[Image:pands.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Click on the VC++ Directories.  Now on the top left of that box you will see a drop box that says Show Directories For&lt;br /&gt;
 Click the drop  box and select Include Files.&lt;br /&gt;
[[Image:vc--.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now you need to add the following Directories to this list at the bottom:&lt;br /&gt;
&lt;br /&gt;
 C:\Program Files\Microsoft Platform SDK\Include&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\common&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\dlls&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\engine&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\pm_shared&lt;br /&gt;
 C:\sdk_files\metamod-1.19\metamod&lt;br /&gt;
 C:\sdk_files\amxmodx&lt;br /&gt;
[[Image:Directories.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Message Module ( Demo ) ==&lt;br /&gt;
Right, now that we have the base all good and done, we need to get going with the module.  First thing we need to do is create a new module, for ease of use I have for the moment made up a demo module called [http://www.dodplugins.net/files/dod_mm.zip dod_mm], DoD Message Module.  Grab this and extract it to the c:\sdk_files directory.&lt;br /&gt;
&lt;br /&gt;
=== Editing Module Information ===&lt;br /&gt;
First things first you need to open up the dod_mm.vcproj this will open up Visual C++.  Once its open you will see on the left a dod_mm under the solutions area.  Open moduleconfig.h.  In here we will look for the following:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;--ENTER NAME HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;--ENTER VERSION HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;--ENTER AUTHOR HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;--ENTER URL HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;--ENTER LOGTAG HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;--ENTER LIBRARY HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
This is the infor that will be displayed about the module when you have it running on your server.  Lets say you type in amxx modules in the command line, you will get information about all the modules running on your server, including this one, once its done.  So now we need to edit it to reflect our new module:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;DoD Message Module&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;0.1&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;DoD Plugins Community&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;http://www.dodplugins.net&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;DoDMM&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;dod_mm&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
=== Exposing Functions ===&lt;br /&gt;
So now that this is done we need to tell the module to use Metamod Natives, this is done by finding the followin:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 // #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
And changing it to:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
Or in other words uncommenting it.  :-)  So now that this is done we have access to loads of stuff that metamod has to offer us as well as Amxmodx stuff.  Once this is done we now need to expose the functions from metamod that we will be using for this message module.  &lt;br /&gt;
&lt;br /&gt;
==== Amxmodx ====&lt;br /&gt;
If you scroll down you will find the following two functions from amxmodx that we will be using:&lt;br /&gt;
&lt;br /&gt;
 /** AMXX attach&lt;br /&gt;
  * Do native functions init here (MF_AddNatives)&lt;br /&gt;
  */&lt;br /&gt;
 // #define FN_AMXX_ATTACH OnAmxxAttach&lt;br /&gt;
 &lt;br /&gt;
 /** AMXX Detach (unload) */&lt;br /&gt;
 // #define FN_AMXX_DETACH OnAmxxDetach&lt;br /&gt;
&lt;br /&gt;
We will expose these by uncommenting them.  Later on in this document I will explain where the function itself goes and what goes in them.&lt;br /&gt;
&lt;br /&gt;
==== HL API ====&lt;br /&gt;
Next we will expose some of the functions that come from the HL Server Engine that Metamod has exposed for us.  The functions that we are exposing are ones that we will need specific to messages:&lt;br /&gt;
&lt;br /&gt;
 #define FN_MessageBegin_Post					MessageBegin_Post&lt;br /&gt;
 #define FN_MessageEnd_Post					MessageEnd_Post&lt;br /&gt;
 #define FN_WriteByte_Post					WriteByte_Post&lt;br /&gt;
 #define FN_WriteChar_Post					WriteChar_Post&lt;br /&gt;
 #define FN_WriteShort_Post					WriteShort_Post&lt;br /&gt;
 #define FN_WriteLong_Post					WriteLong_Post&lt;br /&gt;
 #define FN_WriteAngle_Post					WriteAngle_Post&lt;br /&gt;
 #define FN_WriteCoord_Post					WriteCoord_Post&lt;br /&gt;
 #define FN_WriteString_Post					WriteString_Post&lt;br /&gt;
 #define FN_WriteEntity_Post					WriteEntity_Post&lt;br /&gt;
&lt;br /&gt;
These are the actual messages that will be caught.  Finally we need to catch the registering of those messages we can see in [http://wiki.dodplugins.net/index.php/Meta_Game Meta Game].  This is the function we are going to expose next:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Now that all the functions that we will be using have been exposed we are good to carry on with the meat of the module.&lt;br /&gt;
&lt;br /&gt;
=== Developing Module ===&lt;br /&gt;
Right on, now we have the basics down.  We are ready to start programming.  So we need a main file now.  So now we need to right click on the dod_mm and goto Add-&amp;gt;New Item as shown in the picture below:&lt;br /&gt;
&lt;br /&gt;
[[Image:adding_item.jpg]]&lt;br /&gt;
&lt;br /&gt;
Once thats done a new window comes up, we need to click on code, then Header File (.h) giving it the name main.h&lt;br /&gt;
&lt;br /&gt;
[[Image:main_header.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now we have a file to work with.  So, we need to first set it up as a standard Header file so that it is only included once into memory.  So we add the following:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
So this will ensure that all the code we put between those two comments are only loaded once into the compilation process.  Now that we have this part complete we will start coding.  As we are making a module to catch all the Messages that occur on a HL DoD Server the first thing we need to do is create a structure to keep all the data that we will use.  This structure will be called StructUserMsg and will contain two members the id of the message which can be anything from 0 - 256 messages and the name of the message.  We can get these names from [http://wiki.dodplugins.net/index.php/Meta_Game Meta Game].  These will be the messages that will pop up.  Now that we have this done the file should look like so:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
      #include &amp;quot;sdk/amxxmodule.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
      struct StructUserMsg &lt;br /&gt;
      {&lt;br /&gt;
            int id;&lt;br /&gt;
            char name[256];&lt;br /&gt;
      };&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
==== CPP File ====&lt;br /&gt;
So now that we have the structure done the first thing we have to do is make a CPP file the same as we did the Header file except with a CPP.  We will name this file the same as the Header that we created as this cpp will call the header to get its information.  Once we have created the file the first thing we need to do is call the header file by adding this to the top:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;main.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
That will ensure to grab our structure so the rest of the program knows what it is.  Once this is done we need to create a few global variables to use.  The first one we will use is one that will allow us to output to a file all the data that we are gathering:&lt;br /&gt;
&lt;br /&gt;
 FILE *stream;&lt;br /&gt;
&lt;br /&gt;
Next we need a global state variable so that we know what call we are on within the message.  This will count all the calls to each specific message:&lt;br /&gt;
&lt;br /&gt;
 int g_state;&lt;br /&gt;
&lt;br /&gt;
Now finally we need to create the global variable for the structure we created:&lt;br /&gt;
&lt;br /&gt;
 StructUserMsg g_user_msg[MAX_REG_MSGS];&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx Functions Created ====&lt;br /&gt;
So this is most important.  We created a StructUserMsg array of MAX_REG_MSGS in length, this is 256.  Ok we are good now on the globals.  Pretty simple.  Now remember those functions we exposed, well we need to create those functions so that Amxmodx will call them.  First we will look at the Amxmodx functions:&lt;br /&gt;
&lt;br /&gt;
 void OnAmxxAttach()&lt;br /&gt;
 {&lt;br /&gt;
      fopen_s(&amp;amp;stream, &amp;quot;messages.txt&amp;quot;, &amp;quot;w&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void OnAmxxDetach()&lt;br /&gt;
 {&lt;br /&gt;
      fclose(stream);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
So now that these are created lets understand them.  When amxmodx starts up and calls the module we are creating the OnAmxxAttach is the first thing that is called, in our case we are opening up a file called messages.txt that will be in the base HL directory.  This will contain all the output from our module.  &lt;br /&gt;
&lt;br /&gt;
 '''*** NOTE *** This will take up alot of room, so be carefull'''&lt;br /&gt;
&lt;br /&gt;
Ok, the second function is just the opposite, when amxmodx closes this is the last function called, so we want to close the file.&lt;br /&gt;
&lt;br /&gt;
==== Metamod HL API Functions Created ====&lt;br /&gt;
Now onward.  The Amxmodx functions are complete now we need to create the functions for the Metamod / HL API.  First we will create the most important function the registration function, in order to understand the funtions we first need to know what we are looking for.  So we exposed the following:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Ok so what the hell is this???  Well if you highlight and copy FN_RegUserMsg_Post then open up amxxmodule.h and do a search for '''FN_RegUserMsg_Post''' you will find the following:&lt;br /&gt;
&lt;br /&gt;
 #ifdef FN_RegUserMsg_Post&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
 #endif // FN_RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
This is where we get the function declaration from.  So we copy the following:&lt;br /&gt;
&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
&lt;br /&gt;
And make a function out of it as such:&lt;br /&gt;
&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Now this is the start of our function.  You notice the RETURN_META_VALUE, this is a metamod return, because the function is returning an int we need to tell metamod to ignore what we have done with this function and return an integer.  This is what this means.  One of the others we will be returning alot is as follows:&lt;br /&gt;
&lt;br /&gt;
 RETURN_META(MRES_IGNORED);&lt;br /&gt;
&lt;br /&gt;
This is what we use when a function returns a void or nothing.  This function is pretty basic.  First thing we are going to do is grab the original return value that we would have gotten if we wanted to do stuff with this function.  In this case it is the message id:&lt;br /&gt;
&lt;br /&gt;
 int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
&lt;br /&gt;
Next we are going to assign the message id to our message structure at the location of the message id...bit confusing but important:&lt;br /&gt;
&lt;br /&gt;
 g_user_msg[msgid].id = msgid;&lt;br /&gt;
&lt;br /&gt;
Finally we are going to assign the message name to the message structure using a string copy:&lt;br /&gt;
&lt;br /&gt;
 strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
&lt;br /&gt;
Ok now we have the register function done it will look like so when done:&lt;br /&gt;
&lt;br /&gt;
 // First thing when all the messages are sent out to a client we grab them and take a look at them&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
      g_user_msg[msgid].id = msgid;&lt;br /&gt;
      strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to worry about the next important function, the message begins function.  This is called when a message is initialized on the server to be sent out to someone somewhere.  It looks like this:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Voila...now this is very important part because this is where and when the message begins...remember we can '''NEVER''' call another message_begin while we are in a message...so we have to wait until after when we hit message_end.  Now we are going to add some stuff to this to make it work.  First we want to make sure that its not a bogus or bad message:&lt;br /&gt;
&lt;br /&gt;
 if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
 {&lt;br /&gt;
      g_state = -1;&lt;br /&gt;
      RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
If it is we bounce out of this message.  If not then its a good message and we want to carry on.  Next thing we do is print out that we are in the message beginning to both the console and the file:&lt;br /&gt;
&lt;br /&gt;
 // Log the message Name&lt;br /&gt;
 printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
&lt;br /&gt;
As you can see we are printing out the message id the message name that we stored in our structure earlier.  Once this is done we will check the message destination and print that out as well.  There are 3 places a message could be going 0 = all, 1 - 32 is Individually to a player, and 33 - MAX_REG_MSGS is all others.  So we will tell which it is with the following:&lt;br /&gt;
&lt;br /&gt;
 // Is it too all, or to an individual&lt;br /&gt;
 if(msg_dest == 0)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
       if(player)&lt;br /&gt;
       {&lt;br /&gt;
              int id = ENTINDEX(player);&lt;br /&gt;
              const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
              const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
              printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
              fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
       }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Self explanatory, finally we need to set the global variable g_state to zero:&lt;br /&gt;
&lt;br /&gt;
 g_state = 0;&lt;br /&gt;
&lt;br /&gt;
So this funtion is done.  Here is the end result:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
      {&lt;br /&gt;
            g_state = -1;&lt;br /&gt;
            RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      // Log the message Name&lt;br /&gt;
      printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
      fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 &lt;br /&gt;
      // Is it too all, or to an individual&lt;br /&gt;
      if(msg_dest == 0)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
            if(player)&lt;br /&gt;
            {&lt;br /&gt;
                  int id = ENTINDEX(player);&lt;br /&gt;
                  const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
                  const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
                  printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
                  fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
            }&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      g_state = 0;&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ok from here on out it will be a bit repetitive so I will just show them too you:&lt;br /&gt;
&lt;br /&gt;
 void WriteByte_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteChar_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      char buffer[10];&lt;br /&gt;
      _itoa_s(iValue, buffer, 10);&lt;br /&gt;
      printf(&amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteShort_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteLong_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteAngle_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteCoord_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteString_Post(const char *sz) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteEntity_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The last but not least function is the message end function.  It too is simple to understand:&lt;br /&gt;
&lt;br /&gt;
 void MessageEnd_Post(void) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
      fprintf(stream, &amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
      fflush(stream);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The only thing weird about this one is the flush...this just ensures the data we just collected gets sent to the file.  Well thats it...we're done...all thats left is the compile and moving the module to the addons/amxmodx/modules/ directory then adding it to the addons/amxmodx/configs/modules.ini file at the bottom.  Remember to name it dod_mm not dod_mm_amxx.dll just the first part.&lt;br /&gt;
&lt;br /&gt;
== In Conclusion ==&lt;br /&gt;
&lt;br /&gt;
Ok we are setup to start compiling, you can grab the source code to any of the modules at amxmodx and compile them now...or just play about.  I suggest you try the easy one that you can grab here: [http://forums.alliedmods.net/showthread.php?t=18763  ESF Model Changing Module] just to look at it.  Here is the direct download: [http://forums.alliedmods.net/attachment.php?attachmentid=4104&amp;amp;d=1128187905 esf_model_changer]&lt;br /&gt;
&lt;br /&gt;
The files for this project can be found [http://www.dodplugins.net/forums/showthread.php?p=2471 DoD Message Module Tutorial / Module]&lt;br /&gt;
&lt;br /&gt;
I have made great use of this in helping in developing dodx and dodfun.&lt;br /&gt;
&lt;br /&gt;
Cheers!&lt;br /&gt;
Zor&lt;br /&gt;
&lt;br /&gt;
For more information, look in: [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx /svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx] or [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk.tar.gz?root=amxmodx&amp;amp;view=tar click here] to download a tarball of that directory.&lt;br /&gt;
&lt;br /&gt;
Copy these files into a new folder.  The amxxmodule.h/cpp files are the Module SDK backend.  You only need to edit the moduleconfig.h file to customize your module.&lt;br /&gt;
&lt;br /&gt;
[[Category:AMX_Mod_X]]&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5514</id>
		<title>Module Writing (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5514"/>
		<updated>2007-12-26T20:21:27Z</updated>

		<summary type="html">&lt;p&gt;Zor: /* HL API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AMX Mod X Modules are written in C or C++ (the API is C compatible).&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
So you want to be a module developer for Amxmodx!  Well its not too hard.  I will be doing this in Windows as I dont have a Linux box to frick around with at the moment.  So, windows only at this point, a Linux version will be forthcoming!&lt;br /&gt;
&lt;br /&gt;
== Necessary Files ==&lt;br /&gt;
Well first we need to gather up the neccessary files for your computer.  The first thing you need to know, its NOT complicated.  If you can script in pawn, you can program in C/C++!&lt;br /&gt;
&lt;br /&gt;
=== Metamod ===&lt;br /&gt;
As we all know metamod is the backbone of the whole thing, without this all mods for and HL game would not be possible unless we programmed it ourselves!  So many thanks to willday for the development of Metamod, and for BAILOPAN and his crew helping to maintain and update it!  Hats off to all!  Ok so now onto the file gathering!  First thing is first we need to goto Metamod: [http://metamod.org/ metamod.org] from there we need to gather up 2 SDK's.&lt;br /&gt;
&lt;br /&gt;
==== HL-SDK ====&lt;br /&gt;
The Half Life SDK is the first thing in the list to gather up!  We can get this at the same spot that we will be gathering up metamod!  So we click on the SDK Link or goto:  [http://metamod.sourceforge.net/files/sdk/ Here].  From here we need to grab the HLSDK, preferably the one that has been tweeked out for Metamod.  So we are looking for this:&lt;br /&gt;
&lt;br /&gt;
 hlsdk-2.3-p3.zip                - The Standard SDK v2.3 with various fixes and&lt;br /&gt;
                                   updates, that Metamod is compiled against.&lt;br /&gt;
                                   Files are in DOS format.&lt;br /&gt;
&lt;br /&gt;
So lets grab the [http://metamod.sourceforge.net/files/sdk/hlsdk-2.3-p3.zip hlsdk-2.3-p3.zip] first!  Once this is done you will need to extract this to your Hard Drive.  What we will be doing is extracting these files to the following directory, these will be arbitray directories for ease of the document so dont sweat it once you proficient you can move them around :-)  Ok so extract the files to the following directory: c:\sdk_files\&lt;br /&gt;
&lt;br /&gt;
==== Metamod SDK ====&lt;br /&gt;
Ok, so we have the HL-SDK we now need to Metamod SDK.  So we need to go back to the root of Metamod &lt;br /&gt;
[http://metamod.org/ here] and then click on the  v1.xx Sourcecode zip to get the latest SDK from Sourceforge, you can get that file from the best location for you or for a quick link click [http://prdownloads.sourceforge.net/metamod/metamod-1.19-win.src.zip?download metamod-1.xx-win.src.zip] to get the files.&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx SDK ==== &lt;br /&gt;
Now we need to grab the last of the SDK's so we can go carry on.  First we need to goto the Amxmodx Website so that we can get to the SDK via the Downloads area and SVN!  [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx.tar.gz?root=amxmodx&amp;amp;view=tar Amxmodx SDK].&lt;br /&gt;
&lt;br /&gt;
==== Unix2Dos the Files ====&lt;br /&gt;
So, once you have all the files we need to fix them up a bit.  One of the things that will become bothersome later is the Unix File Format that HLSDK / Metamod has, its suppose to be Windows, but its not, so we need to convert the files, soooo...we will use the following tutorial to fix this [[GnuWin32]] Once you have that setup you can use the following to repair all files easily [http://wiki.dodplugins.net/images/6/61/Repair.rar Repair.bat].&lt;br /&gt;
&lt;br /&gt;
== Compiler GUI ==&lt;br /&gt;
Now that we have all the SDK files we will need to get the Compiler.  The one that we will be using will be the Microsoft Visual 2005 Express Edition.  &lt;br /&gt;
&lt;br /&gt;
=== Visual C++ 2005 Express Edition ===&lt;br /&gt;
First thing you need to do is grab the web install files:  [http://go.microsoft.com/fwlink/?LinkId=51410&amp;amp;clcid=0x409 Visual C++ 2005 Express Edition] if you want to grab the network install you should grab the following: [http://msdn.microsoft.com/vstudio/express/support/install/ Network Install Files], for network install either grab the [http://go.microsoft.com/fwlink/?linkid=54766 Image File] or the [http://go.microsoft.com/fwlink/?linkid=57034 ISO File] your choice. Ok so now your have the iso/img file you need to either burn it or use a Virtual CD/DVD to install it.  I wont go into detail on this as its pretty simple, but make sure that you only install the Graphical IDE, if you want to you can install the Microsoft MSDN 2005 Express Edition, these are the help files that you can access by hitting F1 once in the GUI, if you haven't downloaded them, thats fine it will connect you to the Online version of them instead.&lt;br /&gt;
&lt;br /&gt;
=== Platform SDK ===&lt;br /&gt;
The platform SDK is a needed piece of kit, without it we wont be able to compile.  You will need to grab it from this site: [http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/ Platform SDK Site].  Specifically you need to grab proper file for your architecture, goto the above page and scroll down to the Files in This Download section.  Download the file that you need and install it.  Make sure to do a custom install unless you dont mind a bunch of crap on your computer.  You want to have only the following items installed:&lt;br /&gt;
&lt;br /&gt;
 Microsoft Windows Core SDK&lt;br /&gt;
 Microsoft Direct Show SDK&lt;br /&gt;
 Microsoft Media Services SDK&lt;br /&gt;
&lt;br /&gt;
=== .NET SDK ===&lt;br /&gt;
Next we need to grab the Dot Net install and the Dot Net SDK.  You can grab the [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=262d25e3-f589-4842-8157-034d1e7cf3a3&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2fa%2fa%2fc%2faac39226-8825-44ce-90e3-bf8203e74006%2fdotnetfx.exe dotnet.1.1.exe] and install it.  Next you will need the .NET SDK, you can grapple [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=9B3A2CA6-3647-4070-9F41-A333C6B9181D&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f5%2f2%2f0%2f5202f918-306e-426d-9637-d7ee26fbe507%2fsetup.exe dotnet.1.1.sdk.exe]  Once these are installed your good to start up the GUI.&lt;br /&gt;
&lt;br /&gt;
== Setting up the GUI ==&lt;br /&gt;
Ok, so now we start up Visual C++, click on Start-&amp;gt;Program Files-&amp;gt;Visual C++ 2005 Express Edition-&amp;gt;Microsoft Visual C++ 2005 Express Edition duh...but just in case :-) allow it to go through the initialization and start up.  Once its started up you will need to do the following:&lt;br /&gt;
&lt;br /&gt;
 Click Tools-&amp;gt;Options&lt;br /&gt;
[[Image:options.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Now expand the Projects and Solutions are by clicking on the + symbol to the left of the name.&lt;br /&gt;
[[Image:pands.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Click on the VC++ Directories.  Now on the top left of that box you will see a drop box that says Show Directories For&lt;br /&gt;
 Click the drop  box and select Include Files.&lt;br /&gt;
[[Image:vc--.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now you need to add the following Directories to this list at the bottom:&lt;br /&gt;
&lt;br /&gt;
 C:\Program Files\Microsoft Platform SDK\Include&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\common&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\dlls&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\engine&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\pm_shared&lt;br /&gt;
 C:\sdk_files\metamod-1.19\metamod&lt;br /&gt;
 C:\sdk_files\amxmodx&lt;br /&gt;
[[Image:Directories.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Message Module ( Demo ) ==&lt;br /&gt;
Right, now that we have the base all good and done, we need to get going with the module.  First thing we need to do is create a new module, for ease of use I have for the moment made up a demo module called [http://www.dodplugins.net/files/dod_mm.zip dod_mm], DoD Message Module.  Grab this and extract it to the c:\sdk_files directory.&lt;br /&gt;
&lt;br /&gt;
=== Editing Module Information ===&lt;br /&gt;
First things first you need to open up the dod_mm.vcproj this will open up Visual C++.  Once its open you will see on the left a dod_mm under the solutions area.  Open moduleconfig.h.  In here we will look for the following:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;--ENTER NAME HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;--ENTER VERSION HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;--ENTER AUTHOR HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;--ENTER URL HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;--ENTER LOGTAG HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;--ENTER LIBRARY HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
This is the infor that will be displayed about the module when you have it running on your server.  Lets say you type in amxx modules in the command line, you will get information about all the modules running on your server, including this one, once its done.  So now we need to edit it to reflect our new module:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;DoD Message Module&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;0.1&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;DoD Plugins Community&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;http://www.dodplugins.net&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;DoDMM&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;dod_mm&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
=== Exposing Functions ===&lt;br /&gt;
So now that this is done we need to tell the module to use Metamod Natives, this is done by finding the followin:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 // #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
And changing it to:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
Or in other words uncommenting it.  :-)  So now that this is done we have access to loads of stuff that metamod has to offer us as well as Amxmodx stuff.  Once this is done we now need to expose the functions from metamod that we will be using for this message module.  &lt;br /&gt;
&lt;br /&gt;
==== Amxmodx ====&lt;br /&gt;
If you scroll down you will find the following two functions from amxmodx that we will be using:&lt;br /&gt;
&lt;br /&gt;
 /** AMXX attach&lt;br /&gt;
  * Do native functions init here (MF_AddNatives)&lt;br /&gt;
  */&lt;br /&gt;
 // #define FN_AMXX_ATTACH OnAmxxAttach&lt;br /&gt;
 &lt;br /&gt;
 /** AMXX Detach (unload) */&lt;br /&gt;
 // #define FN_AMXX_DETACH OnAmxxDetach&lt;br /&gt;
&lt;br /&gt;
We will expose these by uncommenting them.  Later on in this document I will explain where the function itself goes and what goes in them.&lt;br /&gt;
&lt;br /&gt;
==== HL API ====&lt;br /&gt;
Next we will expose some of the functions that come from the HL Server Engine that Metamod has exposed for us.  The functions that we are exposing are ones that we will need specific to messages:&lt;br /&gt;
&lt;br /&gt;
 #define FN_MessageBegin_Post					MessageBegin_Post&lt;br /&gt;
 #define FN_MessageEnd_Post					MessageEnd_Post&lt;br /&gt;
 #define FN_WriteByte_Post					WriteByte_Post&lt;br /&gt;
 #define FN_WriteChar_Post					WriteChar_Post&lt;br /&gt;
 #define FN_WriteShort_Post					WriteShort_Post&lt;br /&gt;
 #define FN_WriteLong_Post					WriteLong_Post&lt;br /&gt;
 #define FN_WriteAngle_Post					WriteAngle_Post&lt;br /&gt;
 #define FN_WriteCoord_Post					WriteCoord_Post&lt;br /&gt;
 #define FN_WriteString_Post					WriteString_Post&lt;br /&gt;
 #define FN_WriteEntity_Post					WriteEntity_Post&lt;br /&gt;
&lt;br /&gt;
These are the actual messages that will be caught.  Finally we need to catch the registering of those messages we can see in [http://wiki.dodplugins.net/index.php/Meta_Game Meta Game].  This is the function we are going to expose next:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Now that all the functions that we will be using have been exposed we are good to carry on with the meat of the module.&lt;br /&gt;
&lt;br /&gt;
=== Developing Module ===&lt;br /&gt;
Right on, now we have the basics down.  We are ready to start programming.  So we need a main file now.  So now we need to right click on the dod_mm and goto Add-&amp;gt;New Item as shown in the picture below:&lt;br /&gt;
&lt;br /&gt;
[[Image:adding_item.jpg]]&lt;br /&gt;
&lt;br /&gt;
Once thats done a new window comes up, we need to click on code, then Header File (.h) giving it the name main.h&lt;br /&gt;
&lt;br /&gt;
[[Image:main_header.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now we have a file to work with.  So, we need to first set it up as a standard Header file so that it is only included once into memory.  So we add the following:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
So this will ensure that all the code we put between those two comments are only loaded once into the compilation process.  Now that we have this part complete we will start coding.  As we are making a module to catch all the Messages that occur on a HL DoD Server the first thing we need to do is create a structure to keep all the data that we will use.  This structure will be called StructUserMsg and will contain two members the id of the message which can be anything from 0 - 256 messages and the name of the message.  We can get these names from [http://wiki.dodplugins.net/index.php/Meta_Game].  These will be the messages that will pop up.  Now that we have this done the file should look like so:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
      #include &amp;quot;sdk/amxxmodule.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
      struct StructUserMsg &lt;br /&gt;
      {&lt;br /&gt;
            int id;&lt;br /&gt;
            char name[256];&lt;br /&gt;
      };&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
==== CPP File ====&lt;br /&gt;
So now that we have the structure done the first thing we have to do is make a CPP file the same as we did the Header file except with a CPP.  We will name this file the same as the Header that we created as this cpp will call the header to get its information.  Once we have created the file the first thing we need to do is call the header file by adding this to the top:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;main.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
That will ensure to grab our structure so the rest of the program knows what it is.  Once this is done we need to create a few global variables to use.  The first one we will use is one that will allow us to output to a file all the data that we are gathering:&lt;br /&gt;
&lt;br /&gt;
 FILE *stream;&lt;br /&gt;
&lt;br /&gt;
Next we need a global state variable so that we know what call we are on within the message.  This will count all the calls to each specific message:&lt;br /&gt;
&lt;br /&gt;
 int g_state;&lt;br /&gt;
&lt;br /&gt;
Now finally we need to create the global variable for the structure we created:&lt;br /&gt;
&lt;br /&gt;
 StructUserMsg g_user_msg[MAX_REG_MSGS];&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx Functions Created ====&lt;br /&gt;
So this is most important.  We created a StructUserMsg array of MAX_REG_MSGS in length, this is 256.  Ok we are good now on the globals.  Pretty simple.  Now remember those functions we exposed, well we need to create those functions so that Amxmodx will call them.  First we will look at the Amxmodx functions:&lt;br /&gt;
&lt;br /&gt;
 void OnAmxxAttach()&lt;br /&gt;
 {&lt;br /&gt;
      fopen_s(&amp;amp;stream, &amp;quot;messages.txt&amp;quot;, &amp;quot;w&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void OnAmxxDetach()&lt;br /&gt;
 {&lt;br /&gt;
      fclose(stream);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
So now that these are created lets understand them.  When amxmodx starts up and calls the module we are creating the OnAmxxAttach is the first thing that is called, in our case we are opening up a file called messages.txt that will be in the base HL directory.  This will contain all the output from our module.  &lt;br /&gt;
&lt;br /&gt;
 '''*** NOTE *** This will take up alot of room, so be carefull'''&lt;br /&gt;
&lt;br /&gt;
Ok, the second function is just the opposite, when amxmodx closes this is the last function called, so we want to close the file.&lt;br /&gt;
&lt;br /&gt;
==== Metamod HL API Functions Created ====&lt;br /&gt;
Now onward.  The Amxmodx functions are complete now we need to create the functions for the Metamod / HL API.  First we will create the most important function the registration function, in order to understand the funtions we first need to know what we are looking for.  So we exposed the following:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Ok so what the hell is this???  Well if you highlight and copy FN_RegUserMsg_Post then open up amxxmodule.h and do a search for '''FN_RegUserMsg_Post''' you will find the following:&lt;br /&gt;
&lt;br /&gt;
 #ifdef FN_RegUserMsg_Post&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
 #endif // FN_RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
This is where we get the function declaration from.  So we copy the following:&lt;br /&gt;
&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
&lt;br /&gt;
And make a function out of it as such:&lt;br /&gt;
&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Now this is the start of our function.  You notice the RETURN_META_VALUE, this is a metamod return, because the function is returning an int we need to tell metamod to ignore what we have done with this function and return an integer.  This is what this means.  One of the others we will be returning alot is as follows:&lt;br /&gt;
&lt;br /&gt;
 RETURN_META(MRES_IGNORED);&lt;br /&gt;
&lt;br /&gt;
This is what we use when a function returns a void or nothing.  This function is pretty basic.  First thing we are going to do is grab the original return value that we would have gotten if we wanted to do stuff with this function.  In this case it is the message id:&lt;br /&gt;
&lt;br /&gt;
 int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
&lt;br /&gt;
Next we are going to assign the message id to our message structure at the location of the message id...bit confusing but important:&lt;br /&gt;
&lt;br /&gt;
 g_user_msg[msgid].id = msgid;&lt;br /&gt;
&lt;br /&gt;
Finally we are going to assign the message name to the message structure using a string copy:&lt;br /&gt;
&lt;br /&gt;
 strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
&lt;br /&gt;
Ok now we have the register function done it will look like so when done:&lt;br /&gt;
&lt;br /&gt;
 // First thing when all the messages are sent out to a client we grab them and take a look at them&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
      g_user_msg[msgid].id = msgid;&lt;br /&gt;
      strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to worry about the next important function, the message begins function.  This is called when a message is initialized on the server to be sent out to someone somewhere.  It looks like this:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Voila...now this is very important part because this is where and when the message begins...remember we can '''NEVER''' call another message_begin while we are in a message...so we have to wait until after when we hit message_end.  Now we are going to add some stuff to this to make it work.  First we want to make sure that its not a bogus or bad message:&lt;br /&gt;
&lt;br /&gt;
 if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
 {&lt;br /&gt;
      g_state = -1;&lt;br /&gt;
      RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
If it is we bounce out of this message.  If not then its a good message and we want to carry on.  Next thing we do is print out that we are in the message beginning to both the console and the file:&lt;br /&gt;
&lt;br /&gt;
 // Log the message Name&lt;br /&gt;
 printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
&lt;br /&gt;
As you can see we are printing out the message id the message name that we stored in our structure earlier.  Once this is done we will check the message destination and print that out as well.  There are 3 places a message could be going 0 = all, 1 - 32 is Individually to a player, and 33 - MAX_REG_MSGS is all others.  So we will tell which it is with the following:&lt;br /&gt;
&lt;br /&gt;
 // Is it too all, or to an individual&lt;br /&gt;
 if(msg_dest == 0)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
       if(player)&lt;br /&gt;
       {&lt;br /&gt;
              int id = ENTINDEX(player);&lt;br /&gt;
              const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
              const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
              printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
              fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
       }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Self explanatory, finally we need to set the global variable g_state to zero:&lt;br /&gt;
&lt;br /&gt;
 g_state = 0;&lt;br /&gt;
&lt;br /&gt;
So this funtion is done.  Here is the end result:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
      {&lt;br /&gt;
            g_state = -1;&lt;br /&gt;
            RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      // Log the message Name&lt;br /&gt;
      printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
      fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 &lt;br /&gt;
      // Is it too all, or to an individual&lt;br /&gt;
      if(msg_dest == 0)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
            if(player)&lt;br /&gt;
            {&lt;br /&gt;
                  int id = ENTINDEX(player);&lt;br /&gt;
                  const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
                  const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
                  printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
                  fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
            }&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      g_state = 0;&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ok from here on out it will be a bit repetitive so I will just show them too you:&lt;br /&gt;
&lt;br /&gt;
 void WriteByte_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteChar_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      char buffer[10];&lt;br /&gt;
      _itoa_s(iValue, buffer, 10);&lt;br /&gt;
      printf(&amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteShort_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteLong_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteAngle_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteCoord_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteString_Post(const char *sz) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteEntity_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The last but not least function is the message end function.  It too is simple to understand:&lt;br /&gt;
&lt;br /&gt;
 void MessageEnd_Post(void) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
      fprintf(stream, &amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
      fflush(stream);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The only thing weird about this one is the flush...this just ensures the data we just collected gets sent to the file.  Well thats it...we're done...all thats left is the compile and moving the module to the addons/amxmodx/modules/ directory then adding it to the addons/amxmodx/configs/modules.ini file at the bottom.  Remember to name it dod_mm not dod_mm_amxx.dll just the first part.&lt;br /&gt;
&lt;br /&gt;
== In Conclusion ==&lt;br /&gt;
&lt;br /&gt;
Ok we are setup to start compiling, you can grab the source code to any of the modules at amxmodx and compile them now...or just play about.  I suggest you try the easy one that you can grab here: [http://forums.alliedmods.net/showthread.php?t=18763  ESF Model Changing Module] just to look at it.  Here is the direct download: [http://forums.alliedmods.net/attachment.php?attachmentid=4104&amp;amp;d=1128187905 esf_model_changer]&lt;br /&gt;
&lt;br /&gt;
The files for this project can be found [http://www.dodplugins.net/forums/showthread.php?p=2471 DoD Message Module Tutorial / Module]&lt;br /&gt;
&lt;br /&gt;
I have made great use of this in helping in developing dodx and dodfun.&lt;br /&gt;
&lt;br /&gt;
Cheers!&lt;br /&gt;
Zor&lt;br /&gt;
&lt;br /&gt;
For more information, look in: [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx /svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx] or [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk.tar.gz?root=amxmodx&amp;amp;view=tar click here] to download a tarball of that directory.&lt;br /&gt;
&lt;br /&gt;
Copy these files into a new folder.  The amxxmodule.h/cpp files are the Module SDK backend.  You only need to edit the moduleconfig.h file to customize your module.&lt;br /&gt;
&lt;br /&gt;
[[Category:AMX_Mod_X]]&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5513</id>
		<title>Module Writing (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5513"/>
		<updated>2007-12-26T20:18:32Z</updated>

		<summary type="html">&lt;p&gt;Zor: /* HL API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AMX Mod X Modules are written in C or C++ (the API is C compatible).&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
So you want to be a module developer for Amxmodx!  Well its not too hard.  I will be doing this in Windows as I dont have a Linux box to frick around with at the moment.  So, windows only at this point, a Linux version will be forthcoming!&lt;br /&gt;
&lt;br /&gt;
== Necessary Files ==&lt;br /&gt;
Well first we need to gather up the neccessary files for your computer.  The first thing you need to know, its NOT complicated.  If you can script in pawn, you can program in C/C++!&lt;br /&gt;
&lt;br /&gt;
=== Metamod ===&lt;br /&gt;
As we all know metamod is the backbone of the whole thing, without this all mods for and HL game would not be possible unless we programmed it ourselves!  So many thanks to willday for the development of Metamod, and for BAILOPAN and his crew helping to maintain and update it!  Hats off to all!  Ok so now onto the file gathering!  First thing is first we need to goto Metamod: [http://metamod.org/ metamod.org] from there we need to gather up 2 SDK's.&lt;br /&gt;
&lt;br /&gt;
==== HL-SDK ====&lt;br /&gt;
The Half Life SDK is the first thing in the list to gather up!  We can get this at the same spot that we will be gathering up metamod!  So we click on the SDK Link or goto:  [http://metamod.sourceforge.net/files/sdk/ Here].  From here we need to grab the HLSDK, preferably the one that has been tweeked out for Metamod.  So we are looking for this:&lt;br /&gt;
&lt;br /&gt;
 hlsdk-2.3-p3.zip                - The Standard SDK v2.3 with various fixes and&lt;br /&gt;
                                   updates, that Metamod is compiled against.&lt;br /&gt;
                                   Files are in DOS format.&lt;br /&gt;
&lt;br /&gt;
So lets grab the [http://metamod.sourceforge.net/files/sdk/hlsdk-2.3-p3.zip hlsdk-2.3-p3.zip] first!  Once this is done you will need to extract this to your Hard Drive.  What we will be doing is extracting these files to the following directory, these will be arbitray directories for ease of the document so dont sweat it once you proficient you can move them around :-)  Ok so extract the files to the following directory: c:\sdk_files\&lt;br /&gt;
&lt;br /&gt;
==== Metamod SDK ====&lt;br /&gt;
Ok, so we have the HL-SDK we now need to Metamod SDK.  So we need to go back to the root of Metamod &lt;br /&gt;
[http://metamod.org/ here] and then click on the  v1.xx Sourcecode zip to get the latest SDK from Sourceforge, you can get that file from the best location for you or for a quick link click [http://prdownloads.sourceforge.net/metamod/metamod-1.19-win.src.zip?download metamod-1.xx-win.src.zip] to get the files.&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx SDK ==== &lt;br /&gt;
Now we need to grab the last of the SDK's so we can go carry on.  First we need to goto the Amxmodx Website so that we can get to the SDK via the Downloads area and SVN!  [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx.tar.gz?root=amxmodx&amp;amp;view=tar Amxmodx SDK].&lt;br /&gt;
&lt;br /&gt;
==== Unix2Dos the Files ====&lt;br /&gt;
So, once you have all the files we need to fix them up a bit.  One of the things that will become bothersome later is the Unix File Format that HLSDK / Metamod has, its suppose to be Windows, but its not, so we need to convert the files, soooo...we will use the following tutorial to fix this [[GnuWin32]] Once you have that setup you can use the following to repair all files easily [http://wiki.dodplugins.net/images/6/61/Repair.rar Repair.bat].&lt;br /&gt;
&lt;br /&gt;
== Compiler GUI ==&lt;br /&gt;
Now that we have all the SDK files we will need to get the Compiler.  The one that we will be using will be the Microsoft Visual 2005 Express Edition.  &lt;br /&gt;
&lt;br /&gt;
=== Visual C++ 2005 Express Edition ===&lt;br /&gt;
First thing you need to do is grab the web install files:  [http://go.microsoft.com/fwlink/?LinkId=51410&amp;amp;clcid=0x409 Visual C++ 2005 Express Edition] if you want to grab the network install you should grab the following: [http://msdn.microsoft.com/vstudio/express/support/install/ Network Install Files], for network install either grab the [http://go.microsoft.com/fwlink/?linkid=54766 Image File] or the [http://go.microsoft.com/fwlink/?linkid=57034 ISO File] your choice. Ok so now your have the iso/img file you need to either burn it or use a Virtual CD/DVD to install it.  I wont go into detail on this as its pretty simple, but make sure that you only install the Graphical IDE, if you want to you can install the Microsoft MSDN 2005 Express Edition, these are the help files that you can access by hitting F1 once in the GUI, if you haven't downloaded them, thats fine it will connect you to the Online version of them instead.&lt;br /&gt;
&lt;br /&gt;
=== Platform SDK ===&lt;br /&gt;
The platform SDK is a needed piece of kit, without it we wont be able to compile.  You will need to grab it from this site: [http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/ Platform SDK Site].  Specifically you need to grab proper file for your architecture, goto the above page and scroll down to the Files in This Download section.  Download the file that you need and install it.  Make sure to do a custom install unless you dont mind a bunch of crap on your computer.  You want to have only the following items installed:&lt;br /&gt;
&lt;br /&gt;
 Microsoft Windows Core SDK&lt;br /&gt;
 Microsoft Direct Show SDK&lt;br /&gt;
 Microsoft Media Services SDK&lt;br /&gt;
&lt;br /&gt;
=== .NET SDK ===&lt;br /&gt;
Next we need to grab the Dot Net install and the Dot Net SDK.  You can grab the [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=262d25e3-f589-4842-8157-034d1e7cf3a3&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2fa%2fa%2fc%2faac39226-8825-44ce-90e3-bf8203e74006%2fdotnetfx.exe dotnet.1.1.exe] and install it.  Next you will need the .NET SDK, you can grapple [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=9B3A2CA6-3647-4070-9F41-A333C6B9181D&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f5%2f2%2f0%2f5202f918-306e-426d-9637-d7ee26fbe507%2fsetup.exe dotnet.1.1.sdk.exe]  Once these are installed your good to start up the GUI.&lt;br /&gt;
&lt;br /&gt;
== Setting up the GUI ==&lt;br /&gt;
Ok, so now we start up Visual C++, click on Start-&amp;gt;Program Files-&amp;gt;Visual C++ 2005 Express Edition-&amp;gt;Microsoft Visual C++ 2005 Express Edition duh...but just in case :-) allow it to go through the initialization and start up.  Once its started up you will need to do the following:&lt;br /&gt;
&lt;br /&gt;
 Click Tools-&amp;gt;Options&lt;br /&gt;
[[Image:options.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Now expand the Projects and Solutions are by clicking on the + symbol to the left of the name.&lt;br /&gt;
[[Image:pands.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Click on the VC++ Directories.  Now on the top left of that box you will see a drop box that says Show Directories For&lt;br /&gt;
 Click the drop  box and select Include Files.&lt;br /&gt;
[[Image:vc--.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now you need to add the following Directories to this list at the bottom:&lt;br /&gt;
&lt;br /&gt;
 C:\Program Files\Microsoft Platform SDK\Include&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\common&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\dlls&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\engine&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\pm_shared&lt;br /&gt;
 C:\sdk_files\metamod-1.19\metamod&lt;br /&gt;
 C:\sdk_files\amxmodx&lt;br /&gt;
[[Image:Directories.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Message Module ( Demo ) ==&lt;br /&gt;
Right, now that we have the base all good and done, we need to get going with the module.  First thing we need to do is create a new module, for ease of use I have for the moment made up a demo module called [http://www.dodplugins.net/files/dod_mm.zip dod_mm], DoD Message Module.  Grab this and extract it to the c:\sdk_files directory.&lt;br /&gt;
&lt;br /&gt;
=== Editing Module Information ===&lt;br /&gt;
First things first you need to open up the dod_mm.vcproj this will open up Visual C++.  Once its open you will see on the left a dod_mm under the solutions area.  Open moduleconfig.h.  In here we will look for the following:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;--ENTER NAME HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;--ENTER VERSION HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;--ENTER AUTHOR HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;--ENTER URL HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;--ENTER LOGTAG HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;--ENTER LIBRARY HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
This is the infor that will be displayed about the module when you have it running on your server.  Lets say you type in amxx modules in the command line, you will get information about all the modules running on your server, including this one, once its done.  So now we need to edit it to reflect our new module:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;DoD Message Module&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;0.1&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;DoD Plugins Community&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;http://www.dodplugins.net&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;DoDMM&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;dod_mm&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
=== Exposing Functions ===&lt;br /&gt;
So now that this is done we need to tell the module to use Metamod Natives, this is done by finding the followin:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 // #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
And changing it to:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
Or in other words uncommenting it.  :-)  So now that this is done we have access to loads of stuff that metamod has to offer us as well as Amxmodx stuff.  Once this is done we now need to expose the functions from metamod that we will be using for this message module.  &lt;br /&gt;
&lt;br /&gt;
==== Amxmodx ====&lt;br /&gt;
If you scroll down you will find the following two functions from amxmodx that we will be using:&lt;br /&gt;
&lt;br /&gt;
 /** AMXX attach&lt;br /&gt;
  * Do native functions init here (MF_AddNatives)&lt;br /&gt;
  */&lt;br /&gt;
 // #define FN_AMXX_ATTACH OnAmxxAttach&lt;br /&gt;
 &lt;br /&gt;
 /** AMXX Detach (unload) */&lt;br /&gt;
 // #define FN_AMXX_DETACH OnAmxxDetach&lt;br /&gt;
&lt;br /&gt;
We will expose these by uncommenting them.  Later on in this document I will explain where the function itself goes and what goes in them.&lt;br /&gt;
&lt;br /&gt;
==== HL API ====&lt;br /&gt;
Next we will expose some of the functions that come from the HL Server Engine that Metamod has exposed for us.  The functions that we are exposing are ones that we will need specific to messages:&lt;br /&gt;
&lt;br /&gt;
 #define FN_MessageBegin_Post					MessageBegin_Post&lt;br /&gt;
 #define FN_MessageEnd_Post					MessageEnd_Post&lt;br /&gt;
 #define FN_WriteByte_Post					WriteByte_Post&lt;br /&gt;
 #define FN_WriteChar_Post					WriteChar_Post&lt;br /&gt;
 #define FN_WriteShort_Post					WriteShort_Post&lt;br /&gt;
 #define FN_WriteLong_Post					WriteLong_Post&lt;br /&gt;
 #define FN_WriteAngle_Post					WriteAngle_Post&lt;br /&gt;
 #define FN_WriteCoord_Post					WriteCoord_Post&lt;br /&gt;
 #define FN_WriteString_Post					WriteString_Post&lt;br /&gt;
 #define FN_WriteEntity_Post					WriteEntity_Post&lt;br /&gt;
&lt;br /&gt;
These are the actual messages that will be caught.  Finally we need to catch the registering of those messages we can see in [http://wiki.dodplugins.net/index.php/Meta_Game].  This is the function we are going to expose next:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Now that all the functions that we will be using have been exposed we are good to carry on with the meat of the module.&lt;br /&gt;
&lt;br /&gt;
=== Developing Module ===&lt;br /&gt;
Right on, now we have the basics down.  We are ready to start programming.  So we need a main file now.  So now we need to right click on the dod_mm and goto Add-&amp;gt;New Item as shown in the picture below:&lt;br /&gt;
&lt;br /&gt;
[[Image:adding_item.jpg]]&lt;br /&gt;
&lt;br /&gt;
Once thats done a new window comes up, we need to click on code, then Header File (.h) giving it the name main.h&lt;br /&gt;
&lt;br /&gt;
[[Image:main_header.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now we have a file to work with.  So, we need to first set it up as a standard Header file so that it is only included once into memory.  So we add the following:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
So this will ensure that all the code we put between those two comments are only loaded once into the compilation process.  Now that we have this part complete we will start coding.  As we are making a module to catch all the Messages that occur on a HL DoD Server the first thing we need to do is create a structure to keep all the data that we will use.  This structure will be called StructUserMsg and will contain two members the id of the message which can be anything from 0 - 256 messages and the name of the message.  We can get these names from [http://wiki.dodplugins.net/index.php/Meta_Game].  These will be the messages that will pop up.  Now that we have this done the file should look like so:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
      #include &amp;quot;sdk/amxxmodule.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
      struct StructUserMsg &lt;br /&gt;
      {&lt;br /&gt;
            int id;&lt;br /&gt;
            char name[256];&lt;br /&gt;
      };&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
==== CPP File ====&lt;br /&gt;
So now that we have the structure done the first thing we have to do is make a CPP file the same as we did the Header file except with a CPP.  We will name this file the same as the Header that we created as this cpp will call the header to get its information.  Once we have created the file the first thing we need to do is call the header file by adding this to the top:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;main.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
That will ensure to grab our structure so the rest of the program knows what it is.  Once this is done we need to create a few global variables to use.  The first one we will use is one that will allow us to output to a file all the data that we are gathering:&lt;br /&gt;
&lt;br /&gt;
 FILE *stream;&lt;br /&gt;
&lt;br /&gt;
Next we need a global state variable so that we know what call we are on within the message.  This will count all the calls to each specific message:&lt;br /&gt;
&lt;br /&gt;
 int g_state;&lt;br /&gt;
&lt;br /&gt;
Now finally we need to create the global variable for the structure we created:&lt;br /&gt;
&lt;br /&gt;
 StructUserMsg g_user_msg[MAX_REG_MSGS];&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx Functions Created ====&lt;br /&gt;
So this is most important.  We created a StructUserMsg array of MAX_REG_MSGS in length, this is 256.  Ok we are good now on the globals.  Pretty simple.  Now remember those functions we exposed, well we need to create those functions so that Amxmodx will call them.  First we will look at the Amxmodx functions:&lt;br /&gt;
&lt;br /&gt;
 void OnAmxxAttach()&lt;br /&gt;
 {&lt;br /&gt;
      fopen_s(&amp;amp;stream, &amp;quot;messages.txt&amp;quot;, &amp;quot;w&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void OnAmxxDetach()&lt;br /&gt;
 {&lt;br /&gt;
      fclose(stream);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
So now that these are created lets understand them.  When amxmodx starts up and calls the module we are creating the OnAmxxAttach is the first thing that is called, in our case we are opening up a file called messages.txt that will be in the base HL directory.  This will contain all the output from our module.  &lt;br /&gt;
&lt;br /&gt;
 '''*** NOTE *** This will take up alot of room, so be carefull'''&lt;br /&gt;
&lt;br /&gt;
Ok, the second function is just the opposite, when amxmodx closes this is the last function called, so we want to close the file.&lt;br /&gt;
&lt;br /&gt;
==== Metamod HL API Functions Created ====&lt;br /&gt;
Now onward.  The Amxmodx functions are complete now we need to create the functions for the Metamod / HL API.  First we will create the most important function the registration function, in order to understand the funtions we first need to know what we are looking for.  So we exposed the following:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Ok so what the hell is this???  Well if you highlight and copy FN_RegUserMsg_Post then open up amxxmodule.h and do a search for '''FN_RegUserMsg_Post''' you will find the following:&lt;br /&gt;
&lt;br /&gt;
 #ifdef FN_RegUserMsg_Post&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
 #endif // FN_RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
This is where we get the function declaration from.  So we copy the following:&lt;br /&gt;
&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
&lt;br /&gt;
And make a function out of it as such:&lt;br /&gt;
&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Now this is the start of our function.  You notice the RETURN_META_VALUE, this is a metamod return, because the function is returning an int we need to tell metamod to ignore what we have done with this function and return an integer.  This is what this means.  One of the others we will be returning alot is as follows:&lt;br /&gt;
&lt;br /&gt;
 RETURN_META(MRES_IGNORED);&lt;br /&gt;
&lt;br /&gt;
This is what we use when a function returns a void or nothing.  This function is pretty basic.  First thing we are going to do is grab the original return value that we would have gotten if we wanted to do stuff with this function.  In this case it is the message id:&lt;br /&gt;
&lt;br /&gt;
 int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
&lt;br /&gt;
Next we are going to assign the message id to our message structure at the location of the message id...bit confusing but important:&lt;br /&gt;
&lt;br /&gt;
 g_user_msg[msgid].id = msgid;&lt;br /&gt;
&lt;br /&gt;
Finally we are going to assign the message name to the message structure using a string copy:&lt;br /&gt;
&lt;br /&gt;
 strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
&lt;br /&gt;
Ok now we have the register function done it will look like so when done:&lt;br /&gt;
&lt;br /&gt;
 // First thing when all the messages are sent out to a client we grab them and take a look at them&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
      g_user_msg[msgid].id = msgid;&lt;br /&gt;
      strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to worry about the next important function, the message begins function.  This is called when a message is initialized on the server to be sent out to someone somewhere.  It looks like this:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Voila...now this is very important part because this is where and when the message begins...remember we can '''NEVER''' call another message_begin while we are in a message...so we have to wait until after when we hit message_end.  Now we are going to add some stuff to this to make it work.  First we want to make sure that its not a bogus or bad message:&lt;br /&gt;
&lt;br /&gt;
 if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
 {&lt;br /&gt;
      g_state = -1;&lt;br /&gt;
      RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
If it is we bounce out of this message.  If not then its a good message and we want to carry on.  Next thing we do is print out that we are in the message beginning to both the console and the file:&lt;br /&gt;
&lt;br /&gt;
 // Log the message Name&lt;br /&gt;
 printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
&lt;br /&gt;
As you can see we are printing out the message id the message name that we stored in our structure earlier.  Once this is done we will check the message destination and print that out as well.  There are 3 places a message could be going 0 = all, 1 - 32 is Individually to a player, and 33 - MAX_REG_MSGS is all others.  So we will tell which it is with the following:&lt;br /&gt;
&lt;br /&gt;
 // Is it too all, or to an individual&lt;br /&gt;
 if(msg_dest == 0)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
       if(player)&lt;br /&gt;
       {&lt;br /&gt;
              int id = ENTINDEX(player);&lt;br /&gt;
              const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
              const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
              printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
              fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
       }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Self explanatory, finally we need to set the global variable g_state to zero:&lt;br /&gt;
&lt;br /&gt;
 g_state = 0;&lt;br /&gt;
&lt;br /&gt;
So this funtion is done.  Here is the end result:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
      {&lt;br /&gt;
            g_state = -1;&lt;br /&gt;
            RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      // Log the message Name&lt;br /&gt;
      printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
      fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 &lt;br /&gt;
      // Is it too all, or to an individual&lt;br /&gt;
      if(msg_dest == 0)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
            if(player)&lt;br /&gt;
            {&lt;br /&gt;
                  int id = ENTINDEX(player);&lt;br /&gt;
                  const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
                  const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
                  printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
                  fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
            }&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      g_state = 0;&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ok from here on out it will be a bit repetitive so I will just show them too you:&lt;br /&gt;
&lt;br /&gt;
 void WriteByte_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteChar_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      char buffer[10];&lt;br /&gt;
      _itoa_s(iValue, buffer, 10);&lt;br /&gt;
      printf(&amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteShort_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteLong_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteAngle_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteCoord_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteString_Post(const char *sz) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteEntity_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The last but not least function is the message end function.  It too is simple to understand:&lt;br /&gt;
&lt;br /&gt;
 void MessageEnd_Post(void) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
      fprintf(stream, &amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
      fflush(stream);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The only thing weird about this one is the flush...this just ensures the data we just collected gets sent to the file.  Well thats it...we're done...all thats left is the compile and moving the module to the addons/amxmodx/modules/ directory then adding it to the addons/amxmodx/configs/modules.ini file at the bottom.  Remember to name it dod_mm not dod_mm_amxx.dll just the first part.&lt;br /&gt;
&lt;br /&gt;
== In Conclusion ==&lt;br /&gt;
&lt;br /&gt;
Ok we are setup to start compiling, you can grab the source code to any of the modules at amxmodx and compile them now...or just play about.  I suggest you try the easy one that you can grab here: [http://forums.alliedmods.net/showthread.php?t=18763  ESF Model Changing Module] just to look at it.  Here is the direct download: [http://forums.alliedmods.net/attachment.php?attachmentid=4104&amp;amp;d=1128187905 esf_model_changer]&lt;br /&gt;
&lt;br /&gt;
The files for this project can be found [http://www.dodplugins.net/forums/showthread.php?p=2471 DoD Message Module Tutorial / Module]&lt;br /&gt;
&lt;br /&gt;
I have made great use of this in helping in developing dodx and dodfun.&lt;br /&gt;
&lt;br /&gt;
Cheers!&lt;br /&gt;
Zor&lt;br /&gt;
&lt;br /&gt;
For more information, look in: [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx /svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx] or [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk.tar.gz?root=amxmodx&amp;amp;view=tar click here] to download a tarball of that directory.&lt;br /&gt;
&lt;br /&gt;
Copy these files into a new folder.  The amxxmodule.h/cpp files are the Module SDK backend.  You only need to edit the moduleconfig.h file to customize your module.&lt;br /&gt;
&lt;br /&gt;
[[Category:AMX_Mod_X]]&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5512</id>
		<title>Module Writing (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5512"/>
		<updated>2007-12-26T20:17:47Z</updated>

		<summary type="html">&lt;p&gt;Zor: /* Developing Module */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AMX Mod X Modules are written in C or C++ (the API is C compatible).&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
So you want to be a module developer for Amxmodx!  Well its not too hard.  I will be doing this in Windows as I dont have a Linux box to frick around with at the moment.  So, windows only at this point, a Linux version will be forthcoming!&lt;br /&gt;
&lt;br /&gt;
== Necessary Files ==&lt;br /&gt;
Well first we need to gather up the neccessary files for your computer.  The first thing you need to know, its NOT complicated.  If you can script in pawn, you can program in C/C++!&lt;br /&gt;
&lt;br /&gt;
=== Metamod ===&lt;br /&gt;
As we all know metamod is the backbone of the whole thing, without this all mods for and HL game would not be possible unless we programmed it ourselves!  So many thanks to willday for the development of Metamod, and for BAILOPAN and his crew helping to maintain and update it!  Hats off to all!  Ok so now onto the file gathering!  First thing is first we need to goto Metamod: [http://metamod.org/ metamod.org] from there we need to gather up 2 SDK's.&lt;br /&gt;
&lt;br /&gt;
==== HL-SDK ====&lt;br /&gt;
The Half Life SDK is the first thing in the list to gather up!  We can get this at the same spot that we will be gathering up metamod!  So we click on the SDK Link or goto:  [http://metamod.sourceforge.net/files/sdk/ Here].  From here we need to grab the HLSDK, preferably the one that has been tweeked out for Metamod.  So we are looking for this:&lt;br /&gt;
&lt;br /&gt;
 hlsdk-2.3-p3.zip                - The Standard SDK v2.3 with various fixes and&lt;br /&gt;
                                   updates, that Metamod is compiled against.&lt;br /&gt;
                                   Files are in DOS format.&lt;br /&gt;
&lt;br /&gt;
So lets grab the [http://metamod.sourceforge.net/files/sdk/hlsdk-2.3-p3.zip hlsdk-2.3-p3.zip] first!  Once this is done you will need to extract this to your Hard Drive.  What we will be doing is extracting these files to the following directory, these will be arbitray directories for ease of the document so dont sweat it once you proficient you can move them around :-)  Ok so extract the files to the following directory: c:\sdk_files\&lt;br /&gt;
&lt;br /&gt;
==== Metamod SDK ====&lt;br /&gt;
Ok, so we have the HL-SDK we now need to Metamod SDK.  So we need to go back to the root of Metamod &lt;br /&gt;
[http://metamod.org/ here] and then click on the  v1.xx Sourcecode zip to get the latest SDK from Sourceforge, you can get that file from the best location for you or for a quick link click [http://prdownloads.sourceforge.net/metamod/metamod-1.19-win.src.zip?download metamod-1.xx-win.src.zip] to get the files.&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx SDK ==== &lt;br /&gt;
Now we need to grab the last of the SDK's so we can go carry on.  First we need to goto the Amxmodx Website so that we can get to the SDK via the Downloads area and SVN!  [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx.tar.gz?root=amxmodx&amp;amp;view=tar Amxmodx SDK].&lt;br /&gt;
&lt;br /&gt;
==== Unix2Dos the Files ====&lt;br /&gt;
So, once you have all the files we need to fix them up a bit.  One of the things that will become bothersome later is the Unix File Format that HLSDK / Metamod has, its suppose to be Windows, but its not, so we need to convert the files, soooo...we will use the following tutorial to fix this [[GnuWin32]] Once you have that setup you can use the following to repair all files easily [http://wiki.dodplugins.net/images/6/61/Repair.rar Repair.bat].&lt;br /&gt;
&lt;br /&gt;
== Compiler GUI ==&lt;br /&gt;
Now that we have all the SDK files we will need to get the Compiler.  The one that we will be using will be the Microsoft Visual 2005 Express Edition.  &lt;br /&gt;
&lt;br /&gt;
=== Visual C++ 2005 Express Edition ===&lt;br /&gt;
First thing you need to do is grab the web install files:  [http://go.microsoft.com/fwlink/?LinkId=51410&amp;amp;clcid=0x409 Visual C++ 2005 Express Edition] if you want to grab the network install you should grab the following: [http://msdn.microsoft.com/vstudio/express/support/install/ Network Install Files], for network install either grab the [http://go.microsoft.com/fwlink/?linkid=54766 Image File] or the [http://go.microsoft.com/fwlink/?linkid=57034 ISO File] your choice. Ok so now your have the iso/img file you need to either burn it or use a Virtual CD/DVD to install it.  I wont go into detail on this as its pretty simple, but make sure that you only install the Graphical IDE, if you want to you can install the Microsoft MSDN 2005 Express Edition, these are the help files that you can access by hitting F1 once in the GUI, if you haven't downloaded them, thats fine it will connect you to the Online version of them instead.&lt;br /&gt;
&lt;br /&gt;
=== Platform SDK ===&lt;br /&gt;
The platform SDK is a needed piece of kit, without it we wont be able to compile.  You will need to grab it from this site: [http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/ Platform SDK Site].  Specifically you need to grab proper file for your architecture, goto the above page and scroll down to the Files in This Download section.  Download the file that you need and install it.  Make sure to do a custom install unless you dont mind a bunch of crap on your computer.  You want to have only the following items installed:&lt;br /&gt;
&lt;br /&gt;
 Microsoft Windows Core SDK&lt;br /&gt;
 Microsoft Direct Show SDK&lt;br /&gt;
 Microsoft Media Services SDK&lt;br /&gt;
&lt;br /&gt;
=== .NET SDK ===&lt;br /&gt;
Next we need to grab the Dot Net install and the Dot Net SDK.  You can grab the [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=262d25e3-f589-4842-8157-034d1e7cf3a3&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2fa%2fa%2fc%2faac39226-8825-44ce-90e3-bf8203e74006%2fdotnetfx.exe dotnet.1.1.exe] and install it.  Next you will need the .NET SDK, you can grapple [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=9B3A2CA6-3647-4070-9F41-A333C6B9181D&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f5%2f2%2f0%2f5202f918-306e-426d-9637-d7ee26fbe507%2fsetup.exe dotnet.1.1.sdk.exe]  Once these are installed your good to start up the GUI.&lt;br /&gt;
&lt;br /&gt;
== Setting up the GUI ==&lt;br /&gt;
Ok, so now we start up Visual C++, click on Start-&amp;gt;Program Files-&amp;gt;Visual C++ 2005 Express Edition-&amp;gt;Microsoft Visual C++ 2005 Express Edition duh...but just in case :-) allow it to go through the initialization and start up.  Once its started up you will need to do the following:&lt;br /&gt;
&lt;br /&gt;
 Click Tools-&amp;gt;Options&lt;br /&gt;
[[Image:options.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Now expand the Projects and Solutions are by clicking on the + symbol to the left of the name.&lt;br /&gt;
[[Image:pands.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Click on the VC++ Directories.  Now on the top left of that box you will see a drop box that says Show Directories For&lt;br /&gt;
 Click the drop  box and select Include Files.&lt;br /&gt;
[[Image:vc--.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now you need to add the following Directories to this list at the bottom:&lt;br /&gt;
&lt;br /&gt;
 C:\Program Files\Microsoft Platform SDK\Include&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\common&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\dlls&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\engine&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\pm_shared&lt;br /&gt;
 C:\sdk_files\metamod-1.19\metamod&lt;br /&gt;
 C:\sdk_files\amxmodx&lt;br /&gt;
[[Image:Directories.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Message Module ( Demo ) ==&lt;br /&gt;
Right, now that we have the base all good and done, we need to get going with the module.  First thing we need to do is create a new module, for ease of use I have for the moment made up a demo module called [http://www.dodplugins.net/files/dod_mm.zip dod_mm], DoD Message Module.  Grab this and extract it to the c:\sdk_files directory.&lt;br /&gt;
&lt;br /&gt;
=== Editing Module Information ===&lt;br /&gt;
First things first you need to open up the dod_mm.vcproj this will open up Visual C++.  Once its open you will see on the left a dod_mm under the solutions area.  Open moduleconfig.h.  In here we will look for the following:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;--ENTER NAME HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;--ENTER VERSION HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;--ENTER AUTHOR HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;--ENTER URL HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;--ENTER LOGTAG HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;--ENTER LIBRARY HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
This is the infor that will be displayed about the module when you have it running on your server.  Lets say you type in amxx modules in the command line, you will get information about all the modules running on your server, including this one, once its done.  So now we need to edit it to reflect our new module:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;DoD Message Module&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;0.1&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;DoD Plugins Community&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;http://www.dodplugins.net&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;DoDMM&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;dod_mm&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
=== Exposing Functions ===&lt;br /&gt;
So now that this is done we need to tell the module to use Metamod Natives, this is done by finding the followin:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 // #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
And changing it to:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
Or in other words uncommenting it.  :-)  So now that this is done we have access to loads of stuff that metamod has to offer us as well as Amxmodx stuff.  Once this is done we now need to expose the functions from metamod that we will be using for this message module.  &lt;br /&gt;
&lt;br /&gt;
==== Amxmodx ====&lt;br /&gt;
If you scroll down you will find the following two functions from amxmodx that we will be using:&lt;br /&gt;
&lt;br /&gt;
 /** AMXX attach&lt;br /&gt;
  * Do native functions init here (MF_AddNatives)&lt;br /&gt;
  */&lt;br /&gt;
 // #define FN_AMXX_ATTACH OnAmxxAttach&lt;br /&gt;
 &lt;br /&gt;
 /** AMXX Detach (unload) */&lt;br /&gt;
 // #define FN_AMXX_DETACH OnAmxxDetach&lt;br /&gt;
&lt;br /&gt;
We will expose these by uncommenting them.  Later on in this document I will explain where the function itself goes and what goes in them.&lt;br /&gt;
&lt;br /&gt;
==== HL API ====&lt;br /&gt;
Next we will expose some of the functions that come from the HL Server Engine that Metamod has exposed for us.  The functions that we are exposing are ones that we will need specific to messages:&lt;br /&gt;
&lt;br /&gt;
 #define FN_MessageBegin_Post					MessageBegin_Post&lt;br /&gt;
 #define FN_MessageEnd_Post					MessageEnd_Post&lt;br /&gt;
 #define FN_WriteByte_Post					WriteByte_Post&lt;br /&gt;
 #define FN_WriteChar_Post					WriteChar_Post&lt;br /&gt;
 #define FN_WriteShort_Post					WriteShort_Post&lt;br /&gt;
 #define FN_WriteLong_Post					WriteLong_Post&lt;br /&gt;
 #define FN_WriteAngle_Post					WriteAngle_Post&lt;br /&gt;
 #define FN_WriteCoord_Post					WriteCoord_Post&lt;br /&gt;
 #define FN_WriteString_Post					WriteString_Post&lt;br /&gt;
 #define FN_WriteEntity_Post					WriteEntity_Post&lt;br /&gt;
&lt;br /&gt;
These are the actual messages that will be caught.  Finally we need to catch the registering of those messages we can see in [[Meta_Game]].  This is the function we are going to expose next:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Now that all the functions that we will be using have been exposed we are good to carry on with the meat of the module.&lt;br /&gt;
&lt;br /&gt;
=== Developing Module ===&lt;br /&gt;
Right on, now we have the basics down.  We are ready to start programming.  So we need a main file now.  So now we need to right click on the dod_mm and goto Add-&amp;gt;New Item as shown in the picture below:&lt;br /&gt;
&lt;br /&gt;
[[Image:adding_item.jpg]]&lt;br /&gt;
&lt;br /&gt;
Once thats done a new window comes up, we need to click on code, then Header File (.h) giving it the name main.h&lt;br /&gt;
&lt;br /&gt;
[[Image:main_header.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now we have a file to work with.  So, we need to first set it up as a standard Header file so that it is only included once into memory.  So we add the following:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
So this will ensure that all the code we put between those two comments are only loaded once into the compilation process.  Now that we have this part complete we will start coding.  As we are making a module to catch all the Messages that occur on a HL DoD Server the first thing we need to do is create a structure to keep all the data that we will use.  This structure will be called StructUserMsg and will contain two members the id of the message which can be anything from 0 - 256 messages and the name of the message.  We can get these names from [http://wiki.dodplugins.net/index.php/Meta_Game].  These will be the messages that will pop up.  Now that we have this done the file should look like so:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
      #include &amp;quot;sdk/amxxmodule.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
      struct StructUserMsg &lt;br /&gt;
      {&lt;br /&gt;
            int id;&lt;br /&gt;
            char name[256];&lt;br /&gt;
      };&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
==== CPP File ====&lt;br /&gt;
So now that we have the structure done the first thing we have to do is make a CPP file the same as we did the Header file except with a CPP.  We will name this file the same as the Header that we created as this cpp will call the header to get its information.  Once we have created the file the first thing we need to do is call the header file by adding this to the top:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;main.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
That will ensure to grab our structure so the rest of the program knows what it is.  Once this is done we need to create a few global variables to use.  The first one we will use is one that will allow us to output to a file all the data that we are gathering:&lt;br /&gt;
&lt;br /&gt;
 FILE *stream;&lt;br /&gt;
&lt;br /&gt;
Next we need a global state variable so that we know what call we are on within the message.  This will count all the calls to each specific message:&lt;br /&gt;
&lt;br /&gt;
 int g_state;&lt;br /&gt;
&lt;br /&gt;
Now finally we need to create the global variable for the structure we created:&lt;br /&gt;
&lt;br /&gt;
 StructUserMsg g_user_msg[MAX_REG_MSGS];&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx Functions Created ====&lt;br /&gt;
So this is most important.  We created a StructUserMsg array of MAX_REG_MSGS in length, this is 256.  Ok we are good now on the globals.  Pretty simple.  Now remember those functions we exposed, well we need to create those functions so that Amxmodx will call them.  First we will look at the Amxmodx functions:&lt;br /&gt;
&lt;br /&gt;
 void OnAmxxAttach()&lt;br /&gt;
 {&lt;br /&gt;
      fopen_s(&amp;amp;stream, &amp;quot;messages.txt&amp;quot;, &amp;quot;w&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void OnAmxxDetach()&lt;br /&gt;
 {&lt;br /&gt;
      fclose(stream);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
So now that these are created lets understand them.  When amxmodx starts up and calls the module we are creating the OnAmxxAttach is the first thing that is called, in our case we are opening up a file called messages.txt that will be in the base HL directory.  This will contain all the output from our module.  &lt;br /&gt;
&lt;br /&gt;
 '''*** NOTE *** This will take up alot of room, so be carefull'''&lt;br /&gt;
&lt;br /&gt;
Ok, the second function is just the opposite, when amxmodx closes this is the last function called, so we want to close the file.&lt;br /&gt;
&lt;br /&gt;
==== Metamod HL API Functions Created ====&lt;br /&gt;
Now onward.  The Amxmodx functions are complete now we need to create the functions for the Metamod / HL API.  First we will create the most important function the registration function, in order to understand the funtions we first need to know what we are looking for.  So we exposed the following:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Ok so what the hell is this???  Well if you highlight and copy FN_RegUserMsg_Post then open up amxxmodule.h and do a search for '''FN_RegUserMsg_Post''' you will find the following:&lt;br /&gt;
&lt;br /&gt;
 #ifdef FN_RegUserMsg_Post&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
 #endif // FN_RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
This is where we get the function declaration from.  So we copy the following:&lt;br /&gt;
&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
&lt;br /&gt;
And make a function out of it as such:&lt;br /&gt;
&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Now this is the start of our function.  You notice the RETURN_META_VALUE, this is a metamod return, because the function is returning an int we need to tell metamod to ignore what we have done with this function and return an integer.  This is what this means.  One of the others we will be returning alot is as follows:&lt;br /&gt;
&lt;br /&gt;
 RETURN_META(MRES_IGNORED);&lt;br /&gt;
&lt;br /&gt;
This is what we use when a function returns a void or nothing.  This function is pretty basic.  First thing we are going to do is grab the original return value that we would have gotten if we wanted to do stuff with this function.  In this case it is the message id:&lt;br /&gt;
&lt;br /&gt;
 int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
&lt;br /&gt;
Next we are going to assign the message id to our message structure at the location of the message id...bit confusing but important:&lt;br /&gt;
&lt;br /&gt;
 g_user_msg[msgid].id = msgid;&lt;br /&gt;
&lt;br /&gt;
Finally we are going to assign the message name to the message structure using a string copy:&lt;br /&gt;
&lt;br /&gt;
 strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
&lt;br /&gt;
Ok now we have the register function done it will look like so when done:&lt;br /&gt;
&lt;br /&gt;
 // First thing when all the messages are sent out to a client we grab them and take a look at them&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
      g_user_msg[msgid].id = msgid;&lt;br /&gt;
      strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to worry about the next important function, the message begins function.  This is called when a message is initialized on the server to be sent out to someone somewhere.  It looks like this:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Voila...now this is very important part because this is where and when the message begins...remember we can '''NEVER''' call another message_begin while we are in a message...so we have to wait until after when we hit message_end.  Now we are going to add some stuff to this to make it work.  First we want to make sure that its not a bogus or bad message:&lt;br /&gt;
&lt;br /&gt;
 if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
 {&lt;br /&gt;
      g_state = -1;&lt;br /&gt;
      RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
If it is we bounce out of this message.  If not then its a good message and we want to carry on.  Next thing we do is print out that we are in the message beginning to both the console and the file:&lt;br /&gt;
&lt;br /&gt;
 // Log the message Name&lt;br /&gt;
 printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
&lt;br /&gt;
As you can see we are printing out the message id the message name that we stored in our structure earlier.  Once this is done we will check the message destination and print that out as well.  There are 3 places a message could be going 0 = all, 1 - 32 is Individually to a player, and 33 - MAX_REG_MSGS is all others.  So we will tell which it is with the following:&lt;br /&gt;
&lt;br /&gt;
 // Is it too all, or to an individual&lt;br /&gt;
 if(msg_dest == 0)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
       if(player)&lt;br /&gt;
       {&lt;br /&gt;
              int id = ENTINDEX(player);&lt;br /&gt;
              const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
              const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
              printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
              fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
       }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Self explanatory, finally we need to set the global variable g_state to zero:&lt;br /&gt;
&lt;br /&gt;
 g_state = 0;&lt;br /&gt;
&lt;br /&gt;
So this funtion is done.  Here is the end result:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
      {&lt;br /&gt;
            g_state = -1;&lt;br /&gt;
            RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      // Log the message Name&lt;br /&gt;
      printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
      fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 &lt;br /&gt;
      // Is it too all, or to an individual&lt;br /&gt;
      if(msg_dest == 0)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
            if(player)&lt;br /&gt;
            {&lt;br /&gt;
                  int id = ENTINDEX(player);&lt;br /&gt;
                  const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
                  const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
                  printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
                  fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
            }&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      g_state = 0;&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ok from here on out it will be a bit repetitive so I will just show them too you:&lt;br /&gt;
&lt;br /&gt;
 void WriteByte_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteChar_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      char buffer[10];&lt;br /&gt;
      _itoa_s(iValue, buffer, 10);&lt;br /&gt;
      printf(&amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteShort_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteLong_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteAngle_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteCoord_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteString_Post(const char *sz) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteEntity_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The last but not least function is the message end function.  It too is simple to understand:&lt;br /&gt;
&lt;br /&gt;
 void MessageEnd_Post(void) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
      fprintf(stream, &amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
      fflush(stream);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The only thing weird about this one is the flush...this just ensures the data we just collected gets sent to the file.  Well thats it...we're done...all thats left is the compile and moving the module to the addons/amxmodx/modules/ directory then adding it to the addons/amxmodx/configs/modules.ini file at the bottom.  Remember to name it dod_mm not dod_mm_amxx.dll just the first part.&lt;br /&gt;
&lt;br /&gt;
== In Conclusion ==&lt;br /&gt;
&lt;br /&gt;
Ok we are setup to start compiling, you can grab the source code to any of the modules at amxmodx and compile them now...or just play about.  I suggest you try the easy one that you can grab here: [http://forums.alliedmods.net/showthread.php?t=18763  ESF Model Changing Module] just to look at it.  Here is the direct download: [http://forums.alliedmods.net/attachment.php?attachmentid=4104&amp;amp;d=1128187905 esf_model_changer]&lt;br /&gt;
&lt;br /&gt;
The files for this project can be found [http://www.dodplugins.net/forums/showthread.php?p=2471 DoD Message Module Tutorial / Module]&lt;br /&gt;
&lt;br /&gt;
I have made great use of this in helping in developing dodx and dodfun.&lt;br /&gt;
&lt;br /&gt;
Cheers!&lt;br /&gt;
Zor&lt;br /&gt;
&lt;br /&gt;
For more information, look in: [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx /svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx] or [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk.tar.gz?root=amxmodx&amp;amp;view=tar click here] to download a tarball of that directory.&lt;br /&gt;
&lt;br /&gt;
Copy these files into a new folder.  The amxxmodule.h/cpp files are the Module SDK backend.  You only need to edit the moduleconfig.h file to customize your module.&lt;br /&gt;
&lt;br /&gt;
[[Category:AMX_Mod_X]]&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=File:Main_header.jpg&amp;diff=5511</id>
		<title>File:Main header.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=File:Main_header.jpg&amp;diff=5511"/>
		<updated>2007-12-26T20:15:46Z</updated>

		<summary type="html">&lt;p&gt;Zor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=File:Adding_item.jpg&amp;diff=5510</id>
		<title>File:Adding item.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=File:Adding_item.jpg&amp;diff=5510"/>
		<updated>2007-12-26T20:15:37Z</updated>

		<summary type="html">&lt;p&gt;Zor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=File:Directories.JPG&amp;diff=5509</id>
		<title>File:Directories.JPG</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=File:Directories.JPG&amp;diff=5509"/>
		<updated>2007-12-26T20:15:23Z</updated>

		<summary type="html">&lt;p&gt;Zor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=File:Vc--.jpg&amp;diff=5508</id>
		<title>File:Vc--.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=File:Vc--.jpg&amp;diff=5508"/>
		<updated>2007-12-26T20:15:12Z</updated>

		<summary type="html">&lt;p&gt;Zor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=File:Pands.jpg&amp;diff=5507</id>
		<title>File:Pands.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=File:Pands.jpg&amp;diff=5507"/>
		<updated>2007-12-26T20:15:01Z</updated>

		<summary type="html">&lt;p&gt;Zor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=File:Options.jpg&amp;diff=5506</id>
		<title>File:Options.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=File:Options.jpg&amp;diff=5506"/>
		<updated>2007-12-26T20:14:36Z</updated>

		<summary type="html">&lt;p&gt;Zor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5505</id>
		<title>Module Writing (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5505"/>
		<updated>2007-12-26T20:11:32Z</updated>

		<summary type="html">&lt;p&gt;Zor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AMX Mod X Modules are written in C or C++ (the API is C compatible).&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
So you want to be a module developer for Amxmodx!  Well its not too hard.  I will be doing this in Windows as I dont have a Linux box to frick around with at the moment.  So, windows only at this point, a Linux version will be forthcoming!&lt;br /&gt;
&lt;br /&gt;
== Necessary Files ==&lt;br /&gt;
Well first we need to gather up the neccessary files for your computer.  The first thing you need to know, its NOT complicated.  If you can script in pawn, you can program in C/C++!&lt;br /&gt;
&lt;br /&gt;
=== Metamod ===&lt;br /&gt;
As we all know metamod is the backbone of the whole thing, without this all mods for and HL game would not be possible unless we programmed it ourselves!  So many thanks to willday for the development of Metamod, and for BAILOPAN and his crew helping to maintain and update it!  Hats off to all!  Ok so now onto the file gathering!  First thing is first we need to goto Metamod: [http://metamod.org/ metamod.org] from there we need to gather up 2 SDK's.&lt;br /&gt;
&lt;br /&gt;
==== HL-SDK ====&lt;br /&gt;
The Half Life SDK is the first thing in the list to gather up!  We can get this at the same spot that we will be gathering up metamod!  So we click on the SDK Link or goto:  [http://metamod.sourceforge.net/files/sdk/ Here].  From here we need to grab the HLSDK, preferably the one that has been tweeked out for Metamod.  So we are looking for this:&lt;br /&gt;
&lt;br /&gt;
 hlsdk-2.3-p3.zip                - The Standard SDK v2.3 with various fixes and&lt;br /&gt;
                                   updates, that Metamod is compiled against.&lt;br /&gt;
                                   Files are in DOS format.&lt;br /&gt;
&lt;br /&gt;
So lets grab the [http://metamod.sourceforge.net/files/sdk/hlsdk-2.3-p3.zip hlsdk-2.3-p3.zip] first!  Once this is done you will need to extract this to your Hard Drive.  What we will be doing is extracting these files to the following directory, these will be arbitray directories for ease of the document so dont sweat it once you proficient you can move them around :-)  Ok so extract the files to the following directory: c:\sdk_files\&lt;br /&gt;
&lt;br /&gt;
==== Metamod SDK ====&lt;br /&gt;
Ok, so we have the HL-SDK we now need to Metamod SDK.  So we need to go back to the root of Metamod &lt;br /&gt;
[http://metamod.org/ here] and then click on the  v1.xx Sourcecode zip to get the latest SDK from Sourceforge, you can get that file from the best location for you or for a quick link click [http://prdownloads.sourceforge.net/metamod/metamod-1.19-win.src.zip?download metamod-1.xx-win.src.zip] to get the files.&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx SDK ==== &lt;br /&gt;
Now we need to grab the last of the SDK's so we can go carry on.  First we need to goto the Amxmodx Website so that we can get to the SDK via the Downloads area and SVN!  [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx.tar.gz?root=amxmodx&amp;amp;view=tar Amxmodx SDK].&lt;br /&gt;
&lt;br /&gt;
==== Unix2Dos the Files ====&lt;br /&gt;
So, once you have all the files we need to fix them up a bit.  One of the things that will become bothersome later is the Unix File Format that HLSDK / Metamod has, its suppose to be Windows, but its not, so we need to convert the files, soooo...we will use the following tutorial to fix this [[GnuWin32]] Once you have that setup you can use the following to repair all files easily [http://wiki.dodplugins.net/images/6/61/Repair.rar Repair.bat].&lt;br /&gt;
&lt;br /&gt;
== Compiler GUI ==&lt;br /&gt;
Now that we have all the SDK files we will need to get the Compiler.  The one that we will be using will be the Microsoft Visual 2005 Express Edition.  &lt;br /&gt;
&lt;br /&gt;
=== Visual C++ 2005 Express Edition ===&lt;br /&gt;
First thing you need to do is grab the web install files:  [http://go.microsoft.com/fwlink/?LinkId=51410&amp;amp;clcid=0x409 Visual C++ 2005 Express Edition] if you want to grab the network install you should grab the following: [http://msdn.microsoft.com/vstudio/express/support/install/ Network Install Files], for network install either grab the [http://go.microsoft.com/fwlink/?linkid=54766 Image File] or the [http://go.microsoft.com/fwlink/?linkid=57034 ISO File] your choice. Ok so now your have the iso/img file you need to either burn it or use a Virtual CD/DVD to install it.  I wont go into detail on this as its pretty simple, but make sure that you only install the Graphical IDE, if you want to you can install the Microsoft MSDN 2005 Express Edition, these are the help files that you can access by hitting F1 once in the GUI, if you haven't downloaded them, thats fine it will connect you to the Online version of them instead.&lt;br /&gt;
&lt;br /&gt;
=== Platform SDK ===&lt;br /&gt;
The platform SDK is a needed piece of kit, without it we wont be able to compile.  You will need to grab it from this site: [http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/ Platform SDK Site].  Specifically you need to grab proper file for your architecture, goto the above page and scroll down to the Files in This Download section.  Download the file that you need and install it.  Make sure to do a custom install unless you dont mind a bunch of crap on your computer.  You want to have only the following items installed:&lt;br /&gt;
&lt;br /&gt;
 Microsoft Windows Core SDK&lt;br /&gt;
 Microsoft Direct Show SDK&lt;br /&gt;
 Microsoft Media Services SDK&lt;br /&gt;
&lt;br /&gt;
=== .NET SDK ===&lt;br /&gt;
Next we need to grab the Dot Net install and the Dot Net SDK.  You can grab the [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=262d25e3-f589-4842-8157-034d1e7cf3a3&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2fa%2fa%2fc%2faac39226-8825-44ce-90e3-bf8203e74006%2fdotnetfx.exe dotnet.1.1.exe] and install it.  Next you will need the .NET SDK, you can grapple [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=9B3A2CA6-3647-4070-9F41-A333C6B9181D&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f5%2f2%2f0%2f5202f918-306e-426d-9637-d7ee26fbe507%2fsetup.exe dotnet.1.1.sdk.exe]  Once these are installed your good to start up the GUI.&lt;br /&gt;
&lt;br /&gt;
== Setting up the GUI ==&lt;br /&gt;
Ok, so now we start up Visual C++, click on Start-&amp;gt;Program Files-&amp;gt;Visual C++ 2005 Express Edition-&amp;gt;Microsoft Visual C++ 2005 Express Edition duh...but just in case :-) allow it to go through the initialization and start up.  Once its started up you will need to do the following:&lt;br /&gt;
&lt;br /&gt;
 Click Tools-&amp;gt;Options&lt;br /&gt;
[[Image:options.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Now expand the Projects and Solutions are by clicking on the + symbol to the left of the name.&lt;br /&gt;
[[Image:pands.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Click on the VC++ Directories.  Now on the top left of that box you will see a drop box that says Show Directories For&lt;br /&gt;
 Click the drop  box and select Include Files.&lt;br /&gt;
[[Image:vc--.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now you need to add the following Directories to this list at the bottom:&lt;br /&gt;
&lt;br /&gt;
 C:\Program Files\Microsoft Platform SDK\Include&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\common&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\dlls&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\engine&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\pm_shared&lt;br /&gt;
 C:\sdk_files\metamod-1.19\metamod&lt;br /&gt;
 C:\sdk_files\amxmodx&lt;br /&gt;
[[Image:Directories.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Message Module ( Demo ) ==&lt;br /&gt;
Right, now that we have the base all good and done, we need to get going with the module.  First thing we need to do is create a new module, for ease of use I have for the moment made up a demo module called [http://www.dodplugins.net/files/dod_mm.zip dod_mm], DoD Message Module.  Grab this and extract it to the c:\sdk_files directory.&lt;br /&gt;
&lt;br /&gt;
=== Editing Module Information ===&lt;br /&gt;
First things first you need to open up the dod_mm.vcproj this will open up Visual C++.  Once its open you will see on the left a dod_mm under the solutions area.  Open moduleconfig.h.  In here we will look for the following:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;--ENTER NAME HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;--ENTER VERSION HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;--ENTER AUTHOR HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;--ENTER URL HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;--ENTER LOGTAG HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;--ENTER LIBRARY HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
This is the infor that will be displayed about the module when you have it running on your server.  Lets say you type in amxx modules in the command line, you will get information about all the modules running on your server, including this one, once its done.  So now we need to edit it to reflect our new module:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;DoD Message Module&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;0.1&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;DoD Plugins Community&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;http://www.dodplugins.net&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;DoDMM&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;dod_mm&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
=== Exposing Functions ===&lt;br /&gt;
So now that this is done we need to tell the module to use Metamod Natives, this is done by finding the followin:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 // #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
And changing it to:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
Or in other words uncommenting it.  :-)  So now that this is done we have access to loads of stuff that metamod has to offer us as well as Amxmodx stuff.  Once this is done we now need to expose the functions from metamod that we will be using for this message module.  &lt;br /&gt;
&lt;br /&gt;
==== Amxmodx ====&lt;br /&gt;
If you scroll down you will find the following two functions from amxmodx that we will be using:&lt;br /&gt;
&lt;br /&gt;
 /** AMXX attach&lt;br /&gt;
  * Do native functions init here (MF_AddNatives)&lt;br /&gt;
  */&lt;br /&gt;
 // #define FN_AMXX_ATTACH OnAmxxAttach&lt;br /&gt;
 &lt;br /&gt;
 /** AMXX Detach (unload) */&lt;br /&gt;
 // #define FN_AMXX_DETACH OnAmxxDetach&lt;br /&gt;
&lt;br /&gt;
We will expose these by uncommenting them.  Later on in this document I will explain where the function itself goes and what goes in them.&lt;br /&gt;
&lt;br /&gt;
==== HL API ====&lt;br /&gt;
Next we will expose some of the functions that come from the HL Server Engine that Metamod has exposed for us.  The functions that we are exposing are ones that we will need specific to messages:&lt;br /&gt;
&lt;br /&gt;
 #define FN_MessageBegin_Post					MessageBegin_Post&lt;br /&gt;
 #define FN_MessageEnd_Post					MessageEnd_Post&lt;br /&gt;
 #define FN_WriteByte_Post					WriteByte_Post&lt;br /&gt;
 #define FN_WriteChar_Post					WriteChar_Post&lt;br /&gt;
 #define FN_WriteShort_Post					WriteShort_Post&lt;br /&gt;
 #define FN_WriteLong_Post					WriteLong_Post&lt;br /&gt;
 #define FN_WriteAngle_Post					WriteAngle_Post&lt;br /&gt;
 #define FN_WriteCoord_Post					WriteCoord_Post&lt;br /&gt;
 #define FN_WriteString_Post					WriteString_Post&lt;br /&gt;
 #define FN_WriteEntity_Post					WriteEntity_Post&lt;br /&gt;
&lt;br /&gt;
These are the actual messages that will be caught.  Finally we need to catch the registering of those messages we can see in [[Meta_Game]].  This is the function we are going to expose next:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Now that all the functions that we will be using have been exposed we are good to carry on with the meat of the module.&lt;br /&gt;
&lt;br /&gt;
=== Developing Module ===&lt;br /&gt;
Right on, now we have the basics down.  We are ready to start programming.  So we need a main file now.  So now we need to right click on the dod_mm and goto Add-&amp;gt;New Item as shown in the picture below:&lt;br /&gt;
&lt;br /&gt;
[[Image:adding_item.jpg]]&lt;br /&gt;
&lt;br /&gt;
Once thats done a new window comes up, we need to click on code, then Header File (.h) giving it the name main.h&lt;br /&gt;
&lt;br /&gt;
[[Image:main_header.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now we have a file to work with.  So, we need to first set it up as a standard Header file so that it is only included once into memory.  So we add the following:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
So this will ensure that all the code we put between those two comments are only loaded once into the compilation process.  Now that we have this part complete we will start coding.  As we are making a module to catch all the Messages that occur on a HL DoD Server the first thing we need to do is create a structure to keep all the data that we will use.  This structure will be called StructUserMsg and will contain two members the id of the message which can be anything from 0 - 256 messages and the name of the message.  We can get these names from [[Meta_Game]].  These will be the messages that will pop up.  Now that we have this done the file should look like so:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
      #include &amp;quot;sdk/amxxmodule.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
      struct StructUserMsg &lt;br /&gt;
      {&lt;br /&gt;
            int id;&lt;br /&gt;
            char name[256];&lt;br /&gt;
      };&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
==== CPP File ====&lt;br /&gt;
So now that we have the structure done the first thing we have to do is make a CPP file the same as we did the Header file except with a CPP.  We will name this file the same as the Header that we created as this cpp will call the header to get its information.  Once we have created the file the first thing we need to do is call the header file by adding this to the top:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;main.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
That will ensure to grab our structure so the rest of the program knows what it is.  Once this is done we need to create a few global variables to use.  The first one we will use is one that will allow us to output to a file all the data that we are gathering:&lt;br /&gt;
&lt;br /&gt;
 FILE *stream;&lt;br /&gt;
&lt;br /&gt;
Next we need a global state variable so that we know what call we are on within the message.  This will count all the calls to each specific message:&lt;br /&gt;
&lt;br /&gt;
 int g_state;&lt;br /&gt;
&lt;br /&gt;
Now finally we need to create the global variable for the structure we created:&lt;br /&gt;
&lt;br /&gt;
 StructUserMsg g_user_msg[MAX_REG_MSGS];&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx Functions Created ====&lt;br /&gt;
So this is most important.  We created a StructUserMsg array of MAX_REG_MSGS in length, this is 256.  Ok we are good now on the globals.  Pretty simple.  Now remember those functions we exposed, well we need to create those functions so that Amxmodx will call them.  First we will look at the Amxmodx functions:&lt;br /&gt;
&lt;br /&gt;
 void OnAmxxAttach()&lt;br /&gt;
 {&lt;br /&gt;
      fopen_s(&amp;amp;stream, &amp;quot;messages.txt&amp;quot;, &amp;quot;w&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void OnAmxxDetach()&lt;br /&gt;
 {&lt;br /&gt;
      fclose(stream);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
So now that these are created lets understand them.  When amxmodx starts up and calls the module we are creating the OnAmxxAttach is the first thing that is called, in our case we are opening up a file called messages.txt that will be in the base HL directory.  This will contain all the output from our module.  &lt;br /&gt;
&lt;br /&gt;
 '''*** NOTE *** This will take up alot of room, so be carefull'''&lt;br /&gt;
&lt;br /&gt;
Ok, the second function is just the opposite, when amxmodx closes this is the last function called, so we want to close the file.&lt;br /&gt;
&lt;br /&gt;
==== Metamod HL API Functions Created ====&lt;br /&gt;
Now onward.  The Amxmodx functions are complete now we need to create the functions for the Metamod / HL API.  First we will create the most important function the registration function, in order to understand the funtions we first need to know what we are looking for.  So we exposed the following:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Ok so what the hell is this???  Well if you highlight and copy FN_RegUserMsg_Post then open up amxxmodule.h and do a search for '''FN_RegUserMsg_Post''' you will find the following:&lt;br /&gt;
&lt;br /&gt;
 #ifdef FN_RegUserMsg_Post&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
 #endif // FN_RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
This is where we get the function declaration from.  So we copy the following:&lt;br /&gt;
&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
&lt;br /&gt;
And make a function out of it as such:&lt;br /&gt;
&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Now this is the start of our function.  You notice the RETURN_META_VALUE, this is a metamod return, because the function is returning an int we need to tell metamod to ignore what we have done with this function and return an integer.  This is what this means.  One of the others we will be returning alot is as follows:&lt;br /&gt;
&lt;br /&gt;
 RETURN_META(MRES_IGNORED);&lt;br /&gt;
&lt;br /&gt;
This is what we use when a function returns a void or nothing.  This function is pretty basic.  First thing we are going to do is grab the original return value that we would have gotten if we wanted to do stuff with this function.  In this case it is the message id:&lt;br /&gt;
&lt;br /&gt;
 int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
&lt;br /&gt;
Next we are going to assign the message id to our message structure at the location of the message id...bit confusing but important:&lt;br /&gt;
&lt;br /&gt;
 g_user_msg[msgid].id = msgid;&lt;br /&gt;
&lt;br /&gt;
Finally we are going to assign the message name to the message structure using a string copy:&lt;br /&gt;
&lt;br /&gt;
 strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
&lt;br /&gt;
Ok now we have the register function done it will look like so when done:&lt;br /&gt;
&lt;br /&gt;
 // First thing when all the messages are sent out to a client we grab them and take a look at them&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
      g_user_msg[msgid].id = msgid;&lt;br /&gt;
      strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to worry about the next important function, the message begins function.  This is called when a message is initialized on the server to be sent out to someone somewhere.  It looks like this:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Voila...now this is very important part because this is where and when the message begins...remember we can '''NEVER''' call another message_begin while we are in a message...so we have to wait until after when we hit message_end.  Now we are going to add some stuff to this to make it work.  First we want to make sure that its not a bogus or bad message:&lt;br /&gt;
&lt;br /&gt;
 if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
 {&lt;br /&gt;
      g_state = -1;&lt;br /&gt;
      RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
If it is we bounce out of this message.  If not then its a good message and we want to carry on.  Next thing we do is print out that we are in the message beginning to both the console and the file:&lt;br /&gt;
&lt;br /&gt;
 // Log the message Name&lt;br /&gt;
 printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
&lt;br /&gt;
As you can see we are printing out the message id the message name that we stored in our structure earlier.  Once this is done we will check the message destination and print that out as well.  There are 3 places a message could be going 0 = all, 1 - 32 is Individually to a player, and 33 - MAX_REG_MSGS is all others.  So we will tell which it is with the following:&lt;br /&gt;
&lt;br /&gt;
 // Is it too all, or to an individual&lt;br /&gt;
 if(msg_dest == 0)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
       if(player)&lt;br /&gt;
       {&lt;br /&gt;
              int id = ENTINDEX(player);&lt;br /&gt;
              const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
              const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
              printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
              fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
       }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Self explanatory, finally we need to set the global variable g_state to zero:&lt;br /&gt;
&lt;br /&gt;
 g_state = 0;&lt;br /&gt;
&lt;br /&gt;
So this funtion is done.  Here is the end result:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
      {&lt;br /&gt;
            g_state = -1;&lt;br /&gt;
            RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      // Log the message Name&lt;br /&gt;
      printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
      fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 &lt;br /&gt;
      // Is it too all, or to an individual&lt;br /&gt;
      if(msg_dest == 0)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
            if(player)&lt;br /&gt;
            {&lt;br /&gt;
                  int id = ENTINDEX(player);&lt;br /&gt;
                  const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
                  const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
                  printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
                  fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
            }&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      g_state = 0;&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ok from here on out it will be a bit repetitive so I will just show them too you:&lt;br /&gt;
&lt;br /&gt;
 void WriteByte_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteChar_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      char buffer[10];&lt;br /&gt;
      _itoa_s(iValue, buffer, 10);&lt;br /&gt;
      printf(&amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteShort_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteLong_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteAngle_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteCoord_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteString_Post(const char *sz) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteEntity_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The last but not least function is the message end function.  It too is simple to understand:&lt;br /&gt;
&lt;br /&gt;
 void MessageEnd_Post(void) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
      fprintf(stream, &amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
      fflush(stream);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The only thing weird about this one is the flush...this just ensures the data we just collected gets sent to the file.  Well thats it...we're done...all thats left is the compile and moving the module to the addons/amxmodx/modules/ directory then adding it to the addons/amxmodx/configs/modules.ini file at the bottom.  Remember to name it dod_mm not dod_mm_amxx.dll just the first part.&lt;br /&gt;
  &lt;br /&gt;
== In Conclusion ==&lt;br /&gt;
&lt;br /&gt;
Ok we are setup to start compiling, you can grab the source code to any of the modules at amxmodx and compile them now...or just play about.  I suggest you try the easy one that you can grab here: [http://forums.alliedmods.net/showthread.php?t=18763  ESF Model Changing Module] just to look at it.  Here is the direct download: [http://forums.alliedmods.net/attachment.php?attachmentid=4104&amp;amp;d=1128187905 esf_model_changer]&lt;br /&gt;
&lt;br /&gt;
The files for this project can be found [http://www.dodplugins.net/forums/showthread.php?p=2471 DoD Message Module Tutorial / Module]&lt;br /&gt;
&lt;br /&gt;
I have made great use of this in helping in developing dodx and dodfun.&lt;br /&gt;
&lt;br /&gt;
Cheers!&lt;br /&gt;
Zor&lt;br /&gt;
&lt;br /&gt;
For more information, look in: [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx /svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx] or [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk.tar.gz?root=amxmodx&amp;amp;view=tar click here] to download a tarball of that directory.&lt;br /&gt;
&lt;br /&gt;
Copy these files into a new folder.  The amxxmodule.h/cpp files are the Module SDK backend.  You only need to edit the moduleconfig.h file to customize your module.&lt;br /&gt;
&lt;br /&gt;
[[Category:AMX_Mod_X]]&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5504</id>
		<title>Module Writing (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Module_Writing_(AMX_Mod_X)&amp;diff=5504"/>
		<updated>2007-12-26T20:08:00Z</updated>

		<summary type="html">&lt;p&gt;Zor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AMX Mod X Modules are written in C or C++ (the API is C compatible).&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
So you want to be a module developer for Amxmodx!  Well its not too hard.  I will be doing this in Windows as I dont have a Linux box to frick around with at the moment.  So, windows only at this point, a Linux version will be forthcoming!&lt;br /&gt;
&lt;br /&gt;
== Necessary Files ==&lt;br /&gt;
Well first we need to gather up the neccessary files for your computer.  The first thing you need to know, its NOT complicated.  If you can script in pawn, you can program in C/C++!&lt;br /&gt;
&lt;br /&gt;
=== Metamod ===&lt;br /&gt;
As we all know metamod is the backbone of the whole thing, without this all mods for and HL game would not be possible unless we programmed it ourselves!  So many thanks to willday for the development of Metamod, and for BAILOPAN and his crew helping to maintain and update it!  Hats off to all!  Ok so now onto the file gathering!  First thing is first we need to goto Metamod: [http://metamod.org/ metamod.org] from there we need to gather up 2 SDK's.&lt;br /&gt;
&lt;br /&gt;
==== HL-SDK ====&lt;br /&gt;
The Half Life SDK is the first thing in the list to gather up!  We can get this at the same spot that we will be gathering up metamod!  So we click on the SDK Link or goto:  [http://metamod.sourceforge.net/files/sdk/ Here].  From here we need to grab the HLSDK, preferably the one that has been tweeked out for Metamod.  So we are looking for this:&lt;br /&gt;
&lt;br /&gt;
 hlsdk-2.3-p3.zip                - The Standard SDK v2.3 with various fixes and&lt;br /&gt;
                                   updates, that Metamod is compiled against.&lt;br /&gt;
                                   Files are in DOS format.&lt;br /&gt;
&lt;br /&gt;
So lets grab the [http://metamod.sourceforge.net/files/sdk/hlsdk-2.3-p3.zip hlsdk-2.3-p3.zip] first!  Once this is done you will need to extract this to your Hard Drive.  What we will be doing is extracting these files to the following directory, these will be arbitray directories for ease of the document so dont sweat it once you proficient you can move them around :-)  Ok so extract the files to the following directory: c:\sdk_files\&lt;br /&gt;
&lt;br /&gt;
==== Metamod SDK ====&lt;br /&gt;
Ok, so we have the HL-SDK we now need to Metamod SDK.  So we need to go back to the root of Metamod &lt;br /&gt;
[http://metamod.org/ here] and then click on the  v1.xx Sourcecode zip to get the latest SDK from Sourceforge, you can get that file from the best location for you or for a quick link click [http://prdownloads.sourceforge.net/metamod/metamod-1.19-win.src.zip?download metamod-1.xx-win.src.zip] to get the files.&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx SDK ==== &lt;br /&gt;
Now we need to grab the last of the SDK's so we can go carry on.  First we need to goto the Amxmodx Website so that we can get to the SDK via the Downloads area and SVN!  [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx.tar.gz?root=amxmodx&amp;amp;view=tar Amxmodx SDK].&lt;br /&gt;
&lt;br /&gt;
==== Unix2Dos the Files ====&lt;br /&gt;
So, once you have all the files we need to fix them up a bit.  One of the things that will become bothersome later is the Unix File Format that HLSDK / Metamod has, its suppose to be Windows, but its not, so we need to convert the files, soooo...we will use the following tutorial to fix this [[GnuWin32]] Once you have that setup you can use the following to repair all files easily [http://docs.dodplugins.net/images/6/61/Repair.rar Repair.bat].&lt;br /&gt;
&lt;br /&gt;
== Compiler GUI ==&lt;br /&gt;
Now that we have all the SDK files we will need to get the Compiler.  The one that we will be using will be the Microsoft Visual 2005 Express Edition.  &lt;br /&gt;
&lt;br /&gt;
=== Visual C++ 2005 Express Edition ===&lt;br /&gt;
First thing you need to do is grab the web install files:  [http://go.microsoft.com/fwlink/?LinkId=51410&amp;amp;clcid=0x409 Visual C++ 2005 Express Edition] if you want to grab the network install you should grab the following: [http://msdn.microsoft.com/vstudio/express/support/install/ Network Install Files], for network install either grab the [http://go.microsoft.com/fwlink/?linkid=54766 Image File] or the [http://go.microsoft.com/fwlink/?linkid=57034 ISO File] your choice. Ok so now your have the iso/img file you need to either burn it or use a Virtual CD/DVD to install it.  I wont go into detail on this as its pretty simple, but make sure that you only install the Graphical IDE, if you want to you can install the Microsoft MSDN 2005 Express Edition, these are the help files that you can access by hitting F1 once in the GUI, if you haven't downloaded them, thats fine it will connect you to the Online version of them instead.&lt;br /&gt;
&lt;br /&gt;
=== Platform SDK ===&lt;br /&gt;
The platform SDK is a needed piece of kit, without it we wont be able to compile.  You will need to grab it from this site: [http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/ Platform SDK Site].  Specifically you need to grab proper file for your architecture, goto the above page and scroll down to the Files in This Download section.  Download the file that you need and install it.  Make sure to do a custom install unless you dont mind a bunch of crap on your computer.  You want to have only the following items installed:&lt;br /&gt;
&lt;br /&gt;
 Microsoft Windows Core SDK&lt;br /&gt;
 Microsoft Direct Show SDK&lt;br /&gt;
 Microsoft Media Services SDK&lt;br /&gt;
&lt;br /&gt;
=== .NET SDK ===&lt;br /&gt;
Next we need to grab the Dot Net install and the Dot Net SDK.  You can grab the [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=262d25e3-f589-4842-8157-034d1e7cf3a3&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2fa%2fa%2fc%2faac39226-8825-44ce-90e3-bf8203e74006%2fdotnetfx.exe dotnet.1.1.exe] and install it.  Next you will need the .NET SDK, you can grapple [http://www.microsoft.com/downloads/info.aspx?na=90&amp;amp;p=&amp;amp;SrcDisplayLang=en&amp;amp;SrcCategoryId=&amp;amp;SrcFamilyId=9B3A2CA6-3647-4070-9F41-A333C6B9181D&amp;amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f5%2f2%2f0%2f5202f918-306e-426d-9637-d7ee26fbe507%2fsetup.exe dotnet.1.1.sdk.exe]  Once these are installed your good to start up the GUI.&lt;br /&gt;
&lt;br /&gt;
== Setting up the GUI ==&lt;br /&gt;
Ok, so now we start up Visual C++, click on Start-&amp;gt;Program Files-&amp;gt;Visual C++ 2005 Express Edition-&amp;gt;Microsoft Visual C++ 2005 Express Edition duh...but just in case :-) allow it to go through the initialization and start up.  Once its started up you will need to do the following:&lt;br /&gt;
&lt;br /&gt;
 Click Tools-&amp;gt;Options&lt;br /&gt;
[[Image:options.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Now expand the Projects and Solutions are by clicking on the + symbol to the left of the name.&lt;br /&gt;
[[Image:pands.jpg]]&lt;br /&gt;
&lt;br /&gt;
 Click on the VC++ Directories.  Now on the top left of that box you will see a drop box that says Show Directories For&lt;br /&gt;
 Click the drop  box and select Include Files.&lt;br /&gt;
[[Image:vc--.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now you need to add the following Directories to this list at the bottom:&lt;br /&gt;
&lt;br /&gt;
 C:\Program Files\Microsoft Platform SDK\Include&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\common&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\dlls&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\engine&lt;br /&gt;
 C:\sdk_files\hlsdk-2.3-p3\multiplayer\pm_shared&lt;br /&gt;
 C:\sdk_files\metamod-1.19\metamod&lt;br /&gt;
 C:\sdk_files\amxmodx&lt;br /&gt;
[[Image:Directories.JPG]]&lt;br /&gt;
&lt;br /&gt;
== Message Module ( Demo ) ==&lt;br /&gt;
Right, now that we have the base all good and done, we need to get going with the module.  First thing we need to do is create a new module, for ease of use I have for the moment made up a demo module called [http://www.dodplugins.net/files/dod_mm.zip dod_mm], DoD Message Module.  Grab this and extract it to the c:\sdk_files directory.&lt;br /&gt;
&lt;br /&gt;
=== Editing Module Information ===&lt;br /&gt;
First things first you need to open up the dod_mm.vcproj this will open up Visual C++.  Once its open you will see on the left a dod_mm under the solutions area.  Open moduleconfig.h.  In here we will look for the following:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;--ENTER NAME HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;--ENTER VERSION HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;--ENTER AUTHOR HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;--ENTER URL HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;--ENTER LOGTAG HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;--ENTER LIBRARY HERE--&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
This is the infor that will be displayed about the module when you have it running on your server.  Lets say you type in amxx modules in the command line, you will get information about all the modules running on your server, including this one, once its done.  So now we need to edit it to reflect our new module:&lt;br /&gt;
&lt;br /&gt;
 #define MODULE_NAME &amp;quot;DoD Message Module&amp;quot;&lt;br /&gt;
 #define MODULE_VERSION &amp;quot;0.1&amp;quot;&lt;br /&gt;
 #define MODULE_AUTHOR &amp;quot;DoD Plugins Community&amp;quot;&lt;br /&gt;
 #define MODULE_URL &amp;quot;http://www.dodplugins.net&amp;quot;&lt;br /&gt;
 #define MODULE_LOGTAG &amp;quot;DoDMM&amp;quot;&lt;br /&gt;
 #define MODULE_LIBRARY &amp;quot;dod_mm&amp;quot;&lt;br /&gt;
 #define MODULE_LIBCLASS &amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
=== Exposing Functions ===&lt;br /&gt;
So now that this is done we need to tell the module to use Metamod Natives, this is done by finding the followin:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 // #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
And changing it to:&lt;br /&gt;
&lt;br /&gt;
 // metamod plugin?&lt;br /&gt;
 #define USE_METAMOD&lt;br /&gt;
&lt;br /&gt;
Or in other words uncommenting it.  :-)  So now that this is done we have access to loads of stuff that metamod has to offer us as well as Amxmodx stuff.  Once this is done we now need to expose the functions from metamod that we will be using for this message module.  &lt;br /&gt;
&lt;br /&gt;
==== Amxmodx ====&lt;br /&gt;
If you scroll down you will find the following two functions from amxmodx that we will be using:&lt;br /&gt;
&lt;br /&gt;
 /** AMXX attach&lt;br /&gt;
  * Do native functions init here (MF_AddNatives)&lt;br /&gt;
  */&lt;br /&gt;
 // #define FN_AMXX_ATTACH OnAmxxAttach&lt;br /&gt;
 &lt;br /&gt;
 /** AMXX Detach (unload) */&lt;br /&gt;
 // #define FN_AMXX_DETACH OnAmxxDetach&lt;br /&gt;
&lt;br /&gt;
We will expose these by uncommenting them.  Later on in this document I will explain where the function itself goes and what goes in them.&lt;br /&gt;
&lt;br /&gt;
==== HL API ====&lt;br /&gt;
Next we will expose some of the functions that come from the HL Server Engine that Metamod has exposed for us.  The functions that we are exposing are ones that we will need specific to messages:&lt;br /&gt;
&lt;br /&gt;
 #define FN_MessageBegin_Post					MessageBegin_Post&lt;br /&gt;
 #define FN_MessageEnd_Post					MessageEnd_Post&lt;br /&gt;
 #define FN_WriteByte_Post					WriteByte_Post&lt;br /&gt;
 #define FN_WriteChar_Post					WriteChar_Post&lt;br /&gt;
 #define FN_WriteShort_Post					WriteShort_Post&lt;br /&gt;
 #define FN_WriteLong_Post					WriteLong_Post&lt;br /&gt;
 #define FN_WriteAngle_Post					WriteAngle_Post&lt;br /&gt;
 #define FN_WriteCoord_Post					WriteCoord_Post&lt;br /&gt;
 #define FN_WriteString_Post					WriteString_Post&lt;br /&gt;
 #define FN_WriteEntity_Post					WriteEntity_Post&lt;br /&gt;
&lt;br /&gt;
These are the actual messages that will be caught.  Finally we need to catch the registering of those messages we can see in [[Meta_Game]].  This is the function we are going to expose next:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Now that all the functions that we will be using have been exposed we are good to carry on with the meat of the module.&lt;br /&gt;
&lt;br /&gt;
=== Developing Module ===&lt;br /&gt;
Right on, now we have the basics down.  We are ready to start programming.  So we need a main file now.  So now we need to right click on the dod_mm and goto Add-&amp;gt;New Item as shown in the picture below:&lt;br /&gt;
&lt;br /&gt;
[[Image:adding_item.jpg]]&lt;br /&gt;
&lt;br /&gt;
Once thats done a new window comes up, we need to click on code, then Header File (.h) giving it the name main.h&lt;br /&gt;
&lt;br /&gt;
[[Image:main_header.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now we have a file to work with.  So, we need to first set it up as a standard Header file so that it is only included once into memory.  So we add the following:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
So this will ensure that all the code we put between those two comments are only loaded once into the compilation process.  Now that we have this part complete we will start coding.  As we are making a module to catch all the Messages that occur on a HL DoD Server the first thing we need to do is create a structure to keep all the data that we will use.  This structure will be called StructUserMsg and will contain two members the id of the message which can be anything from 0 - 256 messages and the name of the message.  We can get these names from [[Meta_Game]].  These will be the messages that will pop up.  Now that we have this done the file should look like so:&lt;br /&gt;
&lt;br /&gt;
 #ifndef DOD_MM_H&lt;br /&gt;
      #define DOD_MM_H&lt;br /&gt;
      // Code will go between here&lt;br /&gt;
 &lt;br /&gt;
      #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
      #include &amp;quot;sdk/amxxmodule.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
      struct StructUserMsg &lt;br /&gt;
      {&lt;br /&gt;
            int id;&lt;br /&gt;
            char name[256];&lt;br /&gt;
      };&lt;br /&gt;
 &lt;br /&gt;
      // And Here!&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
==== CPP File ====&lt;br /&gt;
So now that we have the structure done the first thing we have to do is make a CPP file the same as we did the Header file except with a CPP.  We will name this file the same as the Header that we created as this cpp will call the header to get its information.  Once we have created the file the first thing we need to do is call the header file by adding this to the top:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;main.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
That will ensure to grab our structure so the rest of the program knows what it is.  Once this is done we need to create a few global variables to use.  The first one we will use is one that will allow us to output to a file all the data that we are gathering:&lt;br /&gt;
&lt;br /&gt;
 FILE *stream;&lt;br /&gt;
&lt;br /&gt;
Next we need a global state variable so that we know what call we are on within the message.  This will count all the calls to each specific message:&lt;br /&gt;
&lt;br /&gt;
 int g_state;&lt;br /&gt;
&lt;br /&gt;
Now finally we need to create the global variable for the structure we created:&lt;br /&gt;
&lt;br /&gt;
 StructUserMsg g_user_msg[MAX_REG_MSGS];&lt;br /&gt;
&lt;br /&gt;
==== Amxmodx Functions Created ====&lt;br /&gt;
So this is most important.  We created a StructUserMsg array of MAX_REG_MSGS in length, this is 256.  Ok we are good now on the globals.  Pretty simple.  Now remember those functions we exposed, well we need to create those functions so that Amxmodx will call them.  First we will look at the Amxmodx functions:&lt;br /&gt;
&lt;br /&gt;
 void OnAmxxAttach()&lt;br /&gt;
 {&lt;br /&gt;
      fopen_s(&amp;amp;stream, &amp;quot;messages.txt&amp;quot;, &amp;quot;w&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void OnAmxxDetach()&lt;br /&gt;
 {&lt;br /&gt;
      fclose(stream);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
So now that these are created lets understand them.  When amxmodx starts up and calls the module we are creating the OnAmxxAttach is the first thing that is called, in our case we are opening up a file called messages.txt that will be in the base HL directory.  This will contain all the output from our module.  &lt;br /&gt;
&lt;br /&gt;
 '''*** NOTE *** This will take up alot of room, so be carefull'''&lt;br /&gt;
&lt;br /&gt;
Ok, the second function is just the opposite, when amxmodx closes this is the last function called, so we want to close the file.&lt;br /&gt;
&lt;br /&gt;
==== Metamod HL API Functions Created ====&lt;br /&gt;
Now onward.  The Amxmodx functions are complete now we need to create the functions for the Metamod / HL API.  First we will create the most important function the registration function, in order to understand the funtions we first need to know what we are looking for.  So we exposed the following:&lt;br /&gt;
&lt;br /&gt;
 #define FN_RegUserMsg_Post					RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
Ok so what the hell is this???  Well if you highlight and copy FN_RegUserMsg_Post then open up amxxmodule.h and do a search for '''FN_RegUserMsg_Post''' you will find the following:&lt;br /&gt;
&lt;br /&gt;
 #ifdef FN_RegUserMsg_Post&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
 #endif // FN_RegUserMsg_Post&lt;br /&gt;
&lt;br /&gt;
This is where we get the function declaration from.  So we copy the following:&lt;br /&gt;
&lt;br /&gt;
 int FN_RegUserMsg_Post(const char *pszName, int iSize);&lt;br /&gt;
&lt;br /&gt;
And make a function out of it as such:&lt;br /&gt;
&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Now this is the start of our function.  You notice the RETURN_META_VALUE, this is a metamod return, because the function is returning an int we need to tell metamod to ignore what we have done with this function and return an integer.  This is what this means.  One of the others we will be returning alot is as follows:&lt;br /&gt;
&lt;br /&gt;
 RETURN_META(MRES_IGNORED);&lt;br /&gt;
&lt;br /&gt;
This is what we use when a function returns a void or nothing.  This function is pretty basic.  First thing we are going to do is grab the original return value that we would have gotten if we wanted to do stuff with this function.  In this case it is the message id:&lt;br /&gt;
&lt;br /&gt;
 int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
&lt;br /&gt;
Next we are going to assign the message id to our message structure at the location of the message id...bit confusing but important:&lt;br /&gt;
&lt;br /&gt;
 g_user_msg[msgid].id = msgid;&lt;br /&gt;
&lt;br /&gt;
Finally we are going to assign the message name to the message structure using a string copy:&lt;br /&gt;
&lt;br /&gt;
 strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
&lt;br /&gt;
Ok now we have the register function done it will look like so when done:&lt;br /&gt;
&lt;br /&gt;
 // First thing when all the messages are sent out to a client we grab them and take a look at them&lt;br /&gt;
 int RegUserMsg_Post(const char *pszName, int iSize)&lt;br /&gt;
 {&lt;br /&gt;
      int msgid = META_RESULT_ORIG_RET(int);&lt;br /&gt;
      g_user_msg[msgid].id = msgid;&lt;br /&gt;
      strcpy(g_user_msg[msgid].name, pszName);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META_VALUE(MRES_IGNORED, 0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to worry about the next important function, the message begins function.  This is called when a message is initialized on the server to be sent out to someone somewhere.  It looks like this:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Voila...now this is very important part because this is where and when the message begins...remember we can '''NEVER''' call another message_begin while we are in a message...so we have to wait until after when we hit message_end.  Now we are going to add some stuff to this to make it work.  First we want to make sure that its not a bogus or bad message:&lt;br /&gt;
&lt;br /&gt;
 if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
 {&lt;br /&gt;
      g_state = -1;&lt;br /&gt;
      RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
If it is we bounce out of this message.  If not then its a good message and we want to carry on.  Next thing we do is print out that we are in the message beginning to both the console and the file:&lt;br /&gt;
&lt;br /&gt;
 // Log the message Name&lt;br /&gt;
 printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
&lt;br /&gt;
As you can see we are printing out the message id the message name that we stored in our structure earlier.  Once this is done we will check the message destination and print that out as well.  There are 3 places a message could be going 0 = all, 1 - 32 is Individually to a player, and 33 - MAX_REG_MSGS is all others.  So we will tell which it is with the following:&lt;br /&gt;
&lt;br /&gt;
 // Is it too all, or to an individual&lt;br /&gt;
 if(msg_dest == 0)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
       if(player)&lt;br /&gt;
       {&lt;br /&gt;
              int id = ENTINDEX(player);&lt;br /&gt;
              const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
              const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
              printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
              fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
       }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 else&lt;br /&gt;
 {&lt;br /&gt;
       printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
       fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Self explanatory, finally we need to set the global variable g_state to zero:&lt;br /&gt;
&lt;br /&gt;
 g_state = 0;&lt;br /&gt;
&lt;br /&gt;
So this funtion is done.  Here is the end result:&lt;br /&gt;
&lt;br /&gt;
 // When a MESSAGE_BEGIN is sent we catch it After it gets to the player&lt;br /&gt;
 void MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *player) &lt;br /&gt;
 {&lt;br /&gt;
      if(msg_type &amp;lt; 0 || msg_type &amp;gt;= MAX_REG_MSGS)&lt;br /&gt;
      {&lt;br /&gt;
            g_state = -1;&lt;br /&gt;
            RETURN_META(MRES_IGNORED); // Bad Message&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      // Log the message Name&lt;br /&gt;
      printf(&amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
      fprintf(stream, &amp;quot;[Message ID]\t%d\n[Message Name]\t%s\n[Message Dest]\t&amp;quot;, g_user_msg[msg_type].id, g_user_msg[msg_type].name);&lt;br /&gt;
 &lt;br /&gt;
      // Is it too all, or to an individual&lt;br /&gt;
      if(msg_dest == 0)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;All\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;All\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else if(msg_dest &amp;gt; 0 &amp;amp;&amp;amp; msg_dest &amp;lt; 33)&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Individual\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
            if(player)&lt;br /&gt;
            {&lt;br /&gt;
                  int id = ENTINDEX(player);&lt;br /&gt;
                  const char* name = STRING(player-&amp;gt;v.netname);&lt;br /&gt;
                  const char* auth = (*g_engfuncs.pfnGetPlayerAuthId)(player);&lt;br /&gt;
                  printf(&amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
                  fprintf(stream, &amp;quot;[Player]\t&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%s&amp;gt;\n&amp;quot;, name, id, auth);&lt;br /&gt;
            }&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
            printf(&amp;quot;Other\n&amp;quot;);&lt;br /&gt;
            fprintf(stream, &amp;quot;Other\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      g_state = 0;&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ok from here on out it will be a bit repetitive so I will just show them too you:&lt;br /&gt;
&lt;br /&gt;
 void WriteByte_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Byte]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteChar_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      char buffer[10];&lt;br /&gt;
      _itoa_s(iValue, buffer, 10);&lt;br /&gt;
      printf(&amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Char]\t%s\n&amp;quot;, g_state++, buffer);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteShort_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Short]\t%d\n&amp;quot;, g_state++, (short)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteLong_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Long]\t%d\n&amp;quot;, g_state++, (long)iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteAngle_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Angle]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteCoord_Post(float flValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Coord]\t%d\n&amp;quot;, g_state++, (int)flValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteString_Post(const char *sz) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [String]\t%s\n&amp;quot;, g_state++, sz);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void WriteEntity_Post(int iValue) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
      fprintf(stream, &amp;quot;%d [Entity]\t%d\n&amp;quot;, g_state++, iValue);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The last but not least function is the message end function.  It too is simple to understand:&lt;br /&gt;
&lt;br /&gt;
 void MessageEnd_Post(void) &lt;br /&gt;
 {&lt;br /&gt;
      if(g_state == -1)&lt;br /&gt;
            RETURN_META(MRES_IGNORED);&lt;br /&gt;
 &lt;br /&gt;
      printf(&amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
      fprintf(stream, &amp;quot;[End Message]\n\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
      fflush(stream);&lt;br /&gt;
 &lt;br /&gt;
      RETURN_META(MRES_IGNORED);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The only thing weird about this one is the flush...this just ensures the data we just collected gets sent to the file.  Well thats it...we're done...all thats left is the compile and moving the module to the addons/amxmodx/modules/ directory then adding it to the addons/amxmodx/configs/modules.ini file at the bottom.  Remember to name it dod_mm not dod_mm_amxx.dll just the first part.&lt;br /&gt;
  &lt;br /&gt;
== In Conclusion ==&lt;br /&gt;
&lt;br /&gt;
Ok we are setup to start compiling, you can grab the source code to any of the modules at amxmodx and compile them now...or just play about.  I suggest you try the easy one that you can grab here: [http://forums.alliedmods.net/showthread.php?t=18763  ESF Model Changing Module] just to look at it.  Here is the direct download: [http://forums.alliedmods.net/attachment.php?attachmentid=4104&amp;amp;d=1128187905 esf_model_changer]&lt;br /&gt;
&lt;br /&gt;
The files for this project can be found [http://www.dodplugins.net/forums/showthread.php?p=2471 DoD Message Module Tutorial / Module]&lt;br /&gt;
&lt;br /&gt;
I have made great use of this in helping in developing dodx and dodfun.&lt;br /&gt;
&lt;br /&gt;
Cheers!&lt;br /&gt;
Zor&lt;br /&gt;
&lt;br /&gt;
For more information, look in: [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx /svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk/?root=amxmodx] or [http://svn.tcwonline.org/viewvc.cgi/trunk/amxmodx/sdk.tar.gz?root=amxmodx&amp;amp;view=tar click here] to download a tarball of that directory.&lt;br /&gt;
&lt;br /&gt;
Copy these files into a new folder.  The amxxmodule.h/cpp files are the Module SDK backend.  You only need to edit the moduleconfig.h file to customize your module.&lt;br /&gt;
&lt;br /&gt;
[[Category:AMX_Mod_X]]&lt;/div&gt;</summary>
		<author><name>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=AMX_Mod_X_1.75_Scripting_Changes&amp;diff=3084</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=3084"/>
		<updated>2006-06-11T21:44:39Z</updated>

		<summary type="html">&lt;p&gt;Zor: /* Stocks */&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;
*&amp;lt;tt&amp;gt;cs_set_user_zoom&amp;lt;/tt&amp;gt; - Sets a zooming type on a player for any weapon.&lt;br /&gt;
*&amp;lt;tt&amp;gt;cs_get_user_zoom&amp;lt;/tt&amp;gt; - Returns the zooming type of a player.&lt;br /&gt;
&lt;br /&gt;
==DoD==&lt;br /&gt;
===Forwards===&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_client_changeteam(id, team, oldteam)&amp;lt;/tt&amp;gt; - This Forward is called when a player changes team, it contains the player id, the new team they have joined and the old team they were on.&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_client_changeclass(id, class, oldclass)&amp;lt;/tt&amp;gt; - This Forward is called just after player spawns if a player changes class, it contains the player id, the new class number and the old class number.&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_client_spawn(id)&amp;lt;/tt&amp;gt; - This Forward is called when a player spawns, it contains the player id.&lt;br /&gt;
&lt;br /&gt;
===Stocks===&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_set_model(id, model[])&amp;lt;/tt&amp;gt; - Sets the model for a player, good for if you want to have special models.  The models used MUST be located in the following directory: dod/models/player/ And should look something like this: dod/models/player/models-name/model-name.mdl dod/models/player/models-name/model-nameT.mdl&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_set_body_number(id, bodynumber)&amp;lt;/tt&amp;gt; - Sets the model number for a players model&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_clear_model(id)&amp;lt;/tt&amp;gt; - Turns off the special model for a player&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;
** Any file in the configs folder 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 cs_set_user_zoom.&lt;br /&gt;
** Added cs_get_user_zoom.&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;
** Fixed some menu item calculation bugs on single paged menus.&lt;br /&gt;
** Fixed CreateOneForward() not working as intended.&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;
&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>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=AMX_Mod_X_1.75_Scripting_Changes&amp;diff=3083</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=3083"/>
		<updated>2006-06-11T21:42:47Z</updated>

		<summary type="html">&lt;p&gt;Zor: /* Stocks */&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;
*&amp;lt;tt&amp;gt;cs_set_user_zoom&amp;lt;/tt&amp;gt; - Sets a zooming type on a player for any weapon.&lt;br /&gt;
*&amp;lt;tt&amp;gt;cs_get_user_zoom&amp;lt;/tt&amp;gt; - Returns the zooming type of a player.&lt;br /&gt;
&lt;br /&gt;
==DoD==&lt;br /&gt;
===Forwards===&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_client_changeteam(id, team, oldteam)&amp;lt;/tt&amp;gt; - This Forward is called when a player changes team, it contains the player id, the new team they have joined and the old team they were on.&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_client_changeclass(id, class, oldclass)&amp;lt;/tt&amp;gt; - This Forward is called just after player spawns if a player changes class, it contains the player id, the new class number and the old class number.&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_client_spawn(id)&amp;lt;/tt&amp;gt; - This Forward is called when a player spawns, it contains the player id.&lt;br /&gt;
&lt;br /&gt;
===Stocks===&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_set_model(id, model[])&amp;lt;/tt&amp;gt; - Sets the model for a player, good for if you want to have special models.  The models used MUST be located in the following directory:&lt;br /&gt;
dod/models/player/&lt;br /&gt;
&lt;br /&gt;
And should look something like this:&lt;br /&gt;
dod/models/player/models-name/model-name.mdl&lt;br /&gt;
dod/models/player/models-name/model-nameT.mdl&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_set_body_number(id, bodynumber)&amp;lt;/tt&amp;gt; - Sets the model number for a players model&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_clear_model(id)&amp;lt;/tt&amp;gt; - Turns off the special model for a player&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;
** Any file in the configs folder 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 cs_set_user_zoom.&lt;br /&gt;
** Added cs_get_user_zoom.&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;
** Fixed some menu item calculation bugs on single paged menus.&lt;br /&gt;
** Fixed CreateOneForward() not working as intended.&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;
&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>Zor</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=AMX_Mod_X_1.75_Scripting_Changes&amp;diff=3082</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=3082"/>
		<updated>2006-06-11T21:41:34Z</updated>

		<summary type="html">&lt;p&gt;Zor: &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;
*&amp;lt;tt&amp;gt;cs_set_user_zoom&amp;lt;/tt&amp;gt; - Sets a zooming type on a player for any weapon.&lt;br /&gt;
*&amp;lt;tt&amp;gt;cs_get_user_zoom&amp;lt;/tt&amp;gt; - Returns the zooming type of a player.&lt;br /&gt;
&lt;br /&gt;
==DoD==&lt;br /&gt;
===Forwards===&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_client_changeteam(id, team, oldteam)&amp;lt;/tt&amp;gt; - This Forward is called when a player changes team, it contains the player id, the new team they have joined and the old team they were on.&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_client_changeclass(id, class, oldclass)&amp;lt;/tt&amp;gt; - This Forward is called just after player spawns if a player changes class, it contains the player id, the new class number and the old class number.&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_client_spawn(id)&amp;lt;/tt&amp;gt; - This Forward is called when a player spawns, it contains the player id.&lt;br /&gt;
&lt;br /&gt;
===Stocks===&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_set_model(id, model[])&amp;lt;/tt&amp;gt; - Sets the model for a player, good for if you want to have special models.  The models used MUST be located in the following directory: dod/models/player/models-name/model-name.mdl and&lt;br /&gt;
dod/models/player/models-name/model-nameT.mdl&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_set_body_number(id, bodynumber)&amp;lt;/tt&amp;gt; - Sets the model number for a players model&lt;br /&gt;
*&amp;lt;tt&amp;gt;dod_clear_model(id)&amp;lt;/tt&amp;gt; - Turns off the special model for a player&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;
** Any file in the configs folder 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 cs_set_user_zoom.&lt;br /&gt;
** Added cs_get_user_zoom.&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;
** Fixed some menu item calculation bugs on single paged menus.&lt;br /&gt;
** Fixed CreateOneForward() not working as intended.&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;
&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>Zor</name></author>
		
	</entry>
</feed>