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

Virtual Hook System

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

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

Virtual Hook System

Сообщение Juli » 11 апр 2016, 13:49

Virtual Hook System by Juli


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

Установка

Первым делом необходимо вызвать функцию проверки build'а (вообще, компилятора, но пусть будет так). Вызывать ее необходимо в событии attach'а. Для этого хукаем OnMetaAttach also OnAmxxAttach и вызываем необходимую функцию:

Код: Выделить всё
void OnAmxxAttach()
{
    checkCompiler();
}


Пример использования

Код: Выделить всё
#include "amxxmodule.h"
#include "virtual_hook.h"

VIRTUAL_CALLBACK(void) PlayerTakeDamage(void *pthis VIRTUAL_ARG, entvars_t *pInflictor, entvars_t *pAttacker, float fDamage, int iDamagebits);

virtualHook pTakeDamage("player", virtualHookName::takedamage, (void *)PlayerTakeDamage);

void OnAmxxAttach()
{
    checkCompiler();
}

void ServerActivate(edict_s *a, int b, int c)
{
    pTakeDamage.registerHook();
}

void ServerDeactivate()
{
    pTakeDamage.removeHook();
}

VIRTUAL_CALLBACK(void) PlayerTakeDamage(void *pthis VIRTUAL_ARG, entvars_t *pInflictor, entvars_t *pAttacker, float fDamage, int iDamagebits)
{
    //pre

    VIRTUAL_CALL<void>(pTakeDamage.getAddress(), pthis, pInflictor, pAttacker, fDamage, iDamagebits); //call original function in gamedll

    //post

    edict_t *pVictim = UTIL_PrivateToEdict(pthis); //get this edict

    const char *szName = STRING(pVictim->v.netname); //get this player name

    CENTER_SAY(PLID, "Player %s received damage", szName); //say to all print_center
}




Доступные функции класса

Код: Выделить всё
//регистрирует виртуальную функцию
bool registerHook();

//удаляет хук виртуальной функции//
bool removeHook();

/*получает адрес оригинальной функции
необходимо для вызова, с помощью функции VIRTUAL_CALL*/
void *getAddress();

//возвращает состояние, зарегистрирована функция или нет
bool getState(); 


Дополнительные функции

Код: Выделить всё
//возвращает оффсет необходимой функции
inline int getVirtualOffset(int hookid);

//говорилось в пункте "Установка"
void checkCompiler(void);

//вызов оригинальной функции по адресу
template <typename ReturnType>
inline ReturnType VIRTUAL_CALL(void *address, /*аргументы функции*/);

//получение edict из void
inline edict_t * UTIL_PrivateToEdict(void * pvPrivateData);

//получение edict из entvars
inline edict_t * UTIL_EntvarsToEdict(entvars_t * pthis);

//получение целочисленного индекса из edict
inline int UTIL_EdictToIndex(edict_t * pthis);

//получение целочисленного индекса из entvars
inline int UTIL_EntvarToIndex(entvars_t * pthis);

//получение целочисленного индекса из void
inline int UTIL_PrivateToIndex(void * pthis);


P.S.: Аргументы отлавливаемых функций можете увидеть в комментариях к перечислению virtualHookName:
Код: Выделить всё
enum virtualHookName
{
    base,
    pev,

    spawn,                            //Function params: function(void *this) | Return type: void
    precache,                        //Function params: function(void *this) | Return type: void
    keyvalue,                        //Function params: function(void *this, int kvd_handle) | Return type: void
    objectcaps,                        //Function params: function(void *this) | Return type: int
    activate,                        //Function params: function(void *this) | Return type: void
    setobjectcollisionbox,            //Function params: function(void *this) | Return type: void
    classify,                        //Function params: function(void *this) | Return type: int
    deathnotice,                    //Function params: function(void *this, entvars_t *idchild) | Return type: void
    traceattack,                    //Function params: function(void *this, entvars_t *attacker, float damage, float direction[3], int traceresult, int damagebits) | Return type: void
    takedamage,                        //Function params: function(void *this, entvars_t *inflictor, entvars_t *attacker, float damage, int damagebits) | Return type: int
    takehealth,                        //Function params: function(void *this, float health, int damagebits) | Return type: int
    killed,                            //Function params: function(void *this, entvars_t *attacker, int shouldgib) | Return type: void
    bloodcolor,                        //Function params: function(void *this) | Return type: int
    tracebleed,                        //Function params: function(void *this, float damage, float direction[3], int trace_handle, int damagebits) | Return type: void
    istriggered,                    //Function params: function(void *this, void *activator) | Return type: int
    mymonsterpointer,                //Function params: function(void *this) | Return type: void
    mysquadmonsterpointer,            //Function params: function(void *this) | Return type: void
    gettogglestate,                    //Function params: function(void *this) | Return type: int
    addpoints,                        //Function params: function(void *this, int points, int cangonegative) | Return type: void
    addpointstoteam,                //Function params: function(void *this, int points, int cangonegative) | Return type: void
    addplayeritem,                    //Function params: function(void *this, void *other) | Return type: int
    removeplayeritem,                //Function params: function(void *this, void *other) | Return type: int
    giveammo,                        //Function params: function(void *this, int amount, const char *name, int max) | Return type: int
    getdelay,                        //Function params: function(void *this) | Return type: float
    ismoving,                        //Function params: function(void *this) | Return type: int
    overridereset,                    //Function params: function(void *this) | Return type: void
    damagedecal,                    //Function params: function(void *this, int damagebits) | Return type: int
    settogglestate,                    //Function params: function(void *this, int state) | Return type: void
    startsneaking,                    //Function params: function(void *this) | Return type: void
    stopsneaking,                    //Function params: function(void *this) | Return type: void
    oncontrols,                        //Function params: function(void *this, int idon) | Return type: int
    issneaking,                        //Function params: function(void *this) | Return type: int
    isalive,                        //Function params: function(void *this) | Return type: int
    isbspmodel,                        //Function params: function(void *this) | Return type: int
    reflectgauss,                    //Function params: function(void *this) | Return type: int
    hastarget,                        //Function params: function(void *this, int strindex) | Return type: int
    isinworld,                        //Function params: function(void *this) | Return type: int
    isplayer,                        //Function params: function(void *this) | Return type: int
    isnetclient,                    //Function params: function(void *this) | Return type: int
    teamid,                            //Function params: function(void *this) | Return type: char
    getnexttarget,                    //Function params: function(void *this) | Return type: void
    think,                            //Function params: function(void *this) | Return type: void
    touch,                            //Function params: function(void *this, void *other) | Return type: void
    use,                            //Function params: function(void *this, void *caller, void *activator, int use_type, float value) | Return type: void
    blocked,                        //Function params: function(void *this, void *other) | Return type: void
    respawn,                        //Function params: function(void *this) | Return type: void
    updateowner,                    //Function params: function(void *this) | Return type: void
    fbecomeprone,                    //Function params: function(void *this) | Return type: int
    center,                            //Function params: function(void *this) | Return type: Vector
    eyeposition,                    //Function params: function(void *this) | Return type: Vector
    earposition,                    //Function params: function(void *this) | Return type: Vector
    bodytarget,                        //Function params: function(void *this, Vector *srcvector) | Return type: Vector
    illumination,                    //Function params: function(void *this) | Return type: int
    fvisible,                        //Function params: function(void *this, void *other) | Return type: int
    fvecvisible,                    //Function params: function(void *this, Vector *origin) | Return type: int

    player_jump,                    //Function params: function(void *this) | Return type: void
    player_duck,                    //Function params: function(void *this) | Return type: void
    player_prethink,                //Function params: function(void *this) | Return type: void
    player_postthink,                //Function params: function(void *this) | Return type: void
    player_getgunposition,            //Function params: function(void *this) | Return type: Vector
    player_shouldfadeondeath,        //Function params: function(void *this) | Return type: int
    player_impulsecommands,            //Function params: function(void *this) | Return type: void
    player_updateclientdata,        //Function params: function(void *this) | Return type: void

    item_addtoplayer,                //Function params: function(void *this, void *player) | Return type: int
    item_addduplicate,                //Function params: function(void *this, void *original) | Return type: int
    item_getiteminfo,                //Function params: function(void *this) | Return type: int
    item_candeploy,                    //Function params: function(void *this) | Return type: int
    item_deploy,                    //Function params: function(void *this) | Return type: int
    item_canholster,                //Function params: function(void *this) | Return type: void
    item_holster,                    //Function params: function(void *this) | Return type: void
    item_updateiteminfo,            //Function params: function(void *this) | Return type: void
    item_preframe,                    //Function params: function(void *this) | Return type: void
    item_postframe,                    //Function params: function(void *this) | Return type: void
    item_drop,                        //Function params: function(void *this) | Return type: void
    item_kill,                        //Function params: function(void *this) | Return type: void
    item_attachtoplayer,            //Function params: function(void *this, void *player) | Return type: void
    item_primaryammoindex,            //Function params: function(void *this) | Return type: int
    item_secondaryammoindex,        //Function params: function(void *this) | Return type: int
    item_updateclientdata,            //Function params: function(void *this, void *player) | Return type: int
    item_getweaponptr,                //Function params: function(void *this) | Return type: void
    item_itemslot,                    //Function params: function(void *this) | Return type: int

    weapon_extractammo,                //Function params: function(void *this, void *target) | Return type: int
    weapon_extractclipammo,            //Function params: function(void *this, void *target) | Return type: int
    weapon_addweapon,                //Function params: function(void *this) | Return type: int
    weapon_playemptysound,            //Function params: function(void *this) | Return type: int
    weapon_resetemptysound,            //Function params: function(void *this) | Return type: void
    weapon_sendweaponanim,            //Function params: function(void *this, int anim, int skiplocal, int body) | Return type: void
    weapon_isusable,                //Function params: function(void *this) | Return type: int
    weapon_primaryattack,            //Function params: function(void *this) | Return type: void
    weapon_secondaryattack,            //Function params: function(void *this) | Return type: void
    weapon_reload,                    //Function params: function(void *this) | Return type: void
    weapon_weaponidle,                //Function params: function(void *this) | Return type: void
    weapon_retireweapon,            //Function params: function(void *this) | Return type: void
    weapon_shouldweaponidle,        //Function params: function(void *this) | Return type: int
    weapon_usedecrement,            //Function params: function(void *this) | Return type: int

    cstrike_restart,                //Function params: function(void *this) | Return type: void
    cstrike_roundrespawn,            //Function params: function(void *this) | Return type: void
    cstrike_item_candrop,            //Function params: function(void *this) | Return type: int
    cstrike_item_getmaxspeed,        //Function params: function(void *this) | Return type: float

    end                                // No use me
}; 
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Последний раз редактировалось Juli 14 апр 2016, 18:00, всего редактировалось 5 раз(а).
Аватара пользователя
Juli
 
Сообщения: 661
Зарегистрирован: 09 июн 2013, 00:13
Благодарил (а): 140 раз.
Поблагодарили: 250 раз.
Опыт программирования: Больше трех лет

Re: Virtual Hook System

Сообщение quckly » 11 апр 2016, 20:25

У тебя и определение и объявление в 1 заголовочном файле, скорее всего будут ошибки на этапе компоновки, если использовать в более чем 1 месте этот заголовочный файл.

Добавлено спустя 15 минут 5 секунд:
Можно использовать Variadic template с с++11 Вы должны зарегистрироваться, чтобы видеть ссылки.

Код: Выделить всё
#define VIRTUAL_TYPE
#define VIRTUAL_ARG
#define VIRTUAL_VAL
template <typename ReturnType, typename... TArgs>
inline ReturnType VIRTUAL_CALL(void *address, void* p, TArgs... args)
{
   return reinterpret_cast<ReturnType(VIRTUAL_TYPE *)(void * VIRTUAL_ARG, TArgs...)>(address)(p VIRTUAL_VAL, args...);
}


Добавлено спустя 33 секунды:
Код: Выделить всё
const char* a = "fdsg";
   int b = 123;
   string* c = new string("g");
   VIRTUAL_CALL<void>((void*)0, (void*)0, "abc", a, b, c);
   VIRTUAL_CALL<int>((void*)0, (void*)0);
Аватара пользователя
quckly
Скриптер
 
Сообщения: 403
Зарегистрирован: 20 ноя 2009, 10:03
Благодарил (а): 41 раз.
Поблагодарили: 240 раз.
Опыт программирования: Около 6 месяцев
Языки программирования: Counter-Strike 1.6

Re: Virtual Hook System

Сообщение Juli » 11 апр 2016, 20:31

quckly, по поводу компоновки, да, однако, не подумала что-то. Спасибо, учту. А на счет переменных чисел аргументов - это я сама решила обычным методом пойти, так как у переменных чисел аргументов есть свои неудобства.

Upd.: первое исправила.
Аватара пользователя
Juli
 
Сообщения: 661
Зарегистрирован: 09 июн 2013, 00:13
Благодарил (а): 140 раз.
Поблагодарили: 250 раз.
Опыт программирования: Больше трех лет

Re: Virtual Hook System

Сообщение Juli » 13 апр 2016, 12:57

Обновила с учетом переменных чисел аргументов.
Аватара пользователя
Juli
 
Сообщения: 661
Зарегистрирован: 09 июн 2013, 00:13
Благодарил (а): 140 раз.
Поблагодарили: 250 раз.
Опыт программирования: Больше трех лет

Re: Virtual Hook System

Сообщение wopox1337 » 18 апр 2016, 09:32

Это для metamod (amxx module) системы?
Аватара пользователя
wopox1337
 
Сообщения: 10
Зарегистрирован: 18 окт 2012, 22:34
Благодарил (а): 8 раз.
Поблагодарили: 0 раз.
Опыт программирования: Меньше недели
Языки программирования: Counter-Strike 1.6

Re: Virtual Hook System

Сообщение Juli » 18 апр 2016, 13:13

wopox1337, да.

Что-то как-то тихо вообще. Я бы в свое время радовалась подобной вещичке.
Аватара пользователя
Juli
 
Сообщения: 661
Зарегистрирован: 09 июн 2013, 00:13
Благодарил (а): 140 раз.
Поблагодарили: 250 раз.
Опыт программирования: Больше трех лет

Re: Virtual Hook System

Сообщение Chuvi » 18 апр 2016, 15:45

Juli, сложнаа, сложнаа, нипанятна. ©

У меня есть способ ещё сложнее (хотя, он был сложнее в написании, а не в использовании), но там можно использовать элементы класса, которому принадлежит виртуальная функция.
Правда для этого нужны сами классы (можно взять из ReGameDLL, например).

Ну, то есть, создаём класс, типо такого
Код: Выделить всё

class CHalfLifeMultiplayHook 
:public CHalfLifeMultiplay
{
public:
   void PlayerKilledHook(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor);
   void CheckWinConditionsHook();
};
 

И нехитрым способом перебрасываем виртуальные функции на новые.

Код: Выделить всё

CHalfLifeMultiplay 
*gGameRules = 0;
void (CHalfLifeMultiplay::*PlayerKilledOrig)(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor);
void (CHalfLifeMultiplay::*CheckWinConditionsOrig)();

//Это хукнутая InstallGameRules, если что.
void *InstallGameRulesHook()
{
   CGameRules *Rules;
   void **vTab = NULL; //Указатель на таблицу виртуальных функций.
   Rules = gGamePatcherData->InstallGameRules();
   if (!Rules->IsMultiplayer())
   {
      ErrorMsg("CSDM in not multiplayer?! WTF?!");
   }
   else
   
{
      gGameRules = reinterpret_cast<CHalfLifeMultiplay*>(Rules);
      vTab = GetClassVTable(gDllLib, "CHalfLifeMultiplay", gGameRules);
      if (vTab)
      {
         PlayerKilledOrig = gDllLib->HookVFunctionCall(vTab, &CHalfLifeMultiplay::PlayerKilled, &CHalfLifeMultiplayHook::PlayerKilledHook);
         if (!PlayerKilledOrig)
         {
            ErrorMsg("CHalfLifeMultiplay::PlayerKilled not hooked!");
         }
         else
         
{
            SysMsg("CHalfLifeMultiplay::PlayerKilled HOOKED!");
         }
         CheckWinConditionsOrig = gDllLib->HookVFunctionCall(vTab, &CHalfLifeMultiplay::CheckWinConditions, &CHalfLifeMultiplayHook::CheckWinConditionsHook);
         if (!CheckWinConditionsOrig)
         {
            ErrorMsg("CHalfLifeMultiplay::CheckWinConditions not hooked!");
         }
         else
         
{
            SysMsg("CHalfLifeMultiplay::CheckWinConditions HOOKED!");
         }
      }
   }
   SysMsg("InstallGameRulesHook passed");
   return Rules;
}
 

Таким образом, за счёт наследования мы можем обращаться к переменным класса CHalfLifeMultiplay, но есть один недостаток: мы не можем добавлять новые переменные в Hook класс.

Короче, надо как-нибудь сподобиться сделать пример.
Правда я это делал ещё до появления ReGameDLL-а. Теперь же мне технически проще весь необходимый функционал добавить в свой форк, без каких-либо хуков.

"Незнание английского языка - это ваша проблема."

Плагинами на заказ не занимаюсь. Своих дел хватает.
Аватара пользователя
Chuvi
Модератор
 
Сообщения: 2253
Зарегистрирован: 24 ноя 2011, 08:03
Благодарил (а): 127 раз.
Поблагодарили: 561 раз.

Re: Virtual Hook System

Сообщение Juli » 18 апр 2016, 16:32

Chuvi, так а что сложного? По-моему все элементарно, даже в том же примере. Может, людям просто не интересно, раз даже вопросы не задают, если им сложно, ведь я только за, чтобы помочь. :dntknw:

P.S.: В killed последний аргумент int же.)
Аватара пользователя
Juli
 
Сообщения: 661
Зарегистрирован: 09 июн 2013, 00:13
Благодарил (а): 140 раз.
Поблагодарили: 250 раз.
Опыт программирования: Больше трех лет

Re: Virtual Hook System

Сообщение Chuvi » 18 апр 2016, 16:42

Juli писал(а):P.S.: В killed последний аргумент int же.)


Вы должны зарегистрироваться, чтобы видеть ссылки. (221-я строка)

Добавлено спустя 1 минуту 49 секунд:
Juli писал(а):Chuvi, так а что сложного? По-моему все элементарно, даже в том же примере.


Та там нет ничего сложного, если вьехать в тему. А пока не вьедешь - всё сложно и непонятно.
А когда вьехал - непонятно, что в этом сложного. Короче, замкнутый круг. xD)

"Незнание английского языка - это ваша проблема."

Плагинами на заказ не занимаюсь. Своих дел хватает.
Аватара пользователя
Chuvi
Модератор
 
Сообщения: 2253
Зарегистрирован: 24 ноя 2011, 08:03
Благодарил (а): 127 раз.
Поблагодарили: 561 раз.

Re: Virtual Hook System

Сообщение Juli » 18 апр 2016, 17:30

Chuvi, хм, надо будет исправить в своей таблице.

Та там нет ничего сложного, если вьехать в тему. А пока не вьедешь - всё сложно и непонятно.
А когда вьехал - непонятно, что в этом сложного. Короче, замкнутый круг. xD)

Просто я сужу по себе, мне вот почему-то очень интересно, даже не понимаю, почему метамод не пользуется такой же популярностью среди скриптеров, как amxx. :dntknw:
Аватара пользователя
Juli
 
Сообщения: 661
Зарегистрирован: 09 июн 2013, 00:13
Благодарил (а): 140 раз.
Поблагодарили: 250 раз.
Опыт программирования: Больше трех лет

След.

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

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

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