Как вызвать любую функцию ReGame / ReAPI / ReHLDS (без EXT_FUNC)

  • Автор темы Автор темы Refresh
  • Дата начала Дата начала
Здравствуйте!

Я никогда не понимал, почему Repi большую часть функционала ReGame просто "дублирует". Сегодня ночью столкнувшись с необходимостью выдать Defkit игроку, я полез смотреть реализацию натива rg_give_defusekit. Вспоминаю, что совсем недавно в регейме видел в player.h функцию GiveDefuser.

Сравнивая обе реализации, написанные одними и теми же разработчиками, я решительно не понимал, ПААЧЕМУУУУ? этот натив нельзя было сократить и написать в виде:
Код:
cell AMX_NATIVE_CALL rg_give_defusekit(AMX *amx, cell *params)
{
    enum args_e { arg_count, arg_index, arg_def, arg_color, arg_icon, arg_flash };

    CHECK_GAMERULES();
    CHECK_ISPLAYER(arg_index);

    CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]);
    CHECK_CONNECTED(pPlayer, arg_index);

    // on the map there is not bomb places
    if (CSGameRules() != nullptr && !CSGameRules()->m_bMapHasBombTarget && !CSGameRules()->m_bMapHasBombZone) {
        return FALSE;
    }

    if (pPlayer->m_iTeam != CT) {
        return FALSE;
    }

    pPlayer->GiveDefuser();

    return TRUE;
}

Прикинув, что если я скопирую реализацию функции регеймаGiveDefuser, суммарно в памяти получится 3 копии одного и того же кода... Бредo_O

Полез к себе в модуль и написав для объекта типа CBasePlayer "pl_to->" в списке доступных функций GiveDefuser не было... Прошерстив cssdk я понял, что это древнее говно мамонта, которое 9 лет никто не обновлял и оно кочует из проекта в проект без изменений. Но мне точно нужно pl_to->GiveDefuser() и еще много функций из player.h регейма... Перепробовав наверно десяток разных вариантов (включая изменение ячеек памяти vtable и т.п.), рабочих оказалось 3... Самый красивый и удобный ниже.

Для своего модуля я использую "обертку" от ReAPI, в которой есть файлик ex_regamedll_api.cpp, добавляем туда строки (+):
Diff:
+CBasePlayer_GiveDefuser_t func_CBasePlayer_GiveDefuser;
bool RegamedllApi_Init()
{
    const char *szGameDLLModule = GET_GAME_INFO(PLID, GINFO_DLL_FULLPATH);
    if (!szGameDLLModule)
        return false;

    CSysModule *gameModule = Sys_GetModuleHandle(szGameDLLModule);
    if (!gameModule)
        return false;

    CreateInterfaceFn ifaceFactory = Sys_GetFactory(gameModule);
    if (!ifaceFactory)
        return false;

    int retCode = 0;
    g_ReGameApi = (IReGameApi *)ifaceFactory(VRE_GAMEDLL_API_VERSION, &retCode);
    if (!g_ReGameApi)
    {
        return false;
    }

    int majorVersion = g_ReGameApi->GetMajorVersion();
    int minorVersion = g_ReGameApi->GetMinorVersion();

    if (majorVersion != REGAMEDLL_API_VERSION_MAJOR)
    {
        UTIL_ServerPrint("[%s]: ReGameDLL API major version mismatch; expected %d, real %d\n", Plugin_info.logtag, REGAMEDLL_API_VERSION_MAJOR, majorVersion);

        // need to notify that it is necessary to update the ReGameDLL.
        if (majorVersion < REGAMEDLL_API_VERSION_MAJOR)
        {
            UTIL_ServerPrint("[%s]: Please update the ReGameDLL up to a major version API >= %d\n", Plugin_info.logtag, REGAMEDLL_API_VERSION_MAJOR);
        }

        // need to notify that it is necessary to update the module.
        else if (majorVersion > REGAMEDLL_API_VERSION_MAJOR)
        {
            UTIL_ServerPrint("[%s]: Please update the %s up to a major version API >= %d\n", Plugin_info.logtag, Plugin_info.logtag, majorVersion);
        }

        return false;
    }

    if (minorVersion < REGAMEDLL_API_VERSION_MINOR)
    {
        UTIL_ServerPrint("[%s]: ReGameDLL API minor version mismatch; expected at least %d, real %d\n", Plugin_info.logtag, REGAMEDLL_API_VERSION_MINOR, minorVersion);
        UTIL_ServerPrint("[%s]: Please update the ReGameDLL up to a minor version API >= %d\n", Plugin_info.logtag, REGAMEDLL_API_VERSION_MINOR);
        return false;
    }

    g_ReGameFuncs = g_ReGameApi->GetFuncs();
    g_ReGameHookchains = g_ReGameApi->GetHookchains();

    // Safe check CCSEntity API interface version
    if (!g_ReGameApi->BGetICSEntity(CSENTITY_API_INTERFACE_VERSION))
    {
        UTIL_ServerPrint("[%s]: Interface CCSEntity API version '%s' not found.\n", Plugin_info.logtag, CSENTITY_API_INTERFACE_VERSION);

        if (g_ReGameApi->BGetICSEntity("CSENTITY_API_INTERFACE_VERSION002"))
            UTIL_ServerPrint("[%s]: Please update ReGameDLL to the latest version.\n", Plugin_info.logtag);
        else
            UTIL_ServerPrint("[%s]: Please update ReAPI to the latest version.\n", Plugin_info.logtag);

        return false;
    }

+    // Hack ReGame
+    func_CBasePlayer_GiveDefuser = (CBasePlayer_GiveDefuser_t)Sys_GetProcAddress(gameModule, "_ZN11CBasePlayer11GiveDefuserEv");
+    if (!func_CBasePlayer_GiveDefuser)
+    {
+        UTIL_ServerPrint("[%s]: ReGame function %s not found.\n", Plugin_info.logtag, "_ZN11CBasePlayer11GiveDefuserEv");
+        return false;
+    }
+
    return true;
}

Лезем в player.h из cssdk и добавляем строчки наверх:
Код:
// Hack ReGame
typedef void (*CBasePlayer_GiveDefuser_t)(CBasePlayer*);
extern CBasePlayer_GiveDefuser_t func_CBasePlayer_GiveDefuser;

Там же, чуть ниже, в описание класса CBasePlayer в public секции добавляем:
Код:
// RefsAPI
void GiveDefuser() { if (func_CBasePlayer_GiveDefuser) func_CBasePlayer_GiveDefuser(this); };

После чего для объекта типа CBasePlayer в списке доступных элементов появляется новая функция GiveDefuser():
Код:
pl_to->GiveDefuser();
Компилируем, проверяем... УРААА!! Все работает 😅

Продолжаем искать и добавлять функции, берем бинарник регейма (cs.so) и ищем теперь следующую функцию без модификатора EXT_FUNC:
Код:
ubuntu@ubuntu1604:~/dev/Release$ strings cs.so | grep RemoveDefuser
_ZN11CBasePlayer13RemoveDefuserEv

Берем mangled имя функции "_ZN11CBasePlayer13RemoveDefuserEv" и повторяем процесс...
 
Последнее редактирование:
А кто то еще поддерживает эти проекты? Тогда стоит сделать pull request
 

Кто просматривает тему

Назад
Верх