Некорректная загрузка из БД

Сообщения
1,032
Реакции
828
Помог
10 раз(а)
zhorzh78, так он передает ее в обработчик сразу, единственное только я не знаю, в самом обработчики какое значение тянется из глобалки или локалки, оно объявлено одинаково
 
Сообщения
673
Реакции
242
Помог
11 раз(а)
Javekson, Глобально , пока SQL_ThreadQuery ждет ответа от БД, в это время data[3] может занести данные уже другого игрока
 
Сообщения
73
Реакции
8
ошибок в этот момент никаких не было с запросами?
неа)

Точно в один момент? Или с разницей в три секунды?
в один момент))

data[3] делайте локально для каждой функции
окей!!

Спасибо всем за советы, буду дальше наблюдать (топик не закрывайте'с)
 
Сообщения
73
Реакции
8
Всем привет еще раз, снова я с проблемами базы данных.
Как выше мне уже подсказали переделать переменную data в "локальный" тип, что я и сделал.
Последние несколько дней вообще никаких проблем не было, пока сегодня сам не увидел в логах странную ситуацию: в логах не было строчки с началом запроса загрузки валюты из бд (66 строка), но, запрос всё таки ушел каким-то образом. В ответ пришла информация о том, что steamid данного игрока нет в бд и ему назначено стартовое кол-во валюты (хотя он там был).

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

Код:
#include <amxmodx>
#include <sqlx>

new const TASKID = 11575757;

new bool:g_isLoad[33];

native zp_get_user_ammo_packs(id);
native zp_set_user_ammo_packs(id, amount);

enum _:ques { INSTALL_PLUGIN, LOAD_AMMO, SAVE_AMMO, PRUNED };
new Handle:g_sql_tuple, szQuery[1024];

public plugin_init()
    set_task(1.0, "PluginCfg");

public PluginCfg()
{
    new szHost[64], szUser[32], szPasswd[32], szDb[32];
    get_cvar_string("amx_sql_host", szHost, charsmax(szHost));
    get_cvar_string("amx_sql_user", szUser, charsmax(szUser));
    get_cvar_string("amx_sql_pass", szPasswd, charsmax(szPasswd));
    get_cvar_string("amx_sql_db", szDb, charsmax(szDb));
    
    g_sql_tuple = SQL_MakeDbTuple(szHost, szUser, szPasswd, szDb);
    
    new data[3];
    
    data[0] = INSTALL_PLUGIN;
    formatex(szQuery, charsmax(szQuery), "CREATE TABLE IF NOT EXISTS `zp_ammo_manager` (`id` int(11) NOT NULL AUTO_INCREMENT, `Name` varchar(33) NOT NULL, `Ammo` int(10) NOT NULL, `SteamID` varchar(25) NOT NULL UNIQUE, `LastConnect` int(11) NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;");
    SQL_ThreadQuery(g_sql_tuple, "SQL_Handler", szQuery, data, sizeof(data));
    
    SQL_SetCharset(g_sql_tuple, "utf8");
    
    data[0] = PRUNED;
    formatex(szQuery, charsmax(szQuery), "DELETE FROM `zp_ammo_manager` WHERE `LastConnect` < (UNIX_TIMESTAMP(NOW()) - %d)", (30 * 86400)); // delete players after 30 days
    SQL_ThreadQuery(g_sql_tuple, "SQL_Handler", szQuery, data, sizeof(data));
}

public client_connect(id)
    g_isLoad[id] = false;

public client_putinserver(id)
{
    if(is_user_bot(id) || is_user_hltv(id)) return;
    
    zp_set_user_ammo_packs(id, 0);
    set_task(3.0, "LoadAmmo", id+TASKID);
}

public LoadAmmo(taskid)
{
    new id = taskid - TASKID;
    
    if(!is_user_connected(id) || g_isLoad[id]) return;
    
    new data[3];
    
    data[0] = LOAD_AMMO;
    data[1] = id;
    data[2] = get_user_userid(id);
    
    new szName[32]; get_user_name(id, szName, charsmax(szName));
    new szAuthid[25]; get_user_authid(id, szAuthid, charsmax(szAuthid));
    
    log_amx("[Ammo Manager] Запрос на загрузку аммо для: %s | %s", szName, szAuthid);
    
    formatex(szQuery, charsmax(szQuery), "SELECT * FROM `zp_ammo_manager` WHERE `SteamID` = '%s'", szAuthid);
    SQL_ThreadQuery(g_sql_tuple, "SQL_Handler", szQuery, data, sizeof(data));
}

public client_disconnected(id)
{
    if(is_user_bot(id) || is_user_hltv(id) || !g_isLoad[id]) return;
    
    remove_task(id+TASKID);
    
    new ammo = zp_get_user_ammo_packs(id);
    
    new szName[32]; get_user_name(id, szName, charsmax(szName));
    new szAuthid[25]; get_user_authid(id, szAuthid, charsmax(szAuthid));
    
    new szNewName[64];
    SQL_QuoteString(Empty_Handle, szNewName, charsmax(szNewName), szName);
    
    formatex(szQuery, charsmax(szQuery), "INSERT INTO `zp_ammo_manager` (`Name`, `Ammo`, `SteamID`, `LastConnect`) \
    VALUES ('%s', '%d', '%s', UNIX_TIMESTAMP(NOW())) \
    ON DUPLICATE KEY UPDATE `Name` = '%s', `Ammo` = '%d', `LastConnect` = UNIX_TIMESTAMP(NOW())",
    szNewName, ammo, szAuthid, szNewName, ammo);
    
    SQL_ThreadQuery(g_sql_tuple, "SQL_Handler", szQuery);
    
    g_isLoad[id] = false;
}

public SQL_Handler(failstate, Handle:query, err[], errcode, data[], datasize)
{
    if(failstate == TQUERY_SUCCESS)
    {
        switch(data[0])
        {
            case LOAD_AMMO:
            {
                new id = data[1];
                
                if(!is_user_connected(id) || g_isLoad[id]) return 0;
                
                if(data[2] != get_user_userid(id))
                {
                    log_amx("[Ammo Manager] Загрузка другому игроку");
                    return 0;
                }
                
                new szName[32]; get_user_name(id, szName, charsmax(szName));
                
                if(SQL_NumResults(query) > 0)
                {
                    zp_set_user_ammo_packs(id, SQL_ReadResult(query, 3));
                    log_amx("[Ammo Manager] Загружено %d аммо для игрока %s", SQL_ReadResult(query, 3), szName);
                }
                else // first connect
                {
                    zp_set_user_ammo_packs(id, 50); // start bonus
                    log_amx("[Ammo Manager] Игрок %s получил стартовый бонус", szName);
                }
                
                g_isLoad[id] = true;
            }
            case PRUNED:
            {
                new pruned = SQL_AffectedRows(query);
                if(pruned) log_amx("[Pruned] Removed %d players!", pruned);
            }
            case INSTALL_PLUGIN, SAVE_AMMO: { }
        }
    }
    else    log_amx("[State #%d] Error [#%d] %s", data[0], errcode, err);
    return PLUGIN_CONTINUE;
}

public plugin_end()
    SQL_FreeHandle(g_sql_tuple);

123123123.png
 
Сообщения
673
Реакции
242
Помог
11 раз(а)
To_be_or_not_to_be,
Код:
data[0] = LOAD_AMMO;
data[1] = id;
data[2] = get_user_userid(id);

new szName[32]; get_user_name(id, szName, charsmax(szName));
new szAuthid[25]; get_user_authid(id, szAuthid, charsmax(szAuthid));
размер массива szAuthid[25], как минимум должен быть больше 34
 
Сообщения
53
Реакции
13
Помог
2 раз(а)
Может просто id совпал. Я не скриптер, но как то пытался написать плагин и у меня каким то образом присваивало одинаковый id 2 игрокам. Т.е. в запросах у игроков был разный id, но в момент выполнения функции после запроса почему то второму игроку выдавался уже существующий id. Это конечно было редко но было. Хз чего, но когда я data вынес в глобальную переменную, такой ошибки больше не было. Пользовался вот этой статьёй Работа с Базами Данных
 
Сообщения
53
Реакции
13
Помог
2 раз(а)
To_be_or_not_to_be, у меня изначально тоже была не глобальная. Я добавил лог с выводом имени стиамид и айди в каждое действие. При запросе все норм, а вот в момент if(SQL_NumResults(query) > 0) id у двух игроков одинаковый. так и у тебя могло последним двум игрокам одинаково выдать деньги
 
Сообщения
53
Реакции
13
Помог
2 раз(а)
To_be_or_not_to_be, не знаю. Он только в один момент почему то ошибочно присваивается и второму игроку и именно при смене карты т.е. когда одновременно заходит большое количество людей. Ну так у меня было)
 
Сообщения
673
Реакции
242
Помог
11 раз(а)
To_be_or_not_to_be,
потому что...
Зашел первый игрок
Код:
public client_putinserver(id)
{
    if(is_user_bot(id) || is_user_hltv(id)) return;
   
    zp_set_user_ammo_packs(id, 0);
    set_task(3.0, "LoadAmmo", id+TASKID);
}
через 3 секунды обращается в БД,за это время игрок может
отключиться от сервера а таск все еще задействован, в этом время при подключение данный таск может подхватить совсем другой игрок
13 Янв 2021
remove_task(id+TASKID); не будет задействован пока g_isLoad[id] == false ибо

Код:
public client_disconnected(id)
{
    if(is_user_bot(id) || is_user_hltv(id) || !g_isLoad[id]) return;
13 Янв 2021
уберите таск, ставьте прямой запрос
Код:
public client_putinserver(id)
{
    if(is_user_bot(id) || is_user_hltv(id)) return;
    
    zp_set_user_ammo_packs(id, 0);
    
    new data[3];
       data[0] = LOAD_AMMO;
    data[1] = id;
    data[2] = get_user_userid(id);
    
    new szAuthid[25]; get_user_authid(id, szAuthid, charsmax(szAuthid));
    
    formatex(szQuery, charsmax(szQuery), "SELECT * FROM `zp_ammo_manager` WHERE `SteamID` = '%s'", szAuthid);
    SQL_ThreadQuery(g_sql_tuple, "SQL_Handler", szQuery, data, sizeof(data));
}
 
Сообщения
73
Реакции
8
Limbooc,
remove_task(id+TASKID); не будет задействован пока
как-то я проглядел этот момент
спасибо)))
13 Янв 2021
Limbooc,
размер массива szAuthid[25], как минимум должен быть больше 34
никогда не видел столь длинных steamid, Вы уверены? :D
 
Сообщения
673
Реакции
242
Помог
11 раз(а)
Limbooc,

как-то я проглядел этот момент
спасибо)))
13 Янв 2021
Limbooc,

никогда не видел столь длинных steamid, Вы уверены? :D
13 Янв 2021
To_be_or_not_to_be,
никогда не видел столь длинных steamid, Вы уверены? :D
не длина а размер массива, не путайте
 
Сообщения
73
Реакции
8
Limbooc, ну так мы размер массива задаём под максимальную длину нужной нам информации, или я не прав?
Зачем нам создавать массив с размером массива больше, чем может быть строка ?
 
Сообщения
1,032
Реакции
828
Помог
10 раз(а)
To_be_or_not_to_be, в client_putinserver может вернуть пустой стим айди игрока, не всегда в этот момент может произойти авторизация, юзай client_authorized( id, const sAuthID[ ] ) и в нем отправляй прямой запрос
 
Сообщения
459
Реакции
272
Помог
9 раз(а)
Javekson, раз на то пошло, authorized может вызваться раньше ПутИнСервер'а, так шо, если этого боятся:
Код:
const AUTHORIZED = (1 << 0);
const PUTINSERVER = (1 << 1);

new g_iState[MAX_PLAYERS + 1];

public client_putinserver(id)    {
    g_iState[id] |= PUTINSERVER;

    if (g_iState[id] & AUTHORIZED)    {
        do_sql(id);
    }
}

public client_authorized(id)    {
    g_iState[id] |= AUTHORIZED;

    if (g_iState[id] & PUTINSERVER)    {
        do_sql(id);
    }
}
 

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу