Интеграция MySQL в Pawn: подключение и работа

Активный
Статус
Сообщения
516
Лайки
32

8

месяц на сайте

MySQL позволяет хранить данные игроков в базе данных. Разберем подключение и использование.

Подключение библиотеки
Код:
#include <a_mysql>
#include <mysql>

Подключение к базе данных
Код:
new MySQL:g_SQL;

public OnGameModeInit()
{
    g_SQL = mysql_connect("localhost", "user", "password", "database");
    
    if(g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0)
    {
        print("Ошибка подключения к MySQL");
        SendRconCommand("exit");
        return 1;
    }
    
    print("Подключение к MySQL успешно");
    
    // Создание таблиц
    mysql_query(g_SQL, "CREATE TABLE IF NOT EXISTS players (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(24), money INT, level INT)");
    
    return 1;
}

public OnGameModeExit()
{
    mysql_close(g_SQL);
    return 1;
}

Выполнение запросов
Код:
// Простой запрос без результата
mysql_query(g_SQL, "UPDATE players SET money = 1000 WHERE name = 'Player1'");

// Запрос с обработкой результата
mysql_query(g_SQL, "SELECT * FROM players WHERE name = 'Player1'", "OnPlayerDataLoaded", "i", playerid);

Колбэки запросов
Код:
forward OnPlayerDataLoaded(playerid);
public OnPlayerDataLoaded(playerid)
{
    new rows = cache_num_rows();
    if(rows > 0)
    {
        new name[24], money, level;
        cache_get_value_name(0, "name", name);
        cache_get_value_name_int(0, "money", money);
        cache_get_value_name_int(0, "level", level);
        
        PlayerInfo[playerid][pMoney] = money;
        PlayerInfo[playerid][pLevel] = level;
        
        SendClientMessage(playerid, -1, "Данные загружены");
    }
    else
    {
        // игрок не найден, создаем нового
        CreateNewPlayer(playerid);
    }
    cache_delete();
    return 1;
}

Сохранение данных игрока
Код:
SavePlayerData(playerid)
{
    new query[256], name[MAX_PLAYER_NAME];
    GetPlayerName(playerid, name, sizeof(name));
    
    format(query, sizeof(query), 
        "UPDATE players SET money = %d, level = %d WHERE name = '%e'",
        GetPlayerMoney(playerid),
        PlayerInfo[playerid][pLevel],
        name);
    
    mysql_query(g_SQL, query);
}

CreateNewPlayer(playerid)
{
    new query[256], name[MAX_PLAYER_NAME];
    GetPlayerName(playerid, name, sizeof(name));
    
    format(query, sizeof(query),
        "INSERT INTO players (name, money, level) VALUES ('%e', %d, %d)",
        name,
        GetPlayerMoney(playerid),
        PlayerInfo[playerid][pLevel]);
    
    mysql_query(g_SQL, query);
}

LoadPlayerData(playerid)
{
    new query[128], name[MAX_PLAYER_NAME];
    GetPlayerName(playerid, name, sizeof(name));
    
    format(query, sizeof(query),
        "SELECT * FROM players WHERE name = '%e'",
        name);
    
    mysql_query(g_SQL, query, "OnPlayerDataLoaded", "i", playerid);
}

Безопасность: экранирование строк
Код:
// Используйте '%e' вместо '%s' для экранирования
format(query, sizeof(query), "SELECT * FROM players WHERE name = '%e'", name);

// Или используйте mysql_escape_string
new escaped_name[48];
mysql_escape_string(name, escaped_name, g_SQL);
format(query, sizeof(query), "SELECT * FROM players WHERE name = '%s'", escaped_name);

Асинхронные запросы
Код:
// Используйте mysql_tquery вместо mysql_query для асинхронности
mysql_tquery(g_SQL, query, "OnPlayerDataLoaded", "i", playerid);

// Это не блокирует основной поток сервера

Пример: система регистрации
Код:
CMD:register(playerid, params[])
{
    if(PlayerInfo[playerid][pLoggedIn])
    {
        SendClientMessage(playerid, -1, "Вы уже зарегистрированы");
        return 1;
    }
    
    new password[64];
    if(sscanf(params, "s[64]", password))
    {
        SendClientMessage(playerid, -1, "Использование: /register [пароль]");
        return 1;
    }
    
    if(strlen(password) < 6)
    {
        SendClientMessage(playerid, -1, "Пароль должен быть не менее 6 символов");
        return 1;
    }
    
    new query[256], name[MAX_PLAYER_NAME], hash[129];
    GetPlayerName(playerid, name, sizeof(name));
    
    // Хеширование пароля (используйте bcrypt или другой алгоритм)
    WP_Hash(hash, sizeof(hash), password);
    
    format(query, sizeof(query),
        "INSERT INTO players (name, password, money, level) VALUES ('%e', '%e', 1000, 1)",
        name, hash);
    
    mysql_tquery(g_SQL, query, "OnPlayerRegistered", "i", playerid);
    return 1;
}

forward OnPlayerRegistered(playerid);
public OnPlayerRegistered(playerid)
{
    if(mysql_errno(g_SQL) != 0)
    {
        SendClientMessage(playerid, -1, "Ошибка регистрации");
        return 1;
    }
    
    PlayerInfo[playerid][pLoggedIn] = true;
    SendClientMessage(playerid, -1, "Регистрация успешна!");
    return 1;
}

Важные моменты:
- Всегда экранируйте пользовательский ввод
- Используйте mysql_tquery для асинхронности
- Проверяйте ошибки подключения
- Закрывайте кеш после использования (cache_delete)
- Используйте индексы для ускорения запросов

MySQL обеспечивает надежное хранение данных!
 

1 человек читают эту тему (Всего: 1, Пользователей: 0, Гостей: 1)

Сверху