Continued making adding new entries easier

{hs_}register_function->ham_register(HamHook:function,...)

Added a few more hooks

Fixed a few directory errors

Updated config file
This commit is contained in:
Steve Dudenhoeffer 2007-03-09 18:15:09 +00:00
parent 71065a65dd
commit 8939c3076a
22 changed files with 3703 additions and 138 deletions

View File

@ -20,7 +20,7 @@ static char *FP_FormatLine(char *data)
{ {
char *End; /**< Pointer to the end of the string. */ char *End; /**< Pointer to the end of the string. */
char *Start; /**< Pointer to the start of the string. */ char *Start; /**< Pointer to the start of the string. */
char *Temp=Start; /**< Temporary pointer for parsing. */ char *Temp; /**< Temporary pointer for parsing. */
Start=data; Start=data;

View File

@ -25,7 +25,9 @@ BIN_SUFFIX = amxx_i386.so
OBJECTS = sdk/amxxmodule.cpp FileParser.cpp amxxapi.cpp hooks.cpp \ OBJECTS = sdk/amxxmodule.cpp FileParser.cpp amxxapi.cpp hooks.cpp \
tableentries/VTableManager.cpp tableentries/TakeDamage.cpp tableentries/Use.cpp \ tableentries/VTableManager.cpp tableentries/TakeDamage.cpp tableentries/Use.cpp \
tableentries/Blocked.cpp tableentries/Blocked.cpp tableentries/Killed.cpp tableentries/Respawn.cpp \
tableentries/Restart.cpp tableentries/AddPoints.cpp tableentries/AddPointsToTeam.cpp \
#natives.cpp vtable.cpp #natives.cpp vtable.cpp

View File

@ -37,6 +37,14 @@
#endif #endif
#if defined _WIN32 #if defined _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif // WIN32_LEAN_AND_MEAN
#if _MSC_VER >= 1400
#ifdef offsetof
#undef offsetof
#endif // offsetof
#endif // _MSC_VER >= 1400
#include <windows.h> #include <windows.h>
#elif defined __linux__ #elif defined __linux__
#include <sys/mman.h> #include <sys/mman.h>

View File

@ -101,6 +101,12 @@ void HAM_CallInitialization(void)
VTINIT(TakeDamage); VTINIT(TakeDamage);
VTINIT(Use); VTINIT(Use);
VTINIT(Killed);
VTINIT(Blocked);
VTINIT(Respawn);
VTINIT(Restart);
VTINIT(AddPoints);
VTINIT(AddPointsToTeam);
#undef VTINIT #undef VTINIT
} }
@ -217,6 +223,8 @@ void OnAmxxAttach()
HAM_classbaseset=1; HAM_classbaseset=1;
#endif #endif
RegisterRegisterNatives();
FP_SetupOffsets(ModKey,HAM_GetKey); FP_SetupOffsets(ModKey,HAM_GetKey);
HAM_CallConfigDone(); HAM_CallConfigDone();

View File

@ -26,10 +26,21 @@
; Data dated: 2007-02-23 ; Data dated: 2007-02-23
; Version tested: 1.6 Steam (legitimate) ; Version tested: 1.6 Steam (legitimate)
cstrike_windows_takedamage 12 cstrike_windows_takedamage 12
cstrike_windows_killed 14 ;estimated
cstrike_windows_addpoints 23 ;estimated
cstrike_windows_addpointstoteam 24 ;estimated
cstrike_windows_use 46 cstrike_windows_use 46
cstrike_windows_blocked 47 ;estimated
cstrike_windows_respawn 48 ;estimated
cstrike_windows_pev 4 cstrike_windows_pev 4
cstrike_linux_restart 4 ;estimated
cstrike_linux_takedamage 14 cstrike_linux_takedamage 14
cstrike_windows_addpoints 25 ;estimated
cstrike_windows_addpointstoteam 26 ;estimated
cstrike_linux_killed 16 ;estimated
cstrike_linux_use 48 cstrike_linux_use 48
cstrike_linux_blocked 49 ;estimated
cstrike_linux_respawn 50 ;estimated
cstrike_linux_pev 0 cstrike_linux_pev 0
cstrike_linux_classbase 0x94 cstrike_linux_classbase 0x94
@ -46,20 +57,20 @@ czero_linux_classbase 0x94
; Data dated: 2007-02-23 ; Data dated: 2007-02-23
; Version tested: 3.1 ; Version tested: 3.1
ns_windows_takedamage 10 ns_windows_takedamage 10
ns_windows_use 48 ns_windows_use 49
ns_windows_pev 4 ns_windows_pev 4
ns_linux_takedamage 11 ns_linux_takedamage 11
ns_linux_use 49 ns_linux_use 50
ns_linux_pev 4 ns_linux_pev 4
ns_linux_classbase 0x0 ns_linux_classbase 0x0
; Data dated: 2007-02-23 ; Data dated: 2007-02-23
; Version tested: 3.2 beta 2 ; Version tested: 3.2 beta 2
nsp_windows_takedamage 10 nsp_windows_takedamage 10
nsp_windows_use 48 nsp_windows_use 49
nsp_windows_pev 4 nsp_windows_pev 4
nsp_linux_takedamage 11 nsp_linux_takedamage 11
nsp_linux_use 49 nsp_linux_use 50
nsp_linux_pev 4 nsp_linux_pev 4
nsp_linux_classbase 0x0 nsp_linux_classbase 0x0
@ -75,23 +86,23 @@ dod_linux_classbase 0x154
; Data dated: 2007-02-23 ; Data dated: 2007-02-23
; Version tested: 2.1 ; Version tested: 2.1
ts_windows_takedamage 14 ts_windows_takedamage 12
ts_windows_use 48 ts_windows_use 44
ts_windows_pev 4 ts_windows_pev 4
ts_linux_takedamage 16 ts_linux_takedamage 14
ts_linux_use 50 ts_linux_use 46
ts_linux_pev 0 ts_linux_pev 0
ts_linux_classbase 0x60 ts_linux_classbase 0x470
; Data dated: 2007-02-23 ; Data dated: 2007-02-23
; Version tested: ?? (Most up to date) Steam (legitimate) ; Version tested: 1.5 Steam (legitimate)
tfc_windows_takedamage 12 tfc_windows_takedamage 14
tfc_windows_use 44 tfc_windows_use 48
tfc_windows_pev 4 tfc_windows_pev 4
tfc_linux_takedamage 14 tfc_linux_takedamage 16
tfc_linux_use 46 tfc_linux_use 50
tfc_linux_pev 0 tfc_linux_pev 0
tfc_linux_classbase 0x470 tfc_linux_classbase 0x60
; Data dated: 2007-02-23 ; Data dated: 2007-02-23
; Version tested: 3.0 ; Version tested: 3.0
@ -102,7 +113,7 @@ svencoop_windows_pev 4
; Data dated: 2007-02-26 ; Data dated: 2007-02-26
; Version tested: 2.18.07 ; Version tested: 2.18.07
; Earth's Special Forces (I can't find the non beta version, but it should still work! ; Earth's Special Forces (I can't find the non beta version, but it should still work!)
; ESF does not have a Linux binary! ; ESF does not have a Linux binary!
esf_openbeta_windows_takedamage 12 esf_openbeta_windows_takedamage 12
esf_openbeta_windows_use 46 esf_openbeta_windows_use 46

View File

@ -36,6 +36,20 @@
extern unsigned int HAM_pev; extern unsigned int HAM_pev;
extern unsigned int HAM_classbase; extern unsigned int HAM_classbase;
enum HAMHooks
{
HAM_TakeDamage,
HAM_Use,
HAM_AddPoints,
HAM_AddPointsToTeam,
HAM_Blocked,
HAM_Killed,
HAM_Respawn,
HAM_Restart,
HAM_TakeHealth,
HAM_END_DONT_USE_ME
};
inline edict_t *PrivateToEdict(const void *pdata) inline edict_t *PrivateToEdict(const void *pdata)
{ {

View File

@ -12,6 +12,10 @@
#pragma library hamsandwich #pragma library hamsandwich
#endif #endif
#if !defined _amxmodx_included
#include <amxmodx>
#endif
/** /**
* Ham Sandwich general usage * Ham Sandwich general usage
* - * -
@ -112,6 +116,15 @@ native hs_etakedamage(id,inflictor,attacker,Float:damage,type);
native hs_use(id,activator,caller,use_type,Float:use_value); native hs_use(id,activator,caller,use_type,Float:use_value);
native hs_euse(id,activator,caller,use_type,Float:use_value); native hs_euse(id,activator,caller,use_type,Float:use_value);
native hs_killed(id,attacker,gib);
native hs_ekilled(id,attacker,gib);
native hs_blocked(id,other);
native hs_eblocked(id,other);
native hs_respawn(id);
native hs_erespawn(id);
native hs_restart(id);
native hs_erestart(id);
enum enum
@ -133,7 +146,7 @@ enum
* Note: For now, this will also intercept calls to hs_takedamage * Note: For now, this will also intercept calls to hs_takedamage
* that is very likely to change shortly in the future. * that is very likely to change shortly in the future.
*/ */
native register_takedamage(const classname[], const function[]); native register_takedamage(const classname[], const function[], post=0);
/** /**
* Forwards all use routines that would occur to the given * Forwards all use routines that would occur to the given
@ -145,4 +158,31 @@ native register_takedamage(const classname[], const function[]);
* Note: For now, this will also intercept calls to hs_use * Note: For now, this will also intercept calls to hs_use
* that is very likely to change shortly in the future. * that is very likely to change shortly in the future.
*/ */
native register_use(const classname[], const function[]); native register_use(const classname[], const function[], post=0);
native register_killed(const classname[], const function[], post=0);
native register_blocked(const classname[], const function[], post=0);
native hs_register_respawn(const classname[], const function[], post=0);
native hs_register_restart(const classname[], const function[], post=0);
enum HAMHooks
{
HAM_TakeDamage,
HAM_Use,
HAM_AddPoints,
HAM_AddPointsToTeam,
HAM_Blocked,
HAM_Killed,
HAM_Respawn,
HAM_Restart,
HAM_TakeHealth,
HAM_END_DONT_USE_ME
};
native ham_register(HAMHooks:hook, const classname[], const function[], post=0);
public __fatal_ham_error(const reason[])
{
set_fail_state(reason);
}

View File

@ -133,7 +133,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="z:\metamod\metamod;z:\hlsdk\common;z:\hlsdk\engine;z:\hlsdk\dlls;z:\hlsdk\pm_shared;.." AdditionalIncludeDirectories="z:\metamod\metamod;z:\hlsdk\common;z:\hlsdk\engine;z:\hlsdk\dlls;z:\hlsdk\pm_shared;&quot;$(ProjectDir)\..\tableentries&quot;;&quot;$(ProjectDir)\..&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ns_amxx_EXPORTS" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ns_amxx_EXPORTS"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="3" RuntimeLibrary="3"
@ -214,6 +214,50 @@
> >
</File> </File>
</Filter> </Filter>
<Filter
Name="Entries"
>
<File
RelativePath="..\tableentries\AddPoints.cpp"
>
</File>
<File
RelativePath="..\tableentries\AddPointsToTeam.cpp"
>
</File>
<File
RelativePath="..\tableentries\Blocked.cpp"
>
</File>
<File
RelativePath="..\tableentries\Killed.cpp"
>
</File>
<File
RelativePath="..\tableentries\Respawn.cpp"
>
</File>
<File
RelativePath="..\tableentries\Restart.cpp"
>
</File>
<File
RelativePath="..\tableentries\TakeDamage.cpp"
>
</File>
<File
RelativePath="..\tableentries\TakeHealth.cpp"
>
</File>
<File
RelativePath="..\tableentries\Use.cpp"
>
</File>
<File
RelativePath="..\tableentries\VTableEntries.h"
>
</File>
</Filter>
<File <File
RelativePath="..\amxxapi.cpp" RelativePath="..\amxxapi.cpp"
> >
@ -234,10 +278,6 @@
RelativePath="..\Makefile" RelativePath="..\Makefile"
> >
</File> </File>
<File
RelativePath="..\natives.cpp"
>
</File>
<File <File
RelativePath="..\NEW_Util.h" RelativePath="..\NEW_Util.h"
> >
@ -255,11 +295,11 @@
> >
</File> </File>
<File <File
RelativePath="..\vtable.cpp" RelativePath="..\tableentries\VTableManager.cpp"
> >
</File> </File>
<File <File
RelativePath="..\VTableManager.h" RelativePath="..\tableentries\VTableManager.h"
> >
</File> </File>
</Files> </Files>

View File

@ -0,0 +1,363 @@
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "vfunc_gcc295.h"
#include "vfunc_msvc.h"
#include "NEW_Util.h"
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableAddPoints
#define ThisEntries AddPointsEntries
#define ThisKey "addpoints"
#define ThisNative "hs_addpoints"
#define ThisENative "hs_eaddpoints"
#define ThisRegisterID HAM_AddPoints
#define ThisParamCount 0
#define ThisVoidCall 1
unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL;
unsigned int *ThisVTable::baseoffset=NULL;
unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO callnatives[] = {
{ ThisNative, ThisVTable::NativeCall },
{ ThisENative, ThisVTable::ENativeCall },
{ NULL, NULL }
};
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
{
ThisVTable::pevoffset=poffset;
ThisVTable::pevset=pset;
ThisVTable::baseoffset=baseoffs;
ThisVTable::baseset=baseset;
ThisVTable::index=0;
ThisVTable::indexset=0;
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
};
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,ThisKey)==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
}
};
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
void ThisVTable::ConfigDone(void)
{
if (ThisVTable::indexset && *(ThisVTable::baseset))
{
MF_AddNatives(callnatives);
if (*(ThisVTable::pevset))
{
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
return;
}
}
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
// create an entity, assign it the gamedll's class, hook it and destroy it
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
// Simulate a call to hs_register_id_takedamage
cell tempparams[4];
memcpy(tempparams,params,sizeof(cell)*4);
tempparams[1]=ENTINDEX_NEW(Entity);
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
// class was not found
// throw an error alerting console that this hook did not happen
char *function=MF_GetAmxString(amx,params[2],0,NULL);
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0;
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
edict_t *Entity=INDEXENT_NEW(params[1]);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
return 1;
}
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::NativeCall(AMX *amx, cell *params)
{
// scan to see if this virtual function is a trampoline
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
int i=0;
int end=VTMan.ThisEntries.size();
while (i<end)
{
if (VTMan.ThisEntries[i]->IsTrampoline(func))
{
// this function is a trampoline
// use the original function instead
func=VTMan.ThisEntries[i]->GetOriginalFunction();
break;
}
++i;
}
// TODO: Inline ASM this
#ifdef _WIN32
reinterpret_cast<void (__fastcall *)(void *,int,int,int)>(func)(
pthis, /*this*/
0, /*fastcall buffer*/
params[2],
params[3]
);
#else
reinterpret_cast<void (*)(void *,int,int)>(func)(
pthis, /*this*/
params[2],
params[3]
);
#endif
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
{
VoidVCall2(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
params[2],
params[3]
);
return 1;
};
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
{
VTableEntryBase::CreateGenericTrampoline(manager,
vtable,
ThisVTable::index,
id,
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisVTable::EntryPoint),
ThisParamCount, // param count
ThisVoidCall, // voidcall
1); // thiscall
};
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
{
void *ptr=vtable[ThisVTable::index];
int i=0;
int end=manager->ThisEntries.size();
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL,FP_CELL,FP_DONE);
while (i<end)
{
if (manager->ThisEntries[i]->IsTrampoline(ptr))
{
// this function is already hooked!
if (post)
{
manager->ThisEntries[i]->AddPostForward(fwd);
}
else
{
manager->ThisEntries[i]->AddForward(fwd);
}
return;
}
++i;
}
// this function is NOT hooked
void *tramp;
void *func;
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
ThisVTable *entry=new ThisVTable;
entry->Setup(&vtable[ThisVTable::index],tramp,func);
manager->ThisEntries.push_back(entry);
if (post)
{
entry->AddPostForward(fwd);
}
else
{
entry->AddForward(fwd);
}
}
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @return Unsure. Does not appear to be used.
*/
void ThisVTable::Execute(void *pthis,int points, int allownegative)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,points,allownegative);
if (thisresult>result)
{
result=thisresult;
}
};
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
reinterpret_cast<void (__fastcall *)(void *,int,int,int)>(function)(pthis,0,points,allownegative);
#elif defined __linux__
reinterpret_cast<void (*)(void *,int,int)>(function)(pthis,points,allownegative);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis,points,allownegative);
}
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,int points,int allownegative)
{
VTMan.AddPointsEntries[id]->Execute(pthis,points,allownegative);
}

View File

@ -0,0 +1,362 @@
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "vfunc_gcc295.h"
#include "vfunc_msvc.h"
#include "NEW_Util.h"
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableAddPointsToTeam
#define ThisEntries AddPointsToTeamEntries
#define ThisKey "addpointstoteam"
#define ThisNative "hs_addpointstoteam"
#define ThisENative "hs_eaddpointstoteam"
#define ThisRegisterID HAM_AddPointsToTeam
#define ThisParamCount 2
#define ThisVoidCall 1
unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL;
unsigned int *ThisVTable::baseoffset=NULL;
unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO callnatives[] = {
{ ThisNative, ThisVTable::NativeCall },
{ ThisENative, ThisVTable::ENativeCall },
{ NULL, NULL }
};
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
{
ThisVTable::pevoffset=poffset;
ThisVTable::pevset=pset;
ThisVTable::baseoffset=baseoffs;
ThisVTable::baseset=baseset;
ThisVTable::index=0;
ThisVTable::indexset=0;
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
};
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,ThisKey)==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
}
};
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
void ThisVTable::ConfigDone(void)
{
if (ThisVTable::indexset && *(ThisVTable::baseset))
{
MF_AddNatives(callnatives);
if (*(ThisVTable::pevset))
{
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
}
}
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
// create an entity, assign it the gamedll's class, hook it and destroy it
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
// Simulate a call to hs_register_id_takedamage
cell tempparams[4];
memcpy(tempparams,params,sizeof(cell)*4);
tempparams[1]=ENTINDEX_NEW(Entity);
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
// class was not found
// throw an error alerting console that this hook did not happen
char *function=MF_GetAmxString(amx,params[2],0,NULL);
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0;
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
edict_t *Entity=INDEXENT_NEW(params[1]);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
return 1;
}
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::NativeCall(AMX *amx, cell *params)
{
// scan to see if this virtual function is a trampoline
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
int i=0;
int end=VTMan.ThisEntries.size();
while (i<end)
{
if (VTMan.ThisEntries[i]->IsTrampoline(func))
{
// this function is a trampoline
// use the original function instead
func=VTMan.ThisEntries[i]->GetOriginalFunction();
break;
}
++i;
}
// TODO: Inline ASM this
#ifdef _WIN32
reinterpret_cast<void (__fastcall *)(void *,int,int,int)>(func)(
pthis, /*this*/
0, /*fastcall buffer*/
params[2],
params[3]
);
#else
reinterpret_cast<void (*)(void *,int,int)>(func)(
pthis, /*this*/
params[2],
params[3]
);
#endif
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
{
VoidVCall2(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
params[2],
params[3]
);
return 1;
};
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
{
VTableEntryBase::CreateGenericTrampoline(manager,
vtable,
ThisVTable::index,
id,
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisVTable::EntryPoint),
ThisParamCount, // param count
ThisVoidCall, // voidcall
1); // thiscall
};
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
{
void *ptr=vtable[ThisVTable::index];
int i=0;
int end=manager->ThisEntries.size();
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL,FP_CELL,FP_DONE);
while (i<end)
{
if (manager->ThisEntries[i]->IsTrampoline(ptr))
{
// this function is already hooked!
if (post)
{
manager->ThisEntries[i]->AddPostForward(fwd);
}
else
{
manager->ThisEntries[i]->AddForward(fwd);
}
return;
}
++i;
}
// this function is NOT hooked
void *tramp;
void *func;
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
ThisVTable *entry=new ThisVTable;
entry->Setup(&vtable[ThisVTable::index],tramp,func);
manager->ThisEntries.push_back(entry);
if (post)
{
entry->AddPostForward(fwd);
}
else
{
entry->AddForward(fwd);
}
}
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @return Unsure. Does not appear to be used.
*/
void ThisVTable::Execute(void *pthis,int points, int allownegative)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,points,allownegative);
if (thisresult>result)
{
result=thisresult;
}
};
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
reinterpret_cast<void (__fastcall *)(void *,int,int,int)>(function)(pthis,0,points,allownegative);
#elif defined __linux__
reinterpret_cast<void (*)(void *,int,int)>(function)(pthis,points,allownegative);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis,points,allownegative);
}
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,int points,int allownegative)
{
VTMan.AddPointsToTeamEntries[id]->Execute(pthis,points,allownegative);
}

View File

@ -13,7 +13,14 @@
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions // Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableBlocked #define ThisVTable VTableBlocked
#define ThisEntries BlockedEntries #define ThisEntries BlockedEntries
#define ThisHook VHOOK_Blocked
#define ThisKey "blocked"
#define ThisNative "hs_blocked"
#define ThisENative "hs_eblocked"
#define ThisRegisterID HAM_Blocked
#define ThisParamCount 1
#define ThisVoidCall 1
unsigned int *ThisVTable::pevoffset=NULL; unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL; unsigned int *ThisVTable::pevset=NULL;
@ -22,11 +29,6 @@ unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0; unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0; unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO registernatives[] = {
{ "register_blocked", ThisVTable::RegisterNative },
{ NULL, NULL }
};
static AMX_NATIVE_INFO callnatives[] = { static AMX_NATIVE_INFO callnatives[] = {
{ "hs_blocked", ThisVTable::NativeCall }, { "hs_blocked", ThisVTable::NativeCall },
{ "hs_eblocked", ThisVTable::ENativeCall }, { "hs_eblocked", ThisVTable::ENativeCall },
@ -56,6 +58,8 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned
RegisterConfigCallback(ThisVTable::ConfigDone); RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix("blocked",ThisVTable::KeyValue); RegisterKeySuffix("blocked",ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
}; };
/** /**
@ -87,7 +91,7 @@ void ThisVTable::ConfigDone(void)
if (*(ThisVTable::pevset)) if (*(ThisVTable::pevset))
{ {
MF_AddNatives(registernatives); RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
} }
} }
}; };
@ -101,14 +105,6 @@ void ThisVTable::ConfigDone(void)
*/ */
cell ThisVTable::RegisterNative(AMX *amx, cell *params) cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{ {
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
// Get the classname // Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL); char *classname=MF_GetAmxString(amx,params[1],1,NULL);
@ -119,7 +115,11 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params)
if (Entity->pvPrivateData) if (Entity->pvPrivateData)
{ {
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid); // Simulate a call to hs_register_id_takedamage
cell tempparams[4];
memcpy(tempparams,params,sizeof(cell)*4);
tempparams[1]=ENTINDEX_NEW(Entity);
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
REMOVE_ENTITY(Entity); REMOVE_ENTITY(Entity);
return 1; return 1;
} }
@ -127,12 +127,46 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params)
REMOVE_ENTITY(Entity); REMOVE_ENTITY(Entity);
// class was not found // class was not found
// throw an error alerting console that this hook did not happen // throw an error alerting console that this hook did not happen
char *function=MF_GetAmxString(amx,params[2],0,NULL);
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function); MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0; return 0;
}; };
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
edict_t *Entity=INDEXENT_NEW(params[1]);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
return 1;
}
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
return 0;
};
/** /**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
* *
@ -142,8 +176,38 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params)
*/ */
cell ThisVTable::NativeCall(AMX *amx, cell *params) cell ThisVTable::NativeCall(AMX *amx, cell *params)
{ {
// TODO: This // scan to see if this virtual function is a trampoline
return 0; void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
int i=0;
int end=VTMan.ThisEntries.size();
while (i<end)
{
if (VTMan.ThisEntries[i]->IsTrampoline(func))
{
// this function is a trampoline
// use the original function instead
func=VTMan.ThisEntries[i]->GetOriginalFunction();
break;
}
++i;
}
// TODO: Inline ASM this
#ifdef _WIN32
reinterpret_cast<void (__fastcall *)(void *,int,void *)>(func)(
pthis, /*this*/
0, /*fastcall buffer*/
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
);
#else
reinterpret_cast<void (*)(void *,void *)>(func)(
pthis, /*this*/
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
);
#endif
return 1;
}; };
/** /**
@ -183,7 +247,7 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void
id, id,
outtrampoline, outtrampoline,
origfunc, origfunc,
reinterpret_cast<void *>(ThisHook), reinterpret_cast<void *>(ThisVTable::EntryPoint),
1, // param count 1, // param count
1, // voidcall 1, // voidcall
1); // thiscall 1); // thiscall
@ -199,7 +263,7 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void
* @param funcid The function id of the callback. * @param funcid The function id of the callback.
* @noreturn * @noreturn
*/ */
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid) void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
{ {
void *ptr=vtable[ThisVTable::index]; void *ptr=vtable[ThisVTable::index];
@ -212,7 +276,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu
{ {
// this function is already hooked! // this function is already hooked!
manager->ThisEntries[i]->AddForward(fwd); if (post)
{
manager->ThisEntries[i]->AddPostForward(fwd);
}
else
{
manager->ThisEntries[i]->AddForward(fwd);
}
return; return;
} }
@ -229,7 +300,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu
manager->ThisEntries.push_back(entry); manager->ThisEntries.push_back(entry);
entry->AddForward(fwd); if (post)
{
entry->AddPostForward(fwd);
}
else
{
entry->AddForward(fwd);
}
} }
@ -265,16 +343,24 @@ void ThisVTable::Execute(void *pthis, void *other)
} }
}; };
if (result>=HAM_SUPERCEDE) if (result<HAM_SUPERCEDE)
{ {
return; #if defined _WIN32
reinterpret_cast<void (__fastcall *)(void *,int, void *)>(function)(pthis,0,other);
#elif defined __linux__
reinterpret_cast<void (*)(void *,void *)>(function)(pthis,other);
#endif
} }
#if defined _WIN32 i=0;
reinterpret_cast<void (__fastcall *)(void *,int, void *)>(function)(pthis,0,other); end=PostForwards.size();
#elif defined __linux__ while (i<end)
reinterpret_cast<void (*)(void *,void *)>(function)(pthis,other); {
#endif MF_ExecuteForward(PostForwards[i++],iThis,iOther);
}
}; };
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,void *other)
{
VTMan.BlockedEntries[id]->Execute(pthis,other);
}

View File

@ -0,0 +1,368 @@
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "vfunc_gcc295.h"
#include "vfunc_msvc.h"
#include "NEW_Util.h"
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableKilled
#define ThisEntries KilledEntries
#define ThisKey "killed"
#define ThisNative "hs_killed"
#define ThisENative "hs_ekilled"
#define ThisRegisterID HAM_Killed
#define ThisParamCount 2
#define ThisVoidCall 1
unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL;
unsigned int *ThisVTable::baseoffset=NULL;
unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO callnatives[] = {
{ ThisNative, ThisVTable::NativeCall },
{ ThisENative, ThisVTable::ENativeCall },
{ NULL, NULL }
};
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
{
ThisVTable::pevoffset=poffset;
ThisVTable::pevset=pset;
ThisVTable::baseoffset=baseoffs;
ThisVTable::baseset=baseset;
ThisVTable::index=0;
ThisVTable::indexset=0;
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
};
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,ThisKey)==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
}
};
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
void ThisVTable::ConfigDone(void)
{
if (ThisVTable::indexset && *(ThisVTable::baseset))
{
MF_AddNatives(callnatives);
if (*(ThisVTable::pevset))
{
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
}
}
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
// create an entity, assign it the gamedll's class, hook it and destroy it
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
// Simulate a call to hs_register_id_takedamage
cell tempparams[4];
memcpy(tempparams,params,sizeof(cell)*4);
tempparams[1]=ENTINDEX_NEW(Entity);
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
// class was not found
// throw an error alerting console that this hook did not happen
char *function=MF_GetAmxString(amx,params[2],0,NULL);
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0;
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
edict_t *Entity=INDEXENT_NEW(params[1]);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
return 1;
}
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::NativeCall(AMX *amx, cell *params)
{
// scan to see if this virtual function is a trampoline
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
int i=0;
int end=VTMan.ThisEntries.size();
while (i<end)
{
if (VTMan.ThisEntries[i]->IsTrampoline(func))
{
// this function is a trampoline
// use the original function instead
func=VTMan.ThisEntries[i]->GetOriginalFunction();
break;
}
++i;
}
// TODO: Inline ASM this
#ifdef _WIN32
return reinterpret_cast<int (__fastcall *)(void *,int,void *,int)>(func)(
pthis, /*this*/
0, /*fastcall buffer*/
&(INDEXENT_NEW(params[2])->v), /*pevattacker*/
(int)params[3] /*gib*/
);
#else
return reinterpret_cast<int (*)(void *,void *,int)>(func)(
pthis, /*this*/
&(INDEXENT_NEW(params[2])->v), /*pevattacker*/
(int)params[3] /*gib*/
);
#endif
};
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
{
VoidVCall2(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
&(INDEXENT_NEW(params[2])->v), /*pevattacker*/
(int)params[3] /*gib*/
);
return 1;
};
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
{
VTableEntryBase::CreateGenericTrampoline(manager,
vtable,
ThisVTable::index,
id,
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisVTable::EntryPoint),
ThisParamCount, // param count
ThisVoidCall, // voidcall
1); // thiscall
};
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
{
void *ptr=vtable[ThisVTable::index];
int i=0;
int end=manager->ThisEntries.size();
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*attacker*/,FP_CELL/*gib*/,FP_DONE);
while (i<end)
{
if (manager->ThisEntries[i]->IsTrampoline(ptr))
{
// this function is already hooked!
if (post)
{
manager->ThisEntries[i]->AddPostForward(fwd);
}
else
{
manager->ThisEntries[i]->AddForward(fwd);
}
return;
}
++i;
}
// this function is NOT hooked
void *tramp;
void *func;
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
ThisVTable *entry=new ThisVTable;
entry->Setup(&vtable[ThisVTable::index],tramp,func);
manager->ThisEntries.push_back(entry);
if (post)
{
entry->AddPostForward(fwd);
}
else
{
entry->AddForward(fwd);
}
}
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param inflictor Damage inflictor.
* @param attacker The attacker who caused the inflictor to damage the victim.
* @param damage How much damage was caused.
* @param type Damage type (usually in bitmask form).
* @return Unsure. Does not appear to be used.
*/
void ThisVTable::Execute(void *pthis, void *attacker, int gib)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
int iAttacker=EntvarToIndex((entvars_t *)attacker);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iAttacker,gib);
if (thisresult>result)
{
result=thisresult;
}
};
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
reinterpret_cast<void (__fastcall *)(void *,int,void *,int)>(function)(pthis,0,attacker,gib);
#elif defined __linux__
reinterpret_cast<void (*)(void *,void *,int)>(function)(pthis,attacker,gib);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis,iAttacker,gib);
}
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,void *attacker,int gib)
{
VTMan.KilledEntries[id]->Execute(pthis,attacker,gib);
}

View File

@ -0,0 +1,356 @@
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "vfunc_gcc295.h"
#include "vfunc_msvc.h"
#include "NEW_Util.h"
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableRespawn
#define ThisEntries RespawnEntries
#define ThisKey "respawn"
#define ThisNative "hs_respawn"
#define ThisENative "hs_erespawn"
#define ThisRegisterID HAM_Respawn
#define ThisParamCount 0
#define ThisVoidCall 1
unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL;
unsigned int *ThisVTable::baseoffset=NULL;
unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO callnatives[] = {
{ "hs_respawn", ThisVTable::NativeCall },
{ "hs_respawn", ThisVTable::ENativeCall },
{ NULL, NULL }
};
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
{
ThisVTable::pevoffset=poffset;
ThisVTable::pevset=pset;
ThisVTable::baseoffset=baseoffs;
ThisVTable::baseset=baseset;
ThisVTable::index=0;
ThisVTable::indexset=0;
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
};
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,ThisKey)==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
}
};
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
void ThisVTable::ConfigDone(void)
{
if (ThisVTable::indexset && *(ThisVTable::baseset))
{
MF_AddNatives(callnatives);
if (*(ThisVTable::pevset))
{
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
}
}
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
// create an entity, assign it the gamedll's class, hook it and destroy it
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
// Simulate a call to hs_register_id_takedamage
cell tempparams[4];
memcpy(tempparams,params,sizeof(cell)*4);
tempparams[1]=ENTINDEX_NEW(Entity);
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
// class was not found
// throw an error alerting console that this hook did not happen
char *function=MF_GetAmxString(amx,params[2],0,NULL);
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0;
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
edict_t *Entity=INDEXENT_NEW(params[1]);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
return 1;
}
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::NativeCall(AMX *amx, cell *params)
{
// scan to see if this virtual function is a trampoline
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
int i=0;
int end=VTMan.ThisEntries.size();
while (i<end)
{
if (VTMan.ThisEntries[i]->IsTrampoline(func))
{
// this function is a trampoline
// use the original function instead
func=VTMan.ThisEntries[i]->GetOriginalFunction();
break;
}
++i;
}
// TODO: Inline ASM this
#ifdef _WIN32
return PrivateToIndex(reinterpret_cast<void *(__fastcall *)(void *,int)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
));
#else
return PrivateToIndex(reinterpret_cast<void *(*)(void *)>(func)(
pthis /*this*/
));
#endif
};
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
{
return PrivateToIndex(VCall0<void *>(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset) /*size of class*/
));
};
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
{
VTableEntryBase::CreateGenericTrampoline(manager,
vtable,
ThisVTable::index,
id,
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisVTable::EntryPoint),
ThisParamCount, // param count
ThisVoidCall, // voidcall
1); // thiscall
};
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
{
void *ptr=vtable[ThisVTable::index];
int i=0;
int end=manager->ThisEntries.size();
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
while (i<end)
{
if (manager->ThisEntries[i]->IsTrampoline(ptr))
{
// this function is already hooked!
if (post)
{
manager->ThisEntries[i]->AddPostForward(fwd);
}
else
{
manager->ThisEntries[i]->AddForward(fwd);
}
return;
}
++i;
}
// this function is NOT hooked
void *tramp;
void *func;
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
ThisVTable *entry=new ThisVTable;
entry->Setup(&vtable[ThisVTable::index],tramp,func);
manager->ThisEntries.push_back(entry);
if (post)
{
entry->AddPostForward(fwd);
}
else
{
entry->AddForward(fwd);
}
}
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @return Pointer to the this object it seems? Pointless
*/
void *ThisVTable::Execute(void *pthis)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
if (thisresult>result)
{
result=thisresult;
}
};
void *ret=NULL;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ret=reinterpret_cast<void *(__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ret=reinterpret_cast<void *(*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
return ret;
};
extern "C" void *ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.RespawnEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,356 @@
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "vfunc_gcc295.h"
#include "vfunc_msvc.h"
#include "NEW_Util.h"
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableRestart
#define ThisEntries RestartEntries
#define ThisKey "restart"
#define ThisNative "hs_restart"
#define ThisENative "hs_erestart"
#define ThisRegisterID HAM_Restart
#define ThisParamCount 0
#define ThisVoidCall 1
unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL;
unsigned int *ThisVTable::baseoffset=NULL;
unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO callnatives[] = {
{ ThisNative, ThisVTable::NativeCall },
{ ThisENative, ThisVTable::ENativeCall },
{ NULL, NULL }
};
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
{
ThisVTable::pevoffset=poffset;
ThisVTable::pevset=pset;
ThisVTable::baseoffset=baseoffs;
ThisVTable::baseset=baseset;
ThisVTable::index=0;
ThisVTable::indexset=0;
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
};
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,ThisKey)==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
}
};
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
void ThisVTable::ConfigDone(void)
{
if (ThisVTable::indexset && *(ThisVTable::baseset))
{
MF_AddNatives(callnatives);
if (*(ThisVTable::pevset))
{
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
}
}
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
// create an entity, assign it the gamedll's class, hook it and destroy it
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
// Simulate a call to hs_register_id_takedamage
cell tempparams[4];
memcpy(tempparams,params,sizeof(cell)*4);
tempparams[1]=ENTINDEX_NEW(Entity);
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
// class was not found
// throw an error alerting console that this hook did not happen
char *function=MF_GetAmxString(amx,params[2],0,NULL);
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0;
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
edict_t *Entity=INDEXENT_NEW(params[1]);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
return 1;
}
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::NativeCall(AMX *amx, cell *params)
{
// scan to see if this virtual function is a trampoline
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
int i=0;
int end=VTMan.ThisEntries.size();
while (i<end)
{
if (VTMan.ThisEntries[i]->IsTrampoline(func))
{
// this function is a trampoline
// use the original function instead
func=VTMan.ThisEntries[i]->GetOriginalFunction();
break;
}
++i;
}
// TODO: Inline ASM this
#ifdef _WIN32
reinterpret_cast<void (__fastcall *)(void *,int)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
reinterpret_cast<void (*)(void *)>(func)(
pthis /*this*/
);
#endif
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
{
VoidVCall0(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset) /*size of class*/
);
return 1;
};
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
{
VTableEntryBase::CreateGenericTrampoline(manager,
vtable,
ThisVTable::index,
id,
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisVTable::EntryPoint),
0, // param count
1, // voidcall
1); // thiscall
};
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
{
void *ptr=vtable[ThisVTable::index];
int i=0;
int end=manager->ThisEntries.size();
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
while (i<end)
{
if (manager->ThisEntries[i]->IsTrampoline(ptr))
{
// this function is already hooked!
if (post)
{
manager->ThisEntries[i]->AddPostForward(fwd);
}
else
{
manager->ThisEntries[i]->AddForward(fwd);
}
return;
}
++i;
}
// this function is NOT hooked
void *tramp;
void *func;
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
ThisVTable *entry=new ThisVTable;
entry->Setup(&vtable[ThisVTable::index],tramp,func);
manager->ThisEntries.push_back(entry);
if (post)
{
entry->AddPostForward(fwd);
}
else
{
entry->AddForward(fwd);
}
}
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @return Unsure. Does not appear to be used.
*/
void ThisVTable::Execute(void *pthis)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
if (thisresult>result)
{
result=thisresult;
}
};
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
reinterpret_cast<void (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
reinterpret_cast<void (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis)
{
VTMan.RestartEntries[id]->Execute(pthis);
}

View File

@ -2,7 +2,6 @@
#include "hamsandwich.h" #include "hamsandwich.h"
#include "hooks.h"
#include "VTableManager.h" #include "VTableManager.h"
#include "VTableEntries.h" #include "VTableEntries.h"
@ -14,7 +13,13 @@
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions // Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableTakeDamage #define ThisVTable VTableTakeDamage
#define ThisEntries TakeDamageEntries #define ThisEntries TakeDamageEntries
#define ThisHook VHOOK_TakeDamage
#define ThisKey "takedamage"
#define ThisNative "hs_takedamage"
#define ThisENative "hs_etakedamage"
#define ThisRegisterID HAM_TakeDamage
#define ThisParamCount 4
#define ThisVoidCall 0
unsigned int *ThisVTable::pevoffset=NULL; unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL; unsigned int *ThisVTable::pevset=NULL;
@ -23,14 +28,9 @@ unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0; unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0; unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO registernatives[] = {
{ "register_takedamage", ThisVTable::RegisterNative },
{ NULL, NULL }
};
static AMX_NATIVE_INFO callnatives[] = { static AMX_NATIVE_INFO callnatives[] = {
{ "hs_takedamage", ThisVTable::NativeCall }, { ThisNative, ThisVTable::NativeCall },
{ "hs_etakedamage", ThisVTable::ENativeCall }, { ThisENative, ThisVTable::ENativeCall },
{ NULL, NULL } { NULL, NULL }
}; };
@ -56,7 +56,9 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned
RegisterConfigCallback(ThisVTable::ConfigDone); RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix("takedamage",ThisVTable::KeyValue); RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
}; };
/** /**
@ -68,7 +70,7 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned
*/ */
void ThisVTable::KeyValue(const char *key, const char *data) void ThisVTable::KeyValue(const char *key, const char *data)
{ {
if (strcmp(key,"takedamage")==0) if (strcmp(key,ThisKey)==0)
{ {
ThisVTable::index=HAM_StrToNum(data); ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1; ThisVTable::indexset=1;
@ -88,7 +90,8 @@ void ThisVTable::ConfigDone(void)
if (*(ThisVTable::pevset)) if (*(ThisVTable::pevset))
{ {
MF_AddNatives(registernatives); //MF_AddNatives(registernatives);
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
} }
} }
}; };
@ -102,14 +105,6 @@ void ThisVTable::ConfigDone(void)
*/ */
cell ThisVTable::RegisterNative(AMX *amx, cell *params) cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{ {
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
// Get the classname // Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL); char *classname=MF_GetAmxString(amx,params[1],1,NULL);
@ -120,12 +115,18 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params)
if (Entity->pvPrivateData) if (Entity->pvPrivateData)
{ {
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid); // Simulate a call to hs_register_id_takedamage
cell tempparams[4];
memcpy(tempparams,params,sizeof(cell)*4);
tempparams[1]=ENTINDEX_NEW(Entity);
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
REMOVE_ENTITY(Entity); REMOVE_ENTITY(Entity);
return 1; return 1;
} }
REMOVE_ENTITY(Entity); REMOVE_ENTITY(Entity);
char *function=MF_GetAmxString(amx,params[2],0,NULL);
// class was not found // class was not found
// throw an error alerting console that this hook did not happen // throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function); MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
@ -134,6 +135,39 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params)
}; };
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
edict_t *Entity=INDEXENT_NEW(params[1]);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
return 1;
}
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
return 0;
};
/** /**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
* *
@ -220,9 +254,9 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void
id, id,
outtrampoline, outtrampoline,
origfunc, origfunc,
reinterpret_cast<void *>(ThisHook), reinterpret_cast<void *>(ThisVTable::EntryPoint),
4, // param count ThisParamCount, // param count
0, // voidcall ThisVoidCall, // voidcall
1); // thiscall 1); // thiscall
}; };
@ -236,7 +270,7 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void
* @param funcid The function id of the callback. * @param funcid The function id of the callback.
* @noreturn * @noreturn
*/ */
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid) void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
{ {
void *ptr=vtable[ThisVTable::index]; void *ptr=vtable[ThisVTable::index];
@ -249,7 +283,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu
{ {
// this function is already hooked! // this function is already hooked!
manager->ThisEntries[i]->AddForward(fwd); if (post)
{
manager->ThisEntries[i]->AddPostForward(fwd);
}
else
{
manager->ThisEntries[i]->AddForward(fwd);
}
return; return;
} }
@ -266,7 +307,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu
manager->ThisEntries.push_back(entry); manager->ThisEntries.push_back(entry);
entry->AddForward(fwd); if (post)
{
entry->AddPostForward(fwd);
}
else
{
entry->AddForward(fwd);
}
} }
@ -302,21 +350,32 @@ int ThisVTable::Execute(void *pthis, void *inflictor, void *attacker, float dama
result=thisresult; result=thisresult;
} }
}; };
int ireturn=0;
// stop here if (result<HAM_SUPERCEDE)
if (result>=HAM_SUPERCEDE)
{ {
return 0; #if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int,void *,void *,float,int)>(function)(pthis,0,inflictor,attacker,damage,type);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *,void *,void *,float,int)>(function)(pthis,inflictor,attacker,damage,type);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis,iInflictor,iAttacker,amx_ftoc2(damage),type);
} }
#if defined _WIN32
int ireturn=reinterpret_cast<int (__fastcall *)(void *,int,void *,void *,float,int)>(function)(pthis,0,inflictor,attacker,damage,type);
#elif defined __linux__
int ireturn=reinterpret_cast<int (*)(void *,void *,void *,float,int)>(function)(pthis,inflictor,attacker,damage,type);
#endif
if (result!=HAM_OVERRIDE) if (result!=HAM_OVERRIDE)
return ireturn; return ireturn;
return 0; return 0;
}; };
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis,void *inflictor,void *attacker,float damage,int type)
{
return VTMan.TakeDamageEntries[id]->Execute(pthis,inflictor,attacker,damage,type);
}

View File

@ -0,0 +1,374 @@
#include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "VTableManager.h"
#include "VTableEntries.h"
#include "vfunc_gcc295.h"
#include "vfunc_msvc.h"
#include "NEW_Util.h"
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableTakeHealth
#define ThisEntries TakeHealthEntries
#define ThisKey "takehealth"
#define ThisNative "hs_takehealth"
#define ThisENative "hs_etakehealth"
#define ThisRegisterID HAM_TakeHealth
#define ThisParamCount 2
#define ThisVoidCall 0
unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL;
unsigned int *ThisVTable::baseoffset=NULL;
unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO callnatives[] = {
{ ThisNative, ThisVTable::NativeCall },
{ ThisENative, ThisVTable::ENativeCall },
{ NULL, NULL }
};
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
{
ThisVTable::pevoffset=poffset;
ThisVTable::pevset=pset;
ThisVTable::baseoffset=baseoffs;
ThisVTable::baseset=baseset;
ThisVTable::index=0;
ThisVTable::indexset=0;
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
};
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,ThisKey)==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
}
};
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
void ThisVTable::ConfigDone(void)
{
if (ThisVTable::indexset && *(ThisVTable::baseset))
{
MF_AddNatives(callnatives);
if (*(ThisVTable::pevset))
{
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
}
}
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{
// Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
// create an entity, assign it the gamedll's class, hook it and destroy it
edict_t *Entity=CREATE_ENTITY();
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
if (Entity->pvPrivateData)
{
// Simulate a call to hs_register_id_TakeHealth
cell tempparams[4];
memcpy(tempparams,params,sizeof(cell)*4);
tempparams[1]=ENTINDEX_NEW(Entity);
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
REMOVE_ENTITY(Entity);
return 1;
}
REMOVE_ENTITY(Entity);
char *function=MF_GetAmxString(amx,params[2],0,NULL);
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
return 0;
};
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
edict_t *Entity=INDEXENT_NEW(params[1]);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
return 1;
}
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
return 0;
};
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::NativeCall(AMX *amx, cell *params)
{
// scan to see if this virtual function is a trampoline
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
int i=0;
int end=VTMan.ThisEntries.size();
while (i<end)
{
if (VTMan.ThisEntries[i]->IsTrampoline(func))
{
// this function is a trampoline
// use the original function instead
func=VTMan.ThisEntries[i]->GetOriginalFunction();
break;
}
++i;
}
// TODO: Inline ASM this
#ifdef _WIN32
return reinterpret_cast<int (__fastcall *)(void *,int,void *,void *,float,int)>(func)(
pthis, /*this*/
0, /*fastcall buffer*/
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
&(INDEXENT_NEW(params[3])->v), /*attacker*/
amx_ctof2(params[4]), /*damage*/
(int)params[5] /*dmgtype*/
);
#else
return reinterpret_cast<int (*)(void *,void *,void *,float,int)>(func)(
pthis, /*this*/
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
&(INDEXENT_NEW(params[3])->v), /*attacker*/
amx_ctof2(params[4]), /*damage*/
(int)params[5] /*dmgtype*/
);
#endif
};
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
{
return VCall4<int>(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
&(INDEXENT_NEW(params[3])->v), /*attacker*/
amx_ctof2(params[4]), /*damage*/
(int)params[5] /*dmgtype*/
);
};
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
{
VTableEntryBase::CreateGenericTrampoline(manager,
vtable,
ThisVTable::index,
id,
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisVTable::EntryPoint),
ThisParamCount, // param count
ThisVoidCall, // voidcall
1); // thiscall
};
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
{
void *ptr=vtable[ThisVTable::index];
int i=0;
int end=manager->ThisEntries.size();
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*amount*/,FP_CELL/*type*/,FP_DONE);
while (i<end)
{
if (manager->ThisEntries[i]->IsTrampoline(ptr))
{
// this function is already hooked!
if (post)
{
manager->ThisEntries[i]->AddPostForward(fwd);
}
else
{
manager->ThisEntries[i]->AddForward(fwd);
}
return;
}
++i;
}
// this function is NOT hooked
void *tramp;
void *func;
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
ThisVTable *entry=new ThisVTable;
entry->Setup(&vtable[ThisVTable::index],tramp,func);
manager->ThisEntries.push_back(entry);
if (post)
{
entry->AddPostForward(fwd);
}
else
{
entry->AddForward(fwd);
}
}
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param inflictor Damage inflictor.
* @param attacker The attacker who caused the inflictor to damage the victim.
* @param damage How much damage was caused.
* @param type Damage type (usually in bitmask form).
* @return Unsure. Does not appear to be used.
*/
int ThisVTable::Execute(void *pthis, float amount, int type)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,amx_ftoc2(amount),type);
if (thisresult>result)
{
result=thisresult;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int,float,int)>(function)(pthis,0,amount,type);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *,float,int)>(function)(pthis,amount,type);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis,amx_ftoc2(amount),type);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};

View File

@ -13,7 +13,14 @@
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions // Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
#define ThisVTable VTableUse #define ThisVTable VTableUse
#define ThisEntries UseEntries #define ThisEntries UseEntries
#define ThisHook VHOOK_Use
#define ThisKey "use"
#define ThisNative "hs_use"
#define ThisENative "hs_euse"
#define ThisRegisterID HAM_Use
#define ThisParamCount 4
#define ThisVoidCall 1
unsigned int *ThisVTable::pevoffset=NULL; unsigned int *ThisVTable::pevoffset=NULL;
unsigned int *ThisVTable::pevset=NULL; unsigned int *ThisVTable::pevset=NULL;
@ -22,14 +29,9 @@ unsigned int *ThisVTable::baseset=0;
unsigned int ThisVTable::index=0; unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0; unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO registernatives[] = {
{ "register_use", ThisVTable::RegisterNative },
{ NULL, NULL }
};
static AMX_NATIVE_INFO callnatives[] = { static AMX_NATIVE_INFO callnatives[] = {
{ "hs_use", ThisVTable::NativeCall }, { ThisNative, ThisVTable::NativeCall },
{ "hs_euse", ThisVTable::ENativeCall }, { ThisENative, ThisVTable::ENativeCall },
{ NULL, NULL } { NULL, NULL }
}; };
@ -55,7 +57,9 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned
RegisterConfigCallback(ThisVTable::ConfigDone); RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix("use",ThisVTable::KeyValue); RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
}; };
/** /**
@ -67,7 +71,7 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned
*/ */
void ThisVTable::KeyValue(const char *key, const char *data) void ThisVTable::KeyValue(const char *key, const char *data)
{ {
if (strcmp(key,"use")==0) if (strcmp(key,ThisKey)==0)
{ {
ThisVTable::index=HAM_StrToNum(data); ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1; ThisVTable::indexset=1;
@ -87,7 +91,7 @@ void ThisVTable::ConfigDone(void)
if (*(ThisVTable::pevset)) if (*(ThisVTable::pevset))
{ {
MF_AddNatives(registernatives); RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
} }
} }
}; };
@ -101,14 +105,6 @@ void ThisVTable::ConfigDone(void)
*/ */
cell ThisVTable::RegisterNative(AMX *amx, cell *params) cell ThisVTable::RegisterNative(AMX *amx, cell *params)
{ {
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
// Get the classname // Get the classname
char *classname=MF_GetAmxString(amx,params[1],1,NULL); char *classname=MF_GetAmxString(amx,params[1],1,NULL);
@ -119,12 +115,19 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params)
if (Entity->pvPrivateData) if (Entity->pvPrivateData)
{ {
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid); // Simulate a call to hs_register_id_takedamage
cell tempparams[4];
memcpy(tempparams,params,sizeof(cell)*4);
tempparams[1]=ENTINDEX_NEW(Entity);
printf("TEMPPARAMS[1]==%d\n",tempparams[1]);
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
REMOVE_ENTITY(Entity); REMOVE_ENTITY(Entity);
return 1; return 1;
} }
REMOVE_ENTITY(Entity); REMOVE_ENTITY(Entity);
char *function=MF_GetAmxString(amx,params[2],0,NULL);
// class was not found // class was not found
// throw an error alerting console that this hook did not happen // throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function); MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
@ -133,6 +136,40 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params)
}; };
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
{
int funcid;
char *function=MF_GetAmxString(amx,params[2],0,NULL);
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
return 0;
}
printf("PARAMS[1]==%d\n",params[1]);
edict_t *Entity=INDEXENT_NEW(params[1]);
if (Entity->pvPrivateData)
{
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
return 1;
}
// class was not found
// throw an error alerting console that this hook did not happen
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
return 0;
};
/** /**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
* *
@ -142,7 +179,43 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params)
*/ */
cell ThisVTable::NativeCall(AMX *amx, cell *params) cell ThisVTable::NativeCall(AMX *amx, cell *params)
{ {
// TODO: This // scan to see if this virtual function is a trampoline
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
int i=0;
int end=VTMan.ThisEntries.size();
while (i<end)
{
if (VTMan.ThisEntries[i]->IsTrampoline(func))
{
// this function is a trampoline
// use the original function instead
func=VTMan.ThisEntries[i]->GetOriginalFunction();
break;
}
++i;
}
// TODO: Inline ASM this
#ifdef _WIN32
reinterpret_cast<void (__fastcall *)(void *,int,void *, void *, int, float)>(func)(
pthis, /*this*/
0, /*fastcall buffer*/
INDEXENT_NEW(params[2])->pvPrivateData,
INDEXENT_NEW(params[3])->pvPrivateData,
params[4],
amx_ctof2(params[5])
);
#else
reinterpret_cast<void (*)(void *,void *, void *, int, float)>(func)(
pthis, /*this*/
INDEXENT_NEW(params[2])->pvPrivateData,
INDEXENT_NEW(params[3])->pvPrivateData,
params[4],
amx_ctof2(params[5])
);
#endif
return 0; return 0;
}; };
@ -185,9 +258,9 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void
id, id,
outtrampoline, outtrampoline,
origfunc, origfunc,
reinterpret_cast<void *>(ThisHook), reinterpret_cast<void *>(ThisVTable::EntryPoint),
4, // param count ThisParamCount, // param count
1, // voidcall ThisVoidCall, // voidcall
1); // thiscall 1); // thiscall
}; };
@ -201,7 +274,7 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void
* @param funcid The function id of the callback. * @param funcid The function id of the callback.
* @noreturn * @noreturn
*/ */
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid) void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
{ {
void *ptr=vtable[ThisVTable::index]; void *ptr=vtable[ThisVTable::index];
@ -214,7 +287,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu
{ {
// this function is already hooked! // this function is already hooked!
manager->ThisEntries[i]->AddForward(fwd); if (post)
{
manager->ThisEntries[i]->AddPostForward(fwd);
}
else
{
manager->ThisEntries[i]->AddForward(fwd);
}
return; return;
} }
@ -231,7 +311,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu
manager->ThisEntries.push_back(entry); manager->ThisEntries.push_back(entry);
entry->AddForward(fwd); if (post)
{
entry->AddForward(fwd);
}
else
{
entry->AddPostForward(fwd);
}
} }
@ -268,15 +355,27 @@ void ThisVTable::Execute(void *pthis, void *activator, void *caller, int type, f
} }
}; };
if (result>=HAM_SUPERCEDE)
if (result<HAM_SUPERCEDE)
{ {
return; #if defined _WIN32
reinterpret_cast<void (__fastcall *)(void *,int,void *,void *,int,float)>(function)(pthis,0,activator,caller,type,value);
#elif defined __linux__
reinterpret_cast<void (*)(void *,void *,void *,int,float)>(function)(pthis,activator,caller,type,value);
#endif
} }
#if defined _WIN32 i=0;
reinterpret_cast<void (__fastcall *)(void *,int,void *,void *,int,float)>(function)(pthis,0,activator,caller,type,value);
#elif defined __linux__ end=PostForwards.size();
reinterpret_cast<void (*)(void *,void *,void *,int,float)>(function)(pthis,activator,caller,type,value);
#endif while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis,iActivator,iCaller,type,amx_ftoc2(value));
};
}; };
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,void *activator,void *caller,int type,float value)
{
VTMan.UseEntries[id]->Execute(pthis,activator,caller,type,value);
}

View File

@ -32,9 +32,13 @@
#ifndef VTABLEENTRIES_H #ifndef VTABLEENTRIES_H
#define VTABLEENTRIES_H #define VTABLEENTRIES_H
#include "CVector.h" #ifdef _WIN32
#define HAM_CDECL __cdecl
#else
#define HAM_CDECL __attribute__((cdecl))
#endif
#include "hooks.h" #include "CVector.h"
class VTableManager; class VTableManager;
@ -45,6 +49,7 @@ public:
void **location; /**< The location of the vtable entry that is being hooked. */ void **location; /**< The location of the vtable entry that is being hooked. */
void *trampoline; /**< Our trampoline (needs to be freed when it's not hooking any more!). */ void *trampoline; /**< Our trampoline (needs to be freed when it's not hooking any more!). */
CVector<int> Forwards; /**< Vector of forwards to call for this hook.*/ CVector<int> Forwards; /**< Vector of forwards to call for this hook.*/
CVector<int> PostForwards; /**< Vector of forwards to call for this post hook.*/
/** /**
* Saves virtual table location, trampoline and function pointers. * Saves virtual table location, trampoline and function pointers.
@ -87,6 +92,7 @@ public:
free(trampoline); free(trampoline);
Forwards.clear(); Forwards.clear();
PostForwards.clear();
}; };
/** /**
@ -141,6 +147,17 @@ public:
Forwards.push_back(fwd); Forwards.push_back(fwd);
}; };
/**
* Adds a forward to this entry's post forward vector.
*
* @param fwd Forward index to add.
* @noreturn
*/
void AddPostForward(int fwd)
{
PostForwards.push_back(fwd);
};
/** /**
* Creates a generic trampoline. * Creates a generic trampoline.
* *
@ -159,6 +176,121 @@ public:
}; };
class VTableTraceAttack : public VTableEntryBase
{
public:
static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */
static unsigned int *pevset; /**< Whether or not pev entry has been set */
static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */
static unsigned int *baseset; /**< Whether or base offset value has been set. */
static unsigned int index; /**< This entry's virtual table index. */
static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset);
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
static void KeyValue(const char *key, const char *data);
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
static void ConfigDone(void);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterIDNative(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell ENativeCall(AMX *amx, cell *params);
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post);
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param inflictor Damage inflictor.
* @param attacker The attacker who caused the inflictor to damage the victim.
* @param damage How much damage was caused.
* @param type Damage type (usually in bitmask form).
* @return Unsure. Does not appear to be used.
*/
int Execute(void *pthis, void *pevattacker, float flDamage, float *direction, void *tr, int bitsDamageType);
/**
* The hook that is directly called by the trampoline.
*
* @param id The index of the hook to call.
* @param pthis The "this" pointer.
*/
static HAM_CDECL void EntryPoint(int id,void *pthis,void *pevattacker,float flDamage,float *direction,void *tr,int bits);
};
class VTableTakeDamage : public VTableEntryBase class VTableTakeDamage : public VTableEntryBase
{ {
public: public:
@ -205,6 +337,15 @@ public:
*/ */
static cell RegisterNative(AMX *amx, cell *params); static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterIDNative(AMX *amx, cell *params);
/** /**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
* *
@ -243,7 +384,7 @@ public:
* @param funcid The function id of the callback. * @param funcid The function id of the callback.
* @noreturn * @noreturn
*/ */
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid); static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post);
/** /**
* Execute the command. This is called directly from our global hook function. * Execute the command. This is called directly from our global hook function.
@ -256,6 +397,127 @@ public:
* @return Unsure. Does not appear to be used. * @return Unsure. Does not appear to be used.
*/ */
int Execute(void *pthis, void *inflictor, void *attacker, float damage, int type); int Execute(void *pthis, void *inflictor, void *attacker, float damage, int type);
/**
* The hook that is directly called by the trampoline.
*
* @param id The index of the hook to call.
* @param pthis The "this" pointer.
*/
static HAM_CDECL int EntryPoint(int id,void *pthis,void *inflictor,void *attacker,float damage,int type);
};
class VTableKilled : public VTableEntryBase
{
public:
static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */
static unsigned int *pevset; /**< Whether or not pev entry has been set */
static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */
static unsigned int *baseset; /**< Whether or base offset value has been set. */
static unsigned int index; /**< This entry's virtual table index. */
static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset);
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
static void KeyValue(const char *key, const char *data);
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
static void ConfigDone(void);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterIDNative(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell ENativeCall(AMX *amx, cell *params);
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post);
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param attacker The attacker who caused the inflictor to damage the victim.
* @param gib Whether to gib or not.
* @noreturn
*/
void Execute(void *pthis, void *attacker, int gib);
/**
* The hook that is directly called by the trampoline.
*
* @param id The index of the hook to call.
* @param pthis The "this" pointer.
*/
static HAM_CDECL void EntryPoint(int id,void *pthis,void *attacker, int gib);
}; };
class VTableUse : public VTableEntryBase class VTableUse : public VTableEntryBase
{ {
@ -312,6 +574,15 @@ public:
*/ */
static cell NativeCall(AMX *amx, cell *params); static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterIDNative(AMX *amx, cell *params);
/** /**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
* *
@ -341,7 +612,7 @@ public:
* @param funcid The function id of the callback. * @param funcid The function id of the callback.
* @noreturn * @noreturn
*/ */
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid); static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post);
/** /**
* Execute the command. This is called directly from our global hook function. * Execute the command. This is called directly from our global hook function.
@ -354,6 +625,15 @@ public:
* @noreturn * @noreturn
*/ */
void Execute(void *pthis, void *activator, void *caller, int type, float value); void Execute(void *pthis, void *activator, void *caller, int type, float value);
/**
* The hook that is directly called by the trampoline.
*
* @param id The index of the hook to call.
* @param pthis The "this" pointer.
*/
static HAM_CDECL void EntryPoint(int id,void *pthis, void *activator, void *caller, int type, float value);
}; };
class VTableBlocked : public VTableEntryBase class VTableBlocked : public VTableEntryBase
{ {
@ -401,6 +681,15 @@ public:
*/ */
static cell RegisterNative(AMX *amx, cell *params); static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterIDNative(AMX *amx, cell *params);
/** /**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
* *
@ -439,17 +728,474 @@ public:
* @param funcid The function id of the callback. * @param funcid The function id of the callback.
* @noreturn * @noreturn
*/ */
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid); static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post);
/** /**
* Execute the command. This is called directly from our global hook function. * Execute the command. This is called directly from our global hook function.
* *
* @param pthis The "this" pointer, cast to a void. The victim. * @param pthis The "this" pointer, cast to a void. The victim.
* @param activator Entity that's blocking. * @param other Entity that's blocking.
* @noreturn * @noreturn
*/ */
void Execute(void *pthis, void *other); void Execute(void *pthis, void *other);
/**
* The hook that is directly called by the trampoline.
*
* @param id The index of the hook to call.
* @param pthis The "this" pointer.
*/
static HAM_CDECL void EntryPoint(int id,void *pthis,void *other);
}; };
class VTableRespawn : public VTableEntryBase
{
public:
static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */
static unsigned int *pevset; /**< Whether or not pev entry has been set */
static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */
static unsigned int *baseset; /**< Whether or base offset value has been set. */
static unsigned int index; /**< This entry's virtual table index. */
static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset);
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
static void KeyValue(const char *key, const char *data);
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
static void ConfigDone(void);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterIDNative(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell ENativeCall(AMX *amx, cell *params);
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post);
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param other Entity that's blocking.
* @noreturn
*/
void *Execute(void *pthis);
/**
* The hook that is directly called by the trampoline.
*
* @param id The index of the hook to call.
* @param pthis The "this" pointer.
*/
static void *EntryPoint(int id,void *pthis);
};
class VTableRestart : public VTableEntryBase
{
public:
static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */
static unsigned int *pevset; /**< Whether or not pev entry has been set */
static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */
static unsigned int *baseset; /**< Whether or base offset value has been set. */
static unsigned int index; /**< This entry's virtual table index. */
static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset);
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
static void KeyValue(const char *key, const char *data);
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
static void ConfigDone(void);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterIDNative(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell ENativeCall(AMX *amx, cell *params);
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post);
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param other Entity that's blocking.
* @noreturn
*/
void Execute(void *pthis);
/**
* The hook that is directly called by the trampoline.
*
* @param id The index of the hook to call.
* @param pthis The "this" pointer.
*/
static HAM_CDECL void EntryPoint(int id,void *pthis);
};
class VTableAddPoints : public VTableEntryBase
{
public:
static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */
static unsigned int *pevset; /**< Whether or not pev entry has been set */
static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */
static unsigned int *baseset; /**< Whether or base offset value has been set. */
static unsigned int index; /**< This entry's virtual table index. */
static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset);
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
static void KeyValue(const char *key, const char *data);
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
static void ConfigDone(void);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterIDNative(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell ENativeCall(AMX *amx, cell *params);
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post);
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param other Entity that's blocking.
* @noreturn
*/
void Execute(void *pthis, int points, int allowneg);
/**
* The hook that is directly called by the trampoline.
*
* @param id The index of the hook to call.
* @param pthis The "this" pointer.
*/
static HAM_CDECL void EntryPoint(int id,void *pthis,int points,int allownegative);
};
class VTableAddPointsToTeam : public VTableEntryBase
{
public:
static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */
static unsigned int *pevset; /**< Whether or not pev entry has been set */
static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */
static unsigned int *baseset; /**< Whether or base offset value has been set. */
static unsigned int index; /**< This entry's virtual table index. */
static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */
/**
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
*
* @param poffset Pointer to an integer that stores the pev offset for this mod.
* @param pset Pointer to an integer that tells whether pev offset was set or not.
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
* @param baseset Pointer to an integer that tells whether class base offset has been set.
* @noreturn
*/
static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset);
/**
* Called when one of this table entry's keyvalues is caught in a config file.
*
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
* @param data The data this keyvalue is set to.
* @noreturn
*/
static void KeyValue(const char *key, const char *data);
/**
* Called immediately after the config file is done being parsed. Register our natives here.
*
* @noreturn
*/
static void ConfigDone(void);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterNative(AMX *amx, cell *params);
/**
* A plugin is registering this entry's virtual hook. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell RegisterIDNative(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell NativeCall(AMX *amx, cell *params);
/**
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
*
* @param amx The AMX structure for the plugin.
* @param params The parameters passed from the plugin.
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
*/
static cell ENativeCall(AMX *amx, cell *params);
/**
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param outtrampoline The trampoline that was created.
* @param origfunc The original function that was hooked.
* @noreturn
*/
static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc);
/**
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
*
* @param manager The VTableManager this is a child of.
* @param vtable The virtual table we're molesting.
* @param plugin The plugin that's requesting this.
* @param funcid The function id of the callback.
* @noreturn
*/
static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post);
/**
* Execute the command. This is called directly from our global hook function.
*
* @param pthis The "this" pointer, cast to a void. The victim.
* @param other Entity that's blocking.
* @noreturn
*/
void Execute(void *pthis, int points, int allowneg);
/**
* The hook that is directly called by the trampoline.
*
* @param id The index of the hook to call.
* @param pthis The "this" pointer.
*/
static HAM_CDECL void EntryPoint(int id,void *pthis,int points,int allownegative);
};
//TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); //TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
/*class VTableTraceAttack : public VTableEntryBase /*class VTableTraceAttack : public VTableEntryBase
{ {

View File

@ -1,10 +1,98 @@
#include "sdk/amxxmodule.h" #include "sdk/amxxmodule.h"
#include "hamsandwich.h"
#include "VTableManager.h" #include "VTableManager.h"
#include "VTableEntries.h" #include "VTableEntries.h"
#include "NEW_Util.h" #include "NEW_Util.h"
VTableManager VTMan;
NATIVEFUNC VTableManager::RegisterNatives[HAM_END_DONT_USE_ME];
NATIVEFUNC VTableManager::RegisterIDNatives[HAM_END_DONT_USE_ME];
const char *VTableManager::RegisterNames[HAM_END_DONT_USE_ME];
void RegisterThisRegister(int index,NATIVEFUNC byname, NATIVEFUNC byid)
{
VTableManager::RegisterNatives[index]=byname;
VTableManager::RegisterIDNatives[index]=byid;
}
void RegisterThisRegisterName(int index, const char *name)
{
VTableManager::RegisterNames[index]=name;
}
static AMX_NATIVE_INFO registernatives[] = {
{ "ham_register", VTableManager::Register },
{ "ham_registerid", VTableManager::RegisterID },
{ NULL, NULL }
};
void RegisterRegisterNatives(void)
{
MF_AddNatives(registernatives);
}
cell VTableManager::Register(AMX *amx, cell *params)
{
int id=params[1];
if (id<0 || id>=HAM_END_DONT_USE_ME || RegisterIDNatives[id]==NULL)
{
// this register is not found, fail the plugin
int fwd=MF_RegisterSPForwardByName(amx,"__fatal_ham_error",FP_STRING,FP_DONE);
char error[]="Requested to hs_registerid a function ID that is not registered in configs/hamdata.ini, cannot continue.";
int errorcell=MF_PrepareCharArray(&error[0],strlen(error)+1);
MF_ExecuteForward(fwd,errorcell);
MF_UnregisterSPForward(fwd);
return 0;
}
cell tempparams[4];
// remove one parameter from this param count
tempparams[0]=(params[0]-(sizeof(cell)));
tempparams[1]=params[2];
tempparams[2]=params[3];
tempparams[3]=params[4];
return RegisterNatives[id](amx,&tempparams[0]);
}
cell VTableManager::RegisterID(AMX *amx, cell *params)
{
int id=params[1];
if (id<0 || id>=HAM_END_DONT_USE_ME || RegisterNatives[id]==NULL)
{
// this register is not found, fail the plugin
int fwd=MF_RegisterSPForwardByName(amx,"__fatal_ham_error",FP_STRING,FP_DONE);
char error[]="Requested to hs_register a function ID that is not registered in configs/hamdata.ini, cannot continue.";
int errorcell=MF_PrepareCharArray(&error[0],strlen(error)+1);
MF_ExecuteForward(fwd,errorcell);
MF_UnregisterSPForward(fwd);
return 0;
}
cell tempparams[4];
// remove one parameter from this param count
tempparams[0]=(params[0]-(sizeof(cell)));
tempparams[1]=params[2];
tempparams[2]=params[3];
tempparams[3]=params[4];
return RegisterIDNatives[id](amx,&tempparams[0]);
}
void *VTableManager::InsertIntoVTable(void **vtable, int index, void *trampoline) void *VTableManager::InsertIntoVTable(void **vtable, int index, void *trampoline)
{ {
void *func; void *func;

View File

@ -3,8 +3,9 @@
#include "Trampolines.h" #include "Trampolines.h"
#include "hamsandwich.h"
#include "CVector.h" #include "CVector.h"
#include "hooks.h"
#include "VTableEntries.h" #include "VTableEntries.h"
/* !!WARNING: HERE BE DRAGONS /* !!WARNING: HERE BE DRAGONS
@ -72,22 +73,38 @@ enum
}; };
typedef cell (*NATIVEFUNC)(AMX *, cell *);
class VTableManager class VTableManager
{ {
public: public:
CVector<VTableUse *> UseEntries; #define VTINIT(Type) CVector<VTable##Type *> Type##Entries
CVector<VTableTakeDamage *> TakeDamageEntries; VTINIT(Use);
CVector<VTableBlocked *> BlockedEntries; VTINIT(TakeDamage);
VTINIT(Blocked);
VTINIT(Killed);
VTINIT(Respawn);
VTINIT(Restart);
VTINIT(AddPoints);
VTINIT(AddPointsToTeam);
#undef VTINIT
static NATIVEFUNC RegisterNatives[HAM_END_DONT_USE_ME];
static NATIVEFUNC RegisterIDNatives[HAM_END_DONT_USE_ME];
static const char *RegisterNames[HAM_END_DONT_USE_ME];
static cell Register(AMX *amx, cell *params);
static cell RegisterID(AMX *amx, cell *params);
/* returns the original function */ /* returns the original function */
void *InsertIntoVTable(void **vtable, int index, void *trampoline); void *InsertIntoVTable(void **vtable, int index, void *trampoline);
void Cleanup(void); void Cleanup(void);
}; };
void RegisterThisRegister(int index,NATIVEFUNC byname, NATIVEFUNC byid);
void RegisterThisRegisterName(int index, const char *name);
void RegisterRegisterNatives(void);
extern VTableManager VTMan; extern VTableManager VTMan;
//#include "VTableEntries.h"
#endif // VTABLEMANAGER_H #endif // VTABLEMANAGER_H

View File

@ -80,6 +80,46 @@ inline RetType VCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, P
fptr function=reinterpret_cast<fptr>(vtbl[ventry]); fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
return function(pThis,pa,pb,pc,pd); return function(pThis,pa,pb,pc,pd);
}; };
template <class PTypeA, class PTypeB, class PTypeC>
inline void VoidVCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
int **vtbl=*(int ***)pcThis;
typedef void (*fptr)(void*,PTypeA,PTypeB,PTypeC);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
function(pThis,pa,pb,pc);
};
template <class RetType, class PTypeA, class PTypeB, class PTypeC>
inline RetType VCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
int **vtbl=*(int ***)pcThis;
typedef RetType (*fptr)(void*,PTypeA,PTypeB,PTypeC);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
return function(pThis,pa,pb,pc);
};
template <class PTypeA, class PTypeB>
inline void VoidVCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
int **vtbl=*(int ***)pcThis;
typedef void (*fptr)(void*,PTypeA,PTypeB);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
function(pThis,pa,pb);
};
template <class RetType, class PTypeA, class PTypeB>
inline RetType VCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
int **vtbl=*(int ***)pcThis;
typedef RetType (*fptr)(void*,PTypeA,PTypeB);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
return function(pThis,pa,pb);
};
template <class PTypeA> template <class PTypeA>
inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa) inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa)
{ {
@ -100,6 +140,26 @@ inline RetType VCall1(void *pThis, int ventry, int size, PTypeA pa)
fptr function=reinterpret_cast<fptr>(vtbl[ventry]); fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
return function(pThis,pa); return function(pThis,pa);
}; };
inline void VoidVCall0(void *pThis, int ventry, int size)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
int **vtbl=*(int ***)pcThis;
typedef void (*fptr)(void*);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
function(pThis);
};
template <class RetType>
inline RetType VCall0(void *pThis, int ventry, int size)
{
char *pcThis=*(char **)&pThis;
pcThis+=size;
int **vtbl=*(int ***)pcThis;
typedef RetType (*fptr)(void*);
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
return function(pThis);
};
#endif //VFUNC_GCC295_H #endif //VFUNC_GCC295_H
#endif // __linux__ #endif // __linux__

View File

@ -93,6 +93,78 @@ inline RetType VCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, P
return _ret; return _ret;
}; };
template <class PTypeA, class PTypeB, class PTypeC>
inline void VoidVCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc)
{
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
_asm {
push ecx;
push eax;
push pc;
push pb;
push pa;
mov ecx, pThis;
call [func];
pop eax;
pop ecx;
};
};
template <class RetType, class PTypeA, class PTypeB, class PTypeC>
inline RetType VCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc)
{
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
RetType _ret;
_asm {
push ecx;
push eax;
push pc;
push pb;
push pa;
mov ecx, pThis;
call [func];
mov _ret, eax;
pop eax;
pop ecx;
};
return _ret;
};
template <class PTypeA, class PTypeB>
inline void VoidVCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb)
{
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
_asm {
push ecx;
push eax;
push pb;
push pa;
mov ecx, pThis;
call [func];
pop eax;
pop ecx;
};
};
template <class RetType, class PTypeA, class PTypeB>
inline RetType VCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb)
{
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
RetType _ret;
_asm {
push ecx;
push eax;
push pb;
push pa;
mov ecx, pThis;
call [func];
mov _ret, eax;
pop eax;
pop ecx;
};
return _ret;
};
template <class PTypeA> template <class PTypeA>
inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa) inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa)
{ {
@ -132,6 +204,42 @@ inline RetType VCall1(void *pThis, int ventry, int size, PTypeA pa)
return _ret; return _ret;
}; };
inline void VoidVCall0(void *pThis, int ventry, int size)
{
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
_asm {
push ecx;
push eax;
mov ecx, pThis;
call [func];
pop eax;
pop ecx;
};
};
template <class RetType>
inline RetType VCall0(void *pThis, int ventry, int size)
{
void **vtbl=*(void ***)pThis;
void *func=vtbl[ventry];
RetType _ret;
_asm {
push ecx;
push eax;
mov ecx, pThis;
call [func];
mov _ret, eax;
pop eax;
pop ecx;
};
return _ret;
};
#endif //VFUNC_MSVC_H #endif //VFUNC_MSVC_H
#endif // _WIN32 #endif // _WIN32