Ru:Timers (SourceMod Scripting)

From AlliedModders Wiki
Jump to: navigation, search

Timers in SourceMod are timed events that occur once or repeatedly at a given interval.

Introduction

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.

All timer functions are in plugins/include/timers.inc.

Basic Usage

One-Time Timers

One-time timers are timers that only execute once. An example of a one-time timer might look like:

public OnPluginStart()
{
	CreateTimer(5.0, LoadStuff)
}
 
public Action:LoadStuff(Handle:timer)
{
	PrintToServer("Loading stuff!")
}

This code will print "Loading stuff!" to the server console five seconds after the map loads. The return value has no meaning for one-time timers.

Repeatable Timers

Repeatable timers execute infinitely many times, once every interval. Based on the return value, they either continue or cancel.

For example, say you want to display a message five times, once every three seconds:

DoMessage()
{
	CreateTimer(3.0, PrintMsg, _, TIMER_REPEAT)
}
 
public Action:PrintMsg(Handle:timer)
{
	static NumPrinted = 0
	if (NumPrinted++ >= 5)
	{
		PrintToServer("Warning! This is a message.")
		NumPrinted = 0
 
		return Plugin_Stop
	}
 
	return Plugin_Continue
}

Note that Plugin_Stop stops the timer, and Plugin_Continue allows it to continue repeating.

Passing Data

Simple Values

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:

#define MAX_PLAYERS 256
 
new Handle:WelcomeTimers[MAX_PLAYERS+1]
 
public OnClientPutInServer(client)
{
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, client)
}
 
public OnClientDisconnect(client)
{
	if (WelcomeTimers[client] != INVALID_HANDLE)
	{
		KillTimer(WelcomeTimers[client])
		WelcomeTimers[client] = INVALID_HANDLE
	}
}
 
public Action:WelcomePlayer(Handle:timer, any:client)
{
	PrintToConsole(client, "Welcome to the server!")
	WelcomeTimers[client] = INVALID_HANDLE
}

Handles

If you want to pass a Handle as a value, you have the option of using TIMER_HNDL_CLOSE, which will automatically call CloseHandle() for you once the timer dies.

Data Packs

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 CreateDataTimer(), which creates a timer using a data pack handle. The handle is created and closed automatically for you.

The above example could be rewritten as:

#define MAX_PLAYERS 256
 
new Handle:WelcomeTimers[MAX_PLAYERS+1]
 
public OnClientPutInServer(client)
{
	new Handle:pack
	WelcomeTimers[client] = CreateDataTimer(15.0, WelcomePlayer, pack)
	WritePackCell(pack, client)
	WritePackString(pack, "Welcome to the server!")
}
 
public OnClientDisconnect(client)
{
	if (WelcomeTimers[client] != INVALID_HANDLE)
	{
		KillTimer(WelcomeTimers[client])
		WelcomeTimers[client] = INVALID_HANDLE
	}
}
 
public Action:WelcomePlayer(Handle:timer, Handle:pack)
{
	decl String:str[128]
	new client
 
	/* Set to the beginning and unpack it */
	ResetPack(pack)
	client = ReadPackCell(pack)
	ReadPackString(pack, str, sizeof(str))
 
	PrintToConsole(client, "%s", str)
	WelcomeTimers[client] = INVALID_HANDLE
}

Notes

Accuracy

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:

  • If the server is paused (not ticking), timers will not run.
  • The server will not always tick at an exact interval.

For example, a 1.234 second interval timer starting from time t might not tick until t+1.242 at a tickrate of 66 ticks per second.

Timer Death

All timers are guaranteed to die either by:

  • CloseHandle() being called (or on plugin unload);
  • KillTimer() being called;
  • Plugin_Stop being returned from a repeatable timer;
  • TriggerTimer() being called on a one-time timer;
  • Execution of a one-time timer finishes.

When a timer dies, if TIMER_HNDL_CLOSE is set, the Handle will always be closed with the permissions that CloseHandle() uses by default. Since timers cannot be cloned, there should be no ownership issues.

Changing Intervals

The interval of a timer cannot be changed as of this writing. The timer must be killed and a new one created.

AMX Mod X

Unlike AMX Mod X's set_task function, you cannot pass arrays using CreateTimer. To accomplish this, you should use the data pack functionality explained above.

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.

External Links