Update code add natives and listeners
This commit is contained in:
parent
f9af5e9017
commit
2f38de616e
7
Makefile
7
Makefile
@ -5,7 +5,7 @@
|
||||
### EDIT THESE PATHS FOR YOUR OWN SETUP ###
|
||||
###########################################
|
||||
|
||||
SMSDK = ../sourcemod-1.5
|
||||
SMSDK = ../sourcemod-central
|
||||
HL2SDK_ORIG = ../../../hl2sdk
|
||||
HL2SDK_OB = ../../../hl2sdk-ob
|
||||
HL2SDK_CSS = ../hl2sdk-css
|
||||
@ -24,7 +24,7 @@ PROJECT = sample
|
||||
#Uncomment for Metamod: Source enabled extension
|
||||
USEMETA = true
|
||||
|
||||
OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp
|
||||
OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp ../sourcemod-central/public/jit/x86/assembler-x86.cpp
|
||||
|
||||
##############################################
|
||||
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
||||
@ -109,7 +109,7 @@ else
|
||||
LIB_SUFFIX = .$(LIB_EXT)
|
||||
endif
|
||||
|
||||
INCLUDE += -I. -I.. -Isdk -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions
|
||||
INCLUDE += -I. -I.. -Isdk -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions -I$(SMSDK)/public/jit/x86 -I$(SMSDK)/public/jit
|
||||
|
||||
ifeq "$(USEMETA)" "true"
|
||||
LINK_HL2 = $(HL2LIB)/tier1_i486.a $(HL2LIB)/$(LIB_PREFIX)vstdlib_srv$(LIB_SUFFIX) $(HL2LIB)/$(LIB_PREFIX)tier0_srv$(LIB_SUFFIX)
|
||||
@ -205,6 +205,7 @@ $(BIN_DIR)/%.o: %.cpp
|
||||
|
||||
all: check
|
||||
mkdir -p $(BIN_DIR)/sdk
|
||||
mkdir -p $(BIN_DIR)/../sourcemod-central/public/jit/x86
|
||||
if [ "$(USEMETA)" = "true" ]; then \
|
||||
ln -sf $(HL2LIB)/$(LIB_PREFIX)vstdlib$(LIB_SUFFIX); \
|
||||
ln -sf $(HL2LIB)/$(LIB_PREFIX)tier0$(LIB_SUFFIX); \
|
||||
|
137
extension.cpp
137
extension.cpp
@ -1,41 +1,101 @@
|
||||
#include "extension.h"
|
||||
#include "vhook.h"
|
||||
#include "listeners.h"
|
||||
#include <macro-assembler-x86.h>
|
||||
|
||||
DHooks g_Sample; /**< Global singleton for extension's main interface */
|
||||
SMEXT_LINK(&g_Sample);
|
||||
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;
|
||||
|
||||
CBitVec<NUM_ENT_ENTRIES> m_EntityExists;
|
||||
bool g_bAllowGamerules = true;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
if(g_pSDKTools == NULL)
|
||||
{
|
||||
smutils->LogError(myself, "SDKTools interface not found. DHookGamerules native disabled.");
|
||||
}
|
||||
else if(g_pSDKTools->GetInterfaceVersion() < 2)
|
||||
|
||||
if(g_pSDKTools->GetInterfaceVersion() < 2)
|
||||
{
|
||||
//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
|
||||
g_bAllowGamerules = false;
|
||||
smutils->LogError(myself, "SDKTools interface is outdated. DHookGamerules native disabled.");
|
||||
}
|
||||
|
||||
SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
|
||||
SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks);
|
||||
g_pSDKHooks->AddEntityListener(this);
|
||||
|
||||
g_pEntityListener = new DHooksEntityListener();
|
||||
g_pSDKHooks->AddEntityListener(g_pEntityListener);
|
||||
}
|
||||
|
||||
void DHooks::SDK_OnUnload()
|
||||
{
|
||||
CleanupHooks(NULL);
|
||||
if(g_pEntityListener)
|
||||
{
|
||||
g_pEntityListener->CleanupListeners(NULL);
|
||||
g_pSDKHooks->RemoveEntityListener(g_pEntityListener);
|
||||
delete g_pEntityListener;
|
||||
}
|
||||
plsys->RemovePluginsListener(this);
|
||||
}
|
||||
|
||||
bool DHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late)
|
||||
{
|
||||
if(!SetupHookManager(ismm))
|
||||
@ -45,61 +105,12 @@ bool DHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, boo
|
||||
}
|
||||
return true;
|
||||
}
|
||||
DHooksManager *manager1;
|
||||
DHooksManager *manager2;
|
||||
|
||||
#ifndef __linux__
|
||||
#define WEAPON_CANUSE 258
|
||||
#define SET_MODEL 24
|
||||
#else
|
||||
#define WEAPON_CANUSE 259
|
||||
#define SET_MODEL 25
|
||||
#endif
|
||||
|
||||
void DHooks::OnEntityCreated(CBaseEntity *pEntity, const char *classname)
|
||||
void DHooks::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
int entity = gamehelpers->ReferenceToIndex(gamehelpers->EntityToBCompatRef(pEntity));
|
||||
|
||||
if(entity <= playerhelpers->GetMaxClients() && entity > 0)
|
||||
{
|
||||
SourceHook::HookManagerPubFunc hook;
|
||||
SourceHook::CProtoInfoBuilder protoInfo(SourceHook::ProtoInfo::CallConv_ThisCall);
|
||||
protoInfo.AddParam(sizeof(CBaseEntity *), SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal, NULL, NULL, NULL, NULL);
|
||||
protoInfo.SetReturnType(sizeof(bool), SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal, NULL, NULL, NULL, NULL);
|
||||
hook = g_pHookManager->MakeHookMan(protoInfo, 0, WEAPON_CANUSE);
|
||||
manager1 = new DHooksManager();
|
||||
manager1->callback_bool = new DHooksCallback<bool>();
|
||||
manager1->callback_bool->paramcount = 1;
|
||||
manager1->callback_bool->params[0].size = sizeof(CBaseEntity *);
|
||||
manager1->callback_bool->params[0].type = HookParamType_CBaseEntity;
|
||||
manager1->callback_bool->params[0].flag = PASSFLAG_BYVAL;
|
||||
manager1->callback_bool->offset = WEAPON_CANUSE;
|
||||
manager1->hookid = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, pEntity, 0, hook, manager1->callback_bool, false);
|
||||
|
||||
SourceHook::CProtoInfoBuilder protoInfo2(SourceHook::ProtoInfo::CallConv_ThisCall);
|
||||
protoInfo2.AddParam(sizeof(char *), SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal, NULL, NULL, NULL, NULL);
|
||||
protoInfo2.SetReturnType(0, SourceHook::PassInfo::PassType_Unknown, 0, NULL, NULL, NULL, NULL);
|
||||
hook = g_pHookManager->MakeHookMan(protoInfo2, 0, SET_MODEL);
|
||||
manager2 = new DHooksManager();
|
||||
manager2->callback_void = new DHooksCallback<void>();
|
||||
manager2->callback_void->paramcount = 1;
|
||||
manager2->callback_void->params[0].size = sizeof(char *);
|
||||
manager2->callback_void->params[0].type = HookParamType_CharPtr;
|
||||
manager2->callback_void->params[0].flag = PASSFLAG_BYVAL;
|
||||
manager2->callback_void->offset = SET_MODEL;
|
||||
manager2->hookid = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, pEntity, 0, hook, manager2->callback_void, false);
|
||||
|
||||
META_CONPRINTF("Hooked entity %i\n", entity);
|
||||
CleanupHooks(plugin->GetBaseContext());
|
||||
if(g_pEntityListener)
|
||||
{
|
||||
g_pEntityListener->CleanupListeners(plugin->GetBaseContext());
|
||||
}
|
||||
}
|
||||
void DHooks::OnEntityDestroyed(CBaseEntity *pEntity)
|
||||
{
|
||||
int entity = gamehelpers->ReferenceToIndex(gamehelpers->EntityToBCompatRef(pEntity));
|
||||
|
||||
if(entity <= playerhelpers->GetMaxClients() && entity > 0)
|
||||
{
|
||||
META_CONPRINTF("Cleaning\n");
|
||||
delete manager1;
|
||||
delete manager2;
|
||||
}
|
||||
}
|
12
extension.h
12
extension.h
@ -48,12 +48,13 @@
|
||||
* Note: Uncomment one of the pre-defined virtual functions in order to use it.
|
||||
*/
|
||||
|
||||
class DHooks : public SDKExtension, public ISMEntityListener
|
||||
class DHooks : public SDKExtension, public ISMEntityListener, public IPluginsListener, public IHandleTypeDispatch
|
||||
{
|
||||
public:
|
||||
void OnEntityCreated(CBaseEntity *pEntity, const char *classname);
|
||||
void OnEntityDestroyed(CBaseEntity *pEntity);
|
||||
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
public: //IPluginsListener
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
public:
|
||||
/**
|
||||
* @brief This is called after the initial loading sequence has been processed.
|
||||
*
|
||||
@ -67,7 +68,7 @@ public:
|
||||
/**
|
||||
* @brief This is called right before the extension is unloaded.
|
||||
*/
|
||||
//virtual void SDK_OnUnload();
|
||||
virtual void SDK_OnUnload();
|
||||
|
||||
/**
|
||||
* @brief This is called once all known extensions have been loaded.
|
||||
@ -123,4 +124,5 @@ public:
|
||||
#endif
|
||||
};
|
||||
extern SourceHook::IHookManagerAutoGen *g_pHookManager;
|
||||
extern sp_nativeinfo_t g_Natives[];
|
||||
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||
|
61
listeners.cpp
Normal file
61
listeners.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include "listeners.h"
|
||||
#include "vhook.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
CUtlVector<EntityListener> g_EntityListeners;
|
||||
|
||||
void DHooksEntityListener::CleanupListeners(IPluginContext *pContext)
|
||||
{
|
||||
for(int i = g_EntityListeners.Count() -1; i >= 0; i--)
|
||||
{
|
||||
if(pContext == NULL || pContext == g_EntityListeners.Element(i).callback->GetParentContext())
|
||||
{
|
||||
g_EntityListeners.Remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DHooksEntityListener::OnEntityCreated(CBaseEntity *pEntity, const char *classname)
|
||||
{
|
||||
int entity = gamehelpers->EntityToBCompatRef(pEntity);
|
||||
|
||||
for(int i = g_EntityListeners.Count() -1; i >= 0; i--)
|
||||
{
|
||||
EntityListener listerner = g_EntityListeners.Element(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.Count() -1; i >= 0; i--)
|
||||
{
|
||||
EntityListener listerner = g_EntityListeners.Element(i);
|
||||
if(listerner.type == ListenType_Deleted)
|
||||
{
|
||||
IPluginFunction *callback = listerner.callback;
|
||||
callback->PushCell(gamehelpers->EntityToBCompatRef(pEntity));
|
||||
callback->Execute(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = g_pHooks.Count() -1; i >= 0; i--)
|
||||
{
|
||||
DHooksManager *manager = g_pHooks.Element(i);
|
||||
if(manager->callback->entity == entity)
|
||||
{
|
||||
META_CONPRINT("Removing 1\n");
|
||||
delete manager;
|
||||
g_pHooks.Remove(i);
|
||||
}
|
||||
}
|
||||
}
|
28
listeners.h
Normal file
28
listeners.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef _INCLUDE_FORWARDS_H_
|
||||
#define _INCLUDE_FORWARDS_H_
|
||||
|
||||
#include "extension.h"
|
||||
#include "vhook.h"
|
||||
|
||||
class DHooksEntityListener : public ISMEntityListener
|
||||
{
|
||||
public:
|
||||
void OnEntityCreated(CBaseEntity *pEntity, const char *classname);
|
||||
void OnEntityDestroyed(CBaseEntity *pEntity);
|
||||
void CleanupListeners(IPluginContext *func);
|
||||
};
|
||||
|
||||
enum ListenType
|
||||
{
|
||||
ListenType_Created,
|
||||
ListenType_Deleted
|
||||
};
|
||||
|
||||
struct EntityListener
|
||||
{
|
||||
ListenType type;
|
||||
IPluginFunction *callback;
|
||||
};
|
||||
|
||||
extern CUtlVector<DHooksManager *> g_pHooks;
|
||||
#endif
|
@ -599,7 +599,7 @@
|
||||
<ClCompile>
|
||||
<AdditionalOptions>/MP /D SE_EPISODEONE=1 /D SE_DARKMESSIAH=2 /D SE_ORANGEBOX=3 /D SE_BLOODYGOODTIME=4 /D SE_EYE=5 /D SE_ORANGEBOXVALVE=6 /D SE_LEFT4DEAD=7 /D SE_LEFT4DEAD2=8 /D SE_ALIENSWARM=9 /D SE_PORTAL2=10 /D SE_CSGO=11 %(AdditionalOptions)</AdditionalOptions>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>..;..\sdk;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(MMSOURCE19)\core;$(MMSOURCE19)\core\sourcehook;$(SOURCEMOD)\public;$(SOURCEMOD)\public\sourcepawn;$(SOURCEMOD)\public\extensions;$(HL2SDKOBVALVE)\game\server;$(HL2SDKOBVALVE)\game\shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..;..\sdk;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(MMSOURCE19)\core;$(MMSOURCE19)\core\sourcehook;$(SMCENTRAL)\public;$(SMCENTRAL)\public\sourcepawn;$(SMCENTRAL)\public\extensions;$(HL2SDKOBVALVE)\game\server;$(HL2SDKOBVALVE)\game\shared;$(SMCENTRAL)\public\jit;$(SMCENTRAL)\public\jit\x86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;SOURCE_ENGINE=6;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||
@ -610,7 +610,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(HL2SDKOBVALVE)\lib\public\tier0.lib;$(HL2SDKOBVALVE)\lib\public\tier1.lib;$(HL2SDKOBVALVE)\lib\public\vstdlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)sample.ext.2.css.dll</OutputFile>
|
||||
<OutputFile>$(OutDir)dhooks.ext.2.css.dll</OutputFile>
|
||||
<IgnoreSpecificDefaultLibraries>LIBC;LIBCD;LIBCMTD;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -882,12 +882,17 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\sourcemod-central\public\jit\x86\assembler-x86.cpp" />
|
||||
<ClCompile Include="..\extension.cpp" />
|
||||
<ClCompile Include="..\listeners.cpp" />
|
||||
<ClCompile Include="..\natives.cpp" />
|
||||
<ClCompile Include="..\vhook.cpp" />
|
||||
<ClCompile Include="..\sdk\smsdk_ext.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\extension.h" />
|
||||
<ClInclude Include="..\listeners.h" />
|
||||
<ClInclude Include="..\natives.h" />
|
||||
<ClInclude Include="..\vhook.h" />
|
||||
<ClInclude Include="..\sdk\smsdk_config.h" />
|
||||
<ClInclude Include="..\sdk\smsdk_ext.h" />
|
||||
|
@ -6,6 +6,11 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\vhook.cpp" />
|
||||
<ClCompile Include="..\extension.cpp" />
|
||||
<ClCompile Include="..\..\..\sourcemod-central\public\jit\x86\assembler-x86.cpp">
|
||||
<Filter>JIT</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\natives.cpp" />
|
||||
<ClCompile Include="..\listeners.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\extension.h">
|
||||
@ -23,6 +28,12 @@
|
||||
<ClInclude Include="..\vhook_macros.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\natives.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\listeners.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Headers">
|
||||
@ -31,5 +42,8 @@
|
||||
<Filter Include="sdk">
|
||||
<UniqueIdentifier>{8a0b4570-752f-44d9-b270-ef886743e9ea}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="JIT">
|
||||
<UniqueIdentifier>{9ac7d92a-8a9d-4e7c-b108-09d915244278}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
252
natives.cpp
Normal file
252
natives.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
#include "natives.h"
|
||||
|
||||
CBaseEntity *UTIL_GetCBaseEntity(int num)
|
||||
{
|
||||
edict_t *pEdict = gamehelpers->EdictOfIndex(num);
|
||||
if (!pEdict || pEdict->IsFree())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
IServerUnknown *pUnk;
|
||||
if ((pUnk=pEdict->GetUnknown()) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pUnk->GetBaseEntity();
|
||||
}
|
||||
|
||||
//native Handle:DHookCreate(offset, HookType:hooktype, ReturnType:returntype, ThisPointerType:thistype, DHookCallback:callback);
|
||||
cell_t Native_CreateHook(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if(!pContext->GetFunctionById(params[5]))
|
||||
{
|
||||
return pContext->ThrowNativeError("Failed to retrieve function by id");
|
||||
}
|
||||
|
||||
HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL,(HookType)params[2], (ThisPointerType)params[4], params[1], pContext->GetFunctionById(params[5]));
|
||||
|
||||
Handle_t hndl = handlesys->CreateHandle(g_HookSetupHandle, setup, pContext->GetIdentity(), myself->GetIdentity(), NULL);
|
||||
|
||||
if(!hndl)
|
||||
{
|
||||
delete setup;
|
||||
return pContext->ThrowNativeError("Failed to create hook");
|
||||
}
|
||||
|
||||
return hndl;
|
||||
}
|
||||
//native bool:DHookAddParam(Handle:setup, HookParamType:type);
|
||||
cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if(params[1] == BAD_HANDLE)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %i", BAD_HANDLE);
|
||||
}
|
||||
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
HookSetup *setup;
|
||||
|
||||
if((err = handlesys->ReadHandle(params[1], g_HookSetupHandle, &sec, (void **)&setup)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
|
||||
}
|
||||
ParamInfo info;
|
||||
|
||||
if(params[0] == 3)
|
||||
{
|
||||
info.flag = params[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
info.flag = PASSFLAG_BYVAL;
|
||||
}
|
||||
|
||||
info.type = (HookParamType)params[2];
|
||||
info.size = GetParamTypeSize(info.type);
|
||||
info.pass_type = GetParamTypePassType(info.type);
|
||||
setup->params.AddToTail(info);
|
||||
|
||||
return 1;
|
||||
}
|
||||
cell_t Native_HookEntity(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if(params[1] == BAD_HANDLE)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %i", BAD_HANDLE);
|
||||
}
|
||||
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
HookSetup *setup;
|
||||
|
||||
if((err = handlesys->ReadHandle(params[1], g_HookSetupHandle, &sec, (void **)&setup)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
|
||||
}
|
||||
if(setup->hookType != HookType_Entity)
|
||||
{
|
||||
return pContext->ThrowNativeError("Hook is not an entity hook");
|
||||
}
|
||||
bool post = params[2] != 0;
|
||||
|
||||
for(int i = g_pHooks.Count() -1; i >= 0; i--)
|
||||
{
|
||||
if(g_pHooks.Element(i)->callback->hookType == HookType_Entity && g_pHooks.Element(i)->callback->entity == params[3] && g_pHooks.Element(i)->callback->offset == setup->offset && g_pHooks.Element(i)->callback->post == post && g_pHooks.Element(i)->remove_callback == pContext->GetFunctionById(params[4]) && g_pHooks.Element(i)->callback->plugin_callback == setup->callback)
|
||||
{
|
||||
return g_pHooks.Element(i)->hookid;
|
||||
}
|
||||
}
|
||||
CBaseEntity *pEnt = UTIL_GetCBaseEntity(params[3]);
|
||||
|
||||
if(!pEnt)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid entity passed %i", params[2]);
|
||||
}
|
||||
|
||||
DHooksManager *manager = new DHooksManager(setup, pEnt, pContext->GetFunctionById(params[4]), post);
|
||||
|
||||
if(!manager->hookid)
|
||||
{
|
||||
delete manager;
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_pHooks.AddToTail(manager);
|
||||
|
||||
return manager->hookid;
|
||||
}
|
||||
/*cell_t Native_HookGamerules(IPluginContext *pContext, const cell_t *params);
|
||||
cell_t Native_RemoveHookID(IPluginContext *pContext, const cell_t *params);*/
|
||||
cell_t Native_GetParam(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if(params[1] == BAD_HANDLE)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %i", BAD_HANDLE);
|
||||
}
|
||||
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
HookParamsStruct *paramStruct;
|
||||
if((err = handlesys->ReadHandle(params[1], g_HookParamsHandle, &sec, (void **)¶mStruct)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
|
||||
}
|
||||
|
||||
if(params[2] > paramStruct->dg->params.Count() || params[2] < 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.Count());
|
||||
}
|
||||
if(params[2] == 0)
|
||||
{
|
||||
return paramStruct->dg->params.Count();
|
||||
}
|
||||
|
||||
int index = params[2] - 1;
|
||||
|
||||
if(paramStruct->orgParams[index] == NULL && (paramStruct->dg->params.Element(index).type == HookParamType_CBaseEntity || paramStruct->dg->params.Element(index).type == HookParamType_Edict))
|
||||
{
|
||||
return pContext->ThrowNativeError("Trying to get value for null pointer.");
|
||||
}
|
||||
|
||||
switch(paramStruct->dg->params.Element(index).type)
|
||||
{
|
||||
case HookParamType_Int:
|
||||
return (int)paramStruct->orgParams[index];
|
||||
case HookParamType_Bool:
|
||||
return (cell_t)paramStruct->orgParams[index] != 0;
|
||||
case HookParamType_CBaseEntity:
|
||||
return gamehelpers->EntityToBCompatRef((CBaseEntity *)paramStruct->orgParams[index]);
|
||||
case HookParamType_Edict:
|
||||
return gamehelpers->IndexOfEdict((edict_t *)paramStruct->orgParams[index]);
|
||||
case HookParamType_Float:
|
||||
return sp_ftoc(*(float *)paramStruct->orgParams[index]);
|
||||
default:
|
||||
return pContext->ThrowNativeError("Invalid param type (%i) to get", paramStruct->dg->params.Element(index).type);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
cell_t Native_GetReturn(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
cell_t Native_SetReturn(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
/*cell_t Native_SetParam(IPluginContext *pContext, const cell_t *params);
|
||||
cell_t Native_GetParamVector(IPluginContext *pContext, const cell_t *params);
|
||||
cell_t Native_GetReturnVector(IPluginContext *pContext, const cell_t *params);
|
||||
cell_t Native_SetReturnVector(IPluginContext *pContext, const cell_t *params);
|
||||
cell_t Native_SetParamVector(IPluginContext *pContext, const cell_t *params);*/
|
||||
cell_t Native_GetParamString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if(params[1] == BAD_HANDLE)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %i", BAD_HANDLE);
|
||||
}
|
||||
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
HookParamsStruct *paramStruct;
|
||||
if((err = handlesys->ReadHandle(params[1], g_HookParamsHandle, &sec, (void **)¶mStruct)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
|
||||
}
|
||||
|
||||
if(params[2] > paramStruct->dg->params.Count() || params[2] <= 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.Count());
|
||||
}
|
||||
int index = params[2] - 1;
|
||||
|
||||
if(paramStruct->orgParams[index] == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Trying to get value for null pointer.");
|
||||
}
|
||||
|
||||
if(paramStruct->dg->params.Element(index).type == HookParamType_CharPtr)
|
||||
{
|
||||
pContext->StringToLocal(params[3], params[4], (const char *)paramStruct->orgParams[index]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
//cell_t Native_GetReturnString(IPluginContext *pContext, const cell_t *params);
|
||||
//cell_t Native_SetReturnString(IPluginContext *pContext, const cell_t *params);
|
||||
cell_t Native_SetParamString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
sp_nativeinfo_t g_Natives[] =
|
||||
{
|
||||
{"DHookCreate", Native_CreateHook},
|
||||
{"DHookAddParam", Native_AddParam},
|
||||
{"DHookEntity", Native_HookEntity},
|
||||
/*{"DHookGamerules", Native_HookGamerules},
|
||||
{"DHookRaw", Native_HookRaw},
|
||||
{"DHookRemoveHookID", Native_RemoveHookID},*/
|
||||
{"DHookGetParam", Native_GetParam},
|
||||
{"DHookGetReturn", Native_GetReturn},
|
||||
{"DHookSetReturn", Native_SetReturn},
|
||||
/*{"DHookSetParam", Native_SetParam},
|
||||
{"DHookGetParamVector", Native_GetParamVector},
|
||||
{"DHookGetReturnVector", Native_GetReturnVector},
|
||||
{"DHookSetReturnVector", Native_SetReturnVector},
|
||||
{"DHookSetParamVector", Native_SetParamVector},*/
|
||||
{"DHookGetParamString", Native_GetParamString},
|
||||
//{"DHookGetReturnString", Native_GetReturnString},
|
||||
//{"DHookSetReturnString", Native_SetReturnString},
|
||||
{"DHookSetParamString", Native_SetParamString},
|
||||
/*{"DHookAddEntityListener", Native_AddEntityListener},
|
||||
{"DHookRemoveEntityListener", Native_RemoveEntityListener},
|
||||
{"DHookGetParamObjectPtrVar", Native_GetParamObjectPtrVar},
|
||||
{"DHookSetParamObjectPtrVar", Native_SetParamObjectPtrVar},
|
||||
{"DHookGetParamObjectPtrVarVector", Native_GetParamObjectPtrVarVector},
|
||||
{"DHookSetParamObjectPtrVarVector", Native_SetParamObjectPtrVarVector},
|
||||
{"DHookIsNullParam", Native_IsNullParam},*/
|
||||
{NULL, NULL}
|
||||
};
|
12
natives.h
Normal file
12
natives.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _INCLUDE_NATIVES_H_
|
||||
#define _INCLUDE_NATIVES_H_
|
||||
|
||||
#include "extension.h"
|
||||
#include "vhook.h"
|
||||
|
||||
extern bool g_bAllowGamerules;
|
||||
extern HandleType_t g_HookSetupHandle;
|
||||
extern HandleType_t g_HookParamsHandle;
|
||||
extern HandleType_t g_HookReturnHandle;
|
||||
extern CUtlVector<DHooksManager *> g_pHooks;
|
||||
#endif
|
@ -60,7 +60,7 @@
|
||||
|
||||
/** Enable interfaces you want to use here by uncommenting lines */
|
||||
//#define SMEXT_ENABLE_FORWARDSYS
|
||||
//#define SMEXT_ENABLE_HANDLESYS
|
||||
#define SMEXT_ENABLE_HANDLESYS
|
||||
#define SMEXT_ENABLE_PLAYERHELPERS
|
||||
//#define SMEXT_ENABLE_DBMANAGER
|
||||
#define SMEXT_ENABLE_GAMECONF
|
||||
@ -71,7 +71,7 @@
|
||||
//#define SMEXT_ENABLE_LIBSYS
|
||||
//#define SMEXT_ENABLE_MENUS
|
||||
//#define SMEXT_ENABLE_ADTFACTORY
|
||||
//#define SMEXT_ENABLE_PLUGINSYS
|
||||
#define SMEXT_ENABLE_PLUGINSYS
|
||||
//#define SMEXT_ENABLE_ADMINSYS
|
||||
//#define SMEXT_ENABLE_TEXTPARSERS
|
||||
//#define SMEXT_ENABLE_USERMSGS
|
||||
|
455
vhook.cpp
455
vhook.cpp
@ -1,8 +1,71 @@
|
||||
#include "vhook.h"
|
||||
#include "vhook_macros.h"
|
||||
|
||||
SourceHook::IHookManagerAutoGen *g_pHookManager = NULL;
|
||||
|
||||
CUtlVector<DHooksManager *> g_pHooks;
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, bool post)
|
||||
{
|
||||
this->callback = MakeHandler(setup->returnType);
|
||||
this->hookid = 0;
|
||||
this->remove_callback = remove_callback;
|
||||
this->callback->offset = setup->offset;
|
||||
this->callback->plugin_callback = setup->callback;
|
||||
this->callback->returnFlag = setup->returnFlag;
|
||||
this->callback->thisType = setup->thisType;
|
||||
this->callback->post = post;
|
||||
this->callback->hookType = setup->hookType;
|
||||
this->callback->params = setup->params;
|
||||
|
||||
if(this->callback->hookType == HookType_Entity)
|
||||
{
|
||||
this->callback->entity = gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->callback->entity = -1;
|
||||
}
|
||||
|
||||
CProtoInfoBuilder protoInfo(ProtoInfo::CallConv_ThisCall);
|
||||
|
||||
for(int i = this->callback->params.Count() -1; i >= 0; i--)
|
||||
{
|
||||
protoInfo.AddParam(this->callback->params.Element(i).size, this->callback->params.Element(i).pass_type, this->callback->params.Element(i).flag, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
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, 0, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
protoInfo.SetReturnType(sizeof(void *), SourceHook::PassInfo::PassType_Basic, 0, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
HookManagerPubFunc hook = g_pHookManager->MakeHookMan(protoInfo, 0, this->callback->offset);
|
||||
|
||||
this->hookid = g_SHPtr->AddHook(g_PLID,ISourceHook::Hook_Normal, iface, 0, hook, this->callback, this->callback->post);
|
||||
}
|
||||
|
||||
void CleanupHooks(IPluginContext *pContext)
|
||||
{
|
||||
for(int i = g_pHooks.Count() -1; i >= 0; i--)
|
||||
{
|
||||
DHooksManager *manager = g_pHooks.Element(i);
|
||||
|
||||
if(pContext == NULL || pContext == manager->callback->plugin_callback->GetParentContext())
|
||||
{
|
||||
delete manager;
|
||||
g_pHooks.Remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SetupHookManager(ISmmAPI *ismm)
|
||||
{
|
||||
g_pHookManager = static_cast<SourceHook::IHookManagerAutoGen *>(ismm->MetaFactory(MMIFACE_SH_HOOKMANAUTOGEN, NULL, NULL));
|
||||
@ -10,210 +73,208 @@ bool SetupHookManager(ISmmAPI *ismm)
|
||||
return g_pHookManager != NULL;
|
||||
}
|
||||
|
||||
void CallFunction_Void(DHooksCallback<void> *info, unsigned long stack, void *iface)
|
||||
size_t GetParamTypeSize(HookParamType type)
|
||||
{
|
||||
PassInfo *paramInfo = NULL;
|
||||
ICallWrapper *call;
|
||||
size_t size = 0;
|
||||
|
||||
if(info->paramcount > 0)
|
||||
return sizeof(void *);
|
||||
}
|
||||
SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
paramInfo = (PassInfo *)malloc(sizeof(PassInfo) * info->paramcount);
|
||||
for(int i = 0; i < info->paramcount; i++)
|
||||
case HookParamType_Float:
|
||||
return SourceHook::PassInfo::PassType::PassType_Float;
|
||||
default:
|
||||
return SourceHook::PassInfo::PassType::PassType_Basic;
|
||||
}
|
||||
}
|
||||
size_t GetStackArgsSize(DHooksCallback *dg)
|
||||
{
|
||||
size_t res = 0;
|
||||
for(int i = dg->params.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
res += dg->params.Element(i).size;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t argStackSize)
|
||||
{
|
||||
HookParamsStruct *res = new HookParamsStruct();
|
||||
res->dg = dg;
|
||||
res->orgParams = (void **)malloc(argStackSize);
|
||||
res->newParams = (void **)malloc(argStackSize);
|
||||
memcpy(res->orgParams, argStack, argStackSize);
|
||||
for(int i = 0; i < dg->params.Count(); i++)
|
||||
{
|
||||
res->newParams[i] = NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
HookReturnStruct *GetReturnStruct(DHooksCallback *dg, const void *result)
|
||||
{
|
||||
HookReturnStruct *res = new HookReturnStruct();
|
||||
res->isChanged = false;
|
||||
res->type = dg->returnType;
|
||||
res->orgResult = &result;
|
||||
res->newResult = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
cell_t GetThisPtr(void *iface, ThisPointerType type)
|
||||
{
|
||||
if(ThisPointer_CBaseEntity)
|
||||
{
|
||||
return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
|
||||
}
|
||||
|
||||
return (cell_t)iface;
|
||||
}
|
||||
#ifndef __linux__
|
||||
void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep)
|
||||
{
|
||||
HookReturnStruct *returnStruct = NULL;
|
||||
HookParamsStruct *paramStruct = NULL;
|
||||
Handle_t rHndl;
|
||||
Handle_t pHndl;
|
||||
|
||||
*argsizep = GetStackArgsSize(dg);
|
||||
|
||||
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, g_SHPtr->GetOrigRet());
|
||||
rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
|
||||
if(!rHndl)
|
||||
{
|
||||
switch(info->params[i].type)
|
||||
if(returnStruct)
|
||||
{
|
||||
PARAMINFO_SWITCH_CASE(int, HookParamType_Int ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(bool, HookParamType_Bool ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(float, HookParamType_Float ,PassType_Float);
|
||||
PARAMINFO_SWITCH_CASE(string_t, HookParamType_String ,PassType_Object);
|
||||
PARAMINFO_SWITCH_CASE(string_t *, HookParamType_StringPtr ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(char *, HookParamType_CharPtr ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(Vector *, HookParamType_VectorPtr ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(CBaseEntity *, HookParamType_CBaseEntity ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(edict_t *, HookParamType_Edict ,PassType_Basic);
|
||||
default:
|
||||
paramInfo[i].flags = info->params[i].flag;
|
||||
paramInfo[i].size = sizeof(void *);
|
||||
paramInfo[i].type = PassType_Basic;
|
||||
size += sizeof(void *);
|
||||
break;
|
||||
delete returnStruct;
|
||||
}
|
||||
g_SHPtr->SetRes(MRES_IGNORED);
|
||||
return 0;
|
||||
}
|
||||
call = g_pBinTools->CreateVCall(info->offset, 0, 0, NULL, paramInfo, info->paramcount);
|
||||
dg->plugin_callback->PushCell(rHndl);
|
||||
}
|
||||
if(*argsizep > 0)
|
||||
{
|
||||
paramStruct = GetParamStruct(dg, argStack, *argsizep);
|
||||
pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL);
|
||||
if(!pHndl)
|
||||
{
|
||||
if(returnStruct)
|
||||
{
|
||||
delete returnStruct;
|
||||
}
|
||||
if(paramStruct)
|
||||
{
|
||||
delete paramStruct;
|
||||
}
|
||||
g_SHPtr->SetRes(MRES_IGNORED);
|
||||
return 0;
|
||||
}
|
||||
dg->plugin_callback->PushCell(pHndl);
|
||||
}
|
||||
cell_t result = (cell_t)MRES_Ignored;
|
||||
dg->plugin_callback->Execute(&result);
|
||||
|
||||
void *ret = g_SHPtr->GetOverrideRetPtr();
|
||||
void *res = 0;
|
||||
|
||||
switch((MRESReturn)result)
|
||||
{
|
||||
case MRES_Handled:
|
||||
case MRES_ChangedHandled:
|
||||
g_SHPtr->DoRecall();
|
||||
g_SHPtr->SetRes(MRES_SUPERCEDE);
|
||||
//ret = CallVFunction(dg, argStack, g_SHPtr->GetIfacePtr());
|
||||
memcpy(res, ret, sizeof(void *));
|
||||
break;
|
||||
case MRES_ChangedOverride:
|
||||
g_SHPtr->DoRecall();
|
||||
g_SHPtr->SetRes(MRES_SUPERCEDE);
|
||||
//CallVFunction(dg, argStack, g_SHPtr->GetIfacePtr());
|
||||
if(dg->returnType != ReturnType_Void)
|
||||
{
|
||||
if(returnStruct->isChanged)
|
||||
{
|
||||
memcpy(ret, returnStruct->newResult, sizeof(void *));
|
||||
memcpy(res, returnStruct->newResult, sizeof(void *));
|
||||
}
|
||||
else if(dg->post)
|
||||
{
|
||||
memcpy(ret, returnStruct->orgResult, sizeof(void *));
|
||||
memcpy(res, returnStruct->orgResult, sizeof(void *));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MRES_Override:
|
||||
g_SHPtr->SetRes(MRES_OVERRIDE);
|
||||
if(dg->returnType != ReturnType_Void)
|
||||
{
|
||||
if(returnStruct->isChanged)
|
||||
{
|
||||
memcpy(ret, returnStruct->newResult, sizeof(void *));
|
||||
memcpy(res, returnStruct->newResult, sizeof(void *));
|
||||
}
|
||||
else if(dg->post)
|
||||
{
|
||||
memcpy(ret, returnStruct->orgResult, sizeof(void *));
|
||||
memcpy(res, returnStruct->orgResult, sizeof(void *));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MRES_Supercede:
|
||||
g_SHPtr->SetRes(MRES_SUPERCEDE);
|
||||
if(dg->returnType != ReturnType_Void)
|
||||
{
|
||||
if(returnStruct->isChanged)
|
||||
{
|
||||
memcpy(ret, returnStruct->newResult, sizeof(void *));
|
||||
memcpy(res, returnStruct->newResult, sizeof(void *));
|
||||
}
|
||||
else if(dg->post)
|
||||
{
|
||||
memcpy(ret, returnStruct->orgResult, sizeof(void *));
|
||||
memcpy(res, returnStruct->orgResult, sizeof(void *));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_SHPtr->SetRes(MRES_IGNORED);
|
||||
break;
|
||||
}
|
||||
|
||||
HandleSecurity sec(dg->plugin_callback->GetParentContext()->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if(returnStruct)
|
||||
{
|
||||
handlesys->FreeHandle(rHndl, &sec);
|
||||
}
|
||||
if(paramStruct)
|
||||
{
|
||||
handlesys->FreeHandle(pHndl, &sec);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
void *Callback(DHooksCallback *dg, void **argStack)
|
||||
{
|
||||
if(dg->returnType == ReturnType_Void)
|
||||
{
|
||||
META_CONPRINTF("String is %s\n", argStack[0]);
|
||||
g_SHPtr->SetRes(MRES_IGNORED);
|
||||
}
|
||||
else
|
||||
{
|
||||
call = g_pBinTools->CreateVCall(info->offset, 0, 0, NULL, NULL, 0);
|
||||
//META_CONPRINTF("Entity %i\n", gamehelpers->ReferenceToIndex(gamehelpers->EntityToBCompatRef((CBaseEntity *)g_SHPtr->GetIfacePtr())));
|
||||
g_SHPtr->SetRes(MRES_SUPERCEDE);
|
||||
void *ret = g_SHPtr->GetOverrideRetPtr();
|
||||
ret = (void *)false;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size);
|
||||
unsigned char *vptr = vstk;
|
||||
|
||||
*(void **)vptr = iface;
|
||||
vptr += sizeof(void *);
|
||||
|
||||
size_t offset = STACK_OFFSET;
|
||||
|
||||
if(info->paramcount > 0)
|
||||
{
|
||||
for(int i = 0; i < info->paramcount; i++)
|
||||
{
|
||||
switch(info->params[i].type)
|
||||
{
|
||||
VSTK_PARAM_SWITCH(int, HookParamType_Int);
|
||||
VSTK_PARAM_SWITCH(bool, HookParamType_Bool);
|
||||
VSTK_PARAM_SWITCH(float, HookParamType_Float);
|
||||
VSTK_PARAM_SWITCH(string_t, HookParamType_String);
|
||||
VSTK_PARAM_SWITCH(string_t *, HookParamType_StringPtr);
|
||||
VSTK_PARAM_SWITCH(char *, HookParamType_CharPtr);
|
||||
VSTK_PARAM_SWITCH(Vector *, HookParamType_VectorPtr);
|
||||
VSTK_PARAM_SWITCH(CBaseEntity *, HookParamType_CBaseEntity);
|
||||
VSTK_PARAM_SWITCH(edict_t *, HookParamType_Edict);
|
||||
default:
|
||||
*(void **)vptr = *(void **)(stack+offset);
|
||||
if(i + 1 != info->paramcount)
|
||||
{
|
||||
vptr += sizeof(void *);
|
||||
}
|
||||
offset += sizeof(void *);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
call->Execute(vstk, NULL);
|
||||
call->Destroy();
|
||||
|
||||
free(vstk);
|
||||
|
||||
if(paramInfo)
|
||||
free(paramInfo);
|
||||
return 0;
|
||||
}
|
||||
template<class T>
|
||||
T CallFunction(DHooksCallback<T> *info, unsigned long stack, void *iface)
|
||||
{
|
||||
PassInfo *paramInfo = NULL;
|
||||
ICallWrapper *call;
|
||||
size_t size = 0;
|
||||
|
||||
PassInfo returnInfo;
|
||||
returnInfo.flags = PASSFLAG_BYVAL;
|
||||
returnInfo.size = sizeof(T);
|
||||
returnInfo.type = PassType_Basic;
|
||||
|
||||
if(info->paramcount > 0)
|
||||
{
|
||||
paramInfo = (PassInfo *)malloc(sizeof(PassInfo) * info->paramcount);
|
||||
for(int i = 0; i < info->paramcount; i++)
|
||||
{
|
||||
switch(info->params[i].type)
|
||||
{
|
||||
PARAMINFO_SWITCH_CASE(int, HookParamType_Int ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(bool, HookParamType_Bool ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(float, HookParamType_Float ,PassType_Float);
|
||||
PARAMINFO_SWITCH_CASE(string_t, HookParamType_String ,PassType_Object);
|
||||
PARAMINFO_SWITCH_CASE(string_t *, HookParamType_StringPtr ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(char *, HookParamType_CharPtr ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(Vector *, HookParamType_VectorPtr ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(CBaseEntity *, HookParamType_CBaseEntity ,PassType_Basic);
|
||||
PARAMINFO_SWITCH_CASE(edict_t *, HookParamType_Edict ,PassType_Basic);
|
||||
default:
|
||||
paramInfo[i].flags = info->params[i].flag;
|
||||
paramInfo[i].size = sizeof(void *);
|
||||
paramInfo[i].type = PassType_Basic;
|
||||
size += sizeof(void *);
|
||||
break;
|
||||
}
|
||||
}
|
||||
call = g_pBinTools->CreateVCall(info->offset, 0, 0, &returnInfo, paramInfo, info->paramcount);
|
||||
}
|
||||
else
|
||||
{
|
||||
call = g_pBinTools->CreateVCall(info->offset, 0, 0, &returnInfo, NULL, 0);
|
||||
}
|
||||
|
||||
unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size);
|
||||
unsigned char *vptr = vstk;
|
||||
|
||||
*(void **)vptr = iface;
|
||||
vptr += sizeof(void *);
|
||||
|
||||
size_t offset = STACK_OFFSET;
|
||||
|
||||
if(info->paramcount > 0)
|
||||
{
|
||||
for(int i = 0; i < info->paramcount; i++)
|
||||
{
|
||||
switch(info->params[i].type)
|
||||
{
|
||||
VSTK_PARAM_SWITCH(int, HookParamType_Int);
|
||||
VSTK_PARAM_SWITCH(bool, HookParamType_Bool);
|
||||
VSTK_PARAM_SWITCH(float, HookParamType_Float);
|
||||
VSTK_PARAM_SWITCH(string_t, HookParamType_String);
|
||||
VSTK_PARAM_SWITCH(string_t *, HookParamType_StringPtr);
|
||||
VSTK_PARAM_SWITCH(char *, HookParamType_CharPtr);
|
||||
VSTK_PARAM_SWITCH(Vector *, HookParamType_VectorPtr);
|
||||
VSTK_PARAM_SWITCH(CBaseEntity *, HookParamType_CBaseEntity);
|
||||
VSTK_PARAM_SWITCH(edict_t *, HookParamType_Edict);
|
||||
default:
|
||||
*(void **)vptr = *(void **)(stack+offset);
|
||||
if(i + 1 != info->paramcount)
|
||||
{
|
||||
vptr += sizeof(void *);
|
||||
}
|
||||
offset += sizeof(void *);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
T ret;
|
||||
call->Execute(vstk, &ret);
|
||||
call->Destroy();
|
||||
|
||||
free(vstk);
|
||||
|
||||
if(paramInfo)
|
||||
free(paramInfo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
void DHooksCallback<void>::Call()
|
||||
{
|
||||
GET_STACK;
|
||||
META_CONPRINTF("String %s\n", *(char **)(stack+STACK_OFFSET));
|
||||
strcpy(*(char **)(stack+STACK_OFFSET), "models/player/t_phoenix.mdl");
|
||||
|
||||
SH_GLOB_SHPTR->DoRecall();
|
||||
CallFunction_Void(this, stack, g_SHPtr->GetIfacePtr());
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
template <>
|
||||
bool DHooksCallback<bool>::Call()
|
||||
{
|
||||
GET_STACK;
|
||||
META_CONPRINTF("Entity %i\n", gamehelpers->ReferenceToIndex(gamehelpers->EntityToBCompatRef(*(CBaseEntity **)(stack+STACK_OFFSET))));
|
||||
/*__asm
|
||||
{
|
||||
mov ebp, stack
|
||||
};*/
|
||||
META_RES result = MRES_IGNORED;
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
/*do
|
||||
{
|
||||
SH_GLOB_SHPTR->DoRecall();
|
||||
if ((result) >= MRES_OVERRIDE)
|
||||
{
|
||||
void *pOverride = g_SHPtr->GetOverrideRetPtr();
|
||||
pOverride = (void *)false;
|
||||
}
|
||||
if(result != MRES_SUPERCEDE)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, CallFunction<bool>(this, stack, g_SHPtr->GetIfacePtr()));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, true);
|
||||
}
|
||||
} while (0);*/
|
||||
}
|
||||
#endif
|
||||
|
215
vhook.h
215
vhook.h
@ -3,8 +3,18 @@
|
||||
|
||||
#include "extension.h"
|
||||
#include <sourcehook.h>
|
||||
#include <macro-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
|
||||
};
|
||||
|
||||
#define MAX_PARAMS 10
|
||||
enum HookParamType
|
||||
{
|
||||
HookParamType_Unknown,
|
||||
@ -19,6 +29,7 @@ enum HookParamType
|
||||
HookParamType_ObjectPtr,
|
||||
HookParamType_Edict
|
||||
};
|
||||
|
||||
enum ReturnType
|
||||
{
|
||||
ReturnType_Unknown,
|
||||
@ -35,52 +46,216 @@ enum ReturnType
|
||||
ReturnType_Edict
|
||||
};
|
||||
|
||||
class ParamInfo
|
||||
enum ThisPointerType
|
||||
{
|
||||
ThisPointer_Ignore,
|
||||
ThisPointer_CBaseEntity,
|
||||
ThisPointer_Address
|
||||
};
|
||||
|
||||
enum HookType
|
||||
{
|
||||
HookType_Entity,
|
||||
HookType_GameRules,
|
||||
HookType_Raw
|
||||
};
|
||||
|
||||
struct ParamInfo
|
||||
{
|
||||
public:
|
||||
HookParamType type;
|
||||
size_t size;
|
||||
unsigned int flag;
|
||||
SourceHook::PassInfo::PassType pass_type;
|
||||
};
|
||||
|
||||
struct HookReturnStruct
|
||||
{
|
||||
ReturnType type;
|
||||
bool isChanged;
|
||||
void *orgResult;
|
||||
void *newResult;
|
||||
};
|
||||
|
||||
class DHooksInfo
|
||||
{
|
||||
public:
|
||||
int paramcount;
|
||||
ParamInfo params[MAX_PARAMS];
|
||||
CUtlVector<ParamInfo> params;
|
||||
int offset;
|
||||
unsigned int returnFlag;
|
||||
ReturnType returnType;
|
||||
bool post;
|
||||
IPluginFunction *plugin_callback;
|
||||
int entity;
|
||||
ThisPointerType thisType;
|
||||
HookType hookType;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DHooksCallback : public SourceHook::ISHDelegate, public DHooksInfo
|
||||
{
|
||||
public:
|
||||
virtual bool IsEqual(ISHDelegate *pOtherDeleg){return false;};
|
||||
virtual void DeleteThis(){delete this;};
|
||||
virtual T Call();
|
||||
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;
|
||||
};
|
||||
|
||||
#ifndef __linux__
|
||||
void *Callback(DHooksCallback *dg, void **stack, size_t *argsizep);
|
||||
//float Callback_float(DHooksCallback *dg, void **stack, size_t *argsizep);
|
||||
#else
|
||||
void *Callback(DHooksCallback *dg, void **stack);
|
||||
float Callback_float(DHooksCallback *dg, void **stack);
|
||||
#endif
|
||||
bool SetupHookManager(ISmmAPI *ismm);
|
||||
void CleanupHooks(IPluginContext *pContext);
|
||||
size_t GetParamTypeSize(HookParamType type);
|
||||
SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type);
|
||||
|
||||
#ifdef __linux__
|
||||
static void *GenerateThunk(ReturnType type)
|
||||
{
|
||||
MacroAssemblerX86 masm;
|
||||
|
||||
masm.push(ebp);
|
||||
masm.movl(ebp, esp);
|
||||
masm.lea(eax, Operand(ebp, 12));
|
||||
masm.push(eax);
|
||||
masm.push(Operand(ebp, 8));
|
||||
if(type == ReturnType_Float)
|
||||
masm.call(ExternalAddress((void *)Callback_float));
|
||||
else
|
||||
masm.call(ExternalAddress((void *)Callback));
|
||||
masm.addl(esp, 8);
|
||||
masm.pop(ebp);
|
||||
masm.ret();
|
||||
|
||||
void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length());
|
||||
masm.emitToExecutableMemory(base);
|
||||
return base;
|
||||
}
|
||||
#else
|
||||
static void *GenerateThunk(ReturnType type)
|
||||
{
|
||||
MacroAssemblerX86 masm;
|
||||
|
||||
masm.push(ebp);
|
||||
masm.movl(ebp, esp);
|
||||
masm.subl(esp, 4);
|
||||
masm.push(esp);
|
||||
masm.lea(eax, Operand(ebp, 8));
|
||||
masm.push(eax);
|
||||
masm.push(ecx);
|
||||
//if(type == ReturnType_Float)
|
||||
// masm.call(ExternalAddress(Callback_float));
|
||||
//else
|
||||
masm.call(ExternalAddress(Callback));
|
||||
masm.addl(esp, 12);
|
||||
masm.pop(ecx); // grab arg size
|
||||
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;
|
||||
}
|
||||
~HookParamsStruct()
|
||||
{
|
||||
if(this->orgParams != NULL)
|
||||
{
|
||||
delete this->orgParams;
|
||||
}
|
||||
if(this->newParams != NULL)
|
||||
{
|
||||
delete this->newParams;
|
||||
}
|
||||
}
|
||||
public:
|
||||
//CUtlVector<int> cleanup;
|
||||
void **orgParams;
|
||||
void **newParams;
|
||||
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;
|
||||
CUtlVector<ParamInfo> params;
|
||||
int offset;
|
||||
IPluginFunction *callback;
|
||||
};
|
||||
|
||||
class DHooksManager
|
||||
{
|
||||
public:
|
||||
DHooksManager()
|
||||
{
|
||||
this->callback_bool = NULL;
|
||||
this->callback_void = NULL;
|
||||
this->hookid = 0;
|
||||
};
|
||||
DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, bool post);
|
||||
~DHooksManager()
|
||||
{
|
||||
if(this->hookid != 0)
|
||||
if(this->hookid)
|
||||
{
|
||||
SH_REMOVE_HOOK_ID(this->hookid);
|
||||
g_SHPtr->RemoveHookByID(this->hookid);
|
||||
if(this->remove_callback)
|
||||
{
|
||||
this->remove_callback->PushCell(this->hookid);
|
||||
this->remove_callback->Execute(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
DHooksCallback<bool> *callback_bool;
|
||||
DHooksCallback<void> *callback_void;
|
||||
public:
|
||||
int hookid;
|
||||
unsigned int returnFlag;
|
||||
DHooksCallback *callback;
|
||||
IPluginFunction *remove_callback;
|
||||
};
|
||||
|
||||
bool SetupHookManager(ISmmAPI *ismm);
|
||||
extern IBinTools *g_pBinTools;
|
||||
extern HandleType_t g_HookParamsHandle;
|
||||
extern HandleType_t g_HookReturnHandle;
|
||||
#endif
|
@ -1,32 +0,0 @@
|
||||
#define PARAMINFO_SWITCH_CASE(paramType, enumType, passType) \
|
||||
case enumType: \
|
||||
paramInfo[i].flags = info->params[i].flag; \
|
||||
paramInfo[i].size = sizeof(paramType); \
|
||||
paramInfo[i].type = passType; \
|
||||
size += sizeof(paramType); \
|
||||
break;
|
||||
|
||||
#define VSTK_PARAM_SWITCH(paramType, enumType) \
|
||||
case enumType: \
|
||||
*(paramType *)vptr = *(paramType *)(stack+offset); \
|
||||
if(i + 1 != info->paramcount) \
|
||||
{ \
|
||||
vptr += sizeof(paramType); \
|
||||
} \
|
||||
offset += sizeof(paramType); \
|
||||
break;
|
||||
#ifndef __linux__
|
||||
|
||||
#define STACK_OFFSET 8
|
||||
#define GET_STACK \
|
||||
unsigned long stack; \
|
||||
__asm \
|
||||
{ \
|
||||
mov stack, ebp \
|
||||
};
|
||||
#else
|
||||
#define STACK_OFFSET 4
|
||||
#define GET_STACK \
|
||||
unsigned long stack = 0; \
|
||||
asm ("movl %%esp, %0;" : "=r" (stack));
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user