Система администрации.

Пользователь
Статус
Сообщения
84
Лайки
12

1

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

Всем привет!

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

Аннотации

После подключения к базе данных, добавьте функцию:
Pawn:
admin_SetMySQLConnectionHandle(/* переменная хранящая ID подключения к БД */);

В директиве DB_USERS:
Укажите название своей основной таблицы с аккаунтами игроков, если она отличается от стандартной.

Лог обновлений

Версия 0.1:

Добавим ко всем подключаемым библиотекам:
Pawn:
/*
    Для удобства работы, нам понадобится наличие подключения библиотек:
    #include <foreach>
    #include <Pawn.CMD>
*/

Ко всем константам:
Pawn:
/* Определим директиву с названием основной таблицы администраторов. */
#if !defined DB_USERS_ADMINS
    #define DB_USERS_ADMINS "users_admins"
#endif

/* Определим директиву с названием основной таблицы аккаунтов игроков. */
#if !defined DB_USERS
    #define DB_USERS "users"
#endif

/* Определим директиву с названием для поля идентификатора аккаунтов игроков. */
#if !defined DB_USERS_ID
    #define DB_USERS_ID "id"
#endif

/* Определим директиву хранящую ID подключения к БД. */
#if !defined ADMIN_DB_HANDLE
    #define ADMIN_DB_HANDLE GetMySQLHandle()
#endif

/* Определим директивы основных HEX цветов. */
#if !defined HEX_COLOR_ADMIN_CHAT
    #define HEX_COLOR_ADMIN_CHAT 0xFF6347FF
#endif

#if !defined HEX_COLOR_ADMIN_SUCCESS
    #define HEX_COLOR_ADMIN_SUCCESS 0x46BD38ff
#endif

#if !defined HEX_COLOR_ADMIN_WARNING
    #define HEX_COLOR_ADMIN_WARNING  0xAFAFAFFF
#endif 

/* Определим директиву, которая устанавливает ID аккаунта игрока. */
#if !defined SetPlayerUserID
    #define SetPlayerUserID(%0,%1) g_player_data[%0][PD_ID] = %1
#endif

/* Определим директивы, которые будут получать значения: ID аккаунта в базе и имени. */
#if !defined GetPlayerUserID
    #define GetPlayerUserID(%0) g_player_data[%0][PD_ID] 
#endif

#if !defined GetPlayerNameEx
    #define GetPlayerNameEx(%0) g_player_data[%0][PD_NAME] 
#endif

/* Определим директиву с максимальным количеством символов в пароле администратора. */
#if !defined MAX_ADMIN_PASSWORD_LENGTH
    #define MAX_ADMIN_PASSWORD_LENGTH 32
#endif

/* Определим директиву с минимальным количеством символов в пароле администратора. */
#if !defined MIN_ADMIN_PASSWORD_LENGTH
    #define MIN_ADMIN_PASSWORD_LENGTH 6
#endif

/* Определим директиву с максимальным количеством доступных администраторов в сети. */
#if !defined MAX_ADMINS_COUNT
        #define MAX_ADMINS_COUNT (50)
#endif

/* Определим директиву с максимальным уровнем администратора. */
#if !defined MAX_ADMIN_LEVEL
        #define MAX_ADMIN_LEVEL (6)
#endif

/* Определим директиву с минимальным уровнем администратора. */
#if !defined MIN_ADMIN_LEVEL
        #define MIN_ADMIN_LEVEL (1)
#endif

/* Определим директиву с максимальным размером хэща для пароля администратора. */
#if !defined MAX_ADMIN_PASSWORD_HASH_LENGTH
    #define MAX_ADMIN_PASSWORD_HASH_LENGTH (64)
#endif

/* Определим директиву с максимальным размером соли для пароля администратора. */
#if !defined MAX_ADMIN_PASSWORD_SALT_LENGTH
    #define MAX_ADMIN_PASSWORD_SALT_LENGTH (12)
#endif

/* Определим директиву с максимальной длиной IP при регистрации администратора. */
#if !defined MAX_ADMIN_REG_IP_LENGTH
    #define MAX_ADMIN_REG_IP_LENGTH (16)
#endif

/* Определим директиву c максимальной длиной даты регистрации администратора. */
#if !defined MAX_ADMIN_REG_DATE_LENGTH
    #define MAX_ADMIN_REG_DATE_LENGTH (20)
#endif

/* Определим директиву c максимальным количеством попыток для авторизации в панели администратора. */
#if !defined MAX_ADMIN_LOGIN_ATTEMPTS
    #define MAX_ADMIN_LOGIN_ATTEMPTS (5)
#endif

Ко всем глобальным переменным:
Pawn:
/* Объявим структуру для удобства работы с ID диалогов. */
enum {
        DIALOG_ADMIN_REGISTER = 8999, /* Задайте своё значение свободного диалога. */
        DIALOG_ADMIN_LOGIN
}

/* Объявим структуру для удобства работы с доступом к командам администратора, с помощью использования флагов командного процессора Pawn.CMD. */
enum (<<=1) {
        ADMIN_COMMAND_LEVEL_6 = 1, /* Доступ к командам 6-го уровня */
        ADMIN_COMMAND_LEVEL_5, /* Доступ к командам 5-го уровня */
        ADMIN_COMMAND_LEVEL_4, /* Доступ к командам 4-го уровня */
        ADMIN_COMMAND_LEVEL_3, /* Доступ к командам 3-го уровня */
        ADMIN_COMMAND_LEVEL_2, /* Доступ к командам 2-го уровня */
        ADMIN_COMMAND_LEVEL_1 /* Доступ к командам 1-го уровня */
};

/* Объявим структуру с данными администратора. */
enum E_PLAYER_ADMIN_STRUCT {
        PA_ID, /* ID аккаунта администратора в базе. */
        PA_LEVEL, /* Уровень администратора. */
        PA_PASSWORD[MAX_ADMIN_PASSWORD_HASH_LENGTH + 1], /* Хэшированный пароль администратора. */
        PA_SALT[MAX_ADMIN_PASSWORD_SALT_LENGTH + 1], /* Соль для хэш пароля администратора. */
        PA_REG_IP[MAX_ADMIN_REG_IP_LENGTH], /* IP при регистрации администратора. */
    PA_REG_DATE[MAX_ADMIN_REG_DATE_LENGTH + 1], /* Дата при регистрации администратора. */
        bool: PA_IS_LOGGED, /* Статус авторизации в панели администратора. */
    PA_LOGIN_ATTEMPTS /* Количество попыток для авторизации в панели администратора. */
};

new g_player_admin[MAX_PLAYERS][E_PLAYER_ADMIN_STRUCT];

/* Очистка данных структуры администратора. */
new const NULL_g_player_admin[E_PLAYER_ADMIN_STRUCT] = {
        0,
        0,
        EOS,
        EOS,
        EOS,
        EOS,
        false,
    MAX_ADMIN_LOGIN_ATTEMPTS
};

/* Объявим структуру с данными аккаунта игрока. */
enum E_PLAYER_DATA_STRUCT {
    PD_ID, /* ID аккаунта игрока в базе. */
    PD_NAME[MAX_PLAYER_NAME + 1] /* Имя игрока при подключении к серверу. */
};

new g_player_data[MAX_PLAYERS][E_PLAYER_DATA_STRUCT];

/* Очистка данных структуры игрока. */
new const NULL_g_player_data[E_PLAYER_DATA_STRUCT] = {
    0,
    EOS
};

/* Создадим итератор для хранения авторизованных администраторов. */
new Iterator: AdminPlayers<MAX_ADMINS_COUNT>;

/* Подавить наличие warning 208 */
forward bool: admin_IsPlayerLogged(const playerid);
forward bool: admin_IsPlayerValid(const playerid);
forward bool: admin_IsPasswordLengthValid(const password[]);

Ко всем функциям:
Pawn:
stock admin_GetPlayerAdminID(const playerid) 
{
    return g_player_admin[playerid][PA_ID];
}

stock admin_SetPlayerAdminID(const playerid, const value) 
{
    g_player_admin[playerid][PA_ID] = value;
}

stock admin_GetPlayerLevel(const playerid)
{
    return g_player_admin[playerid][PA_LEVEL];
}

stock admin_SetPlayerLevel(const playerid, const value)
{
    g_player_admin[playerid][PA_LEVEL] = value;
}

stock admin_GetPlayerPassword(const playerid, output_string[], size = sizeof(output_string))
{
    strcat((output_string[0] = EOS, output_string), g_player_admin[playerid][PA_PASSWORD], size);

    return 1;
}

stock admin_SetPlayerPassword(const playerid, const output_string[], size = sizeof(output_string))
{
    strcat(g_player_admin[playerid][PA_PASSWORD], output_string, size);

    return 1;
}

stock admin_GetPlayerSalt(const playerid, output_string[], size = sizeof(output_string))
{
    strcat((output_string[0] = EOS, output_string), g_player_admin[playerid][PA_SALT], size);

    return 1;
}

stock admin_SetPlayerSalt(const playerid, const output_string[], size = sizeof(output_string))
{
    strcat(g_player_admin[playerid][PA_SALT], output_string, size);

    return 1;
}

stock bool: admin_IsPlayerLogged(const playerid)
{
    return (g_player_admin[playerid][PA_IS_LOGGED] != NULL_g_player_admin[PA_IS_LOGGED]);
}

stock admin_GetPlayerLogged(const playerid, const bool: is_logged)
{
    return g_player_admin[playerid][PA_IS_LOGGED];
}

stock admin_SetPlayerLogged(const playerid, const bool: is_logged)
{
    g_player_admin[playerid][PA_IS_LOGGED] = is_logged;
}

stock admin_GetPlayerLoginAttempts(const playerid, const value)
{
    g_player_admin[playerid][PA_LOGIN_ATTEMPTS] = value;  
}

stock admin_SetPlayerLoginAttempts(const playerid, const value)
{
    g_player_admin[playerid][PA_LOGIN_ATTEMPTS] = value;  
}

stock admin_Init()
{
    new 
        Cache: cache_id = mysql_query(ADMIN_DB_HANDLE, !"SHOW TABLES LIKE '"DB_USERS_ADMINS"'", true),
        tick = GetTickCount();

    if (!cache_num_rows()) {
        mysql_query(ADMIN_DB_HANDLE,
            "\
                CREATE TABLE `"DB_USERS_ADMINS"` ( \
                    `id` int(11) NOT NULL AUTO_INCREMENT, \
                    `user_id` int(11) NOT NULL, \
                    `password` varchar(64) NOT NULL, \
                    `salt` varchar(12) NOT NULL, \
                    `level` int(2) NOT NULL, \
                    `register_IP` varchar(16) NOT NULL, \
                    `register_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, \
                    PRIMARY KEY (`id`) \
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8; \
            ", false
        );
        mysql_query(ADMIN_DB_HANDLE,
            !"\
                CREATE INDEX \
                    user_id \
                ON \
                    `"DB_USERS_ADMINS"`(user_id) \
            ", false
        );
        mysql_query(ADMIN_DB_HANDLE,
            !"\
                ALTER TABLE \
                    `"DB_USERS_ADMINS"`\
                ADD CONSTRAINT \
                    `users_admins_users_fk_1` \
                FOREIGN KEY \
                    (`user_id`) \
                REFERENCES \
                    `"DB_USERS"` (`"DB_USERS_ID"`) \
                ON DELETE CASCADE ON UPDATE CASCADE \
            ", false
        );

        printf("[Debug]: таблица `"DB_USERS_ADMINS"` инициализирована за %d мс.", GetTickCount() - tick);
    } 

    cache_delete(cache_id);

    return (!mysql_errno() ? 1 : 0);
}

stock admin_SavePlayerEx(const playerid, const column_name[], const column_value[])
{
    static const query[] = 
    "\
        UPDATE "DB_USERS_ADMINS" SET '%e'='%e' WHERE id=%d \
    ";
    
    new fmt_query[sizeof(query) + (- 2 + 20) + (- 2 + 128) + (- 2 + 11)];

    mysql_format(
            ADMIN_DB_HANDLE, 
            fmt_query, 
            sizeof(fmt_query), 
            query, 
            column_name,
            column_value,
            admin_GetPlayerAdminID(playerid)
    );
    mysql_tquery(ADMIN_DB_HANDLE, fmt_query, "", !"");

    return (!mysql_errno() ? 1 : 0);
}

stock admin_LoadPlayerUserID(playerid)
{
    static const query[] = 
        "\
                SELECT u.id FROM users u WHERE u.name='%e' \
        ";
        
    new fmt_query[sizeof(query) + (- 2 + MAX_PLAYER_NAME)];

    format(
            fmt_query, 
            sizeof fmt_query,
            query,
            GetPlayerNameEx(playerid)
    );
    mysql_tquery(ADMIN_DB_HANDLE, fmt_query, !"@__OnPlayerLoadUserID", !"d", playerid);

    return (!mysql_errno() ? 1 : 0);
}

stock admin_LoadPlayerData(const playerid)
{
        static const query[] = 
        "\
        SELECT * FROM users u \
        LEFT JOIN "DB_USERS_ADMINS" a ON u.id=a.user_id \
        WHERE u.id=%d \
        ";
        
    new fmt_query[sizeof(query) + (- 2 + 11)];

    format(
            fmt_query, 
            sizeof fmt_query,
            query,
            GetPlayerUserID(playerid)
    );
    mysql_tquery(ADMIN_DB_HANDLE, fmt_query, !"@__OnPlayerLoadAdminData", !"d", playerid);
    
    return (!mysql_errno() ? 1 : 0);
}

stock admin_PlayerCreate(const playerid)
{
    static const query[] = 
    "\
        INSERT INTO "DB_USERS_ADMINS" (level, register_IP) VALUES (%d, '%e') \
    ";

    new 
        fmt_query[sizeof(query) + (- 2 + MAX_ADMIN_REG_IP_LENGTH)],
        tmp_ip[MAX_ADMIN_REG_IP_LENGTH];

    GetPlayerIp(playerid, tmp_ip, MAX_ADMIN_REG_IP_LENGTH);

    admin_SetPlayerLevel(playerid, MIN_ADMIN_LEVEL);

    g_player_admin[playerid][PA_PASSWORD][0] = NULL_g_player_admin[PA_PASSWORD];
    g_player_admin[playerid][PA_SALT][0]     = NULL_g_player_admin[PA_SALT];

    mysql_format(
            ADMIN_DB_HANDLE, 
            fmt_query, 
            sizeof(fmt_query), 
            query, 
            tmp_ip,
            MIN_ADMIN_LEVEL
    );
    mysql_tquery(ADMIN_DB_HANDLE, fmt_query, !"@__OnPlayerLoadAdminID", !"d", playerid);

    Iter_Add(AdminPlayers, playerid);

    SendClientMessage(playerid, HEX_COLOR_ADMIN_SUCCESS, !"Для регистрации пароля администратора, используйте команду - /aduty.");

    return (!mysql_errno() ? 1 : 0);
}

stock admin_PlayerUpdate(const playerid)
{
        static const query[] = 
    "\
        UPDATE "DB_USERS_ADMINS" SET level=%d WHERE id=%d \
    ";
    
    new fmt_query[sizeof(query) + (- 2 + 2) + (- 2 + 11)];

    mysql_format(
            ADMIN_DB_HANDLE, 
            fmt_query, 
            sizeof(fmt_query), 
            query,
            admin_GetPlayerLevel(playerid),
            admin_GetPlayerAdminID(playerid)
    );
    mysql_tquery(ADMIN_DB_HANDLE, fmt_query, "", !"");

    SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Ваш уровень администратора был повышен.");

        return (!mysql_errno() ? 1 : 0);
}

stock admin_PlayerRemove(const playerid)
{
    static const query[] = 
    "\
        DELETE FROM "DB_USERS_ADMINS" WHERE id=%d \
    ";
    
    new fmt_query[sizeof(query) + (- 2 + 11)];

    mysql_format(
            ADMIN_DB_HANDLE, 
            fmt_query, 
            sizeof(fmt_query), 
            query,
            admin_GetPlayerAdminID(playerid)
    );
    mysql_tquery(ADMIN_DB_HANDLE, fmt_query, "", !"");

    if (Iter_Contains(AdminPlayers, playerid)) {
        Iter_Remove(AdminPlayers, playerid);
    }

    admin_SetPlayerLogged(playerid, false);

    SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Вы были сняты с должности администратора.");

    return 1;
}

stock admin_ClearPlayerData(const playerid)
{
    g_player_data[playerid] = NULL_g_player_data;
}

stock admin_ClearPlayerAdminData(const playerid)
{
    if (admin_IsPlayerLogged(playerid)) {
        g_player_admin[playerid] = NULL_g_player_admin;

        if (Iter_Contains(AdminPlayers, playerid)) {
            Iter_Remove(AdminPlayers, playerid);
        }
    }

    return 1;
}

stock bool: admin_IsPlayerValid(const playerid) 
{
    return (g_player_admin[playerid][PA_LEVEL] != NULL_g_player_admin[PA_LEVEL]);
}

stock bool: admin_IsPasswordLengthValid(const password[]) 
{
    if (!(MIN_ADMIN_PASSWORD_LENGTH <= strlen(password) <= MAX_ADMIN_PASSWORD_LENGTH)) {
        return false;
    }

    return true;
}

stock admin_GeneratePlayerPassword(const playerid, password[])
{
        GenerateRandomString(
                g_player_admin[playerid][PA_SALT], 
                MAX_ADMIN_PASSWORD_SALT_LENGTH, 
                MAX_ADMIN_PASSWORD_SALT_LENGTH + 1
        );

        SHA256_PassHash(
                password, 
                g_player_admin[playerid][PA_SALT], 
                g_player_admin[playerid][PA_PASSWORD], 
                MAX_ADMIN_PASSWORD_HASH_LENGTH
        );

    return 1;
}

stock admin_SendMessage(const color, const message[])
{
    foreach (new idx : AdminPlayers) {
        SendClientMessage(idx, color, message);
    }

    return 1;
}

stock ShowPlayerAdminRegisterDialog(playerid) 
{
    return ShowPlayerDialog(
            playerid, 
            DIALOG_ADMIN_REGISTER, 
            DIALOG_STYLE_INPUT,
            !"{FFFFFF}Регистрация пароля администратора",
            !"{FFFFFF}Придумайте ваш личный пароль от панели администратора и введите его в диалоговое поле ниже:\n\
            – Важно:\n\
            • {AFAFAF}Пароль администратора должен быть не менее "#MIN_ADMIN_PASSWORD_LENGTH" и не более "#MAX_ADMIN_PASSWORD_LENGTH" символов в длину.\n\
            • {AFAFAF}Пароль администратора может состоять только из латинских символов и цифр (aA-zZ, 0-9).\n\
            Пример надёжного пароля администратора: 32asbe501Tg67F9k",
            !"Далее", !"Закрыть"
        );
}

stock ShowPlayerAdminLoginDialog(playerid) 
{
    return ShowPlayerDialog(
            playerid, 
            DIALOG_ADMIN_LOGIN, 
            DIALOG_STYLE_PASSWORD,
                !"{FFFFFF}Авторизация администратора",
                    !"{FFFFFF}Введите ваш личный пароль администратора в диалоговое поле ниже:",
                    !"Далее", !"Закрыть"
        );
}

/*
        auxiliary functions
*/

static stock GenerateRandomString(
    result_str[], 
    length, 
    const size = sizeof(result_str), 
    const alphabet[] = DEFAULT_ALPHABET, 
    const alphabet_size = sizeof(alphabet)) // by ziggi
{
        result_str[0] = '\0';

        if (length >= size) {
                length = size - 1;
        }

        if (length < 1) {
                return 0;
        }

        for (new i = 0; i < length; i++) {
                result_str[i] = alphabet[ random(alphabet_size - 1) ];
        }

        return 1;
}

static stock bool: IsValidPasswordChars(const string[]) 
{
    for (new i = 0; string[i] != '\0'; ++i) {
                switch (string[i]) {
                        case 'a'..'z', 'A'..'Z', '0'..'9': {
                                continue;
                        }
                        default: {
                                return false;
                        }
                }
        }

    return true;
}

static stock bool: strequal(const string1[], const string2[], bool:ignorecase = false, length = cellmax) // by m1n1vv.
{
    new
        s1 = string1[0],
        s2 = string2[0];
            
    if ((s1 == '\0' || s2 == '\0') && (s1 != s2))
        return false;
            
    return strcmp(string1, string2, ignorecase, length) == 0;
}

@__OnPlayerLoadUserID(playerid);
@__OnPlayerLoadUserID(playerid)
{
    new row_count = cache_num_rows();

    if (row_count) {
        new user_id;
        cache_get_value_name_int(0, !"id", user_id);

        SetPlayerUserID(playerid, user_id);

        admin_LoadPlayerData(playerid);
    }

    return 1;
}

@__OnPlayerLoadAdminData(playerid);
@__OnPlayerLoadAdminData(playerid)
{
    new row_count = cache_num_rows();

    if (row_count) {
        cache_get_value_name_int(0, !"id", g_player_admin[playerid][PA_ID]);
        cache_get_value_name_int(0, !"level", g_player_admin[playerid][PA_LEVEL]);

        cache_get_value_name(0, !"password", g_player_admin[playerid][PA_PASSWORD], MAX_ADMIN_PASSWORD_HASH_LENGTH);
        cache_get_value_name(0, !"salt", g_player_admin[playerid][PA_SALT], MAX_ADMIN_PASSWORD_SALT_LENGTH);
        cache_get_value_name(0, !"register_IP", g_player_admin[playerid][PA_REG_IP], MAX_ADMIN_REG_IP_LENGTH);
        cache_get_value_name(0, !"register_date", g_player_admin[playerid][PA_REG_DATE], MAX_ADMIN_REG_DATE_LENGTH);

        new buffer[MAX_ADMIN_PASSWORD_HASH_LENGTH];

        admin_GetPlayerPassword(playerid, buffer);

        if (isnull(buffer)) {
                    SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Вы вошли как незарегистрированный администратор.");
            SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Для регистрации пароля используйте - /aduty.");
            } else {
            static const message[] = "Вы вошли как администратор (%d) уровня. Для авторизации используйте - /aduty.";
            new fmt_message[sizeof(message) + (- 2 + 2)];

                    format(
                    fmt_message, 
                    sizeof(fmt_message), 
                    message,
                    g_player_admin[playerid][PA_LEVEL]
                    );
                    SendClientMessage(playerid, HEX_COLOR_ADMIN_SUCCESS, fmt_message);
            }

        Iter_Add(AdminPlayers, playerid);
    }

    return 1;
}

@__OnPlayerLoadAdminID(playerid);
@__OnPlayerLoadAdminID(playerid)
{
    admin_SetPlayerAdminID(playerid, cache_insert_id());

    return 1;
}

В коллбэк OnGameModeInit:
Pawn:
public OnGameModeInit()
{
    admin_Init();

    return 1;
}

В коллбэк OnPlayerConnect:
Pawn:
public OnPlayerConnect(playerid)
{ 
    admin_ClearPlayerData(playerid);
    
    GetPlayerName(playerid, g_player_data[playerid][PD_NAME], MAX_PLAYER_NAME);

    admin_LoadPlayerUserID(playerid);

    return 1;
}

В коллбэк OnPlayerDisconnect:
Pawn:
public OnPlayerDisconnect(playerid, reason)
{
    admin_ClearPlayerAdminData(playerid);
        
    return 1;
}

В коллбэк OnDialogResponse:
Pawn:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
        switch (dialogid) {
                case DIALOG_ADMIN_REGISTER: {
            if (!response) {
                return 0;
            }

            if (!admin_IsPasswordLengthValid(inputtext)) {
                SendClientMessage(
                        playerid, 
                        HEX_COLOR_ADMIN_WARNING, 
                        !"Пароль должен быть не менее \
                        "#MIN_ADMIN_PASSWORD_LENGTH" и не более \
                        "#MAX_ADMIN_PASSWORD_LENGTH" символов в длину."
                );
                return ShowPlayerAdminRegisterDialog(playerid);
            }

            if (!IsValidPasswordChars(inputtext)) {
                SendClientMessage(
                        playerid, 
                        HEX_COLOR_ADMIN_WARNING, 
                        !"Пароль может состоять только из латинских символов и цифр (aA-zZ, 0-9)"
                );
                return ShowPlayerAdminRegisterDialog(playerid);
            }
            
            admin_GeneratePlayerPassword(playerid, inputtext);

            admin_SavePlayerEx(playerid, "password", g_player_admin[playerid][PA_PASSWORD]);
            admin_SavePlayerEx(playerid, "salt", g_player_admin[playerid][PA_SALT]);

            admin_SetPlayerLogged(playerid, true);

            Iter_Add(AdminPlayers, playerid);

            SendClientMessage(playerid, HEX_COLOR_ADMIN_SUCCESS, !"Ваш пароль от панели администратора: ");
            SendClientMessage(playerid, -1, inputtext);

            return 1; 
        }
        case DIALOG_ADMIN_LOGIN: {
            if (!response) {
                return 0;
            }

            if (!admin_IsPasswordLengthValid(inputtext)) {
                SendClientMessage(
                        playerid, 
                        HEX_COLOR_ADMIN_WARNING, 
                        !"Пароль должен быть не менее \
                        "#MIN_ADMIN_PASSWORD_LENGTH" и не более \
                        "#MAX_ADMIN_PASSWORD_LENGTH" символов в длину."
                );
                return ShowPlayerAdminLoginDialog(playerid);
            }

            new hash[MAX_ADMIN_PASSWORD_HASH_LENGTH + 1];

            SHA256_PassHash(
                inputtext, 
                g_player_admin[playerid][PA_SALT],
                hash,
                MAX_ADMIN_PASSWORD_HASH_LENGTH
            );

            if (strequal(hash, g_player_admin[playerid][PA_PASSWORD])) {
                admin_SetPlayerLogged(playerid, true);

                if (!Iter_Contains(AdminPlayers, playerid)) {
                    Iter_Add(AdminPlayers, playerid);
                }

                SendClientMessage(playerid, HEX_COLOR_ADMIN_SUCCESS, !"Вы успешно авторизовались в панели администратора.");
            } else {
                if (--g_player_admin[playerid][PA_LOGIN_ATTEMPTS] <= 0) {
                    SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Вы исчерпали все попытки ввода пароля администратора и были кикнуты.");
                    return Kick(playerid);
                }

                ShowPlayerAdminLoginDialog(playerid);
                SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Пароли не совпадают. Повторите попытку.");
            }

            return 1; 
        }
    }

    return 1;
}

В коллбэк OnPlayerCommandReceived:
Pawn:
public OnPlayerCommandReceived(playerid, cmd[], params[], flags) 
{
        if (((flags & ADMIN_COMMAND_LEVEL_1) ||
                (flags & ADMIN_COMMAND_LEVEL_2) ||
                (flags & ADMIN_COMMAND_LEVEL_3) ||
                (flags & ADMIN_COMMAND_LEVEL_4) ||
                (flags & ADMIN_COMMAND_LEVEL_5) ||
                (flags & ADMIN_COMMAND_LEVEL_6))
                && !admin_IsPlayerLogged(playerid) && admin_IsPlayerValid(playerid)) {
                SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Вы не авторизированы в панели администратора.");
                return 0;
        }

        if ((flags & ADMIN_COMMAND_LEVEL_1) && admin_GetPlayerLevel(playerid) < 1 ||
                (flags & ADMIN_COMMAND_LEVEL_2) && admin_GetPlayerLevel(playerid) < 2 ||
                (flags & ADMIN_COMMAND_LEVEL_3) && admin_GetPlayerLevel(playerid) < 3 ||
                (flags & ADMIN_COMMAND_LEVEL_4) && admin_GetPlayerLevel(playerid) < 4 ||
                (flags & ADMIN_COMMAND_LEVEL_5) && admin_GetPlayerLevel(playerid) < 5 ||
                (flags & ADMIN_COMMAND_LEVEL_6) && admin_GetPlayerLevel(playerid) < 6) {
        return 0;
        }

    return 1;
}

Ко всем командам:
Pawn:
flags:aduty(ADMIN_COMMAND_LEVEL_1)
cmd:aduty(playerid) 
{
    if (Iter_Count(AdminPlayers) > MAX_ADMINS_COUNT) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Превышен лимит администраторов на сервере.");
    }

    if (admin_IsPlayerLogged(playerid)) {
        admin_SetPlayerLogged(playerid, false);
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Вы вышли из панели администратора.");
    }

    new buffer[MAX_ADMIN_PASSWORD_HASH_LENGTH];

    admin_GetPlayerPassword(playerid, buffer);

    if (isnull(buffer)) {
        ShowPlayerAdminRegisterDialog(playerid);
    } else {
        ShowPlayerAdminLoginDialog(playerid);
    }

    return 1;
}

flags:create_admin(ADMIN_COMMAND_LEVEL_6)
cmd:create_admin(playerid, params[])
{
    new targetid = INVALID_PLAYER_ID;

    if (sscanf(params, !"u", targetid)) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, "/create_admin: [ID / Часть имени]");
    }

    if (targetid == INVALID_PLAYER_ID) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Указанного игрока нет на сервере.");
    }

    if (targetid == playerid) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Вы указали свой ID.");
    }
    
    if (admin_IsPlayerValid(targetid)) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Указанный игрок уже администратор.");
    }

    if (Iter_Count(AdminPlayers) > MAX_ADMINS_COUNT) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Превышен лимит администраторов на сервере.");
    }

    admin_PlayerCreate(targetid);

        return 1;
}

flags:edit_admin(ADMIN_COMMAND_LEVEL_6)
cmd:edit_admin(playerid, params[])
{
    new 
        targetid = INVALID_PLAYER_ID,
        level;

    if (sscanf(params, !"ud", targetid, level)) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, "/edit_admin: [ID / Часть имени] [Уровень]");
    }

    if (targetid == INVALID_PLAYER_ID) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Указанного игрока нет на сервере.");
    }

    if (targetid == playerid) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Вы указали свой ID.");
    }

        if (!admin_IsPlayerValid(targetid)) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Указанный игрок не администратор.");
    }
    
    if (!(0 <= level <= MAX_ADMIN_LEVEL)) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Некорректный уровень администратора.");
    }
    
    if (admin_GetPlayerLevel(targetid) == level) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Указанный администратор такого же уровня.");
    }
    
    admin_SetPlayerLevel(playerid, level);
    admin_PlayerUpdate(targetid);
    
    return 1;
}

flags:remove_admin(ADMIN_COMMAND_LEVEL_6)
cmd:remove_admin(playerid, params[])
{
    new targetid = INVALID_PLAYER_ID;

    if (sscanf(params, !"u", targetid)) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, "/remove_admin: [ID / Часть имени]");
    }

    if (targetid == INVALID_PLAYER_ID) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Указанного игрока нет на сервере.");
    }

    if (targetid == playerid) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Вы указали свой ID.");
    }
    
    if (!admin_IsPlayerValid(targetid)) {
        return SendClientMessage(playerid, HEX_COLOR_ADMIN_WARNING, !"Указанный игрок не администратор.");
    }

    admin_PlayerRemove(targetid);

    return 1;
}
1. Вся система полностью переведена в инклуд для подключения к вашему игровому моду.
2. Убрано использование флагов.
3. Добавлена функция admin_GetAccessCommand(const playerid, const level)
4. Исправлен баг при загрузке данных администратора.
5. Исправлен баг при авторизации в панели администратора.
6. Добавлена функция admin_IsPlayerPasswordEqual(password[], expected_hash[], salt[])
7. Добавлена функция admin_GeneratePlayerPassword(const playerid, password[])
8. Добавлена функция admin_SetMySQLConnectionHandle(MySQL: handle)
9. Добавлена функция admin_GetPlayerOnlineByID(const player_name[])
10. Добавлена команда /admin - отправить сообщение в чат администрации.
11. Добавлена команда /admins - посмотреть список администрации онлайн.
12. Добавлена команда /off_admins - посмотреть список администрации (OFFLINE).
13. Добавлена команда /ahelp - посмотреть список доступных команд администора 1-6 уровня.
14. Добавлена команда /off_create_admin - создать нового администратора (OFFLINE).
15. Добавлена команда /off_edit_admin - изменить уровень администратора (OFFLINE).
16. Добавлена команда /off_remove_admin - снять администратора (OFFLINE).

1. Исправлена MySQL ошибка при добавлении нового администратора (OFFLINE).
2. В функции admin_GetAccessCommand(const playerid, const level), убрано использование тернарного оператора.
3. Убрана функция admin_GetPlayerLogged(const playerid, const bool: is_logged).
4. Убрана функция admin_SetPlayerLogged(const playerid, const bool: is_logged).
5. Изменена функция admin_IsPlayerLogin(const playerid). Теперь для проверки на авторизацию в панели администратора используется функция Iter_Contains.
6. В команде /admins, исправлена ошибка отображения диалога при отсутствии активных администраторов.
7. Обновлены/добавлены директивы HEX_COLOR_ADMIN_DEFAULT, HEX_COLOR_ADMIN_CHAT, HEX_COLOR_ADMIN_SUCCESS, HEX_COLOR_ADMIN_ERROR, HEX_COLOR_ADMIN_NOTE, для удобства редактирования цветовой гаммы.
8. Исправлена ошибка, при которой была возможность использовать команды без необходимости авторизации в панели администратора.
9. Исправлена ошибка при компиляции с автоматическим подсчётом размера массива.
10. Исправлена ошибка при компиляции при использовании static enum.
11. Исправлена ошибка при компиляции с перехватом public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]).
13. Убрана директива MAX_ADMIN_REG_IP_LENGTH. Теперь IP-адрес храниться как число.
14. Убраны директивы хранения ID диалогов. Добавлено перечисление с ID диалогов.
15. Добавлена команда /give_weapon для администратора 4-го уровня — выдать оружие игроку.
16. Добавлена команда /slap для администратора 4-го уровня — подкинуть игрока.
18. Добавлена команда /goto для администратора 2-го уровня — ТП к игроку.
19. Добавлена команда /gethere для администратора 3-го уровня — ТП игрока к себе.
20. Добавлена команда /setworld для администратора 4-го уровня — изменить виртуальный мир игроку.
21. Добавлена команда /setint для администратора 4-го уровня — изменить интерьер игроку.
22. Добавлена команда /settime для администратора 5-го уровня — изменить время на сервере.
23. Добавлена команда /setweather для администратора 5-го уровня — изменить погоду на сервере.
24. Добавлена команда /asay для администратора 2-го уровня — написать в общий чат.
25. Добавлена команда /answer для администратора 1-го уровня — ответить игроку.
26. Добавлена команда /gotopos для администратора 3-го уровня — ТП по координатам.
27. Добавлена команда /cc для администратора 3-го уровня — очистить чат.
28. Добавлена команда /eject для администратора 1-го уровня — выкинуть игрока из транспортного средства.
29. Добавлена команда /freeze для администратора 2-го уровня — заморозка игрока.
30. Добавлена команда /unfreeze для администратора 2-го уровня — разморозка игрока.
31. Добавлена команда /weapon для администратора 4-го уровня — информация об оружии игрока.
32. Добавлена команда /spawnveh для администратора 2-го уровня — телепортировать транспорта на спавн.
33. Добавлена команда /repairveh для администратора 4-го уровня — починка транспорта.
34. Добавлена команда /veh для администратора 6-го уровня — создать транспорт.
35. Добавлена команда /setskin для администратора 4-го уровня — изменить скин игроку.
36. Добавлена команда /showstats для администратора 1-го уровня — показать статистику игрока.
37. Добавлена команда /set_health для администратора 4-го уровня — установить жизни игроку.
38. Добавлена команда /set_armour для администратора 4-го уровня — установить броню игроку.
39. Добавлена команда /set_money для администратора 4-го уровня — установить деньги игроку.
40. Добавлена команда /aspawn для администратора 3-го го уровня — заспавить игрока.
41. Добавлена команда /dveh для администратора 6-го уровня — удалить транспорт.
42. Добавлена команда /set_prefix для администратора 6-го уровня — установить префикс администратору.
43. Добавлена команда /prefix_color для администратора 6-го уровня — установить цвет префикса администратору.
 

Вложения

  • admin_sys.inc
    89.3 KB · Просмотры: 0

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

Сверху