Added a whole lot more functions that nobody will use

This commit is contained in:
Steve Dudenhoeffer
2007-03-10 18:05:30 +00:00
parent 8939c3076a
commit c9b19c76a5
31 changed files with 7956 additions and 400 deletions

View File

@ -0,0 +1,371 @@
#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 VTableAddPlayerItem
#define ThisEntries AddPlayerItemEntries
#define ThisKey "addplayeritem"
#define ThisNative "ham_addplayeritem"
#define ThisENative "ham_eaddplayeritem"
#define ThisRegisterID HAM_AddPlayerItem
#define ThisParamCount 1
#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))
{
//MF_AddNatives(registernatives);
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);
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 *)>(func)(
pthis, /*this*/
0, /*fastcall buffer*/
INDEXENT_NEW(params[2])->pvPrivateData /*item*/
);
#else
return reinterpret_cast<int (*)(void *,void *)>(func)(
pthis, /*this*/
INDEXENT_NEW(params[2])->pvPrivateData /*item*/
);
#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 VCall1<int>(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
INDEXENT_NEW(params[3])->pvPrivateData /*item*/
);
};
/**
* 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/*item*/,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, void *item)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
int iItem=PrivateToIndex(item);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,item);
if (thisresult>result)
{
result=thisresult;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int,void *)>(function)(pthis,0,item);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *,void *)>(function)(pthis,item);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis,iItem);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis,void *item)
{
return VTMan.ThisEntries[id]->Execute(pthis,item);
}

View File

@ -14,8 +14,8 @@
#define ThisVTable VTableAddPoints
#define ThisEntries AddPointsEntries
#define ThisKey "addpoints"
#define ThisNative "hs_addpoints"
#define ThisENative "hs_eaddpoints"
#define ThisNative "ham_addpoints"
#define ThisENative "ham_eaddpoints"
#define ThisRegisterID HAM_AddPoints
#define ThisParamCount 0
#define ThisVoidCall 1
@ -359,5 +359,5 @@ void ThisVTable::Execute(void *pthis,int points, int allownegative)
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,int points,int allownegative)
{
VTMan.AddPointsEntries[id]->Execute(pthis,points,allownegative);
VTMan.ThisEntries[id]->Execute(pthis,points,allownegative);
}

View File

@ -14,8 +14,8 @@
#define ThisVTable VTableAddPointsToTeam
#define ThisEntries AddPointsToTeamEntries
#define ThisKey "addpointstoteam"
#define ThisNative "hs_addpointstoteam"
#define ThisENative "hs_eaddpointstoteam"
#define ThisNative "ham_addpointstoteam"
#define ThisENative "ham_eaddpointstoteam"
#define ThisRegisterID HAM_AddPointsToTeam
#define ThisParamCount 2
#define ThisVoidCall 1
@ -358,5 +358,5 @@ void ThisVTable::Execute(void *pthis,int points, int allownegative)
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,int points,int allownegative)
{
VTMan.AddPointsToTeamEntries[id]->Execute(pthis,points,allownegative);
VTMan.ThisEntries[id]->Execute(pthis,points,allownegative);
}

View File

@ -15,8 +15,8 @@
#define ThisEntries BlockedEntries
#define ThisKey "blocked"
#define ThisNative "hs_blocked"
#define ThisENative "hs_eblocked"
#define ThisNative "ham_blocked"
#define ThisENative "ham_eblocked"
#define ThisRegisterID HAM_Blocked
#define ThisParamCount 1
#define ThisVoidCall 1
@ -30,8 +30,8 @@ unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO callnatives[] = {
{ "hs_blocked", ThisVTable::NativeCall },
{ "hs_eblocked", ThisVTable::ENativeCall },
{ ThisNative, ThisVTable::NativeCall },
{ ThisENative, ThisVTable::ENativeCall },
{ NULL, NULL }
};
@ -57,7 +57,7 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned
RegisterConfigCallback(ThisVTable::ConfigDone);
RegisterKeySuffix("blocked",ThisVTable::KeyValue);
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
RegisterThisRegisterName(ThisRegisterID,ThisKey);
};
@ -71,7 +71,7 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned
*/
void ThisVTable::KeyValue(const char *key, const char *data)
{
if (strcmp(key,"blocked")==0)
if (strcmp(key,ThisKey)==0)
{
ThisVTable::index=HAM_StrToNum(data);
ThisVTable::indexset=1;
@ -248,8 +248,8 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void
outtrampoline,
origfunc,
reinterpret_cast<void *>(ThisVTable::EntryPoint),
1, // param count
1, // voidcall
ThisParamCount, // param count
ThisVoidCall, // voidcall
1); // thiscall
};
@ -362,5 +362,5 @@ void ThisVTable::Execute(void *pthis, void *other)
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,void *other)
{
VTMan.BlockedEntries[id]->Execute(pthis,other);
VTMan.ThisEntries[id]->Execute(pthis,other);
}

View File

@ -0,0 +1,366 @@
#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 VTableBloodColor
#define ThisEntries BloodColorEntries
#define ThisKey "bloodcolor"
#define ThisNative "ham_bloodcolor"
#define ThisENative "ham_ebloodcolor"
#define ThisRegisterID HAM_BloodColor
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableClassify
#define ThisEntries ClassifyEntries
#define ThisKey "classify"
#define ThisNative "ham_classify"
#define ThisENative "ham_eclassify"
#define ThisRegisterID HAM_Classify
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableGetToggleState
#define ThisEntries GetToggleStateEntries
#define ThisKey "gettogglestate"
#define ThisNative "ham_gettogglestate"
#define ThisENative "ham_egettogglestate"
#define ThisRegisterID HAM_GetToggleState
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableIsAlive
#define ThisEntries IsAliveEntries
#define ThisKey "isalive"
#define ThisNative "ham_isalive"
#define ThisENative "ham_eisalive"
#define ThisRegisterID HAM_IsAlive
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableIsBSPModel
#define ThisEntries IsBSPModelEntries
#define ThisKey "isbspmodel"
#define ThisNative "ham_isbspmodel"
#define ThisENative "ham_eisbspmodel"
#define ThisRegisterID HAM_IsBSPModel
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableIsInWorld
#define ThisEntries IsInWorldEntries
#define ThisKey "isinworld"
#define ThisNative "ham_isinworld"
#define ThisENative "ham_eisinworld"
#define ThisRegisterID HAM_IsInWorld
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableIsMoving
#define ThisEntries IsMovingEntries
#define ThisKey "ismoving"
#define ThisNative "ham_ismoving"
#define ThisENative "ham_eismoving"
#define ThisRegisterID HAM_IsMoving
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableIsNetClient
#define ThisEntries IsNetClientEntries
#define ThisKey "isnetclient"
#define ThisNative "ham_isnetclient"
#define ThisENative "ham_eisnetclient"
#define ThisRegisterID HAM_IsNetClient
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableIsPlayer
#define ThisEntries IsPlayerEntries
#define ThisKey "isplayer"
#define ThisNative "ham_isplayer"
#define ThisENative "ham_eisplayer"
#define ThisRegisterID HAM_IsPlayer
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableIsSneaking
#define ThisEntries IsSneakingEntries
#define ThisKey "issneaking"
#define ThisNative "ham_issneaking"
#define ThisENative "ham_eissneaking"
#define ThisRegisterID HAM_IsSneaking
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -15,8 +15,8 @@
#define ThisEntries KilledEntries
#define ThisKey "killed"
#define ThisNative "hs_killed"
#define ThisENative "hs_ekilled"
#define ThisNative "ham_killed"
#define ThisENative "ham_ekilled"
#define ThisRegisterID HAM_Killed
#define ThisParamCount 2
#define ThisVoidCall 1
@ -363,6 +363,6 @@ void ThisVTable::Execute(void *pthis, void *attacker, int gib)
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,void *attacker,int gib)
{
VTMan.KilledEntries[id]->Execute(pthis,attacker,gib);
VTMan.ThisEntries[id]->Execute(pthis,attacker,gib);
}

View File

@ -0,0 +1,366 @@
#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 VTableObjectCaps
#define ThisEntries ObjectCapsEntries
#define ThisKey "objectcaps"
#define ThisNative "ham_objectcaps"
#define ThisENative "ham_eobjectcaps"
#define ThisRegisterID HAM_ObjectCaps
#define ThisParamCount 0
#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))
{
//MF_AddNatives(registernatives);
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);
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)>(func)(
pthis, /*this*/
0 /*fastcall buffer*/
);
#else
return reinterpret_cast<int (*)(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 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_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.
*/
int 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;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,371 @@
#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 VTableRemovePlayerItem
#define ThisEntries RemovePlayerItemEntries
#define ThisKey "removeplayeritem"
#define ThisNative "ham_removeplayeritem"
#define ThisENative "ham_eremoveplayeritem"
#define ThisRegisterID HAM_RemovePlayerItem
#define ThisParamCount 1
#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))
{
//MF_AddNatives(registernatives);
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);
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 *)>(func)(
pthis, /*this*/
0, /*fastcall buffer*/
INDEXENT_NEW(params[2])->pvPrivateData /*item*/
);
#else
return reinterpret_cast<int (*)(void *,void *)>(func)(
pthis, /*this*/
INDEXENT_NEW(params[2])->pvPrivateData /*item*/
);
#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 VCall1<int>(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
INDEXENT_NEW(params[3])->pvPrivateData /*item*/
);
};
/**
* 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/*item*/,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, void *item)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
int iItem=PrivateToIndex(item);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,item);
if (thisresult>result)
{
result=thisresult;
}
};
int ireturn=0;
if (result<HAM_SUPERCEDE)
{
#if defined _WIN32
ireturn=reinterpret_cast<int (__fastcall *)(void *,int,void *)>(function)(pthis,0,item);
#elif defined __linux__
ireturn=reinterpret_cast<int (*)(void *,void *)>(function)(pthis,item);
#endif
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis,iItem);
}
if (result!=HAM_OVERRIDE)
return ireturn;
return 0;
};
HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis,void *item)
{
return VTMan.ThisEntries[id]->Execute(pthis,item);
}

View File

@ -14,8 +14,8 @@
#define ThisVTable VTableRespawn
#define ThisEntries RespawnEntries
#define ThisKey "respawn"
#define ThisNative "hs_respawn"
#define ThisENative "hs_erespawn"
#define ThisNative "ham_respawn"
#define ThisENative "ham_erespawn"
#define ThisRegisterID HAM_Respawn
#define ThisParamCount 0
#define ThisVoidCall 1
@ -28,8 +28,8 @@ unsigned int ThisVTable::index=0;
unsigned int ThisVTable::indexset=0;
static AMX_NATIVE_INFO callnatives[] = {
{ "hs_respawn", ThisVTable::NativeCall },
{ "hs_respawn", ThisVTable::ENativeCall },
{ ThisNative, ThisVTable::NativeCall },
{ ThisENative, ThisVTable::ENativeCall },
{ NULL, NULL }
};
@ -352,5 +352,5 @@ void *ThisVTable::Execute(void *pthis)
};
extern "C" void *ThisVTable::EntryPoint(int id,void *pthis)
{
return VTMan.RespawnEntries[id]->Execute(pthis);
return VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -14,8 +14,8 @@
#define ThisVTable VTableRestart
#define ThisEntries RestartEntries
#define ThisKey "restart"
#define ThisNative "hs_restart"
#define ThisENative "hs_erestart"
#define ThisNative "ham_restart"
#define ThisENative "ham_erestart"
#define ThisRegisterID HAM_Restart
#define ThisParamCount 0
#define ThisVoidCall 1
@ -352,5 +352,5 @@ void ThisVTable::Execute(void *pthis)
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis)
{
VTMan.RestartEntries[id]->Execute(pthis);
VTMan.ThisEntries[id]->Execute(pthis);
}

View File

@ -15,8 +15,8 @@
#define ThisEntries TakeDamageEntries
#define ThisKey "takedamage"
#define ThisNative "hs_takedamage"
#define ThisENative "hs_etakedamage"
#define ThisNative "ham_takedamage"
#define ThisENative "ham_etakedamage"
#define ThisRegisterID HAM_TakeDamage
#define ThisParamCount 4
#define ThisVoidCall 0
@ -377,5 +377,5 @@ int ThisVTable::Execute(void *pthis, void *inflictor, void *attacker, float dama
};
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);
return VTMan.ThisEntries[id]->Execute(pthis,inflictor,attacker,damage,type);
}

View File

@ -15,8 +15,8 @@
#define ThisEntries TakeHealthEntries
#define ThisKey "takehealth"
#define ThisNative "hs_takehealth"
#define ThisENative "hs_etakehealth"
#define ThisNative "ham_takehealth"
#define ThisENative "ham_etakehealth"
#define ThisRegisterID HAM_TakeHealth
#define ThisParamCount 2
#define ThisVoidCall 0

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 VTableThink
#define ThisEntries ThinkEntries
#define ThisKey "think"
#define ThisNative "ham_think"
#define ThisENative "ham_ethink"
#define ThisRegisterID HAM_Think
#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.ThisEntries[id]->Execute(pthis);
}

View File

@ -0,0 +1,366 @@
#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 VTableTouch
#define ThisEntries TouchEntries
#define ThisKey "touch"
#define ThisNative "ham_touch"
#define ThisENative "ham_etouch"
#define ThisRegisterID HAM_Touch
#define ThisParamCount 1
#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,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;
};
/**
* 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)
{
VoidVCall1(
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
ThisVTable::index, /*vtable entry*/
*(ThisVTable::baseoffset), /*size of class*/
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
);
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/*other*/,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 activator Entity causing the opening.
* @param caller Entity controlling the caller.
* @param type USE_TYPE (USE_{ON,OFF,SET}
* @param value Use value, only seen set when USE_SET is used.
* @noreturn
*/
void ThisVTable::Execute(void *pthis, void *other)
{
int i=0;
int end=Forwards.size();
int result=HAM_UNSET;
int thisresult=HAM_UNSET;
int iThis=PrivateToIndex(pthis);
int iOther=PrivateToIndex(other);
while (i<end)
{
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iOther);
if (thisresult>result)
{
result=thisresult;
}
};
if (result<HAM_SUPERCEDE)
{
#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
}
i=0;
end=PostForwards.size();
while (i<end)
{
MF_ExecuteForward(PostForwards[i++],iThis,iOther);
}
};
HAM_CDECL void ThisVTable::EntryPoint(int id,void *pthis,void *other)
{
VTMan.ThisEntries[id]->Execute(pthis,other);
}

View File

@ -15,8 +15,8 @@
#define ThisEntries UseEntries
#define ThisKey "use"
#define ThisNative "hs_use"
#define ThisENative "hs_euse"
#define ThisNative "ham_use"
#define ThisENative "ham_euse"
#define ThisRegisterID HAM_Use
#define ThisParamCount 4
#define ThisVoidCall 1
@ -119,7 +119,6 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params)
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);
return 1;
@ -153,7 +152,6 @@ cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
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)
@ -377,5 +375,5 @@ void ThisVTable::Execute(void *pthis, void *activator, void *caller, int type, f
};
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);
VTMan.ThisEntries[id]->Execute(pthis,activator,caller,type,value);
}

File diff suppressed because it is too large Load Diff

View File

@ -41,11 +41,11 @@ cell VTableManager::Register(AMX *amx, cell *params)
{
// this register is not found, fail the plugin
int fwd=MF_RegisterSPForwardByName(amx,"__fatal_ham_error",FP_STRING,FP_DONE);
char error[256];
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);
snprintf(&error[0],sizeof(error)-1,"Requested to ham_registerid a function ID that is not registered in configs/hamdata.ini, cannot continue. (Requested: %d)",id);
MF_ExecuteForward(fwd,errorcell);
MF_ExecuteForward(fwd,&error[0]);
MF_UnregisterSPForward(fwd);
return 0;
@ -71,10 +71,11 @@ cell VTableManager::RegisterID(AMX *amx, cell *params)
// 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);
char error[256];
MF_ExecuteForward(fwd,errorcell);
snprintf(&error[0],sizeof(error)-1,"Requested to ham_register a function ID that is not registered in configs/hamdata.ini, cannot continue. (Requested: %d)",id);
MF_ExecuteForward(fwd,&error[0]);
MF_UnregisterSPForward(fwd);
return 0;

View File

@ -87,6 +87,22 @@ public:
VTINIT(Restart);
VTINIT(AddPoints);
VTINIT(AddPointsToTeam);
VTINIT(AddPlayerItem);
VTINIT(RemovePlayerItem);
VTINIT(BloodColor);
VTINIT(Classify);
VTINIT(GetToggleState);
VTINIT(IsAlive);
VTINIT(IsBSPModel);
VTINIT(IsInWorld);
VTINIT(IsMoving);
VTINIT(IsNetClient);
VTINIT(IsPlayer);
VTINIT(IsSneaking);
VTINIT(ObjectCaps);
VTINIT(Think);
VTINIT(Touch);
#undef VTINIT
static NATIVEFUNC RegisterNatives[HAM_END_DONT_USE_ME];
static NATIVEFUNC RegisterIDNatives[HAM_END_DONT_USE_ME];