From 8939c3076a243f9e8e7d8372392441f4798dd2cf Mon Sep 17 00:00:00 2001 From: Steve Dudenhoeffer Date: Fri, 9 Mar 2007 18:15:09 +0000 Subject: [PATCH] Continued making adding new entries easier {hs_}register_function->ham_register(HamHook:function,...) Added a few more hooks Fixed a few directory errors Updated config file --- dlls/hamsandwich/FileParser.cpp | 2 +- dlls/hamsandwich/Makefile | 4 +- dlls/hamsandwich/Trampolines.h | 8 + dlls/hamsandwich/amxxapi.cpp | 8 + dlls/hamsandwich/{ => config}/hamdata.ini | 43 +- dlls/hamsandwich/hamsandwich.h | 14 + .../{msvc8 => }/include/hamsandwich.inc | 44 +- dlls/hamsandwich/msvc8/hs.vcproj | 54 +- dlls/hamsandwich/tableentries/AddPoints.cpp | 363 +++++++++ .../tableentries/AddPointsToTeam.cpp | 362 +++++++++ dlls/hamsandwich/tableentries/Blocked.cpp | 146 +++- dlls/hamsandwich/tableentries/Killed.cpp | 368 +++++++++ dlls/hamsandwich/tableentries/Respawn.cpp | 356 ++++++++ dlls/hamsandwich/tableentries/Restart.cpp | 356 ++++++++ dlls/hamsandwich/tableentries/TakeDamage.cpp | 129 ++- dlls/hamsandwich/tableentries/TakeHealth.cpp | 374 +++++++++ dlls/hamsandwich/tableentries/Use.cpp | 167 +++- dlls/hamsandwich/tableentries/VTableEntries.h | 758 +++++++++++++++++- .../tableentries/VTableManager.cpp | 88 ++ dlls/hamsandwich/tableentries/VTableManager.h | 29 +- dlls/hamsandwich/vfunc_gcc295.h | 60 ++ dlls/hamsandwich/vfunc_msvc.h | 108 +++ 22 files changed, 3703 insertions(+), 138 deletions(-) rename dlls/hamsandwich/{ => config}/hamdata.ini (75%) rename dlls/hamsandwich/{msvc8 => }/include/hamsandwich.inc (80%) create mode 100644 dlls/hamsandwich/tableentries/AddPoints.cpp create mode 100644 dlls/hamsandwich/tableentries/AddPointsToTeam.cpp create mode 100644 dlls/hamsandwich/tableentries/Killed.cpp create mode 100644 dlls/hamsandwich/tableentries/Respawn.cpp create mode 100644 dlls/hamsandwich/tableentries/Restart.cpp create mode 100644 dlls/hamsandwich/tableentries/TakeHealth.cpp diff --git a/dlls/hamsandwich/FileParser.cpp b/dlls/hamsandwich/FileParser.cpp index e116d14c..d4a0489c 100644 --- a/dlls/hamsandwich/FileParser.cpp +++ b/dlls/hamsandwich/FileParser.cpp @@ -20,7 +20,7 @@ static char *FP_FormatLine(char *data) { char *End; /**< Pointer to the end of the string. */ char *Start; /**< Pointer to the start of the string. */ - char *Temp=Start; /**< Temporary pointer for parsing. */ + char *Temp; /**< Temporary pointer for parsing. */ Start=data; diff --git a/dlls/hamsandwich/Makefile b/dlls/hamsandwich/Makefile index 886c7d93..96f9512e 100644 --- a/dlls/hamsandwich/Makefile +++ b/dlls/hamsandwich/Makefile @@ -25,7 +25,9 @@ BIN_SUFFIX = amxx_i386.so OBJECTS = sdk/amxxmodule.cpp FileParser.cpp amxxapi.cpp hooks.cpp \ tableentries/VTableManager.cpp tableentries/TakeDamage.cpp tableentries/Use.cpp \ -tableentries/Blocked.cpp +tableentries/Blocked.cpp tableentries/Killed.cpp tableentries/Respawn.cpp \ +tableentries/Restart.cpp tableentries/AddPoints.cpp tableentries/AddPointsToTeam.cpp \ + #natives.cpp vtable.cpp diff --git a/dlls/hamsandwich/Trampolines.h b/dlls/hamsandwich/Trampolines.h index 40611a37..1fbc5ffd 100644 --- a/dlls/hamsandwich/Trampolines.h +++ b/dlls/hamsandwich/Trampolines.h @@ -37,6 +37,14 @@ #endif #if defined _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#if _MSC_VER >= 1400 +#ifdef offsetof +#undef offsetof +#endif // offsetof +#endif // _MSC_VER >= 1400 #include #elif defined __linux__ #include diff --git a/dlls/hamsandwich/amxxapi.cpp b/dlls/hamsandwich/amxxapi.cpp index ad7b643d..546f38e8 100644 --- a/dlls/hamsandwich/amxxapi.cpp +++ b/dlls/hamsandwich/amxxapi.cpp @@ -101,6 +101,12 @@ void HAM_CallInitialization(void) VTINIT(TakeDamage); VTINIT(Use); + VTINIT(Killed); + VTINIT(Blocked); + VTINIT(Respawn); + VTINIT(Restart); + VTINIT(AddPoints); + VTINIT(AddPointsToTeam); #undef VTINIT } @@ -217,6 +223,8 @@ void OnAmxxAttach() HAM_classbaseset=1; #endif + RegisterRegisterNatives(); + FP_SetupOffsets(ModKey,HAM_GetKey); HAM_CallConfigDone(); diff --git a/dlls/hamsandwich/hamdata.ini b/dlls/hamsandwich/config/hamdata.ini similarity index 75% rename from dlls/hamsandwich/hamdata.ini rename to dlls/hamsandwich/config/hamdata.ini index b113e837..21fcb84d 100644 --- a/dlls/hamsandwich/hamdata.ini +++ b/dlls/hamsandwich/config/hamdata.ini @@ -26,10 +26,21 @@ ; Data dated: 2007-02-23 ; Version tested: 1.6 Steam (legitimate) cstrike_windows_takedamage 12 +cstrike_windows_killed 14 ;estimated +cstrike_windows_addpoints 23 ;estimated +cstrike_windows_addpointstoteam 24 ;estimated cstrike_windows_use 46 +cstrike_windows_blocked 47 ;estimated +cstrike_windows_respawn 48 ;estimated cstrike_windows_pev 4 +cstrike_linux_restart 4 ;estimated cstrike_linux_takedamage 14 +cstrike_windows_addpoints 25 ;estimated +cstrike_windows_addpointstoteam 26 ;estimated +cstrike_linux_killed 16 ;estimated cstrike_linux_use 48 +cstrike_linux_blocked 49 ;estimated +cstrike_linux_respawn 50 ;estimated cstrike_linux_pev 0 cstrike_linux_classbase 0x94 @@ -46,20 +57,20 @@ czero_linux_classbase 0x94 ; Data dated: 2007-02-23 ; Version tested: 3.1 ns_windows_takedamage 10 -ns_windows_use 48 +ns_windows_use 49 ns_windows_pev 4 ns_linux_takedamage 11 -ns_linux_use 49 +ns_linux_use 50 ns_linux_pev 4 ns_linux_classbase 0x0 ; Data dated: 2007-02-23 ; Version tested: 3.2 beta 2 nsp_windows_takedamage 10 -nsp_windows_use 48 +nsp_windows_use 49 nsp_windows_pev 4 nsp_linux_takedamage 11 -nsp_linux_use 49 +nsp_linux_use 50 nsp_linux_pev 4 nsp_linux_classbase 0x0 @@ -75,23 +86,23 @@ dod_linux_classbase 0x154 ; Data dated: 2007-02-23 ; Version tested: 2.1 -ts_windows_takedamage 14 -ts_windows_use 48 +ts_windows_takedamage 12 +ts_windows_use 44 ts_windows_pev 4 -ts_linux_takedamage 16 -ts_linux_use 50 +ts_linux_takedamage 14 +ts_linux_use 46 ts_linux_pev 0 -ts_linux_classbase 0x60 +ts_linux_classbase 0x470 ; Data dated: 2007-02-23 -; Version tested: ?? (Most up to date) Steam (legitimate) -tfc_windows_takedamage 12 -tfc_windows_use 44 +; Version tested: 1.5 Steam (legitimate) +tfc_windows_takedamage 14 +tfc_windows_use 48 tfc_windows_pev 4 -tfc_linux_takedamage 14 -tfc_linux_use 46 +tfc_linux_takedamage 16 +tfc_linux_use 50 tfc_linux_pev 0 -tfc_linux_classbase 0x470 +tfc_linux_classbase 0x60 ; Data dated: 2007-02-23 ; Version tested: 3.0 @@ -102,7 +113,7 @@ svencoop_windows_pev 4 ; Data dated: 2007-02-26 ; Version tested: 2.18.07 -; Earth's Special Forces (I can't find the non beta version, but it should still work! +; Earth's Special Forces (I can't find the non beta version, but it should still work!) ; ESF does not have a Linux binary! esf_openbeta_windows_takedamage 12 esf_openbeta_windows_use 46 diff --git a/dlls/hamsandwich/hamsandwich.h b/dlls/hamsandwich/hamsandwich.h index 46662b38..c8f694ac 100644 --- a/dlls/hamsandwich/hamsandwich.h +++ b/dlls/hamsandwich/hamsandwich.h @@ -36,6 +36,20 @@ extern unsigned int HAM_pev; extern unsigned int HAM_classbase; +enum HAMHooks +{ + HAM_TakeDamage, + HAM_Use, + HAM_AddPoints, + HAM_AddPointsToTeam, + HAM_Blocked, + HAM_Killed, + HAM_Respawn, + HAM_Restart, + HAM_TakeHealth, + + HAM_END_DONT_USE_ME +}; inline edict_t *PrivateToEdict(const void *pdata) { diff --git a/dlls/hamsandwich/msvc8/include/hamsandwich.inc b/dlls/hamsandwich/include/hamsandwich.inc similarity index 80% rename from dlls/hamsandwich/msvc8/include/hamsandwich.inc rename to dlls/hamsandwich/include/hamsandwich.inc index 06243f3f..86745253 100644 --- a/dlls/hamsandwich/msvc8/include/hamsandwich.inc +++ b/dlls/hamsandwich/include/hamsandwich.inc @@ -12,6 +12,10 @@ #pragma library hamsandwich #endif +#if !defined _amxmodx_included + #include +#endif + /** * Ham Sandwich general usage * - @@ -112,6 +116,15 @@ native hs_etakedamage(id,inflictor,attacker,Float:damage,type); native hs_use(id,activator,caller,use_type,Float:use_value); native hs_euse(id,activator,caller,use_type,Float:use_value); +native hs_killed(id,attacker,gib); +native hs_ekilled(id,attacker,gib); +native hs_blocked(id,other); +native hs_eblocked(id,other); +native hs_respawn(id); +native hs_erespawn(id); +native hs_restart(id); +native hs_erestart(id); + enum @@ -133,7 +146,7 @@ enum * 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[]); +native register_takedamage(const classname[], const function[], post=0); /** * Forwards all use routines that would occur to the given @@ -145,4 +158,31 @@ native register_takedamage(const classname[], const function[]); * Note: For now, this will also intercept calls to hs_use * that is very likely to change shortly in the future. */ -native register_use(const classname[], const function[]); \ No newline at end of file +native register_use(const classname[], const function[], post=0); + +native register_killed(const classname[], const function[], post=0); +native register_blocked(const classname[], const function[], post=0); +native hs_register_respawn(const classname[], const function[], post=0); +native hs_register_restart(const classname[], const function[], post=0); + + +enum HAMHooks +{ + HAM_TakeDamage, + HAM_Use, + HAM_AddPoints, + HAM_AddPointsToTeam, + HAM_Blocked, + HAM_Killed, + HAM_Respawn, + HAM_Restart, + HAM_TakeHealth, + + HAM_END_DONT_USE_ME +}; + +native ham_register(HAMHooks:hook, const classname[], const function[], post=0); +public __fatal_ham_error(const reason[]) +{ + set_fail_state(reason); +} \ No newline at end of file diff --git a/dlls/hamsandwich/msvc8/hs.vcproj b/dlls/hamsandwich/msvc8/hs.vcproj index 6e22a6e8..d6f80a8b 100644 --- a/dlls/hamsandwich/msvc8/hs.vcproj +++ b/dlls/hamsandwich/msvc8/hs.vcproj @@ -133,7 +133,7 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -234,10 +278,6 @@ RelativePath="..\Makefile" > - - @@ -255,11 +295,11 @@ > diff --git a/dlls/hamsandwich/tableentries/AddPoints.cpp b/dlls/hamsandwich/tableentries/AddPoints.cpp new file mode 100644 index 00000000..14021fa4 --- /dev/null +++ b/dlls/hamsandwich/tableentries/AddPoints.cpp @@ -0,0 +1,363 @@ +#include "sdk/amxxmodule.h" + +#include "hamsandwich.h" + +#include "VTableManager.h" +#include "VTableEntries.h" + +#include "vfunc_gcc295.h" +#include "vfunc_msvc.h" + +#include "NEW_Util.h" + +// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions +#define ThisVTable VTableAddPoints +#define ThisEntries AddPointsEntries +#define ThisKey "addpoints" +#define ThisNative "hs_addpoints" +#define ThisENative "hs_eaddpoints" +#define ThisRegisterID HAM_AddPoints +#define ThisParamCount 0 +#define ThisVoidCall 1 + +unsigned int *ThisVTable::pevoffset=NULL; +unsigned int *ThisVTable::pevset=NULL; +unsigned int *ThisVTable::baseoffset=NULL; +unsigned int *ThisVTable::baseset=0; +unsigned int ThisVTable::index=0; +unsigned int ThisVTable::indexset=0; + +static AMX_NATIVE_INFO callnatives[] = { + { ThisNative, ThisVTable::NativeCall }, + { ThisENative, ThisVTable::ENativeCall }, + { NULL, NULL } +}; + +/** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ +void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset) +{ + ThisVTable::pevoffset=poffset; + ThisVTable::pevset=pset; + + ThisVTable::baseoffset=baseoffs; + ThisVTable::baseset=baseset; + + ThisVTable::index=0; + ThisVTable::indexset=0; + + RegisterConfigCallback(ThisVTable::ConfigDone); + + RegisterKeySuffix(ThisKey,ThisVTable::KeyValue); + + RegisterThisRegisterName(ThisRegisterID,ThisKey); +}; + +/** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" is removed) + * @param data The data this keyvalue is set to. + * @noreturn + */ +void ThisVTable::KeyValue(const char *key, const char *data) +{ + if (strcmp(key,ThisKey)==0) + { + ThisVTable::index=HAM_StrToNum(data); + ThisVTable::indexset=1; + } +}; + +/** + * Called immediately after the config file is done being parsed. Register our natives here. + * + * @noreturn + */ +void ThisVTable::ConfigDone(void) +{ + if (ThisVTable::indexset && *(ThisVTable::baseset)) + { + MF_AddNatives(callnatives); + + if (*(ThisVTable::pevset)) + { + RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative); + return; + } + } +}; + +/** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::RegisterNative(AMX *amx, cell *params) +{ + // Get the classname + char *classname=MF_GetAmxString(amx,params[1],1,NULL); + + // create an entity, assign it the gamedll's class, hook it and destroy it + edict_t *Entity=CREATE_ENTITY(); + + CALL_GAME_ENTITY(PLID,classname,&Entity->v); + + if (Entity->pvPrivateData) + { + // Simulate a call to hs_register_id_takedamage + cell tempparams[4]; + memcpy(tempparams,params,sizeof(cell)*4); + tempparams[1]=ENTINDEX_NEW(Entity); + ThisVTable::RegisterIDNative(amx,&tempparams[0]); + REMOVE_ENTITY(Entity); + return 1; + } + + REMOVE_ENTITY(Entity); + // class was not found + // throw an error alerting console that this hook did not happen + char *function=MF_GetAmxString(amx,params[2],0,NULL); + MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function); + + return 0; + +}; + +/** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::RegisterIDNative(AMX *amx, cell *params) +{ + int funcid; + char *function=MF_GetAmxString(amx,params[2],0,NULL); + + if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE) + { + MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function); + return 0; + } + edict_t *Entity=INDEXENT_NEW(params[1]); + + if (Entity->pvPrivateData) + { + ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0); + return 1; + } + + // class was not found + // throw an error alerting console that this hook did not happen + MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function); + + return 0; + +}; + +/** + * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::NativeCall(AMX *amx, cell *params) +{ + // scan to see if this virtual function is a trampoline + void *pthis=INDEXENT_NEW(params[1])->pvPrivateData; + void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset); + + int i=0; + int end=VTMan.ThisEntries.size(); + + while (iIsTrampoline(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(func)( + pthis, /*this*/ + 0, /*fastcall buffer*/ + params[2], + params[3] + ); +#else + reinterpret_cast(func)( + pthis, /*this*/ + params[2], + params[3] + ); +#endif + return 0; +}; + +/** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::ENativeCall(AMX *amx, cell *params) +{ + VoidVCall2( + INDEXENT_NEW(params[1])->pvPrivateData, /*this*/ + ThisVTable::index, /*vtable entry*/ + *(ThisVTable::baseoffset), /*size of class*/ + params[2], + params[3] + ); + return 1; +}; + +/** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ +void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc) +{ + + VTableEntryBase::CreateGenericTrampoline(manager, + vtable, + ThisVTable::index, + id, + outtrampoline, + origfunc, + reinterpret_cast(ThisVTable::EntryPoint), + ThisParamCount, // param count + ThisVoidCall, // voidcall + 1); // thiscall + +}; + +/** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ +void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post) +{ + void *ptr=vtable[ThisVTable::index]; + + int i=0; + int end=manager->ThisEntries.size(); + int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL,FP_CELL,FP_DONE); + while (iThisEntries[i]->IsTrampoline(ptr)) + { + // this function is already hooked! + + if (post) + { + manager->ThisEntries[i]->AddPostForward(fwd); + } + else + { + manager->ThisEntries[i]->AddForward(fwd); + } + + return; + } + + ++i; + } + // this function is NOT hooked + void *tramp; + void *func; + ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func); + ThisVTable *entry=new ThisVTable; + + entry->Setup(&vtable[ThisVTable::index],tramp,func); + + manager->ThisEntries.push_back(entry); + + if (post) + { + entry->AddPostForward(fwd); + } + else + { + entry->AddForward(fwd); + } + +} + +/** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @return Unsure. Does not appear to be used. + */ +void ThisVTable::Execute(void *pthis,int points, int allownegative) +{ + int i=0; + + int end=Forwards.size(); + + int result=HAM_UNSET; + int thisresult=HAM_UNSET; + + int iThis=PrivateToIndex(pthis); + + while (iresult) + { + result=thisresult; + } + }; + + if (result(function)(pthis,0,points,allownegative); +#elif defined __linux__ + reinterpret_cast(function)(pthis,points,allownegative); +#endif + } + + i=0; + end=PostForwards.size(); + + while (iExecute(pthis,points,allownegative); +} diff --git a/dlls/hamsandwich/tableentries/AddPointsToTeam.cpp b/dlls/hamsandwich/tableentries/AddPointsToTeam.cpp new file mode 100644 index 00000000..fa65f3dd --- /dev/null +++ b/dlls/hamsandwich/tableentries/AddPointsToTeam.cpp @@ -0,0 +1,362 @@ +#include "sdk/amxxmodule.h" + +#include "hamsandwich.h" + +#include "VTableManager.h" +#include "VTableEntries.h" + +#include "vfunc_gcc295.h" +#include "vfunc_msvc.h" + +#include "NEW_Util.h" + +// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions +#define ThisVTable VTableAddPointsToTeam +#define ThisEntries AddPointsToTeamEntries +#define ThisKey "addpointstoteam" +#define ThisNative "hs_addpointstoteam" +#define ThisENative "hs_eaddpointstoteam" +#define ThisRegisterID HAM_AddPointsToTeam +#define ThisParamCount 2 +#define ThisVoidCall 1 + +unsigned int *ThisVTable::pevoffset=NULL; +unsigned int *ThisVTable::pevset=NULL; +unsigned int *ThisVTable::baseoffset=NULL; +unsigned int *ThisVTable::baseset=0; +unsigned int ThisVTable::index=0; +unsigned int ThisVTable::indexset=0; + +static AMX_NATIVE_INFO callnatives[] = { + { ThisNative, ThisVTable::NativeCall }, + { ThisENative, ThisVTable::ENativeCall }, + { NULL, NULL } +}; + +/** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ +void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset) +{ + ThisVTable::pevoffset=poffset; + ThisVTable::pevset=pset; + + ThisVTable::baseoffset=baseoffs; + ThisVTable::baseset=baseset; + + ThisVTable::index=0; + ThisVTable::indexset=0; + + RegisterConfigCallback(ThisVTable::ConfigDone); + + RegisterKeySuffix(ThisKey,ThisVTable::KeyValue); + + RegisterThisRegisterName(ThisRegisterID,ThisKey); +}; + +/** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" 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 (iIsTrampoline(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(func)( + pthis, /*this*/ + 0, /*fastcall buffer*/ + params[2], + params[3] + ); +#else + reinterpret_cast(func)( + pthis, /*this*/ + params[2], + params[3] + ); +#endif + return 0; +}; + +/** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::ENativeCall(AMX *amx, cell *params) +{ + VoidVCall2( + INDEXENT_NEW(params[1])->pvPrivateData, /*this*/ + ThisVTable::index, /*vtable entry*/ + *(ThisVTable::baseoffset), /*size of class*/ + params[2], + params[3] + ); + return 1; +}; + +/** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ +void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc) +{ + + VTableEntryBase::CreateGenericTrampoline(manager, + vtable, + ThisVTable::index, + id, + outtrampoline, + origfunc, + reinterpret_cast(ThisVTable::EntryPoint), + ThisParamCount, // param count + ThisVoidCall, // voidcall + 1); // thiscall + +}; + +/** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ +void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post) +{ + void *ptr=vtable[ThisVTable::index]; + + int i=0; + int end=manager->ThisEntries.size(); + int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL,FP_CELL,FP_DONE); + while (iThisEntries[i]->IsTrampoline(ptr)) + { + // this function is already hooked! + + if (post) + { + manager->ThisEntries[i]->AddPostForward(fwd); + } + else + { + manager->ThisEntries[i]->AddForward(fwd); + } + + return; + } + + ++i; + } + // this function is NOT hooked + void *tramp; + void *func; + ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func); + ThisVTable *entry=new ThisVTable; + + entry->Setup(&vtable[ThisVTable::index],tramp,func); + + manager->ThisEntries.push_back(entry); + + if (post) + { + entry->AddPostForward(fwd); + } + else + { + entry->AddForward(fwd); + } + +} + +/** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @return Unsure. Does not appear to be used. + */ +void ThisVTable::Execute(void *pthis,int points, int allownegative) +{ + int i=0; + + int end=Forwards.size(); + + int result=HAM_UNSET; + int thisresult=HAM_UNSET; + + int iThis=PrivateToIndex(pthis); + + while (iresult) + { + result=thisresult; + } + }; + + if (result(function)(pthis,0,points,allownegative); +#elif defined __linux__ + reinterpret_cast(function)(pthis,points,allownegative); +#endif + } + + i=0; + end=PostForwards.size(); + + while (iExecute(pthis,points,allownegative); +} diff --git a/dlls/hamsandwich/tableentries/Blocked.cpp b/dlls/hamsandwich/tableentries/Blocked.cpp index d99c3edb..2978650c 100644 --- a/dlls/hamsandwich/tableentries/Blocked.cpp +++ b/dlls/hamsandwich/tableentries/Blocked.cpp @@ -13,7 +13,14 @@ // Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions #define ThisVTable VTableBlocked #define ThisEntries BlockedEntries -#define ThisHook VHOOK_Blocked + +#define ThisKey "blocked" +#define ThisNative "hs_blocked" +#define ThisENative "hs_eblocked" +#define ThisRegisterID HAM_Blocked +#define ThisParamCount 1 +#define ThisVoidCall 1 + unsigned int *ThisVTable::pevoffset=NULL; unsigned int *ThisVTable::pevset=NULL; @@ -22,11 +29,6 @@ unsigned int *ThisVTable::baseset=0; unsigned int ThisVTable::index=0; unsigned int ThisVTable::indexset=0; -static AMX_NATIVE_INFO registernatives[] = { - { "register_blocked", ThisVTable::RegisterNative }, - { NULL, NULL } -}; - static AMX_NATIVE_INFO callnatives[] = { { "hs_blocked", ThisVTable::NativeCall }, { "hs_eblocked", ThisVTable::ENativeCall }, @@ -56,6 +58,8 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned RegisterConfigCallback(ThisVTable::ConfigDone); RegisterKeySuffix("blocked",ThisVTable::KeyValue); + + RegisterThisRegisterName(ThisRegisterID,ThisKey); }; /** @@ -87,7 +91,7 @@ void ThisVTable::ConfigDone(void) if (*(ThisVTable::pevset)) { - MF_AddNatives(registernatives); + RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative); } } }; @@ -101,14 +105,6 @@ void ThisVTable::ConfigDone(void) */ cell ThisVTable::RegisterNative(AMX *amx, cell *params) { - int funcid; - char *function=MF_GetAmxString(amx,params[2],0,NULL); - - if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE) - { - MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function); - return 0; - } // Get the classname char *classname=MF_GetAmxString(amx,params[1],1,NULL); @@ -119,7 +115,11 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params) if (Entity->pvPrivateData) { - ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid); + // Simulate a call to hs_register_id_takedamage + cell tempparams[4]; + memcpy(tempparams,params,sizeof(cell)*4); + tempparams[1]=ENTINDEX_NEW(Entity); + ThisVTable::RegisterIDNative(amx,&tempparams[0]); REMOVE_ENTITY(Entity); return 1; } @@ -127,12 +127,46 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params) 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. * @@ -142,8 +176,38 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params) */ cell ThisVTable::NativeCall(AMX *amx, cell *params) { - // TODO: This - return 0; + // 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 (iIsTrampoline(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(func)( + pthis, /*this*/ + 0, /*fastcall buffer*/ + INDEXENT_NEW(params[2])->pvPrivateData /*other*/ + ); +#else + reinterpret_cast(func)( + pthis, /*this*/ + INDEXENT_NEW(params[2])->pvPrivateData /*other*/ + ); +#endif + return 1; }; /** @@ -183,7 +247,7 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void id, outtrampoline, origfunc, - reinterpret_cast(ThisHook), + reinterpret_cast(ThisVTable::EntryPoint), 1, // param count 1, // voidcall 1); // thiscall @@ -199,7 +263,7 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void * @param funcid The function id of the callback. * @noreturn */ -void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid) +void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post) { void *ptr=vtable[ThisVTable::index]; @@ -212,7 +276,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu { // this function is already hooked! - manager->ThisEntries[i]->AddForward(fwd); + if (post) + { + manager->ThisEntries[i]->AddPostForward(fwd); + } + else + { + manager->ThisEntries[i]->AddForward(fwd); + } return; } @@ -229,7 +300,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu manager->ThisEntries.push_back(entry); - entry->AddForward(fwd); + if (post) + { + entry->AddPostForward(fwd); + } + else + { + entry->AddForward(fwd); + } } @@ -265,16 +343,24 @@ void ThisVTable::Execute(void *pthis, void *other) } }; - if (result>=HAM_SUPERCEDE) + if (result(function)(pthis,0,other); +#elif defined __linux__ + reinterpret_cast(function)(pthis,other); +#endif } -#if defined _WIN32 - reinterpret_cast(function)(pthis,0,other); -#elif defined __linux__ - reinterpret_cast(function)(pthis,other); -#endif - + i=0; + end=PostForwards.size(); + while (iExecute(pthis,other); +} diff --git a/dlls/hamsandwich/tableentries/Killed.cpp b/dlls/hamsandwich/tableentries/Killed.cpp new file mode 100644 index 00000000..628bc5b1 --- /dev/null +++ b/dlls/hamsandwich/tableentries/Killed.cpp @@ -0,0 +1,368 @@ +#include "sdk/amxxmodule.h" + +#include "hamsandwich.h" + +#include "VTableManager.h" +#include "VTableEntries.h" + +#include "vfunc_gcc295.h" +#include "vfunc_msvc.h" + +#include "NEW_Util.h" + +// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions +#define ThisVTable VTableKilled +#define ThisEntries KilledEntries + +#define ThisKey "killed" +#define ThisNative "hs_killed" +#define ThisENative "hs_ekilled" +#define ThisRegisterID HAM_Killed +#define ThisParamCount 2 +#define ThisVoidCall 1 + +unsigned int *ThisVTable::pevoffset=NULL; +unsigned int *ThisVTable::pevset=NULL; +unsigned int *ThisVTable::baseoffset=NULL; +unsigned int *ThisVTable::baseset=0; +unsigned int ThisVTable::index=0; +unsigned int ThisVTable::indexset=0; + +static AMX_NATIVE_INFO callnatives[] = { + { ThisNative, ThisVTable::NativeCall }, + { ThisENative, ThisVTable::ENativeCall }, + { NULL, NULL } +}; + +/** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ +void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset) +{ + ThisVTable::pevoffset=poffset; + ThisVTable::pevset=pset; + + ThisVTable::baseoffset=baseoffs; + ThisVTable::baseset=baseset; + + ThisVTable::index=0; + ThisVTable::indexset=0; + + RegisterConfigCallback(ThisVTable::ConfigDone); + + RegisterKeySuffix(ThisKey,ThisVTable::KeyValue); + + RegisterThisRegisterName(ThisRegisterID,ThisKey); +}; + +/** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" 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 (iIsTrampoline(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(func)( + pthis, /*this*/ + 0, /*fastcall buffer*/ + &(INDEXENT_NEW(params[2])->v), /*pevattacker*/ + (int)params[3] /*gib*/ + ); +#else + return reinterpret_cast(func)( + pthis, /*this*/ + &(INDEXENT_NEW(params[2])->v), /*pevattacker*/ + (int)params[3] /*gib*/ + ); +#endif +}; + +/** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::ENativeCall(AMX *amx, cell *params) +{ + VoidVCall2( + INDEXENT_NEW(params[1])->pvPrivateData, /*this*/ + ThisVTable::index, /*vtable entry*/ + *(ThisVTable::baseoffset), /*size of class*/ + &(INDEXENT_NEW(params[2])->v), /*pevattacker*/ + (int)params[3] /*gib*/ + ); + return 1; +}; + +/** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ +void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc) +{ + + VTableEntryBase::CreateGenericTrampoline(manager, + vtable, + ThisVTable::index, + id, + outtrampoline, + origfunc, + reinterpret_cast(ThisVTable::EntryPoint), + ThisParamCount, // param count + ThisVoidCall, // voidcall + 1); // thiscall + +}; + +/** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ +void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post) +{ + void *ptr=vtable[ThisVTable::index]; + + int i=0; + int end=manager->ThisEntries.size(); + int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*attacker*/,FP_CELL/*gib*/,FP_DONE); + while (iThisEntries[i]->IsTrampoline(ptr)) + { + // this function is already hooked! + + if (post) + { + manager->ThisEntries[i]->AddPostForward(fwd); + } + else + { + manager->ThisEntries[i]->AddForward(fwd); + } + + return; + } + + ++i; + } + // this function is NOT hooked + void *tramp; + void *func; + ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func); + ThisVTable *entry=new ThisVTable; + + entry->Setup(&vtable[ThisVTable::index],tramp,func); + + manager->ThisEntries.push_back(entry); + + if (post) + { + entry->AddPostForward(fwd); + } + else + { + entry->AddForward(fwd); + } + +} + +/** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @param inflictor Damage inflictor. + * @param attacker The attacker who caused the inflictor to damage the victim. + * @param damage How much damage was caused. + * @param type Damage type (usually in bitmask form). + * @return Unsure. Does not appear to be used. + */ +void ThisVTable::Execute(void *pthis, void *attacker, int gib) +{ + int i=0; + + int end=Forwards.size(); + + int result=HAM_UNSET; + int thisresult=HAM_UNSET; + + int iThis=PrivateToIndex(pthis); + int iAttacker=EntvarToIndex((entvars_t *)attacker); + + while (iresult) + { + result=thisresult; + } + }; + + if (result(function)(pthis,0,attacker,gib); +#elif defined __linux__ + reinterpret_cast(function)(pthis,attacker,gib); +#endif + } + + i=0; + end=PostForwards.size(); + + while (iExecute(pthis,attacker,gib); +} + diff --git a/dlls/hamsandwich/tableentries/Respawn.cpp b/dlls/hamsandwich/tableentries/Respawn.cpp new file mode 100644 index 00000000..dc307e23 --- /dev/null +++ b/dlls/hamsandwich/tableentries/Respawn.cpp @@ -0,0 +1,356 @@ +#include "sdk/amxxmodule.h" + +#include "hamsandwich.h" + +#include "VTableManager.h" +#include "VTableEntries.h" + +#include "vfunc_gcc295.h" +#include "vfunc_msvc.h" + +#include "NEW_Util.h" + +// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions +#define ThisVTable VTableRespawn +#define ThisEntries RespawnEntries +#define ThisKey "respawn" +#define ThisNative "hs_respawn" +#define ThisENative "hs_erespawn" +#define ThisRegisterID HAM_Respawn +#define ThisParamCount 0 +#define ThisVoidCall 1 + +unsigned int *ThisVTable::pevoffset=NULL; +unsigned int *ThisVTable::pevset=NULL; +unsigned int *ThisVTable::baseoffset=NULL; +unsigned int *ThisVTable::baseset=0; +unsigned int ThisVTable::index=0; +unsigned int ThisVTable::indexset=0; + +static AMX_NATIVE_INFO callnatives[] = { + { "hs_respawn", ThisVTable::NativeCall }, + { "hs_respawn", ThisVTable::ENativeCall }, + { NULL, NULL } +}; + +/** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ +void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset) +{ + ThisVTable::pevoffset=poffset; + ThisVTable::pevset=pset; + + ThisVTable::baseoffset=baseoffs; + ThisVTable::baseset=baseset; + + ThisVTable::index=0; + ThisVTable::indexset=0; + + RegisterConfigCallback(ThisVTable::ConfigDone); + + RegisterKeySuffix(ThisKey,ThisVTable::KeyValue); + + RegisterThisRegisterName(ThisRegisterID,ThisKey); +}; + +/** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" 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 (iIsTrampoline(func)) + { + // this function is a trampoline + // use the original function instead + func=VTMan.ThisEntries[i]->GetOriginalFunction(); + break; + } + ++i; + } + // TODO: Inline ASM this +#ifdef _WIN32 + return PrivateToIndex(reinterpret_cast(func)( + pthis, /*this*/ + 0 /*fastcall buffer*/ + )); +#else + return PrivateToIndex(reinterpret_cast(func)( + pthis /*this*/ + )); +#endif +}; + +/** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::ENativeCall(AMX *amx, cell *params) +{ + return PrivateToIndex(VCall0( + INDEXENT_NEW(params[1])->pvPrivateData, /*this*/ + ThisVTable::index, /*vtable entry*/ + *(ThisVTable::baseoffset) /*size of class*/ + )); +}; + +/** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ +void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc) +{ + + VTableEntryBase::CreateGenericTrampoline(manager, + vtable, + ThisVTable::index, + id, + outtrampoline, + origfunc, + reinterpret_cast(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 (iThisEntries[i]->IsTrampoline(ptr)) + { + // this function is already hooked! + + if (post) + { + manager->ThisEntries[i]->AddPostForward(fwd); + } + else + { + manager->ThisEntries[i]->AddForward(fwd); + } + + return; + } + + ++i; + } + // this function is NOT hooked + void *tramp; + void *func; + ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func); + ThisVTable *entry=new ThisVTable; + + entry->Setup(&vtable[ThisVTable::index],tramp,func); + + manager->ThisEntries.push_back(entry); + + if (post) + { + entry->AddPostForward(fwd); + } + else + { + entry->AddForward(fwd); + } + +} + +/** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @return Pointer to the this object it seems? Pointless + */ +void *ThisVTable::Execute(void *pthis) +{ + int i=0; + + int end=Forwards.size(); + + int result=HAM_UNSET; + int thisresult=HAM_UNSET; + + int iThis=PrivateToIndex(pthis); + + while (iresult) + { + result=thisresult; + } + }; + + void *ret=NULL; + if (result(function)(pthis,0); +#elif defined __linux__ + ret=reinterpret_cast(function)(pthis); +#endif + } + + i=0; + end=PostForwards.size(); + while (iExecute(pthis); +} diff --git a/dlls/hamsandwich/tableentries/Restart.cpp b/dlls/hamsandwich/tableentries/Restart.cpp new file mode 100644 index 00000000..82fcd8da --- /dev/null +++ b/dlls/hamsandwich/tableentries/Restart.cpp @@ -0,0 +1,356 @@ +#include "sdk/amxxmodule.h" + +#include "hamsandwich.h" + +#include "VTableManager.h" +#include "VTableEntries.h" + +#include "vfunc_gcc295.h" +#include "vfunc_msvc.h" + +#include "NEW_Util.h" + +// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions +#define ThisVTable VTableRestart +#define ThisEntries RestartEntries +#define ThisKey "restart" +#define ThisNative "hs_restart" +#define ThisENative "hs_erestart" +#define ThisRegisterID HAM_Restart +#define ThisParamCount 0 +#define ThisVoidCall 1 + +unsigned int *ThisVTable::pevoffset=NULL; +unsigned int *ThisVTable::pevset=NULL; +unsigned int *ThisVTable::baseoffset=NULL; +unsigned int *ThisVTable::baseset=0; +unsigned int ThisVTable::index=0; +unsigned int ThisVTable::indexset=0; + +static AMX_NATIVE_INFO callnatives[] = { + { ThisNative, ThisVTable::NativeCall }, + { ThisENative, ThisVTable::ENativeCall }, + { NULL, NULL } +}; + +/** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ +void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset) +{ + ThisVTable::pevoffset=poffset; + ThisVTable::pevset=pset; + + ThisVTable::baseoffset=baseoffs; + ThisVTable::baseset=baseset; + + ThisVTable::index=0; + ThisVTable::indexset=0; + + RegisterConfigCallback(ThisVTable::ConfigDone); + + RegisterKeySuffix(ThisKey,ThisVTable::KeyValue); + + RegisterThisRegisterName(ThisRegisterID,ThisKey); +}; + +/** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" 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 (iIsTrampoline(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(func)( + pthis, /*this*/ + 0 /*fastcall buffer*/ + ); +#else + reinterpret_cast(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(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 (iThisEntries[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 (iresult) + { + result=thisresult; + } + }; + + if (result(function)(pthis,0); +#elif defined __linux__ + reinterpret_cast(function)(pthis); +#endif + } + + i=0; + end=PostForwards.size(); + + while (iExecute(pthis); +} diff --git a/dlls/hamsandwich/tableentries/TakeDamage.cpp b/dlls/hamsandwich/tableentries/TakeDamage.cpp index a763fa28..2eaa989e 100644 --- a/dlls/hamsandwich/tableentries/TakeDamage.cpp +++ b/dlls/hamsandwich/tableentries/TakeDamage.cpp @@ -2,7 +2,6 @@ #include "hamsandwich.h" -#include "hooks.h" #include "VTableManager.h" #include "VTableEntries.h" @@ -14,7 +13,13 @@ // Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions #define ThisVTable VTableTakeDamage #define ThisEntries TakeDamageEntries -#define ThisHook VHOOK_TakeDamage + +#define ThisKey "takedamage" +#define ThisNative "hs_takedamage" +#define ThisENative "hs_etakedamage" +#define ThisRegisterID HAM_TakeDamage +#define ThisParamCount 4 +#define ThisVoidCall 0 unsigned int *ThisVTable::pevoffset=NULL; unsigned int *ThisVTable::pevset=NULL; @@ -23,14 +28,9 @@ unsigned int *ThisVTable::baseset=0; unsigned int ThisVTable::index=0; unsigned int ThisVTable::indexset=0; -static AMX_NATIVE_INFO registernatives[] = { - { "register_takedamage", ThisVTable::RegisterNative }, - { NULL, NULL } -}; - static AMX_NATIVE_INFO callnatives[] = { - { "hs_takedamage", ThisVTable::NativeCall }, - { "hs_etakedamage", ThisVTable::ENativeCall }, + { ThisNative, ThisVTable::NativeCall }, + { ThisENative, ThisVTable::ENativeCall }, { NULL, NULL } }; @@ -56,7 +56,9 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned RegisterConfigCallback(ThisVTable::ConfigDone); - RegisterKeySuffix("takedamage",ThisVTable::KeyValue); + RegisterKeySuffix(ThisKey,ThisVTable::KeyValue); + + RegisterThisRegisterName(ThisRegisterID,ThisKey); }; /** @@ -68,7 +70,7 @@ void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned */ void ThisVTable::KeyValue(const char *key, const char *data) { - if (strcmp(key,"takedamage")==0) + if (strcmp(key,ThisKey)==0) { ThisVTable::index=HAM_StrToNum(data); ThisVTable::indexset=1; @@ -88,7 +90,8 @@ void ThisVTable::ConfigDone(void) if (*(ThisVTable::pevset)) { - MF_AddNatives(registernatives); + //MF_AddNatives(registernatives); + RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative); } } }; @@ -102,14 +105,6 @@ void ThisVTable::ConfigDone(void) */ cell ThisVTable::RegisterNative(AMX *amx, cell *params) { - int funcid; - char *function=MF_GetAmxString(amx,params[2],0,NULL); - - if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE) - { - MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function); - return 0; - } // Get the classname char *classname=MF_GetAmxString(amx,params[1],1,NULL); @@ -120,12 +115,18 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params) if (Entity->pvPrivateData) { - ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid); + // Simulate a call to hs_register_id_takedamage + cell tempparams[4]; + memcpy(tempparams,params,sizeof(cell)*4); + tempparams[1]=ENTINDEX_NEW(Entity); + ThisVTable::RegisterIDNative(amx,&tempparams[0]); REMOVE_ENTITY(Entity); 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); @@ -134,6 +135,39 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params) }; +/** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::RegisterIDNative(AMX *amx, cell *params) +{ + int funcid; + char *function=MF_GetAmxString(amx,params[2],0,NULL); + + if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE) + { + MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function); + return 0; + } + edict_t *Entity=INDEXENT_NEW(params[1]); + + if (Entity->pvPrivateData) + { + ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0); + return 1; + } + + // class was not found + // throw an error alerting console that this hook did not happen + MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function); + + return 0; + +}; + /** * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. * @@ -220,9 +254,9 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void id, outtrampoline, origfunc, - reinterpret_cast(ThisHook), - 4, // param count - 0, // voidcall + reinterpret_cast(ThisVTable::EntryPoint), + ThisParamCount, // param count + ThisVoidCall, // voidcall 1); // thiscall }; @@ -236,7 +270,7 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void * @param funcid The function id of the callback. * @noreturn */ -void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid) +void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post) { void *ptr=vtable[ThisVTable::index]; @@ -249,7 +283,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu { // this function is already hooked! - manager->ThisEntries[i]->AddForward(fwd); + if (post) + { + manager->ThisEntries[i]->AddPostForward(fwd); + } + else + { + manager->ThisEntries[i]->AddForward(fwd); + } return; } @@ -266,7 +307,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu manager->ThisEntries.push_back(entry); - entry->AddForward(fwd); + if (post) + { + entry->AddPostForward(fwd); + } + else + { + entry->AddForward(fwd); + } } @@ -302,21 +350,32 @@ int ThisVTable::Execute(void *pthis, void *inflictor, void *attacker, float dama result=thisresult; } }; + int ireturn=0; - // stop here - if (result>=HAM_SUPERCEDE) + if (result(function)(pthis,0,inflictor,attacker,damage,type); +#elif defined __linux__ + ireturn=reinterpret_cast(function)(pthis,inflictor,attacker,damage,type); +#endif + } + + i=0; + + end=PostForwards.size(); + while (i(function)(pthis,0,inflictor,attacker,damage,type); -#elif defined __linux__ - int ireturn=reinterpret_cast(function)(pthis,inflictor,attacker,damage,type); -#endif if (result!=HAM_OVERRIDE) return ireturn; return 0; }; +HAM_CDECL int ThisVTable::EntryPoint(int id,void *pthis,void *inflictor,void *attacker,float damage,int type) +{ + return VTMan.TakeDamageEntries[id]->Execute(pthis,inflictor,attacker,damage,type); +} diff --git a/dlls/hamsandwich/tableentries/TakeHealth.cpp b/dlls/hamsandwich/tableentries/TakeHealth.cpp new file mode 100644 index 00000000..72949af1 --- /dev/null +++ b/dlls/hamsandwich/tableentries/TakeHealth.cpp @@ -0,0 +1,374 @@ +#include "sdk/amxxmodule.h" + +#include "hamsandwich.h" + +#include "VTableManager.h" +#include "VTableEntries.h" + +#include "vfunc_gcc295.h" +#include "vfunc_msvc.h" + +#include "NEW_Util.h" + +// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions +#define ThisVTable VTableTakeHealth +#define ThisEntries TakeHealthEntries + +#define ThisKey "takehealth" +#define ThisNative "hs_takehealth" +#define ThisENative "hs_etakehealth" +#define ThisRegisterID HAM_TakeHealth +#define ThisParamCount 2 +#define ThisVoidCall 0 + +unsigned int *ThisVTable::pevoffset=NULL; +unsigned int *ThisVTable::pevset=NULL; +unsigned int *ThisVTable::baseoffset=NULL; +unsigned int *ThisVTable::baseset=0; +unsigned int ThisVTable::index=0; +unsigned int ThisVTable::indexset=0; + +static AMX_NATIVE_INFO callnatives[] = { + { ThisNative, ThisVTable::NativeCall }, + { ThisENative, ThisVTable::ENativeCall }, + { NULL, NULL } +}; + +/** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ +void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset) +{ + ThisVTable::pevoffset=poffset; + ThisVTable::pevset=pset; + + ThisVTable::baseoffset=baseoffs; + ThisVTable::baseset=baseset; + + ThisVTable::index=0; + ThisVTable::indexset=0; + + RegisterConfigCallback(ThisVTable::ConfigDone); + + RegisterKeySuffix(ThisKey,ThisVTable::KeyValue); + + RegisterThisRegisterName(ThisRegisterID,ThisKey); +}; + +/** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" is removed) + * @param data The data this keyvalue is set to. + * @noreturn + */ +void ThisVTable::KeyValue(const char *key, const char *data) +{ + if (strcmp(key,ThisKey)==0) + { + ThisVTable::index=HAM_StrToNum(data); + ThisVTable::indexset=1; + } +}; + +/** + * Called immediately after the config file is done being parsed. Register our natives here. + * + * @noreturn + */ +void ThisVTable::ConfigDone(void) +{ + if (ThisVTable::indexset && *(ThisVTable::baseset)) + { + MF_AddNatives(callnatives); + + if (*(ThisVTable::pevset)) + { + RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative); + } + } +}; + +/** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::RegisterNative(AMX *amx, cell *params) +{ + // Get the classname + char *classname=MF_GetAmxString(amx,params[1],1,NULL); + + // create an entity, assign it the gamedll's class, hook it and destroy it + edict_t *Entity=CREATE_ENTITY(); + + CALL_GAME_ENTITY(PLID,classname,&Entity->v); + + if (Entity->pvPrivateData) + { + // Simulate a call to hs_register_id_TakeHealth + cell tempparams[4]; + memcpy(tempparams,params,sizeof(cell)*4); + tempparams[1]=ENTINDEX_NEW(Entity); + ThisVTable::RegisterIDNative(amx,&tempparams[0]); + REMOVE_ENTITY(Entity); + return 1; + } + + REMOVE_ENTITY(Entity); + + char *function=MF_GetAmxString(amx,params[2],0,NULL); + // class was not found + // throw an error alerting console that this hook did not happen + MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function); + + return 0; + +}; + +/** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::RegisterIDNative(AMX *amx, cell *params) +{ + int funcid; + char *function=MF_GetAmxString(amx,params[2],0,NULL); + + if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE) + { + MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function); + return 0; + } + edict_t *Entity=INDEXENT_NEW(params[1]); + + if (Entity->pvPrivateData) + { + ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0); + return 1; + } + + // class was not found + // throw an error alerting console that this hook did not happen + MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function); + + return 0; + +}; + +/** + * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::NativeCall(AMX *amx, cell *params) +{ + // scan to see if this virtual function is a trampoline + void *pthis=INDEXENT_NEW(params[1])->pvPrivateData; + void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset); + + int i=0; + int end=VTMan.ThisEntries.size(); + + while (iIsTrampoline(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(func)( + pthis, /*this*/ + 0, /*fastcall buffer*/ + &(INDEXENT_NEW(params[2])->v), /*inflictor*/ + &(INDEXENT_NEW(params[3])->v), /*attacker*/ + amx_ctof2(params[4]), /*damage*/ + (int)params[5] /*dmgtype*/ + ); +#else + return reinterpret_cast(func)( + pthis, /*this*/ + &(INDEXENT_NEW(params[2])->v), /*inflictor*/ + &(INDEXENT_NEW(params[3])->v), /*attacker*/ + amx_ctof2(params[4]), /*damage*/ + (int)params[5] /*dmgtype*/ + ); +#endif +}; + +/** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::ENativeCall(AMX *amx, cell *params) +{ + return VCall4( + 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(ThisVTable::EntryPoint), + ThisParamCount, // param count + ThisVoidCall, // voidcall + 1); // thiscall + +}; + +/** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ +void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post) +{ + void *ptr=vtable[ThisVTable::index]; + + int i=0; + int end=manager->ThisEntries.size(); + int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*amount*/,FP_CELL/*type*/,FP_DONE); + while (iThisEntries[i]->IsTrampoline(ptr)) + { + // this function is already hooked! + + if (post) + { + manager->ThisEntries[i]->AddPostForward(fwd); + } + else + { + manager->ThisEntries[i]->AddForward(fwd); + } + + return; + } + + ++i; + } + // this function is NOT hooked + void *tramp; + void *func; + ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func); + ThisVTable *entry=new ThisVTable; + + entry->Setup(&vtable[ThisVTable::index],tramp,func); + + manager->ThisEntries.push_back(entry); + + if (post) + { + entry->AddPostForward(fwd); + } + else + { + entry->AddForward(fwd); + } + +} + +/** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @param inflictor Damage inflictor. + * @param attacker The attacker who caused the inflictor to damage the victim. + * @param damage How much damage was caused. + * @param type Damage type (usually in bitmask form). + * @return Unsure. Does not appear to be used. + */ +int ThisVTable::Execute(void *pthis, float amount, int type) +{ + int i=0; + + int end=Forwards.size(); + + int result=HAM_UNSET; + int thisresult=HAM_UNSET; + + int iThis=PrivateToIndex(pthis); + + while (iresult) + { + result=thisresult; + } + }; + int ireturn=0; + + if (result(function)(pthis,0,amount,type); +#elif defined __linux__ + ireturn=reinterpret_cast(function)(pthis,amount,type); +#endif + } + + i=0; + + end=PostForwards.size(); + while (ipvPrivateData) { - ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid); + // Simulate a call to hs_register_id_takedamage + cell tempparams[4]; + memcpy(tempparams,params,sizeof(cell)*4); + tempparams[1]=ENTINDEX_NEW(Entity); + printf("TEMPPARAMS[1]==%d\n",tempparams[1]); + ThisVTable::RegisterIDNative(amx,&tempparams[0]); REMOVE_ENTITY(Entity); 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); @@ -133,6 +136,40 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params) }; +/** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ +cell ThisVTable::RegisterIDNative(AMX *amx, cell *params) +{ + int funcid; + char *function=MF_GetAmxString(amx,params[2],0,NULL); + + if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE) + { + MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function); + return 0; + } + printf("PARAMS[1]==%d\n",params[1]); + edict_t *Entity=INDEXENT_NEW(params[1]); + + if (Entity->pvPrivateData) + { + ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0); + return 1; + } + + // class was not found + // throw an error alerting console that this hook did not happen + MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function); + + return 0; + +}; + /** * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. * @@ -142,7 +179,43 @@ cell ThisVTable::RegisterNative(AMX *amx, cell *params) */ cell ThisVTable::NativeCall(AMX *amx, cell *params) { - // TODO: This + // scan to see if this virtual function is a trampoline + void *pthis=INDEXENT_NEW(params[1])->pvPrivateData; + void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset); + + int i=0; + int end=VTMan.ThisEntries.size(); + + while (iIsTrampoline(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(func)( + pthis, /*this*/ + 0, /*fastcall buffer*/ + INDEXENT_NEW(params[2])->pvPrivateData, + INDEXENT_NEW(params[3])->pvPrivateData, + params[4], + amx_ctof2(params[5]) + ); +#else + reinterpret_cast(func)( + pthis, /*this*/ + INDEXENT_NEW(params[2])->pvPrivateData, + INDEXENT_NEW(params[3])->pvPrivateData, + params[4], + amx_ctof2(params[5]) + ); +#endif return 0; }; @@ -185,9 +258,9 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void id, outtrampoline, origfunc, - reinterpret_cast(ThisHook), - 4, // param count - 1, // voidcall + reinterpret_cast(ThisVTable::EntryPoint), + ThisParamCount, // param count + ThisVoidCall, // voidcall 1); // thiscall }; @@ -201,7 +274,7 @@ void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void * @param funcid The function id of the callback. * @noreturn */ -void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid) +void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post) { void *ptr=vtable[ThisVTable::index]; @@ -214,7 +287,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu { // this function is already hooked! - manager->ThisEntries[i]->AddForward(fwd); + if (post) + { + manager->ThisEntries[i]->AddPostForward(fwd); + } + else + { + manager->ThisEntries[i]->AddForward(fwd); + } return; } @@ -231,7 +311,14 @@ void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int fu manager->ThisEntries.push_back(entry); - entry->AddForward(fwd); + if (post) + { + entry->AddForward(fwd); + } + else + { + entry->AddPostForward(fwd); + } } @@ -268,15 +355,27 @@ void ThisVTable::Execute(void *pthis, void *activator, void *caller, int type, f } }; - if (result>=HAM_SUPERCEDE) + + if (result(function)(pthis,0,activator,caller,type,value); +#elif defined __linux__ + reinterpret_cast(function)(pthis,activator,caller,type,value); +#endif } -#if defined _WIN32 - reinterpret_cast(function)(pthis,0,activator,caller,type,value); -#elif defined __linux__ - reinterpret_cast(function)(pthis,activator,caller,type,value); -#endif + i=0; + + end=PostForwards.size(); + + while (iExecute(pthis,activator,caller,type,value); +} diff --git a/dlls/hamsandwich/tableentries/VTableEntries.h b/dlls/hamsandwich/tableentries/VTableEntries.h index 9e0aeafe..5d0803f8 100644 --- a/dlls/hamsandwich/tableentries/VTableEntries.h +++ b/dlls/hamsandwich/tableentries/VTableEntries.h @@ -32,9 +32,13 @@ #ifndef VTABLEENTRIES_H #define VTABLEENTRIES_H -#include "CVector.h" +#ifdef _WIN32 +#define HAM_CDECL __cdecl +#else +#define HAM_CDECL __attribute__((cdecl)) +#endif -#include "hooks.h" +#include "CVector.h" class VTableManager; @@ -45,6 +49,7 @@ public: void **location; /**< The location of the vtable entry that is being hooked. */ void *trampoline; /**< Our trampoline (needs to be freed when it's not hooking any more!). */ CVector Forwards; /**< Vector of forwards to call for this hook.*/ + CVector PostForwards; /**< Vector of forwards to call for this post hook.*/ /** * Saves virtual table location, trampoline and function pointers. @@ -87,6 +92,7 @@ public: free(trampoline); Forwards.clear(); + PostForwards.clear(); }; /** @@ -141,6 +147,17 @@ public: Forwards.push_back(fwd); }; + /** + * Adds a forward to this entry's post forward vector. + * + * @param fwd Forward index to add. + * @noreturn + */ + void AddPostForward(int fwd) + { + PostForwards.push_back(fwd); + }; + /** * Creates a generic trampoline. * @@ -159,6 +176,121 @@ public: }; +class VTableTraceAttack : public VTableEntryBase +{ +public: + static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */ + static unsigned int *pevset; /**< Whether or not pev entry has been set */ + static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */ + static unsigned int *baseset; /**< Whether or base offset value has been set. */ + static unsigned int index; /**< This entry's virtual table index. */ + static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */ + + /** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ + static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset); + + /** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" is removed) + * @param data The data this keyvalue is set to. + * @noreturn + */ + static void KeyValue(const char *key, const char *data); + + /** + * Called immediately after the config file is done being parsed. Register our natives here. + * + * @noreturn + */ + static void ConfigDone(void); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterNative(AMX *amx, cell *params); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterIDNative(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell NativeCall(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell ENativeCall(AMX *amx, cell *params); + + /** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ + static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc); + + /** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ + static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post); + + /** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @param inflictor Damage inflictor. + * @param attacker The attacker who caused the inflictor to damage the victim. + * @param damage How much damage was caused. + * @param type Damage type (usually in bitmask form). + * @return Unsure. Does not appear to be used. + */ + int Execute(void *pthis, void *pevattacker, float flDamage, float *direction, void *tr, int bitsDamageType); + + /** + * The hook that is directly called by the trampoline. + * + * @param id The index of the hook to call. + * @param pthis The "this" pointer. + */ + static HAM_CDECL void EntryPoint(int id,void *pthis,void *pevattacker,float flDamage,float *direction,void *tr,int bits); +}; class VTableTakeDamage : public VTableEntryBase { public: @@ -205,6 +337,15 @@ public: */ static cell RegisterNative(AMX *amx, cell *params); + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterIDNative(AMX *amx, cell *params); + /** * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. * @@ -243,7 +384,7 @@ public: * @param funcid The function id of the callback. * @noreturn */ - static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid); + static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post); /** * Execute the command. This is called directly from our global hook function. @@ -256,6 +397,127 @@ public: * @return Unsure. Does not appear to be used. */ int Execute(void *pthis, void *inflictor, void *attacker, float damage, int type); + + /** + * The hook that is directly called by the trampoline. + * + * @param id The index of the hook to call. + * @param pthis The "this" pointer. + */ + static HAM_CDECL int EntryPoint(int id,void *pthis,void *inflictor,void *attacker,float damage,int type); +}; +class VTableKilled : public VTableEntryBase +{ +public: + static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */ + static unsigned int *pevset; /**< Whether or not pev entry has been set */ + static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */ + static unsigned int *baseset; /**< Whether or base offset value has been set. */ + static unsigned int index; /**< This entry's virtual table index. */ + static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */ + + /** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ + static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset); + + /** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" is removed) + * @param data The data this keyvalue is set to. + * @noreturn + */ + static void KeyValue(const char *key, const char *data); + + /** + * Called immediately after the config file is done being parsed. Register our natives here. + * + * @noreturn + */ + static void ConfigDone(void); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterNative(AMX *amx, cell *params); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterIDNative(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell NativeCall(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell ENativeCall(AMX *amx, cell *params); + + /** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ + static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc); + + /** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ + static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post); + + /** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @param attacker The attacker who caused the inflictor to damage the victim. + * @param gib Whether to gib or not. + * @noreturn + */ + void Execute(void *pthis, void *attacker, int gib); + + /** + * The hook that is directly called by the trampoline. + * + * @param id The index of the hook to call. + * @param pthis The "this" pointer. + */ + static HAM_CDECL void EntryPoint(int id,void *pthis,void *attacker, int gib); }; class VTableUse : public VTableEntryBase { @@ -312,6 +574,15 @@ public: */ static cell NativeCall(AMX *amx, cell *params); + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterIDNative(AMX *amx, cell *params); + /** * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. * @@ -341,7 +612,7 @@ public: * @param funcid The function id of the callback. * @noreturn */ - static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid); + static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post); /** * Execute the command. This is called directly from our global hook function. @@ -354,6 +625,15 @@ public: * @noreturn */ void Execute(void *pthis, void *activator, void *caller, int type, float value); + + /** + * The hook that is directly called by the trampoline. + * + * @param id The index of the hook to call. + * @param pthis The "this" pointer. + */ + static HAM_CDECL void EntryPoint(int id,void *pthis, void *activator, void *caller, int type, float value); + }; class VTableBlocked : public VTableEntryBase { @@ -401,6 +681,15 @@ public: */ static cell RegisterNative(AMX *amx, cell *params); + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterIDNative(AMX *amx, cell *params); + /** * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. * @@ -439,17 +728,474 @@ public: * @param funcid The function id of the callback. * @noreturn */ - static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid); + static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post); /** * Execute the command. This is called directly from our global hook function. * * @param pthis The "this" pointer, cast to a void. The victim. - * @param activator Entity that's blocking. + * @param other Entity that's blocking. * @noreturn */ void Execute(void *pthis, void *other); + + /** + * The hook that is directly called by the trampoline. + * + * @param id The index of the hook to call. + * @param pthis The "this" pointer. + */ + static HAM_CDECL void EntryPoint(int id,void *pthis,void *other); }; +class VTableRespawn : public VTableEntryBase +{ +public: + static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */ + static unsigned int *pevset; /**< Whether or not pev entry has been set */ + static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */ + static unsigned int *baseset; /**< Whether or base offset value has been set. */ + static unsigned int index; /**< This entry's virtual table index. */ + static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */ + + /** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ + static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset); + + /** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" is removed) + * @param data The data this keyvalue is set to. + * @noreturn + */ + static void KeyValue(const char *key, const char *data); + + /** + * Called immediately after the config file is done being parsed. Register our natives here. + * + * @noreturn + */ + static void ConfigDone(void); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterNative(AMX *amx, cell *params); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterIDNative(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell NativeCall(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell ENativeCall(AMX *amx, cell *params); + + /** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ + static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc); + + /** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ + static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post); + + /** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @param other Entity that's blocking. + * @noreturn + */ + void *Execute(void *pthis); + + /** + * The hook that is directly called by the trampoline. + * + * @param id The index of the hook to call. + * @param pthis The "this" pointer. + */ + static void *EntryPoint(int id,void *pthis); +}; +class VTableRestart : public VTableEntryBase +{ +public: + static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */ + static unsigned int *pevset; /**< Whether or not pev entry has been set */ + static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */ + static unsigned int *baseset; /**< Whether or base offset value has been set. */ + static unsigned int index; /**< This entry's virtual table index. */ + static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */ + + /** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ + static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset); + + /** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" is removed) + * @param data The data this keyvalue is set to. + * @noreturn + */ + static void KeyValue(const char *key, const char *data); + + /** + * Called immediately after the config file is done being parsed. Register our natives here. + * + * @noreturn + */ + static void ConfigDone(void); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterNative(AMX *amx, cell *params); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterIDNative(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell NativeCall(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell ENativeCall(AMX *amx, cell *params); + + /** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ + static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc); + + /** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ + static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post); + + /** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @param other Entity that's blocking. + * @noreturn + */ + void Execute(void *pthis); + + /** + * The hook that is directly called by the trampoline. + * + * @param id The index of the hook to call. + * @param pthis The "this" pointer. + */ + static HAM_CDECL void EntryPoint(int id,void *pthis); +}; +class VTableAddPoints : public VTableEntryBase +{ +public: + static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */ + static unsigned int *pevset; /**< Whether or not pev entry has been set */ + static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */ + static unsigned int *baseset; /**< Whether or base offset value has been set. */ + static unsigned int index; /**< This entry's virtual table index. */ + static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */ + + /** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ + static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset); + + /** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" is removed) + * @param data The data this keyvalue is set to. + * @noreturn + */ + static void KeyValue(const char *key, const char *data); + + /** + * Called immediately after the config file is done being parsed. Register our natives here. + * + * @noreturn + */ + static void ConfigDone(void); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterNative(AMX *amx, cell *params); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterIDNative(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell NativeCall(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell ENativeCall(AMX *amx, cell *params); + + /** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ + static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc); + + /** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ + static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post); + + /** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @param other Entity that's blocking. + * @noreturn + */ + void Execute(void *pthis, int points, int allowneg); + + /** + * The hook that is directly called by the trampoline. + * + * @param id The index of the hook to call. + * @param pthis The "this" pointer. + */ + static HAM_CDECL void EntryPoint(int id,void *pthis,int points,int allownegative); +}; +class VTableAddPointsToTeam : public VTableEntryBase +{ +public: + static unsigned int *pevoffset; /**< Offset of pev value (globally stored) */ + static unsigned int *pevset; /**< Whether or not pev entry has been set */ + static unsigned int *baseoffset; /**< Offset of the base class (only needed for GCC 2.95). */ + static unsigned int *baseset; /**< Whether or base offset value has been set. */ + static unsigned int index; /**< This entry's virtual table index. */ + static unsigned int indexset; /**< Whether or not this entry's virtual table index has been set. */ + + /** + * Initialize this table hook. This also registers our required keyvalue suffixes to the file parser. + * + * @param poffset Pointer to an integer that stores the pev offset for this mod. + * @param pset Pointer to an integer that tells whether pev offset was set or not. + * @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required) + * @param baseset Pointer to an integer that tells whether class base offset has been set. + * @noreturn + */ + static void Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset); + + /** + * Called when one of this table entry's keyvalues is caught in a config file. + * + * @param key The keyvalue suffix ("__" is removed) + * @param data The data this keyvalue is set to. + * @noreturn + */ + static void KeyValue(const char *key, const char *data); + + /** + * Called immediately after the config file is done being parsed. Register our natives here. + * + * @noreturn + */ + static void ConfigDone(void); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterNative(AMX *amx, cell *params); + + /** + * A plugin is registering this entry's virtual hook. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell RegisterIDNative(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell NativeCall(AMX *amx, cell *params); + + /** + * A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback. + * + * @param amx The AMX structure for the plugin. + * @param params The parameters passed from the plugin. + * @return 1 on success, 0 on failure. It only fails if the callback function is not found. + */ + static cell ENativeCall(AMX *amx, cell *params); + + /** + * Hook this entry's function! This creates our trampoline and modifies the virtual table. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param outtrampoline The trampoline that was created. + * @param origfunc The original function that was hooked. + * @noreturn + */ + static void CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc); + + /** + * Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector. + * + * @param manager The VTableManager this is a child of. + * @param vtable The virtual table we're molesting. + * @param plugin The plugin that's requesting this. + * @param funcid The function id of the callback. + * @noreturn + */ + static void Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post); + + /** + * Execute the command. This is called directly from our global hook function. + * + * @param pthis The "this" pointer, cast to a void. The victim. + * @param other Entity that's blocking. + * @noreturn + */ + void Execute(void *pthis, int points, int allowneg); + + /** + * The hook that is directly called by the trampoline. + * + * @param id The index of the hook to call. + * @param pthis The "this" pointer. + */ + static HAM_CDECL void EntryPoint(int id,void *pthis,int points,int allownegative); +}; + //TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); /*class VTableTraceAttack : public VTableEntryBase { diff --git a/dlls/hamsandwich/tableentries/VTableManager.cpp b/dlls/hamsandwich/tableentries/VTableManager.cpp index 8abfd317..0dab6a66 100644 --- a/dlls/hamsandwich/tableentries/VTableManager.cpp +++ b/dlls/hamsandwich/tableentries/VTableManager.cpp @@ -1,10 +1,98 @@ #include "sdk/amxxmodule.h" +#include "hamsandwich.h" + #include "VTableManager.h" #include "VTableEntries.h" #include "NEW_Util.h" +VTableManager VTMan; + +NATIVEFUNC VTableManager::RegisterNatives[HAM_END_DONT_USE_ME]; +NATIVEFUNC VTableManager::RegisterIDNatives[HAM_END_DONT_USE_ME]; +const char *VTableManager::RegisterNames[HAM_END_DONT_USE_ME]; + +void RegisterThisRegister(int index,NATIVEFUNC byname, NATIVEFUNC byid) +{ + VTableManager::RegisterNatives[index]=byname; + VTableManager::RegisterIDNatives[index]=byid; +} +void RegisterThisRegisterName(int index, const char *name) +{ + VTableManager::RegisterNames[index]=name; +} + +static AMX_NATIVE_INFO registernatives[] = { + { "ham_register", VTableManager::Register }, + { "ham_registerid", VTableManager::RegisterID }, + + { NULL, NULL } +}; +void RegisterRegisterNatives(void) +{ + MF_AddNatives(registernatives); +} +cell VTableManager::Register(AMX *amx, cell *params) +{ + int id=params[1]; + + if (id<0 || id>=HAM_END_DONT_USE_ME || RegisterIDNatives[id]==NULL) + { + // this register is not found, fail the plugin + int fwd=MF_RegisterSPForwardByName(amx,"__fatal_ham_error",FP_STRING,FP_DONE); + + char error[]="Requested to hs_registerid a function ID that is not registered in configs/hamdata.ini, cannot continue."; + int errorcell=MF_PrepareCharArray(&error[0],strlen(error)+1); + + MF_ExecuteForward(fwd,errorcell); + + MF_UnregisterSPForward(fwd); + return 0; + + } + + cell tempparams[4]; + + // remove one parameter from this param count + tempparams[0]=(params[0]-(sizeof(cell))); + tempparams[1]=params[2]; + tempparams[2]=params[3]; + tempparams[3]=params[4]; + + return RegisterNatives[id](amx,&tempparams[0]); +} +cell VTableManager::RegisterID(AMX *amx, cell *params) +{ + int id=params[1]; + + if (id<0 || id>=HAM_END_DONT_USE_ME || RegisterNatives[id]==NULL) + { + // this register is not found, fail the plugin + int fwd=MF_RegisterSPForwardByName(amx,"__fatal_ham_error",FP_STRING,FP_DONE); + + char error[]="Requested to hs_register a function ID that is not registered in configs/hamdata.ini, cannot continue."; + int errorcell=MF_PrepareCharArray(&error[0],strlen(error)+1); + + MF_ExecuteForward(fwd,errorcell); + + MF_UnregisterSPForward(fwd); + return 0; + + } + + cell tempparams[4]; + + // remove one parameter from this param count + tempparams[0]=(params[0]-(sizeof(cell))); + tempparams[1]=params[2]; + tempparams[2]=params[3]; + tempparams[3]=params[4]; + + return RegisterIDNatives[id](amx,&tempparams[0]); +} + + void *VTableManager::InsertIntoVTable(void **vtable, int index, void *trampoline) { void *func; diff --git a/dlls/hamsandwich/tableentries/VTableManager.h b/dlls/hamsandwich/tableentries/VTableManager.h index 03fca45f..fe108763 100644 --- a/dlls/hamsandwich/tableentries/VTableManager.h +++ b/dlls/hamsandwich/tableentries/VTableManager.h @@ -3,8 +3,9 @@ #include "Trampolines.h" +#include "hamsandwich.h" + #include "CVector.h" -#include "hooks.h" #include "VTableEntries.h" /* !!WARNING: HERE BE DRAGONS @@ -72,22 +73,38 @@ enum }; - +typedef cell (*NATIVEFUNC)(AMX *, cell *); class VTableManager { public: - CVector UseEntries; - CVector TakeDamageEntries; - CVector BlockedEntries; +#define VTINIT(Type) CVector Type##Entries + VTINIT(Use); + VTINIT(TakeDamage); + VTINIT(Blocked); + VTINIT(Killed); + VTINIT(Respawn); + VTINIT(Restart); + VTINIT(AddPoints); + VTINIT(AddPointsToTeam); +#undef VTINIT + static NATIVEFUNC RegisterNatives[HAM_END_DONT_USE_ME]; + static NATIVEFUNC RegisterIDNatives[HAM_END_DONT_USE_ME]; + static const char *RegisterNames[HAM_END_DONT_USE_ME]; + + static cell Register(AMX *amx, cell *params); + static cell RegisterID(AMX *amx, cell *params); /* returns the original function */ void *InsertIntoVTable(void **vtable, int index, void *trampoline); void Cleanup(void); }; +void RegisterThisRegister(int index,NATIVEFUNC byname, NATIVEFUNC byid); +void RegisterThisRegisterName(int index, const char *name); +void RegisterRegisterNatives(void); + extern VTableManager VTMan; -//#include "VTableEntries.h" #endif // VTABLEMANAGER_H diff --git a/dlls/hamsandwich/vfunc_gcc295.h b/dlls/hamsandwich/vfunc_gcc295.h index bb8559a1..5202ae15 100644 --- a/dlls/hamsandwich/vfunc_gcc295.h +++ b/dlls/hamsandwich/vfunc_gcc295.h @@ -80,6 +80,46 @@ inline RetType VCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, P fptr function=reinterpret_cast(vtbl[ventry]); return function(pThis,pa,pb,pc,pd); }; +template +inline void VoidVCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc) +{ + char *pcThis=*(char **)&pThis; + pcThis+=size; + int **vtbl=*(int ***)pcThis; + typedef void (*fptr)(void*,PTypeA,PTypeB,PTypeC); + fptr function=reinterpret_cast(vtbl[ventry]); + function(pThis,pa,pb,pc); +}; +template +inline RetType VCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc) +{ + char *pcThis=*(char **)&pThis; + pcThis+=size; + int **vtbl=*(int ***)pcThis; + typedef RetType (*fptr)(void*,PTypeA,PTypeB,PTypeC); + fptr function=reinterpret_cast(vtbl[ventry]); + return function(pThis,pa,pb,pc); +}; +template +inline void VoidVCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb) +{ + char *pcThis=*(char **)&pThis; + pcThis+=size; + int **vtbl=*(int ***)pcThis; + typedef void (*fptr)(void*,PTypeA,PTypeB); + fptr function=reinterpret_cast(vtbl[ventry]); + function(pThis,pa,pb); +}; +template +inline RetType VCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb) +{ + char *pcThis=*(char **)&pThis; + pcThis+=size; + int **vtbl=*(int ***)pcThis; + typedef RetType (*fptr)(void*,PTypeA,PTypeB); + fptr function=reinterpret_cast(vtbl[ventry]); + return function(pThis,pa,pb); +}; template inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa) { @@ -100,6 +140,26 @@ inline RetType VCall1(void *pThis, int ventry, int size, PTypeA pa) fptr function=reinterpret_cast(vtbl[ventry]); return function(pThis,pa); }; +inline void VoidVCall0(void *pThis, int ventry, int size) +{ + char *pcThis=*(char **)&pThis; + pcThis+=size; + int **vtbl=*(int ***)pcThis; + typedef void (*fptr)(void*); + fptr function=reinterpret_cast(vtbl[ventry]); + function(pThis); +}; +template +inline RetType VCall0(void *pThis, int ventry, int size) +{ + char *pcThis=*(char **)&pThis; + pcThis+=size; + int **vtbl=*(int ***)pcThis; + typedef RetType (*fptr)(void*); + fptr function=reinterpret_cast(vtbl[ventry]); + return function(pThis); +}; + #endif //VFUNC_GCC295_H #endif // __linux__ diff --git a/dlls/hamsandwich/vfunc_msvc.h b/dlls/hamsandwich/vfunc_msvc.h index ab51e2c7..340c48fb 100644 --- a/dlls/hamsandwich/vfunc_msvc.h +++ b/dlls/hamsandwich/vfunc_msvc.h @@ -93,6 +93,78 @@ inline RetType VCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, P return _ret; }; +template +inline void VoidVCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc) +{ + void **vtbl=*(void ***)pThis; + void *func=vtbl[ventry]; + _asm { + push ecx; + push eax; + push pc; + push pb; + push pa; + mov ecx, pThis; + call [func]; + pop eax; + pop ecx; + }; +}; +template +inline RetType VCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc) +{ + void **vtbl=*(void ***)pThis; + void *func=vtbl[ventry]; + RetType _ret; + _asm { + push ecx; + push eax; + push pc; + push pb; + push pa; + mov ecx, pThis; + call [func]; + mov _ret, eax; + pop eax; + pop ecx; + }; + return _ret; +}; +template +inline void VoidVCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb) +{ + void **vtbl=*(void ***)pThis; + void *func=vtbl[ventry]; + _asm { + push ecx; + push eax; + push pb; + push pa; + mov ecx, pThis; + call [func]; + pop eax; + pop ecx; + }; +}; +template +inline RetType VCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb) +{ + void **vtbl=*(void ***)pThis; + void *func=vtbl[ventry]; + RetType _ret; + _asm { + push ecx; + push eax; + push pb; + push pa; + mov ecx, pThis; + call [func]; + mov _ret, eax; + pop eax; + pop ecx; + }; + return _ret; +}; template inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa) { @@ -132,6 +204,42 @@ inline RetType VCall1(void *pThis, int ventry, int size, PTypeA pa) return _ret; }; +inline void VoidVCall0(void *pThis, int ventry, int size) +{ + void **vtbl=*(void ***)pThis; + + void *func=vtbl[ventry]; + + _asm { + push ecx; + push eax; + mov ecx, pThis; + call [func]; + pop eax; + pop ecx; + }; +}; +template +inline RetType VCall0(void *pThis, int ventry, int size) +{ + void **vtbl=*(void ***)pThis; + + void *func=vtbl[ventry]; + + RetType _ret; + _asm { + push ecx; + push eax; + mov ecx, pThis; + call [func]; + mov _ret, eax; + pop eax; + pop ecx; + }; + + return _ret; +}; + #endif //VFUNC_MSVC_H #endif // _WIN32