Русское сообщество по скриптингу

Orpheu: Перехват сообщений в чат от других плагинов

Статьи или фрагменты кода для новичков и уже опытных скриптеров по AMXX.

Модератор: Chuvi

Правила форума
1. Запрещено материться и оскорблять других участников форума.
2. Запрещен флуд, оффтоп, дабл постинг во всех разделах форума, кроме раздела "Болтовня".
3. Запрещено взламывать сайт/форум или наносить любой вред проекту.
4. Запрещено рекламировать другие ресурсы.
5. Запрещено создавать темы без информативного названия. Название темы должно отображать ее смысл.

В данном разделе форума разрешено создавать темы, касающие только обучающему материалу по AMX Mod X.

Orpheu: Перехват сообщений в чат от других плагинов

Сообщение DJ_WEST » 29 авг 2010, 03:57

Автор: DJ_WEST

В данной статье речь пойдет о перехвате сообщений в чат, которые посылаются другими плагинами AMXX. Заметил, что многие об этом спрашивали на форуме, как это сделать. Собственно, перехватывать будем функцию client_print. Зачем это нужно? К примеру, у вас нет исходника плагина, а вам нужно или изменить сообщение, или русифицировать его, а может даже убрать вшитую в плагин рекламу. Для перехвата нам понадобится модуль Вы должны зарегистрироваться, чтобы видеть ссылки..

Итак, начнем с простого. Функция для вывода сообщений имеет следующий синтаксис:
[pawn]client_print(index, type, const message[], ...) [/pawn]
index - id игрока или 0, если нужно отправить сообщение всем игрокам
type - тип сообщения:
  • print_chat - сообщение в чат
  • print_console - сообщение в консоль
  • print_notify - сообщение в консоль при режиме разработчика (developer)
  • print_center - сообщение по центру
message - текст сообщения

Теперь попробуем обратиться к исходникам мода AMX Mod X. В файле amxmodx.cpp находим нашу функцию:
[pawn]
static cell AMX_NATIVE_CALL client_print
(AMX *amx, cell *params) /* 3 param */
{
    int len = 0;
    char *msg;
    
    if 
(params[1] == 0)
    {
        for (int i = 1; i <= gpGlobals->maxClients; ++i)
        {
            CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
            
            if 
(pPlayer->ingame)
            {
                g_langMngr.SetDefLang(i);
                msg = format_amxstring(amx, params, 3, len);
                msg[len++] = '\n';
                msg[len] = 0;
                UTIL_ClientPrint(pPlayer->pEdict, params[2], msg);
            }
        }
    } else {
        int index = params[1];
        
        if 
(index < 1 || index > gpGlobals->maxClients)
        {
            LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
            return 0;
        }
        
        CPlayer
* pPlayer = GET_PLAYER_POINTER_I(index);
        g_langMngr.SetDefLang(index);
        
        msg 
= format_amxstring(amx, params, 3, len);
        msg[len++] = '\n';
        msg[len] = 0;
        
        if 
(pPlayer->ingame)
            UTIL_ClientPrint(pPlayer->pEdict, params[2], msg);        //format_amxstring(amx, params, 3, len));
    }
    
    return len
;
}
 
 
[/pawn]
Внимательно изучив код, можно заметить, что в нем вызывается функция UTIL_ClientPrint. Открываем util.cpp и находим ее:
[pawn]void UTIL_ClientPrint(edict_t *pEntity, int msg_dest, char *msg)
{
    if (!gmsgTextMsg)
        return;                // :TODO: Maybe output a warning log?

    char c = msg[190];
    msg[190] = 0;            // truncate without checking with strlen()
    
    if 
(pEntity)
        MESSAGE_BEGIN(MSG_ONE, gmsgTextMsg, NULL, pEntity);
    else
        MESSAGE_BEGIN
(MSG_BROADCAST, gmsgTextMsg);
    
    WRITE_BYTE
(msg_dest);
    WRITE_STRING(msg);
    MESSAGE_END();
    msg[190] = c;
}
 [/pawn]
Данную функцию (UTIL_ClientPrint) мы и будем перехватывать. Теперь нам нужно найти сигнатуру этой функции для Windows и Linux версий библиотеки. А затем создать конфиг к Orpheu и использовать ее для перехвата сообщений. Сигнатуры находим с помощью программы IDA Pro.

[align=center]
client_print_linux.jpg

client_print_win.jpg
[/align]

Так как мы будем искать функцию в библиотеке AMXX, то нужно добавить в Orpheu его поддержку. Для этого в директории ..\addons\amxmodx\configs\orpheu\libraries создадим файл amxmodx. Добавим в него:
Код: Выделить всё

[
   "amxmodx", "amx_mode"
]

Теперь создадим конфигурационный файл для Orpheu в директории ..\addons\amxmodx\configs\orpheu\functions с именем UTIL_ClientPrint. Содержание файла должно быть таким:
Код: Выделить всё
{
   "name" : "UTIL_ClientPrint",
   "library" : "amxmodx",
   "arguments" :
   [
        {
            "type" : "pointer"
        },
        {
            "type" : "int"
        },
        {
            "type" : "char *"
        }
   ],
   "identifiers":
   [
      {
         "os" : "windows",
         "value" : [0x83,"*","*","*","*","*","*",0x74,"*",0x8B,"*","*","*",0x85,0xC0,0x53,0x56,0x8B,"*","*","*",0x8A,"*","*","*","*","*",0xC6,"*","*","*","*","*","*",0x74,"*",0x50,0xA1,"*","*","*","*",0x6A,0x00,0x50,0x6A,0x01,0xEB,"*"]
      },
      {
         "os" : "linux",
         "value" : "_Z16UTIL_ClientPrintP7edict_siPc"
      }
   ]
}

name - имя нашей функции
library - библиотека, где нужно искать функцию, ставим amxmodx, так как мы добавили поддержку
arguments - аргументы функции UTIL_ClientPrint, если вернуться к исходникам AMXX, то функция имеет данный вид:
[pawn]UTIL_ClientPrint(edict_t *pEntity, int msg_dest, char *msg) [/pawn]
Так как Orpheu не поддерживает тип edict_t, вместо этого указываем pointer. Второй тип - int, третий - char *.
identifiers - идентификаторы функции, в данном случае это сигнатуры
os - операционная система (windows/linux)
value - значение, в данном случае сигнатура (на скриншотах выше выделено красным цветом)


Все, наш конфиг готов. Еще один важный момент, как видно функция использует edict_t *pEntity, что нам не подходит, потому что это указатель на объект, а не его id. А для того, чтобы правильно перехватить id игрока, которому отправляется сообщение, нам нужно будет использовать еще одну функцию из engine модуля игры под названием IndexOfEdict.

[align=center]
indexofedict_linux.jpg

indexofedict_windows.jpg
[/align]

Теперь создадим конфигурационный файл для Orpheu в директории ..\addons\amxmodx\configs\orpheu\functions с именем IndexOfEdict. Содержание файла должно быть таким:
Код: Выделить всё
{
   "name" : "IndexOfEdict",
   "library" : "engine",
   "return" :
   {
      "type" : "int"
   },
   "arguments" :
   [
      {
            "type" : "pointer"
      }
   ],
   "identifiers":
   [
      {
         "os" : "windows",
         "value" : [0x55,0x8B,0xEC,0x8B,"*","*",0x85,0xC0,0x75,"*",0x5D,0xC3,0x8B,"*","*","*","*","*",0x56,0x2B,0xC1,0x8B,0xC8,0xB8,"*","*","*","*"]
      },
      {
         "os" : "linux",
         "value" : "IndexOfEdict"
      }
   ]
}

return - тип возвращаемого значения


Осталось применить полученные знания и конфиги на практике, рассмотрим примерный плагин:
[pawn]#include <amxmodx>
#include <orpheu>

#define PLUGIN "Hook client_print"
#define VERSION "1.0"
#define AUTHOR "DJ_WEST"

// Используем для проверки, что объект - это игрок, если входит значение в промежуток между 1 и 32
#define IsPlayer(%1) (1 <= (%1) <= 32)

// Создаем переменную для хранения указателя на функцию IndexOfEdict
new OrpheuFunction:o_IndexOfEdict

public plugin_init
()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)
        
    
// Регистрируем перехват на функцию UTIL_ClientPrint
    // On_ClientPrint_Pre - функция, которая будет вызываться при вызове функции UTIL_ClientPrint
    // OrpheuHookPre - означает, что перехватываем функцию перед ее вызовом
    OrpheuRegisterHook(OrpheuGetFunction("UTIL_ClientPrint"), "On_ClientPrint_Pre", OrpheuHookPre)
    
    
// Помещаем в переменную o_IndexOfEdict указатель на функцию IndexOfEdict
    o_IndexOfEdict = OrpheuGetFunction("IndexOfEdict")
}

// Указываем аргументы для функции относительно тех, что прописаны в конфиге
// p_Edict - указатель на объект
// i_Type - тип сообщения
// s_Message - текст сообщения
public OrpheuHookReturn:On_ClientPrint_Pre(p_Edict, i_Type, s_Message[190])
{
    // Удаляем пробелы с начала и конца s_Message
    trim(s_Message)

    // Если полученное сообщение s_Message равняется указанному
    // и тип сообщения равен print_chat (вывод в чат)
    if (equal(s_Message, "Type 'amx_help' in the console to see available commands") && i_Type == print_chat)
    {
        //  Создаем переменную для хранения id игрока
        static id
        
        
// Вызываем функцию IndexOfEdict, передавая ей указатель p_Edict
        // Полученное значение сохраняем в переменную, как id игрока
        id = OrpheuCall(o_IndexOfEdict, p_Edict)
    
        if 
(IsPlayer(id))
        {
            // Если мы хотим заменить сообщение своим, то посылаем новое
            // Если хотим только блокировать, то не посылаем
            client_print(id, i_Type, "Visit http://amx-x.ru", id)
        
            
// Используем OrpheuSupercede для блокировки выполнения функции UTIL_ClientPrint
            // Следовательно оригинальное сообщение, которое мы заменяем, игрок не увидит
            return OrpheuSupercede
        
}
    }

    // Если сообщение не подходит нашему условию
    // то просто продолжаем выполнение функции UTIL_ClientPrint
    return OrpheuIgnored
}  [/pawn]
Не пишите мне в ЛС: если вам нужна помощь на бесплатной основе. Любые вопросы на форум.
Аватара пользователя
DJ_WEST
Администратор
 
Сообщения: 3641
Зарегистрирован: 22 авг 2009, 00:38
Благодарил (а): 48 раз.
Поблагодарили: 2209 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Counter-Strike: Source
Left 4 Dead
Left 4 Dead 2

Re: Orpheu: Перехват сообщений в чат от других плагинов

Сообщение CS Faktor » 28 июл 2014, 20:38

Сигнатуры находим с помощью программы IDA Pro.

скажите какая версия программы оптимальна, я скачал но у меня по другому немного
и где найти сигнатуру под client_print функцию(всмысле в каком файле)?
-AfterBans[100%]
[ ПЕРЕЗАЛИЛ!!!!Для АМХБАНС!При бане дозаписывает метки на игроке(смотрите кфг) и тем самым уменьшает вероятность обхода AfterBans Скачать]
-CreativeChat[20%]
Аватара пользователя
CS Faktor
 
Сообщения: 42
Зарегистрирован: 04 июл 2014, 22:42
Благодарил (а): 6 раз.
Поблагодарили: 2 раз.
Опыт программирования: Около года
Языки программирования: Counter-Strike 1.6

Re: Orpheu: Перехват сообщений в чат от других плагинов

Сообщение Bos93 » 28 июл 2014, 22:03

Что у тебя не так ? Искать в .dll\so амыикса.
Всем добра, любви и осознанности.

Nosce animum tuum.

А осознание и есть, что понял и осмыслил..
А коль не думал ты о том, то кто о том замыслил..?
Аватара пользователя
Bos93
 
Сообщения: 1425
Зарегистрирован: 03 апр 2010, 13:44
Благодарил (а): 149 раз.
Поблагодарили: 514 раз.

Re: Orpheu: Перехват сообщений в чат от других плагинов

Сообщение CS Faktor » 29 июл 2014, 08:52

пишет что сигнатура для файла UTIL_ClientPrint не найдена..
-AfterBans[100%]
[ ПЕРЕЗАЛИЛ!!!!Для АМХБАНС!При бане дозаписывает метки на игроке(смотрите кфг) и тем самым уменьшает вероятность обхода AfterBans Скачать]
-CreativeChat[20%]
Аватара пользователя
CS Faktor
 
Сообщения: 42
Зарегистрирован: 04 июл 2014, 22:42
Благодарил (а): 6 раз.
Поблагодарили: 2 раз.
Опыт программирования: Около года
Языки программирования: Counter-Strike 1.6

Re: Orpheu: Перехват сообщений в чат от других плагинов

Сообщение Bos93 » 29 июл 2014, 16:16

Ну значит не верна составил.
Всем добра, любви и осознанности.

Nosce animum tuum.

А осознание и есть, что понял и осмыслил..
А коль не думал ты о том, то кто о том замыслил..?
Аватара пользователя
Bos93
 
Сообщения: 1425
Зарегистрирован: 03 апр 2010, 13:44
Благодарил (а): 149 раз.
Поблагодарили: 514 раз.

Re: Orpheu: Перехват сообщений в чат от других плагинов

Сообщение Leonidddd » 29 июл 2014, 16:25

У меня на билде 6027 она называется
_Z19UTIL_ClientPrintAlliPKcS0_S0_S0_S0_
Аватара пользователя
Leonidddd
Модератор
 
Сообщения: 2557
Зарегистрирован: 08 апр 2012, 18:13
Откуда: г. Запорожье
Благодарил (а): 192 раз.
Поблагодарили: 718 раз.

Re: Orpheu: Перехват сообщений в чат от других плагинов

Сообщение CS Faktor » 29 июл 2014, 23:03

Leonidddd писал(а):У меня на билде 6027 она называется
_Z19UTIL_ClientPrintAlliPKcS0_S0_S0_S0_

учту, но у меня винда
-AfterBans[100%]
[ ПЕРЕЗАЛИЛ!!!!Для АМХБАНС!При бане дозаписывает метки на игроке(смотрите кфг) и тем самым уменьшает вероятность обхода AfterBans Скачать]
-CreativeChat[20%]
Аватара пользователя
CS Faktor
 
Сообщения: 42
Зарегистрирован: 04 июл 2014, 22:42
Благодарил (а): 6 раз.
Поблагодарили: 2 раз.
Опыт программирования: Около года
Языки программирования: Counter-Strike 1.6

Пред.

Вернуться в Статьи / фрагменты кода

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3