Перейти к содержимому


Фотография

CreateTimer() / TIMER_FLAG_NO_MAPCHANGE не убивает таймер

CreateTimer баг sm 1.10

  • Авторизуйтесь для ответа в теме
Сообщений в теме: 28

#1 Goldfish

Goldfish

    Пользователь

  • Пользователь
  • PipPipPip
  • 388 сообщений

Отправлено 26 Март 2020 - 10:45

Всем привет, столкнулся с такой проблемой, флаг TIMER_FLAG_NO_MAPCHANGE не убивает таймер при сливе раунда, повторюсь, именно при сливе, при смене все норм.

Обращусь даже с просьбой, объясните мне тупому что я делаю не так.

Проблему пытался выяснить в течении 2ух дней, я уже и сервер переустановил, и последнюю SM 1.10 поставил - бестолку.

Приведу простой пример

#include <sourcemod>
#pragma semicolon 1
#pragma newdecls required

public void OnPluginStart() {
	HookEvent("round_start", Event_RoundStart);
}

public Action Event_RoundStart(Event event, const char[] name, bool dontBroadcast) {
	CreateTimer(10.0, TimerPost, _, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT);
}

public Action TimerPost(Handle timer) {
	PrintToChatAll("TEST TEXT");
}

в итоге таймер запуститься и начнет через каждые 10 секунд показывать текст, если пройти раунд, то таймер удалится и в начале раунда опять появится, но если раунд будет слит, то появятся  уже 2 одновременно работающих таймера, после 4х сливов - 4 соотвественно (это видно по частоте его появления в чате), сами можете проверить.

я даже скажу больше, даже одиночный таймер (без флага TIMER_REPEAT) остается работать.

Не знаю баг ли это SM или у меня что-то но я уже просто в прямом смысле отчаялся))

Скрытый текст

 

вот даже доказательство  https://vk.com/video...85815_456239437 как себя ведет таймер, который должен появляться через каждые 10 секунд)

 

Конечно можно сделать небольшой говнокод костыль, типо того
 

public Action TimerPost(Handle timer)
{
    PrintToChatAll("TEST TEXT 2");
    CreateTimer(10.0, TimerPost, _, TIMER_FLAG_NO_MAPCHANGE);
}

но все же что не так с этим TIMER_FLAG_NO_MAPCHANGE ?


как заставить таймер с флагом TIMER_REPEAT уничтожить себя при сливе раунда?


Сообщение отредактировал Goldfish: 26 Март 2020 - 10:49

  • RyanAnderson это нравится

#2 BloodyBlade

BloodyBlade

    Постоянный пользователь

  • Пользователь
  • PipPipPipPipPip
  • 1 097 сообщений

Отправлено 26 Март 2020 - 14:47

Всем привет, столкнулся с такой проблемой, флаг TIMER_FLAG_NO_MAPCHANGE не убивает таймер при сливе раунда, повторюсь, именно при сливе, при смене все норм.

Обращусь даже с просьбой, объясните мне тупому что я делаю не так.

Проблему пытался выяснить в течении 2ух дней, я уже и сервер переустановил, и последнюю SM 1.10 поставил - бестолку.

Приведу простой пример

#include <sourcemod>
#pragma semicolon 1
#pragma newdecls required

public void OnPluginStart() {
	HookEvent("round_start", Event_RoundStart);
}

public Action Event_RoundStart(Event event, const char[] name, bool dontBroadcast) {
	CreateTimer(10.0, TimerPost, _, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT);
}

public Action TimerPost(Handle timer) {
	PrintToChatAll("TEST TEXT");
}

в итоге таймер запуститься и начнет через каждые 10 секунд показывать текст, если пройти раунд, то таймер удалится и в начале раунда опять появится, но если раунд будет слит, то появятся  уже 2 одновременно работающих таймера, после 4х сливов - 4 соотвественно (это видно по частоте его появления в чате), сами можете проверить.

я даже скажу больше, даже одиночный таймер (без флага TIMER_REPEAT) остается работать.

Не знаю баг ли это SM или у меня что-то но я уже просто в прямом смысле отчаялся))

Скрытый текст

 

вот даже доказательство  https://vk.com/video...85815_456239437 как себя ведет таймер, который должен появляться через каждые 10 секунд)

 

Конечно можно сделать небольшой говнокод костыль, типо того
 

public Action TimerPost(Handle timer)
{
    PrintToChatAll("TEST TEXT 2");
    CreateTimer(10.0, TimerPost, _, TIMER_FLAG_NO_MAPCHANGE);
}

но все же что не так с этим TIMER_FLAG_NO_MAPCHANGE ?


как заставить таймер с флагом TIMER_REPEAT уничтожить себя при сливе раунда?

Событие mission_lost - Выжившие проиграли/умерли.

Скрытый текст

Сообщение отредактировал BloodyBlade: 26 Март 2020 - 15:10


#3 adacer

adacer

    Новичок

  • Пользователь
  • Pip
  • 44 сообщений

Отправлено 26 Март 2020 - 21:36

round_start стреляет сразу после старта карты, поэтому очевидно старый убивается и сразу появляется новый, тут ты затупил с ивентом.



#4 8rutu5

8rutu5

    Пользователь

  • Пользователь
  • PipPipPip
  • 397 сообщений

Отправлено 26 Март 2020 - 23:35

При проигрыше карта не меняется ни в версусе ни в коопе. Поэтому там выше правильно ивенты скинули.



#5 Goldfish

Goldfish

    Пользователь

  • Пользователь
  • PipPipPip
  • 388 сообщений

Отправлено 27 Март 2020 - 1:29

При проигрыше карта не меняется ни в версусе ни в коопе. Поэтому там выше правильно ивенты скинули.

так плагин тоже чтоли не перезагружается при соливе? Как например при начале новой карты? Поидеи если карта начинается сначала и пусть даже та же, то плагин должен перезагружаться заново, и все переменные в нем обнуляться разве нет?\

 

 

короче решил проблему поставив в таймере  проверку через глобалку, что раунд слит, очень стремный конечно получился говнокод, в целом это выглядит у меня теперь примерно так:

public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) {
	gNoStopTimer == true;
	hUpdateDirectorTimer = CreateTimer(5.0, UpdateDirectorTimer, 0, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
	hTimer_directorNoBossControl = CreateTimer(2.0, Timer_directorNoBossControl, 0, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);	
} 

public Action Event_MapEnd(Event event, const char[] name, bool dontBroadcast) {
	if (gNoStopTimer == true) sLogClose();
	gNoStopTimer = false;
	if (hUpdateDirectorTimer != INVALID_HANDLE) TriggerTimer(hUpdateDirectorTimer);
	if (hTimer_directorNoBossControl != INVALID_HANDLE) TriggerTimer(hTimer_directorNoBossControl);
}

public Action UpdateDirectorTimer(Handle timer) {
	if (gNoStopTimer == false) {
		hUpdateDirectorTimer = INVALID_HANDLE;
		return Plugin_Stop;
	}
	if (gInfectedSpawnCheck == true) UpdateLimits();
}



при этом стоит учитывать, что чем больше интервал таймера, тем позже он вызовится и вот тут то я встретился с проблемой, когда таймер при сливе еще не успел вызваться и не успел проверит что руанд слит и уже начался новый и в итоге он продолжал рабоать, пришлось вручную эмулировать его вызов (через TriggerTimer) при  провале раунда, тогда же он успевает дойти до return Plugin_Stop; и завершит свой цикл


И думаю это многих касается, кто пишет плагины с таймерами,  про этот косяк ни где не написано и следовательно это за зря потраченое время на дебаг нервы и непонимания. Так что, те кто делает таймеры больше , скажем, 5 секунд имейте введу, флага TIMER_FLAG_NO_MAPCHANGE не достаточно, после слива таймер продолжит работу и что там он уже выполнит и какой код страшно представить..

 

п.с. сорян если что за ошибки, написал по быстрому


Сообщение отредактировал Goldfish: 27 Март 2020 - 1:32


#6 BloodyBlade

BloodyBlade

    Постоянный пользователь

  • Пользователь
  • PipPipPipPipPip
  • 1 097 сообщений

Отправлено 27 Март 2020 - 14:11

И думаю это многих касается, кто пишет плагины с таймерами,  про этот косяк ни где не написано и следовательно это за зря потраченое время на дебаг нервы и непонимания. Так что, те кто делает таймеры больше , скажем, 5 секунд имейте введу, флага TIMER_FLAG_NO_MAPCHANGE не достаточно, после слива таймер продолжит работу и что там он уже выполнит и какой код страшно представить..

Тебе уже объяснили выше, что TIMER_FLAG_NO_MAPCHANGE срабатывает только при смене карты. При проигрыше срабатывает событие mission_lost

К тому же, я тебе выше уже было скинул код, который при проигрыше миссии останавливает таймер.


Сообщение отредактировал BloodyBlade: 27 Март 2020 - 14:15


#7 Goldfish

Goldfish

    Пользователь

  • Пользователь
  • PipPipPip
  • 388 сообщений

Отправлено 27 Март 2020 - 18:52

Тебе уже объяснили выше, что TIMER_FLAG_NO_MAPCHANGE срабатывает только при смене карты. При проигрыше срабатывает событие mission_lost

К тому же, я тебе выше уже было скинул код, который при проигрыше миссии останавливает таймер.

не остановил, к сожалению, останавливает если плагин стоп находиться внутри таймера



#8 BloodyBlade

BloodyBlade

    Постоянный пользователь

  • Пользователь
  • PipPipPipPipPip
  • 1 097 сообщений

Отправлено 27 Март 2020 - 19:01

не остановил, к сожалению, останавливает если плагин стоп находиться внутри таймера

Если внутри таймера, то он при первом срабатывании таймера его остановит.



#9 dragokas

dragokas

    Постоянный пользователь

  • Пользователь
  • PipPipPipPipPip
  • 792 сообщений

Отправлено 27 Март 2020 - 19:51

Goldfish, правильно составленным таймером в твоём случае будет такой вариант:

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>

Handle g_hTimer;

public void OnPluginStart()
{
	HookEvent("round_start", 	Event_RoundStart,		EventHookMode_PostNoCopy);
	HookEvent("round_end", 		Event_RoundEnd, 		EventHookMode_PostNoCopy);
}

public void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast)
{
	delete g_hTimer;
}

public void OnMapEnd()
{
	delete g_hTimer;
}

public Action Event_RoundStart(Event event, const char[] name, bool dontBroadcast)
{
	delete g_hTimer;
	g_hTimer = CreateTimer(10.0, TimerPost, _, TIMER_REPEAT);
}

public Action TimerPost(Handle timer)
{
	PrintToChatAll("TEST TEXT");
	return Plugin_Continue;
}

Чтобы раз и навсегда закрыть вопросы, связанные с ошибками при создании и уничтожении таймеров,

я написал такой мануал с примерами: https://forums.allie...63&postcount=34


  • Game Over - L4D2 - CS:GO и Goldfish это нравится

#10 Goldfish

Goldfish

    Пользователь

  • Пользователь
  • PipPipPip
  • 388 сообщений

Отправлено 05 Апрель 2020 - 1:13

Goldfish, правильно составленным таймером в твоём случае будет такой вариант:

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>

Handle g_hTimer;

public void OnPluginStart()
{
	HookEvent("round_start", 	Event_RoundStart,		EventHookMode_PostNoCopy);
	HookEvent("round_end", 		Event_RoundEnd, 		EventHookMode_PostNoCopy);
}

public void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast)
{
	delete g_hTimer;
}

public void OnMapEnd()
{
	delete g_hTimer;
}

public Action Event_RoundStart(Event event, const char[] name, bool dontBroadcast)
{
	delete g_hTimer;
	g_hTimer = CreateTimer(10.0, TimerPost, _, TIMER_REPEAT);
}

public Action TimerPost(Handle timer)
{
	PrintToChatAll("TEST TEXT");
	return Plugin_Continue;
}

Чтобы раз и навсегда закрыть вопросы, связанные с ошибками при создании и уничтожении таймеров,

я написал такой мануал с примерами: https://forums.allie...63&postcount=34

Спасибо!

 

Одна проблема, почему-то иногда ошибки в логах и ругается как раз на сам процесс удаления таймера "delete <хендл таймера>" , как такое возможно? На сколько я понял из вашего поста на АМ delete не должен ловить ошибку на invalid handle , но судя по логам он пытался удалить реальный хендл содержащий указатель одно из таймера (или что там в этом хендле обычно храниться хз), но факт есть фактом, пытался перед оператором delete проверить хендлс помощью IsValidHandle , но компиль говорит, что эта функция уже устаревшая, что посоветуете?


Сообщение отредактировал Goldfish: 05 Апрель 2020 - 1:14


#11 dragokas

dragokas

    Постоянный пользователь

  • Пользователь
  • PipPipPipPipPip
  • 792 сообщений

Отправлено 05 Апрель 2020 - 1:20

Скиньте полный код или в ЛС. И заодно сообщение об ошибке.

 

P.S. Тот код на AM, я специально проганял пару дней на живом сервере, ошибок не было.


Сообщение отредактировал dragokas: 05 Апрель 2020 - 1:22


#12 Goldfish

Goldfish

    Пользователь

  • Пользователь
  • PipPipPip
  • 388 сообщений

Отправлено 05 Апрель 2020 - 1:50

вот

#include <sourcemod>
#include <sdktools>

#pragma newdecls required


Handle g_iTimer[31];
int gTimerCount;

public void OnPluginStart()
{

	HookEvent("round_start", Event_Round_Start);
	HookEvent("round_end", Event_MapEnd,EventHookMode_PostNoCopy);
}

void killTimers() {
	for ( int i = 1; i < 30; i++ ) {
		delete g_iTimer[i];
	}
}

public Action Event_MapEnd(Event event, const char [] name, bool dontBroadcast){
	killTimers();
}

public void OnMapEnd() {
	killTimers();
}


public Action Event_Round_Start(Event event, const char [] name, bool dontBroadcast) {
	gTimerCount++;
	g_iTimer[gTimerCount] = CreateTimer(5.0, Timer_panic65, _);
}

public Action Timer_panic65(Handle timer) {
	gTimerCount++;
	g_iTimer[gTimerCount] = CreateTimer(5.0, Timer_panic30, _);
}

public Action Timer_panic30(Handle timer) {
	gTimerCount++;
	g_iTimer[gTimerCount] = CreateTimer(5.0, Timer_panic10, _);
}

public Action Timer_panic10(Handle timer) {
	gTimerCount++;
	g_iTimer[gTimerCount] = CreateTimer(5.0, Timer_panic0, _);
}

public Action Timer_panic0(Handle timer) {

}


smx (1.09)  https://download.ru/files/473KCAwE

 

 

L 04/05/2020 - 01:34:16: [SM] Exception reported: Handle a74f0f8b is invalid (error 1)
L 04/05/2020 - 01:34:16: [SM] Blaming: test.smx
L 04/05/2020 - 01:34:16: [SM] Call stack trace:
L 04/05/2020 - 01:34:16: [SM]   [0] CloseHandle
L 04/05/2020 - 01:34:16: [SM]   [1] Line 20, C:\Users\Win Gold\Desktop\ L4D2\! compiler\addons\sourcemod\scripting\test.sp::killTimers
L 04/05/2020 - 01:34:16: [SM]   [2] Line 29, C:\Users\Win Gold\Desktop\ L4D2\! compiler\addons\sourcemod\scripting\test.sp::OnMapEnd
L 04/05/2020 - 01:34:16: Error log file session closed.

 

ошибка кажется возникает при ручном смене карты, но это не точно


извиняюсь заранее за говнокод, в торопях  весь код пишу хд

 

это если что пример, на самом деле таймер у меня не одичный, а для каждого юзера создается и таким способом я позже прохожусь по массиву таймеров и удаляю их


кстати оператор delete случаем не перекомпилируется в CloseHandle()? Ведь у него  как раз нет проверки от инвалид хендл и он по видимому может привести к сбою


у меня тут прям бЯда, без проверки на инвалид хендл по вашему методу во всех плагинах сбои ))

 

 

L 04/05/2020 - 01:46:27: Info (map "c5m4_quarter") (file "errors_20200405.log")
L 04/05/2020 - 01:46:27: [SM] Exception reported: Handle d1780f93 is invalid (error 1)
L 04/05/2020 - 01:46:27: [SM] Blaming: panicDoor.smx
L 04/05/2020 - 01:46:27: [SM] Call stack trace:
L 04/05/2020 - 01:46:27: [SM]   [0] CloseHandle
L 04/05/2020 - 01:46:27: [SM]   [1] Line 48, C:\Users\Win Gold\Desktop\ L4D2\! compiler\addons\sourcemod\scripting\panicDoor.sp::killTimers
L 04/05/2020 - 01:46:27: [SM]   [2] Line 57, C:\Users\Win Gold\Desktop\ L4D2\! compiler\addons\sourcemod\scripting\panicDoor.sp::OnMapEnd
L 04/05/2020 - 01:46:27: [SM] Exception reported: Handle a74f0f8b is invalid (error 1)
L 04/05/2020 - 01:46:27: [SM] Blaming: test.smx
L 04/05/2020 - 01:46:27: [SM] Call stack trace:
L 04/05/2020 - 01:46:27: [SM]   [0] CloseHandle
L 04/05/2020 - 01:46:27: [SM]   [1] Line 20, C:\Users\Win Gold\Desktop\ L4D2\! compiler\addons\sourcemod\scripting\test.sp::killTimers
L 04/05/2020 - 01:46:27: [SM]   [2] Line 29, C:\Users\Win Gold\Desktop\ L4D2\! compiler\addons\sourcemod\scripting\test.sp::OnMapEnd
L 04/05/2020 - 01:46:28: Error log file session closed.


Сообщение отредактировал Goldfish: 05 Апрель 2020 - 1:41


#13 dragokas

dragokas

    Постоянный пользователь

  • Пользователь
  • PipPipPipPipPip
  • 792 сообщений

Отправлено 05 Апрель 2020 - 2:00

Когда одиночный таймер отрабатывает, т.е. завершается выполнение его колбека, то хендл становится невалидным - т.е. он закрывается автоматически.

Прежде чем это произойдёт, нужно присвоить null вашей глобальной переменной, чтобы delete не пыталась закрыть этот хендл еще раз.

 

Чтобы в вашем коде найти нужную переменную в колбеке, можно написать такую вспомогательную функцию:

void NullifyHandle(Handle timer)
{
	for( int i = 0; i <= gTimerCount; i++ )
	{
		if( timer == g_iTimer[i])
		{
			g_iTimer[i] = null;
			break;
		}
	}
}

Далее в конце каждого колбека таймера пропишите, например:

public Action Timer_panic0(Handle timer) {
	NullifyHandle(timer);
}

Вот здесь в killTimers, подозреваю, закрываются не все хендлы, поменяйте < 30 на <= gTimerCount

Ну и в том же месте обнулить переменную gTimerCount не плохо было бы.

 

По сути, из мануала на AM, был пропущен этот совет:

public Action Timer_Sample(Handle timer) 
{ 
    //do something 
    PrintToChatAll("tick"); 

    // do not forget to zero timer's handle here, because after callback finishes, timer's handle become invalid 
    g_iTimer = null; 
}  

И еще, претензия чисто по визуальной части и компактности. Так выглядит лучше:

public Action Event_Round_Start(Event event, const char [] name, bool dontBroadcast)
{
	g_iTimer[gTimerCount++] = CreateTimer(5.0, Timer_panic65);
	g_iTimer[gTimerCount++] = CreateTimer(10.0, Timer_panic30);
	g_iTimer[gTimerCount++] = CreateTimer(15.0, Timer_panic10);
	g_iTimer[gTimerCount++] = CreateTimer(20.0, Timer_panic0);
}

Хотя всё сильно зависит, от реальной задачи, конечно.


Сообщение отредактировал dragokas: 05 Апрель 2020 - 2:01

  • Goldfish это нравится

#14 Goldfish

Goldfish

    Пользователь

  • Пользователь
  • PipPipPip
  • 388 сообщений

Отправлено 05 Апрель 2020 - 2:02

Когда одиночный таймер отрабатывает, т.е. завершается выполнение его колбека, то хендл становится невалидным - т.е. он закрывается автоматически.

Прежде чем это произойдёт, нужно присвоить null вашей глобальной переменной, чтобы delete не пыталась закрыть этот хендл еще раз.

 

Чтобы в вашем коде найти нужную переменную в колбеке, можно написать такую вспомогательную функцию:

void NullifyHandle(Handle timer)
{
	for( int i = 0; i <= gTimerCount; i++ )
	{
		if( timer == g_iTimer[i])
		{
			g_iTimer[i] = null;
			break;
		}
	}
}

Далее в конце каждого колбека таймера пропишите, например:

public Action Timer_panic0(Handle timer) {
	NullifyHandle(timer);
}

Вот здесь в killTimers, подозреваю, закрываются не все хендлы, поменяйте < 30 на <= gTimerCount

Ну и в том же месте обнулить переменную gTimerCount не плохо было бы.

 

По сути, из мануала на AM, был пропущен этот совет:

public Action Timer_Sample(Handle timer) 
{ 
    //do something 
    PrintToChatAll("tick"); 

    // do not forget to zero timer's handle here, because after callback finishes, timer's handle become invalid 
    g_iTimer = null; 
}  

И еще, претензия чисто по визуальной части и компактности. Так выглядит лучше:

public Action Event_Round_Start(Event event, const char [] name, bool dontBroadcast)
{
	g_iTimer[gTimerCount++] = CreateTimer(5.0, Timer_panic65);
	g_iTimer[gTimerCount++] = CreateTimer(10.0, Timer_panic30);
	g_iTimer[gTimerCount++] = CreateTimer(15.0, Timer_panic10);
	g_iTimer[gTimerCount++] = CreateTimer(20.0, Timer_panic0);
}

Хотя всё сильно зависит, от реальной задачи, конечно.

 

так стопе, а если к примеру я сделал таймер на 60, а через 5 секунд у меня меняется карта, как тогда мне эти таймеры преждевременно завершить если их хендлы не успеют обнулиться? И для чего тогда delete если все хендлы будут равны нулю?

 

п.с. спс за советы


Сообщение отредактировал Goldfish: 05 Апрель 2020 - 2:07


#15 dragokas

dragokas

    Постоянный пользователь

  • Пользователь
  • PipPipPipPipPip
  • 792 сообщений

Отправлено 05 Апрель 2020 - 2:03

У вас они завершаются через форвард OnMapEnd



#16 Goldfish

Goldfish

    Пользователь

  • Пользователь
  • PipPipPip
  • 388 сообщений

Отправлено 05 Апрель 2020 - 2:11

У вас они завершаются через форвард OnMapEnd

но ведь там срабатывает тот же цикл с удалением хендлов

void killTimers() {
    for ( int i = 1; i < 30; i++ ) {
        delete g_iTimer[i];
    }
}

и он выходит опять же  будет удалять не закрытые  и не обнуленные хендлы, ведь некоторые таймеры еще не успели отработать и обнулиться
 


Сообщение отредактировал Goldfish: 05 Апрель 2020 - 2:12


#17 dragokas

dragokas

    Постоянный пользователь

  • Пользователь
  • PipPipPipPipPip
  • 792 сообщений

Отправлено 05 Апрель 2020 - 2:12

но ведь там срабатывает тот же цикл с удалением хендлов

void killTimers() {
    for ( int i = 1; i < 30; i++ ) {
        delete g_iTimer[i];
    }
}

и он выходит опять же  будет удалять не закрытые  и не обнуленные хендлы, ведь некоторые таймеры еще не успели отработать и обнулиться
 

 

Всё так и будет. Что вас смущает?



#18 Goldfish

Goldfish

    Пользователь

  • Пользователь
  • PipPipPip
  • 388 сообщений

Отправлено 05 Апрель 2020 - 2:14

Всё так и будет. Что вас смущает?

так, кажется понял своей тугодумностью, сейчас попробую, извините за дотошность)



#19 dragokas

dragokas

    Постоянный пользователь

  • Пользователь
  • PipPipPipPipPip
  • 792 сообщений

Отправлено 05 Апрель 2020 - 2:17

Если не совсем понятно, то delete - кроме закрытия хендла ещё и обнуляет переменную.

 

Ещё момент, 

 

если у вас в реальном коде аргумент таймера вообще никак не используется, то вы можете передать туда номер счётчика, чтобы избавиться от необходимости крутить цикл NullifyHandle

Пример:

public Action Event_Round_Start(Event event, const char [] name, bool dontBroadcast)
{
	g_iTimer[++gTimerCount] = CreateTimer(5.0, Timer_panic65, gTimerCount);
}

public Action Timer_panic65(Handle timer, int Counter)
{
	g_iTimer[Counter] = null;
}

Только обратите внимание, что в этом случае ++ нужно ставить перед переменной, а не после.



#20 Goldfish

Goldfish

    Пользователь

  • Пользователь
  • PipPipPip
  • 388 сообщений

Отправлено 05 Апрель 2020 - 2:48

Если не совсем понятно, то delete - кроме закрытия хендла ещё и обнуляет переменную.

 

Ещё момент, 

 

если у вас в реальном коде аргумент таймера вообще никак не используется, то вы можете передать туда номер счётчика, чтобы избавиться от необходимости крутить цикл NullifyHandle

Пример:

public Action Event_Round_Start(Event event, const char [] name, bool dontBroadcast)
{
	g_iTimer[++gTimerCount] = CreateTimer(5.0, Timer_panic65, gTimerCount);
}

public Action Timer_panic65(Handle timer, int Counter)
{
	g_iTimer[Counter] = null;
}

Только обратите внимание, что в этом случае ++ нужно ставить перед переменной, а не после.

понятно, но в реальности он  у меня используется =)





Темы с аналогичным тегами CreateTimer, баг, sm 1.10

Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных