AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Coding MM:S Plugins & SM Extensions (https://forums.alliedmods.net/forumdisplay.php?f=75)
-   -   how do i detour the function has variable argument? (https://forums.alliedmods.net/showthread.php?t=311022)

Zeisen 09-30-2018 13:09

how do i detour the function has variable argument?
 
I'm new c++ and extension and i made my extension for some detour functions, compile/build works okay. But server does crash when PrintIfWatched detouring.

so I oversaw PrintIfWatched source-code, and i found that function uses variable argument. I have no idea how to detour that function.

and I'm sure signatures are correct.

PrintIfWatched code : https://github.com/VSES/SourceEngine...ot/bot.h#L1011

my extension.cpp
Code:


#include "extension.h"

IGameConfig *g_pGameConf;

IForward *g_pOnStopFollowing;
IForward *g_pOnSetState;
IForward *g_pOnPrintIfWatched;

CDetour *dtrStopFollowing;
CDetour *dtrSetState;
CDetour *dtrPrintIfWatched;

BotController g_BotController;

SMEXT_LINK(&g_BotController);

DETOUR_DECL_MEMBER0(StopFollowing, void)
{
        CBaseEntity *pBot = (CBaseEntity *)this;

        cell_t result = g_BotController.OnStopFollowing(pBot);
        if (result == Pl_Handled || result == Pl_Stop)
                return;

        DETOUR_MEMBER_CALL(StopFollowing)();
}

DETOUR_DECL_MEMBER1(SetState, void, cell_t, state)
{
        CBaseEntity *pBot = (CBaseEntity *)this;
       
        cell_t result = g_BotController.OnSetState(pBot, state);
        if (result == Pl_Handled || result == Pl_Stop)
                return;

        DETOUR_MEMBER_CALL(SetState)(state);
}

DETOUR_DECL_MEMBER1(PrintIfWatched, void, char *, message)
{
        CBaseEntity *pBot = (CBaseEntity *)this;

        cell_t result = g_BotController.OnPrintIfWatched(pBot, message);
        if (result == Pl_Handled || result == Pl_Stop)
                return;

        DETOUR_MEMBER_CALL(PrintIfWatched)(message);
}

bool BotController::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
        if (!gameconfs->LoadGameConfigFile("bot.games", &g_pGameConf, error, maxlength))
                return false;

        g_pOnStopFollowing = g_pForwards->CreateForward("CCSBot_OnStopFollowing", ET_Hook, 1, NULL, Param_Cell);
        g_pOnSetState                = g_pForwards->CreateForward("CCSBot_OnSetState", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
        g_pOnPrintIfWatched = g_pForwards->CreateForward("CCSBot_OnPrintIfWatched", ET_Hook, 2, NULL, Param_Cell, Param_String);

        CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
       
        dtrStopFollowing = DETOUR_CREATE_MEMBER(StopFollowing, "CCSBot::StopFollowing");
        if (!dtrStopFollowing)
                return false;

        dtrSetState = DETOUR_CREATE_MEMBER(SetState, "CCSBot::SetState");
        if (!dtrSetState) {
                smutils->Format(error, maxlength, "Detour failed: CCSBot::SetState");
                return false;
        }

        dtrPrintIfWatched = DETOUR_CREATE_MEMBER(PrintIfWatched, "CCSBot::PrintIfWatched");
        if (!dtrPrintIfWatched) {
                smutils->Format(error, maxlength, "Detour failed: CCSBot::PrintIfWatched");
                return false;
        }

        dtrStopFollowing->EnableDetour();
        dtrSetState->EnableDetour();
        dtrPrintIfWatched->EnableDetour();

        g_SMAPI->ConPrint("Bot Controller Extension Loaded");

        return true;
}

void BotController::SDK_OnUnload()
{
        if (dtrStopFollowing != NULL) {
                dtrStopFollowing->Destroy();
                dtrStopFollowing = NULL;
        }
        if (dtrSetState != NULL) {
                dtrSetState->Destroy();
                dtrSetState = NULL;
        }
        if (dtrPrintIfWatched != NULL) {
                dtrPrintIfWatched->Destroy();
                dtrPrintIfWatched = NULL;
        }
}

cell_t BotController::OnStopFollowing(CBaseEntity *pBot)
{
        g_pOnStopFollowing->PushCell(gamehelpers->EntityToBCompatRef(pBot));

        cell_t retValue = Pl_Continue;
        g_pOnStopFollowing->Execute(&retValue);

        return retValue;
}

cell_t BotController::OnSetState(CBaseEntity *pBot, cell_t stateAddress)
{
        g_pOnSetState->PushCell(gamehelpers->EntityToBCompatRef(pBot));
        g_pOnSetState->PushCell(stateAddress);

        cell_t retValue = Pl_Continue;
        g_pOnSetState->Execute(&retValue);

        return retValue;
}

cell_t BotController::OnPrintIfWatched(CBaseEntity *pBot, char *message)
{
        if (pBot == NULL)
                return Pl_Continue;

        cell_t pBotRef = gamehelpers->EntityToBCompatRef(pBot);
        g_SMAPI->LogMsg(g_PLAPI, "%d %s", pBotRef, message);

        g_pOnPrintIfWatched->PushCell(pBotRef);
        g_pOnPrintIfWatched->PushString(message);

        cell_t retValue = Pl_Continue;
        g_pOnPrintIfWatched->Execute(&retValue);

        return retValue;
}

and my extension.h
Code:

#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_

#define CCSPlayer CBasePlayer

/**
 * @file extension.h
 * @brief Sample extension code header.
 */

#include "smsdk_ext.h"
#include "CDetour/detours.h"

/**
 * @brief Sample implementation of the SDK Extension.
 * Note: Uncomment one of the pre-defined virtual functions in order to use it.
 */
class BotController : public SDKExtension
{
public:
        /**
        * @brief This is called after the initial loading sequence has been processed.
        *
        * @param error                Error message buffer.
        * @param maxlength        Size of error message buffer.
        * @param late                Whether or not the module was loaded after map load.
        * @return                        True to succeed loading, false to fail.
        */
        virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
       
        /**
        * @brief This is called right before the extension is unloaded.
        */
        virtual void SDK_OnUnload();

        /**
        * @brief This is called once all known extensions have been loaded.
        * Note: It is is a good idea to add natives here, if any are provided.
        */
        //virtual void SDK_OnAllLoaded();

        /**
        * @brief Called when the pause state is changed.
        */
        //virtual void SDK_OnPauseChange(bool paused);

        /**
        * @brief this is called when Core wants to know if your extension is working.
        *
        * @param error                Error message buffer.
        * @param maxlength        Size of error message buffer.
        * @return                        True if working, false otherwise.
        */
        //virtual bool QueryRunning(char *error, size_t maxlength);
public:
#if defined SMEXT_CONF_METAMOD
        /**
        * @brief Called when Metamod is attached, before the extension version is called.
        *
        * @param error                        Error buffer.
        * @param maxlength                Maximum size of error buffer.
        * @param late                        Whether or not Metamod considers this a late load.
        * @return                                True to succeed, false to fail.
        */
        //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late);

        /**
        * @brief Called when Metamod is detaching, after the extension version is called.
        * NOTE: By default this is blocked unless sent from SourceMod.
        *
        * @param error                        Error buffer.
        * @param maxlength                Maximum size of error buffer.
        * @return                                True to succeed, false to fail.
        */
        //virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength);

        /**
        * @brief Called when Metamod's pause state is changing.
        * NOTE: By default this is blocked unless sent from SourceMod.
        *
        * @param paused                Pause state being set.
        * @param error                        Error buffer.
        * @param maxlength                Maximum size of error buffer.
        * @return                                True to succeed, false to fail.
        */
        //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength);
#endif

        cell_t OnStopFollowing(CBaseEntity *bot);
        cell_t OnSetState(CBaseEntity *bot, cell_t stateAddress);
        cell_t OnPrintIfWatched(CBaseEntity *bot, char *message);
};

#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_


Zeisen 10-02-2018 22:15

Re: how do i detour the function has variable argument?
 
I'm still figuring out this. added va_list, but still crash. and buffer prints obstruction string.

Code:

DETOUR_DECL_MEMBER2(PrintIfWatched, void, char *, format, va_list *, args)
{
        CBaseEntity *pBot = (CBaseEntity *)this;

        size_t len;
        va_list ap;

        char buffer[1024];
        va_start(ap, format);
        vsprintf(buffer, format, ap);
        va_end(ap);

        g_SMAPI->ConPrintf("buffer : %s\n", buffer);

        cell_t result = g_BotController.OnPrintIfWatched(pBot, buffer);
        if (result == Pl_Handled || result == Pl_Stop)
                return;

        g_SMAPI->ConPrintf("Calling..\n");

        DETOUR_MEMBER_CALL(PrintIfWatched)(format, args);
}


Fyren 10-03-2018 00:06

Re: how do i detour the function has variable argument?
 
Adding a va_list parameter isn't going to help and trying to pass one to the original function is definitely going to crash.

You might just be able to pass what you get back from vprintf (like DETOUR_MEMBER_CALL(PrintIfWatched)("%s", buffer) might work).

hmmmmm 10-03-2018 01:55

Re: how do i detour the function has variable argument?
 
Make your own macro based off of DETOUR_DECL_MEMBER2 that takes the var args "..." as the second argument.

Zeisen 11-11-2018 22:20

Re: how do i detour the function has variable argument?
 
thank you for answers, unfortunately I still couldn't figure out this. other detours works okay, but PrinfIfWatched looks something special.


All times are GMT -4. The time now is 22:19.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.