DHooks Merge pt1

This commit is contained in:
Michael Flaherty 2019-04-20 16:48:06 -07:00 committed by Headline
parent 4f3c3175e6
commit 8fc0e6fd5a
17 changed files with 3971 additions and 0 deletions

View File

@ -657,6 +657,7 @@ BuildScripts = [
'extensions/tf2/AMBuilder',
'extensions/topmenus/AMBuilder',
'extensions/updater/AMBuilder',
'extensions/dhooks/AMBuilder',
]
if builder.backend == 'amb2':

View File

@ -0,0 +1,39 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os
for arch in SM.archs:
binary = SM.ExtLibrary(builder, 'dhooks.ext', arch)
binary.compiler.cxxincludes += [
os.path.join(builder.currentSourcePath),
os.path.join(SM.mms_root, 'core'),
os.path.join(SM.mms_root, 'core', 'sourcehook'),
os.path.join(builder.sourcePath, 'public'),
os.path.join(builder.sourcePath, 'public', 'extensions'),
os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
os.path.join(builder.sourcePath, 'public', 'amtl'),
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
os.path.join(builder.sourcePath, 'public', 'jit'),
os.path.join(builder.sourcePath, 'public', 'jit', 'x86'),
os.path.join(builder.sourcePath, 'sourcepawn', 'vm'),
os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86'),
os.path.join(builder.sourcePath, 'public', 'amtl', 'include'),
os.path.join(builder.sourcePath, 'public', 'amtl', 'amtl'),
]
binary.compiler.defines += ['META_NO_HL2SDK']
binary.sources += [
'extension.cpp',
'listeners.cpp',
'natives.cpp',
'vhook.cpp',
'util.cpp',
os.path.join(builder.sourcePath, 'public', 'smsdk_ext.cpp'),
]
if os.path.isfile(os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86', 'assembler-x86.cpp')):
binary.sources += [os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86', 'assembler-x86.cpp'),]
elif os.path.isfile(os.path.join(builder.sourcePath, 'public', 'jit', 'x86', 'assembler-x86.cpp')):
binary.sources += [os.path.join(builder.sourcePath, 'public', 'jit', 'x86', 'assembler-x86.cpp'),]
else:
raise Exception('Could not find assembler-x86.cpp. Did you checkout SourceMod\'s submodules?')
SM.extensions += [builder.Add(binary)]

View File

@ -0,0 +1,141 @@
#include "extension.h"
#include "listeners.h"
DHooks g_DHooksIface; /**< Global singleton for extension's main interface */
SMEXT_LINK(&g_DHooksIface);
IBinTools *g_pBinTools;
ISDKHooks *g_pSDKHooks;
ISDKTools *g_pSDKTools;
DHooksEntityListener *g_pEntityListener = NULL;
HandleType_t g_HookSetupHandle = 0;
HandleType_t g_HookParamsHandle = 0;
HandleType_t g_HookReturnHandle = 0;
bool DHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
HandleError err;
g_HookSetupHandle = handlesys->CreateType("HookSetup", this, 0, NULL, NULL, myself->GetIdentity(), &err);
if(g_HookSetupHandle == 0)
{
snprintf(error, maxlength, "Could not create hook setup handle type (err: %d)", err);
return false;
}
g_HookParamsHandle = handlesys->CreateType("HookParams", this, 0, NULL, NULL, myself->GetIdentity(), &err);
if(g_HookParamsHandle == 0)
{
snprintf(error, maxlength, "Could not create hook params handle type (err: %d)", err);
return false;
}
g_HookReturnHandle = handlesys->CreateType("HookReturn", this, 0, NULL, NULL, myself->GetIdentity(), &err);
if(g_HookReturnHandle == 0)
{
snprintf(error, maxlength, "Could not create hook return handle type (err: %d)", err);
return false;
}
sharesys->AddDependency(myself, "bintools.ext", true, true);
sharesys->AddDependency(myself, "sdktools.ext", true, true);
sharesys->AddDependency(myself, "sdkhooks.ext", true, true);
sharesys->RegisterLibrary(myself, "dhooks");
plsys->AddPluginsListener(this);
sharesys->AddNatives(myself, g_Natives);
g_pEntityListener = new DHooksEntityListener();
return true;
}
void DHooks::OnHandleDestroy(HandleType_t type, void *object)
{
if(type == g_HookSetupHandle)
{
delete (HookSetup *)object;
}
else if(type == g_HookParamsHandle)
{
delete (HookParamsStruct *)object;
}
else if(type == g_HookReturnHandle)
{
delete (HookReturnStruct *)object;
}
}
void DHooks::SDK_OnAllLoaded()
{
SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools);
SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks);
g_pSDKHooks->AddEntityListener(g_pEntityListener);
}
void DHooks::SDK_OnUnload()
{
CleanupHooks();
if(g_pEntityListener)
{
g_pEntityListener->CleanupListeners();
g_pSDKHooks->RemoveEntityListener(g_pEntityListener);
delete g_pEntityListener;
}
plsys->RemovePluginsListener(this);
handlesys->RemoveType(g_HookSetupHandle, myself->GetIdentity());
handlesys->RemoveType(g_HookParamsHandle, myself->GetIdentity());
handlesys->RemoveType(g_HookReturnHandle, myself->GetIdentity());
}
bool DHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late)
{
if(!SetupHookManager(ismm))
{
snprintf(error, maxlength, "Failed to get IHookManagerAutoGen iface");
return false;
}
return true;
}
void DHooks::OnPluginUnloaded(IPlugin *plugin)
{
CleanupHooks(plugin->GetBaseContext());
if(g_pEntityListener)
{
g_pEntityListener->CleanupListeners(plugin->GetBaseContext());
}
}
// The next 3 functions handle cleanup if our interfaces are going to be unloaded
bool DHooks::QueryRunning(char *error, size_t maxlength)
{
SM_CHECK_IFACE(SDKTOOLS, g_pSDKTools);
SM_CHECK_IFACE(BINTOOLS, g_pBinTools);
SM_CHECK_IFACE(SDKHOOKS, g_pSDKHooks);
return true;
}
void DHooks::NotifyInterfaceDrop(SMInterface *pInterface)
{
if(strcmp(pInterface->GetInterfaceName(), SMINTERFACE_SDKHOOKS_NAME) == 0)
{
if(g_pEntityListener)
{
// If this fails, remove this line and just delete the ent listener instead
g_pSDKHooks->RemoveEntityListener(g_pEntityListener);
g_pEntityListener->CleanupListeners();
delete g_pEntityListener;
g_pEntityListener = NULL;
}
g_pSDKHooks = NULL;
}
else if(strcmp(pInterface->GetInterfaceName(), SMINTERFACE_BINTOOLS_NAME) == 0)
{
g_pBinTools = NULL;
}
else if(strcmp(pInterface->GetInterfaceName(), SMINTERFACE_SDKTOOLS_NAME) == 0)
{
g_pSDKTools = NULL;
}
}

View File

@ -0,0 +1,132 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Sample Extension
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
/**
* @file extension.h
* @brief Sample extension code header.
*/
#include "smsdk_ext.h"
#include <ISDKHooks.h>
#include <IBinTools.h>
#include <ISDKTools.h>
#include "sdk-hacks.h"
/**
* @brief Sample implementation of the SDK Extension.
* Note: Uncomment one of the pre-defined virtual functions in order to use it.
*/
class DHooks : public SDKExtension, public ISMEntityListener, public IPluginsListener, public IHandleTypeDispatch
{
public:
virtual void OnHandleDestroy(HandleType_t type, void *object);
public: //IPluginsListener
virtual void OnPluginUnloaded(IPlugin *plugin);
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);
//virtual bool QueryInterfaceDrop(SMInterface *pInterface);
virtual void NotifyInterfaceDrop(SMInterface *pInterface);
virtual void OnCoreMapEnd();
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
};
extern SourceHook::IHookManagerAutoGen *g_pHookManager;
extern sp_nativeinfo_t g_Natives[];
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_

View File

@ -0,0 +1,118 @@
#include "listeners.h"
#include "vhook.h"
using namespace SourceHook;
ke::Vector<EntityListener> g_EntityListeners;
ke::Vector<DHooksManager *>g_pRemoveList;
void FrameCleanupHooks(void *data)
{
for (int i = g_pRemoveList.length() - 1; i >= 0; i--)
{
DHooksManager *manager = g_pRemoveList.at(i);
delete manager;
g_pRemoveList.remove(i);
}
}
void DHooks::OnCoreMapEnd()
{
for(int i = g_pHooks.length() -1; i >= 0; i--)
{
DHooksManager *manager = g_pHooks.at(i);
if(manager->callback->hookType == HookType_GameRules)
{
delete manager;
g_pHooks.remove(i);
}
}
}
void DHooksEntityListener::CleanupListeners(IPluginContext *pContext)
{
for(int i = g_EntityListeners.length() -1; i >= 0; i--)
{
if(pContext == NULL || pContext == g_EntityListeners.at(i).callback->GetParentRuntime()->GetDefaultContext())
{
g_EntityListeners.remove(i);
}
}
}
void DHooksEntityListener::OnEntityCreated(CBaseEntity *pEntity, const char *classname)
{
int entity = gamehelpers->EntityToBCompatRef(pEntity);
for(int i = g_EntityListeners.length() -1; i >= 0; i--)
{
EntityListener listerner = g_EntityListeners.at(i);
if(listerner.type == ListenType_Created)
{
IPluginFunction *callback = listerner.callback;
callback->PushCell(entity);
callback->PushString(classname);
callback->Execute(NULL);
}
}
}
void DHooksEntityListener::OnEntityDestroyed(CBaseEntity *pEntity)
{
int entity = gamehelpers->EntityToBCompatRef(pEntity);
for(int i = g_EntityListeners.length() -1; i >= 0; i--)
{
EntityListener listerner = g_EntityListeners.at(i);
if(listerner.type == ListenType_Deleted)
{
IPluginFunction *callback = listerner.callback;
callback->PushCell(gamehelpers->EntityToBCompatRef(pEntity));
callback->Execute(NULL);
}
}
for(int i = g_pHooks.length() -1; i >= 0; i--)
{
DHooksManager *manager = g_pHooks.at(i);
if(manager->callback->hookType == HookType_Entity && manager->callback->entity == entity)
{
if(g_pRemoveList.length() == 0)
{
smutils->AddFrameAction(&FrameCleanupHooks, NULL);
}
g_pRemoveList.append(manager);
g_pHooks.remove(i);
}
}
}
bool DHooksEntityListener::AddPluginEntityListener(ListenType type, IPluginFunction *callback)
{
for(int i = g_EntityListeners.length() -1; i >= 0; i--)
{
EntityListener listerner = g_EntityListeners.at(i);
if(listerner.callback == callback && listerner.type == type)
{
return true;
}
}
EntityListener listener;
listener.callback = callback;
listener.type = type;
g_EntityListeners.append(listener);
return true;
}
bool DHooksEntityListener::RemovePluginEntityListener(ListenType type, IPluginFunction *callback)
{
for(int i = g_EntityListeners.length() -1; i >= 0; i--)
{
EntityListener listerner = g_EntityListeners.at(i);
if(listerner.callback == callback && listerner.type == type)
{
g_EntityListeners.remove(i);
return true;
}
}
return false;
}

View File

@ -0,0 +1,31 @@
#ifndef _INCLUDE_LISTENERS_H_
#define _INCLUDE_LISTENERS_H_
#include "extension.h"
#include "vhook.h"
enum ListenType
{
ListenType_Created,
ListenType_Deleted
};
class DHooksEntityListener : public ISMEntityListener
{
public:
virtual void OnEntityCreated(CBaseEntity *pEntity, const char *classname);
virtual void OnEntityDestroyed(CBaseEntity *pEntity);
void CleanupListeners(IPluginContext *func = NULL);
bool AddPluginEntityListener(ListenType type, IPluginFunction *callback);
bool RemovePluginEntityListener(ListenType type, IPluginFunction *callback);
};
struct EntityListener
{
ListenType type;
IPluginFunction *callback;
};
extern ke::Vector<DHooksManager *> g_pHooks;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
#ifndef _INCLUDE_NATIVES_H_
#define _INCLUDE_NATIVES_H_
#include "extension.h"
#include "vhook.h"
#include "listeners.h"
extern DHooksEntityListener *g_pEntityListener;
extern ISDKTools *g_pSDKTools;
extern HandleType_t g_HookSetupHandle;
extern HandleType_t g_HookParamsHandle;
extern HandleType_t g_HookReturnHandle;
extern ke::Vector<DHooksManager *> g_pHooks;
#endif

View File

@ -0,0 +1,75 @@
#ifndef _INCLUDE_SDK_HACKS_H_
#define _INCLUDE_SDK_HACKS_H_
class SDKVector
{
public:
SDKVector(float x1, float y1, float z1)
{
this->x = x1;
this->y = y1;
this->z = z1;
}
SDKVector(void)
{
this->x = 0.0;
this->y = 0.0;
this->z = 0.0;
}
float x;
float y;
float z;
};
struct string_t
{
public:
bool operator!() const { return ( pszValue == NULL ); }
bool operator==( const string_t &rhs ) const { return ( pszValue == rhs.pszValue ); }
bool operator!=( const string_t &rhs ) const { return ( pszValue != rhs.pszValue ); }
bool operator<( const string_t &rhs ) const { return ((void *)pszValue < (void *)rhs.pszValue ); }
const char *ToCStr() const { return ( pszValue ) ? pszValue : ""; }
protected:
const char *pszValue;
};
struct castable_string_t : public string_t // string_t is used in unions, hence, no constructor allowed
{
castable_string_t() { pszValue = NULL; }
castable_string_t( const char *pszFrom ) { pszValue = (pszFrom && *pszFrom) ? pszFrom : 0; }
};
#define NULL_STRING castable_string_t()
#define STRING( string_t_obj ) (string_t_obj).ToCStr()
#define MAKE_STRING( c_str ) castable_string_t( c_str )
#define FL_EDICT_FREE (1<<1)
struct edict_t
{
public:
bool IsFree()
{
return (m_fStateFlags & FL_EDICT_FREE) != 0;
}
private:
int m_fStateFlags;
};
class CBaseHandle
{
/*public:
bool IsValid() const {return m_Index != INVALID_EHANDLE_INDEX;}
int GetEntryIndex() const
{
if ( !IsValid() )
return NUM_ENT_ENTRIES-1;
return m_Index & ENT_ENTRY_MASK;
}*/
private:
unsigned long m_Index;
};
#endif

View File

@ -0,0 +1,82 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Sample Extension
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
/**
* @file smsdk_config.h
* @brief Contains macros for configuring basic extension information.
*/
/* Basic information exposed publicly */
#define SMEXT_CONF_NAME "DHooks"
#define SMEXT_CONF_DESCRIPTION "Dynamic Hooks"
#define SMEXT_CONF_VERSION "2.2.0"
#define SMEXT_CONF_AUTHOR "Dr!fter"
#define SMEXT_CONF_URL "http://www.sourcemod.net/"
#define SMEXT_CONF_LOGTAG "DHOOKS"
#define SMEXT_CONF_LICENSE "GPL"
#define SMEXT_CONF_DATESTRING __DATE__
/**
* @brief Exposes plugin's main interface.
*/
#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name;
/**
* @brief Sets whether or not this plugin required Metamod.
* NOTE: Uncomment to enable, comment to disable.
*/
#define SMEXT_CONF_METAMOD
/** Enable interfaces you want to use here by uncommenting lines */
//#define SMEXT_ENABLE_FORWARDSYS
#define SMEXT_ENABLE_HANDLESYS
#define SMEXT_ENABLE_PLAYERHELPERS
//#define SMEXT_ENABLE_DBMANAGER
//#define SMEXT_ENABLE_GAMECONF
//#define SMEXT_ENABLE_MEMUTILS
#define SMEXT_ENABLE_GAMEHELPERS
//#define SMEXT_ENABLE_TIMERSYS
//#define SMEXT_ENABLE_THREADER
//#define SMEXT_ENABLE_LIBSYS
//#define SMEXT_ENABLE_MENUS
//#define SMEXT_ENABLE_ADTFACTORY
#define SMEXT_ENABLE_PLUGINSYS
//#define SMEXT_ENABLE_ADMINSYS
//#define SMEXT_ENABLE_TEXTPARSERS
//#define SMEXT_ENABLE_USERMSGS
//#define SMEXT_ENABLE_TRANSLATOR
//#define SMEXT_ENABLE_NINVOKE
//#define SMEXT_ENABLE_ROOTCONSOLEMENU
#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_

View File

@ -0,0 +1,48 @@
#include "util.h"
void * GetObjectAddr(HookParamType type, unsigned int flags, void **params, size_t offset)
{
#ifdef WIN32
if (type == HookParamType_Object)
return (void *)((intptr_t)params + offset);
#elif POSIX
if (type == HookParamType_Object && !(flags & PASSFLAG_ODTOR)) //Objects are passed by rrefrence if they contain destructors.
return (void *)((intptr_t)params + offset);
#endif
return *(void **)((intptr_t)params + offset);
}
size_t GetParamOffset(HookParamsStruct *paramStruct, unsigned int index)
{
size_t offset = 0;
for (unsigned int i = 0; i < index; i++)
{
#ifndef WIN32
if (paramStruct->dg->params.at(i).type == HookParamType_Object && (paramStruct->dg->params.at(i).flags & PASSFLAG_ODTOR)) //Passed by refrence
{
offset += sizeof(void *);
continue;
}
#endif
offset += paramStruct->dg->params.at(i).size;
}
return offset;
}
size_t GetParamTypeSize(HookParamType type)
{
return sizeof(void *);
}
size_t GetParamsSize(DHooksCallback *dg)//Get the full size, this is for creating the STACK.
{
size_t res = 0;
for (int i = dg->params.size() - 1; i >= 0; i--)
{
res += dg->params.at(i).size;
}
return res;
}

10
extensions/dhooks/util.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _INCLUDE_UTIL_FUNCTIONS_H_
#define _INCLUDE_UTIL_FUNCTIONS_H_
#include "vhook.h"
size_t GetParamOffset(HookParamsStruct *params, unsigned int index);
void * GetObjectAddr(HookParamType type, unsigned int flags, void **params, size_t offset);
size_t GetParamTypeSize(HookParamType type);
size_t GetParamsSize(DHooksCallback *dg);
#endif

View File

@ -0,0 +1,104 @@
// Microsoft Visual C++ generated resource script.
//
//#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
#include <sourcemod_version.h>
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION SM_VERSION_FILE
PRODUCTVERSION SM_VERSION_FILE
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000004b0"
BEGIN
VALUE "Comments", "SourceMod DHooks Extension"
VALUE "FileDescription", "SourceMod DHooks Extension"
VALUE "FileVersion", SM_VERSION_STRING
VALUE "InternalName", "SourceMod DHooks Extension"
VALUE "LegalCopyright", "Copyright (c) 2019, AlliedModders LLC"
VALUE "OriginalFilename", BINARY_NAME
VALUE "ProductName", "SourceMod DHooks Extension"
VALUE "ProductVersion", SM_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0, 1200
END
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,324 @@
#ifndef _INCLUDE_VFUNC_CALL_H_
#define _INCLUDE_VFUNC_CALL_H_
#include "vhook.h"
#include "extension.h"
#include "util.h"
#define PARAMINFO_SWITCH(passType) \
paramInfo[i].flags = dg->params.at(i).flags; \
paramInfo[i].size = dg->params.at(i).size; \
paramInfo[i].type = passType;
#define VSTK_PARAM_SWITCH(paramType) \
if(paramStruct->isChanged[i]) \
{ \
*(paramType *)vptr = *(paramType *)newAddr; \
} \
else \
{ \
*(paramType *)vptr = *(paramType *)orgAddr; \
} \
if(i + 1 != dg->params.size()) \
{ \
vptr += dg->params.at(i).size; \
} \
break;
#define VSTK_PARAM_SWITCH_OBJECT() \
memcpy(vptr, objAddr, dg->params.at(i).size); \
if(i + 1 != dg->params.size()) \
{ \
vptr += dg->params.at(i).size; \
} \
break;
template <class T>
T CallVFunction(DHooksCallback *dg, HookParamsStruct *paramStruct, void *iface)
{
SourceMod::PassInfo *paramInfo = NULL;
SourceMod::PassInfo returnInfo;
if(dg->returnType != ReturnType_Void)
{
returnInfo.flags = dg->returnFlag;
returnInfo.size = sizeof(T);
if( dg->returnType != ReturnType_Vector)
{
returnInfo.type = PassType_Basic;
}
else
{
returnInfo.type = PassType_Object;
}
}
ICallWrapper *pCall;
size_t size = GetParamsSize(dg);
unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size);
unsigned char *vptr = vstk;
*(void **)vptr = iface;
if(paramStruct)
{
vptr += sizeof(void *);
paramInfo = (SourceMod::PassInfo *)malloc(sizeof(SourceMod::PassInfo) * dg->params.size());
for(int i = 0; i < (int)dg->params.size(); i++)
{
size_t offset = GetParamOffset(paramStruct, i);
void *orgAddr = (void **)((intptr_t)paramStruct->orgParams + offset);
void *newAddr = (void **)((intptr_t)paramStruct->newParams + offset);
switch(dg->params.at(i).type)
{
case HookParamType_Int:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(int);
case HookParamType_Bool:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(cell_t);
case HookParamType_Float:
PARAMINFO_SWITCH(PassType_Float);
VSTK_PARAM_SWITCH(float);
case HookParamType_String:
PARAMINFO_SWITCH(PassType_Object);
VSTK_PARAM_SWITCH(string_t);
case HookParamType_StringPtr:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(string_t *);
case HookParamType_CharPtr:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(char *);
case HookParamType_VectorPtr:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(SDKVector *);
case HookParamType_CBaseEntity:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(CBaseEntity *);
case HookParamType_Edict:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(edict_t *);
case HookParamType_Object:
{
void *objAddr = GetObjectAddr(HookParamType_Object, paramStruct->dg->params.at(i).flags, paramStruct->orgParams, offset);
PARAMINFO_SWITCH(PassType_Object);
VSTK_PARAM_SWITCH_OBJECT();
}
default:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(void *);
}
}
}
T ret = 0;
if(dg->returnType == ReturnType_Void)
{
pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, NULL, paramInfo, dg->params.size());
pCall->Execute(vstk, NULL);
}
else
{
pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, &returnInfo, paramInfo, dg->params.size());
pCall->Execute(vstk, &ret);
}
pCall->Destroy();
free(vstk);
if(paramInfo != NULL)
{
free(paramInfo);
}
return ret;
}
template <>
SDKVector CallVFunction<SDKVector>(DHooksCallback *dg, HookParamsStruct *paramStruct, void *iface)
{
SourceMod::PassInfo *paramInfo = NULL;
SourceMod::PassInfo returnInfo;
if(dg->returnType != ReturnType_Void)
{
returnInfo.flags = dg->returnFlag;
returnInfo.size = sizeof(SDKVector);
returnInfo.type = PassType_Object;
}
ICallWrapper *pCall;
size_t size = GetParamsSize(dg);
unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size);
unsigned char *vptr = vstk;
*(void **)vptr = iface;
if(paramStruct)
{
vptr += sizeof(void *);
paramInfo = (SourceMod::PassInfo *)malloc(sizeof(SourceMod::PassInfo) * dg->params.size());
for(int i = 0; i < (int)dg->params.size(); i++)
{
size_t offset = GetParamOffset(paramStruct, i);
void *orgAddr = *(void **)((intptr_t)paramStruct->orgParams + offset);
void *newAddr = *(void **)((intptr_t)paramStruct->newParams + offset);
switch (dg->params.at(i).type)
{
case HookParamType_Int:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(int);
case HookParamType_Bool:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(cell_t);
case HookParamType_Float:
PARAMINFO_SWITCH(PassType_Float);
VSTK_PARAM_SWITCH(float);
case HookParamType_String:
PARAMINFO_SWITCH(PassType_Object);
VSTK_PARAM_SWITCH(string_t);
case HookParamType_StringPtr:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(string_t *);
case HookParamType_CharPtr:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(char *);
case HookParamType_VectorPtr:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(SDKVector *);
case HookParamType_CBaseEntity:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(CBaseEntity *);
case HookParamType_Edict:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(edict_t *);
case HookParamType_Object:
{
void *objAddr = GetObjectAddr(HookParamType_Object, paramStruct->dg->params.at(i).flags, paramStruct->orgParams, offset);
PARAMINFO_SWITCH(PassType_Object);
VSTK_PARAM_SWITCH_OBJECT();
}
default:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(void *);
}
}
}
SDKVector ret;
pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, &returnInfo, paramInfo, dg->params.size());
pCall->Execute(vstk, &ret);
pCall->Destroy();
free(vstk);
if(paramInfo != NULL)
{
free(paramInfo);
}
return ret;
}
#ifndef WIN32
template <>
string_t CallVFunction<string_t>(DHooksCallback *dg, HookParamsStruct *paramStruct, void *iface)
{
SourceMod::PassInfo *paramInfo = NULL;
SourceMod::PassInfo returnInfo;
if(dg->returnType != ReturnType_Void)
{
returnInfo.flags = dg->returnFlag;
returnInfo.size = sizeof(string_t);
returnInfo.type = PassType_Object;
}
ICallWrapper *pCall;
size_t size = GetParamsSize(dg);
unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size);
unsigned char *vptr = vstk;
*(void **)vptr = iface;
if(paramStruct)
{
vptr += sizeof(void *);
paramInfo = (SourceMod::PassInfo *)malloc(sizeof(SourceMod::PassInfo) * dg->params.size());
for(int i = 0; i < dg->params.size(); i++)
{
size_t offset = GetParamOffset(paramStruct, i);
void *orgAddr = *(void **)((intptr_t)paramStruct->orgParams + offset);
void *newAddr = *(void **)((intptr_t)paramStruct->newParams + offset);
switch (dg->params.at(i).type)
{
case HookParamType_Int:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(int);
case HookParamType_Bool:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(cell_t);
case HookParamType_Float:
PARAMINFO_SWITCH(PassType_Float);
VSTK_PARAM_SWITCH(float);
case HookParamType_String:
PARAMINFO_SWITCH(PassType_Object);
VSTK_PARAM_SWITCH(string_t);
case HookParamType_StringPtr:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(string_t *);
case HookParamType_CharPtr:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(char *);
case HookParamType_VectorPtr:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(SDKVector *);
case HookParamType_CBaseEntity:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(CBaseEntity *);
case HookParamType_Edict:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(edict_t *);
case HookParamType_Object:
{
void *objAddr = GetObjectAddr(HookParamType_Object, paramStruct->dg->params.at(i).flags, paramStruct->orgParams, offset);
PARAMINFO_SWITCH(PassType_Object);
VSTK_PARAM_SWITCH_OBJECT();
}
default:
PARAMINFO_SWITCH(PassType_Basic);
VSTK_PARAM_SWITCH(void *);
}
}
}
string_t ret;
pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, &returnInfo, paramInfo, dg->params.size());
pCall->Execute(vstk, &ret);
pCall->Destroy();
free(vstk);
if(paramInfo != NULL)
{
free(paramInfo);
}
return ret;
}
#endif
#endif

922
extensions/dhooks/vhook.cpp Normal file
View File

@ -0,0 +1,922 @@
#include "vhook.h"
#include "vfunc_call.h"
#include "util.h"
SourceHook::IHookManagerAutoGen *g_pHookManager = NULL;
ke::Vector<DHooksManager *> g_pHooks;
using namespace SourceHook;
#ifdef WIN32
#define OBJECT_OFFSET sizeof(void *)
#else
#define OBJECT_OFFSET (sizeof(void *)*2)
#endif
DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, IPluginFunction *plugincb, bool post)
{
this->callback = MakeHandler(setup->returnType);
this->hookid = 0;
this->remove_callback = remove_callback;
this->callback->offset = setup->offset;
this->callback->plugin_callback = plugincb;
this->callback->returnFlag = setup->returnFlag;
this->callback->thisType = setup->thisType;
this->callback->post = post;
this->callback->hookType = setup->hookType;
this->callback->params = setup->params;
this->addr = 0;
if(this->callback->hookType == HookType_Entity)
{
this->callback->entity = gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
}
else
{
if(this->callback->hookType == HookType_Raw)
{
this->addr = (intptr_t)iface;
}
this->callback->entity = -1;
}
CProtoInfoBuilder protoInfo(ProtoInfo::CallConv_ThisCall);
for(int i = this->callback->params.size() -1; i >= 0; i--)
{
protoInfo.AddParam(this->callback->params.at(i).size, this->callback->params.at(i).pass_type, PASSFLAG_BYVAL, NULL, NULL, NULL, NULL);//This seems like we need to do something about it at some point...
}
if(this->callback->returnType == ReturnType_Void)
{
protoInfo.SetReturnType(0, SourceHook::PassInfo::PassType_Unknown, 0, NULL, NULL, NULL, NULL);
}
else if(this->callback->returnType == ReturnType_Float)
{
protoInfo.SetReturnType(sizeof(float), SourceHook::PassInfo::PassType_Float, setup->returnFlag, NULL, NULL, NULL, NULL);
}
else if(this->callback->returnType == ReturnType_String)
{
protoInfo.SetReturnType(sizeof(string_t), SourceHook::PassInfo::PassType_Object, setup->returnFlag, NULL, NULL, NULL, NULL);//We have to be 4 really... or else RIP
}
else if(this->callback->returnType == ReturnType_Vector)
{
protoInfo.SetReturnType(sizeof(SDKVector), SourceHook::PassInfo::PassType_Object, setup->returnFlag, NULL, NULL, NULL, NULL);
}
else
{
protoInfo.SetReturnType(sizeof(void *), SourceHook::PassInfo::PassType_Basic, setup->returnFlag, NULL, NULL, NULL, NULL);
}
this->pManager = g_pHookManager->MakeHookMan(protoInfo, 0, this->callback->offset);
this->hookid = g_SHPtr->AddHook(g_PLID,ISourceHook::Hook_Normal, iface, 0, this->pManager, this->callback, this->callback->post);
}
void CleanupHooks(IPluginContext *pContext)
{
for(int i = g_pHooks.length() -1; i >= 0; i--)
{
DHooksManager *manager = g_pHooks.at(i);
if(pContext == NULL || pContext == manager->callback->plugin_callback->GetParentRuntime()->GetDefaultContext())
{
delete manager;
g_pHooks.remove(i);
}
}
}
bool SetupHookManager(ISmmAPI *ismm)
{
g_pHookManager = static_cast<SourceHook::IHookManagerAutoGen *>(ismm->MetaFactory(MMIFACE_SH_HOOKMANAUTOGEN, NULL, NULL));
return g_pHookManager != NULL;
}
SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type)
{
switch(type)
{
case HookParamType_Float:
return SourceHook::PassInfo::PassType_Float;
case HookParamType_Object:
return SourceHook::PassInfo::PassType_Object;
}
return SourceHook::PassInfo::PassType_Basic;
}
size_t GetStackArgsSize(DHooksCallback *dg)
{
size_t res = GetParamsSize(dg);
#ifdef WIN32
if(dg->returnType == ReturnType_Vector)//Account for result vector ptr.
#else
if(dg->returnType == ReturnType_Vector || dg->returnType == ReturnType_String)
#endif
{
res += OBJECT_OFFSET;
}
return res;
}
HookParamsStruct::~HookParamsStruct()
{
if (this->orgParams != NULL)
{
free(this->orgParams);
}
if (this->isChanged != NULL)
{
free(this->isChanged);
}
if (this->newParams != NULL)
{
for (int i = dg->params.size() - 1; i >= 0; i--)
{
size_t offset = GetParamOffset(this, i);
void *addr = (void **)((intptr_t)this->newParams + offset);
if (*(void **)addr == NULL)
continue;
if (dg->params.at(i).type == HookParamType_VectorPtr)
{
delete *(SDKVector **)addr;
}
else if (dg->params.at(i).type == HookParamType_CharPtr)
{
delete *(char **)addr;
}
}
free(this->newParams);
}
}
HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t argStackSize)
{
HookParamsStruct *params = new HookParamsStruct();
params->dg = dg;
#ifdef WIN32
if(dg->returnType != ReturnType_Vector)
#else
if(dg->returnType != ReturnType_Vector && dg->returnType != ReturnType_String)
#endif
{
params->orgParams = (void **)malloc(argStackSize);
memcpy(params->orgParams, argStack, argStackSize);
}
else //Offset result ptr
{
params->orgParams = (void **)malloc(argStackSize-OBJECT_OFFSET);
memcpy(params->orgParams, argStack+OBJECT_OFFSET, argStackSize-OBJECT_OFFSET);
}
size_t paramsSize = GetParamsSize(dg);
params->newParams = (void **)malloc(paramsSize);
params->isChanged = (bool *)malloc(dg->params.size() * sizeof(bool));
for (unsigned int i = 0; i < dg->params.size(); i++)
{
*(void **)((intptr_t)params->newParams + GetParamOffset(params, i)) = NULL;
params->isChanged[i] = false;
}
return params;
}
HookReturnStruct *GetReturnStruct(DHooksCallback *dg)
{
HookReturnStruct *res = new HookReturnStruct();
res->isChanged = false;
res->type = dg->returnType;
res->orgResult = NULL;
res->newResult = NULL;
if(g_SHPtr->GetOrigRet() && dg->post)
{
switch(dg->returnType)
{
case ReturnType_String:
res->orgResult = malloc(sizeof(string_t));
res->newResult = malloc(sizeof(string_t));
*(string_t *)res->orgResult = META_RESULT_ORIG_RET(string_t);
break;
case ReturnType_Int:
res->orgResult = malloc(sizeof(int));
res->newResult = malloc(sizeof(int));
*(int *)res->orgResult = META_RESULT_ORIG_RET(int);
break;
case ReturnType_Bool:
res->orgResult = malloc(sizeof(bool));
res->newResult = malloc(sizeof(bool));
*(bool *)res->orgResult = META_RESULT_ORIG_RET(bool);
break;
case ReturnType_Float:
res->orgResult = malloc(sizeof(float));
res->newResult = malloc(sizeof(float));
*(float *)res->orgResult = META_RESULT_ORIG_RET(float);
break;
case ReturnType_Vector:
{
res->orgResult = malloc(sizeof(SDKVector));
res->newResult = malloc(sizeof(SDKVector));
SDKVector vec = META_RESULT_ORIG_RET(SDKVector);
*(SDKVector *)res->orgResult = vec;
break;
}
default:
res->orgResult = META_RESULT_ORIG_RET(void *);
break;
}
}
else
{
switch(dg->returnType)
{
case ReturnType_String:
res->orgResult = malloc(sizeof(string_t));
res->newResult = malloc(sizeof(string_t));
*(string_t *)res->orgResult = NULL_STRING;
break;
case ReturnType_Vector:
res->orgResult = malloc(sizeof(SDKVector));
res->newResult = malloc(sizeof(SDKVector));
*(SDKVector *)res->orgResult = SDKVector();
break;
case ReturnType_Int:
res->orgResult = malloc(sizeof(int));
res->newResult = malloc(sizeof(int));
*(int *)res->orgResult = 0;
break;
case ReturnType_Bool:
res->orgResult = malloc(sizeof(bool));
res->newResult = malloc(sizeof(bool));
*(bool *)res->orgResult = false;
break;
case ReturnType_Float:
res->orgResult = malloc(sizeof(float));
res->newResult = malloc(sizeof(float));
*(float *)res->orgResult = 0.0;
break;
}
}
return res;
}
cell_t GetThisPtr(void *iface, ThisPointerType type)
{
if(type == ThisPointer_CBaseEntity)
{
return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
}
return (cell_t)iface;
}
#ifdef WIN32
void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep)
#else
void *Callback(DHooksCallback *dg, void **argStack)
#endif
{
HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL;
Handle_t rHndl;
Handle_t pHndl;
#ifdef WIN32
*argsizep = GetStackArgsSize(dg);
#else
size_t argsize = GetStackArgsSize(dg);
#endif
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
}
if(dg->returnType != ReturnType_Void)
{
returnStruct = GetReturnStruct(dg);
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!rHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(rHndl);
}
#ifdef WIN32
if(*argsizep > 0)
{
paramStruct = GetParamStruct(dg, argStack, *argsizep);
#else
if(argsize > 0)
{
paramStruct = GetParamStruct(dg, argStack, argsize);
#endif
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!pHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
if(paramStruct)
{
delete paramStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(pHndl);
}
cell_t result = (cell_t)MRES_Ignored;
META_RES mres = MRES_IGNORED;
dg->plugin_callback->Execute(&result);
void *ret = g_SHPtr->GetOverrideRetPtr();
switch((MRESReturn)result)
{
case MRES_Handled:
case MRES_ChangedHandled:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
ret = CallVFunction<void *>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
if(dg->returnType == ReturnType_String || dg->returnType == ReturnType_Int || dg->returnType == ReturnType_Bool)
{
ret = *(void **)returnStruct->newResult;
}
else
{
ret = returnStruct->newResult;
}
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
break;
}
}
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
CallVFunction<void *>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_OVERRIDE);
mres = MRES_OVERRIDE;
if(dg->returnType == ReturnType_String || dg->returnType == ReturnType_Int || dg->returnType == ReturnType_Bool)
{
ret = *(void **)returnStruct->newResult;
}
else
{
ret = returnStruct->newResult;
}
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
case MRES_Supercede:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
if(dg->returnType == ReturnType_String || dg->returnType == ReturnType_Int || dg->returnType == ReturnType_Bool)
{
ret = *(void **)returnStruct->newResult;
}
else
{
ret = returnStruct->newResult;
}
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
else
{
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
}
break;
default:
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
break;
}
HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity());
if(returnStruct)
{
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
handlesys->FreeHandle(pHndl, &sec);
}
if(dg->returnType == ReturnType_Void || mres <= MRES_HANDLED)
{
return NULL;
}
return ret;
}
#ifdef WIN32
float Callback_float(DHooksCallback *dg, void **argStack, size_t *argsizep)
#else
float Callback_float(DHooksCallback *dg, void **argStack)
#endif
{
HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL;
Handle_t rHndl;
Handle_t pHndl;
#ifdef WIN32
*argsizep = GetStackArgsSize(dg);
#else
size_t argsize = GetStackArgsSize(dg);
#endif
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
}
returnStruct = GetReturnStruct(dg);
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!rHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return 0.0;
}
dg->plugin_callback->PushCell(rHndl);
#ifdef WIN32
if(*argsizep > 0)
{
paramStruct = GetParamStruct(dg, argStack, *argsizep);
#else
if(argsize > 0)
{
paramStruct = GetParamStruct(dg, argStack, argsize);
#endif
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!pHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
if(paramStruct)
{
delete paramStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return 0.0;
}
dg->plugin_callback->PushCell(pHndl);
}
cell_t result = (cell_t)MRES_Ignored;
META_RES mres = MRES_IGNORED;
dg->plugin_callback->Execute(&result);
void *ret = g_SHPtr->GetOverrideRetPtr();
switch((MRESReturn)result)
{
case MRES_Handled:
case MRES_ChangedHandled:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*(float *)ret = CallVFunction<float>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
*(float *)ret = *(float *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
break;
}
}
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
CallVFunction<float>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_OVERRIDE);
mres = MRES_OVERRIDE;
*(float *)ret = *(float *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
case MRES_Supercede:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*(float *)ret = *(float *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
default:
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
break;
}
HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity());
if(returnStruct)
{
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
handlesys->FreeHandle(pHndl, &sec);
}
if(dg->returnType == ReturnType_Void || mres <= MRES_HANDLED)
{
return 0.0;
}
return *(float *)ret;
}
#ifdef WIN32
SDKVector *Callback_vector(DHooksCallback *dg, void **argStack, size_t *argsizep)
#else
SDKVector *Callback_vector(DHooksCallback *dg, void **argStack)
#endif
{
SDKVector *vec_result = (SDKVector *)argStack[0]; // Save the result
HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL;
Handle_t rHndl;
Handle_t pHndl;
#ifdef WIN32
*argsizep = GetStackArgsSize(dg);
#else
size_t argsize = GetStackArgsSize(dg);
#endif
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
}
returnStruct = GetReturnStruct(dg);
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!rHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(rHndl);
#ifdef WIN32
if(*argsizep > 0)
{
paramStruct = GetParamStruct(dg, argStack, *argsizep);
#else
if(argsize > 0)
{
paramStruct = GetParamStruct(dg, argStack, argsize);
#endif
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!pHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
if(paramStruct)
{
delete paramStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(pHndl);
}
cell_t result = (cell_t)MRES_Ignored;
META_RES mres = MRES_IGNORED;
dg->plugin_callback->Execute(&result);
void *ret = g_SHPtr->GetOverrideRetPtr();
ret = vec_result;
switch((MRESReturn)result)
{
case MRES_Handled:
case MRES_ChangedHandled:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*vec_result = CallVFunction<SDKVector>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
*vec_result = **(SDKVector **)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
break;
}
}
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
CallVFunction<SDKVector>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_OVERRIDE);
mres = MRES_OVERRIDE;
*vec_result = **(SDKVector **)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
case MRES_Supercede:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*vec_result = **(SDKVector **)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
default:
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
break;
}
HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity());
if(returnStruct)
{
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
handlesys->FreeHandle(pHndl, &sec);
}
if(dg->returnType == ReturnType_Void || mres <= MRES_HANDLED)
{
vec_result->x = 0;
vec_result->y = 0;
vec_result->z = 0;
return vec_result;
}
return vec_result;
}
#ifndef WIN32
string_t *Callback_stringt(DHooksCallback *dg, void **argStack)
{
string_t *string_result = (string_t *)argStack[0]; // Save the result
HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL;
Handle_t rHndl;
Handle_t pHndl;
size_t argsize = GetStackArgsSize(dg);
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
}
returnStruct = GetReturnStruct(dg);
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!rHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(rHndl);
if(argsize > 0)
{
paramStruct = GetParamStruct(dg, argStack, argsize);
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
if(!pHndl)
{
dg->plugin_callback->Cancel();
if(returnStruct)
{
delete returnStruct;
}
if(paramStruct)
{
delete paramStruct;
}
g_SHPtr->SetRes(MRES_IGNORED);
return NULL;
}
dg->plugin_callback->PushCell(pHndl);
}
cell_t result = (cell_t)MRES_Ignored;
META_RES mres = MRES_IGNORED;
dg->plugin_callback->Execute(&result);
void *ret = g_SHPtr->GetOverrideRetPtr();
ret = string_result;
switch((MRESReturn)result)
{
case MRES_Handled:
case MRES_ChangedHandled:
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*string_result = CallVFunction<string_t>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_ChangedOverride:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
*string_result = *(string_t *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
break;
}
}
g_SHPtr->DoRecall();
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
CallVFunction<SDKVector>(dg, paramStruct, g_SHPtr->GetIfacePtr());
break;
case MRES_Override:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_OVERRIDE);
mres = MRES_OVERRIDE;
*string_result = *(string_t *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
case MRES_Supercede:
if(dg->returnType != ReturnType_Void)
{
if(returnStruct->isChanged)
{
g_SHPtr->SetRes(MRES_SUPERCEDE);
mres = MRES_SUPERCEDE;
*string_result = *(string_t *)returnStruct->newResult;
}
else //Throw an error if no override was set
{
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(dg->plugin_callback, "Tried to override return value without return value being set");
}
}
break;
default:
g_SHPtr->SetRes(MRES_IGNORED);
mres = MRES_IGNORED;
break;
}
HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity());
if(returnStruct)
{
handlesys->FreeHandle(rHndl, &sec);
}
if(paramStruct)
{
handlesys->FreeHandle(pHndl, &sec);
}
if(dg->returnType == ReturnType_Void || mres <= MRES_HANDLED)
{
*string_result = NULL_STRING;
return string_result;
}
return string_result;
}
#endif

345
extensions/dhooks/vhook.h Normal file
View File

@ -0,0 +1,345 @@
#ifndef _INCLUDE_VHOOK_H_
#define _INCLUDE_VHOOK_H_
#include "extension.h"
#include <sourcehook.h>
#include <sh_vector.h>
#include <macro-assembler.h>
#include <assembler-x86.h>
enum MRESReturn
{
MRES_ChangedHandled = -2, // Use changed values and return MRES_Handled
MRES_ChangedOverride, // Use changed values and return MRES_Override
MRES_Ignored, // plugin didn't take any action
MRES_Handled, // plugin did something, but real function should still be called
MRES_Override, // call real function, but use my return value
MRES_Supercede // skip real function; use my return value
};
enum ObjectValueType
{
ObjectValueType_Int = 0,
ObjectValueType_Bool,
ObjectValueType_Ehandle,
ObjectValueType_Float,
ObjectValueType_CBaseEntityPtr,
ObjectValueType_IntPtr,
ObjectValueType_BoolPtr,
ObjectValueType_EhandlePtr,
ObjectValueType_FloatPtr,
ObjectValueType_Vector,
ObjectValueType_VectorPtr,
ObjectValueType_CharPtr,
ObjectValueType_String
};
enum HookParamType
{
HookParamType_Unknown,
HookParamType_Int,
HookParamType_Bool,
HookParamType_Float,
HookParamType_String,
HookParamType_StringPtr,
HookParamType_CharPtr,
HookParamType_VectorPtr,
HookParamType_CBaseEntity,
HookParamType_ObjectPtr,
HookParamType_Edict,
HookParamType_Object
};
enum ReturnType
{
ReturnType_Unknown,
ReturnType_Void,
ReturnType_Int,
ReturnType_Bool,
ReturnType_Float,
ReturnType_String,
ReturnType_StringPtr,
ReturnType_CharPtr,
ReturnType_Vector,
ReturnType_VectorPtr,
ReturnType_CBaseEntity,
ReturnType_Edict
};
enum ThisPointerType
{
ThisPointer_Ignore,
ThisPointer_CBaseEntity,
ThisPointer_Address
};
enum HookType
{
HookType_Entity,
HookType_GameRules,
HookType_Raw
};
struct ParamInfo
{
HookParamType type;
size_t size;
unsigned int flags;
SourceHook::PassInfo::PassType pass_type;
};
class HookReturnStruct
{
public:
~HookReturnStruct()
{
if(this->type == ReturnType_String || this->type == ReturnType_Int || this->type == ReturnType_Bool || this->type == ReturnType_Float || this->type == ReturnType_Vector)
{
free(this->newResult);
free(this->orgResult);
}
else if(this->isChanged)
{
if(this->type == ReturnType_CharPtr)
{
delete [] (char *)this->newResult;
}
else if(this->type == ReturnType_VectorPtr)
{
delete (SDKVector *)this->newResult;
}
}
}
public:
ReturnType type;
bool isChanged;
void *orgResult;
void *newResult;
};
class DHooksInfo
{
public:
SourceHook::CVector<ParamInfo> params;
int offset;
unsigned int returnFlag;
ReturnType returnType;
bool post;
IPluginFunction *plugin_callback;
int entity;
ThisPointerType thisType;
HookType hookType;
};
class DHooksCallback : public SourceHook::ISHDelegate, public DHooksInfo
{
public:
virtual bool IsEqual(ISHDelegate *pOtherDeleg){return false;};
virtual void DeleteThis()
{
*(void ***)this = this->oldvtable;
g_pSM->GetScriptingEngine()->FreePageMemory(this->newvtable[2]);
delete this->newvtable;
delete this;
};
virtual void Call() {};
public:
void **newvtable;
void **oldvtable;
};
#ifdef WIN32
void *Callback(DHooksCallback *dg, void **stack, size_t *argsizep);
float Callback_float(DHooksCallback *dg, void **stack, size_t *argsizep);
SDKVector *Callback_vector(DHooksCallback *dg, void **stack, size_t *argsizep);
#else
void *Callback(DHooksCallback *dg, void **stack);
float Callback_float(DHooksCallback *dg, void **stack);
SDKVector *Callback_vector(DHooksCallback *dg, void **stack);
string_t *Callback_stringt(DHooksCallback *dg, void **stack);
#endif
bool SetupHookManager(ISmmAPI *ismm);
void CleanupHooks(IPluginContext *pContext = NULL);
size_t GetParamTypeSize(HookParamType type);
SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type);
#ifndef WIN32
static void *GenerateThunk(ReturnType type)
{
sp::MacroAssemblerX86 masm;
static const size_t kStackNeeded = (2) * 4; // 2 args max
static const size_t kReserve = ke::Align(kStackNeeded+8, 16)-8;
masm.push(ebp);
masm.movl(ebp, esp);
masm.subl(esp, kReserve);
if(type != ReturnType_String && type != ReturnType_Vector)
{
masm.lea(eax, Operand(ebp, 12)); // grab the incoming caller argument vector
masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
masm.movl(eax, Operand(ebp, 8)); // grab the |this|
masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
}
else
{
masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
masm.movl(eax, Operand(ebp, 12)); // grab the |this|
masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
}
if(type == ReturnType_Float)
{
masm.call(ExternalAddress((void *)Callback_float));
}
else if(type == ReturnType_Vector)
{
masm.call(ExternalAddress((void *)Callback_vector));
}
else if(type == ReturnType_String)
{
masm.call(ExternalAddress((void *)Callback_stringt));
}
else
{
masm.call(ExternalAddress((void *)Callback));
}
masm.addl(esp, kReserve);
masm.pop(ebp); // restore ebp
masm.ret();
void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length());
masm.emitToExecutableMemory(base);
return base;
}
#else
// HUGE THANKS TO BAILOPAN (dvander)!
static void *GenerateThunk(ReturnType type)
{
sp::MacroAssembler masm;
static const size_t kStackNeeded = (3 + 1) * 4; // 3 args max, 1 locals max
static const size_t kReserve = ke::Align(kStackNeeded+8, 16)-8;
masm.push(ebp);
masm.movl(ebp, esp);
masm.subl(esp, kReserve);
masm.lea(eax, Operand(esp, 3 * 4)); // ptr to 2nd var after argument space
masm.movl(Operand(esp, 2 * 4), eax); // set the ptr as the third argument
masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
masm.movl(Operand(esp, 0 * 4), ecx); // set |this| as the 1st argument
if(type == ReturnType_Float)
{
masm.call(ExternalAddress(Callback_float));
}
else if(type == ReturnType_Vector)
{
masm.call(ExternalAddress(Callback_vector));
}
else
{
masm.call(ExternalAddress(Callback));
}
masm.movl(ecx, Operand(esp, 3*4));
masm.addl(esp, kReserve);
masm.pop(ebp); // restore ebp
masm.pop(edx); // grab return address in edx
masm.addl(esp, ecx); // remove arguments
masm.jmp(edx); // return to caller
void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length());
masm.emitToExecutableMemory(base);
return base;
}
#endif
static DHooksCallback *MakeHandler(ReturnType type)
{
DHooksCallback *dg = new DHooksCallback();
dg->returnType = type;
dg->oldvtable = *(void ***)dg;
dg->newvtable = new void *[3];
dg->newvtable[0] = dg->oldvtable[0];
dg->newvtable[1] = dg->oldvtable[1];
dg->newvtable[2] = GenerateThunk(type);
*(void ***)dg = dg->newvtable;
return dg;
}
class HookParamsStruct
{
public:
HookParamsStruct()
{
this->orgParams = NULL;
this->newParams = NULL;
this->dg = NULL;
this->isChanged = NULL;
}
~HookParamsStruct();
public:
void **orgParams;
void **newParams;
bool *isChanged;
DHooksCallback *dg;
};
class HookSetup
{
public:
HookSetup(ReturnType returnType, unsigned int returnFlag, HookType hookType, ThisPointerType thisType, int offset, IPluginFunction *callback)
{
this->returnType = returnType;
this->returnFlag = returnFlag;
this->hookType = hookType;
this->thisType = thisType;
this->offset = offset;
this->callback = callback;
};
~HookSetup(){};
public:
unsigned int returnFlag;
ReturnType returnType;
HookType hookType;
ThisPointerType thisType;
SourceHook::CVector<ParamInfo> params;
int offset;
IPluginFunction *callback;
};
class DHooksManager
{
public:
DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, IPluginFunction *plugincb, bool post);
~DHooksManager()
{
if(this->hookid)
{
g_SHPtr->RemoveHookByID(this->hookid);
if(this->remove_callback)
{
this->remove_callback->PushCell(this->hookid);
this->remove_callback->Execute(NULL);
}
if(this->pManager)
{
g_pHookManager->ReleaseHookMan(this->pManager);
}
}
}
public:
intptr_t addr;
int hookid;
DHooksCallback *callback;
IPluginFunction *remove_callback;
SourceHook::HookManagerPubFunc pManager;
};
size_t GetStackArgsSize(DHooksCallback *dg);
extern IBinTools *g_pBinTools;
extern HandleType_t g_HookParamsHandle;
extern HandleType_t g_HookReturnHandle;
#endif

487
plugins/include/dhooks.inc Normal file
View File

@ -0,0 +1,487 @@
#if defined _dhooks_included
#endinput
#endif
#define _dhooks_included
enum ObjectValueType
{
ObjectValueType_Int = 0,
ObjectValueType_Bool,
ObjectValueType_Ehandle,
ObjectValueType_Float,
ObjectValueType_CBaseEntityPtr,
ObjectValueType_IntPtr,
ObjectValueType_BoolPtr,
ObjectValueType_EhandlePtr,
ObjectValueType_FloatPtr,
ObjectValueType_Vector,
ObjectValueType_VectorPtr,
ObjectValueType_CharPtr,
ObjectValueType_String
};
enum ListenType
{
ListenType_Created,
ListenType_Deleted
};
enum ReturnType
{
ReturnType_Unknown,
ReturnType_Void,
ReturnType_Int,
ReturnType_Bool,
ReturnType_Float,
ReturnType_String, //Note this is a string_t
ReturnType_StringPtr, //Note this is a string_t *
ReturnType_CharPtr,
ReturnType_Vector,
ReturnType_VectorPtr,
ReturnType_CBaseEntity,
ReturnType_Edict
};
enum HookParamType
{
HookParamType_Unknown,
HookParamType_Int,
HookParamType_Bool,
HookParamType_Float,
HookParamType_String, //Note this is a string_t
HookParamType_StringPtr, //Note this is a string_t *
HookParamType_CharPtr,
HookParamType_VectorPtr,
HookParamType_CBaseEntity,
HookParamType_ObjectPtr,
HookParamType_Edict,
HookParamType_Object
};
enum ThisPointerType
{
ThisPointer_Ignore,
ThisPointer_CBaseEntity,
ThisPointer_Address
};
enum HookType
{
HookType_Entity,
HookType_GameRules,
HookType_Raw
};
enum MRESReturn
{
MRES_ChangedHandled = -2, // Use changed values and return MRES_Handled
MRES_ChangedOverride, // Use changed values and return MRES_Override
MRES_Ignored, // plugin didn't take any action
MRES_Handled, // plugin did something, but real function should still be called
MRES_Override, // call real function, but use my return value
MRES_Supercede // skip real function; use my return value
};
enum DHookPassFlag
{
DHookPass_ByVal = (1<<0), /**< Passing by value */
DHookPass_ByRef = (1<<1), /**< Passing by reference */
DHookPass_ODTOR = (1<<2), /**< Object has a destructor */
DHookPass_OCTOR = (1<<3), /**< Object has a constructor */
DHookPass_OASSIGNOP = (1<<4), /**< Object has an assignment operator */
};
typeset ListenCB
{
//Deleted
function void (int entity);
//Created
function void (int entity, const char[] classname);
};
typeset DHookRemovalCB
{
function void (int hookid);
};
typeset DHookCallback
{
//Function Example: void Ham::Test() with this pointer ignore
function MRESReturn ();
//Function Example: void Ham::Test() with this pointer passed
function MRESReturn (int pThis);
//Function Example: void Ham::Test(int cake) with this pointer ignore
function MRESReturn (Handle hParams);
//Function Example: void Ham::Test(int cake) with this pointer passed
function MRESReturn (int pThis, Handle hParams);
//Function Example: int Ham::Test() with this pointer ignore
function MRESReturn (Handle hReturn);
//Function Example: int Ham::Test() with this pointer passed
function MRESReturn (int pThis, Handle hReturn);
//Function Example: int Ham::Test(int cake) with this pointer ignore
function MRESReturn (Handle hReturn, Handle hParams);
//Function Example: int Ham::Test(int cake) with this pointer passed
function MRESReturn (int pThis, Handle hReturn, Handle hParams);
//Address NOW
//Function Example: void Ham::Test() with this pointer passed
function MRESReturn (Address pThis);
//Function Example: void Ham::Test(int cake) with this pointer passed
function MRESReturn (Address pThis, Handle hParams);
//Function Example: int Ham::Test() with this pointer passed
function MRESReturn (Address pThis, Handle hReturn);
//Function Example: int Ham::Test(int cake) with this pointer passed
function MRESReturn (Address pThis, Handle hReturn, Handle hParams);
};
/* Adds an entity listener hook
*
* @param type Type of listener to add
* @param callback Callback to use
*
* @noreturn
*/
native void DHookAddEntityListener(ListenType type, ListenCB callback);
/* Removes an entity listener hook
*
* @param type Type of listener to remove
* @param callback Callback this listener was using
*
* @return True if one was removed false otherwise.
*/
native bool DHookRemoveEntityListener(ListenType type, ListenCB callback);
/* Creates a hook
*
* @param offset vtable offset for function to hook
* @param hooktype Type of hook
* @param returntype Type type of return
* @param thistype Type of this pointer or ignore (ignore can be used if not needed)
* @param callback Optional callback function, if not set here must be set when hooking.
*
* @return Returns setup handle for the hook or INVALID_HANDLE.
*/
native Handle DHookCreate(int offset, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback=INVALID_FUNCTION);
/* Adds param to a hook setup
*
* @param setup Setup handle to add the param to.
* @param type Param type
* @param size Used for Objects (not Object ptr) to define the size of the object.
* @param flag Used to change the pass type.
*
* @error Invalid setup handle or too many params added (request upping the max in thread)
* @noreturn
*/
native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal);
/* Hook entity
*
* @param setup Setup handle to use to add the hook.
* @param post True to make the hook a post hook. (If you need to change the retunr value or need the return value use a post hook! If you need to change params and return use a pre and post hook!)
* @param entity Entity index to hook on.
* @param removalcb Callback for when the hook is removed (Entity hooks are auto-removed on entity destroyed and will call this callback)
* @param callback Optional callback function, if not set here must be set when creating the hook.
*
* @error Invalid setup handle, invalid address, invalid hook type or invalid callback.
* @return -1 on fail a hookid on success
*/
native int DHookEntity(Handle setup, bool post, int entity, DHookRemovalCB removalcb=INVALID_FUNCTION, DHookCallback callback=INVALID_FUNCTION);
/* Hook gamerules
*
* @param setup Setup handle to use to add the hook.
* @param post True to make the hook a post hook. (If you need to change the retunr value or need the return value use a post hook! If you need to change params and return use a pre and post hook!)
* @param removalcb Callback for when the hook is removed (Game rules hooks are auto-removed on map end and will call this callback)
* @param callback Optional callback function, if not set here must be set when creating the hook.
*
* @error Invalid setup handle, invalid address, invalid hook type or invalid callback.
* @return -1 on fail a hookid on success
*/
native int DHookGamerules(Handle setup, bool post, DHookRemovalCB removalcb=INVALID_FUNCTION, DHookCallback callback=INVALID_FUNCTION);
/* Hook a raw pointer
*
* @param setup Setup handle to use to add the hook.
* @param post True to make the hook a post hook. (If you need to change the retunr value or need the return value use a post hook! If you need to change params and return use a pre and post hook!)
* @param addr This pointer address.
* @param removalcb Callback for when the hook is removed (Entity hooks are auto-removed on entity destroyed and will call this callback)
* @param callback Optional callback function, if not set here must be set when creating the hook.
*
* @error Invalid setup handle, invalid address, invalid hook type or invalid callback.
* @return -1 on fail a hookid on success
*/
native int DHookRaw(Handle setup, bool post, Address addr, DHookRemovalCB removalcb=INVALID_FUNCTION, DHookCallback callback=INVALID_FUNCTION);
/* Remove hook by hook id
*
* @param hookid Hook id to remove
*
* @return true on success false otherwise
* @note This will not fire the removal callback!
*/
native bool DHookRemoveHookID(int hookid);
/* Get param value (Only use for: int, entity, bool or float param types)
*
* @param hParams Handle to params structure
* @param num Param number to get. (Example if the function has 2 params and you need the value of the first param num would be 1. 0 Will return the number of params stored)
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @return value if num greater than 0. If 0 returns paramcount.
*/
native any DHookGetParam(Handle hParams, int num);
/* Get vector param value
*
* @param hParams Handle to params structure
* @param num Param number to get. (Example if the function has 2 params and you need the value of the first param num would be 1.)
* @param vec Vector buffer to store result.
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookGetParamVector(Handle hParams, int num, float vec[3]);
/* Get string param value
*
* @param hParams Handle to params structure
* @param num Param number to get. (Example if the function has 2 params and you need the value of the first param num would be 1.)
* @param buffer String buffer to store result
* @param size Buffer size
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookGetParamString(Handle hParams, int num, char[] buffer, int size);
/* Set param value (Only use for: int, entity, bool or float param types)
*
* @param hParams Handle to params structure
* @params num Param number to set (Example if the function has 2 params and you need to set the value of the first param num would be 1.)
* @param value Value to set it as (only pass int, bool, float or entity index)
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookSetParam(Handle hParams, int num, any value);
/* Set vector param value
*
* @param hParams Handle to params structure
* @params num Param number to set (Example if the function has 2 params and you need to set the value of the first param num would be 1.)
* @param vec Value to set vector as.
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookSetParamVector(Handle hParams, int num, float vec[3]);
/* Set string param value
*
* @param hParams Handle to params structure
* @params num Param number to set (Example if the function has 2 params and you need to set the value of the first param num would be 1.)
* @param value Value to set string as.
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookSetParamString(Handle hParams, int num, char[] value);
/* Get return value (Only use for: int, entity, bool or float return types)
*
* @param hReturn Handle to return structure
*
* @error Invalid Handle, invalid type.
* @return Returns default value if prehook returns actual value if post hook.
*/
native any DHookGetReturn(Handle hReturn);
/* Get return vector value
*
* @param hReturn Handle to return structure
* @param vec Vector buffer to store result in. (In pre hooks will be default value (0.0,0.0,0.0))
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookGetReturnVector(Handle hReturn, float vec[3]);
/* Get return string value
*
* @param hReturn Handle to return structure
* @param buffer String buffer to store result in. (In pre hooks will be default value "")
* @param size String buffer size
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookGetReturnString(Handle hReturn, char[] buffer, int size);
/* Set return value (Only use for: int, entity, bool or float return types)
*
* @param hReturn Handle to return structure
* @param value Value to set return as
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookSetReturn(Handle hReturn, any value);
/* Set return vector value
*
* @param hReturn Handle to return structure
* @param vec Value to set return vector as
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookSetReturnVector(Handle hReturn, float vec[3]);
/* Set return string value
*
* @param hReturn Handle to return structure
* @param value Value to set return string as
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookSetReturnString(Handle hReturn, char[] value);
//WE SHOULD WRAP THESE AROUND STOCKS FOR NON PTR AS WE SUPPORT BOTH WITH THESE NATIVE'S
/* Gets an objects variable value
*
* @param hParams Handle to params structure
* @param num Param number to get.
* @param offset Offset within the object to the var to get.
* @param type Type of var it is
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @return Value of the objects var. If EHANDLE type or entity returns entity index.
*/
native any DHookGetParamObjectPtrVar(Handle hParams, int num, int offset, ObjectValueType type);
/* Sets an objects variable value
*
* @param hParams Handle to params structure
* @param num Param number to set.
* @param offset Offset within the object to the var to set.
* @param type Type of var it is
* @param value The value to set the var to.
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @noreturn
*/
native void DHookSetParamObjectPtrVar(Handle hParams, int num, int offset, ObjectValueType type, any value);
/* Gets an objects vector variable value
*
* @param hParams Handle to params structure
* @param num Param number to get.
* @param offset Offset within the object to the var to get.
* @param type Type of var it is
* @param buffer Buffer to store the result vector
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @noreturn
*/
native void DHookGetParamObjectPtrVarVector(Handle hParams, int num, int offset, ObjectValueType type, float buffer[3]);
/* Sets an objects vector variable value
*
* @param hParams Handle to params structure
* @param num Param number to set.
* @param offset Offset within the object to the var to set.
* @param type Type of var it is
* @param value The value to set the vector var to.
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @noreturn
*/
native void DHookSetParamObjectPtrVarVector(Handle hParams, int num, int offset, ObjectValueType type, float value[3]);
/* Gets an objects string variable value
*
* @param hParams Handle to params structure
* @param num Param number to get.
* @param offset Offset within the object to the var to get.
* @param type Type of var it is
* @param buffer Buffer to store the result vector
* @param size Size of the buffer
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @noreturn
*/
native void DHookGetParamObjectPtrString(Handle hParams, int num, int offset, ObjectValueType type, char[] buffer, int size);
/* Checks if a pointer param is null
*
* @param hParams Handle to params structure
* @param num Param number to check.
*
* @error Non pointer param
* @return True if null false otherwise.
*/
native bool DHookIsNullParam(Handle hParams, int num);
public Extension __ext_dhooks =
{
name = "dhooks",
file = "dhooks.ext",
#if defined AUTOLOAD_EXTENSIONS
autoload = 1,
#else
autoload = 0,
#endif
#if defined REQUIRE_EXTENSIONS
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_EXTENSIONS
public __ext_dhooks_SetNTVOptional()
{
MarkNativeAsOptional("DHookAddEntityListener");
MarkNativeAsOptional("DHookRemoveEntityListener");
MarkNativeAsOptional("DHookCreate");
MarkNativeAsOptional("DHookAddParam");
MarkNativeAsOptional("DHookEntity");
MarkNativeAsOptional("DHookGamerules");
MarkNativeAsOptional("DHookRaw");
MarkNativeAsOptional("DHookRemoveHookID");
MarkNativeAsOptional("DHookGetParam");
MarkNativeAsOptional("DHookGetParamVector");
MarkNativeAsOptional("DHookGetParamString");
MarkNativeAsOptional("DHookSetParam");
MarkNativeAsOptional("DHookSetParamVector");
MarkNativeAsOptional("DHookSetParamString");
MarkNativeAsOptional("DHookGetReturn");
MarkNativeAsOptional("DHookGetReturnVector");
MarkNativeAsOptional("DHookGetReturnString");
MarkNativeAsOptional("DHookSetReturn");
MarkNativeAsOptional("DHookSetReturnVector");
MarkNativeAsOptional("DHookSetReturnString");
MarkNativeAsOptional("DHookGetParamObjectPtrVar");
MarkNativeAsOptional("DHookSetParamObjectPtrVar");
MarkNativeAsOptional("DHookGetParamObjectPtrVarVector");
MarkNativeAsOptional("DHookSetParamObjectPtrVarVector");
MarkNativeAsOptional("DHookIsNullParam");
MarkNativeAsOptional("DHookGetParamObjectPtrString");
}
#endif