mirror of
https://github.com/rehlds/reapi.git
synced 2025-02-05 10:10:38 +03:00
Refactoring
This commit is contained in:
parent
392026e50b
commit
50b5649257
@ -17,22 +17,27 @@
|
||||
#include <reapi_engine.inc> // NOTE: only for ReHLDS
|
||||
#include <reapi_gamedll.inc> // NOTE: only for gamedll Counter-Strike (ReGameDLL_CS)
|
||||
|
||||
// return constants
|
||||
enum
|
||||
{
|
||||
RH_UNSET = 0,
|
||||
RH_IGNORED, // plugin didn't take any action
|
||||
RH_HANDLED, // plugin did something, but real function should still be called
|
||||
RH_OVERRIDE, // call real function, but use my return value
|
||||
RH_SUPERCEDE // skip real function; use my return value
|
||||
HC_CONTINUE = 0,
|
||||
HC_OVERRIDE,
|
||||
HC_SUPERCEDE,
|
||||
HC_BREAK
|
||||
};
|
||||
|
||||
// for hookchain return
|
||||
enum HookChainReturn
|
||||
// hookchain types
|
||||
enum AType
|
||||
{
|
||||
RHV_STRING = 0, // string
|
||||
RHV_FLOAT, // float
|
||||
RHV_INTEGER, // returns an integer or boolean
|
||||
RHV_CLASSPTR // for CBaseEntity *, CBasePlayer * etc
|
||||
ATYPE_INTEGER = 0,
|
||||
ATYPE_FLOAT,
|
||||
ATYPE_STRING,
|
||||
ATYPE_CLASSPTR
|
||||
};
|
||||
|
||||
enum HookChain
|
||||
{
|
||||
INVALID_HOOKCHAIN = 0
|
||||
};
|
||||
|
||||
/*
|
||||
@ -76,11 +81,37 @@ native bool:EnableHookChain(HookChain:hook);
|
||||
* @param type To specify the type RHV_*, look at the enum HookChainReturn
|
||||
* @param value The value to set the return to.
|
||||
*
|
||||
* native SetHookChainReturn(HookChainReturn:type, any:...);
|
||||
* native SetHookChainReturn(AType:type, any:...);
|
||||
*/
|
||||
|
||||
native SetHookChainReturn(HookChainReturn:type, any:...);
|
||||
|
||||
/*
|
||||
* Gets the return value of a hookchain.
|
||||
* This needs to be used in conjunction with RH_OVERRIDE or RH_SUPERCEDE.
|
||||
*
|
||||
* @param type To specify the type RHV_*, look at the enum HookChainReturn
|
||||
* @param value The value to set the return to.
|
||||
*
|
||||
* native GetHookChainReturn(AType:type, any:...);
|
||||
*/
|
||||
|
||||
native GetHookChainReturn(AType:type, any:...);
|
||||
|
||||
/*
|
||||
* Set hookchain argument.
|
||||
* This needs to be used in conjunction with RH_OVERRIDE or RH_SUPERCEDE.
|
||||
*
|
||||
* @param number Number of argument
|
||||
* @param value New value
|
||||
* @param [maxlen] Max length of string (optional)
|
||||
* @return Returns if the function is successful executed true otherwise false
|
||||
*
|
||||
* native SetHookChainArg(number, AType:type, any:...);
|
||||
*/
|
||||
|
||||
native SetHookChainArg(number, AType:type, any:...);
|
||||
|
||||
/*
|
||||
* This is the callback from the module that gives major/minor versions for verifying compatibility reapi API versions
|
||||
* If will be amxx plugin a failure, then you do need to upgrade to the latest version of the module reapi or do update files included for amxx plugins
|
||||
@ -90,13 +121,17 @@ public __reapi_version_check(const majorVersion, const minorVersion)
|
||||
{
|
||||
if (majorVersion != REAPI_VERISON_MAJOR)
|
||||
{
|
||||
set_fail_state("[ReAPI]: Api major version mismatch; expected %d, real %d", REAPI_VERISON_MAJOR, majorVersion);
|
||||
new temp[512];
|
||||
formatex(temp, sizeof temp - 1, "[ReAPI]: Api major version mismatch; expected %d, real %d", REAPI_VERISON_MAJOR, majorVersion);
|
||||
set_fail_state(temp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (minorVersion < REAPI_VERISON_MINOR)
|
||||
{
|
||||
set_fail_state("[ReAPI]: Api minor version mismatch; expected at least %d, real %d", REAPI_VERISON_MINOR, minorVersion);
|
||||
new temp[512];
|
||||
formatex(temp, sizeof temp - 1, "[ReAPI]: Api minor version mismatch; expected at least %d, real %d", REAPI_VERISON_MINOR, minorVersion);
|
||||
set_fail_state(temp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ typedef IHookChain<int> IReGameHook_CBasePlayer_Classify;
|
||||
typedef IHookChainRegistryClass<int, class CBasePlayer> IReGameHookRegistry_CBasePlayer_Classify;
|
||||
|
||||
// CBasePlayer::TraceAttack hook
|
||||
typedef IVoidHookChain<struct entvars_s *, float, Vector, struct TraceResult *, int> IReGameHook_CBasePlayer_TraceAttack;
|
||||
typedef IVoidHookChainRegistryClass<class CBasePlayer, struct entvars_s *, float, Vector, struct TraceResult *, int> IReGameHookRegistry_CBasePlayer_TraceAttack;
|
||||
typedef IVoidHookChain<struct entvars_s *, float, Vector&, struct TraceResult *, int> IReGameHook_CBasePlayer_TraceAttack;
|
||||
typedef IVoidHookChainRegistryClass<class CBasePlayer, struct entvars_s *, float, Vector&, struct TraceResult *, int> IReGameHookRegistry_CBasePlayer_TraceAttack;
|
||||
|
||||
// CBasePlayer::TakeDamage hook
|
||||
typedef IHookChain<int, struct entvars_s *, struct entvars_s *, float, int> IReGameHook_CBasePlayer_TakeDamage;
|
||||
|
@ -52,7 +52,7 @@ typedef IBaseInterface* (*CreateInterfaceFn)(const char *pName, int *pReturnCode
|
||||
typedef IBaseInterface* (*InstantiateInterfaceFn)();
|
||||
|
||||
|
||||
// Used internally to register classes.
|
||||
// Used internally to classes.
|
||||
class InterfaceReg
|
||||
{
|
||||
public:
|
||||
|
@ -358,6 +358,9 @@
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -206,3 +206,25 @@ NOINLINE void MF_LogError(AMX *amx, int err, const char *fmt, ...)
|
||||
|
||||
g_amxxapi.LogError(amx, err, "[%s] %s", g_ModuleInfo.logtag, msg);
|
||||
}
|
||||
|
||||
char* getAmxStringTemp(cell* src, char* dest, size_t max, size_t* len)
|
||||
{
|
||||
char* start = dest;
|
||||
|
||||
while (*src && --max)
|
||||
*dest++ = (char)*src++;
|
||||
*dest = '\0';
|
||||
|
||||
if (len)
|
||||
*len = dest - start;
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
void setAmxString(cell* dest, const char* string, size_t max)
|
||||
{
|
||||
while (*string && max--)
|
||||
*dest++ = (cell)*string++;
|
||||
|
||||
*dest = 0;
|
||||
}
|
||||
|
@ -378,15 +378,6 @@ typedef edict_t * ( *PFN_GET_PLAYER_EDICT ) ( int /*id*/ );
|
||||
typedef void * ( *PFN_GET_PLAYER_EDICT ) ( int /*id*/ );
|
||||
#endif
|
||||
typedef void * ( *PFN_PLAYER_PROP_ADDR ) ( int /*id*/, int /*prop*/ );
|
||||
|
||||
#ifdef MEMORY_TEST
|
||||
typedef void * ( *PFN_ALLOCATOR ) ( const char* /*filename*/, const unsigned int /*line*/, const char* /*func*/,
|
||||
const unsigned int /*type*/, const size_t /*size*/ );
|
||||
typedef void * ( *PFN_REALLOCATOR ) ( const char* /*filename*/, const unsigned int /*line*/, const char* /*func*/,
|
||||
const unsigned int /*type*/, const size_t /*size*/, void* /*addr*/ );
|
||||
typedef void(*PFN_DEALLOCATOR) ( const char* /*filename*/, const unsigned int /*line*/, const char* /*func*/,
|
||||
const unsigned int /*type*/, const void* /*addr*/ );
|
||||
#endif
|
||||
typedef int(*PFN_AMX_EXEC) ( AMX* /*amx*/, cell* /*return val*/, int /*index*/ );
|
||||
typedef int(*PFN_AMX_EXECV) ( AMX* /*amx*/, cell* /*return val*/, int /*index*/, int /*numparams*/, cell[] /*params*/ );
|
||||
typedef int(*PFN_AMX_ALLOT) ( AMX* /*amx*/, int /*length*/, cell* /*amx_addr*/, cell** /*phys_addr*/ );
|
||||
@ -503,5 +494,27 @@ extern amxxapi_t g_amxxapi;
|
||||
|
||||
void MF_Log(const char *fmt, ...);
|
||||
void MF_LogError(AMX *amx, int err, const char *fmt, ...);
|
||||
char* getAmxStringTemp(cell* src, char* dest, size_t max, size_t* len);
|
||||
void setAmxString(cell* dest, const char* string, size_t max);
|
||||
|
||||
inline cell* getAmxAddr(AMX *amx, cell amx_addr)
|
||||
{
|
||||
return (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr));
|
||||
}
|
||||
|
||||
struct getAmxString
|
||||
{
|
||||
getAmxString(cell* src, size_t* len)
|
||||
{
|
||||
getAmxStringTemp(src, temp, sizeof temp - 1, len);
|
||||
}
|
||||
|
||||
operator char *()
|
||||
{
|
||||
return temp;
|
||||
}
|
||||
|
||||
char temp[1024];
|
||||
};
|
||||
|
||||
#endif // __AMXXMODULE_H__
|
@ -2,6 +2,11 @@
|
||||
|
||||
CAPI_Config api_cfg;
|
||||
|
||||
CAPI_Config::CAPI_Config() : m_api_rehlds(false), m_api_regame(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CAPI_Config::Init()
|
||||
{
|
||||
m_api_rehlds = RehldsApi_Init();
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
class CAPI_Config {
|
||||
public:
|
||||
CAPI_Config();
|
||||
bool Init();
|
||||
|
||||
bool hasReHLDS() const { return m_api_rehlds; }
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
extern void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
extern void ServerDeactivate_Post();
|
||||
|
||||
DLL_FUNCTIONS gFunctionTable =
|
||||
@ -79,8 +80,8 @@ DLL_FUNCTIONS gFunctionTable_Post =
|
||||
NULL, // pfnClientPutInServer
|
||||
NULL, // pfnClientCommand
|
||||
NULL, // pfnClientUserInfoChanged
|
||||
NULL, // pfnServerActivate
|
||||
&ServerDeactivate_Post, // pfnServerDeactivate
|
||||
&ServerActivate_Post, // pfnServerActivate
|
||||
&ServerDeactivate_Post, // pfnServerDeactivate
|
||||
NULL, // pfnPlayerPreThink
|
||||
NULL, // pfnPlayerPostThink
|
||||
NULL, // pfnStartFrame
|
||||
|
@ -1,36 +1,48 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
CHook *g_currentHookChain = nullptr;
|
||||
hookctx_t* g_hookCtx;
|
||||
|
||||
/*
|
||||
* ReHLDS functions
|
||||
*/
|
||||
void SV_StartSound(IRehldsHook_SV_StartSound *chain, int recipients, edict_t *entity, int channel, const char *sample, int volume, float attenuation, int fFlags, int pitch)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_SV_StartSound, recipients, ENTINDEX(entity), channel, sample, volume, attenuation, fFlags, pitch)) {
|
||||
chain->callNext(recipients, entity, channel, sample, volume, attenuation, fFlags, pitch);
|
||||
}
|
||||
auto original = [chain](int _recipients, int _entity, int _channel, const char *_sample, int _volume, float _attenuation, int _fFlags, int _pitch)
|
||||
{
|
||||
chain->callNext(_recipients, INDEXENT(_entity), _channel, _sample, _volume, _attenuation, _fFlags, _pitch);
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_SV_StartSound, recipients, ENTINDEX(entity), channel, sample, volume, attenuation, fFlags, pitch);
|
||||
callVoidForward(RH_SV_StartSound, original, recipients, indexOfEdict(entity), channel, sample, volume, attenuation, fFlags, pitch);
|
||||
}
|
||||
|
||||
void SV_DropClient(IRehldsHook_SV_DropClient *chain, IGameClient *cl, bool crash, const char *fmt)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_SV_DropClient, cl->GetId(), crash, fmt)) {
|
||||
chain->callNext(cl, crash, fmt);
|
||||
}
|
||||
auto original = [chain](int _cl, bool _crash, const char *_fmt)
|
||||
{
|
||||
chain->callNext(g_RehldsSvs->GetClient(_cl), _crash, _fmt);
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_SV_DropClient, cl->GetId(), crash, fmt);
|
||||
callVoidForward(RH_SV_DropClient, original, cl->GetId(), crash, fmt);
|
||||
}
|
||||
|
||||
void SV_ActivateServer(IRehldsHook_SV_ActivateServer *chain, int runPhysics)
|
||||
{
|
||||
callVoidForward(chain, RH_SV_ActivateServer, runPhysics);
|
||||
auto original = [chain](int _runPhysics)
|
||||
{
|
||||
chain->callNext(_runPhysics);
|
||||
};
|
||||
|
||||
callVoidForward(RH_SV_ActivateServer, original, runPhysics);
|
||||
}
|
||||
|
||||
void Cvar_DirectSet(IRehldsHook_Cvar_DirectSet *chain, cvar_t *var, const char *value)
|
||||
{
|
||||
callVoidForward(chain, RH_Cvar_DirectSet, var, value);
|
||||
auto original = [chain](cvar_t *_var, const char *_value)
|
||||
{
|
||||
chain->callNext(_var, _value);
|
||||
};
|
||||
|
||||
callVoidForward(RH_Cvar_DirectSet, original, var, value);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -38,297 +50,241 @@ void Cvar_DirectSet(IRehldsHook_Cvar_DirectSet *chain, cvar_t *var, const char *
|
||||
*/
|
||||
void CBasePlayer_Spawn(IReGameHook_CBasePlayer_Spawn *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_Spawn, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_Spawn, pthis->entindex());
|
||||
};
|
||||
|
||||
callVoidForward(RH_CBasePlayer_Spawn, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_Precache(IReGameHook_CBasePlayer_Precache *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_Precache, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_Precache, pthis->entindex());
|
||||
callVoidForward(RH_CBasePlayer_Precache, original, pthis->entindex());
|
||||
}
|
||||
|
||||
int CBasePlayer_ObjectCaps(IReGameHook_CBasePlayer_ObjectCaps *chain, CBasePlayer *pthis)
|
||||
{
|
||||
int ownresult = 0; // return own for OVERRIDE
|
||||
int origresult = 0; // return by call original function
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
return chain->callNext();
|
||||
};
|
||||
|
||||
if (callForward_Pre(RH_CBasePlayer_ObjectCaps, pthis->entindex())) {
|
||||
origresult = chain->callNext();
|
||||
}
|
||||
|
||||
if (callForward_Post(RH_CBasePlayer_ObjectCaps, pthis->entindex())) {
|
||||
// return original
|
||||
return origresult;
|
||||
}
|
||||
|
||||
// return from override
|
||||
return g_currentHookChain->m_data.m_interger;
|
||||
return callForward<int>(RH_CBasePlayer_ObjectCaps, original, pthis->entindex());
|
||||
}
|
||||
|
||||
int CBasePlayer_Classify(IReGameHook_CBasePlayer_Classify *chain, CBasePlayer *pthis)
|
||||
{
|
||||
//int ownresult = 0; // return own for OVERRIDE
|
||||
int origresult = 0; // return by call original function
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
return chain->callNext();
|
||||
};
|
||||
|
||||
if (callForward_Pre(RH_CBasePlayer_Classify, pthis->entindex())) {
|
||||
origresult = chain->callNext();
|
||||
}
|
||||
|
||||
if (callForward_Post(RH_CBasePlayer_Classify, pthis->entindex())) {
|
||||
// return original
|
||||
return origresult;
|
||||
}
|
||||
|
||||
// return from override
|
||||
return g_currentHookChain->m_data.m_interger;
|
||||
return callForward<int>(RH_CBasePlayer_Classify, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_TraceAttack(IReGameHook_CBasePlayer_TraceAttack *chain, CBasePlayer *pthis, entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
|
||||
void CBasePlayer_TraceAttack(IReGameHook_CBasePlayer_TraceAttack *chain, CBasePlayer *pthis, entvars_t *pevAttacker, float flDamage, Vector& vecDir, TraceResult *ptr, int bitsDamageType)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_TraceAttack, pthis->entindex(), ENTINDEX(pevAttacker), flDamage, g_amxxapi.PrepareCellArrayA(reinterpret_cast<cell *>(&vecDir), 3, false), ptr, bitsDamageType)) {
|
||||
chain->callNext(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
|
||||
}
|
||||
Vector vecDirCopy(vecDir);
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_TraceAttack, pthis->entindex(), ENTINDEX(pevAttacker), flDamage, g_amxxapi.PrepareCellArrayA(reinterpret_cast<cell *>(&vecDir), 3, false), ptr, bitsDamageType);
|
||||
auto original = [chain, &vecDirCopy](int _pthis, int _pevAttacker, float _flDamage, cell _vecDir, int _ptr, int _bitsDamageType)
|
||||
{
|
||||
chain->callNext(PEV(_pevAttacker), _flDamage, vecDirCopy, (TraceResult *)_ptr, _bitsDamageType);
|
||||
};
|
||||
|
||||
callVoidForward(RH_CBasePlayer_TraceAttack, original, pthis->entindex(), indexOfEdict(pevAttacker), flDamage, g_amxxapi.PrepareCellArrayA(reinterpret_cast<cell *>(&vecDirCopy), 3, true), int(ptr), bitsDamageType);
|
||||
}
|
||||
|
||||
int CBasePlayer_TakeDamage(IReGameHook_CBasePlayer_TakeDamage *chain, CBasePlayer *pthis, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
|
||||
{
|
||||
//int ownresult = 0; // return own for OVERRIDE
|
||||
int origresult = 0; // return by call original function
|
||||
auto original = [chain](int _pthis, int _pevInflictor, int _pevAttacker, float _flDamage, int _bitsDamageType)
|
||||
{
|
||||
return chain->callNext(PEV(_pevInflictor), PEV(_pevAttacker), _flDamage, _bitsDamageType);
|
||||
};
|
||||
|
||||
if (callForward_Pre(RH_CBasePlayer_TakeDamage, pthis->entindex(), ENTINDEX(pevInflictor), ENTINDEX(pevAttacker), flDamage, bitsDamageType)) {
|
||||
origresult = chain->callNext(pevInflictor, pevAttacker, flDamage, bitsDamageType);
|
||||
}
|
||||
|
||||
if (callForward_Post(RH_CBasePlayer_TakeDamage, pthis->entindex(), ENTINDEX(pevInflictor), ENTINDEX(pevAttacker), flDamage, bitsDamageType)) {
|
||||
// return original
|
||||
return origresult;
|
||||
}
|
||||
|
||||
// return from override
|
||||
return g_currentHookChain->m_data.m_interger;
|
||||
return callForward<int>(RH_CBasePlayer_TakeDamage, original, pthis->entindex(), indexOfEdict(pevInflictor), indexOfEdict(pevAttacker), flDamage, bitsDamageType);
|
||||
}
|
||||
|
||||
int CBasePlayer_TakeHealth(IReGameHook_CBasePlayer_TakeHealth *chain, CBasePlayer *pthis, float flHealth, int bitsDamageType)
|
||||
{
|
||||
//int ownresult = 0; // return own for OVERRIDE
|
||||
int origresult = 0; // return by call original function
|
||||
auto original = [chain](int _pthis, float _flHealth, int _bitsDamageType)
|
||||
{
|
||||
return chain->callNext(_flHealth, _bitsDamageType);
|
||||
};
|
||||
|
||||
if (callForward_Pre(RH_CBasePlayer_TakeHealth, pthis->entindex(), flHealth, bitsDamageType)) {
|
||||
origresult = chain->callNext(flHealth, bitsDamageType);
|
||||
}
|
||||
|
||||
if (callForward_Post(RH_CBasePlayer_TakeHealth, pthis->entindex(), flHealth, bitsDamageType)) {
|
||||
// return original
|
||||
return origresult;
|
||||
}
|
||||
|
||||
// return from override
|
||||
return g_currentHookChain->m_data.m_interger;
|
||||
return callForward<int>(RH_CBasePlayer_TakeHealth, original, pthis->entindex(), flHealth, bitsDamageType);
|
||||
}
|
||||
|
||||
void CBasePlayer_Killed(IReGameHook_CBasePlayer_Killed *chain, CBasePlayer *pthis, entvars_t *pevAttacker, int iGib)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_Killed, pthis->entindex(), ENTINDEX(pevAttacker), iGib)) {
|
||||
chain->callNext(pevAttacker, iGib);
|
||||
}
|
||||
auto original = [chain](int _pthis, int _pevAttacker, int _iGib)
|
||||
{
|
||||
chain->callNext(PEV(_pevAttacker), _iGib);
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_Killed, pthis->entindex(), ENTINDEX(pevAttacker), iGib);
|
||||
callVoidForward(RH_CBasePlayer_Killed, original, pthis->entindex(), indexOfEdict(pevAttacker), iGib);
|
||||
}
|
||||
|
||||
void CBasePlayer_AddPoints(IReGameHook_CBasePlayer_AddPoints *chain, CBasePlayer *pthis, int score, BOOL bAllowNegativeScore)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_AddPoints, pthis->entindex(), score, bAllowNegativeScore)) {
|
||||
chain->callNext(score, bAllowNegativeScore);
|
||||
}
|
||||
auto original = [chain](int _pthis, int _score, BOOL _bAllowNegativeScore)
|
||||
{
|
||||
chain->callNext(_score, _bAllowNegativeScore);
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_AddPoints, pthis->entindex(), score, bAllowNegativeScore);
|
||||
callVoidForward(RH_CBasePlayer_AddPoints, original, pthis->entindex(), score, bAllowNegativeScore);
|
||||
}
|
||||
|
||||
void CBasePlayer_AddPointsToTeam(IReGameHook_CBasePlayer_AddPointsToTeam *chain, CBasePlayer *pthis, int score, BOOL bAllowNegativeScore)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_AddPointsToTeam, pthis->entindex(), score, bAllowNegativeScore)) {
|
||||
chain->callNext(score, bAllowNegativeScore);
|
||||
}
|
||||
auto original = [chain](int _pthis, int _score, BOOL _bAllowNegativeScore)
|
||||
{
|
||||
chain->callNext(_score, _bAllowNegativeScore);
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_AddPointsToTeam, pthis->entindex(), score, bAllowNegativeScore);
|
||||
callVoidForward(RH_CBasePlayer_AddPointsToTeam, original, pthis->entindex(), score, bAllowNegativeScore);
|
||||
}
|
||||
|
||||
BOOL CBasePlayer_AddPlayerItem(IReGameHook_CBasePlayer_AddPlayerItem *chain, CBasePlayer *pthis, CBasePlayerItem *pItem)
|
||||
{
|
||||
//BOOL ownresult = 0; // return own for OVERRIDE
|
||||
BOOL origresult = 0; // return by call original function
|
||||
auto original = [chain](int _pthis, int _pItem)
|
||||
{
|
||||
return chain->callNext(getPrivate<CBasePlayerItem>(_pItem));
|
||||
};
|
||||
|
||||
if (callForward_Pre(RH_CBasePlayer_AddPlayerItem, pthis->entindex(), pItem->entindex())) {
|
||||
origresult = chain->callNext(pItem);
|
||||
}
|
||||
|
||||
if (callForward_Post(RH_CBasePlayer_AddPlayerItem, pthis->entindex(), pItem->entindex())) {
|
||||
// return original
|
||||
return origresult;
|
||||
}
|
||||
|
||||
// return from override
|
||||
return (BOOL)g_currentHookChain->m_data.m_interger;
|
||||
return callForward<BOOL>(RH_CBasePlayer_AddPlayerItem, original, pthis->entindex(), pItem->entindex());
|
||||
}
|
||||
|
||||
BOOL CBasePlayer_RemovePlayerItem(IReGameHook_CBasePlayer_RemovePlayerItem *chain, CBasePlayer *pthis, CBasePlayerItem *pItem)
|
||||
{
|
||||
//BOOL ownresult = 0; // return own for OVERRIDE
|
||||
BOOL origresult = 0; // return by call original function
|
||||
auto original = [chain](int _pthis, int _pItem)
|
||||
{
|
||||
return chain->callNext(getPrivate<CBasePlayerItem>(_pItem));
|
||||
};
|
||||
|
||||
if (callForward_Pre(RH_CBasePlayer_RemovePlayerItem, pthis->entindex(), pItem->entindex())) {
|
||||
origresult = chain->callNext(pItem);
|
||||
}
|
||||
|
||||
if (callForward_Post(RH_CBasePlayer_RemovePlayerItem, pthis->entindex(), pItem->entindex())) {
|
||||
// return original
|
||||
return origresult;
|
||||
}
|
||||
|
||||
// return from override
|
||||
return (BOOL)g_currentHookChain->m_data.m_interger;
|
||||
return callForward<BOOL>(RH_CBasePlayer_RemovePlayerItem, original, pthis->entindex(), pItem->entindex());
|
||||
}
|
||||
|
||||
int CBasePlayer_GiveAmmo(IReGameHook_CBasePlayer_GiveAmmo *chain, CBasePlayer *pthis, int iAmount, char *szName, int iMax)
|
||||
{
|
||||
//int ownresult = 0; // return own for OVERRIDE
|
||||
int origresult = 0; // return by call original function
|
||||
auto original = [chain](int _pthis, int _iAmount, char *_szName, int _iMax)
|
||||
{
|
||||
return chain->callNext(_iAmount, _szName, _iMax);
|
||||
};
|
||||
|
||||
if (callForward_Pre(RH_CBasePlayer_GiveAmmo, pthis->entindex(), iAmount, szName, iMax)) {
|
||||
origresult = chain->callNext(iAmount, szName, iMax);
|
||||
}
|
||||
|
||||
if (callForward_Post(RH_CBasePlayer_GiveAmmo, pthis->entindex(), iAmount, szName, iMax)) {
|
||||
// return original
|
||||
return origresult;
|
||||
}
|
||||
|
||||
// return from override
|
||||
return g_currentHookChain->m_data.m_interger;
|
||||
return callForward<int>(RH_CBasePlayer_GiveAmmo, original, pthis->entindex(), iAmount, szName, iMax);
|
||||
}
|
||||
|
||||
void CBasePlayer_ResetMaxSpeed(IReGameHook_CBasePlayer_ResetMaxSpeed *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_ResetMaxSpeed, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_ResetMaxSpeed, pthis->entindex());
|
||||
callVoidForward(RH_CBasePlayer_ResetMaxSpeed, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_Jump(IReGameHook_CBasePlayer_Jump *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_Jump, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_Jump, pthis->entindex());
|
||||
callVoidForward(RH_CBasePlayer_Jump, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_Duck(IReGameHook_CBasePlayer_Duck *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_Duck, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_Duck, pthis->entindex());
|
||||
callVoidForward(RH_CBasePlayer_Duck, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_PreThink(IReGameHook_CBasePlayer_PreThink *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_PreThink, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_PreThink, pthis->entindex());
|
||||
callVoidForward(RH_CBasePlayer_PreThink, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_PostThink(IReGameHook_CBasePlayer_PostThink *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_PostThink, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_PostThink, pthis->entindex());
|
||||
callVoidForward(RH_CBasePlayer_PostThink, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_UpdateClientData(IReGameHook_CBasePlayer_UpdateClientData *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_UpdateClientData, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_UpdateClientData, pthis->entindex());
|
||||
callVoidForward(RH_CBasePlayer_UpdateClientData, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_ImpulseCommands(IReGameHook_CBasePlayer_ImpulseCommands *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_ImpulseCommands, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_ImpulseCommands, pthis->entindex());
|
||||
};
|
||||
callVoidForward(RH_CBasePlayer_ImpulseCommands, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_RoundRespawn(IReGameHook_CBasePlayer_RoundRespawn *chain, CBasePlayer *pthis)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_RoundRespawn, pthis->entindex())) {
|
||||
auto original = [chain](int _pthis)
|
||||
{
|
||||
chain->callNext();
|
||||
}
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_RoundRespawn, pthis->entindex());
|
||||
callVoidForward(RH_CBasePlayer_RoundRespawn, original, pthis->entindex());
|
||||
}
|
||||
|
||||
void CBasePlayer_Blind(IReGameHook_CBasePlayer_Blind *chain, CBasePlayer *pthis, float flUntilTime, float flHoldTime, float flFadeTime, int iAlpha)
|
||||
{
|
||||
if (callVoidForward_Pre(RH_CBasePlayer_Blind, pthis->entindex(), flUntilTime, flHoldTime, flFadeTime, iAlpha)) {
|
||||
chain->callNext(flUntilTime, flHoldTime, flFadeTime, iAlpha);
|
||||
}
|
||||
auto original = [chain](int _pthis, float _flUntilTime, float _flHoldTime, float _flFadeTime, int _iAlpha)
|
||||
{
|
||||
chain->callNext(_flUntilTime, _flHoldTime, _flFadeTime, _iAlpha);
|
||||
};
|
||||
|
||||
callVoidForward_Post(RH_CBasePlayer_Blind, pthis->entindex(), flUntilTime, flHoldTime, flFadeTime, iAlpha);
|
||||
callVoidForward(RH_CBasePlayer_Blind, original, pthis->entindex(), flUntilTime, flHoldTime, flFadeTime, iAlpha);
|
||||
}
|
||||
|
||||
CBaseEntity *CBasePlayer_Observer_IsValidTarget(IReGameHook_CBasePlayer_Observer_IsValidTarget *chain, CBasePlayer *pthis, int iPlayerIndex, bool bSameTeam)
|
||||
{
|
||||
//CBaseEntity *ownresult = nullptr; // return own for OVERRIDE
|
||||
CBaseEntity *origresult = nullptr; // return by call original function
|
||||
auto original = [chain](int _pthis, int _iPlayerIndex, bool _bSameTeam)
|
||||
{
|
||||
return chain->callNext(_iPlayerIndex, _bSameTeam);
|
||||
};
|
||||
|
||||
if (callForward_Pre(RH_CBasePlayer_Observer_IsValidTarget, pthis->entindex(), iPlayerIndex, bSameTeam)) {
|
||||
origresult = chain->callNext(iPlayerIndex, bSameTeam);
|
||||
}
|
||||
|
||||
if (callForward_Post(RH_CBasePlayer_Observer_IsValidTarget, pthis->entindex(), iPlayerIndex, bSameTeam)) {
|
||||
// return original
|
||||
return origresult;
|
||||
}
|
||||
|
||||
// return from override
|
||||
return g_currentHookChain->m_data.m_classptr;
|
||||
return callForward<CBaseEntity *>(RH_CBasePlayer_Observer_IsValidTarget, original, pthis->entindex(), iPlayerIndex, bSameTeam);
|
||||
}
|
||||
|
||||
int GetForceCamera(IReGameHook_GetForceCamera *chain, CBasePlayer *pObserver)
|
||||
{
|
||||
//int ownresult = 0; // return own for OVERRIDE
|
||||
int origresult = 0; // return by call original function
|
||||
auto original = [chain](int _pObserver)
|
||||
{
|
||||
return chain->callNext(getPrivate<CBasePlayer>(_pObserver));
|
||||
};
|
||||
|
||||
if (callForward_Pre(RH_GetForceCamera, pObserver->entindex())) {
|
||||
origresult = chain->callNext(pObserver);
|
||||
}
|
||||
|
||||
if (callForward_Post(RH_GetForceCamera, pObserver->entindex())) {
|
||||
// return original
|
||||
return origresult;
|
||||
}
|
||||
|
||||
// return from override
|
||||
return g_currentHookChain->m_data.m_interger;
|
||||
return callForward<int>(RH_GetForceCamera, original, pObserver->entindex());
|
||||
}
|
||||
|
@ -1,119 +1,176 @@
|
||||
#pragma once
|
||||
|
||||
enum
|
||||
// hookchain return type
|
||||
enum HookChainState
|
||||
{
|
||||
RH_UNSET = 0,
|
||||
RH_IGNORED, // plugin didn't take any action
|
||||
RH_HANDLED, // plugin did something, but real function should still be called
|
||||
RH_OVERRIDE, // call real function, but use my return value
|
||||
RH_SUPERCEDE // skip real function; use my return value
|
||||
HC_CONTINUE = 0,
|
||||
HC_OVERRIDE,
|
||||
HC_SUPERCEDE,
|
||||
HC_BREAK
|
||||
};
|
||||
|
||||
// for hookchain return
|
||||
enum HookChainReturn
|
||||
// api types
|
||||
enum AType : uint8
|
||||
{
|
||||
RHV_STRING = 0,
|
||||
RHV_FLOAT,
|
||||
RHV_INTEGER,
|
||||
RHV_CLASSPTR
|
||||
ATYPE_INTEGER = 0,
|
||||
ATYPE_FLOAT,
|
||||
ATYPE_STRING,
|
||||
ATYPE_CLASSPTR
|
||||
};
|
||||
|
||||
extern CHook *g_currentHookChain;
|
||||
|
||||
template <typename ...t_args>
|
||||
inline bool callVoidForward_Pre(int func, t_args... args)
|
||||
struct retval_t
|
||||
{
|
||||
bool set;
|
||||
AType type;
|
||||
|
||||
union
|
||||
{
|
||||
char* _string;
|
||||
float _float;
|
||||
int _interger;
|
||||
CBaseEntity* _classptr;
|
||||
};
|
||||
};
|
||||
|
||||
inline AType getApiType(int) { return ATYPE_INTEGER; }
|
||||
inline AType getApiType(unsigned) { return ATYPE_INTEGER; }
|
||||
inline AType getApiType(cvar_s *) { return ATYPE_INTEGER; }
|
||||
inline AType getApiType(float) { return ATYPE_FLOAT; }
|
||||
inline AType getApiType(const char *) { return ATYPE_STRING; }
|
||||
inline AType getApiType(CBaseEntity *) { return ATYPE_CLASSPTR; }
|
||||
|
||||
template<size_t current>
|
||||
void setupArgTypes(AType args_type[])
|
||||
{
|
||||
auto hook = hooklist[func];
|
||||
register int ret = RH_UNSET;
|
||||
for (auto it = hook->pre.begin(), end = hook->pre.end(); it != end; ++it)
|
||||
{
|
||||
if ((*it)->GetState() == FSTATE_OK)
|
||||
{
|
||||
ret = g_amxxapi.ExecuteForward((*it)->GetForwardID(), args...);
|
||||
}
|
||||
}
|
||||
|
||||
// no supercede, continue to call original func
|
||||
return (ret < RH_SUPERCEDE);
|
||||
}
|
||||
|
||||
template <typename ...t_args>
|
||||
inline void callVoidForward_Post(int func, t_args... args)
|
||||
#define MAX_ARGS 10u
|
||||
|
||||
template<size_t current, typename T, typename ...t_args>
|
||||
void setupArgTypes(AType args_type[MAX_ARGS], T arg, t_args... args)
|
||||
{
|
||||
auto hook = hooklist[func];
|
||||
for (auto it = hook->post.begin(), end = hook->post.end(); it != end; ++it)
|
||||
{
|
||||
if ((*it)->GetState() == FSTATE_OK)
|
||||
{
|
||||
g_currentHookChain = (*it);
|
||||
g_amxxapi.ExecuteForward((*it)->GetForwardID(), args...);
|
||||
}
|
||||
}
|
||||
args_type[current] = getApiType(arg);
|
||||
if (sizeof...(args) && current + 1 < MAX_ARGS)
|
||||
setupArgTypes<current + 1>(args_type, args...);
|
||||
}
|
||||
|
||||
template <typename t_chain, typename ...t_args>
|
||||
inline void callVoidForward(t_chain chain, int func, t_args... args)
|
||||
struct hookctx_t
|
||||
{
|
||||
auto hook = hooklist[func];
|
||||
register int ret = RH_UNSET;
|
||||
for (auto it = hook->pre.begin(), end = hook->pre.end(); it != end; ++it)
|
||||
template<typename ...t_args>
|
||||
hookctx_t(size_t count, size_t ptr, t_args... args)
|
||||
{
|
||||
if ((*it)->GetState() == FSTATE_OK)
|
||||
args_count = min(count, MAX_ARGS);
|
||||
args_ptr = ptr;
|
||||
setupArgTypes<0>(this->args_type, args...);
|
||||
}
|
||||
|
||||
retval_t retVal;
|
||||
size_t args_count;
|
||||
size_t args_ptr;
|
||||
AType args_type[MAX_ARGS];
|
||||
};
|
||||
|
||||
extern hookctx_t* g_hookCtx;
|
||||
|
||||
template <typename original_t, typename ...f_args>
|
||||
void callVoidForward(int func, original_t original, f_args... args)
|
||||
{
|
||||
hookctx_t hookCtx(sizeof...(args), size_t(&original) + sizeof(original), args...);
|
||||
hookCtx.retVal.set = false;
|
||||
g_hookCtx = &hookCtx;
|
||||
|
||||
int hc_state = HC_CONTINUE;
|
||||
auto hook = g_hookManager.getHook(func);
|
||||
|
||||
for (auto& fwd : hook->pre)
|
||||
{
|
||||
if (fwd->GetState() == FSTATE_ENABLED)
|
||||
{
|
||||
ret = g_amxxapi.ExecuteForward((*it)->GetForwardID(), args...);
|
||||
auto ret = g_amxxapi.ExecuteForward(fwd->m_forward, args...);
|
||||
|
||||
if (ret == HC_BREAK) {
|
||||
g_hookCtx = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret > hc_state)
|
||||
hc_state = ret;
|
||||
}
|
||||
}
|
||||
|
||||
// no supercede, continue to call original func
|
||||
if (ret < RH_SUPERCEDE)
|
||||
{
|
||||
chain->callNext(args...);
|
||||
}
|
||||
if (hc_state != HC_SUPERCEDE)
|
||||
original(args...);
|
||||
|
||||
// Post
|
||||
for (auto it = hook->post.begin(), end = hook->post.end(); it != end; ++it)
|
||||
for (auto& fwd : hook->post)
|
||||
{
|
||||
if ((*it)->GetState() == FSTATE_OK)
|
||||
if (fwd->GetState() == FSTATE_ENABLED)
|
||||
{
|
||||
g_currentHookChain = (*it);
|
||||
g_amxxapi.ExecuteForward((*it)->GetForwardID(), args...);
|
||||
auto ret = g_amxxapi.ExecuteForward(fwd->m_forward, args...);
|
||||
|
||||
if (ret == HC_BREAK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_hookCtx = nullptr;
|
||||
}
|
||||
|
||||
template <typename ...t_args>
|
||||
inline bool callForward_Pre(int func, t_args... args)
|
||||
template <typename R, typename original_t, typename ...f_args>
|
||||
R callForward(int func, original_t original, f_args... args)
|
||||
{
|
||||
auto hook = hooklist[func];
|
||||
register int ret = RH_UNSET;
|
||||
for (auto it = hook->pre.begin(), end = hook->pre.end(); it != end; ++it)
|
||||
hookctx_t hookCtx(sizeof...(args), size_t(&original) + sizeof(original), args...);
|
||||
hookCtx.retVal.set = false;
|
||||
hookCtx.retVal.type = getApiType(R());
|
||||
g_hookCtx = &hookCtx;
|
||||
|
||||
int hc_state = HC_CONTINUE;
|
||||
auto hook = g_hookManager.getHook(func);
|
||||
|
||||
for (auto& fwd : hook->pre)
|
||||
{
|
||||
if ((*it)->GetState() == FSTATE_OK)
|
||||
if (fwd->GetState() == FSTATE_ENABLED)
|
||||
{
|
||||
ret = g_amxxapi.ExecuteForward((*it)->GetForwardID(), args...);
|
||||
auto ret = g_amxxapi.ExecuteForward(fwd->m_forward, args...);
|
||||
|
||||
if (ret == HC_CONTINUE)
|
||||
continue;
|
||||
|
||||
if (!hookCtx.retVal.set)
|
||||
{
|
||||
g_amxxapi.LogError(fwd->GetAmx(), AMX_ERR_CALLBACK, "%s", "can't suppress original function call without new return value set");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret == HC_BREAK) {
|
||||
g_hookCtx = nullptr;
|
||||
return (R)hookCtx.retVal._interger;
|
||||
}
|
||||
|
||||
if (ret > hc_state)
|
||||
hc_state = ret;
|
||||
}
|
||||
}
|
||||
|
||||
// no supercede, continue to call original func
|
||||
return (ret < RH_SUPERCEDE);
|
||||
}
|
||||
|
||||
template <typename ...t_args>
|
||||
inline bool callForward_Post(int func, t_args... args)
|
||||
{
|
||||
auto hook = hooklist[func];
|
||||
register int ret = RH_UNSET;
|
||||
for (auto it = hook->post.begin(), end = hook->post.end(); it != end; ++it)
|
||||
if (hc_state != HC_SUPERCEDE)
|
||||
{
|
||||
if ((*it)->GetState() == FSTATE_OK)
|
||||
{
|
||||
g_currentHookChain = (*it);
|
||||
ret = g_amxxapi.ExecuteForward((*it)->GetForwardID(), args...);
|
||||
auto retVal = original(args...);
|
||||
|
||||
if (hc_state != HC_OVERRIDE)
|
||||
hookCtx.retVal._interger = *(int *)&retVal;
|
||||
}
|
||||
|
||||
for (auto& fwd : hook->post) {
|
||||
if (fwd->GetState() == FSTATE_ENABLED) {
|
||||
auto ret = g_amxxapi.ExecuteForward(fwd->m_forward, args...);
|
||||
|
||||
if (ret == HC_BREAK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no override
|
||||
return (ret < RH_OVERRIDE);
|
||||
g_hookCtx = nullptr;
|
||||
return (R)hookCtx.retVal._interger;
|
||||
}
|
||||
|
||||
// rehlds functions
|
||||
@ -130,7 +187,7 @@ void CBasePlayer_Spawn(IReGameHook_CBasePlayer_Spawn *chain, CBasePlayer *pthis)
|
||||
void CBasePlayer_Precache(IReGameHook_CBasePlayer_Precache *chain, CBasePlayer *pthis);
|
||||
int CBasePlayer_ObjectCaps(IReGameHook_CBasePlayer_ObjectCaps *chain, CBasePlayer *pthis);
|
||||
int CBasePlayer_Classify(IReGameHook_CBasePlayer_Classify *chain, CBasePlayer *pthis);
|
||||
void CBasePlayer_TraceAttack(IReGameHook_CBasePlayer_TraceAttack *chain, CBasePlayer *pthis, entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
|
||||
void CBasePlayer_TraceAttack(IReGameHook_CBasePlayer_TraceAttack *chain, CBasePlayer *pthis, entvars_t *pevAttacker, float flDamage, Vector& vecDir, TraceResult *ptr, int bitsDamageType);
|
||||
int CBasePlayer_TakeDamage(IReGameHook_CBasePlayer_TakeDamage *chain, CBasePlayer *pthis, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
|
||||
int CBasePlayer_TakeHealth(IReGameHook_CBasePlayer_TakeHealth *chain, CBasePlayer *pthis, float flHealth, int bitsDamageType);
|
||||
void CBasePlayer_Killed(IReGameHook_CBasePlayer_Killed *chain, CBasePlayer *pthis, entvars_t *pevAttacker, int iGib);
|
||||
|
@ -41,14 +41,12 @@ hook_t hooklist_player[] = {
|
||||
DLL(CBasePlayer_Observer_IsValidTarget),
|
||||
};
|
||||
|
||||
hooklist_t hooklist;
|
||||
|
||||
hook_t *hooklist_t::operator[](size_t hook) const
|
||||
{
|
||||
#define CASE(h) case ht_##h: if (index < arraysize(hooklist_##h)) return &hooklist_##h[index]; else break;
|
||||
|
||||
const auto table = hooks_tables_e(hook / MAX_RANGE_REGION);
|
||||
const auto index = hook & (MAX_RANGE_REGION - 1);
|
||||
const auto table = hooks_tables_e(hook / MAX_REGION_RANGE);
|
||||
const auto index = hook & (MAX_REGION_RANGE - 1);
|
||||
|
||||
switch (table) {
|
||||
CASE(engine)
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
#include "reapi_utils.h"
|
||||
|
||||
#define MAX_RANGE_REGION 1024
|
||||
#define BEGIN_FUNC_REGION(x) (MAX_RANGE_REGION * hooklist_t::hooks_tables_e::ht_##x)
|
||||
#define MAX_REGION_RANGE 1024
|
||||
#define BEGIN_FUNC_REGION(x) (MAX_REGION_RANGE * hooklist_t::hooks_tables_e::ht_##x)
|
||||
#define MAX_HOOK_FORWARDS 1024
|
||||
|
||||
typedef bool (*ablfunc_t)();
|
||||
typedef int (*regfunc_t)(AMX *, const char *);
|
||||
@ -36,7 +36,7 @@ struct regfunc
|
||||
}
|
||||
|
||||
template<typename T, typename R>
|
||||
regfunc(R (*)(T *, CBasePlayer *, entvars_t *, float, Vector, TraceResult *, int)) {
|
||||
regfunc(R (*)(T *, CBasePlayer *, entvars_t *, float, Vector&, TraceResult *, int)) {
|
||||
func = [](AMX *amx, const char *name) { return g_amxxapi.RegisterSPForwardByName(amx, name, FP_CELL, FP_CELL, FP_FLOAT, FP_ARRAY, FP_CELL, FP_CELL, FP_DONE); };
|
||||
}
|
||||
|
||||
@ -89,16 +89,16 @@ struct regfunc
|
||||
|
||||
struct hook_t
|
||||
{
|
||||
std::vector<class CHook *> pre; // array pre forward
|
||||
std::vector<class CHook *> post; // array post forward
|
||||
std::vector<class CAmxxHook *> pre; // pre forwards
|
||||
std::vector<class CAmxxHook *> post; // post forwards
|
||||
|
||||
const char *func_name; // name functions
|
||||
const char *func_name; // function name
|
||||
const char *depend_name; // platform dependency
|
||||
|
||||
ablfunc_t availableFunc;
|
||||
regfunc_t registerForward; // register AMXX forward and get ID
|
||||
regchain_t registerHookchain; // register function-hook API
|
||||
regchain_t unregisterHookchain; // unregister function-hook API
|
||||
ablfunc_t checkRequirements;
|
||||
regfunc_t registerForward; // AMXX forward registration function
|
||||
regchain_t registerHookchain; // register re* API hook
|
||||
regchain_t unregisterHookchain; // unregister re* API hook
|
||||
};
|
||||
|
||||
struct hooklist_t
|
||||
@ -200,4 +200,3 @@ enum GamedllFunc_CBasePlayer
|
||||
|
||||
extern hook_t hooklist_engine[];
|
||||
extern hook_t hooklist_player[];
|
||||
extern hooklist_t hooklist;
|
||||
|
@ -2,39 +2,67 @@
|
||||
|
||||
CHookManager g_hookManager;
|
||||
|
||||
CHook *CHookManager::addHandler(int func, int forward, bool post)
|
||||
int CHookManager::addHandler(AMX* amx, int func, int forward, bool post) const
|
||||
{
|
||||
if (!hooklist[func]->post.size() && !hooklist[func]->pre.size())
|
||||
if (!m_hooklist[func]->post.size() && !m_hooklist[func]->pre.size())
|
||||
{
|
||||
// register API hookchain
|
||||
hooklist[func]->registerHookchain();
|
||||
// API hookchain
|
||||
m_hooklist[func]->registerHookchain();
|
||||
}
|
||||
|
||||
CHook *hook = new CHook(forward);
|
||||
if (post)
|
||||
{
|
||||
hooklist[func]->post.push_back(hook);
|
||||
}
|
||||
else
|
||||
{
|
||||
hooklist[func]->pre.push_back(hook);
|
||||
}
|
||||
|
||||
return hook;
|
||||
auto& dest = post ? m_hooklist[func]->post : m_hooklist[func]->pre;
|
||||
dest.push_back(new CAmxxHook(amx, forward));
|
||||
int id = func * MAX_HOOK_FORWARDS + dest.size();
|
||||
return post ? -id : id; // use unsigned ids for post hooks
|
||||
}
|
||||
|
||||
void CHookManager::clearHandlers()
|
||||
AMX* CAmxxHook::GetAmx() const
|
||||
{
|
||||
return m_amx;
|
||||
}
|
||||
|
||||
void CHookManager::clearHandlers() const
|
||||
{
|
||||
#define CLEAR_HOOKLIST(__END__, __START__)\
|
||||
for (size_t i = BEGIN_FUNC_REGION(__START__); i < RH_##__END__##_End; ++i) {\
|
||||
if (hooklist[i] == nullptr)\
|
||||
if (m_hooklist[i] == nullptr)\
|
||||
continue;\
|
||||
hooklist[i]->pre.clear();\
|
||||
hooklist[i]->post.clear();\
|
||||
hooklist[i]->unregisterHookchain();\
|
||||
m_hooklist[i]->pre.clear();\
|
||||
m_hooklist[i]->post.clear();\
|
||||
m_hooklist[i]->unregisterHookchain();\
|
||||
}
|
||||
|
||||
CLEAR_HOOKLIST(EngineFunc, engine);
|
||||
CLEAR_HOOKLIST(GameDLL, gamedll);
|
||||
CLEAR_HOOKLIST(CBasePlayer, player);
|
||||
}
|
||||
|
||||
hook_t* CHookManager::getHook(size_t func) const
|
||||
{
|
||||
return m_hooklist[func];
|
||||
}
|
||||
|
||||
CAmxxHook* CHookManager::getAmxxHook(cell handle) const
|
||||
{
|
||||
bool post = false;
|
||||
|
||||
if (handle < 0) // post
|
||||
{
|
||||
handle = ~handle;
|
||||
post = true;
|
||||
}
|
||||
else handle--;
|
||||
|
||||
const size_t func = handle / MAX_HOOK_FORWARDS;
|
||||
const size_t id = handle & (MAX_HOOK_FORWARDS - 1);
|
||||
auto hook = m_hooklist[func];
|
||||
|
||||
if (hook)
|
||||
{
|
||||
auto& forwards = post ? hook->post : hook->pre;
|
||||
if (id < forwards.size())
|
||||
return forwards[id];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -6,38 +6,36 @@
|
||||
enum fwdstate
|
||||
{
|
||||
FSTATE_INVALID = 0,
|
||||
FSTATE_OK,
|
||||
FSTATE_PAUSE,
|
||||
FSTATE_STOP
|
||||
FSTATE_ENABLED,
|
||||
FSTATE_PAUSED,
|
||||
FSTATE_STOPPED
|
||||
};
|
||||
|
||||
class CHook
|
||||
class CAmxxHook
|
||||
{
|
||||
public:
|
||||
CHook(int forward_index) : m_forward(forward_index), m_state(FSTATE_OK) {};
|
||||
CAmxxHook(AMX* amx, int forward_index) : m_forward(forward_index), m_state(FSTATE_ENABLED), m_amx(amx) {};
|
||||
|
||||
int GetForwardID() const { return m_forward; }
|
||||
fwdstate GetState() const { return m_state; }
|
||||
AMX* GetAmx() const;
|
||||
|
||||
public:
|
||||
int m_forward;
|
||||
fwdstate m_state;
|
||||
|
||||
struct data_return_t
|
||||
{
|
||||
char* m_string;
|
||||
float m_float;
|
||||
int m_interger;
|
||||
CBaseEntity* m_classptr;
|
||||
};
|
||||
data_return_t m_data;
|
||||
AMX* m_amx;
|
||||
};
|
||||
|
||||
class CHookManager
|
||||
{
|
||||
public:
|
||||
void clearHandlers();
|
||||
CHook *addHandler(int func, int forward, bool post);
|
||||
void clearHandlers() const;
|
||||
cell addHandler(AMX* amx, int func, int forward, bool post) const;
|
||||
hook_t* getHook(size_t func) const;
|
||||
CAmxxHook* getAmxxHook(cell hook) const;
|
||||
|
||||
private:
|
||||
hooklist_t m_hooklist;
|
||||
};
|
||||
|
||||
extern CHookManager g_hookManager;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
edict_t* g_pEdicts;
|
||||
|
||||
bool OnMetaAttach()
|
||||
{
|
||||
// initialize API
|
||||
@ -15,7 +17,14 @@ void OnMetaDetach()
|
||||
g_hookManager.clearHandlers();
|
||||
}
|
||||
|
||||
void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax)
|
||||
{
|
||||
g_pEdicts = pEdictList;
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void ServerDeactivate_Post()
|
||||
{
|
||||
g_hookManager.clearHandlers();
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
@ -318,8 +318,8 @@ member_t *memberlist_t::operator[](size_t members) const
|
||||
{
|
||||
#define CASE(h) case ht_##h: if (index < arraysize(memberlist_##h)) return &memberlist_##h[index]; else break;
|
||||
|
||||
const auto table = members_tables_e(members / MAX_RANGE_REGION);
|
||||
const auto index = members & (MAX_RANGE_REGION - 1);
|
||||
const auto table = members_tables_e(members / MAX_REGION_RANGE);
|
||||
const auto index = members & (MAX_REGION_RANGE - 1);
|
||||
|
||||
switch (table) {
|
||||
CASE(gamerules)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define BEGIN_MEMBER_REGION(x) (MAX_RANGE_REGION * memberlist_t::members_tables_e::ht_##x)
|
||||
#define BEGIN_MEMBER_REGION(x) (MAX_REGION_RANGE * memberlist_t::members_tables_e::ht_##x)
|
||||
|
||||
enum enum_membertypes
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
* @param function The function to hook.
|
||||
* @param callback The forward to call.
|
||||
* @param post Whether or not to forward this in post.
|
||||
* @return Returns a handle to the hook. Use EnableHookChain/DisableHookChain to toggle the forward on or off.
|
||||
* @return Returns a handle to the hook. Use EnableHookChain/DisableHookChain to toggle the forward on or off.
|
||||
*
|
||||
* native RegisterHookChain(any:function_id, const callback[], post = 0);
|
||||
*/
|
||||
@ -18,16 +18,17 @@ static cell AMX_NATIVE_CALL RegisterHookChain(AMX *amx, cell *params)
|
||||
|
||||
int func = params[arg_func];
|
||||
int post = params[arg_post];
|
||||
auto hook = g_hookManager.getHook(func);
|
||||
|
||||
if (hooklist[func] == nullptr)
|
||||
if (hook == nullptr)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Function (%d) doesn't match hook definition.", func);
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "RegisterHookChain: function with id (%d) doesn't exist in current API version.", func);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hooklist[func]->availableFunc())
|
||||
if (!hook->checkRequirements())
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Function (%s) is not available, required %s", hooklist[func]->func_name, hooklist[func]->depend_name);
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "RegisterHookChain: function (%s) is not available, %s required", hook->func_name, hook->depend_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -35,26 +36,26 @@ static cell AMX_NATIVE_CALL RegisterHookChain(AMX *amx, cell *params)
|
||||
const char *funcname = g_amxxapi.GetAmxString(amx, params[arg_handler], 0, &len);
|
||||
if (g_amxxapi.amx_FindPublic(amx, funcname, &funcid) != AMX_ERR_NONE)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Public function \"%s\" not found.", funcname);
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "RegisterHookChain: public function \"%s\" not found.", funcname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fwid = hooklist[func]->registerForward(amx, funcname);
|
||||
int fwid = hook->registerForward(amx, funcname);
|
||||
if (fwid == -1)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Public function \"%s\" not found.", funcname);
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "RegisterHookChain: register forward failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (cell)g_hookManager.addHandler(func, fwid, post != 0);
|
||||
return g_hookManager.addHandler(amx, func, fwid, post != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Starts a hook back up.
|
||||
* Disable hook by handle.
|
||||
* Use the return value from RegisterHookChain as the parameter here!
|
||||
*
|
||||
* @param fwd The hook to re-enable.
|
||||
* @return Returns if the function is successful executed true otherwise false
|
||||
* @return Returns if the function is successful executed true otherwise false
|
||||
*
|
||||
* native bool:EnableHookChain(any:fwd);
|
||||
*/
|
||||
@ -63,20 +64,20 @@ static cell AMX_NATIVE_CALL EnableHookChain(AMX *amx, cell *params)
|
||||
{
|
||||
enum args_e { arg_count, arg_handle_hook };
|
||||
|
||||
CHook *hook = reinterpret_cast<CHook *>(params[arg_handle_hook]);
|
||||
auto hook = g_hookManager.getAmxxHook(params[arg_handle_hook]);
|
||||
|
||||
if (hook == nullptr)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid HookChain handle.");
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "EnableHookChain: invalid HookChain handle.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
hook->m_state = FSTATE_OK;
|
||||
hook->m_state = FSTATE_ENABLED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stops a hook from triggering.
|
||||
* Enable hook by handle.
|
||||
* Use the return value from RegisterHookChain as the parameter here!
|
||||
*
|
||||
* @param fwd The hook to stop.
|
||||
@ -88,15 +89,15 @@ static cell AMX_NATIVE_CALL DisableHookChain(AMX *amx, cell *params)
|
||||
{
|
||||
enum args_e { arg_count, arg_handle_hook };
|
||||
|
||||
CHook *hook = reinterpret_cast<CHook *>(params[arg_handle_hook]);
|
||||
auto hook = g_hookManager.getAmxxHook(params[arg_handle_hook]);
|
||||
|
||||
if (hook == nullptr)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid HookChain handle.");
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "DisableHookChain: invalid HookChain handle.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
hook->m_state = FSTATE_STOP;
|
||||
hook->m_state = FSTATE_STOPPED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -104,49 +105,164 @@ static cell AMX_NATIVE_CALL DisableHookChain(AMX *amx, cell *params)
|
||||
* Sets the return value of a hookchain.
|
||||
* This needs to be used in conjunction with RH_OVERRIDE or RH_SUPERCEDE.
|
||||
*
|
||||
* @param type To specify the type RHV_*, look at the enum HookChainReturn
|
||||
* @param type To specify the type RHV_*, look at the enum AType
|
||||
* @param value The value to set the return to.
|
||||
*
|
||||
* native SetHookChainReturn(HookChainReturn:type, any:...);
|
||||
* native SetHookChainReturn(AType:type, any:...);
|
||||
*/
|
||||
|
||||
static cell AMX_NATIVE_CALL SetHookChainReturn(AMX *amx, cell *params)
|
||||
{
|
||||
if (!g_currentHookChain)
|
||||
if (!g_hookCtx)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Trying get return value without active hook.");
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Trying to set return value without active hook.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum args_e { arg_count, arg_type, arg_value };
|
||||
auto& retVal = g_hookCtx->retVal;
|
||||
|
||||
switch (params[arg_type])
|
||||
if (params[arg_type] != retVal.type)
|
||||
{
|
||||
case RHV_STRING:
|
||||
{
|
||||
if (g_currentHookChain->m_data.m_string != NULL) {
|
||||
delete [] g_currentHookChain->m_data.m_string;
|
||||
}
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Trying to set incompatible return type.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int len;
|
||||
char *dest = g_amxxapi.GetAmxString(amx, params[arg_value], 0, &len);
|
||||
g_currentHookChain->m_data.m_string = new char [len + 1];
|
||||
strcpy(g_currentHookChain->m_data.m_string, dest);
|
||||
cell* srcAddr = getAmxAddr(amx, params[arg_value]);
|
||||
|
||||
switch (retVal.type)
|
||||
{
|
||||
case ATYPE_INTEGER:
|
||||
case ATYPE_FLOAT:
|
||||
retVal._interger = *srcAddr;
|
||||
break;
|
||||
|
||||
case ATYPE_STRING:
|
||||
{
|
||||
if (retVal._string != nullptr)
|
||||
delete[] retVal._string;
|
||||
|
||||
size_t len;
|
||||
const char *dest = getAmxString(srcAddr, &len);
|
||||
retVal._string = strcpy(new char[len + 1], dest);
|
||||
break;
|
||||
}
|
||||
case RHV_FLOAT:
|
||||
g_currentHookChain->m_data.m_float = *(float *)g_amxxapi.GetAmxAddr(amx, params[arg_value]);
|
||||
break;
|
||||
case RHV_INTEGER:
|
||||
g_currentHookChain->m_data.m_interger = *g_amxxapi.GetAmxAddr(amx, params[arg_value]);
|
||||
break;
|
||||
case RHV_CLASSPTR:
|
||||
g_currentHookChain->m_data.m_classptr = CBaseEntity::Instance(INDEXENT(*g_amxxapi.GetAmxAddr(amx, params[arg_value])));
|
||||
case ATYPE_CLASSPTR:
|
||||
retVal._classptr = CBaseEntity::Instance(INDEXENT(*srcAddr));
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
retVal.set = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the return value of a hookchain.
|
||||
* This needs to be used in conjunction with RH_OVERRIDE or RH_SUPERCEDE.
|
||||
*
|
||||
* @param value The value to set the return to.
|
||||
* @param [maxlen] Max length of string (optional)
|
||||
* @return Returns if the function is successful executed true otherwise false
|
||||
*
|
||||
* native GetHookChainReturn(AType:type, any:...);
|
||||
*/
|
||||
|
||||
static cell AMX_NATIVE_CALL GetHookChainReturn(AMX *amx, cell *params)
|
||||
{
|
||||
if (!g_hookCtx)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Trying to get return value without active hook.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum args_e { arg_count, arg_value, arg_maxlen };
|
||||
|
||||
auto& retVal = g_hookCtx->retVal;
|
||||
cell* dstAddr = getAmxAddr(amx, params[arg_value]);
|
||||
|
||||
switch (retVal.type)
|
||||
{
|
||||
case ATYPE_INTEGER:
|
||||
case ATYPE_FLOAT:
|
||||
*dstAddr = retVal._interger;
|
||||
break;
|
||||
case ATYPE_STRING:
|
||||
{
|
||||
if (params[arg_count] != 2)
|
||||
return 0;
|
||||
|
||||
setAmxString(dstAddr, retVal._string, params[arg_maxlen]);
|
||||
break;
|
||||
}
|
||||
case ATYPE_CLASSPTR:
|
||||
*dstAddr = retVal._classptr->entindex();
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set hookchain argument.
|
||||
* This needs to be used in conjunction with RH_OVERRIDE or RH_SUPERCEDE.
|
||||
*
|
||||
* @param number Number of argument
|
||||
* @param value New value
|
||||
* @param [maxlen] Max length of string (optional)
|
||||
* @return Returns if the function is successful executed true otherwise false
|
||||
*
|
||||
* native SetHookChainArg(number, AType:type, any:...);
|
||||
*/
|
||||
|
||||
static cell AMX_NATIVE_CALL SetHookChainArg(AMX *amx, cell *params)
|
||||
{
|
||||
if (!g_hookCtx)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Trying to get return value without active hook.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum args_e { arg_count, arg_number, arg_type, arg_value };
|
||||
|
||||
size_t number = params[arg_number] - 1;
|
||||
|
||||
if (number >= g_hookCtx->args_count)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "SetHookChainArg: can't set argument %i of hookchain with %i args.", params[arg_number], g_hookCtx->args_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AType type = g_hookCtx->args_type[number];
|
||||
|
||||
if (params[arg_type] != type)
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "SetHookChainArg: invalid argument type provided.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char temp_strings[MAX_ARGS][1024];
|
||||
|
||||
cell* srcAddr = getAmxAddr(amx, params[arg_value]);
|
||||
size_t destAddr = g_hookCtx->args_ptr + number * sizeof(int);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ATYPE_INTEGER:
|
||||
case ATYPE_FLOAT:
|
||||
*(cell *)destAddr = *srcAddr;
|
||||
break;
|
||||
case ATYPE_STRING:
|
||||
*(char **)destAddr = getAmxStringTemp(srcAddr, temp_strings[number], 1023, nullptr);
|
||||
break;
|
||||
case ATYPE_CLASSPTR:
|
||||
*(CBaseEntity **)destAddr = CBaseEntity::Instance(INDEXENT(*srcAddr));
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -158,6 +274,9 @@ AMX_NATIVE_INFO Func_Natives[] =
|
||||
{ "DisableHookChain", DisableHookChain },
|
||||
|
||||
{ "SetHookChainReturn", SetHookChainReturn },
|
||||
{ "GetHookChainReturn", GetHookChainReturn },
|
||||
|
||||
{ "SetHookChainArg", SetHookChainArg },
|
||||
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
@ -7,17 +7,18 @@ static cell AMX_NATIVE_CALL set_member(AMX *amx, cell *params)
|
||||
member_t *member = memberlist[params[arg_member]];
|
||||
|
||||
if (member == nullptr) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Member (%d) is unknown", params[arg_member]);
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "set_member: unknown member id %i", params[arg_member]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
edict_t *pEdict = INDEXENT(params[arg_index]);
|
||||
if (pEdict == nullptr || pEdict->pvPrivateData == nullptr) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "set_member: invalid or uninitialized entity", params[arg_member]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t value = *g_amxxapi.GetAmxAddr(amx, params[arg_value]);
|
||||
size_t element = *g_amxxapi.GetAmxAddr(amx, params[arg_elem]);
|
||||
size_t value = *getAmxAddr(amx, params[arg_value]);
|
||||
size_t element = *getAmxAddr(amx, params[arg_elem]);
|
||||
|
||||
switch (member->type)
|
||||
{
|
||||
@ -122,6 +123,12 @@ static cell AMX_NATIVE_CALL set_member(AMX *amx, cell *params)
|
||||
signal.Signal(value);
|
||||
return 1;
|
||||
}
|
||||
case MEMBER_DOUBLE:
|
||||
{
|
||||
// native set_member(_index, any:_member, any:_value, _elem);
|
||||
set_member<double>(pEdict, member->offset, *(float *)&value, element);
|
||||
return 1;
|
||||
}
|
||||
case MEBMER_REBUYSTRUCT:
|
||||
return -1;
|
||||
}
|
||||
@ -172,7 +179,7 @@ static cell AMX_NATIVE_CALL get_member(AMX *amx, cell *params)
|
||||
// native any:get_member(_index, any:_member, element);
|
||||
edict_t *pEntity = get_member<edict_t *>(pEdict, member->offset, element);
|
||||
if (pEntity != nullptr) {
|
||||
return ENTINDEX(pEntity);
|
||||
return indexOfEdict(pEntity);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <vector> // std::vector
|
||||
|
||||
#include <extdll.h>
|
||||
#include "reapi_utils.h"
|
||||
#include <cbase.h>
|
||||
|
||||
#include "osdep.h" // win32 vsnprintf, etc
|
||||
|
@ -4,6 +4,37 @@ template <typename T, size_t N>
|
||||
char(&ArraySizeHelper(T(&array)[N]))[N];
|
||||
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
|
||||
|
||||
#define INDEXENT edictByIndex
|
||||
#define ENTINDEX indexOfEdict
|
||||
|
||||
extern edict_t* g_pEdicts;
|
||||
|
||||
inline size_t indexOfEdict(edict_t* ed)
|
||||
{
|
||||
return ed - g_pEdicts;
|
||||
}
|
||||
|
||||
inline size_t indexOfEdict(entvars_t* pev)
|
||||
{
|
||||
return indexOfEdict(pev->pContainingEntity);
|
||||
}
|
||||
|
||||
inline edict_t* edictByIndex(size_t index)
|
||||
{
|
||||
return g_pEdicts + index;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* getPrivate(int index)
|
||||
{
|
||||
return (T *)edictByIndex(index)->pvPrivateData;
|
||||
}
|
||||
|
||||
inline entvars_t* PEV(int index)
|
||||
{
|
||||
return &edictByIndex(index)->v;
|
||||
}
|
||||
|
||||
// HLTypeConversion.h -> AMXModX
|
||||
template <typename T>
|
||||
inline T &ref_member(void *ptr, int offset, int element = 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user