Pushistik↯❤
Команда форума
- Регистрация
- 6 Июл 2017
- Сообщения
- 393
- Реакции
- 97
- Баллы
- 28
[SourcePawn] Урок 6 - Таймеры
<= К содержанию
Таймеры нужны для выполнения действий через определенный промежуток времени.Таймер создается функцией CreateTimer и имеет тип Handle.
PHP:
Handle CreateTimer(float interval, Timer func, any data, int flags)
- float interval - задает время, через которое будет выполнен обратный вызов таймера.
- Timer func - имя обратного вызова таймера.
- any data - данные, которые будут переданы в таймер.
- int flags - флаги таймера.
- Подробнее о флагах:
Функция уничтожает таймер.- TIMER_REPEAT - Если установлен, таймер будет выполнятся до тех пора пока обратный вызов не вернет Plugin_Stop или не будет уничтожен с помощью KillTimer. Проще говоря, используется для создания повторяющихся таймеров.
- TIMER_FLAG_NO_MAPCHANGE - Если установлен, таймер будет уничтожен при смене карты.
- TIMER_DATA_HNDL_CLOSE - Таймер автоматически будет вызывать CloseHandle() для данных переданных в него после выполнения таймера. (ранее TIMER_HNDL_CLOSE)
PHP:
void KillTimer(Handle timer, bool autoClose = false)
- Handle timer - дескриптор таймера.
- bool autoClose - Если установлено true, то данные, переданные в CreateTimer() будут закрыты с помощью CloseHandle(), если TIMER_DATA_HNDL_CLOSE не был указан.
PHP:void TriggerTimer(Handle timer, bool reset = false)
- Handle timer - дескриптор таймера.
- bool reset - Если установлено true, то прошедшее время сбросится и отсчет начнется заново.
Виды обратных вызовов:
- Используется если в таймер не передавалось никаких данных.
PHP:
function Action(Handle timer)
- Используется если в таймер были переданы данные, для которых не нужно вызывать CloseHandle(). Например int типа.
PHP:
function Action(Handle timer, any data)
- Используется если в таймер были переданы данные, для которых нужно вызывать CloseHandle(). Производные от типа Handle, (в основном DataPack но могут быть и другие).
PHP:
function Action(Handle timer, Handle hndl)
PHP:
/*
Выведем каждому игроку при входе приветствие с задержкой в 10 сек.
*/
public void OnClientPutInServer(int iClient) // Игрок подключается
{
CreateTimer(10.0, Timer_Welcome, GetClientUserId(iClient), TIMER_FLAG_NO_MAPCHANGE);
// Через 10 секунд будет вызван каллбек Timer_Welcome
/* В качестве данных передадим userid игрока,
потому что 10 секунд это достаточно большой интервал,
чтобы игрок отключился и вместо него подключился другой с таким же индексом.
*/
}
public Action Timer_Welcome(Handle hTimer, any UserId) // Каллбек нашего таймера
{
int iClient = GetClientOfUserId(UserId); // Получаем индекс из userid
if(iClient) // Если iClient != 0 значит он всё еще на сервере
{
// Выводим игроку сообщение
PrintToChat(iClient, "Добро пожаловать на наш сервер, %N!", iClient);
}
return Plugin_Stop;
}
PHP:
/*
Будем выводить каждому игроку сообщение с интервалом в 60 сек.
И уничтожим таймер как только все игроки покинули сервер.
*/
public void OnMapStart() // Старт карты
{
CreateTimer(60.0, Timer_Message, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
// Интервал 60 сек
/*
Никаких данных не передаем, поэтому пропускаем параметр с помощью символа [B]_[/B] либо просто пишем 0.
Так же передаем 2 флага:
TIMER_REPEAT - нужен для того чтобы таймер повторялся.
TIMER_FLAG_NO_MAPCHANGE - нужен для того чтобы таймер был уничтожен при смене карты, ведь при запуске новой карты мы создадим новый.
*/
}
public Action Timer_Message(Handle hTimer) // Каллбек нашего таймера
{
int i, iCount;
for(i = 1; i <= MaxClients; ++i) // Цикл по всем игрокам
{
if(IsClientInGame(i) && !IsFakeClient(i)) // Проверяем что игрок в игре и не бот
{
// Выводим игроку сообщение
PrintToChat(iClient, "Прошла еще одна минута карты!");
++iCount; // Прибавляем 1 к счетчику игроков
}
}
if(iCount == 0) // Если нет игроков
{
return Plugin_Stop; // Останавливаем таймер
}
return Plugin_Continue; // Позволяем таймеру выполнятся дальше
}
// В данном случае таймер вновь будет запущен при смене карты
PHP:
/*
Передадим разные данные в таймер
*/
public void OnMapStart()
{
DataPack hPack = new DataPack();
hPack.WriteCell(5);
hPack.WriteFloat(7.5);
hPack.WriteString("string");
CreateTimer(5.0, Timer_ReadDataPack, hPack, TIMER_DATA_HNDL_CLOSE|TIMER_FLAG_NO_MAPCHANGE);
}
public Action Timer_ReadDataPack(Handle hTimer, Handle hDataPack)
{
DataPack hPack = view_as<DataPack>(hDataPack); // Преобразуем Handle в DataPack
hPack.Reset();
LogMessage("Position: %i -> %i", hPack.ReadCell());
LogMessage("Position: %i -> %.2f", hPack.ReadFloat());
char szBuffer[256];
hPack.ReadString(szBuffer, sizeof(szBuffer));
LogMessage("Position: %i -> %s", szBuffer);
/*
Удалять hDataPack в данном случае не нужно,
потому что таймеру был передан флаг TIMER_DATA_HNDL_CLOSE и по завершению выполнения
hDataPack автоматически будет удален.
*/
return Plugin_Stop;
}
Её исходный код:
PHP:
/**
* Creates a timer associated with a new datapack, and returns the datapack.
* @note The datapack is automatically freed when the timer ends.
* @note The position of the datapack is not reset or changed for the timer function.
*
* @param interval Interval from the current game time to execute the given function.
* @param func Function to execute once the given interval has elapsed.
* @param datapack The newly created datapack is passed though this by-reference
* parameter to the timer callback function.
* @param flags Timer flags.
* @return Handle to the timer object. You do not need to call CloseHandle().
*/
stock Handle CreateDataTimer(float interval, Timer func, Handle &datapack, int flags=0)
{
datapack = new DataPack();
flags |= TIMER_DATA_HNDL_CLOSE;
return CreateTimer(interval, func, datapack, flags);
}
PHP:
public void OnMapStart()
{
DataPack hPack;
CreateDataTimer(5.0, Timer_ReadDataPack, hPack, TIMER_FLAG_NO_MAPCHANGE);
hPack.WriteCell(5);
hPack.WriteFloat(7.5);
hPack.WriteString("string");
}
public Action Timer_ReadDataPack(Handle hTimer, Handle hDataPack)
{
DataPack hPack = view_as<DataPack>(hDataPack); // Преобразуем Handle в DataPack
hPack.Reset();
LogMessage("Position: %i -> %i", hPack.ReadCell());
LogMessage("Position: %i -> %.2f", hPack.ReadFloat());
char szBuffer[256];
hPack.ReadString(szBuffer, sizeof(szBuffer));
LogMessage("Position: %i -> %s", szBuffer);
/*
Удалять hDataPack в данном случае не нужно,
потому что таймеру был передан флаг TIMER_DATA_HNDL_CLOSE и по завершению выполнения
hDataPack автоматически будет удален.
*/
return Plugin_Stop;
}
PHP:
/*
При написании игроком команды выводим ему сообщение в чат, и повторно команду он сможет написать только через 30 сек в этом же раунде.
Конечно это можно сделать куда оптимальнее и без таймеров но это просто как пример.
*/
#define DELAY 30.0 // Вынесем задержку в макрос для более удобно корректировки
Handle g_hTimer[MAXPLAYERS+1];
public void OnPluginStart()
{
RegConsoleCmd("sm_timer", Timer_CMD);
HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy);
}
public void Event_RoundStart(Event hEvent, const char[] sEvName, bool bDontBroadcast) // Начался новый раунд
{
for(int i = 1; i <= MaxClients; ++i) // Цикл по всем игрокам
{
if(g_hTimer[i]) // Проверяем что таймер активен
{
KillTimer(g_hTimer[i]); // Уничтожаем таймер
g_hTimer[i] = null; // Обнуляем значения дескриптора
}
}
}
public Action Timer_CMD(int iClient, int iArgs) // Игрок написал команду
{
if(iClient)
{
if(g_hTimer[i]) // Если таймер активен
{
PrintToChat(iClient, "Команда еще недоступна!");
return Plugin_Handled;
}
// Выводим игроку сообщение
PrintToChat(iClient, "Вы ввели команду и сможете её повторно использовать через %i сек.", DELAY);
g_hTimer[iClient] = CreateTimer(DELAY, Timer_Delay, iClient); // Можем передать сразу индекс т.к. если игрок выйдет мы сразу уничтожим его таймер
}
return Plugin_Handled;
}
public void OnClientDisconnect(int iClient) // Игрок отключился
{
if(g_hTimer[iClient]) // Проверяем что таймер активен и уничтожаем
{
KillTimer(g_hTimer[iClient]); // Уничтожаем таймер
g_hTimer[iClient] = null; // Обнуляем значения дескриптора
}
}
public Action Timer_Delay(Handle hTimer, any iClient) // Каллбек нашего таймера
{
g_hTimer[iClient] = null; // Обнуляем значения дескриптора
return Plugin_Stop;
}
<= К содержанию
Последнее редактирование: