mirror of
https://github.com/alliedmodders/amxmodx.git
synced 2024-12-24 13:55:36 +03:00
Added a whole lot more functions that nobody will use
This commit is contained in:
parent
8939c3076a
commit
c9b19c76a5
@ -2,7 +2,7 @@
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
HLSDK = ../../../hlsdk
|
||||
MM_ROOT = ../../../metamod/metamod
|
||||
MM_ROOT = ../../metamod/metamod
|
||||
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
|
||||
@ -27,7 +27,11 @@ OBJECTS = sdk/amxxmodule.cpp FileParser.cpp amxxapi.cpp hooks.cpp \
|
||||
tableentries/VTableManager.cpp tableentries/TakeDamage.cpp tableentries/Use.cpp \
|
||||
tableentries/Blocked.cpp tableentries/Killed.cpp tableentries/Respawn.cpp \
|
||||
tableentries/Restart.cpp tableentries/AddPoints.cpp tableentries/AddPointsToTeam.cpp \
|
||||
|
||||
tableentries/AddPlayerItem.cpp tableentries/RemovePlayerItem.cpp tableentries/IsPlayer.cpp \
|
||||
tableentries/BloodColor.cpp tableentries/ObjectCaps.cpp tableentries/Classify.cpp \
|
||||
tableentries/IsInWorld.cpp tableentries/IsNetClient.cpp tableentries/IsSneaking.cpp \
|
||||
tableentries/IsMoving.cpp tableentries/IsBSPModel.cpp tableentries/IsAlive.cpp \
|
||||
tableentries/GetToggleState.cpp tableentries/Think.cpp tableentries/Touch.cpp
|
||||
|
||||
|
||||
#natives.cpp vtable.cpp
|
||||
|
@ -107,6 +107,22 @@ void HAM_CallInitialization(void)
|
||||
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
|
||||
}
|
||||
|
@ -47,6 +47,22 @@ enum HAMHooks
|
||||
HAM_Respawn,
|
||||
HAM_Restart,
|
||||
HAM_TakeHealth,
|
||||
HAM_AddPlayerItem,
|
||||
HAM_RemovePlayerItem,
|
||||
HAM_BloodColor,
|
||||
HAM_Classify,
|
||||
HAM_GetToggleState,
|
||||
HAM_IsAlive,
|
||||
HAM_IsBSPModel,
|
||||
HAM_IsInWorld,
|
||||
HAM_IsMoving,
|
||||
HAM_IsNetClient,
|
||||
HAM_IsPlayer,
|
||||
HAM_IsSneaking,
|
||||
HAM_ObjectCaps,
|
||||
HAM_Think,
|
||||
HAM_Touch,
|
||||
|
||||
|
||||
HAM_END_DONT_USE_ME
|
||||
};
|
||||
|
@ -16,114 +16,74 @@
|
||||
#include <amxmodx>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Ham Sandwich general usage
|
||||
* -
|
||||
* Mods supported:
|
||||
* cs:
|
||||
* * 1.6 - legimate, most up to date version
|
||||
* * linux 32bit and windows
|
||||
* * czero - legimate, most up to date version
|
||||
* * linux 32bit and windows
|
||||
* * czero untested, theoretically it should work
|
||||
* dod:
|
||||
* * whatever the most up to date legitimate version is (1.3?)
|
||||
* * linux and windows
|
||||
* * windows untested, should work
|
||||
* tfc:
|
||||
* * whatever most up to date legitimate version is
|
||||
* * linux and windows
|
||||
* * windows untested, should work
|
||||
* ns:
|
||||
* * 3.2 beta 2
|
||||
* * linux and windows
|
||||
* * windows untested, should work
|
||||
* ts:
|
||||
* * 2.1
|
||||
* * linux and windows
|
||||
* * windows untested, should work
|
||||
* sven:
|
||||
* * 3.0
|
||||
* * windows
|
||||
* * windows untested, should work
|
||||
* -
|
||||
* The module will automatically use the relevant function depending
|
||||
* on what game mod is loaded. You only have to tell it to do the damage.
|
||||
* -
|
||||
* Be VERY VERY careful. I check _NO_ bounds in any of the natives
|
||||
* Also, these call the game's private function, and I do not have
|
||||
* the time nor desire to figure out the quirks of each mod's function
|
||||
* -
|
||||
* The USE natives haven't been tested yet, but should work!
|
||||
* -
|
||||
* The only mod I tested the windows version of takedamage
|
||||
* for was cs 1.6. It's much easier for me to test linux.
|
||||
*/
|
||||
native ham_addplayeritem(idPlayer,idItem);
|
||||
native ham_eaddplayeritem(idPlayer,idItem);
|
||||
|
||||
/**
|
||||
* Calls the mod's private damage routine.
|
||||
* -
|
||||
* parameters:
|
||||
* id: index of the entity that is to be damaged
|
||||
*
|
||||
* inflictor: the entity that is "doing the damage" (eg a weapon)
|
||||
*
|
||||
* attacker: the entity who controls the inflictor (eg weapon holder)
|
||||
*
|
||||
* damage: how much damage to do to the victim
|
||||
*
|
||||
* type: bitmask of damage flags. Most mods do not
|
||||
* follow the standard HLSDK damage flags, so
|
||||
* you may have to do some testing!
|
||||
* The only flags I figured out were CS related:
|
||||
* * (1<<6) = no slowdown on damage
|
||||
* * (1<<13) = always gib
|
||||
* * (1<<12) = never gib
|
||||
*
|
||||
* -
|
||||
* Note: Setting damage to a ridiculously high value can mess up
|
||||
* some mods!
|
||||
*/
|
||||
native hs_takedamage(id,inflictor,attacker,Float:damage,type);
|
||||
native hs_etakedamage(id,inflictor,attacker,Float:damage,type);
|
||||
native ham_addpoints(idEntity,points,bool:allownegative);
|
||||
native ham_eaddpoints(idEntity,points,bool:allownegative);
|
||||
|
||||
native ham_addpointstoteam(idEntity,points,bool:allownegative);
|
||||
native ham_eaddpointstoteam(idEntity,points,bool:allownegative);
|
||||
|
||||
/**
|
||||
* Calls the mod's private use routine.
|
||||
* -
|
||||
* parameters:
|
||||
* id: index of the entity that is to be used
|
||||
*
|
||||
* activator: the entity that is "doing the use" (eg a trigger_multiple)
|
||||
*
|
||||
* caller: the entity who controls the activator (eg the player who trigger the trigger_multiple)
|
||||
*
|
||||
* use_type: how to use the entity
|
||||
* TYPICAL settings in HLSDK are:
|
||||
* 0 = USE_OFF - turns the object "off"
|
||||
* 1 = USE_ON - turns the object "on"
|
||||
* 2 = USE_SET - sets the object use state (uses the value flag)
|
||||
* 3 = USE_TOGGLE - toggles the state (from on->off and off->on)
|
||||
*
|
||||
* use_value: set when USE_SET is invoked
|
||||
* TYPICALLY USE_SET is only used for players using an object
|
||||
* when he begins using it, the use_value is set to 1.0
|
||||
* when he's done using it, the use_value is set to 0.0
|
||||
*
|
||||
* -
|
||||
* NOTE: This native was not tested at all beyond theory tests!
|
||||
*/
|
||||
native hs_use(id,activator,caller,use_type,Float:use_value);
|
||||
native hs_euse(id,activator,caller,use_type,Float:use_value);
|
||||
native ham_blocked(idEntity,idOther);
|
||||
native ham_eblocked(idEntity,idOther);
|
||||
|
||||
native hs_killed(id,attacker,gib);
|
||||
native hs_ekilled(id,attacker,gib);
|
||||
native hs_blocked(id,other);
|
||||
native hs_eblocked(id,other);
|
||||
native hs_respawn(id);
|
||||
native hs_erespawn(id);
|
||||
native hs_restart(id);
|
||||
native hs_erestart(id);
|
||||
native ham_bloodcolor(idEntity);
|
||||
native ham_ebloodcolor(idEntity);
|
||||
|
||||
native ham_classify(idEntity);
|
||||
native ham_eclassify(idEntity);
|
||||
|
||||
native ham_gettogglestate(idEntity);
|
||||
native ham_egettogglestate(idEntity);
|
||||
|
||||
native ham_isalive(idEntity);
|
||||
native ham_eisalive(idEntity);
|
||||
|
||||
native ham_isbspmodel(idEntity);
|
||||
native ham_eisbspmodel(idEntity);
|
||||
|
||||
native ham_isinworld(idEntity);
|
||||
native ham_eisinworld(idEntity);
|
||||
|
||||
native ham_isnetclient(idEntity);
|
||||
native ham_eisnetclient(idEntity);
|
||||
|
||||
native ham_isplayer(idEntity);
|
||||
native ham_eisplayer(idEntity);
|
||||
|
||||
native ham_issneaking(idEntity);
|
||||
native ham_eissneaking(idEntity);
|
||||
|
||||
native ham_killed(idEntity,idAttacker,iGib);
|
||||
native ham_ekilled(idEntity,idAttacker,iGib);
|
||||
|
||||
native ham_objectcaps(idEntity);
|
||||
native ham_eobjectcaps(idEntity);
|
||||
|
||||
native ham_removeplayeritem(idEntity,idItem);
|
||||
native ham_eremoveplayeritem(idEntity,idItem);
|
||||
|
||||
native ham_respawn(idEntity);
|
||||
native ham_erespawn(idEntity);
|
||||
|
||||
native ham_restart(idEntity);
|
||||
native ham_erestart(idEntity);
|
||||
|
||||
native ham_takedamage(idEntity,idInflictor,idAttacker,Float:damage,dmgtype);
|
||||
native ham_etakedamage(idEntity,idInflictor,idAttacker,Float:damage,dmgtype);
|
||||
|
||||
native ham_takehealth(idEntity,Float:health,dmgtype);
|
||||
native ham_etakehealth(idEntity,Float:health,dmgtype);
|
||||
|
||||
native ham_think(idEntity);
|
||||
native ham_ethink(idEntity);
|
||||
|
||||
native ham_touch(idEntity,idOther);
|
||||
native ham_etouch(idEntity,idOther);
|
||||
|
||||
native ham_use(idEntity,idActivator,idCaller,use_type,Float:value);
|
||||
native ham_euse(idEntity,idActivator,idCaller,use_type,Float:value);
|
||||
|
||||
|
||||
|
||||
@ -136,34 +96,6 @@ enum
|
||||
HAM_SUPERCEDE
|
||||
};
|
||||
|
||||
/**
|
||||
* Forwards all takedamage routines that would occur to the given
|
||||
* classname to the public provided.
|
||||
*
|
||||
* Parameters are:
|
||||
* function(IDVictim, IDInflictor, IDAttacker, Float:Damage, DamageType)
|
||||
*
|
||||
* Note: For now, this will also intercept calls to hs_takedamage
|
||||
* that is very likely to change shortly in the future.
|
||||
*/
|
||||
native register_takedamage(const classname[], const function[], post=0);
|
||||
|
||||
/**
|
||||
* Forwards all use routines that would occur to the given
|
||||
* classname to the public provided.
|
||||
*
|
||||
* Parameters are:
|
||||
* function(IDUsed, IDActivator, IDCaller, UseType, Float:UseValue)
|
||||
*
|
||||
* Note: For now, this will also intercept calls to hs_use
|
||||
* that is very likely to change shortly in the future.
|
||||
*/
|
||||
native register_use(const classname[], const function[], post=0);
|
||||
|
||||
native register_killed(const classname[], const function[], post=0);
|
||||
native register_blocked(const classname[], const function[], post=0);
|
||||
native hs_register_respawn(const classname[], const function[], post=0);
|
||||
native hs_register_restart(const classname[], const function[], post=0);
|
||||
|
||||
|
||||
enum HAMHooks
|
||||
@ -177,11 +109,28 @@ enum HAMHooks
|
||||
HAM_Respawn,
|
||||
HAM_Restart,
|
||||
HAM_TakeHealth,
|
||||
HAM_AddPlayerItem,
|
||||
HAM_RemovePlayerItem,
|
||||
HAM_BloodColor,
|
||||
HAM_Classify,
|
||||
HAM_GetToggleState,
|
||||
HAM_IsAlive,
|
||||
HAM_IsBSPModel,
|
||||
HAM_IsInWorld,
|
||||
HAM_IsMoving,
|
||||
HAM_IsNetClient,
|
||||
HAM_IsPlayer,
|
||||
HAM_IsSneaking,
|
||||
HAM_ObjectCaps,
|
||||
HAM_Think,
|
||||
HAM_Touch,
|
||||
|
||||
|
||||
HAM_END_DONT_USE_ME
|
||||
};
|
||||
|
||||
native ham_register(HAMHooks:hook, const classname[], const function[], post=0);
|
||||
|
||||
public __fatal_ham_error(const reason[])
|
||||
{
|
||||
set_fail_state(reason);
|
||||
|
371
dlls/hamsandwich/tableentries/AddPlayerItem.cpp
Normal file
371
dlls/hamsandwich/tableentries/AddPlayerItem.cpp
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
366
dlls/hamsandwich/tableentries/BloodColor.cpp
Normal file
366
dlls/hamsandwich/tableentries/BloodColor.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/Classify.cpp
Normal file
366
dlls/hamsandwich/tableentries/Classify.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/GetToggleState.cpp
Normal file
366
dlls/hamsandwich/tableentries/GetToggleState.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/IsAlive.cpp
Normal file
366
dlls/hamsandwich/tableentries/IsAlive.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/IsBSPModel.cpp
Normal file
366
dlls/hamsandwich/tableentries/IsBSPModel.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/IsInWorld.cpp
Normal file
366
dlls/hamsandwich/tableentries/IsInWorld.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/IsMoving.cpp
Normal file
366
dlls/hamsandwich/tableentries/IsMoving.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/IsNetClient.cpp
Normal file
366
dlls/hamsandwich/tableentries/IsNetClient.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/IsPlayer.cpp
Normal file
366
dlls/hamsandwich/tableentries/IsPlayer.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/IsSneaking.cpp
Normal file
366
dlls/hamsandwich/tableentries/IsSneaking.cpp
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
366
dlls/hamsandwich/tableentries/ObjectCaps.cpp
Normal file
366
dlls/hamsandwich/tableentries/ObjectCaps.cpp
Normal 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);
|
||||
}
|
371
dlls/hamsandwich/tableentries/RemovePlayerItem.cpp
Normal file
371
dlls/hamsandwich/tableentries/RemovePlayerItem.cpp
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
356
dlls/hamsandwich/tableentries/Think.cpp
Normal file
356
dlls/hamsandwich/tableentries/Think.cpp
Normal 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);
|
||||
}
|
366
dlls/hamsandwich/tableentries/Touch.cpp
Normal file
366
dlls/hamsandwich/tableentries/Touch.cpp
Normal 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);
|
||||
}
|
@ -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
@ -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;
|
||||
|
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user