Блеклист в чатменеджере Mistrick

Сообщения
18
Реакции
21
Добрый день, господа
Установил себе чатменеджер и аддон от Mistrick ( https://dev-cs.ru/resources/112/ )
Увидел у него функцию блеклиста, которая блокирует сообщения в чате. Сразу захотелось очистить чат от разных команд типа /rs и разных модовых (команды в чат ankh, tome, boots и другие - от мода вар3фт). Их я хочу записать в конфигурационный файл блеклиста, но нужна помощь в том, чтобы если игрок писал эти команды в чат, они в чат не выводились (но на сервере выполнялись)

Код:
/**
 * Credits: Subb98.
 */
#include <amxmodx>
#include <regex>

#define PLUGIN "Chat Manager: Addon"
#define VERSION "0.0.4-70"
#define AUTHOR "Mistrick"

#pragma semicolon 1

enum
{
    MESSAGE_IGNORED,
    MESSAGE_CHANGED,
    MESSAGE_BLOCKED
};

forward cm_player_send_message(id, message[], team_chat);
native cm_set_player_message(message[]);

#define FUNCTION_BLACK_LIST
#define FUNCTION_BLOCK_IDENTICAL_MSG
//#define FUNCTION_BLOCK_ADVERTISING
//#define FUNCTION_BLOCK_CAPS

// TODO: Remove this func from main plugin
//#define FUNCTION_LOG_MESSAGES

#define MAX_IDENTICAL_MESSAGES 3
#define MIN_MESSAGE_DELAY 0.1 // seconds
#define MAX_WARNINGS_TO_BLOCK_CHAT 5
#define BLOCK_CHAT_TIME 15.0 // seconds
#define MAX_CAPS_PERCENT 90

#define IP_LEN 22
#define DOMAIN_LEN 32

new Float:g_fLastMsgTime[33];
new g_iWarnings[33];
new Float:g_fBlockTime[33];

#if defined FUNCTION_BLACK_LIST
new const FILE_BLACK_LIST[] = "chatmanager_blacklist.ini";
new Array:g_aBlackList;
new g_iBlackListSize;
#endif // FUNCTION_BLACK_LIST

#if defined FUNCTION_BLOCK_IDENTICAL_MSG
new g_sLastMessage[33][128];
new g_iRepeatWarn[33];
#endif // FUNCTION_BLOCK_IDENTICAL_MSG

#if defined FUNCTION_BLOCK_ADVERTISING
new const FILE_WHITE_LIST[] = "chatmanager_whitelist.ini";
new Array:g_aWhiteListIp;
new Array:g_aWhiteListDomain;
new g_iWhiteListIpSize;
new g_iWhiteListDomainSize;
new Regex:g_rIpPattern;
new Regex:g_rDomainPattern;
#endif // FUNCTION_BLOCK_ADVERTISING

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR);
}

public plugin_cfg()
{
    #if defined FUNCTION_BLACK_LIST
    LoadBlackList();
    #endif // FUNCTION_BLACK_LIST

    #if defined FUNCTION_BLOCK_ADVERTISING
    new error[2], ret;
    g_rIpPattern = regex_compile("(?:\s*\d+\s*\.){3}", ret, error, charsmax(error));
    g_rDomainPattern = regex_compile("(?:[A-z]){2,}\.(?:[A-z]){2,}", ret, error, charsmax(error));
    LoadWhiteList();
    #endif // FUNCTION_BLOCK_ADVERTISING
}

#if defined FUNCTION_BLACK_LIST
LoadBlackList()
{
    g_aBlackList = ArrayCreate(64, 1);

    new file_path[128]; get_localinfo("amxx_configsdir", file_path, charsmax(file_path));
    format(file_path, charsmax(file_path), "%s/%s", file_path, FILE_BLACK_LIST);

    new file = fopen(file_path, "rt");

    if(file)
    {
        new buffer[64], wchar[64];
        while(!feof(file))
        {
            fgets(file, buffer, charsmax(buffer));
            trim(buffer); remove_quotes(buffer);

            if(!buffer[0] || buffer[0] == ';' || strlen(buffer) < 3) continue;

            normalize_string(buffer);
            multibyte_to_wchar(buffer, wchar);
            wchar_tolower_rus(wchar);
            wchar_to_multibyte(wchar, buffer);

            ArrayPushString(g_aBlackList, buffer);
            g_iBlackListSize++;
        }
        fclose(file);
    }
}
#endif // FUNCTION_BLACK_LIST

#if defined FUNCTION_BLOCK_ADVERTISING
LoadWhiteList()
{
    g_aWhiteListIp = ArrayCreate(IP_LEN, 1);
    g_aWhiteListDomain = ArrayCreate(DOMAIN_LEN, 1);

    new file_path[128]; get_localinfo("amxx_configsdir", file_path, charsmax(file_path));
    format(file_path, charsmax(file_path), "%s/%s", file_path, FILE_WHITE_LIST);

    new file = fopen(file_path, "rt");

    enum
    {
        READ_NON,
        READ_DOMAIN,
        READ_IP
    };

    if(file)
    {
        new buffer[64], type = READ_NON;
        while(!feof(file))
        {
            fgets(file, buffer, charsmax(buffer));
            trim(buffer); remove_quotes(buffer);

            if(!buffer[0] || buffer[0] == ';') continue;

            if(contain(buffer, "[ips]") > -1)
            {
                type = READ_IP;
                continue;
            }
            if(contain(buffer, "[domains]") > -1)
            {
                type = READ_DOMAIN;
                continue;
            }

            if(type)
            {
                ArrayPushString(type == READ_IP ? g_aWhiteListIp : g_aWhiteListDomain, buffer);
            }
        }
        fclose(file);

        g_iWhiteListIpSize = ArraySize(g_aWhiteListIp);
        g_iWhiteListDomainSize = ArraySize(g_aWhiteListDomain);
    }
}
#endif // FUNCTION_BLOCK_ADVERTISING


public client_connect(id)
{
    g_fLastMsgTime[id] = 0.0;
    g_iWarnings[id] = 0;
    g_fBlockTime[id] = 0.0;

    #if defined FUNCTION_BLOCK_IDENTICAL_MSG
    g_iRepeatWarn[id] = 0;
    #endif // FUNCTION_BLOCK_IDENTICAL_MSG
}

public cm_player_send_message(id, message[])
{
    new Float:gametime = get_gametime();

    if(gametime < g_fBlockTime[id])
    {
        return MESSAGE_BLOCKED;
    }

    if(gametime < g_fLastMsgTime[id] + MIN_MESSAGE_DELAY)
    {
        client_print(id, print_chat, "[CMA] Stop spamming!");
        add_warning(id);
        return MESSAGE_BLOCKED;
    }
    g_fLastMsgTime[id] = gametime;

    #if defined FUNCTION_BLOCK_IDENTICAL_MSG
    if(equal(message, g_sLastMessage[id]))
    {
        if(++g_iRepeatWarn[id] >= MAX_IDENTICAL_MESSAGES)
        {
            client_print(id, print_chat, "[CMA] Stop spamming! Identical msg.");
            add_warning(id);
            return MESSAGE_BLOCKED;
        }
    }
    else if(g_iRepeatWarn[id])
    {
        g_iRepeatWarn[id]--;
    }
    copy(g_sLastMessage[id], charsmax(g_sLastMessage[]), message);
    #endif // FUNCTION_BLOCK_IDENTICAL_MSG

    #if defined FUNCTION_BLOCK_CAPS
    static _wchar_msg[128];

    normalize_string(message);
    multibyte_to_wchar(message, _wchar_msg);

    new i, uppercase;
    while(_wchar_msg[i])
    {
        if(wchar_is_uppercase(_wchar_msg[i]))
            uppercase++;
        i++;
    }

    if(uppercase * 100.0 / i >= MAX_CAPS_PERCENT)
    {
        client_print(id, print_chat, "[CMA] Stop using caps!");
        add_warning(id);
        return MESSAGE_BLOCKED;
    }
    #endif // FUNCTION_BLOCK_CAPS

    #if defined FUNCTION_BLOCK_ADVERTISING
    static temp[128];
    new ret;
    // TODO: Add white list
    if(regex_match_c(message, g_rIpPattern, ret))
    {
        copy(temp, charsmax(temp), message);
        for(new i, whiteip[IP_LEN]; i < g_iWhiteListIpSize; i++)
        {
            ArrayGetString(g_aWhiteListIp, i, whiteip, charsmax(whiteip));
            while(replace(temp, charsmax(temp), whiteip, "")){}
        }

        if(regex_match_c(temp, g_rIpPattern, ret))
        {
            client_print(id, print_chat, "[CMA] Founded ip pattern!");
            add_warning(id);
            return MESSAGE_BLOCKED;
        }
    }
    if(regex_match_c(message, g_rDomainPattern, ret))
    {
        copy(temp, charsmax(temp), message);
        for(new i, whitedomain[DOMAIN_LEN]; i < g_iWhiteListDomainSize; i++)
        {
            ArrayGetString(g_aWhiteListDomain, i, whitedomain, charsmax(whitedomain));
            while(replace(temp, charsmax(temp), whitedomain, "")){}
        }

        if(regex_match_c(temp, g_rDomainPattern, ret))
        {
            client_print(id, print_chat, "[CMA] Founded domain pattern!");
            add_warning(id);
            return MESSAGE_BLOCKED;
        }
    }
    #endif // FUNCTION_BLOCK_ADVERTISING

    #if defined FUNCTION_BLACK_LIST
    static new_message[128], wchar_msg[128], low_message[128];

    new changed = false;

    copy(new_message, charsmax(new_message), message);
    copy(low_message, charsmax(low_message), message);

    normalize_string(low_message);
    multibyte_to_wchar(low_message, wchar_msg);
    wchar_tolower_rus(wchar_msg);
    wchar_to_multibyte(wchar_msg, low_message);

    for(new i, len, place, word[64]; i < g_iBlackListSize; i++)
    {
        ArrayGetString(g_aBlackList, i, word, charsmax(word));
        len = strlen(word);
        while((place = containi(low_message, word)) > -1)
        {
            changed = true;
            replace_blocked_word(new_message, strlen(new_message), place, len);
            replace_blocked_word(low_message, strlen(low_message), place, len);
        }
    }

    if(changed)
    {
        cm_set_player_message(new_message);
        return MESSAGE_CHANGED;
    }
    #endif // FUNCTION_BLACK_LIST

    return MESSAGE_IGNORED;
}

add_warning(id)
{
    if(++g_iWarnings[id] >= MAX_WARNINGS_TO_BLOCK_CHAT)
    {
        g_fBlockTime[id] = get_gametime() + BLOCK_CHAT_TIME;
        g_iWarnings[id] = 0;
        client_print(id, print_chat, "[CMA] Your chat has been blocked for %.0f seconds!", BLOCK_CHAT_TIME);
    }
    SendAudio(id, "sound/fvox/beep.wav", PITCH_NORM);
}

#if defined FUNCTION_BLACK_LIST
replace_blocked_word(string[], length, start, word_length)
{

    for(new i = start; i < start + 3; i++)
    {
        string[i] = ' ';
    }
    if(length > 3)
    {
        new len = start + word_length;
        new diff = word_length - 3;
        while(len <= length)
        {
            string[len - diff] = string[len];
            len++;
        }
    }
}
#endif // FUNCTION_BLACK_LIST

stock normalize_string(str[])
{
    for (new i; str[i] != EOS; i++)
    {
        str[i] &= 0xFF;
    }
}

stock wchar_tolower_rus(str[])
{
    for (new i; str[i] != EOS; i++)
    {
        if(str[i] == 0x401)
        {
            str[i] = 0x451;
        }
        else if(0x410 <= str[i] <= 0x42F)
        {
            str[i] += 0x20;
        }
    }
}

stock wchar_is_uppercase(ch)
{
    if(0x41 <= ch <= 0x5A || ch == 0x401 || 0x410 <= ch <= 0x42F)
    {
        return true;
    }
    return false;
}

// Converts MultiByte (UTF-8) to WideChar (UTF-16, UCS-2)
// Supports only 1-byte, 2-byte and 3-byte UTF-8 (unicode chars from 0x0000 to 0xFFFF), because client can't display 2-byte UTF-16
// charsmax(wcszOutput) should be >= strlen(mbszInput)
stock multibyte_to_wchar(const mbszInput[], wcszOutput[]) {
    new nOutputChars = 0;
    for (new n = 0; mbszInput[n] != EOS; n++) {
        if (mbszInput[n] < 0x80) { // 0... 1-byte ASCII
            wcszOutput[nOutputChars] = mbszInput[n];
        } else if ((mbszInput[n] & 0xE0) == 0xC0) { // 110... 2-byte UTF-8
            wcszOutput[nOutputChars] = (mbszInput[n] & 0x1F) << 6; // Upper 5 bits
            
            if ((mbszInput[n + 1] & 0xC0) == 0x80) { // Is 10... ?
                wcszOutput[nOutputChars] |= mbszInput[++n] & 0x3F; // Lower 6 bits
            } else { // Decode error
                wcszOutput[nOutputChars] = '?';
            }
        } else if ((mbszInput[n] & 0xF0) == 0xE0) { // 1110... 3-byte UTF-8
            wcszOutput[nOutputChars] = (mbszInput[n] & 0xF) << 12; // Upper 4 bits
            
            if ((mbszInput[n + 1] & 0xC0) == 0x80) { // Is 10... ?
                wcszOutput[nOutputChars] |= (mbszInput[++n] & 0x3F) << 6; // Middle 6 bits
                
                if ((mbszInput[n + 1] & 0xC0) == 0x80) { // Is 10... ?
                    wcszOutput[nOutputChars] |= mbszInput[++n] & 0x3F; // Lower 6 bits
                } else { // Decode error
                    wcszOutput[nOutputChars] = '?';
                }
            } else { // Decode error
                wcszOutput[nOutputChars] = '?';
            }
        } else { // Decode error
            wcszOutput[nOutputChars] = '?';
        }
        
        nOutputChars++;
    }
    wcszOutput[nOutputChars] = EOS;
}

// Converts WideChar (UTF-16, UCS-2) to MultiByte (UTF-8)
// Supports only 1-byte UTF-16 (0x0000 to 0xFFFF), because client can't display 2-byte UTF-16
// charsmax(mbszOutput) should be >= wcslen(wcszInput) * 3
stock wchar_to_multibyte(const wcszInput[], mbszOutput[]) {
    new nOutputChars = 0;
    for (new n = 0; wcszInput[n] != EOS; n++) {
        if (wcszInput[n] < 0x80) {
            mbszOutput[nOutputChars++] = wcszInput[n];
        } else if (wcszInput[n] < 0x800) {
            mbszOutput[nOutputChars++] = (wcszInput[n] >> 6) | 0xC0;
            mbszOutput[nOutputChars++] = (wcszInput[n] & 0x3F) | 0x80;
        } else {
            mbszOutput[nOutputChars++] = (wcszInput[n] >> 12) | 0xE0;
            mbszOutput[nOutputChars++] = ((wcszInput[n] >> 6) & 0x3F) | 0x80;
            mbszOutput[nOutputChars++] = (wcszInput[n] & 0x3F) | 0x80;
        }
    }
    mbszOutput[nOutputChars] = EOS;
}

stock SendAudio(id, audio[], pitch)
{
    static msg_send_audio; if(!msg_send_audio) msg_send_audio = get_user_msgid("SendAudio");

    message_begin( id ? MSG_ONE_UNRELIABLE : MSG_BROADCAST, msg_send_audio, _, id);
    write_byte(id);
    write_string(audio);
    write_short(pitch);
    message_end();
}
 
Сообщения
496
Реакции
621
Помог
16 раз(а)
Плагин Hide Slash не устроит? Он скрывает всё, что написано через слеш. В принципе туда и остальное можно добавить, что начинается с других слов.
 
Сообщения
1,536
Реакции
2,324
Помог
39 раз(а)
Affl, в настройках плагина уже есть такой функционал (#define FUNCTION_HIDE_SLASH // скрытие сообщений на слэш) и не надо вносить отдельно команды в какой-то список
 
Сообщения
18
Реакции
21
Gudaus, Tranquillity, Спасибо за ответ :)
Я уже думал над этой функцией/плагином, но из-за некоторой сложности мода приходится новым игрокам объяснять команды в чате. А если они будут скрыты, объяснять придётся чуть дольше

А команды мода, которые я хочу скрыть дополнительно - не нужно писать со слешом. Отсюда и такой запрос
 
Сообщения
584
Реакции
1,006
Помог
18 раз(а)
Найти эти команды в плагинах и сделать, чтобы они возвращали PLUGIN_HANDLED.
 

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

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