View Single Post
Author Message
Zeisen
Member
Join Date: Nov 2016
Location: Republic of Korea
Old 09-30-2018 , 13:09   how do i detour the function has variable argument?
Reply With Quote #1

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_

Last edited by Zeisen; 09-30-2018 at 13:15.
Zeisen is offline