<?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=Applecorc</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=Applecorc"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/Applecorc"/>
	<updated>2026-06-06T00:21:44Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Menu_API_(SourceMod)&amp;diff=7363</id>
		<title>Menu API (SourceMod)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Menu_API_(SourceMod)&amp;diff=7363"/>
		<updated>2009-08-12T03:45:58Z</updated>

		<summary type="html">&lt;p&gt;Applecorc: Added Semi-colons&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod has an extensive API for building and displaying menus to clients.  Unlike AMX Mod X, this API is highly state driven.  Menus are based on callbacks which are guaranteed to be fired.&lt;br /&gt;
&lt;br /&gt;
For C++, the Menu API can be found in &amp;lt;tt&amp;gt;public/IMenuManager.h&amp;lt;/tt&amp;gt;.  For SourcePawn, it is in &amp;lt;tt&amp;gt;plugins/include/menus.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Objects=&lt;br /&gt;
The SourceMod Menu System is based on an object oriented hierarchy.  Understanding this hierarchy, even for scripting, is critical to using menus effectively.&lt;br /&gt;
&lt;br /&gt;
==Styles==&lt;br /&gt;
The top level object is a ''MenuStyle'' (&amp;lt;tt&amp;gt;IMenuStyle&amp;lt;/tt&amp;gt; in C++).  Styles describe a unique menu system.  There are two such styles built into SourceMod:&lt;br /&gt;
*Valve Style, also called &amp;quot;ESC&amp;quot; menus; 8 items per page, no raw/disabled text can be rendered&lt;br /&gt;
*Radio Style, also called &amp;quot;AMX&amp;quot; menus; 10 items per page, raw/disabled text can be rendered&lt;br /&gt;
&lt;br /&gt;
Each MenuStyle has its own rules and properties.  You can think of them as existing on separate &amp;quot;channels.&amp;quot;  For example, two different menus can exist on a player's screen as both a Valve menu and a Radio menu at the same time, and SourceMod will be able to manage both without any problems.  This is because each style keeps track of its own menus separately.&lt;br /&gt;
&lt;br /&gt;
==Panels==&lt;br /&gt;
Menu displays are drawn with a lower level interface called ''Panels'' (&amp;lt;tt&amp;gt;IMenuPanel&amp;lt;/tt&amp;gt; in C++).  Panels describe exactly one chunk of display text.  Both selectable items and raw text can be added to a panel as long as its parent style supports the contents you're trying to draw.  For example, the Valve style does not support drawing raw text or disabled items.  But with a Radio-style Panel, you can display a large amount of on-screen data in your own format.&lt;br /&gt;
&lt;br /&gt;
Panels are considered temporary objects.  They are created, rendered, displayed, and destroyed.  Although they can be saved indefinitely, it is not necessary to do so.&lt;br /&gt;
&lt;br /&gt;
Valve Style drawing rules/limitations:&lt;br /&gt;
*Max items per page is 8.&lt;br /&gt;
*Disabled items cannot be drawn.&lt;br /&gt;
*Raw text cannot be drawn.&lt;br /&gt;
*Spacers do not add a space/newline, giving a &amp;quot;cramped&amp;quot; feel.&lt;br /&gt;
*Users must press &amp;quot;ESC&amp;quot; or be at their console to view the menu.&lt;br /&gt;
&lt;br /&gt;
Radio Style drawing rules/limitations:&lt;br /&gt;
*Max items per page is 10.&lt;br /&gt;
*Titles appear white; items appear yellow, unless disabled, in which case they are white.&lt;br /&gt;
*The 0th item is always white.  For consistency, this means navigational controls explained in the next section are always white, and simply not drawn if disabled.&lt;br /&gt;
&lt;br /&gt;
==Menus==&lt;br /&gt;
Lastly, there are plain ''Menus'' (&amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; in C++).  These are helper objects designed for storing a menu based on selectable items.  Unlike low-level panels, menus are containers for '''items''', and can only contain items which are selectable (i.e., do not contain raw text).  They fall into two categories:&lt;br /&gt;
*Non-paginated: The menu can only have a certain number of items on it, and no control/navigation options will be added, except for an &amp;quot;Exit&amp;quot; button which will always be in the last position supported by the style.&lt;br /&gt;
**Valve Style maximum items: 8&lt;br /&gt;
**Radio Style maximum items: 10&lt;br /&gt;
*Paginated: The menu can have any number of items.  When displayed, only a certain number of items will be drawn at a time.  Automatic navigation controls are added so players can easily move back and forth to different &amp;quot;pages&amp;quot; of items in the menu.&lt;br /&gt;
**&amp;quot;Previous&amp;quot; is always drawn as the first navigation item, third from the last supported position.  This will not be drawn if the menu only contains one page.  If there are no previous pages, the text will not be drawn on either style; if possible, the menu will be padded so spacing is consistent.&lt;br /&gt;
***Valve Style position: 6&lt;br /&gt;
***Radio Style position: 8&lt;br /&gt;
**&amp;quot;Next&amp;quot; is always drawn as the second navigation item, second from the last supported position.  This will not be drawn if the menu only contains one page.  If there are no further pages, the text will not be drawn on either style; if possible, the menu will be padded so spacing is consistent.&lt;br /&gt;
***Valve Style position: 7&lt;br /&gt;
***Radio Style position: 9&lt;br /&gt;
**&amp;quot;Exit&amp;quot; is drawn if the menu has the exit button property set.  It is always the last supported item position.&lt;br /&gt;
***Valve Style position: 8&lt;br /&gt;
***Radio Style position: 10&lt;br /&gt;
&lt;br /&gt;
The purpose of Menus is to simplify the procedure of storing, drawing, and calculating the selection of items.  Thus, menus do not allow for adding raw text, as that would considerably complicate the drawing algorithm.  ''Note: The C++ API supports hooking &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; drawing procedures and adding raw text; this will be added to the scripting API soon.''&lt;br /&gt;
&lt;br /&gt;
Internally, Menus are drawn via a ''RenderMenu'' algorithm.  This algorithm creates a temporary panel and fills it with items from menus.  This panel is then displayed to a client.  The algorithm attempts to create a consistent feel across all menus, and across all styles.  Thus any menu displayed via the &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; class, or &amp;lt;tt&amp;gt;Menu&amp;lt;/tt&amp;gt; Handles, will look and act the same, and the Menu API is based off the Panel API.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Callbacks=&lt;br /&gt;
==Overview==&lt;br /&gt;
Menus are a callback based system.  Each callback represents an action that occurs during a ''menu display cycle''.  A cycle consists of a number of notifications:&lt;br /&gt;
*Start notification.&lt;br /&gt;
**Display notification if the menu can be displayed to the client.&lt;br /&gt;
**Either an item select or menu cancel notification.&lt;br /&gt;
*End notification.&lt;br /&gt;
&lt;br /&gt;
Since ''End'' signifies the end of a full display cycle, it is usually used to destroy temporary menus.&lt;br /&gt;
&lt;br /&gt;
==Specification==&lt;br /&gt;
A detailed explanation of these events is below.  For C++, an &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; pointer is always available.  For SourcePawn, a &amp;lt;tt&amp;gt;Menu&amp;lt;/tt&amp;gt; Handle and a &amp;lt;tt&amp;gt;MenuAction&amp;lt;/tt&amp;gt; are always set in the &amp;lt;tt&amp;gt;MenuHandler&amp;lt;/tt&amp;gt; callback.  Unlike C++, the SourcePawn API allows certain actions to only be called if they are requested at menu creation time.  This is an optimization.  However, certain actions cannot be prevented from being called.&lt;br /&gt;
&lt;br /&gt;
*'''Start'''.  The menu has been acknowledged.  This does not mean it will be displayed; however, it guarantees that &amp;quot;OnMenuEnd&amp;quot; will be called.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuStart()&amp;lt;/tt&amp;gt; in C++.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Start&amp;lt;/tt&amp;gt; in SourcePawn.  This action is not triggered unless requested.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: Ignored (always 0).&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: Ignored (always 0).&lt;br /&gt;
*'''Display'''.  The menu is being displayed to a client.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuDisplay()&amp;lt;/tt&amp;gt; in C++.  An &amp;lt;tt&amp;gt;IMenuPanel&amp;lt;/tt&amp;gt; pointer and client index are available.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Display&amp;lt;/tt&amp;gt; in SourcePawn.  This action is not triggered unless requested.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: A Handle to a menu panel.&lt;br /&gt;
*'''Select'''.  An item on the menu has been selected.  The item position given will be the position in the menu, rather than the key pressed (unless the menu is a raw panel).  &lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuSelect()&amp;lt;/tt&amp;gt; in C++.  A client index and item position are passed.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Select&amp;lt;/tt&amp;gt; in SourcePawn.  This action is always triggerable, whether requested or not.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: An item position.&lt;br /&gt;
*'''Cancel'''.  The menu's display to one client has been cancelled.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuCancel()&amp;lt;/tt&amp;gt; in C++.  A reason for cancellation is provided.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Cancel&amp;lt;/tt&amp;gt; in SourcePawn.  This action is always triggerable, whether requested or not.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: A menu cancellation reason code.&lt;br /&gt;
*'''End'''.  The menu's display cycle has finished; this means that the &amp;quot;Start&amp;quot; action has occurred, and either &amp;quot;Select&amp;quot; or &amp;quot;Cancel&amp;quot; has occurred thereafter.  This is typically where menu resources are removed/deleted.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuEnd()&amp;lt;/tt&amp;gt; in C++.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt; in SourcePawn.  This action is always triggered, whether requested or not.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A menu end reason code.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: If param1 was MenuEnd_Cancelled, this contains a menu cancellation reason code.&lt;br /&gt;
&lt;br /&gt;
==Panels==&lt;br /&gt;
For panels, the callback rules change.  Panels only receive two of the above callbacks, and it is guaranteed that only one of them will be called for a given display cycle.  For C++, the &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; pointer will always be &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt;.  For SourcePawn, the menu Handle will always be &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*'''Select'''.  A key has been pressed.  This can be any number and should not be considered as reliably in bounds.  For example, even if you only had 2 items in your panel, a client could trigger a key press of &amp;quot;43.&amp;quot;&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuSelect()&amp;lt;/tt&amp;gt; in C++.  A client index and key number pressed are passed.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Select&amp;lt;/tt&amp;gt; in SourcePawn.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: Number of the key pressed.&lt;br /&gt;
*'''Cancel'''.  The menu's display to one client has been cancelled.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuCancel()&amp;lt;/tt&amp;gt; in C++.  A reason for cancellation is provided.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Cancel&amp;lt;/tt&amp;gt; in SourcePawn.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: A menu cancellation reason code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
First, let's start off with a very basic menu.  We want the menu to look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Do you like apples?&lt;br /&gt;
1. Yes&lt;br /&gt;
2. No&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We'll draw this menu with both a basic Menu and a Panel to show the API differences.&lt;br /&gt;
&lt;br /&gt;
==Basic Menu==&lt;br /&gt;
First, let's write our example using the Menu building API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;menu_test1&amp;quot;, Menu_Test1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public MenuHandler1(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	/* If an option was selected, tell the client about the item. */&lt;br /&gt;
	if (action == MenuAction_Select)&lt;br /&gt;
	{&lt;br /&gt;
		new String:info[32];&lt;br /&gt;
		new bool:found = GetMenuItem(menu, param2, info, sizeof(info));&lt;br /&gt;
		PrintToConsole(param1, &amp;quot;You selected item: %d (found? %d info: %s)&amp;quot;, param2, found, info);&lt;br /&gt;
	}&lt;br /&gt;
	/* If the menu was cancelled, print a message to the server about it. */&lt;br /&gt;
	else if (action == MenuAction_Cancel)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToServer(&amp;quot;Client %d's menu was cancelled.  Reason: %d&amp;quot;, param1, param2);&lt;br /&gt;
	}&lt;br /&gt;
	/* If the menu has ended, destroy it */&lt;br /&gt;
	else if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		CloseHandle(menu);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Menu_Test1(client, args)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:menu = CreateMenu(MenuHandler1);&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Do you like apples?&amp;quot;);&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;yes&amp;quot;, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;);&lt;br /&gt;
	SetMenuExitButton(menu, false);&lt;br /&gt;
	DisplayMenu(menu, client, 20);&lt;br /&gt;
	&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note a few very important points from this example:&lt;br /&gt;
*One of either &amp;lt;tt&amp;gt;Select&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; will always be sent to the action handler.&lt;br /&gt;
*&amp;lt;tt&amp;gt;End&amp;lt;/tt&amp;gt; will always be sent to the action handler.&lt;br /&gt;
*We destroy our Menu in the &amp;lt;tt&amp;gt;End&amp;lt;/tt&amp;gt; action, because our Handle is no longer needed.  If we had destroyed the Menu after &amp;lt;tt&amp;gt;DisplayMenu&amp;lt;/tt&amp;gt;, it would have canceled the menu's display to the client.&lt;br /&gt;
*Menus, by default, have an exit button.  We disabled this in our example.&lt;br /&gt;
*Our menu is set to display for 20 seconds.  That means that if the client does not select an item within 20 seconds, the menu will be canceled.  This is usually desired for menus that are for voting.  Note that unlike AMX Mod X, you do not need to set a timer to make sure the menu will be ended.&lt;br /&gt;
*Although we created and destroyed a new Menu Handle, we didn't need to.  It is perfectly acceptable to create the Handle once for the lifetime of the plugin.&lt;br /&gt;
&lt;br /&gt;
Our finished menu and attached console output looks like this (I selected &amp;quot;Yes&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
[[Image:Basic_menu_1.PNG]]&lt;br /&gt;
&lt;br /&gt;
==Basic Panel==&lt;br /&gt;
Now, let's rewrite our example to use Panels instead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;panel_test1&amp;quot;, Panel_Test1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public PanelHandler1(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_Select)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToConsole(param1, &amp;quot;You selected item: %d&amp;quot;, param2);&lt;br /&gt;
	} else if (action == MenuAction_Cancel) {&lt;br /&gt;
		PrintToServer(&amp;quot;Client %d's menu was cancelled.  Reason: %d&amp;quot;, param1, param2);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Panel_Test1(client, args)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:panel = CreatePanel();&lt;br /&gt;
	SetPanelTitle(panel, &amp;quot;Do you like apples?&amp;quot;);&lt;br /&gt;
	DrawPanelItem(panel, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	DrawPanelItem(panel, &amp;quot;No&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
	SendPanelToClient(panel, client, PanelHandler1, 20);&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(panel);&lt;br /&gt;
	&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, Panels are significantly different.&lt;br /&gt;
*We can destroy the Panel as soon as we're done displaying it.  We can create the Panel once and keep re-using it, but we can destroy it at any time without interrupting client menus.&lt;br /&gt;
*The Handler function gets much less data.  Since panels are designed as a raw display, no &amp;quot;item&amp;quot; information is saved internally.  Thus, the handler function only knows whether the display was canceled or whether (and what) numerical key was pressed.&lt;br /&gt;
*There is no automation.  You cannot add more than a certain amount of selectable items to a Panel and get pagination.  Automated control functionality requires using the heftier Menu object API.&lt;br /&gt;
&lt;br /&gt;
Our finished display and console output looks like this (I selected &amp;quot;Yes&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
[[Image:Basic_panel_1.PNG]]&lt;br /&gt;
&lt;br /&gt;
==Basic Paginated Menu==&lt;br /&gt;
Now, let's take a more advanced example -- pagination. Let's say we want to build a menu for changing the map.  An easy way to do this is to read the &amp;lt;tt&amp;gt;maplist.txt&amp;lt;/tt&amp;gt; file at the start of a plugin and build a menu out of it.&lt;br /&gt;
&lt;br /&gt;
Since reading and parsing a file is an expensive operation, we only want to do this once per map.  Thus we'll build the menu in &amp;lt;tt&amp;gt;OnMapStart&amp;lt;/tt&amp;gt;, and we won't call &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt; until &amp;lt;tt&amp;gt;OnMapEnd&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Source code:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new Handle:g_MapMenu = INVALID_HANDLE&lt;br /&gt;
&lt;br /&gt;
public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;menu_changemap&amp;quot;, Command_ChangeMap);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public OnMapStart()&lt;br /&gt;
{&lt;br /&gt;
	g_MapMenu = BuildMapMenu();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public OnMapEnd()&lt;br /&gt;
{&lt;br /&gt;
	if (g_MapMenu != INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		CloseHandle(g_MapMenu);&lt;br /&gt;
		g_MapMenu = INVALID_HANDLE;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Handle:BuildMapMenu()&lt;br /&gt;
{&lt;br /&gt;
	/* Open the file */&lt;br /&gt;
	new Handle:file = OpenFile(&amp;quot;maplist.txt&amp;quot;, &amp;quot;rt&amp;quot;);&lt;br /&gt;
	if (file == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		return INVALID_HANDLE;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	/* Create the menu Handle */&lt;br /&gt;
	new Handle:menu = CreateMenu(Menu_ChangeMap);&lt;br /&gt;
	new String:mapname[255];&lt;br /&gt;
	while (!IsEndOfFile(file) &amp;amp;&amp;amp; ReadFileLine(file, mapname, sizeof(mapname)))&lt;br /&gt;
	{&lt;br /&gt;
		if (mapname[0] == ';' || !IsCharAlpha(mapname[0]))&lt;br /&gt;
		{&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
		/* Cut off the name at any whitespace */&lt;br /&gt;
		new len = strlen(mapname);&lt;br /&gt;
		for (new i=0; i&amp;lt;len; i++);&lt;br /&gt;
		{&lt;br /&gt;
			if (IsCharSpace(mapname[i]))&lt;br /&gt;
			{&lt;br /&gt;
				mapname[i] = '\0';&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		/* Check if the map is valid */&lt;br /&gt;
		if (!IsMapValid(mapname))&lt;br /&gt;
		{&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
		/* Add it to the menu */&lt;br /&gt;
		AddMenuItem(menu, mapname, mapname);&lt;br /&gt;
	}&lt;br /&gt;
	/* Make sure we close the file! */&lt;br /&gt;
	CloseHandle(file);&lt;br /&gt;
	&lt;br /&gt;
	/* Finally, set the title */&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Please select a map:&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return menu;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Menu_ChangeMap(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_Select)&lt;br /&gt;
	{&lt;br /&gt;
		new String:info[32];&lt;br /&gt;
&lt;br /&gt;
		/* Get item info */&lt;br /&gt;
		new bool:found = GetMenuItem(menu, param2, info, sizeof(info));&lt;br /&gt;
&lt;br /&gt;
		/* Tell the client */&lt;br /&gt;
		PrintToConsole(param1, &amp;quot;You selected item: %d (found? %d info: %s)&amp;quot;, param2, found, info);&lt;br /&gt;
&lt;br /&gt;
		/* Change the map */&lt;br /&gt;
		ServerCommand(&amp;quot;changelevel %s&amp;quot;, info);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Command_ChangeMap(client, args)&lt;br /&gt;
{&lt;br /&gt;
	if (g_MapMenu == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToConsole(client, &amp;quot;The maplist.txt file was not found!&amp;quot;);&lt;br /&gt;
		return Plugin_Handled;&lt;br /&gt;
	}	&lt;br /&gt;
	&lt;br /&gt;
	DisplayMenu(g_MapMenu, client, MENU_TIME_FOREVER);&lt;br /&gt;
	&lt;br /&gt;
	return Plugin_Handled;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This menu results in many selections (my &amp;lt;tt&amp;gt;maplist.txt&amp;lt;/tt&amp;gt; file had around 18 maps).  So, our final menu has 3 pages, which side by side, look like:&lt;br /&gt;
&lt;br /&gt;
[[Image:Basic_menu_2_page1.PNG]]&lt;br /&gt;
[[Image:Basic_menu_2_page2.PNG]]&lt;br /&gt;
[[Image:Basic_menu_2_page3.PNG]]&lt;br /&gt;
&lt;br /&gt;
Finally, the console output printed this before the map changed to my selection, &amp;lt;tt&amp;gt;cs_office&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;You selected item: 8 (found? 1 info: cs_office)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Displaying and designing this Menu with a raw &amp;lt;tt&amp;gt;ShowMenu&amp;lt;/tt&amp;gt; message or &amp;lt;tt&amp;gt;Panel&amp;lt;/tt&amp;gt; API would be very time consuming and difficult.  We would have to keep track of all the items in an array of hardcoded size, pages which the user is viewing, and write a function which calculated item selection based on current page and key press.  The Menu system, thankfully, handles all of this for you.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
*Control options which are not available are not drawn.  For example, in the first page, you cannot go &amp;quot;back,&amp;quot; and in the last page, you cannot go &amp;quot;next.&amp;quot;  Despite this, the menu API tries to keep each the interface as consistent as possible.  Thus, visually, each navigational control is always in the same position.  &lt;br /&gt;
*Although we specified no time out for our menu, if we had placed a timeout, flipping through pages does not affect the overall time.  For example, if we had a timeout of 20, each successive page flip would continue to detract from the overall display time, rather than restart the allowed hold time back to 20.&lt;br /&gt;
*If we had disabled the Exit button, options 8 and 9 would still be &amp;quot;Back&amp;quot; and &amp;quot;Next,&amp;quot; respectively.&lt;br /&gt;
*Again, we did not free the Menu Handle in &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;.  This is because our menu is global/static, and we don't want to rebuild it every time.&lt;br /&gt;
*These images show &amp;quot;Back.&amp;quot;  In SourceMod revisions 1011 and higher, &amp;quot;Back&amp;quot; is changed to &amp;quot;Previous,&amp;quot; and &amp;quot;Back&amp;quot; is reserved for the special &amp;quot;ExitBack&amp;quot; functionality.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Voting=&lt;br /&gt;
SourceMod also has API for displaying menus as votable choices to more than one client.  SourceMod automatically handles selecting an item and randomly picking a tie-breaker.  The voting API adds two new &amp;lt;tt&amp;gt;MenuAction&amp;lt;/tt&amp;gt; values, which for vote displays, are '''always''' passed:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;MenuAction_VoteStart&amp;lt;/tt&amp;gt;: Fired after &amp;lt;tt&amp;gt;MenuAction_Start&amp;lt;/tt&amp;gt; when the voting has officially started.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt;: Fired when all clients have either voted or cancelled their vote menu.  The chosen item is passed through &amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;.  This is fired '''before''' &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;.  It is important to note that it does not supercede &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;, nor is it the same thing.  Menus should never be destroyed in &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt;.  '''Note:''' This is not called if &amp;lt;tt&amp;gt;SetVoteResultCallback&amp;lt;/tt&amp;gt;() is used.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MenuAction_VoteCancel&amp;lt;/tt&amp;gt;: Fired if the menu is cancelled while the vote is in progress.  If this is called, &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt; or the result callback will not be called, but &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt; will be afterwards.  A vote cancellation reason is passed in &amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
The voting system extends overall menus with two additional properties:&lt;br /&gt;
*Only one vote can be active at a time.  You must call &amp;lt;tt&amp;gt;IsVoteInProgress&amp;lt;/tt&amp;gt;() or else &amp;lt;tt&amp;gt;VoteMenu&amp;lt;/tt&amp;gt;() will fail.&lt;br /&gt;
*If a client votes and then disconnects while the vote is still active, the client's vote will be invalidated.&lt;br /&gt;
&lt;br /&gt;
The example below shows has to create a function called &amp;lt;tt&amp;gt;DoVoteMenu()&amp;lt;/tt&amp;gt; which will ask all clients whether or not they would like to change to the given map.&lt;br /&gt;
&lt;br /&gt;
==Simple Vote==&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Handle_VoteMenu(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		/* This is called after VoteEnd */&lt;br /&gt;
		CloseHandle(menu);&lt;br /&gt;
	} else if (action == MenuAction_VoteEnd) {&lt;br /&gt;
		/* 0=yes, 1=no */&lt;br /&gt;
		if (param1 == 0)&lt;br /&gt;
		{&lt;br /&gt;
			new String:map[64];&lt;br /&gt;
			GetMenuItem(menu, param1, map, sizeof(map));&lt;br /&gt;
			ServerCommand(&amp;quot;changelevel %s&amp;quot;, map);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
DoVoteMenu(const String:map[])&lt;br /&gt;
{&lt;br /&gt;
	if (IsVoteInProgress())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	new Handle:menu = CreateMenu(Handle_VoteMenu);&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Change map to: %s?&amp;quot;, map);&lt;br /&gt;
	AddMenuItem(menu, map, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;);&lt;br /&gt;
	SetMenuExitButton(menu, false);&lt;br /&gt;
	VoteMenuToAll(menu, 20);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Advanced Voting==&lt;br /&gt;
If you need more information about voting results than &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt; gives you, you can choose to have a different callback invoked.  The new callback will provide much more information, but at a price: &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt; will not be called, and you will have to decide how to interpret the results.  This is done via &amp;lt;tt&amp;gt;SetVoteResultCallback&amp;lt;/tt&amp;gt;().&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Handle_VoteMenu(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		/* This is called after VoteEnd */&lt;br /&gt;
		CloseHandle(menu);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Handle_VoteResults(Handle:menu, &lt;br /&gt;
			num_votes, &lt;br /&gt;
			num_clients, &lt;br /&gt;
			const client_info[][2], &lt;br /&gt;
			num_items, &lt;br /&gt;
			const item_info[][2])&lt;br /&gt;
{&lt;br /&gt;
	/* See if there were multiple winners */&lt;br /&gt;
	new winner = 0;&lt;br /&gt;
	if (num_items &amp;gt; 1&lt;br /&gt;
	    &amp;amp;&amp;amp; (item_info[0][VOTEINFO_ITEM_VOTES] == item_info[1][VOTEINFO_ITEM_VOTES]))&lt;br /&gt;
	{&lt;br /&gt;
		winner = GetRandomInt(0, 1);&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	new String:map[64];&lt;br /&gt;
	GetMenuItem(menu, item_info[winner][VOTEINFO_ITEM_INDEX], map, sizeof(map));&lt;br /&gt;
	ServerCommand(&amp;quot;changelevel %s&amp;quot;, map);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
DoVoteMenu(const String:map[])&lt;br /&gt;
{&lt;br /&gt;
	if (IsVoteInProgress())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	new Handle:menu = CreateMenu(Handle_VoteMenu);&lt;br /&gt;
	SetVoteResultCallback(menu, Handle_VoteResults);&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Change map to: %s?&amp;quot;, map);&lt;br /&gt;
	AddMenuItem(menu, map, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;);&lt;br /&gt;
	SetMenuExitButton(menu, false);&lt;br /&gt;
	VoteMenuToAll(menu, 20);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=ExitBack=&lt;br /&gt;
ExitBack is a special term to refer to the &amp;quot;ExitBack Button.&amp;quot;  This button is disabled by default.  Normally, paginated menus have no &amp;quot;Previous&amp;quot; item for the first page.  If the &amp;quot;ExitBack&amp;quot; button is enabled, the &amp;quot;Previous&amp;quot; item will show up as &amp;quot;Back.&amp;quot;  &lt;br /&gt;
&lt;br /&gt;
Selecting the &amp;quot;ExitBack&amp;quot; option will exit the menu with &amp;lt;tt&amp;gt;MenuCancel_ExitBack&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;MenuEnd_ExitBack&amp;lt;/tt&amp;gt;.  The functionality of this is the same as a normal menu exit internally; extra functionality must be defined through the callbacks.&lt;br /&gt;
&lt;br /&gt;
=Closing Menu Handles=&lt;br /&gt;
It is only necessary to close a menu handle on &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;.  The &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt; is done every time a menu is closed and no longer needed.&lt;br /&gt;
&lt;br /&gt;
=Translations=&lt;br /&gt;
It is possible to dynamically translate menus to each player through the &amp;lt;tt&amp;gt;MenuAction_DisplayItem&amp;lt;/tt&amp;gt; callback.  A special native, &amp;lt;tt&amp;gt;RedrawMenuItem&amp;lt;/tt&amp;gt;, is used to transform the text while inside the callback.  Let's redo the vote example from earlier to be translated:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Handle_VoteMenu(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		/* This is called after VoteEnd */&lt;br /&gt;
		CloseHandle(menu);&lt;br /&gt;
	} else if (action == MenuAction_VoteEnd) {&lt;br /&gt;
		/* 0=yes, 1=no */&lt;br /&gt;
		if (param1 == 0)&lt;br /&gt;
		{&lt;br /&gt;
			new String:map[64];&lt;br /&gt;
			GetMenuItem(menu, param1, map, sizeof(map));&lt;br /&gt;
			ServerCommand(&amp;quot;changelevel %s&amp;quot;, map);&lt;br /&gt;
		}&lt;br /&gt;
	} else if (action == MenuAction_DisplayItem) {&lt;br /&gt;
		/* Get the display string, we'll use it as a translation phrase */&lt;br /&gt;
		decl String:display[64];&lt;br /&gt;
		GetMenuItem(menu, param2, &amp;quot;&amp;quot;, 0, _, display, sizeof(display));&lt;br /&gt;
&lt;br /&gt;
		/* Translate the string to the client's language */&lt;br /&gt;
		decl String:buffer[255];&lt;br /&gt;
		Format(buffer, sizeof(buffer), &amp;quot;%T&amp;quot;, display, param1);&lt;br /&gt;
&lt;br /&gt;
		/* Override the text */&lt;br /&gt;
		return RedrawMenuItem(buffer);&lt;br /&gt;
	} else if (action == MenuAction_Display) {&lt;br /&gt;
		/* Panel Handle is the second parameter */&lt;br /&gt;
		new Handle:panel = Handle:param2;&lt;br /&gt;
		&lt;br /&gt;
		/* Get the map name we're changing to from the first item */&lt;br /&gt;
		decl String:map[64];&lt;br /&gt;
		GetMenuItem(menu, 0, map, sizeof(map));&lt;br /&gt;
		&lt;br /&gt;
		/* Translate to our phrase */&lt;br /&gt;
		decl String:buffer[255];&lt;br /&gt;
		Format(buffer, sizeof(buffer), &amp;quot;%T&amp;quot;, &amp;quot;Change map to?&amp;quot;, client, map);&lt;br /&gt;
&lt;br /&gt;
		SetPanelTitle(panel, buffer);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
DoVoteMenu(const String:map[])&lt;br /&gt;
{&lt;br /&gt;
	if (IsVoteInProgress())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	new Handle:menu = CreateMenu(Handle_VoteMenu, MenuAction_DisplayItem|MenuAction_Display);&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Change map to: %s?&amp;quot;, map);&lt;br /&gt;
	AddMenuItem(menu, map, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;);&lt;br /&gt;
	SetMenuExitButton(menu, false);&lt;br /&gt;
	VoteMenuToAll(menu, 20);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Development]]&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>Applecorc</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Menu_API_(SourceMod)&amp;diff=7362</id>
		<title>Menu API (SourceMod)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Menu_API_(SourceMod)&amp;diff=7362"/>
		<updated>2009-08-12T03:37:24Z</updated>

		<summary type="html">&lt;p&gt;Applecorc: /* Simple Vote */  added semi-colon&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod has an extensive API for building and displaying menus to clients.  Unlike AMX Mod X, this API is highly state driven.  Menus are based on callbacks which are guaranteed to be fired.&lt;br /&gt;
&lt;br /&gt;
For C++, the Menu API can be found in &amp;lt;tt&amp;gt;public/IMenuManager.h&amp;lt;/tt&amp;gt;.  For SourcePawn, it is in &amp;lt;tt&amp;gt;plugins/include/menus.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Objects=&lt;br /&gt;
The SourceMod Menu System is based on an object oriented hierarchy.  Understanding this hierarchy, even for scripting, is critical to using menus effectively.&lt;br /&gt;
&lt;br /&gt;
==Styles==&lt;br /&gt;
The top level object is a ''MenuStyle'' (&amp;lt;tt&amp;gt;IMenuStyle&amp;lt;/tt&amp;gt; in C++).  Styles describe a unique menu system.  There are two such styles built into SourceMod:&lt;br /&gt;
*Valve Style, also called &amp;quot;ESC&amp;quot; menus; 8 items per page, no raw/disabled text can be rendered&lt;br /&gt;
*Radio Style, also called &amp;quot;AMX&amp;quot; menus; 10 items per page, raw/disabled text can be rendered&lt;br /&gt;
&lt;br /&gt;
Each MenuStyle has its own rules and properties.  You can think of them as existing on separate &amp;quot;channels.&amp;quot;  For example, two different menus can exist on a player's screen as both a Valve menu and a Radio menu at the same time, and SourceMod will be able to manage both without any problems.  This is because each style keeps track of its own menus separately.&lt;br /&gt;
&lt;br /&gt;
==Panels==&lt;br /&gt;
Menu displays are drawn with a lower level interface called ''Panels'' (&amp;lt;tt&amp;gt;IMenuPanel&amp;lt;/tt&amp;gt; in C++).  Panels describe exactly one chunk of display text.  Both selectable items and raw text can be added to a panel as long as its parent style supports the contents you're trying to draw.  For example, the Valve style does not support drawing raw text or disabled items.  But with a Radio-style Panel, you can display a large amount of on-screen data in your own format.&lt;br /&gt;
&lt;br /&gt;
Panels are considered temporary objects.  They are created, rendered, displayed, and destroyed.  Although they can be saved indefinitely, it is not necessary to do so.&lt;br /&gt;
&lt;br /&gt;
Valve Style drawing rules/limitations:&lt;br /&gt;
*Max items per page is 8.&lt;br /&gt;
*Disabled items cannot be drawn.&lt;br /&gt;
*Raw text cannot be drawn.&lt;br /&gt;
*Spacers do not add a space/newline, giving a &amp;quot;cramped&amp;quot; feel.&lt;br /&gt;
*Users must press &amp;quot;ESC&amp;quot; or be at their console to view the menu.&lt;br /&gt;
&lt;br /&gt;
Radio Style drawing rules/limitations:&lt;br /&gt;
*Max items per page is 10.&lt;br /&gt;
*Titles appear white; items appear yellow, unless disabled, in which case they are white.&lt;br /&gt;
*The 0th item is always white.  For consistency, this means navigational controls explained in the next section are always white, and simply not drawn if disabled.&lt;br /&gt;
&lt;br /&gt;
==Menus==&lt;br /&gt;
Lastly, there are plain ''Menus'' (&amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; in C++).  These are helper objects designed for storing a menu based on selectable items.  Unlike low-level panels, menus are containers for '''items''', and can only contain items which are selectable (i.e., do not contain raw text).  They fall into two categories:&lt;br /&gt;
*Non-paginated: The menu can only have a certain number of items on it, and no control/navigation options will be added, except for an &amp;quot;Exit&amp;quot; button which will always be in the last position supported by the style.&lt;br /&gt;
**Valve Style maximum items: 8&lt;br /&gt;
**Radio Style maximum items: 10&lt;br /&gt;
*Paginated: The menu can have any number of items.  When displayed, only a certain number of items will be drawn at a time.  Automatic navigation controls are added so players can easily move back and forth to different &amp;quot;pages&amp;quot; of items in the menu.&lt;br /&gt;
**&amp;quot;Previous&amp;quot; is always drawn as the first navigation item, third from the last supported position.  This will not be drawn if the menu only contains one page.  If there are no previous pages, the text will not be drawn on either style; if possible, the menu will be padded so spacing is consistent.&lt;br /&gt;
***Valve Style position: 6&lt;br /&gt;
***Radio Style position: 8&lt;br /&gt;
**&amp;quot;Next&amp;quot; is always drawn as the second navigation item, second from the last supported position.  This will not be drawn if the menu only contains one page.  If there are no further pages, the text will not be drawn on either style; if possible, the menu will be padded so spacing is consistent.&lt;br /&gt;
***Valve Style position: 7&lt;br /&gt;
***Radio Style position: 9&lt;br /&gt;
**&amp;quot;Exit&amp;quot; is drawn if the menu has the exit button property set.  It is always the last supported item position.&lt;br /&gt;
***Valve Style position: 8&lt;br /&gt;
***Radio Style position: 10&lt;br /&gt;
&lt;br /&gt;
The purpose of Menus is to simplify the procedure of storing, drawing, and calculating the selection of items.  Thus, menus do not allow for adding raw text, as that would considerably complicate the drawing algorithm.  ''Note: The C++ API supports hooking &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; drawing procedures and adding raw text; this will be added to the scripting API soon.''&lt;br /&gt;
&lt;br /&gt;
Internally, Menus are drawn via a ''RenderMenu'' algorithm.  This algorithm creates a temporary panel and fills it with items from menus.  This panel is then displayed to a client.  The algorithm attempts to create a consistent feel across all menus, and across all styles.  Thus any menu displayed via the &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; class, or &amp;lt;tt&amp;gt;Menu&amp;lt;/tt&amp;gt; Handles, will look and act the same, and the Menu API is based off the Panel API.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Callbacks=&lt;br /&gt;
==Overview==&lt;br /&gt;
Menus are a callback based system.  Each callback represents an action that occurs during a ''menu display cycle''.  A cycle consists of a number of notifications:&lt;br /&gt;
*Start notification.&lt;br /&gt;
**Display notification if the menu can be displayed to the client.&lt;br /&gt;
**Either an item select or menu cancel notification.&lt;br /&gt;
*End notification.&lt;br /&gt;
&lt;br /&gt;
Since ''End'' signifies the end of a full display cycle, it is usually used to destroy temporary menus.&lt;br /&gt;
&lt;br /&gt;
==Specification==&lt;br /&gt;
A detailed explanation of these events is below.  For C++, an &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; pointer is always available.  For SourcePawn, a &amp;lt;tt&amp;gt;Menu&amp;lt;/tt&amp;gt; Handle and a &amp;lt;tt&amp;gt;MenuAction&amp;lt;/tt&amp;gt; are always set in the &amp;lt;tt&amp;gt;MenuHandler&amp;lt;/tt&amp;gt; callback.  Unlike C++, the SourcePawn API allows certain actions to only be called if they are requested at menu creation time.  This is an optimization.  However, certain actions cannot be prevented from being called.&lt;br /&gt;
&lt;br /&gt;
*'''Start'''.  The menu has been acknowledged.  This does not mean it will be displayed; however, it guarantees that &amp;quot;OnMenuEnd&amp;quot; will be called.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuStart()&amp;lt;/tt&amp;gt; in C++.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Start&amp;lt;/tt&amp;gt; in SourcePawn.  This action is not triggered unless requested.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: Ignored (always 0).&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: Ignored (always 0).&lt;br /&gt;
*'''Display'''.  The menu is being displayed to a client.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuDisplay()&amp;lt;/tt&amp;gt; in C++.  An &amp;lt;tt&amp;gt;IMenuPanel&amp;lt;/tt&amp;gt; pointer and client index are available.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Display&amp;lt;/tt&amp;gt; in SourcePawn.  This action is not triggered unless requested.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: A Handle to a menu panel.&lt;br /&gt;
*'''Select'''.  An item on the menu has been selected.  The item position given will be the position in the menu, rather than the key pressed (unless the menu is a raw panel).  &lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuSelect()&amp;lt;/tt&amp;gt; in C++.  A client index and item position are passed.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Select&amp;lt;/tt&amp;gt; in SourcePawn.  This action is always triggerable, whether requested or not.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: An item position.&lt;br /&gt;
*'''Cancel'''.  The menu's display to one client has been cancelled.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuCancel()&amp;lt;/tt&amp;gt; in C++.  A reason for cancellation is provided.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Cancel&amp;lt;/tt&amp;gt; in SourcePawn.  This action is always triggerable, whether requested or not.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: A menu cancellation reason code.&lt;br /&gt;
*'''End'''.  The menu's display cycle has finished; this means that the &amp;quot;Start&amp;quot; action has occurred, and either &amp;quot;Select&amp;quot; or &amp;quot;Cancel&amp;quot; has occurred thereafter.  This is typically where menu resources are removed/deleted.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuEnd()&amp;lt;/tt&amp;gt; in C++.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt; in SourcePawn.  This action is always triggered, whether requested or not.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A menu end reason code.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: If param1 was MenuEnd_Cancelled, this contains a menu cancellation reason code.&lt;br /&gt;
&lt;br /&gt;
==Panels==&lt;br /&gt;
For panels, the callback rules change.  Panels only receive two of the above callbacks, and it is guaranteed that only one of them will be called for a given display cycle.  For C++, the &amp;lt;tt&amp;gt;IBaseMenu&amp;lt;/tt&amp;gt; pointer will always be &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt;.  For SourcePawn, the menu Handle will always be &amp;lt;tt&amp;gt;INVALID_HANDLE&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*'''Select'''.  A key has been pressed.  This can be any number and should not be considered as reliably in bounds.  For example, even if you only had 2 items in your panel, a client could trigger a key press of &amp;quot;43.&amp;quot;&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuSelect()&amp;lt;/tt&amp;gt; in C++.  A client index and key number pressed are passed.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Select&amp;lt;/tt&amp;gt; in SourcePawn.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: Number of the key pressed.&lt;br /&gt;
*'''Cancel'''.  The menu's display to one client has been cancelled.&lt;br /&gt;
**&amp;lt;tt&amp;gt;OnMenuCancel()&amp;lt;/tt&amp;gt; in C++.  A reason for cancellation is provided.&lt;br /&gt;
**&amp;lt;tt&amp;gt;MenuAction_Cancel&amp;lt;/tt&amp;gt; in SourcePawn.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;: A client index.&lt;br /&gt;
***&amp;lt;tt&amp;gt;param2&amp;lt;/tt&amp;gt;: A menu cancellation reason code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
First, let's start off with a very basic menu.  We want the menu to look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Do you like apples?&lt;br /&gt;
1. Yes&lt;br /&gt;
2. No&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We'll draw this menu with both a basic Menu and a Panel to show the API differences.&lt;br /&gt;
&lt;br /&gt;
==Basic Menu==&lt;br /&gt;
First, let's write our example using the Menu building API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;menu_test1&amp;quot;, Menu_Test1)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public MenuHandler1(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	/* If an option was selected, tell the client about the item. */&lt;br /&gt;
	if (action == MenuAction_Select)&lt;br /&gt;
	{&lt;br /&gt;
		new String:info[32]&lt;br /&gt;
		new bool:found = GetMenuItem(menu, param2, info, sizeof(info))&lt;br /&gt;
		PrintToConsole(param1, &amp;quot;You selected item: %d (found? %d info: %s)&amp;quot;, param2, found, info)&lt;br /&gt;
	}&lt;br /&gt;
	/* If the menu was cancelled, print a message to the server about it. */&lt;br /&gt;
	else if (action == MenuAction_Cancel)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToServer(&amp;quot;Client %d's menu was cancelled.  Reason: %d&amp;quot;, param1, param2)&lt;br /&gt;
	}&lt;br /&gt;
	/* If the menu has ended, destroy it */&lt;br /&gt;
	else if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		CloseHandle(menu)&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Menu_Test1(client, args)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:menu = CreateMenu(MenuHandler1)&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Do you like apples?&amp;quot;)&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;yes&amp;quot;, &amp;quot;Yes&amp;quot;)&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;)&lt;br /&gt;
	SetMenuExitButton(menu, false)&lt;br /&gt;
	DisplayMenu(menu, client, 20)&lt;br /&gt;
	&lt;br /&gt;
	return Plugin_Handled&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note a few very important points from this example:&lt;br /&gt;
*One of either &amp;lt;tt&amp;gt;Select&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; will always be sent to the action handler.&lt;br /&gt;
*&amp;lt;tt&amp;gt;End&amp;lt;/tt&amp;gt; will always be sent to the action handler.&lt;br /&gt;
*We destroy our Menu in the &amp;lt;tt&amp;gt;End&amp;lt;/tt&amp;gt; action, because our Handle is no longer needed.  If we had destroyed the Menu after &amp;lt;tt&amp;gt;DisplayMenu&amp;lt;/tt&amp;gt;, it would have canceled the menu's display to the client.&lt;br /&gt;
*Menus, by default, have an exit button.  We disabled this in our example.&lt;br /&gt;
*Our menu is set to display for 20 seconds.  That means that if the client does not select an item within 20 seconds, the menu will be canceled.  This is usually desired for menus that are for voting.  Note that unlike AMX Mod X, you do not need to set a timer to make sure the menu will be ended.&lt;br /&gt;
*Although we created and destroyed a new Menu Handle, we didn't need to.  It is perfectly acceptable to create the Handle once for the lifetime of the plugin.&lt;br /&gt;
&lt;br /&gt;
Our finished menu and attached console output looks like this (I selected &amp;quot;Yes&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
[[Image:Basic_menu_1.PNG]]&lt;br /&gt;
&lt;br /&gt;
==Basic Panel==&lt;br /&gt;
Now, let's rewrite our example to use Panels instead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;panel_test1&amp;quot;, Panel_Test1)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public PanelHandler1(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_Select)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToConsole(param1, &amp;quot;You selected item: %d&amp;quot;, param2)&lt;br /&gt;
	} else if (action == MenuAction_Cancel) {&lt;br /&gt;
		PrintToServer(&amp;quot;Client %d's menu was cancelled.  Reason: %d&amp;quot;, param1, param2)&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Panel_Test1(client, args)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:panel = CreatePanel();&lt;br /&gt;
	SetPanelTitle(panel, &amp;quot;Do you like apples?&amp;quot;)&lt;br /&gt;
	DrawPanelItem(panel, &amp;quot;Yes&amp;quot;)&lt;br /&gt;
	DrawPanelItem(panel, &amp;quot;No&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
	SendPanelToClient(panel, client, PanelHandler1, 20)&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(panel)&lt;br /&gt;
	&lt;br /&gt;
	return Plugin_Handled&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, Panels are significantly different.&lt;br /&gt;
*We can destroy the Panel as soon as we're done displaying it.  We can create the Panel once and keep re-using it, but we can destroy it at any time without interrupting client menus.&lt;br /&gt;
*The Handler function gets much less data.  Since panels are designed as a raw display, no &amp;quot;item&amp;quot; information is saved internally.  Thus, the handler function only knows whether the display was canceled or whether (and what) numerical key was pressed.&lt;br /&gt;
*There is no automation.  You cannot add more than a certain amount of selectable items to a Panel and get pagination.  Automated control functionality requires using the heftier Menu object API.&lt;br /&gt;
&lt;br /&gt;
Our finished display and console output looks like this (I selected &amp;quot;Yes&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
[[Image:Basic_panel_1.PNG]]&lt;br /&gt;
&lt;br /&gt;
==Basic Paginated Menu==&lt;br /&gt;
Now, let's take a more advanced example -- pagination. Let's say we want to build a menu for changing the map.  An easy way to do this is to read the &amp;lt;tt&amp;gt;maplist.txt&amp;lt;/tt&amp;gt; file at the start of a plugin and build a menu out of it.&lt;br /&gt;
&lt;br /&gt;
Since reading and parsing a file is an expensive operation, we only want to do this once per map.  Thus we'll build the menu in &amp;lt;tt&amp;gt;OnMapStart&amp;lt;/tt&amp;gt;, and we won't call &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt; until &amp;lt;tt&amp;gt;OnMapEnd&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Source code:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new Handle:g_MapMenu = INVALID_HANDLE&lt;br /&gt;
&lt;br /&gt;
public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	RegConsoleCmd(&amp;quot;menu_changemap&amp;quot;, Command_ChangeMap)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public OnMapStart()&lt;br /&gt;
{&lt;br /&gt;
	g_MapMenu = BuildMapMenu()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public OnMapEnd()&lt;br /&gt;
{&lt;br /&gt;
	if (g_MapMenu != INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		CloseHandle(g_MapMenu)&lt;br /&gt;
		g_MapMenu = INVALID_HANDLE&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Handle:BuildMapMenu()&lt;br /&gt;
{&lt;br /&gt;
	/* Open the file */&lt;br /&gt;
	new Handle:file = OpenFile(&amp;quot;maplist.txt&amp;quot;, &amp;quot;rt&amp;quot;)&lt;br /&gt;
	if (file == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		return INVALID_HANDLE&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	/* Create the menu Handle */&lt;br /&gt;
	new Handle:menu = CreateMenu(Menu_ChangeMap);&lt;br /&gt;
	new String:mapname[255]&lt;br /&gt;
	while (!IsEndOfFile(file) &amp;amp;&amp;amp; ReadFileLine(file, mapname, sizeof(mapname)))&lt;br /&gt;
	{&lt;br /&gt;
		if (mapname[0] == ';' || !IsCharAlpha(mapname[0]))&lt;br /&gt;
		{&lt;br /&gt;
			continue&lt;br /&gt;
		}&lt;br /&gt;
		/* Cut off the name at any whitespace */&lt;br /&gt;
		new len = strlen(mapname)&lt;br /&gt;
		for (new i=0; i&amp;lt;len; i++)&lt;br /&gt;
		{&lt;br /&gt;
			if (IsCharSpace(mapname[i]))&lt;br /&gt;
			{&lt;br /&gt;
				mapname[i] = '\0'&lt;br /&gt;
				break&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		/* Check if the map is valid */&lt;br /&gt;
		if (!IsMapValid(mapname))&lt;br /&gt;
		{&lt;br /&gt;
			continue&lt;br /&gt;
		}&lt;br /&gt;
		/* Add it to the menu */&lt;br /&gt;
		AddMenuItem(menu, mapname, mapname)&lt;br /&gt;
	}&lt;br /&gt;
	/* Make sure we close the file! */&lt;br /&gt;
	CloseHandle(file)&lt;br /&gt;
	&lt;br /&gt;
	/* Finally, set the title */&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Please select a map:&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	return menu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Menu_ChangeMap(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_Select)&lt;br /&gt;
	{&lt;br /&gt;
		new String:info[32]&lt;br /&gt;
&lt;br /&gt;
		/* Get item info */&lt;br /&gt;
		new bool:found = GetMenuItem(menu, param2, info, sizeof(info))&lt;br /&gt;
&lt;br /&gt;
		/* Tell the client */&lt;br /&gt;
		PrintToConsole(param1, &amp;quot;You selected item: %d (found? %d info: %s)&amp;quot;, param2, found, info)&lt;br /&gt;
&lt;br /&gt;
		/* Change the map */&lt;br /&gt;
		ServerCommand(&amp;quot;changelevel %s&amp;quot;, info)&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:Command_ChangeMap(client, args)&lt;br /&gt;
{&lt;br /&gt;
	if (g_MapMenu == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToConsole(client, &amp;quot;The maplist.txt file was not found!&amp;quot;)&lt;br /&gt;
		return Plugin_Handled&lt;br /&gt;
	}	&lt;br /&gt;
	&lt;br /&gt;
	DisplayMenu(g_MapMenu, client, MENU_TIME_FOREVER)&lt;br /&gt;
	&lt;br /&gt;
	return Plugin_Handled&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This menu results in many selections (my &amp;lt;tt&amp;gt;maplist.txt&amp;lt;/tt&amp;gt; file had around 18 maps).  So, our final menu has 3 pages, which side by side, look like:&lt;br /&gt;
&lt;br /&gt;
[[Image:Basic_menu_2_page1.PNG]]&lt;br /&gt;
[[Image:Basic_menu_2_page2.PNG]]&lt;br /&gt;
[[Image:Basic_menu_2_page3.PNG]]&lt;br /&gt;
&lt;br /&gt;
Finally, the console output printed this before the map changed to my selection, &amp;lt;tt&amp;gt;cs_office&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;You selected item: 8 (found? 1 info: cs_office)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Displaying and designing this Menu with a raw &amp;lt;tt&amp;gt;ShowMenu&amp;lt;/tt&amp;gt; message or &amp;lt;tt&amp;gt;Panel&amp;lt;/tt&amp;gt; API would be very time consuming and difficult.  We would have to keep track of all the items in an array of hardcoded size, pages which the user is viewing, and write a function which calculated item selection based on current page and key press.  The Menu system, thankfully, handles all of this for you.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
*Control options which are not available are not drawn.  For example, in the first page, you cannot go &amp;quot;back,&amp;quot; and in the last page, you cannot go &amp;quot;next.&amp;quot;  Despite this, the menu API tries to keep each the interface as consistent as possible.  Thus, visually, each navigational control is always in the same position.  &lt;br /&gt;
*Although we specified no time out for our menu, if we had placed a timeout, flipping through pages does not affect the overall time.  For example, if we had a timeout of 20, each successive page flip would continue to detract from the overall display time, rather than restart the allowed hold time back to 20.&lt;br /&gt;
*If we had disabled the Exit button, options 8 and 9 would still be &amp;quot;Back&amp;quot; and &amp;quot;Next,&amp;quot; respectively.&lt;br /&gt;
*Again, we did not free the Menu Handle in &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;.  This is because our menu is global/static, and we don't want to rebuild it every time.&lt;br /&gt;
*These images show &amp;quot;Back.&amp;quot;  In SourceMod revisions 1011 and higher, &amp;quot;Back&amp;quot; is changed to &amp;quot;Previous,&amp;quot; and &amp;quot;Back&amp;quot; is reserved for the special &amp;quot;ExitBack&amp;quot; functionality.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Voting=&lt;br /&gt;
SourceMod also has API for displaying menus as votable choices to more than one client.  SourceMod automatically handles selecting an item and randomly picking a tie-breaker.  The voting API adds two new &amp;lt;tt&amp;gt;MenuAction&amp;lt;/tt&amp;gt; values, which for vote displays, are '''always''' passed:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;MenuAction_VoteStart&amp;lt;/tt&amp;gt;: Fired after &amp;lt;tt&amp;gt;MenuAction_Start&amp;lt;/tt&amp;gt; when the voting has officially started.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt;: Fired when all clients have either voted or cancelled their vote menu.  The chosen item is passed through &amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;.  This is fired '''before''' &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;.  It is important to note that it does not supercede &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;, nor is it the same thing.  Menus should never be destroyed in &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt;.  '''Note:''' This is not called if &amp;lt;tt&amp;gt;SetVoteResultCallback&amp;lt;/tt&amp;gt;() is used.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MenuAction_VoteCancel&amp;lt;/tt&amp;gt;: Fired if the menu is cancelled while the vote is in progress.  If this is called, &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt; or the result callback will not be called, but &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt; will be afterwards.  A vote cancellation reason is passed in &amp;lt;tt&amp;gt;param1&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
The voting system extends overall menus with two additional properties:&lt;br /&gt;
*Only one vote can be active at a time.  You must call &amp;lt;tt&amp;gt;IsVoteInProgress&amp;lt;/tt&amp;gt;() or else &amp;lt;tt&amp;gt;VoteMenu&amp;lt;/tt&amp;gt;() will fail.&lt;br /&gt;
*If a client votes and then disconnects while the vote is still active, the client's vote will be invalidated.&lt;br /&gt;
&lt;br /&gt;
The example below shows has to create a function called &amp;lt;tt&amp;gt;DoVoteMenu()&amp;lt;/tt&amp;gt; which will ask all clients whether or not they would like to change to the given map.&lt;br /&gt;
&lt;br /&gt;
==Simple Vote==&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Handle_VoteMenu(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		/* This is called after VoteEnd */&lt;br /&gt;
		CloseHandle(menu);&lt;br /&gt;
	} else if (action == MenuAction_VoteEnd) {&lt;br /&gt;
		/* 0=yes, 1=no */&lt;br /&gt;
		if (param1 == 0)&lt;br /&gt;
		{&lt;br /&gt;
			new String:map[64];&lt;br /&gt;
			GetMenuItem(menu, param1, map, sizeof(map));&lt;br /&gt;
			ServerCommand(&amp;quot;changelevel %s&amp;quot;, map);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
DoVoteMenu(const String:map[])&lt;br /&gt;
{&lt;br /&gt;
	if (IsVoteInProgress())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	new Handle:menu = CreateMenu(Handle_VoteMenu);&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Change map to: %s?&amp;quot;, map);&lt;br /&gt;
	AddMenuItem(menu, map, &amp;quot;Yes&amp;quot;);&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;);&lt;br /&gt;
	SetMenuExitButton(menu, false);&lt;br /&gt;
	VoteMenuToAll(menu, 20);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Advanced Voting==&lt;br /&gt;
If you need more information about voting results than &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt; gives you, you can choose to have a different callback invoked.  The new callback will provide much more information, but at a price: &amp;lt;tt&amp;gt;MenuAction_VoteEnd&amp;lt;/tt&amp;gt; will not be called, and you will have to decide how to interpret the results.  This is done via &amp;lt;tt&amp;gt;SetVoteResultCallback&amp;lt;/tt&amp;gt;().&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Handle_VoteMenu(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		/* This is called after VoteEnd */&lt;br /&gt;
		CloseHandle(menu);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Handle_VoteResults(Handle:menu, &lt;br /&gt;
			num_votes, &lt;br /&gt;
			num_clients, &lt;br /&gt;
			const client_info[][2], &lt;br /&gt;
			num_items, &lt;br /&gt;
			const item_info[][2])&lt;br /&gt;
{&lt;br /&gt;
	/* See if there were multiple winners */&lt;br /&gt;
	new winner = 0;&lt;br /&gt;
	if (num_items &amp;gt; 1&lt;br /&gt;
	    &amp;amp;&amp;amp; (item_info[0][VOTEINFO_ITEM_VOTES] == item_info[1][VOTEINFO_ITEM_VOTES]))&lt;br /&gt;
	{&lt;br /&gt;
		winner = GetRandomInt(0, 1);&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	new String:map[64]&lt;br /&gt;
	GetMenuItem(menu, item_info[winner][VOTEINFO_ITEM_INDEX], map, sizeof(map))&lt;br /&gt;
	ServerCommand(&amp;quot;changelevel %s&amp;quot;, map)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
DoVoteMenu(const String:map[])&lt;br /&gt;
{&lt;br /&gt;
	if (IsVoteInProgress())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	new Handle:menu = CreateMenu(Handle_VoteMenu)&lt;br /&gt;
	SetVoteResultCallback(menu, Handle_VoteResults)&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Change map to: %s?&amp;quot;, map)&lt;br /&gt;
	AddMenuItem(menu, map, &amp;quot;Yes&amp;quot;)&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;)&lt;br /&gt;
	SetMenuExitButton(menu, false)&lt;br /&gt;
	VoteMenuToAll(menu, 20);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=ExitBack=&lt;br /&gt;
ExitBack is a special term to refer to the &amp;quot;ExitBack Button.&amp;quot;  This button is disabled by default.  Normally, paginated menus have no &amp;quot;Previous&amp;quot; item for the first page.  If the &amp;quot;ExitBack&amp;quot; button is enabled, the &amp;quot;Previous&amp;quot; item will show up as &amp;quot;Back.&amp;quot;  &lt;br /&gt;
&lt;br /&gt;
Selecting the &amp;quot;ExitBack&amp;quot; option will exit the menu with &amp;lt;tt&amp;gt;MenuCancel_ExitBack&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;MenuEnd_ExitBack&amp;lt;/tt&amp;gt;.  The functionality of this is the same as a normal menu exit internally; extra functionality must be defined through the callbacks.&lt;br /&gt;
&lt;br /&gt;
=Closing Menu Handles=&lt;br /&gt;
It is only necessary to close a menu handle on &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt;.  The &amp;lt;tt&amp;gt;MenuAction_End&amp;lt;/tt&amp;gt; is done every time a menu is closed and no longer needed.&lt;br /&gt;
&lt;br /&gt;
=Translations=&lt;br /&gt;
It is possible to dynamically translate menus to each player through the &amp;lt;tt&amp;gt;MenuAction_DisplayItem&amp;lt;/tt&amp;gt; callback.  A special native, &amp;lt;tt&amp;gt;RedrawMenuItem&amp;lt;/tt&amp;gt;, is used to transform the text while inside the callback.  Let's redo the vote example from earlier to be translated:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public Handle_VoteMenu(Handle:menu, MenuAction:action, param1, param2)&lt;br /&gt;
{&lt;br /&gt;
	if (action == MenuAction_End)&lt;br /&gt;
	{&lt;br /&gt;
		/* This is called after VoteEnd */&lt;br /&gt;
		CloseHandle(menu);&lt;br /&gt;
	} else if (action == MenuAction_VoteEnd) {&lt;br /&gt;
		/* 0=yes, 1=no */&lt;br /&gt;
		if (param1 == 0)&lt;br /&gt;
		{&lt;br /&gt;
			new String:map[64]&lt;br /&gt;
			GetMenuItem(menu, param1, map, sizeof(map))&lt;br /&gt;
			ServerCommand(&amp;quot;changelevel %s&amp;quot;, map);&lt;br /&gt;
		}&lt;br /&gt;
	} else if (action == MenuAction_DisplayItem) {&lt;br /&gt;
		/* Get the display string, we'll use it as a translation phrase */&lt;br /&gt;
		decl String:display[64];&lt;br /&gt;
		GetMenuItem(menu, param2, &amp;quot;&amp;quot;, 0, _, display, sizeof(display));&lt;br /&gt;
&lt;br /&gt;
		/* Translate the string to the client's language */&lt;br /&gt;
		decl String:buffer[255];&lt;br /&gt;
		Format(buffer, sizeof(buffer), &amp;quot;%T&amp;quot;, display, param1);&lt;br /&gt;
&lt;br /&gt;
		/* Override the text */&lt;br /&gt;
		return RedrawMenuItem(buffer);&lt;br /&gt;
	} else if (action == MenuAction_Display) {&lt;br /&gt;
		/* Panel Handle is the second parameter */&lt;br /&gt;
		new Handle:panel = Handle:param2;&lt;br /&gt;
		&lt;br /&gt;
		/* Get the map name we're changing to from the first item */&lt;br /&gt;
		decl String:map[64];&lt;br /&gt;
		GetMenuItem(menu, 0, map, sizeof(map));&lt;br /&gt;
		&lt;br /&gt;
		/* Translate to our phrase */&lt;br /&gt;
		decl String:buffer[255];&lt;br /&gt;
		Format(buffer, sizeof(buffer), &amp;quot;%T&amp;quot;, &amp;quot;Change map to?&amp;quot;, client, map);&lt;br /&gt;
&lt;br /&gt;
		SetPanelTitle(panel, buffer);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
DoVoteMenu(const String:map[])&lt;br /&gt;
{&lt;br /&gt;
	if (IsVoteInProgress())&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	new Handle:menu = CreateMenu(Handle_VoteMenu, MenuAction_DisplayItem|MenuAction_Display)&lt;br /&gt;
	SetMenuTitle(menu, &amp;quot;Change map to: %s?&amp;quot;, map)&lt;br /&gt;
	AddMenuItem(menu, map, &amp;quot;Yes&amp;quot;)&lt;br /&gt;
	AddMenuItem(menu, &amp;quot;no&amp;quot;, &amp;quot;No&amp;quot;)&lt;br /&gt;
	SetMenuExitButton(menu, false)&lt;br /&gt;
	VoteMenuToAll(menu, 20);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Development]]&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>Applecorc</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Building_SourceMod&amp;diff=7360</id>
		<title>Building SourceMod</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Building_SourceMod&amp;diff=7360"/>
		<updated>2009-08-11T22:05:10Z</updated>

		<summary type="html">&lt;p&gt;Applecorc: /* Getting the Files */  Added link to L4D SDK&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Compiling SourceMod is not difficult, but requires a number of prerequisites.  This article details the requirements and steps to being able to build working SourceMod binaries.  These directions may change any time and may be updated as SourceMod's build process improves.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' You cannot use MingW to build working SourceMod Windows binaries.  It is not ABI compatible with Visual C++ which is what Valve uses for the Source engine.  You can only use GCC to build Linux binaries.&lt;br /&gt;
&lt;br /&gt;
=Requirements=&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
*Microsoft Visual C++ 2008 (Express or higher) is supported and used for official builds.&lt;br /&gt;
*Microsoft Visual C++ 2005 (Express or higher) is unsupported.&lt;br /&gt;
*Microsoft Visual C++ 2003 7.1 or higher may not build out-of-box, but can build compatible binaries.&lt;br /&gt;
*Microsoft Visual C++ 2003 7.0 or lower '''cannot''' be used.&lt;br /&gt;
&lt;br /&gt;
If you are installing Visual C++ 2005 Express, it may not come with Microsoft's Platform SDK installed.  If this is the case, you must manually install the Platform SDK.  You can find directions on how to do this and test your setup [http://www.microsoft.com/express/2005/platformsdk/default.aspx here].  Visual C++ 2008 &amp;quot;streamlines&amp;quot; the Platform SDK installation according to Microsoft.&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
For Linux, SourceMod requires the GNU C/C++ Compiler (from GCC):&lt;br /&gt;
*Version 4.1 is used for official binaries and is guaranteed to build.&lt;br /&gt;
*Versions 3.4 through 4.2 are guaranteed to be binary (ABI) compatible, although SourceMod may not necessarily build out-of-box against them.&lt;br /&gt;
*Any GCC version below 3.4 '''cannot''' be used.&lt;br /&gt;
&lt;br /&gt;
==CPU==&lt;br /&gt;
SourceMod is strictly a 32-bit x86 (IA32) product.  You should not try to force a compiler to build 64-bit binaries of SourceMod.&lt;br /&gt;
&lt;br /&gt;
Your CPU and its compiler must support SSE in order to build SourceMod.  To build without needing or having a dependency against SSE, please see the [[Compiling SourceMod#Removing SSE|Removing SSE]] section near the bottom.&lt;br /&gt;
&lt;br /&gt;
Approximate compiling times for SourceMod's Core are roughly:&lt;br /&gt;
*Windows, Core 2 Quad E6600: 30 seconds (using /MP)&lt;br /&gt;
*Windows, Core 2 Duo E6600: 75 seconds&lt;br /&gt;
*Windows, Centrino 1.8GHz: 5 minutes&lt;br /&gt;
*Linux, Core 2 Duo E6600: &amp;lt;= 1 minute&lt;br /&gt;
*Linux, P3 Dual 500MHz: &amp;gt;= 7 minutes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Setup=&lt;br /&gt;
This section describes how to set up your computer for compiling.&lt;br /&gt;
&lt;br /&gt;
==Getting the Files==&lt;br /&gt;
This section describes which files you must obtain and how to obtain them.  Do not worry about where to place them yet -- that will be discussed on a per-platform basis.  You can download the files anywhere you'd like.&lt;br /&gt;
&lt;br /&gt;
The recommended method of getting the required files is via [http://subversion.tigris.org/ Subversion].  We have our own [[Subversion Tutorial]] if you prefer that method.  Although you do not need both HL2SDK versions (unless you wish to build binaries against both), you do need both Metamod:Source versions.  Extensions don't necessarily require Metamod:Source (or even the Source Engine) but its template library is used extensively in SourceMod.&lt;br /&gt;
&lt;br /&gt;
*SourceMod. For full download options, see the [http://www.sourcemod.net/downloads.php SourceMod Downloads] page.  Obviously, you must download the source code and not a binary package.&lt;br /&gt;
*HL2SDK Original.  As of this writing (Sep 2008) this engine is used for most Source games, except for TF2, GMod10, and DoD:S. Repository: [http://hg.alliedmods.net/hl2sdk hl2sdk]&lt;br /&gt;
*HL2SDK OrangeBox.  As of this writing (Sep 2008) this engine is used TF2, GMod10, and DoD:S. Repository: [http://hg.alliedmods.net/hl2sdk-ob hl2sdk-ob]&lt;br /&gt;
*HL2SDK Left4Dead. This engine is used for L4D. Repository: [http://hg.alliedmods.net/hl2sdk-l4d hl2sdk-l4d]&lt;br /&gt;
*Metamod:Source Source Code. Visit [http://www.metamodsource.net/?go=downloads Metamod:Source downloads]. Right now SourceMod builds against Metamod:Source 1.7.&lt;br /&gt;
&lt;br /&gt;
'''Note''' that when we refer to &amp;quot;Metamod:Source&amp;quot; in this article, we are referring to its source code tree, not a binary package.&lt;br /&gt;
&lt;br /&gt;
If you intend to compile the MySQL extension, you must also download MySQL 5.0.  You can use any version.  For simplicity, here are the versions we use:&lt;br /&gt;
*Linux: We use the 5.0.45 binary from the &amp;quot;[http://dev.mysql.com/downloads/mysql/5.0.html#linux Linux (non RPM packages)]&amp;quot; for &amp;quot;Linux (x86).&amp;quot;  You can also use [http://dev.mysql.com/get/Downloads/MySQL-5.0/mysql-5.0.45-linux-i686-glibc23.tar.gz/from/pick this direct link] (may not be valid in the future).&lt;br /&gt;
*Windows: Due to a MySQL build change we use 5.0.24a which is an older download.  The file name was &amp;quot;mysql-5.0.24a-win32.zip,&amp;quot; if you can't find it you can use this [http://www.bailopan.net/mysql-5.0.24a-win32.zip direct link] (may not be valid in the future).&lt;br /&gt;
&lt;br /&gt;
You can remove all folders from the distribution except for the &amp;quot;lib&amp;quot; and &amp;quot;include&amp;quot; folders which comprise the MySQL SDK.&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
As of this writing, SourceMod's Makefiles are hardcoded to use a binary called &amp;quot;gcc-4.1&amp;quot;  You can override this, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;make CPP=gcc&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otherwise, you can also just create a symlink:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo ln -s /usr/bin/gcc /usr/bin/gcc-4.1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that you must use &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt; and not &amp;lt;tt&amp;gt;g++&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
SourceMod's Makefiles have strict directory organizational rules.  You must have a top-level folder.  For this document, we'll assume it is called &amp;lt;tt&amp;gt;sourcemod&amp;lt;/tt&amp;gt;, though it can be named anything.  The layout of &amp;lt;tt&amp;gt;sourcemod&amp;lt;/tt&amp;gt; must be:&lt;br /&gt;
*&amp;lt;tt&amp;gt;sourcemod&amp;lt;/tt&amp;gt;/&lt;br /&gt;
**&amp;lt;tt&amp;gt;hl2sdk&amp;lt;/tt&amp;gt; - symlink or folder containing the HL2SDK&lt;br /&gt;
**&amp;lt;tt&amp;gt;hl2sdk-ob&amp;lt;/tt&amp;gt; - symlink or folder containing the HL2SDK for Orange Box/TF&lt;br /&gt;
**&amp;lt;tt&amp;gt;mmsource-1.7&amp;lt;/tt&amp;gt; - symlink or folder containing any Metamod:Source version 1.7 or higher.&lt;br /&gt;
**&amp;lt;tt&amp;gt;sourcemod-central&amp;lt;/tt&amp;gt; - folder containing SourceMod's source code tree.  This can be named anything, as long as it's a valid SourceMod tree (like [http://hg.alliedmods.net/sourcemod-central sourcemod-central]).  You can also use [http://hg.alliedmods.net/sourcemod-1.1 sourcemod-1.1].&lt;br /&gt;
**&amp;lt;tt&amp;gt;mysql-5.0&amp;lt;/tt&amp;gt; - symlink or folder containing a MySQL 5.0 distribution&lt;br /&gt;
&lt;br /&gt;
If you are using a 64-bit version of Linux, you may need to install extra packages to be able to compile SourceMod.  On Debian-based distros, these are typically:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#prerequisites&lt;br /&gt;
#apt-get install g++-4.1 gcc-4.1 make subversion&lt;br /&gt;
#apt-get instal libz libz-dev&lt;br /&gt;
#only needed if you want to use the build tool&lt;br /&gt;
#apt-get install mono mono-devel&lt;br /&gt;
#32-bit support&lt;br /&gt;
apt-get install ia32-libs&lt;br /&gt;
apt-get install lib32z1 lib32z1-dev&lt;br /&gt;
apt-get install libc6-dev-i386 libc6-i386&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
On Windows we don't require a particular directory layout.  Instead, environment variables are used.  The directions below apply to Windows XP, and are assumed to be similar for other versions of Windows.&lt;br /&gt;
*Open the Control Panel (for example, via Start -&amp;gt; Settings).&lt;br /&gt;
*Open the System control.  If you don't see it, you may need to switch to &amp;quot;Classic view&amp;quot; (either via the left-hand pane or by going to Tools -&amp;gt; Folder Options).&lt;br /&gt;
*Click the Advanced tab.&lt;br /&gt;
*Click the Environment Variables button.&lt;br /&gt;
&lt;br /&gt;
You can add your environment variables to either your User settings or your System settings.  Create a new variable for each item in the list below.  The item names are in &amp;lt;tt&amp;gt;fixed-width font&amp;lt;/tt&amp;gt; and their value descriptions follow.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MMSOURCE17&amp;lt;/tt&amp;gt; - Path to Metamod:Source 1.7+&lt;br /&gt;
*&amp;lt;tt&amp;gt;HL2SDK&amp;lt;/tt&amp;gt; - Path to HL2SDK Ep1/Original&lt;br /&gt;
*&amp;lt;tt&amp;gt;HL2SDKOB&amp;lt;/tt&amp;gt; - Path to HL2SDK Ep2/OrangeBox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Building=&lt;br /&gt;
SourceMod has two types of binaries: those with an engine/MM:S dependence, and those without (&amp;quot;normal&amp;quot; binaries).  Normal binaries have two modes:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Release&amp;lt;/tt&amp;gt; - Optimized binary for release.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Debug&amp;lt;/tt&amp;gt; - Unoptimized binary with debugging checks.&lt;br /&gt;
&lt;br /&gt;
Engine/MM:S dependent binaries have three build modes, each paired with either Release or Debug, meaning there are six build options total.  They are:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Original&amp;lt;/tt&amp;gt; - Building against MM:S 1.4 API with HL2SDK&lt;br /&gt;
*&amp;lt;tt&amp;gt;Episode2&amp;lt;/tt&amp;gt; - Building against MM:S 1.6 API with HL2SDK-OB or higher&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
For both Normal and Engine/MM:S dependent binaries, the object files and the final binary are placed in a folder called &amp;lt;tt&amp;gt;Release&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Debug&amp;lt;/tt&amp;gt; (in the same level as the Makefile) depending on which building mechanism you chose.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Our Makefiles are not set up to detect changes in header files.  If you change a header file, you must clean your build.&lt;br /&gt;
&lt;br /&gt;
===Normal Binaries===&lt;br /&gt;
For normal binaries, you can build simply with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;make&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can clean stale object files with:&lt;br /&gt;
&amp;lt;pre&amp;gt;make clean&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or build debug builds with:&lt;br /&gt;
&amp;lt;pre&amp;gt;make DEBUG=true&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Dependent Binaries===&lt;br /&gt;
Binaries that have an Engine or MM:S dependency require one extra parameter, &amp;lt;tt&amp;gt;ENGINE&amp;lt;/tt&amp;gt;.  It must be either &amp;lt;tt&amp;gt;orangebox&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;original&amp;lt;/tt&amp;gt;.  For example, to build a TF-compatible binary in debug mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;make ENGINE=orangebox DEBUG=true&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dependent binaries are dropped into one of the following folders:&lt;br /&gt;
*Debug.original&lt;br /&gt;
*Debug.orangebox&lt;br /&gt;
*Release.original&lt;br /&gt;
*Release.orangebox&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
Windows project files end with &amp;lt;tt&amp;gt;.vcproj&amp;lt;/tt&amp;gt; and are found in an &amp;lt;tt&amp;gt;msvc8&amp;lt;/tt&amp;gt; folder that resides inside each binary's main source folder.  For example, Core is located in &amp;lt;tt&amp;gt;core/msvc8/sourcemod_mm.vcproj&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Once the file is opened, you can select which build to use by going to Build -&amp;gt; Configuration Manager.  Normal binaries have simply &amp;quot;Debug&amp;quot; and &amp;quot;Release.&amp;quot;  Dependent binaries have the following builds:&lt;br /&gt;
*Debug - Old Metamod&lt;br /&gt;
*Debug - Episode 2 &lt;br /&gt;
*Release - Old Metamod&lt;br /&gt;
*Release - Episode 2 &lt;br /&gt;
&lt;br /&gt;
'''Note''' that dependent binaries will have plain &amp;quot;Debug&amp;quot; and &amp;quot;Release&amp;quot; builds.  These should not be used as they are not configured.&lt;br /&gt;
&lt;br /&gt;
Once you have selected a configuration, you can compile by going to Build -&amp;gt; Build Solution.  The binaries and object files will be written to a folder inside &amp;lt;tt&amp;gt;msvc8&amp;lt;/tt&amp;gt; named after the full configuration name.  For example, using &amp;quot;Debug - Old Metamod&amp;quot; with the &amp;quot;sdktools&amp;quot; extension will result in the binary: &amp;lt;tt&amp;gt;extensions/sdktools/msvc8/Debug - Old Metamod/sdktools.ext.dll&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Visual Studio detects changes to header files intelligently.  It is usually not necessary to rebuild a solution.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Binary Organization=&lt;br /&gt;
Although SourceMod has a somewhat unified building mechanism, each of the binaries has a different purpose.  They can be separated into the following classes:&lt;br /&gt;
&lt;br /&gt;
*Core-Related: Binaries which are required or loaded intrinsically by Core.&lt;br /&gt;
*Extensions: Binaries which are loaded via the extension mechanism.&lt;br /&gt;
*External: Binaries which are standalone or unrelated to SourceMod's live operation (for example, the compiler).&lt;br /&gt;
&lt;br /&gt;
This article is only concerned with the first two types.  &lt;br /&gt;
&lt;br /&gt;
==Core-Related Binaries==&lt;br /&gt;
Binaries related to Core are spread throughout the source code tree.  They are always placed in &amp;lt;tt&amp;gt;sourcemod/bin&amp;lt;/tt&amp;gt; for packaging.  The projects files related to Core are:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;loader&amp;lt;/tt&amp;gt; - This is a very small wrapper binary responsible for detecting the MM:S version and game engine, and deciding which SourceMod version to load.  The output binary is &amp;lt;tt&amp;gt;sourcemod_mm_i486.so&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;sourcemod_mm.dll&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;tt&amp;gt;core&amp;lt;/tt&amp;gt; - This is Core itself, and is a dependent binary.  It has three outputs:&lt;br /&gt;
**Original: &amp;lt;tt&amp;gt;sourcemod.1.ep1.so&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;sourcemod.1.ep1.dll&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Episode 1: &amp;lt;tt&amp;gt;sourcemod.1.ep1.so&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;sourcemod.2.ep1.dll&amp;lt;/tt&amp;gt; (unsupported, not packaged)&lt;br /&gt;
**Episode 2: &amp;lt;tt&amp;gt;sourcemod.1.ep1.so&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;sourcemod.2.ep2.dll&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;sourcepawn/jit/x86&amp;lt;/tt&amp;gt; - This is the SourcePawn JIT for generating IA32/x86 instructions from &amp;lt;tt&amp;gt;.smx&amp;lt;/tt&amp;gt; files.  Currently the source code for this is not made available.  It is built as &amp;lt;tt&amp;gt;sourcepawn.jit.x86.so&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;sourcepawn.jit.x86.dll&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
It is technically not necessary to use the loader.  It is provided as a convenience so users do not have to perform extra steps while installing SourceMod.  However, it is highly recommend that you do use it in order to maintain similarity with the default SourceMod package.&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
Extensions are found in the &amp;lt;tt&amp;gt;extensions&amp;lt;/tt&amp;gt; folder of the source tree.  SDKTools, Cstrike, and the upcoming TF extension are engine/MM:S dependent (and the rest are generally not).&lt;br /&gt;
&lt;br /&gt;
Extensions always are named &amp;lt;tt&amp;gt;name.ext.so&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;name.ext.dll&amp;lt;/tt&amp;gt; where &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; is a unique identifier.  This is true even of dependent binaries.  &lt;br /&gt;
&lt;br /&gt;
When loading extensions, SourceMod looks in two separate folders.  First, it checks the ''dependent extension folder'', which is &amp;lt;tt&amp;gt;extensions/auto.x.y&amp;lt;/tt&amp;gt; where &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; is the MM:S version (1 for 1.4, 2 for 1.6) and &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt; is the Engine version (1 for Original/Ep1, 2 for Ep2/OrangeBox).  If no matching extension is found there, it looks in &amp;lt;tt&amp;gt;extensions&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, the SDKTools binary on Counter-Strike would be loaded from &amp;lt;tt&amp;gt;extensions/auto.1.ep1&amp;lt;/tt&amp;gt;, but the GeoIP binary (which is not dependent) would be loaded from &amp;lt;tt&amp;gt;extensions&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Removing SSE=&lt;br /&gt;
SourceMod binaries are built against SSE by default.  SSE is an important set of optimizations, that, according to Valve's hardware survey, are supported on 99.6% percent of respondents' computers.  If you are in this 0.4% which does not have SSE support, you should consider buying a newer processor.  Only early Pentium 3-grade processors did not have SSE support (for example, the very early Durons), and it is likely your Source server will not perform adequately to support more than few players.&lt;br /&gt;
&lt;br /&gt;
Nonetheless, SourceMod's binaries can all be recompiled to remove its SSE dependence.&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
Edit the Makefile of the binary you are trying to compile.  Remove all instances of these flags.  They can simply be erased, there is no need to replace them with anything.&lt;br /&gt;
*&amp;lt;tt&amp;gt;-msse&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;-mfpmath=sse&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure to clean the build after changing the Makefile.&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
Load the project file into Visual Studio.  Go to Project -&amp;gt; Properties.  Expand &amp;quot;Configuration Properties,&amp;quot; and then &amp;quot;C/C++&amp;quot; under it.  Select &amp;quot;Code Generation.&amp;quot;  Change the setting &amp;quot;Enable Enhanced Instruction Set&amp;quot; to &amp;quot;Not Set.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' You must change this setting '''for each build configuration''' that you wish to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Documentation]]&lt;br /&gt;
[[Category:SourceMod Development]]&lt;/div&gt;</summary>
		<author><name>Applecorc</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Building_SourceMod&amp;diff=7359</id>
		<title>Building SourceMod</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Building_SourceMod&amp;diff=7359"/>
		<updated>2009-08-11T21:51:14Z</updated>

		<summary type="html">&lt;p&gt;Applecorc: Fixed page to match makefile&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Compiling SourceMod is not difficult, but requires a number of prerequisites.  This article details the requirements and steps to being able to build working SourceMod binaries.  These directions may change any time and may be updated as SourceMod's build process improves.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' You cannot use MingW to build working SourceMod Windows binaries.  It is not ABI compatible with Visual C++ which is what Valve uses for the Source engine.  You can only use GCC to build Linux binaries.&lt;br /&gt;
&lt;br /&gt;
=Requirements=&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
*Microsoft Visual C++ 2008 (Express or higher) is supported and used for official builds.&lt;br /&gt;
*Microsoft Visual C++ 2005 (Express or higher) is unsupported.&lt;br /&gt;
*Microsoft Visual C++ 2003 7.1 or higher may not build out-of-box, but can build compatible binaries.&lt;br /&gt;
*Microsoft Visual C++ 2003 7.0 or lower '''cannot''' be used.&lt;br /&gt;
&lt;br /&gt;
If you are installing Visual C++ 2005 Express, it may not come with Microsoft's Platform SDK installed.  If this is the case, you must manually install the Platform SDK.  You can find directions on how to do this and test your setup [http://www.microsoft.com/express/2005/platformsdk/default.aspx here].  Visual C++ 2008 &amp;quot;streamlines&amp;quot; the Platform SDK installation according to Microsoft.&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
For Linux, SourceMod requires the GNU C/C++ Compiler (from GCC):&lt;br /&gt;
*Version 4.1 is used for official binaries and is guaranteed to build.&lt;br /&gt;
*Versions 3.4 through 4.2 are guaranteed to be binary (ABI) compatible, although SourceMod may not necessarily build out-of-box against them.&lt;br /&gt;
*Any GCC version below 3.4 '''cannot''' be used.&lt;br /&gt;
&lt;br /&gt;
==CPU==&lt;br /&gt;
SourceMod is strictly a 32-bit x86 (IA32) product.  You should not try to force a compiler to build 64-bit binaries of SourceMod.&lt;br /&gt;
&lt;br /&gt;
Your CPU and its compiler must support SSE in order to build SourceMod.  To build without needing or having a dependency against SSE, please see the [[Compiling SourceMod#Removing SSE|Removing SSE]] section near the bottom.&lt;br /&gt;
&lt;br /&gt;
Approximate compiling times for SourceMod's Core are roughly:&lt;br /&gt;
*Windows, Core 2 Quad E6600: 30 seconds (using /MP)&lt;br /&gt;
*Windows, Core 2 Duo E6600: 75 seconds&lt;br /&gt;
*Windows, Centrino 1.8GHz: 5 minutes&lt;br /&gt;
*Linux, Core 2 Duo E6600: &amp;lt;= 1 minute&lt;br /&gt;
*Linux, P3 Dual 500MHz: &amp;gt;= 7 minutes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Setup=&lt;br /&gt;
This section describes how to set up your computer for compiling.&lt;br /&gt;
&lt;br /&gt;
==Getting the Files==&lt;br /&gt;
This section describes which files you must obtain and how to obtain them.  Do not worry about where to place them yet -- that will be discussed on a per-platform basis.  You can download the files anywhere you'd like.&lt;br /&gt;
&lt;br /&gt;
The recommended method of getting the required files is via [http://subversion.tigris.org/ Subversion].  We have our own [[Subversion Tutorial]] if you prefer that method.  Although you do not need both HL2SDK versions (unless you wish to build binaries against both), you do need both Metamod:Source versions.  Extensions don't necessarily require Metamod:Source (or even the Source Engine) but its template library is used extensively in SourceMod.&lt;br /&gt;
&lt;br /&gt;
*SourceMod. For full download options, see the [http://www.sourcemod.net/downloads.php SourceMod Downloads] page.  Obviously, you must download the source code and not a binary package.&lt;br /&gt;
*HL2SDK Original.  As of this writing (Sep 2008) this engine is used for most Source games, except for TF2, GMod10, and DoD:S. Repository: [http://hg.alliedmods.net/hl2sdk hl2sdk]&lt;br /&gt;
*HL2SDK OrangeBox.  As of this writing (Sep 2008) this engine is used TF2, GMod10, and DoD:S. Repository: [http://hg.alliedmods.net/hl2sdk-ob hl2sdk-ob]&lt;br /&gt;
*Metamod:Source Source Code. Visit [http://www.metamodsource.net/?go=downloads Metamod:Source downloads]. Right now SourceMod builds against Metamod:Source 1.7.&lt;br /&gt;
&lt;br /&gt;
'''Note''' that when we refer to &amp;quot;Metamod:Source&amp;quot; in this article, we are referring to its source code tree, not a binary package.&lt;br /&gt;
&lt;br /&gt;
If you intend to compile the MySQL extension, you must also download MySQL 5.0.  You can use any version.  For simplicity, here are the versions we use:&lt;br /&gt;
*Linux: We use the 5.0.45 binary from the &amp;quot;[http://dev.mysql.com/downloads/mysql/5.0.html#linux Linux (non RPM packages)]&amp;quot; for &amp;quot;Linux (x86).&amp;quot;  You can also use [http://dev.mysql.com/get/Downloads/MySQL-5.0/mysql-5.0.45-linux-i686-glibc23.tar.gz/from/pick this direct link] (may not be valid in the future).&lt;br /&gt;
*Windows: Due to a MySQL build change we use 5.0.24a which is an older download.  The file name was &amp;quot;mysql-5.0.24a-win32.zip,&amp;quot; if you can't find it you can use this [http://www.bailopan.net/mysql-5.0.24a-win32.zip direct link] (may not be valid in the future).&lt;br /&gt;
&lt;br /&gt;
You can remove all folders from the distribution except for the &amp;quot;lib&amp;quot; and &amp;quot;include&amp;quot; folders which comprise the MySQL SDK.&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
As of this writing, SourceMod's Makefiles are hardcoded to use a binary called &amp;quot;gcc-4.1&amp;quot;  You can override this, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;make CPP=gcc&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Otherwise, you can also just create a symlink:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo ln -s /usr/bin/gcc /usr/bin/gcc-4.1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that you must use &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt; and not &amp;lt;tt&amp;gt;g++&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
SourceMod's Makefiles have strict directory organizational rules.  You must have a top-level folder.  For this document, we'll assume it is called &amp;lt;tt&amp;gt;sourcemod&amp;lt;/tt&amp;gt;, though it can be named anything.  The layout of &amp;lt;tt&amp;gt;sourcemod&amp;lt;/tt&amp;gt; must be:&lt;br /&gt;
*&amp;lt;tt&amp;gt;sourcemod&amp;lt;/tt&amp;gt;/&lt;br /&gt;
**&amp;lt;tt&amp;gt;hl2sdk&amp;lt;/tt&amp;gt; - symlink or folder containing the HL2SDK&lt;br /&gt;
**&amp;lt;tt&amp;gt;hl2sdk-ob&amp;lt;/tt&amp;gt; - symlink or folder containing the HL2SDK for Orange Box/TF&lt;br /&gt;
**&amp;lt;tt&amp;gt;mmsource-1.7&amp;lt;/tt&amp;gt; - symlink or folder containing any Metamod:Source version 1.7 or higher.&lt;br /&gt;
**&amp;lt;tt&amp;gt;sourcemod-central&amp;lt;/tt&amp;gt; - folder containing SourceMod's source code tree.  This can be named anything, as long as it's a valid SourceMod tree (like [http://hg.alliedmods.net/sourcemod-central sourcemod-central]).  You can also use [http://hg.alliedmods.net/sourcemod-1.1 sourcemod-1.1].&lt;br /&gt;
**&amp;lt;tt&amp;gt;mysql-5.0&amp;lt;/tt&amp;gt; - symlink or folder containing a MySQL 5.0 distribution&lt;br /&gt;
&lt;br /&gt;
If you are using a 64-bit version of Linux, you may need to install extra packages to be able to compile SourceMod.  On Debian-based distros, these are typically:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#prerequisites&lt;br /&gt;
#apt-get install g++-4.1 gcc-4.1 make subversion&lt;br /&gt;
#apt-get instal libz libz-dev&lt;br /&gt;
#only needed if you want to use the build tool&lt;br /&gt;
#apt-get install mono mono-devel&lt;br /&gt;
#32-bit support&lt;br /&gt;
apt-get install ia32-libs&lt;br /&gt;
apt-get install lib32z1 lib32z1-dev&lt;br /&gt;
apt-get install libc6-dev-i386 libc6-i386&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
On Windows we don't require a particular directory layout.  Instead, environment variables are used.  The directions below apply to Windows XP, and are assumed to be similar for other versions of Windows.&lt;br /&gt;
*Open the Control Panel (for example, via Start -&amp;gt; Settings).&lt;br /&gt;
*Open the System control.  If you don't see it, you may need to switch to &amp;quot;Classic view&amp;quot; (either via the left-hand pane or by going to Tools -&amp;gt; Folder Options).&lt;br /&gt;
*Click the Advanced tab.&lt;br /&gt;
*Click the Environment Variables button.&lt;br /&gt;
&lt;br /&gt;
You can add your environment variables to either your User settings or your System settings.  Create a new variable for each item in the list below.  The item names are in &amp;lt;tt&amp;gt;fixed-width font&amp;lt;/tt&amp;gt; and their value descriptions follow.&lt;br /&gt;
*&amp;lt;tt&amp;gt;MMSOURCE17&amp;lt;/tt&amp;gt; - Path to Metamod:Source 1.7+&lt;br /&gt;
*&amp;lt;tt&amp;gt;HL2SDK&amp;lt;/tt&amp;gt; - Path to HL2SDK Ep1/Original&lt;br /&gt;
*&amp;lt;tt&amp;gt;HL2SDKOB&amp;lt;/tt&amp;gt; - Path to HL2SDK Ep2/OrangeBox&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Building=&lt;br /&gt;
SourceMod has two types of binaries: those with an engine/MM:S dependence, and those without (&amp;quot;normal&amp;quot; binaries).  Normal binaries have two modes:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Release&amp;lt;/tt&amp;gt; - Optimized binary for release.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Debug&amp;lt;/tt&amp;gt; - Unoptimized binary with debugging checks.&lt;br /&gt;
&lt;br /&gt;
Engine/MM:S dependent binaries have three build modes, each paired with either Release or Debug, meaning there are six build options total.  They are:&lt;br /&gt;
*&amp;lt;tt&amp;gt;Original&amp;lt;/tt&amp;gt; - Building against MM:S 1.4 API with HL2SDK&lt;br /&gt;
*&amp;lt;tt&amp;gt;Episode2&amp;lt;/tt&amp;gt; - Building against MM:S 1.6 API with HL2SDK-OB or higher&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
For both Normal and Engine/MM:S dependent binaries, the object files and the final binary are placed in a folder called &amp;lt;tt&amp;gt;Release&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Debug&amp;lt;/tt&amp;gt; (in the same level as the Makefile) depending on which building mechanism you chose.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Our Makefiles are not set up to detect changes in header files.  If you change a header file, you must clean your build.&lt;br /&gt;
&lt;br /&gt;
===Normal Binaries===&lt;br /&gt;
For normal binaries, you can build simply with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;make&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can clean stale object files with:&lt;br /&gt;
&amp;lt;pre&amp;gt;make clean&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or build debug builds with:&lt;br /&gt;
&amp;lt;pre&amp;gt;make DEBUG=true&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Dependent Binaries===&lt;br /&gt;
Binaries that have an Engine or MM:S dependency require one extra parameter, &amp;lt;tt&amp;gt;ENGINE&amp;lt;/tt&amp;gt;.  It must be either &amp;lt;tt&amp;gt;orangebox&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;original&amp;lt;/tt&amp;gt;.  For example, to build a TF-compatible binary in debug mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;make ENGINE=orangebox DEBUG=true&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dependent binaries are dropped into one of the following folders:&lt;br /&gt;
*Debug.original&lt;br /&gt;
*Debug.orangebox&lt;br /&gt;
*Release.original&lt;br /&gt;
*Release.orangebox&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
Windows project files end with &amp;lt;tt&amp;gt;.vcproj&amp;lt;/tt&amp;gt; and are found in an &amp;lt;tt&amp;gt;msvc8&amp;lt;/tt&amp;gt; folder that resides inside each binary's main source folder.  For example, Core is located in &amp;lt;tt&amp;gt;core/msvc8/sourcemod_mm.vcproj&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Once the file is opened, you can select which build to use by going to Build -&amp;gt; Configuration Manager.  Normal binaries have simply &amp;quot;Debug&amp;quot; and &amp;quot;Release.&amp;quot;  Dependent binaries have the following builds:&lt;br /&gt;
*Debug - Old Metamod&lt;br /&gt;
*Debug - Episode 2 &lt;br /&gt;
*Release - Old Metamod&lt;br /&gt;
*Release - Episode 2 &lt;br /&gt;
&lt;br /&gt;
'''Note''' that dependent binaries will have plain &amp;quot;Debug&amp;quot; and &amp;quot;Release&amp;quot; builds.  These should not be used as they are not configured.&lt;br /&gt;
&lt;br /&gt;
Once you have selected a configuration, you can compile by going to Build -&amp;gt; Build Solution.  The binaries and object files will be written to a folder inside &amp;lt;tt&amp;gt;msvc8&amp;lt;/tt&amp;gt; named after the full configuration name.  For example, using &amp;quot;Debug - Old Metamod&amp;quot; with the &amp;quot;sdktools&amp;quot; extension will result in the binary: &amp;lt;tt&amp;gt;extensions/sdktools/msvc8/Debug - Old Metamod/sdktools.ext.dll&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Visual Studio detects changes to header files intelligently.  It is usually not necessary to rebuild a solution.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Binary Organization=&lt;br /&gt;
Although SourceMod has a somewhat unified building mechanism, each of the binaries has a different purpose.  They can be separated into the following classes:&lt;br /&gt;
&lt;br /&gt;
*Core-Related: Binaries which are required or loaded intrinsically by Core.&lt;br /&gt;
*Extensions: Binaries which are loaded via the extension mechanism.&lt;br /&gt;
*External: Binaries which are standalone or unrelated to SourceMod's live operation (for example, the compiler).&lt;br /&gt;
&lt;br /&gt;
This article is only concerned with the first two types.  &lt;br /&gt;
&lt;br /&gt;
==Core-Related Binaries==&lt;br /&gt;
Binaries related to Core are spread throughout the source code tree.  They are always placed in &amp;lt;tt&amp;gt;sourcemod/bin&amp;lt;/tt&amp;gt; for packaging.  The projects files related to Core are:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;loader&amp;lt;/tt&amp;gt; - This is a very small wrapper binary responsible for detecting the MM:S version and game engine, and deciding which SourceMod version to load.  The output binary is &amp;lt;tt&amp;gt;sourcemod_mm_i486.so&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;sourcemod_mm.dll&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;tt&amp;gt;core&amp;lt;/tt&amp;gt; - This is Core itself, and is a dependent binary.  It has three outputs:&lt;br /&gt;
**Original: &amp;lt;tt&amp;gt;sourcemod.1.ep1.so&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;sourcemod.1.ep1.dll&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Episode 1: &amp;lt;tt&amp;gt;sourcemod.1.ep1.so&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;sourcemod.2.ep1.dll&amp;lt;/tt&amp;gt; (unsupported, not packaged)&lt;br /&gt;
**Episode 2: &amp;lt;tt&amp;gt;sourcemod.1.ep1.so&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;sourcemod.2.ep2.dll&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;sourcepawn/jit/x86&amp;lt;/tt&amp;gt; - This is the SourcePawn JIT for generating IA32/x86 instructions from &amp;lt;tt&amp;gt;.smx&amp;lt;/tt&amp;gt; files.  Currently the source code for this is not made available.  It is built as &amp;lt;tt&amp;gt;sourcepawn.jit.x86.so&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;sourcepawn.jit.x86.dll&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
It is technically not necessary to use the loader.  It is provided as a convenience so users do not have to perform extra steps while installing SourceMod.  However, it is highly recommend that you do use it in order to maintain similarity with the default SourceMod package.&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
Extensions are found in the &amp;lt;tt&amp;gt;extensions&amp;lt;/tt&amp;gt; folder of the source tree.  SDKTools, Cstrike, and the upcoming TF extension are engine/MM:S dependent (and the rest are generally not).&lt;br /&gt;
&lt;br /&gt;
Extensions always are named &amp;lt;tt&amp;gt;name.ext.so&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;name.ext.dll&amp;lt;/tt&amp;gt; where &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; is a unique identifier.  This is true even of dependent binaries.  &lt;br /&gt;
&lt;br /&gt;
When loading extensions, SourceMod looks in two separate folders.  First, it checks the ''dependent extension folder'', which is &amp;lt;tt&amp;gt;extensions/auto.x.y&amp;lt;/tt&amp;gt; where &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; is the MM:S version (1 for 1.4, 2 for 1.6) and &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt; is the Engine version (1 for Original/Ep1, 2 for Ep2/OrangeBox).  If no matching extension is found there, it looks in &amp;lt;tt&amp;gt;extensions&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, the SDKTools binary on Counter-Strike would be loaded from &amp;lt;tt&amp;gt;extensions/auto.1.ep1&amp;lt;/tt&amp;gt;, but the GeoIP binary (which is not dependent) would be loaded from &amp;lt;tt&amp;gt;extensions&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Removing SSE=&lt;br /&gt;
SourceMod binaries are built against SSE by default.  SSE is an important set of optimizations, that, according to Valve's hardware survey, are supported on 99.6% percent of respondents' computers.  If you are in this 0.4% which does not have SSE support, you should consider buying a newer processor.  Only early Pentium 3-grade processors did not have SSE support (for example, the very early Durons), and it is likely your Source server will not perform adequately to support more than few players.&lt;br /&gt;
&lt;br /&gt;
Nonetheless, SourceMod's binaries can all be recompiled to remove its SSE dependence.&lt;br /&gt;
&lt;br /&gt;
==Linux==&lt;br /&gt;
Edit the Makefile of the binary you are trying to compile.  Remove all instances of these flags.  They can simply be erased, there is no need to replace them with anything.&lt;br /&gt;
*&amp;lt;tt&amp;gt;-msse&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;-mfpmath=sse&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure to clean the build after changing the Makefile.&lt;br /&gt;
&lt;br /&gt;
==Windows==&lt;br /&gt;
Load the project file into Visual Studio.  Go to Project -&amp;gt; Properties.  Expand &amp;quot;Configuration Properties,&amp;quot; and then &amp;quot;C/C++&amp;quot; under it.  Select &amp;quot;Code Generation.&amp;quot;  Change the setting &amp;quot;Enable Enhanced Instruction Set&amp;quot; to &amp;quot;Not Set.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' You must change this setting '''for each build configuration''' that you wish to use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Documentation]]&lt;br /&gt;
[[Category:SourceMod Development]]&lt;/div&gt;</summary>
		<author><name>Applecorc</name></author>
		
	</entry>
</feed>