[SourcePawn] Урок 6 - Таймеры

DENFER

Пишу плагины за два биг тести и картошку фри..
Сообщения
260
Реакции
289
В OnTakeDamage при попадании создаю таймер
C-подобный:
hTimer[iVictim] = CreateTimer(0.05, TimerM, iVictim, TIMER_REPEAT);
Но дело в том, что мне бы хотелось добавить красоты, всяких эффектов и звуков по окончанию работы функции TimerM, что в таймере, а туда я могу передать данные только жертвы, а хотелось бы и атакера (необходимо передать данные обоих), но как это можно реализовать?
Используй датапак и даже есть соответствующий урок по ним 🙃
 

rejchev

менеджер клоунов
Сообщения
1,669
Реакции
1,291
В OnTakeDamage при попадании создаю таймер
C-подобный:
hTimer[iVictim] = CreateTimer(0.05, TimerM, iVictim, TIMER_REPEAT);
К тому же, повторяющийся, что может спровоцировать утечку при следующем попадании.
Если к этому добавить создание датапака, то и до лимита будет недалеко...

Глупость с таймером заменяется одним sdk хуком и очередью(1 дескриптор - динамический массив, где в четных позициях лежит время исполнения, а в нечетных - необходимые данные)
Нужны повторения? Пожалуйста. Просто перезаписываете время исполнения.

Как пример:
C-подобный:
#pragma newdecls required

#include <sdktools>
#include <sdkhooks>

ArrayList queue;

public void OnPluginStart() {
    queue = new ArrayList(64, 0);
}

public void OnMapStart() {
    queue.Clear();

    SDKHook(GetPlayerResourceEntity(), SDKHook_ThinkPost, OnThinkPost);
}

public void OnThinkPost(int ent) {
    if(ent == -1) {
        SDKUnhook(ent, SDKHook_ThinkPost, OnThinkPost);
        return;
    }

    static int currentTick;
    currentTick = GetGameTickCount();

    if(queue.Length)
        causeEffects(currentTick);
}

void causeEffects(int currentTick) {
    static DataPack dp;

    static bool isRepeat;
    for(int i, tick; i < queue.Length; i+=2) {
        tick = queue.Get(i);
        isRepeat = false;

        if(currentTick > tick)
            continue;
        
        if((dp = view_as<DataPack>(queue.Get(i+1))) != null) {
            // Вызов функции, которая повесит эффект...
            // Отработав, функция возвращает необходимость в повторе.
            // isRepeat = causeEffect(dp);
        }

        // Повтора не требуется, удаляем из очереди
        if(!isRepeat) {
            queue.Erase(i);
            queue.Erase(i);

            delete dp;
            continue;
        }

        // Обновляем время повторения
        queue.Set(i, currentTick + convertTimeToTick(1.00));
    }
}

public void OnClientPutInServer(int iClient) {
    SDKHook(iClient, SDKHook_OnTakeDamage, OnTakeDamage);
}

public void OnClientDisconnect(int iClient) {
    SDKUnhook(iClient, SDKHook_OnTakeDamage, OnTakeDamage);
}

public Action OnTakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) {
    if(attacker != victim) {
        DataPack dp = new DataPack();
        dp.WriteCell(GetClientUserId(attacker));
        dp.WriteCell(GetClientUserId(victim));
        // ....

        queue.Push(GetGameTickCount() + convertTimeToTick(0.05));
        queue.Push(dp);
    }
}

stock int convertTimeToTick(float fTime) {
    return RoundFloat(fTime/GetTickInterval());
}
 

Nekro

Терра инкогнита
Сообщения
4,026
Реакции
2,260
К тому же, повторяющийся, что может спровоцировать утечку при следующем попадании.
Если к этому добавить создание датапака, то и до лимита будет недалеко...

Глупость с таймером заменяется одним sdk хуком и очередью(1 дескриптор - динамический массив, где в четных позициях лежит время исполнения, а в нечетных - необходимые данные)
Нужны повторения? Пожалуйста. Просто перезаписываете время исполнения.

Как пример:
C-подобный:
#pragma newdecls required

#include <sdktools>
#include <sdkhooks>

ArrayList queue;

public void OnPluginStart() {
    queue = new ArrayList(64, 0);
}

public void OnMapStart() {
    queue.Clear();

    SDKHook(GetPlayerResourceEntity(), SDKHook_ThinkPost, OnThinkPost);
}

public void OnThinkPost(int ent) {
    if(ent == -1) {
        SDKUnhook(ent, SDKHook_ThinkPost, OnThinkPost);
        return;
    }

    static int currentTick;
    currentTick = GetGameTickCount();

    if(queue.Length)
        causeEffects(currentTick);
}

void causeEffects(int currentTick) {
    static DataPack dp;

    static bool isRepeat;
    for(int i, tick; i < queue.Length; i+=2) {
        tick = queue.Get(i);
        isRepeat = false;

        if(currentTick > tick)
            continue;
       
        if((dp = view_as<DataPack>(queue.Get(i+1))) != null) {
            // Вызов функции, которая повесит эффект...
            // Отработав, функция возвращает необходимость в повторе.
            // isRepeat = causeEffect(dp);
        }

        // Повтора не требуется, удаляем из очереди
        if(!isRepeat) {
            queue.Erase(i);
            queue.Erase(i);

            delete dp;
            continue;
        }

        // Обновляем время повторения
        queue.Set(i, currentTick + convertTimeToTick(1.00));
    }
}

public void OnClientPutInServer(int iClient) {
    SDKHook(iClient, SDKHook_OnTakeDamage, OnTakeDamage);
}

public void OnClientDisconnect(int iClient) {
    SDKUnhook(iClient, SDKHook_OnTakeDamage, OnTakeDamage);
}

public Action OnTakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) {
    if(attacker != victim) {
        DataPack dp = new DataPack();
        dp.WriteCell(GetClientUserId(attacker));
        dp.WriteCell(GetClientUserId(victim));
        // ....

        queue.Push(GetGameTickCount() + convertTimeToTick(0.05));
        queue.Push(dp);
    }
}

stock int convertTimeToTick(float fTime) {
    return RoundFloat(fTime/GetTickInterval());
}
Большое спасибо, постараюсь разобраться. Пока много не понятного, а SDKUnhook вроде идёт автоматически или нет?
 
Сверху Снизу