<?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=ThatKidWhoGames</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=ThatKidWhoGames"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/ThatKidWhoGames"/>
	<updated>2026-05-26T06:16:03Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Admin_Menu_(SourceMod_Scripting)&amp;diff=10533</id>
		<title>Admin Menu (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Admin_Menu_(SourceMod_Scripting)&amp;diff=10533"/>
		<updated>2018-05-01T19:08:26Z</updated>

		<summary type="html">&lt;p&gt;ThatKidWhoGames: Updated the syntax&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The admin menu is a menu available to all in-game administrators.  It is a simple, one-level, category-based menu with heavy focus on consistency.  The menu is simply a &amp;lt;tt&amp;gt;TopMenu&amp;lt;/tt&amp;gt;, from the TopMenus extension, and is provided by &amp;lt;tt&amp;gt;adminmenu.sp&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
The menu itself has no items unless external plugins provide them.  Thus, it is possible (and recommended) for third party developers to extend the menu by attaching their own functionality to it.  This requires a bit of patience, but this article documents most of the steps necessary.&lt;br /&gt;
&lt;br /&gt;
=Menu Organization=&lt;br /&gt;
The menu is organized into ''categories'' and ''items''.  Categories are top-level selections on the menu.  Items are selectable entries inside categories.  There are two important rules:&lt;br /&gt;
*There is no nesting.  Categories cannot have sub-categories.&lt;br /&gt;
*Only categories can exist at the top level (i.e. items must have a parent category).&lt;br /&gt;
&lt;br /&gt;
All entries on the menu, be they categories or items, are called ''top menu objects'', and each must have a unique name.  For simplicity, the default admin menu entries use their respective command names as unique names, however this style is not required or enforced.&lt;br /&gt;
&lt;br /&gt;
Unique names are used to identify items for sorting.  For more information, see [[Admin Menu Configuration (SourceMod)|Admin Menu Configuration]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Interfacing to the Admin Menu=&lt;br /&gt;
The admin menu plugin can be loaded or unloaded at any time, and accounting for this in your code is important.  Generally, you must account for the following cases:&lt;br /&gt;
*The admin menu is unloaded while you are interfaced to it.&lt;br /&gt;
*The admin menu is loaded while your plugin is already loaded.&lt;br /&gt;
*The admin menu is loaded before your plugin is loaded.&lt;br /&gt;
&lt;br /&gt;
You do not need to remove menu items; they are removed automatically when your plugin is unloaded, and temporarily removed while your plugin is paused.&lt;br /&gt;
&lt;br /&gt;
Example code is below:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;sourcemod&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Make the admin menu plugin optional */&lt;br /&gt;
#undef REQUIRE_PLUGIN&lt;br /&gt;
#include &amp;lt;adminmenu&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Keep track of the top menu */&lt;br /&gt;
TopMenu hAdminMenu = null;&lt;br /&gt;
&lt;br /&gt;
public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	/* See if the menu plugin is already ready */&lt;br /&gt;
	TopMenu topmenu;&lt;br /&gt;
	if (LibraryExists(&amp;quot;adminmenu&amp;quot;) &amp;amp;&amp;amp; ((topmenu = GetAdminTopMenu()) != null))&lt;br /&gt;
	{&lt;br /&gt;
		/* If so, manually fire the callback */&lt;br /&gt;
		OnAdminMenuReady(topmenu);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnLibraryRemoved(const char[] name)&lt;br /&gt;
{&lt;br /&gt;
	if (StrEqual(name, &amp;quot;adminmenu&amp;quot;, false))&lt;br /&gt;
	{&lt;br /&gt;
		hAdminMenu = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnAdminMenuReady(TopMenu topmenu)&lt;br /&gt;
{&lt;br /&gt;
	/* Try to add the category first, if we want to add one.&lt;br /&gt;
	   Leave this out, if you don't add a new category. */&lt;br /&gt;
	if (obj_dmcommands == INVALID_TOPMENUOBJECT)&lt;br /&gt;
	{&lt;br /&gt;
		OnAdminMenuCreated(topmenu);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* Block us from being called twice */&lt;br /&gt;
	if (topmenu == hAdminMenu)&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	hAdminMenu = topmenu;&lt;br /&gt;
	&lt;br /&gt;
	/* :TODO: Add everything to the menu! */&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Top Menu Objects=&lt;br /&gt;
Top Menu Objects are entries, either categories or items, on the admin menu (or any top menu).  Each has the following properties:&lt;br /&gt;
*&amp;lt;tt&amp;gt;ID&amp;lt;/tt&amp;gt; (OUTPUT): The ID of the object in memory.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Name&amp;lt;/tt&amp;gt; (INPUT): The unique name of the object.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Type&amp;lt;/tt&amp;gt; (INPUT): Either a category or an item.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Handler&amp;lt;/tt&amp;gt; (INPUT): The callback function.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Parent&amp;lt;/tt&amp;gt; (INPUT): Empty for categories, or a category object ID for an item.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Override&amp;lt;/tt&amp;gt; (INPUT): The name of the override associated with the command.  For more information, see [[Overriding Command Access (SourceMod)|Overriding Command Access]].  Overrides don't need to be a command name.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Flags&amp;lt;/tt&amp;gt; (INPUT): Default admin flags that should be associated with the object if the override is not set.&lt;br /&gt;
&lt;br /&gt;
The callback determines how the object is drawn on the menu.  If no flags are specified, the item is usable by any admin.  If an admin does not have access to an object (including an entire category), it will not be displayed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Adding Categories=&lt;br /&gt;
Adding categories is sometimes beneficial for larger plugins with many commands.  A category object receives two TopMenuAction callbacks:&lt;br /&gt;
*&amp;lt;tt&amp;gt;TopMenuAction_DisplayOption&amp;lt;/tt&amp;gt; - The category is being displayed.&lt;br /&gt;
*&amp;lt;tt&amp;gt;TopMenuAction_DisplayTitle&amp;lt;/tt&amp;gt; - The category is being displayed as a title.&lt;br /&gt;
&lt;br /&gt;
For example, let's create a category called &amp;quot;CS:S DM Commands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
TopMenuObject obj_dmcommands;&lt;br /&gt;
&lt;br /&gt;
public void OnAdminMenuCreated(TopMenu topmenu)&lt;br /&gt;
{&lt;br /&gt;
	/* Block us from being called twice */&lt;br /&gt;
	if (topmenu == hAdminMenu &amp;amp;&amp;amp; obj_dmcommands != INVALID_TOPMENUOBJECT)&lt;br /&gt;
	{&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	obj_dmcommands = AddToTopMenu(topmenu,&lt;br /&gt;
		&amp;quot;CS:S DM Commands&amp;quot;,&lt;br /&gt;
		TopMenuObject_Category,&lt;br /&gt;
		CategoryHandler,&lt;br /&gt;
		INVALID_TOPMENUOBJECT);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void CategoryHandler(TopMenu topmenu, &lt;br /&gt;
			TopMenuAction action,&lt;br /&gt;
			TopMenuObject object_id,&lt;br /&gt;
			int param,&lt;br /&gt;
			char[] buffer,&lt;br /&gt;
			int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	if (action == TopMenuAction_DisplayTitle)&lt;br /&gt;
	{&lt;br /&gt;
		Format(buffer, maxlength, &amp;quot;CS:S DM Commands:&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else if (action == TopMenuAction_DisplayOption)&lt;br /&gt;
	{&lt;br /&gt;
		Format(buffer, maxlength, &amp;quot;CS:S DM Commands&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that a callback can handle more than one category.  If that is the desired functionality, you can use the &amp;lt;tt&amp;gt;TopMenuObject&amp;lt;/tt&amp;gt; value to see which object is being drawn.&lt;br /&gt;
&lt;br /&gt;
=Adding Items=&lt;br /&gt;
Items are different from categories in that their selection can be detected.  They must have a parent category.  The code below shows an example of finding an existing category and adding an item to it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void AttachAdminMenu()&lt;br /&gt;
{&lt;br /&gt;
	/* If the category is third party, it will have its own unique name. */&lt;br /&gt;
	TopMenuObject player_commands = FindTopMenuCategory(hAdminMenu, ADMINMENU_PLAYERCOMMANDS);&lt;br /&gt;
&lt;br /&gt;
	if (player_commands == INVALID_TOPMENUOBJECT)&lt;br /&gt;
	{&lt;br /&gt;
		/* Error! */&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	AddToTopMenu(hAdminMenu, &lt;br /&gt;
		&amp;quot;sm_poke&amp;quot;,&lt;br /&gt;
		TopMenuObject_Item,&lt;br /&gt;
		AdminMenu_Poke,&lt;br /&gt;
		player_commands,&lt;br /&gt;
		&amp;quot;sm_poke&amp;quot;,&lt;br /&gt;
		ADMFLAG_SLAY);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void AdminMenu_Poke(TopMenu topmenu, &lt;br /&gt;
			TopMenuAction action,&lt;br /&gt;
			TopMenuObject object_id,&lt;br /&gt;
			int param,&lt;br /&gt;
			char[] buffer,&lt;br /&gt;
			int maxlength)&lt;br /&gt;
{&lt;br /&gt;
	if (action == TopMenuAction_DisplayOption)&lt;br /&gt;
	{&lt;br /&gt;
		Format(buffer, maxlength, &amp;quot;Poke&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else if (action == TopMenuAction_SelectOption)&lt;br /&gt;
	{&lt;br /&gt;
		/* Do something! client who selected item is in param */&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that a callback can handle more than one item.  If that is the desired functionality, you can use the &amp;lt;tt&amp;gt;TopMenuObject&amp;lt;/tt&amp;gt; value to see which object is being drawn.&lt;br /&gt;
&lt;br /&gt;
=Returning to the Menu=&lt;br /&gt;
Sometimes it is desirable to re-display the admin menu to the client.  This can be achievied via &amp;lt;tt&amp;gt;RedisplayAdminMenu&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;adminmenu.inc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>ThatKidWhoGames</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10532</id>
		<title>Timers (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10532"/>
		<updated>2018-05-01T13:58:17Z</updated>

		<summary type="html">&lt;p&gt;ThatKidWhoGames: /* Data Packs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timers in [[SourceMod]] are timed events that occur once or repeatedly at a given interval.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Timers allow you to set an interval, a function to use as the event callback, and an optional Handle to pass through the callback.  This is useful for saving data asynchronously.&lt;br /&gt;
&lt;br /&gt;
All timer functions are in &amp;lt;tt&amp;gt;plugins/include/timers.inc&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
=Basic Usage=&lt;br /&gt;
==One-Time Timers==&lt;br /&gt;
One-time timers are timers that only execute once.  An example of a one-time timer might look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(5.0, LoadStuff);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action LoadStuff(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Loading stuff!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code will print &amp;quot;Loading stuff!&amp;quot; to the server console five seconds after the map loads.  The return value has no meaning for one-time timers.&lt;br /&gt;
&lt;br /&gt;
==Repeatable Timers==&lt;br /&gt;
Repeatable timers execute infinitely many times, once every interval.  Based on the return value, they either continue or cancel.&lt;br /&gt;
&lt;br /&gt;
For example, say you want to display a message five times, once every three seconds:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void someFunction()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(3.0, Timer_PrintMessageFiveTimes, _, TIMER_REPEAT);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Timer_PrintMessageFiveTimes(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	// Create a global variable visible only in the local scope (this function).&lt;br /&gt;
	static int numPrinted = 0;&lt;br /&gt;
&lt;br /&gt;
	if (numPrinted &amp;gt;= 5) &lt;br /&gt;
        {&lt;br /&gt;
		numPrinted = 0;&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	PrintToServer(&amp;quot;Warning! This is a message.&amp;quot;);&lt;br /&gt;
	numPrinted++;&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Continue;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; stops the timer, and &amp;lt;tt&amp;gt;Plugin_Continue&amp;lt;/tt&amp;gt; allows it to continue repeating.&lt;br /&gt;
&lt;br /&gt;
=Passing Data=&lt;br /&gt;
==Simple Values==&lt;br /&gt;
As mentioned earlier, timers let you pass values on to the callback function.  This value can be any type.  For example, let's say we want to print a message to a player fifteen seconds after they connect.  However, we want to cancel the timer if the player disconnects.  Implementing this is very easy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, client);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any client)&lt;br /&gt;
{&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Another example without using handles is to use either UserID or ClientSerial (which is unique to each player):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(15.0, WelcomePlayer, GetClientSerial(client)); // You could also use GetClientUserId(client)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any serial)&lt;br /&gt;
{&lt;br /&gt;
	int client = GetClientFromSerial(serial); // Validate the client serial&lt;br /&gt;
	&lt;br /&gt;
	if (client == 0) // The serial is no longer valid, the player must have disconnected&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
If you want to close or cancel a timer when a client disconnects, then use the first example with handles.&lt;br /&gt;
&lt;br /&gt;
==Handles==&lt;br /&gt;
If you want to pass a Handle as a value, you have the option of using &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt;, which will automatically call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; for you once the timer dies.  &lt;br /&gt;
&lt;br /&gt;
==Data Packs==&lt;br /&gt;
Data packs are packable structures that can be used to hold asynchronous data (data that must be saved and unpacked for later).  They are especially useful for timers, and thus there exists a helper function, called &amp;lt;tt&amp;gt;CreateDataTimer()&amp;lt;/tt&amp;gt;, which creates a timer using a data pack handle.  The handle is created and closed automatically for you.&lt;br /&gt;
&lt;br /&gt;
The above example could be rewritten as:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	DataPack pack;&lt;br /&gt;
	WelcomeTimers[client] = CreateDataTimer(15.0, WelcomePlayer, pack);&lt;br /&gt;
	pack.WriteCell(client);&lt;br /&gt;
	pack.WriteString(&amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, Handle pack)&lt;br /&gt;
{&lt;br /&gt;
	char str[128];&lt;br /&gt;
	int client;&lt;br /&gt;
&lt;br /&gt;
	/* Set to the beginning and unpack it */&lt;br /&gt;
	ResetPack(pack);&lt;br /&gt;
	client = ReadPackCell(pack);&lt;br /&gt;
	ReadPackString(pack, str, sizeof(str));&lt;br /&gt;
	PrintToConsole(client, &amp;quot;%s&amp;quot;, str);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Notes=&lt;br /&gt;
==Accuracy==&lt;br /&gt;
The smallest possible interval is 0.1 seconds.  Timers have high precision (floating point) but low accuracy, as the current time is based on the in-game tick count, not the system clock.  This has two implications:&lt;br /&gt;
*If the server is paused (not ticking or hibernating), timers will not run.&lt;br /&gt;
*The server will not always tick at an exact interval.  &lt;br /&gt;
&lt;br /&gt;
For example, a 1.234 second interval timer starting from time &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt; might not tick until &amp;lt;tt&amp;gt;t+1.242&amp;lt;/tt&amp;gt; at a tickrate of 66 ticks per second.&lt;br /&gt;
&lt;br /&gt;
==Timer Death==&lt;br /&gt;
All timers are guaranteed to die either by:&lt;br /&gt;
*&amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; being called (or on plugin unload);&lt;br /&gt;
*&amp;lt;tt&amp;gt;KillTimer()&amp;lt;/tt&amp;gt; being called;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; being returned from a repeatable timer;&lt;br /&gt;
*&amp;lt;tt&amp;gt;TriggerTimer()&amp;lt;/tt&amp;gt; being called on a one-time timer;&lt;br /&gt;
*Execution of a one-time timer finishes.&lt;br /&gt;
&lt;br /&gt;
When a timer dies, if &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt; is set, the Handle will always be closed with the permissions that &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; uses by default.  Since timers cannot be cloned, there should be no ownership issues.&lt;br /&gt;
&lt;br /&gt;
==Changing Intervals==&lt;br /&gt;
The interval of a timer cannot be changed as of this writing.  The timer must be killed and a new one created.&lt;br /&gt;
&lt;br /&gt;
==AMX Mod X==&lt;br /&gt;
Unlike [[AMX Mod X]]'s &amp;lt;tt&amp;gt;set_task&amp;lt;/tt&amp;gt; function, you cannot pass arrays using &amp;lt;tt&amp;gt;CreateTimer&amp;lt;/tt&amp;gt;.  To accomplish this, you should use the data pack functionality explained above.&lt;br /&gt;
&lt;br /&gt;
Similarly, there are no flags for counted repeats (non-infinite loops) or timers based on the map start or end.  These must be done manually.&lt;br /&gt;
&lt;br /&gt;
=External Links=&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=130 On Timer Design, Part 3] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=119 On Timer Design, Part 2] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=118 On Timer Design, Part 1] (SourceMod DevLog)&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>ThatKidWhoGames</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10531</id>
		<title>Timers (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10531"/>
		<updated>2018-05-01T13:58:07Z</updated>

		<summary type="html">&lt;p&gt;ThatKidWhoGames: Nvm reverting changes, didn't read section properly that it is data timer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timers in [[SourceMod]] are timed events that occur once or repeatedly at a given interval.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Timers allow you to set an interval, a function to use as the event callback, and an optional Handle to pass through the callback.  This is useful for saving data asynchronously.&lt;br /&gt;
&lt;br /&gt;
All timer functions are in &amp;lt;tt&amp;gt;plugins/include/timers.inc&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
=Basic Usage=&lt;br /&gt;
==One-Time Timers==&lt;br /&gt;
One-time timers are timers that only execute once.  An example of a one-time timer might look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(5.0, LoadStuff);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action LoadStuff(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Loading stuff!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code will print &amp;quot;Loading stuff!&amp;quot; to the server console five seconds after the map loads.  The return value has no meaning for one-time timers.&lt;br /&gt;
&lt;br /&gt;
==Repeatable Timers==&lt;br /&gt;
Repeatable timers execute infinitely many times, once every interval.  Based on the return value, they either continue or cancel.&lt;br /&gt;
&lt;br /&gt;
For example, say you want to display a message five times, once every three seconds:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void someFunction()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(3.0, Timer_PrintMessageFiveTimes, _, TIMER_REPEAT);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Timer_PrintMessageFiveTimes(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	// Create a global variable visible only in the local scope (this function).&lt;br /&gt;
	static int numPrinted = 0;&lt;br /&gt;
&lt;br /&gt;
	if (numPrinted &amp;gt;= 5) &lt;br /&gt;
        {&lt;br /&gt;
		numPrinted = 0;&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	PrintToServer(&amp;quot;Warning! This is a message.&amp;quot;);&lt;br /&gt;
	numPrinted++;&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Continue;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; stops the timer, and &amp;lt;tt&amp;gt;Plugin_Continue&amp;lt;/tt&amp;gt; allows it to continue repeating.&lt;br /&gt;
&lt;br /&gt;
=Passing Data=&lt;br /&gt;
==Simple Values==&lt;br /&gt;
As mentioned earlier, timers let you pass values on to the callback function.  This value can be any type.  For example, let's say we want to print a message to a player fifteen seconds after they connect.  However, we want to cancel the timer if the player disconnects.  Implementing this is very easy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, client);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any client)&lt;br /&gt;
{&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Another example without using handles is to use either UserID or ClientSerial (which is unique to each player):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(15.0, WelcomePlayer, GetClientSerial(client)); // You could also use GetClientUserId(client)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any serial)&lt;br /&gt;
{&lt;br /&gt;
	int client = GetClientFromSerial(serial); // Validate the client serial&lt;br /&gt;
	&lt;br /&gt;
	if (client == 0) // The serial is no longer valid, the player must have disconnected&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
If you want to close or cancel a timer when a client disconnects, then use the first example with handles.&lt;br /&gt;
&lt;br /&gt;
==Handles==&lt;br /&gt;
If you want to pass a Handle as a value, you have the option of using &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt;, which will automatically call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; for you once the timer dies.  &lt;br /&gt;
&lt;br /&gt;
==Data Packs==&lt;br /&gt;
Data packs are packable structures that can be used to hold asynchronous data (data that must be saved and unpacked for later).  They are especially useful for timers, and thus there exists a helper function, called &amp;lt;tt&amp;gt;CreateDataTimer()&amp;lt;/tt&amp;gt;, which creates a timer using a data pack handle.  The handle is created and closed automatically for you.&lt;br /&gt;
&lt;br /&gt;
The above example could be rewritten as:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	DataPack pack;&lt;br /&gt;
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, pack);&lt;br /&gt;
	pack.WriteCell(client);&lt;br /&gt;
	pack.WriteString(&amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, Handle pack)&lt;br /&gt;
{&lt;br /&gt;
	char str[128];&lt;br /&gt;
	int client;&lt;br /&gt;
&lt;br /&gt;
	/* Set to the beginning and unpack it */&lt;br /&gt;
	ResetPack(pack);&lt;br /&gt;
	client = ReadPackCell(pack);&lt;br /&gt;
	ReadPackString(pack, str, sizeof(str));&lt;br /&gt;
	PrintToConsole(client, &amp;quot;%s&amp;quot;, str);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Notes=&lt;br /&gt;
==Accuracy==&lt;br /&gt;
The smallest possible interval is 0.1 seconds.  Timers have high precision (floating point) but low accuracy, as the current time is based on the in-game tick count, not the system clock.  This has two implications:&lt;br /&gt;
*If the server is paused (not ticking or hibernating), timers will not run.&lt;br /&gt;
*The server will not always tick at an exact interval.  &lt;br /&gt;
&lt;br /&gt;
For example, a 1.234 second interval timer starting from time &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt; might not tick until &amp;lt;tt&amp;gt;t+1.242&amp;lt;/tt&amp;gt; at a tickrate of 66 ticks per second.&lt;br /&gt;
&lt;br /&gt;
==Timer Death==&lt;br /&gt;
All timers are guaranteed to die either by:&lt;br /&gt;
*&amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; being called (or on plugin unload);&lt;br /&gt;
*&amp;lt;tt&amp;gt;KillTimer()&amp;lt;/tt&amp;gt; being called;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; being returned from a repeatable timer;&lt;br /&gt;
*&amp;lt;tt&amp;gt;TriggerTimer()&amp;lt;/tt&amp;gt; being called on a one-time timer;&lt;br /&gt;
*Execution of a one-time timer finishes.&lt;br /&gt;
&lt;br /&gt;
When a timer dies, if &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt; is set, the Handle will always be closed with the permissions that &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; uses by default.  Since timers cannot be cloned, there should be no ownership issues.&lt;br /&gt;
&lt;br /&gt;
==Changing Intervals==&lt;br /&gt;
The interval of a timer cannot be changed as of this writing.  The timer must be killed and a new one created.&lt;br /&gt;
&lt;br /&gt;
==AMX Mod X==&lt;br /&gt;
Unlike [[AMX Mod X]]'s &amp;lt;tt&amp;gt;set_task&amp;lt;/tt&amp;gt; function, you cannot pass arrays using &amp;lt;tt&amp;gt;CreateTimer&amp;lt;/tt&amp;gt;.  To accomplish this, you should use the data pack functionality explained above.&lt;br /&gt;
&lt;br /&gt;
Similarly, there are no flags for counted repeats (non-infinite loops) or timers based on the map start or end.  These must be done manually.&lt;br /&gt;
&lt;br /&gt;
=External Links=&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=130 On Timer Design, Part 3] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=119 On Timer Design, Part 2] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=118 On Timer Design, Part 1] (SourceMod DevLog)&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>ThatKidWhoGames</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10530</id>
		<title>Timers (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10530"/>
		<updated>2018-05-01T13:56:11Z</updated>

		<summary type="html">&lt;p&gt;ThatKidWhoGames: /* Data Packs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timers in [[SourceMod]] are timed events that occur once or repeatedly at a given interval.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Timers allow you to set an interval, a function to use as the event callback, and an optional Handle to pass through the callback.  This is useful for saving data asynchronously.&lt;br /&gt;
&lt;br /&gt;
All timer functions are in &amp;lt;tt&amp;gt;plugins/include/timers.inc&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
=Basic Usage=&lt;br /&gt;
==One-Time Timers==&lt;br /&gt;
One-time timers are timers that only execute once.  An example of a one-time timer might look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(5.0, LoadStuff);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action LoadStuff(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Loading stuff!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code will print &amp;quot;Loading stuff!&amp;quot; to the server console five seconds after the map loads.  The return value has no meaning for one-time timers.&lt;br /&gt;
&lt;br /&gt;
==Repeatable Timers==&lt;br /&gt;
Repeatable timers execute infinitely many times, once every interval.  Based on the return value, they either continue or cancel.&lt;br /&gt;
&lt;br /&gt;
For example, say you want to display a message five times, once every three seconds:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void someFunction()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(3.0, Timer_PrintMessageFiveTimes, _, TIMER_REPEAT);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Timer_PrintMessageFiveTimes(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	// Create a global variable visible only in the local scope (this function).&lt;br /&gt;
	static int numPrinted = 0;&lt;br /&gt;
&lt;br /&gt;
	if (numPrinted &amp;gt;= 5) &lt;br /&gt;
        {&lt;br /&gt;
		numPrinted = 0;&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	PrintToServer(&amp;quot;Warning! This is a message.&amp;quot;);&lt;br /&gt;
	numPrinted++;&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Continue;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; stops the timer, and &amp;lt;tt&amp;gt;Plugin_Continue&amp;lt;/tt&amp;gt; allows it to continue repeating.&lt;br /&gt;
&lt;br /&gt;
=Passing Data=&lt;br /&gt;
==Simple Values==&lt;br /&gt;
As mentioned earlier, timers let you pass values on to the callback function.  This value can be any type.  For example, let's say we want to print a message to a player fifteen seconds after they connect.  However, we want to cancel the timer if the player disconnects.  Implementing this is very easy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, client);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any client)&lt;br /&gt;
{&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Another example without using handles is to use either UserID or ClientSerial (which is unique to each player):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(15.0, WelcomePlayer, GetClientSerial(client)); // You could also use GetClientUserId(client)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any serial)&lt;br /&gt;
{&lt;br /&gt;
	int client = GetClientFromSerial(serial); // Validate the client serial&lt;br /&gt;
	&lt;br /&gt;
	if (client == 0) // The serial is no longer valid, the player must have disconnected&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
If you want to close or cancel a timer when a client disconnects, then use the first example with handles.&lt;br /&gt;
&lt;br /&gt;
==Handles==&lt;br /&gt;
If you want to pass a Handle as a value, you have the option of using &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt;, which will automatically call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; for you once the timer dies.  &lt;br /&gt;
&lt;br /&gt;
==Data Packs==&lt;br /&gt;
Data packs are packable structures that can be used to hold asynchronous data (data that must be saved and unpacked for later).  They are especially useful for timers, and thus there exists a helper function, called &amp;lt;tt&amp;gt;CreateDataTimer()&amp;lt;/tt&amp;gt;, which creates a timer using a data pack handle.  The handle is created and closed automatically for you.&lt;br /&gt;
&lt;br /&gt;
The above example could be rewritten as:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	DataPack pack;&lt;br /&gt;
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, pack);&lt;br /&gt;
	pack.WriteCell(client);&lt;br /&gt;
	pack.WriteString(&amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, DataPack pack)&lt;br /&gt;
{&lt;br /&gt;
	char str[128];&lt;br /&gt;
	int client;&lt;br /&gt;
&lt;br /&gt;
	/* Set to the beginning and unpack it */&lt;br /&gt;
	pack.Reset();&lt;br /&gt;
	client = pack.ReadCell();&lt;br /&gt;
	pack.ReadString(str, sizeof(str));&lt;br /&gt;
	pack.Close();&lt;br /&gt;
	PrintToConsole(client, &amp;quot;%s&amp;quot;, str);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Notes=&lt;br /&gt;
==Accuracy==&lt;br /&gt;
The smallest possible interval is 0.1 seconds.  Timers have high precision (floating point) but low accuracy, as the current time is based on the in-game tick count, not the system clock.  This has two implications:&lt;br /&gt;
*If the server is paused (not ticking or hibernating), timers will not run.&lt;br /&gt;
*The server will not always tick at an exact interval.  &lt;br /&gt;
&lt;br /&gt;
For example, a 1.234 second interval timer starting from time &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt; might not tick until &amp;lt;tt&amp;gt;t+1.242&amp;lt;/tt&amp;gt; at a tickrate of 66 ticks per second.&lt;br /&gt;
&lt;br /&gt;
==Timer Death==&lt;br /&gt;
All timers are guaranteed to die either by:&lt;br /&gt;
*&amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; being called (or on plugin unload);&lt;br /&gt;
*&amp;lt;tt&amp;gt;KillTimer()&amp;lt;/tt&amp;gt; being called;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; being returned from a repeatable timer;&lt;br /&gt;
*&amp;lt;tt&amp;gt;TriggerTimer()&amp;lt;/tt&amp;gt; being called on a one-time timer;&lt;br /&gt;
*Execution of a one-time timer finishes.&lt;br /&gt;
&lt;br /&gt;
When a timer dies, if &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt; is set, the Handle will always be closed with the permissions that &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; uses by default.  Since timers cannot be cloned, there should be no ownership issues.&lt;br /&gt;
&lt;br /&gt;
==Changing Intervals==&lt;br /&gt;
The interval of a timer cannot be changed as of this writing.  The timer must be killed and a new one created.&lt;br /&gt;
&lt;br /&gt;
==AMX Mod X==&lt;br /&gt;
Unlike [[AMX Mod X]]'s &amp;lt;tt&amp;gt;set_task&amp;lt;/tt&amp;gt; function, you cannot pass arrays using &amp;lt;tt&amp;gt;CreateTimer&amp;lt;/tt&amp;gt;.  To accomplish this, you should use the data pack functionality explained above.&lt;br /&gt;
&lt;br /&gt;
Similarly, there are no flags for counted repeats (non-infinite loops) or timers based on the map start or end.  These must be done manually.&lt;br /&gt;
&lt;br /&gt;
=External Links=&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=130 On Timer Design, Part 3] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=119 On Timer Design, Part 2] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=118 On Timer Design, Part 1] (SourceMod DevLog)&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>ThatKidWhoGames</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10529</id>
		<title>Timers (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=10529"/>
		<updated>2018-05-01T13:55:04Z</updated>

		<summary type="html">&lt;p&gt;ThatKidWhoGames: Updated the timer callback with the DataPack method map and closed the handle.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timers in [[SourceMod]] are timed events that occur once or repeatedly at a given interval.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Timers allow you to set an interval, a function to use as the event callback, and an optional Handle to pass through the callback.  This is useful for saving data asynchronously.&lt;br /&gt;
&lt;br /&gt;
All timer functions are in &amp;lt;tt&amp;gt;plugins/include/timers.inc&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
=Basic Usage=&lt;br /&gt;
==One-Time Timers==&lt;br /&gt;
One-time timers are timers that only execute once.  An example of a one-time timer might look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public void OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(5.0, LoadStuff);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action LoadStuff(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Loading stuff!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code will print &amp;quot;Loading stuff!&amp;quot; to the server console five seconds after the map loads.  The return value has no meaning for one-time timers.&lt;br /&gt;
&lt;br /&gt;
==Repeatable Timers==&lt;br /&gt;
Repeatable timers execute infinitely many times, once every interval.  Based on the return value, they either continue or cancel.&lt;br /&gt;
&lt;br /&gt;
For example, say you want to display a message five times, once every three seconds:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
void someFunction()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(3.0, Timer_PrintMessageFiveTimes, _, TIMER_REPEAT);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action Timer_PrintMessageFiveTimes(Handle timer)&lt;br /&gt;
{&lt;br /&gt;
	// Create a global variable visible only in the local scope (this function).&lt;br /&gt;
	static int numPrinted = 0;&lt;br /&gt;
&lt;br /&gt;
	if (numPrinted &amp;gt;= 5) &lt;br /&gt;
        {&lt;br /&gt;
		numPrinted = 0;&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	PrintToServer(&amp;quot;Warning! This is a message.&amp;quot;);&lt;br /&gt;
	numPrinted++;&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Continue;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; stops the timer, and &amp;lt;tt&amp;gt;Plugin_Continue&amp;lt;/tt&amp;gt; allows it to continue repeating.&lt;br /&gt;
&lt;br /&gt;
=Passing Data=&lt;br /&gt;
==Simple Values==&lt;br /&gt;
As mentioned earlier, timers let you pass values on to the callback function.  This value can be any type.  For example, let's say we want to print a message to a player fifteen seconds after they connect.  However, we want to cancel the timer if the player disconnects.  Implementing this is very easy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, client);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any client)&lt;br /&gt;
{&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Another example without using handles is to use either UserID or ClientSerial (which is unique to each player):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(15.0, WelcomePlayer, GetClientSerial(client)); // You could also use GetClientUserId(client)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, any serial)&lt;br /&gt;
{&lt;br /&gt;
	int client = GetClientFromSerial(serial); // Validate the client serial&lt;br /&gt;
	&lt;br /&gt;
	if (client == 0) // The serial is no longer valid, the player must have disconnected&lt;br /&gt;
	{&lt;br /&gt;
		return Plugin_Stop;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
If you want to close or cancel a timer when a client disconnects, then use the first example with handles.&lt;br /&gt;
&lt;br /&gt;
==Handles==&lt;br /&gt;
If you want to pass a Handle as a value, you have the option of using &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt;, which will automatically call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; for you once the timer dies.  &lt;br /&gt;
&lt;br /&gt;
==Data Packs==&lt;br /&gt;
Data packs are packable structures that can be used to hold asynchronous data (data that must be saved and unpacked for later).  They are especially useful for timers, and thus there exists a helper function, called &amp;lt;tt&amp;gt;CreateDataTimer()&amp;lt;/tt&amp;gt;, which creates a timer using a data pack handle.  The handle is created and closed automatically for you.&lt;br /&gt;
&lt;br /&gt;
The above example could be rewritten as:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
Handle WelcomeTimers[MAXPLAYERS+1];&lt;br /&gt;
&lt;br /&gt;
public void OnClientPutInServer(int client)&lt;br /&gt;
{&lt;br /&gt;
	DataPack pack;&lt;br /&gt;
	WelcomeTimers[client] = CreateDataTimer(15.0, WelcomePlayer, pack);&lt;br /&gt;
	pack.WriteCell(client);&lt;br /&gt;
	pack.WriteString(&amp;quot;Welcome to the server!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void OnClientDisconnect(int client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != null)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client]);&lt;br /&gt;
		WelcomeTimers[client] = null;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action WelcomePlayer(Handle timer, DataPack pack)&lt;br /&gt;
{&lt;br /&gt;
	char str[128];&lt;br /&gt;
	int client;&lt;br /&gt;
&lt;br /&gt;
	/* Set to the beginning and unpack it */&lt;br /&gt;
	pack.Reset();&lt;br /&gt;
	client = pack.ReadCell();&lt;br /&gt;
	pack.ReadString(str, sizeof(str));&lt;br /&gt;
	pack.Close();&lt;br /&gt;
	PrintToConsole(client, &amp;quot;%s&amp;quot;, str);&lt;br /&gt;
	WelcomeTimers[client] = null;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Notes=&lt;br /&gt;
==Accuracy==&lt;br /&gt;
The smallest possible interval is 0.1 seconds.  Timers have high precision (floating point) but low accuracy, as the current time is based on the in-game tick count, not the system clock.  This has two implications:&lt;br /&gt;
*If the server is paused (not ticking or hibernating), timers will not run.&lt;br /&gt;
*The server will not always tick at an exact interval.  &lt;br /&gt;
&lt;br /&gt;
For example, a 1.234 second interval timer starting from time &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt; might not tick until &amp;lt;tt&amp;gt;t+1.242&amp;lt;/tt&amp;gt; at a tickrate of 66 ticks per second.&lt;br /&gt;
&lt;br /&gt;
==Timer Death==&lt;br /&gt;
All timers are guaranteed to die either by:&lt;br /&gt;
*&amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; being called (or on plugin unload);&lt;br /&gt;
*&amp;lt;tt&amp;gt;KillTimer()&amp;lt;/tt&amp;gt; being called;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; being returned from a repeatable timer;&lt;br /&gt;
*&amp;lt;tt&amp;gt;TriggerTimer()&amp;lt;/tt&amp;gt; being called on a one-time timer;&lt;br /&gt;
*Execution of a one-time timer finishes.&lt;br /&gt;
&lt;br /&gt;
When a timer dies, if &amp;lt;tt&amp;gt;TIMER_DATA_HNDL_CLOSE&amp;lt;/tt&amp;gt; is set, the Handle will always be closed with the permissions that &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; uses by default.  Since timers cannot be cloned, there should be no ownership issues.&lt;br /&gt;
&lt;br /&gt;
==Changing Intervals==&lt;br /&gt;
The interval of a timer cannot be changed as of this writing.  The timer must be killed and a new one created.&lt;br /&gt;
&lt;br /&gt;
==AMX Mod X==&lt;br /&gt;
Unlike [[AMX Mod X]]'s &amp;lt;tt&amp;gt;set_task&amp;lt;/tt&amp;gt; function, you cannot pass arrays using &amp;lt;tt&amp;gt;CreateTimer&amp;lt;/tt&amp;gt;.  To accomplish this, you should use the data pack functionality explained above.&lt;br /&gt;
&lt;br /&gt;
Similarly, there are no flags for counted repeats (non-infinite loops) or timers based on the map start or end.  These must be done manually.&lt;br /&gt;
&lt;br /&gt;
=External Links=&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=130 On Timer Design, Part 3] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=119 On Timer Design, Part 2] (SourceMod DevLog)&lt;br /&gt;
*[http://www.sourcemod.net/devlog/?p=118 On Timer Design, Part 1] (SourceMod DevLog)&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
&lt;br /&gt;
{{LanguageSwitch}}&lt;/div&gt;</summary>
		<author><name>ThatKidWhoGames</name></author>
		
	</entry>
</feed>