Путает Атакера с Жертвой

Nekro

Терра инкогнита
Сообщения
4,025
Реакции
2,260
Здравствуйте, подсобите ребят.
Плагин выводит оверлей при попадании, но долго не мог найти причину когда ИНОГДА он оставался и не выключался
В итоге сделал тьму проверок и выяснилось, что при смерти жертвы иногда путает индекс атакера с жертвой и по итогу идёт выключение оверлея у жертвы [199] строка
Подскажите как избежать такой проблемы
C-подобный:
#include <sdktools_stringtables>
#include <sdktools_sound>
#include <smartdm>

#define MAX_FILE_LEN3 128

bool
    bPlayerSprite[MAXPLAYERS+1],
    bDebag;

Handle
    hTime,
    hSound,
    hSpriteT,
    hSpriteCT;

float
    fTime;

char
    sSound[MAX_FILE_LEN3],
    sSpriteT[128],
    sSpriteCT[128],
    sBufferCT[128],
    sBufferT[128];

//debag
char
    sTime[256],
    file[PLATFORM_MAX_PATH],
    sFile[PLATFORM_MAX_PATH];

public Plugin myinfo =
{
    name = "Sprite Aim",
    author = "Nek.'a 2x2",
    description = "Отображения значка при попадании по противнику",
    version = "1.2.6"
}

public void OnPluginStart()
{
    ConVar cvar;
    hSpriteT = CreateConVar("sm_spriteaim_t", "iex/hit02.vmt", "Прицел для Т");
    GetConVarString(hSpriteT, sSpriteT, sizeof(sSpriteT));
    HookConVarChange(hSpriteT, OnConVarChanges_SpriteT);
  
    hSpriteCT = CreateConVar("sm_spriteaim_ct", "iex/hit01.vmt", "Прицел для КТ");
    GetConVarString(hSpriteCT, sSpriteCT, sizeof(sSpriteCT));
    HookConVarChange(hSpriteCT, OnConVarChanges_SpriteCT);
  
    hSound = CreateConVar("sm_spriteaim_sound", "weapons/crossbow/hit1.wav", "Путь к звуки который будет проигрывать при пападании");
  
    cvar = CreateConVar("sm_spriteaim_time", "0.3", "Время (в секундах) после которого прицел должеб быть удалён", _, true, 0.01, true, 70.0);
    cvar.AddChangeHook(CVarChanged_Time);
    fTime = cvar.FloatValue;
  
    AutoExecConfig(true, "sprite_aim");
  
    HookEvent("player_hurt", Event_PlayerHurt, EventHookMode_Post);
    HookEvent("player_death", Event_PlayerDeath, EventHookMode_Post);
}

public void CVarChanged_Time(ConVar cvar, const char[] oldVal, const char[] newValue)
{
    fTime = cvar.FloatValue;
}

public void OnConVarChanges_SpriteT(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    if(hSpriteT)
    {
        strcopy(sSpriteT, sizeof(sSpriteT), newValue);
    }
}

public void OnConVarChanges_SpriteCT(ConVar cvar, const char[] oldValue, const char[] newValue)
{
    if(hSpriteCT)
    {
        strcopy(sSpriteCT, sizeof(sSpriteCT), newValue);
    }
}

public void OnMapStart()
{
    Format(sBufferT, sizeof(sBufferT), "materials/%s", sSpriteT);
    if(sBufferT[0]) PrecacheModel(sBufferT, true);
    Downloader_AddFileToDownloadsTable(sBufferT);
  
    Format(sBufferCT, sizeof(sBufferCT), "materials/%s", sSpriteCT);
    if(sBufferCT[0]) PrecacheModel(sBufferCT, true);
    Downloader_AddFileToDownloadsTable(sBufferCT);
  
    GetConVarString(hSound, sSound, MAX_FILE_LEN3);
    char buffer3[MAX_FILE_LEN3];
    PrecacheSound(sSound, true);
    Format(buffer3, sizeof(buffer3), "sound/%s", sSound);
    AddFileToDownloadsTable(buffer3);
  
    char sPath[56];
    BuildPath(Path_SM, sPath, sizeof(sPath), "logs/debag/");
  
    if(!DirExists(sPath))
        CreateDirectory(sPath, 511);
}

public Action Event_PlayerHurt(Handle event, const char[] name, bool dontBroadcast)
{
    FormatTime(sTime, sizeof(sTime), "%Y%m%d");
    BuildPath(Path_SM, file, sizeof(file), "logs/debag/sprite_aim_%s.log", sTime);
  
    bDebag = true;
  
    int iAttacker = GetClientOfUserId(GetEventInt(event, "attacker"));
    int iClient = GetClientOfUserId(GetEventInt(event, "userid"));
    //LogToFileEx(file, "Код работает 1\nАтакер [%N]\nЖертва [%N]", iAttacker, iClient);
    if (iAttacker && iAttacker != iClient && IsClientInGame(iAttacker) && IsPlayerAlive(iAttacker) && !IsFakeClient(iAttacker))    //IsClientObserver(iAttacker)
    {
        char iAttackerName[MAX_NAME_LENGTH];

        GetClientName(iAttacker, iAttackerName, MAX_NAME_LENGTH);
      
        BuildPath(Path_SM, sFile, sizeof(sFile), "logs/debag/sprite_aim_%s.log", iAttackerName);

        char weapon[15];
        int t = GetClientTeam(iAttacker) == 2;
        GetEventString(event, "weapon", weapon, 15);
        //LogToFileEx(file, "Код работает 2\nАтакер [%N]\nЖертва [%N]", iAttacker, iClient);
        if((strcmp(weapon, "hegrenade", false) != 0 && strcmp(weapon, "knife", false) != 0))
        { 
            if(t)
            {
                ClientCommand(iAttacker, "r_screenoverlay \"%s\"", sSpriteT);
                EmitSoundToClient(iAttacker, sSound);
                bPlayerSprite[iAttacker]++;
                if(bDebag)
                {
                    LogToFileEx(sFile, "======= ВКЛЮЧЕНИЕ =======");
                    for(int c = 1; c <= MaxClients; c++) if(c == iAttacker)
                    LogToFileEx(sFile, "Атакер [%N] | Индекс игрока [%d] | Значение индекса [%d]", iAttacker, c, bPlayerSprite[c]);
                    //LogToFileEx(sFile, "[Т] Атакеру [%N] спрайт [%s] активирован", iAttacker, sSpriteT);
                    LogToFileEx(sFile, "[Т] Атакеру [%N] Жертва [%N]", iAttacker, iClient);
                }
            }
            else
            {
                ClientCommand(iAttacker, "r_screenoverlay \"%s\"", sSpriteCT);
                EmitSoundToClient(iAttacker, sSound);
                bPlayerSprite[iAttacker]++;
                if(bDebag)
                {
                    LogToFileEx(sFile, "======= ВКЛЮЧЕНИЕ =======");
                    for(int c = 1; c <= MaxClients; c++) if(c == iAttacker)
                    LogToFileEx(sFile, "Атакер [%N] | Индекс игрока [%d] | Значение индекса [%d]", iAttacker, c, bPlayerSprite[c]);
                    //LogToFileEx(sFile, "[СТ] Атакеру [%N] спрайт [%s] активирован", iAttacker, sSpriteCT);
                    LogToFileEx(sFile, "[СТ] Атакеру [%N] Жертва [%N]", iAttacker, iClient);
                }
            }
          
            if(hTime == INVALID_HANDLE)
            {
                hTime = CreateTimer(fTime, Sprite_Timer, iAttacker);
            }
        }
    }
}

public Action Event_PlayerDeath(Handle event, const char[] name, bool dontBroadcast)
{
    int iVictim = GetClientOfUserId(GetEventInt(event, "userid"));
    int iAttacker = GetClientOfUserId(GetEventInt(event, "attacker"));
  
    FormatTime(sTime, sizeof(sTime), "%Y%m%d");
    BuildPath(Path_SM, file, sizeof(file), "logs/debag/sprite_aim_%s.log", sTime);
  
    for(int c = 1; c <= MaxClients; c++) if(c == iAttacker && bPlayerSprite[c] == true && hTime == INVALID_HANDLE)
    {
        LogToFileEx(file, "У Атакера [%N] | остался срайт", iAttacker, c, bPlayerSprite[c]);
        LogToFileEx(file, "Атакер [%N] | Индекс игрока [%d] | Значение индекса [%d]", iAttacker, c, bPlayerSprite[c]);
        ClientCommand(iAttacker, "r_screenoverlay \"\"");
        bPlayerSprite[iAttacker] = false;
        LogToFileEx(file, "Атакер [%N] | Индекс игрока [%d] | Значение индекса [%d]", iAttacker, c, bPlayerSprite[c]);
    }
    for(int d = 1; d <= MaxClients; d++) if(d == iVictim && bPlayerSprite[d] == true && hTime == INVALID_HANDLE)
    {
        LogToFileEx(file, "У жертвы [%N] | остался срайт", iVictim, d, bPlayerSprite[d]);
        LogToFileEx(file, "Жертва [%N] | Индекс игрока [%d] | Значение индекса [%d]", iVictim, d, bPlayerSprite[d]);
        ClientCommand(iVictim, "r_screenoverlay \"\"");
        bPlayerSprite[iVictim] = false;
        LogToFileEx(file, "Жертва [%N] | Индекс игрока [%d] | Значение индекса [%d]", iVictim, d, bPlayerSprite[d]);
    }
}

public Action Sprite_Timer(Handle timer, any iClient)
{
    if(iClient)    // = GetClientOfUserId(iClient)))
    {
        ClientCommand(iClient, "r_screenoverlay \"\"");
        bPlayerSprite[iClient] = false;
        if(bDebag)
        {
            LogToFileEx(sFile, "======= ОТКЛЮЧЕНИЕ =======");
            for(int c = 1; c <= MaxClients; c++) if(c == iClient)
            LogToFileEx(sFile, "Атакер [%N] | Индекс игрока [%d] | Значение индекса [%d]", iClient, c, bPlayerSprite[c]);
        }
    }
    hTime = INVALID_HANDLE;
    return Plugin_Continue;
}

C-подобный:
L 02/28/2021 - 15:23:25: ======= ВКЛЮЧЕНИЕ =======
L 02/28/2021 - 15:23:25: Атакер [@krivoy] | Индекс игрока [1] | Значение индекса [1]
L 02/28/2021 - 15:23:25: [Т] Атакеру [@krivoy] Жертва [Zver]
L 02/28/2021 - 15:23:26: ======= ОТКЛЮЧЕНИЕ =======
L 02/28/2021 - 15:23:26: Атакер [@krivoy] | Индекс игрока [1] | Значение индекса [0]
L 02/28/2021 - 15:23:45: ======= ВКЛЮЧЕНИЕ =======
L 02/28/2021 - 15:23:45: Атакер [@krivoy] | Индекс игрока [1] | Значение индекса [1]
L 02/28/2021 - 15:23:45: [Т] Атакеру [@krivoy] Жертва [C.T.E.H.A.]
L 02/28/2021 - 15:23:46: ======= ОТКЛЮЧЕНИЕ =======
L 02/28/2021 - 15:23:46: Атакер [@krivoy] | Индекс игрока [1] | Значение индекса [0]
L 02/28/2021 - 15:26:04: ======= ВКЛЮЧЕНИЕ =======
L 02/28/2021 - 15:26:04: Атакер [@krivoy] | Индекс игрока [1] | Значение индекса [1]
L 02/28/2021 - 15:26:04: [Т] Атакеру [@krivoy] Жертва [Nek.'a 2x2]
L 02/28/2021 - 15:26:04: ======= ВКЛЮЧЕНИЕ =======
L 02/28/2021 - 15:26:04: Атакер [@krivoy] | Индекс игрока [1] | Значение индекса [2]
L 02/28/2021 - 15:26:04: [Т] Атакеру [@krivoy] Жертва [Nek.'a 2x2]
L 02/28/2021 - 15:26:04: ======= ОТКЛЮЧЕНИЕ =======
L 02/28/2021 - 15:26:04: Атакер [Nek.'a 2x2] | Индекс игрока [12] | Значение индекса [0]

Как видите в конце он выключает оверлей у жертвы
 

Вложения

  • sprite_aim.sp
    7.5 КБ · Просмотры: 5

Grey83

не пишу плагины с весны 2022
Сообщения
8,521
Реакции
4,980
Посмотрел код. Нефига логики не понял.

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

Для чего делать глобальные строковые переменные sBufferT и sBufferCT, а также локальные buffer3 и sPath?
Т.к. они используются только по разу, то достаточно создать одну локальную с размером PLATFORM_MAX_PATH (т.е. 256 байт). И использовать её одну в OnMapStart().

Дебаг можно делать используя инструкции компилятора
C-подобный:
#define DEBUG 1

#if DEBUG == 1
    -код_для_дебага-
#endif
Тогда при компиляции можно просто менять значение дефайна чтобы скомпилировать версию с дебагом или без.
И да "жук" на англиийском таки "bUg", а не "bAg".

Таймер нужно пересоздавать (м/б даже отсылать оверлей снова, т.к. его мог перебить оверлей созданный другим плагином), потому что у тебя пока таймер работает не будет создаваться оверлей, а время его существования ты ограничил ещё в первую отсылку оверлея. Т.е. ты не продлеваешь время жизни оверлея.

Не пойму для чего делать цикл по игрокам в дебаге и сравнивать равна ли семёрка семёрке (или другое число самому себе). Просто не понимаю сакральный смысл этого действа.

В таймер ты пересылаешь индекс игрока. А если игрок за время заданное для существования оверлея успел выйти?
Передавай UserId в таймер, так ты будешь уверен, что ты работаешь с оверлеем того же игрока, что и при создании таймера.

В таймере ничего не нужно возвращать, если он не имеет флага TIMER_REPEAT или тебе не требуется завершить выполнение кода (тогда возвращай Plugin_Continue для повторяющегося, если хочешь чтобы он снова выполнялся через таймаут и Plugin_Stop для любого, если хочешь остановить таймер).
Сообщения автоматически склеены:

Вообще тебе стоило бы создавать отдельный таймер для каждого из игроков, кому ты отсылаешь оверлей.
В этом твой основной косяк, кмк.
Сообщения автоматически склеены:

И ещё: для чего ты отправляешь оверлей только атакующему, а убиваешь оверлей у атакующего и атакованного?
Сообщения автоматически склеены:

@Nekro, попробуй как будет работать вот этот код.
 

Вложения

  • sprite_aim 1.2.7.sp
    3.9 КБ · Просмотры: 3
Последнее редактирование:

Nekro

Терра инкогнита
Сообщения
4,025
Реакции
2,260
Посмотрел код. Нефига логики не понял.

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

Для чего делать глобальные строковые переменные sBufferT и sBufferCT, а также локальные buffer3 и sPath?
Т.к. они используются только по разу, то достаточно создать одну локальную с размером PLATFORM_MAX_PATH (т.е. 256 байт). И использовать её одну в OnMapStart().

Дебаг можно делать используя инструкции компилятора
C-подобный:
#define DEBUG 1

#if DEBUG == 1
    -код_для_дебага-
#endif
Тогда при компиляции можно просто менять значение дефайна чтобы скомпилировать версию с дебагом или без.
И да "жук" на англиийском таки "bUg", а не "bAg".

Таймер нужно пересоздавать (м/б даже отсылать оверлей снова, т.к. его мог перебить оверлей созданный другим плагином), потому что у тебя пока таймер работает не будет создаваться оверлей, а время его существования ты ограничил ещё в первую отсылку оверлея. Т.е. ты не продлеваешь время жизни оверлея.

Не пойму для чего делать цикл по игрокам в дебаге и сравнивать равна ли семёрка семёрке (или другое число самому себе). Просто не понимаю сакральный смысл этого действа.

В таймер ты пересылаешь индекс игрока. А если игрок за время заданное для существования оверлея успел выйти?
Передавай UserId в таймер, так ты будешь уверен, что ты работаешь с оверлеем того же игрока, что и при создании таймера.

В таймере ничего не нужно возвращать, если он не имеет флага TIMER_REPEAT или тебе не требуется завершить выполнение кода (тогда возвращай Plugin_Continue для повторяющегося, если хочешь чтобы он снова выполнялся через таймаут и Plugin_Stop для любого, если хочешь остановить таймер).
Сообщения автоматически склеены:

Вообще тебе стоило бы создавать отдельный таймер для каждого из игроков, кому ты отсылаешь оверлей.
В этом твой основной косяк, кмк.
Сообщения автоматически склеены:

И ещё: для чего ты отправляешь оверлей только атакующему, а убиваешь оверлей у атакующего и атакованного?
Сообщения автоматически склеены:

@Nekro, попробуй как будет работать вот этот код.
Большое спасибо, поставил, тестируем. Всё работает отлично)
100 лет живи, 100 лет учись) Это совсем другой код)
 

Nekro

Терра инкогнита
Сообщения
4,025
Реакции
2,260
@Grey83,
C-подобный:
L 03/02/2021 - 18:28:28: [SM] Plugin "sprite_aim.smx" encountered error 23: Native detected error
L 03/02/2021 - 18:28:28: [SM] Invalid timer handle ae23090a (error 3) during timer end, displayed function is timer callback, not the stack trace
L 03/02/2021 - 18:28:28: [SM] Unable to call function "Sprite_Timer" due to above error(s).
В больших количествах
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,521
Реакции
4,980
@Nekro, повторяется только эти три строки?
 

Nekro

Терра инкогнита
Сообщения
4,025
Реакции
2,260

Вложения

  • Screenshot_10.png
    Screenshot_10.png
    42.2 КБ · Просмотры: 15

Grey83

не пишу плагины с весны 2022
Сообщения
8,521
Реакции
4,980
@Nekro, перезалил исходник.
Вроде бы должно помочь.
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,521
Реакции
4,980
@Nekro, просто забыл как правильно обнулять таймер из него самого (там просто нужно было приравнять к null и всё). =)
 
Сверху Снизу