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


Фотография

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

CreateTimer баг sm 1.10

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

#21 PawnLomaster

PawnLomaster

    Участник

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

Отправлено 08 Май 2020 - 17:19

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

IsValidHandle в новых версия SourceMod упразднили.
Зачем так коварно убивать таймеры делитом?
Можно же просто мониторить состояние переменной таймера

//Это будет работать в версусе, но скорее всего не в коопе
public Action Event_RoundEnd(Event event, const char[] name, bool dontBroadcast)
{
if (g_iTimer != INVALID_HANDLE)
{
    KillTimer(g_iTimer);
    g_iTimer = INVALID_HANDLE;
}
}

public Action Event_RoundStart(Event event, const char [] name, bool dontBroadcast)
{
    if (g_iTimer != INVALID_HANDLE)
    {
        g_iTimer = CreateTimer(5.0, lalala, lalala_param, TIMER_REPEAT);
    }
}

Конструкцию с g_iTimer и INVALID_HANDLE можно юзать для проверок существования таймера в любой момент игры. И убивать таймер в любой момент. 
Если там таймеров куча, например для каждого клиента, то и в массив можно. Разница будет лишь в наличии индекса у переменной таймера.


Сообщение отредактировал PawnLomaster: 08 Май 2020 - 17:25


#22 dragokas

dragokas

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

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

Отправлено 08 Май 2020 - 17:29

delete для таймера идентична коду:

if (g_iTimer != INVALID_HANDLE)
{
    KillTimer(g_iTimer);
    g_iTimer = INVALID_HANDLE;
}


#23 PawnLomaster

PawnLomaster

    Участник

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

Отправлено 08 Май 2020 - 17:33

 

delete для таймера идентична коду:

if (g_iTimer != INVALID_HANDLE)
{
    KillTimer(g_iTimer);
    g_iTimer = INVALID_HANDLE;
}

Бесспорно. Тут кому как нравится. Я всё таки считаю, что так можно внести долю конкретики в действие.
У меня была ситуация, когда у меня были таймеры эффектов, которые меняются каждую секунду (простое убывание времени, сколько осталось до конца эффекта) независимо друг от друга сразу у нескольких клиентов. Тоже спотыкался об флаг убийства таймера в конце карты, но это ломало мне код. Хендл закрывается, а переменная всё ещё куда-то там указывает.
UPD: но точно ли delete сбрасывает переменную до null?


Сообщение отредактировал PawnLomaster: 08 Май 2020 - 17:35


#24 dragokas

dragokas

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

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

Отправлено 08 Май 2020 - 18:24

UPD: но точно ли delete сбрасывает переменную до null?

 

Да.

 

PS. Там я выше ссылочку кидал на свою статейку с примерами, постарался сэмулировать максимальное кол-во всевозможных вариаций таймеров и их убийств.

Раньше тоже часто имел проблемы с этим, но решил один раз серьезно сесть и во всём разобраться.

Разве что с DataPack-ами пока не писал примеры, там свои заморочки бывают.


Сообщение отредактировал dragokas: 08 Май 2020 - 18:25

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

#25 PawnLomaster

PawnLomaster

    Участник

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

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

 

 

Там я выше ссылочку кидал на свою статейку с примерами

Отличная статья. Про возможность убивать таймер и одновременно зануллять его я не был в курсе. Вредная привычка писать в старом стиле. Спасибо.
Кстати, а есть ли способ, получить время, через которое таймер сработает, из его Handle. А то держать на каждый нужный таймер переменную с UNIX-временем начала отсчёта неудобно.
 

 

 

Разве что с DataPack-ами пока не писал примеры, там свои заморочки бывают.

Да особо нет заморочек. Раньше времени не закрывать. При первом чтении сбрасывать указатель в начало. А ещё там Handle как int записывается, а достаётся с приведением типов



#26 dragokas

dragokas

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

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

Отправлено 08 Май 2020 - 20:48

Вообщем, куча всего писал и форум как всегда сожрал 70% поста.

Лень повторять.


Если коротко, то достать из хендла оставшееся время стандартными средствами не представляется возможным, без копания в сторону Dhooks и прочего.

 

Но можно создать свою CreateTimerEx и хранить связь Handle <-> Время срабатывания в StringMap-е.

 

С DataPack много заморочек когда доходит до оптимизации. Просто оставлю ссылку. Там человек дальше предельно ясно объяснил мой код.

Как увидите, не обязательно делать ре-таггинг int к DataPack.


Сообщение отредактировал dragokas: 08 Май 2020 - 20:44

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

#27 PawnLomaster

PawnLomaster

    Участник

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

Отправлено 08 Май 2020 - 21:52

Вообщем, куча всего писал и форум как всегда сожрал 70% поста.
Лень повторять.

Если коротко, то достать из хендла оставшееся время стандартными средствами не представляется возможным, без копания в сторону Dhooks и прочего.
 
Но можно создать свою CreateTimerEx и хранить связь Handle <-> Время срабатывания в StringMap-е.
 
С DataPack много заморочек когда доходит до оптимизации. Просто оставлю ссылку. Там человек дальше предельно ясно объяснил мой код.
Как увидите, не обязательно делать ре-таггинг int к DataPack.

Offtop

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


Сообщение отредактировал PawnLomaster: 08 Май 2020 - 21:58


#28 dragokas

dragokas

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

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

Отправлено 09 Май 2020 - 18:18

Вчера был уставшим. Отвечу по порядку...

 

Как по мне в Вашем примере необязательно было дублировать датапак ... 

 

Датапак как таковой не дублируется. CloneHandle просто увеличивает кол-во ссылок на объект, при этом сам объект не клонируется, а TIMER_DATA_HNDL_CLOSE закрывает хендл, уменьшая кол-во ссылок на объект.  Объект будет уничтожен, когда кол-во ссылок на него станет = 0.

 

 

Раз он всё равно перезаписывается, то можно попробовать сыграть на TIMER_REPEAT, но в теле функции обыграть момент выключения таймера, например, через TriggerTimer(g_timer) и KillTimer(timer) ...

 

TIMER_REPEAT не используется по причине ТЗ - сделать рандомное время срабатывания каждого из циклов таймера.

TIMER_REPEAT с TriggerTimer это конечно интересная идея, но кто будет вызывать этот самый TriggerTimer  в нужное время - еще один отдельный таймер? :)

 

 

И я всё таки сомневаюсь в безопасности использования delete по отношению к handle.

 

 

Если почитать несколько тем на AM, то можно убедиться, что ее сами разработчики рекомендуют вместо KillTimer и CloseHandle. Но, ваше право.

 

Я не смог найти в Вашей теме про ретаггинг.

 

Как раз потому, что там его нет. Вместо этого, можно сейфово изменять тип данных непосредственно в самом прототипе функции:

public Action Timer_SpawnWitch(Handle timer, DataPack hPack)

не прибегая к ре-тагу view_as<DataPack>. Это на самом деле не является приведением типов (как вы выразились), т.к. в случае с view_as значение просто помечается другим тегом, но никаких операций с самим значением не производится.

 

 

У него свой тип данных, но по факту производная от Handle. Просто так ответ от базы не скопировать, ибо не Handle. Поэтому пришлось приводить к Handle, а потом копировать. 

 

Здесь всё тоже самое. Можно объявить прототип с заранее необходимыми типами (главное чтобы их размер совпадал) и дальше view_as не потребуется.

 

Проблемы началась, когда я пытался гонять функции и Handle плагинов в датапаке из Натива. Ну вот вроде всё правильно, а вылетает ошибка о несуществующей ссылке.

 

Потому что у каждого у каждого хендла есть владелец и права доступа.

Чтобы обратиться к хендлу из другого плагина, нужно сменить его владельца, выполнив клонирование (CloneHandle) из вызывающей стороны. См.: https://hlmod.ru/thr...unctions.41366/

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



#29 PawnLomaster

PawnLomaster

    Участник

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

Отправлено 09 Май 2020 - 20:07

Вчера был уставшим. Отвечу по порядку...

 

 

Датапак как таковой не дублируется. CloneHandle просто увеличивает кол-во ссылок на объект, при этом сам объект не клонируется, а TIMER_DATA_HNDL_CLOSE закрывает хендл, уменьшая кол-во ссылок на объект.  Объект будет уничтожен, когда кол-во ссылок на него станет = 0.

 

 

 

TIMER_REPEAT не используется по причине ТЗ - сделать рандомное время срабатывания каждого из циклов таймера.

TIMER_REPEAT с TriggerTimer это конечно интересная идея, но кто будет вызывать этот самый TriggerTimer  в нужное время - еще один отдельный таймер? :)

 

 

 

 

Если почитать несколько тем на AM, то можно убедиться, что ее сами разработчики рекомендуют вместо KillTimer и CloseHandle. Но, ваше право.

 

 

Как раз потому, что там его нет. Вместо этого, можно сейфово изменять тип данных непосредственно в самом прототипе функции:

public Action Timer_SpawnWitch(Handle timer, DataPack hPack)

не прибегая к ре-тагу view_as<DataPack>. Это на самом деле не является приведением типов (как вы выразились), т.к. в случае с view_as значение просто помечается другим тегом, но никаких операций с самим значением не производится.

 

 

 

Здесь всё тоже самое. Можно объявить прототип с заранее необходимыми типами (главное чтобы их размер совпадал) и дальше view_as не потребуется.

 

 

Потому что у каждого у каждого хендла есть владелец и права доступа.

Чтобы обратиться к хендлу из другого плагина, нужно сменить его владельца, выполнив клонирование (CloneHandle) из вызывающей стороны. См.: https://hlmod.ru/thr...unctions.41366/

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

offtop

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





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

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

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