2
0
mirror of https://github.com/rehlds/reapi.git synced 2025-02-10 13:48:55 +03:00

Refactoring

This commit is contained in:
asmodai 2016-04-07 01:09:51 +03:00
parent 392026e50b
commit 50b5649257
22 changed files with 670 additions and 387 deletions

View File

@ -17,22 +17,27 @@
#include <reapi_engine.inc> // NOTE: only for ReHLDS #include <reapi_engine.inc> // NOTE: only for ReHLDS
#include <reapi_gamedll.inc> // NOTE: only for gamedll Counter-Strike (ReGameDLL_CS) #include <reapi_gamedll.inc> // NOTE: only for gamedll Counter-Strike (ReGameDLL_CS)
// return constants
enum enum
{ {
RH_UNSET = 0, HC_CONTINUE = 0,
RH_IGNORED, // plugin didn't take any action HC_OVERRIDE,
RH_HANDLED, // plugin did something, but real function should still be called HC_SUPERCEDE,
RH_OVERRIDE, // call real function, but use my return value HC_BREAK
RH_SUPERCEDE // skip real function; use my return value
}; };
// for hookchain return // hookchain types
enum HookChainReturn enum AType
{ {
RHV_STRING = 0, // string ATYPE_INTEGER = 0,
RHV_FLOAT, // float ATYPE_FLOAT,
RHV_INTEGER, // returns an integer or boolean ATYPE_STRING,
RHV_CLASSPTR // for CBaseEntity *, CBasePlayer * etc 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 type To specify the type RHV_*, look at the enum HookChainReturn
* @param value The value to set the return to. * @param value The value to set the return to.
* *
* native SetHookChainReturn(HookChainReturn:type, any:...); * native SetHookChainReturn(AType:type, any:...);
*/ */
native SetHookChainReturn(HookChainReturn: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 * 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 * 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) 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; return;
} }
if (minorVersion < REAPI_VERISON_MINOR) 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; return;
} }
} }

View File

@ -51,8 +51,8 @@ typedef IHookChain<int> IReGameHook_CBasePlayer_Classify;
typedef IHookChainRegistryClass<int, class CBasePlayer> IReGameHookRegistry_CBasePlayer_Classify; typedef IHookChainRegistryClass<int, class CBasePlayer> IReGameHookRegistry_CBasePlayer_Classify;
// CBasePlayer::TraceAttack hook // CBasePlayer::TraceAttack hook
typedef IVoidHookChain<struct entvars_s *, float, Vector, struct TraceResult *, int> IReGameHook_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; typedef IVoidHookChainRegistryClass<class CBasePlayer, struct entvars_s *, float, Vector&, struct TraceResult *, int> IReGameHookRegistry_CBasePlayer_TraceAttack;
// CBasePlayer::TakeDamage hook // CBasePlayer::TakeDamage hook
typedef IHookChain<int, struct entvars_s *, struct entvars_s *, float, int> IReGameHook_CBasePlayer_TakeDamage; typedef IHookChain<int, struct entvars_s *, struct entvars_s *, float, int> IReGameHook_CBasePlayer_TakeDamage;

View File

@ -52,7 +52,7 @@ typedef IBaseInterface* (*CreateInterfaceFn)(const char *pName, int *pReturnCode
typedef IBaseInterface* (*InstantiateInterfaceFn)(); typedef IBaseInterface* (*InstantiateInterfaceFn)();
// Used internally to register classes. // Used internally to classes.
class InterfaceReg class InterfaceReg
{ {
public: public:

View File

@ -358,6 +358,9 @@
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
<StringPooling>true</StringPooling>
<ExceptionHandling>Sync</ExceptionHandling>
<OmitFramePointers>true</OmitFramePointers>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>

View File

@ -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); 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;
}

View File

@ -378,15 +378,6 @@ typedef edict_t * ( *PFN_GET_PLAYER_EDICT ) ( int /*id*/ );
typedef void * ( *PFN_GET_PLAYER_EDICT ) ( int /*id*/ ); typedef void * ( *PFN_GET_PLAYER_EDICT ) ( int /*id*/ );
#endif #endif
typedef void * ( *PFN_PLAYER_PROP_ADDR ) ( int /*id*/, int /*prop*/ ); 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_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_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*/ ); 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_Log(const char *fmt, ...);
void MF_LogError(AMX *amx, int err, 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__ #endif // __AMXXMODULE_H__

View File

@ -2,6 +2,11 @@
CAPI_Config api_cfg; CAPI_Config api_cfg;
CAPI_Config::CAPI_Config() : m_api_rehlds(false), m_api_regame(false)
{
}
bool CAPI_Config::Init() bool CAPI_Config::Init()
{ {
m_api_rehlds = RehldsApi_Init(); m_api_rehlds = RehldsApi_Init();

View File

@ -5,6 +5,7 @@
class CAPI_Config { class CAPI_Config {
public: public:
CAPI_Config();
bool Init(); bool Init();
bool hasReHLDS() const { return m_api_rehlds; } bool hasReHLDS() const { return m_api_rehlds; }

View File

@ -1,5 +1,6 @@
#include "precompiled.h" #include "precompiled.h"
extern void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax);
extern void ServerDeactivate_Post(); extern void ServerDeactivate_Post();
DLL_FUNCTIONS gFunctionTable = DLL_FUNCTIONS gFunctionTable =
@ -79,8 +80,8 @@ DLL_FUNCTIONS gFunctionTable_Post =
NULL, // pfnClientPutInServer NULL, // pfnClientPutInServer
NULL, // pfnClientCommand NULL, // pfnClientCommand
NULL, // pfnClientUserInfoChanged NULL, // pfnClientUserInfoChanged
NULL, // pfnServerActivate &ServerActivate_Post, // pfnServerActivate
&ServerDeactivate_Post, // pfnServerDeactivate &ServerDeactivate_Post, // pfnServerDeactivate
NULL, // pfnPlayerPreThink NULL, // pfnPlayerPreThink
NULL, // pfnPlayerPostThink NULL, // pfnPlayerPostThink
NULL, // pfnStartFrame NULL, // pfnStartFrame

View File

@ -1,36 +1,48 @@
#include "precompiled.h" #include "precompiled.h"
CHook *g_currentHookChain = nullptr; hookctx_t* g_hookCtx;
/* /*
* ReHLDS functions * 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) 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)) { auto original = [chain](int _recipients, int _entity, int _channel, const char *_sample, int _volume, float _attenuation, int _fFlags, int _pitch)
chain->callNext(recipients, entity, channel, sample, volume, attenuation, fFlags, 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) void SV_DropClient(IRehldsHook_SV_DropClient *chain, IGameClient *cl, bool crash, const char *fmt)
{ {
if (callVoidForward_Pre(RH_SV_DropClient, cl->GetId(), crash, fmt)) { auto original = [chain](int _cl, bool _crash, const char *_fmt)
chain->callNext(cl, crash, 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) 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) 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) void CBasePlayer_Spawn(IReGameHook_CBasePlayer_Spawn *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_Spawn, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); 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) void CBasePlayer_Precache(IReGameHook_CBasePlayer_Precache *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_Precache, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); 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 CBasePlayer_ObjectCaps(IReGameHook_CBasePlayer_ObjectCaps *chain, CBasePlayer *pthis)
{ {
int ownresult = 0; // return own for OVERRIDE auto original = [chain](int _pthis)
int origresult = 0; // return by call original function {
return chain->callNext();
};
if (callForward_Pre(RH_CBasePlayer_ObjectCaps, pthis->entindex())) { return callForward<int>(RH_CBasePlayer_ObjectCaps, original, 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;
} }
int CBasePlayer_Classify(IReGameHook_CBasePlayer_Classify *chain, CBasePlayer *pthis) int CBasePlayer_Classify(IReGameHook_CBasePlayer_Classify *chain, CBasePlayer *pthis)
{ {
//int ownresult = 0; // return own for OVERRIDE auto original = [chain](int _pthis)
int origresult = 0; // return by call original function {
return chain->callNext();
};
if (callForward_Pre(RH_CBasePlayer_Classify, pthis->entindex())) { return callForward<int>(RH_CBasePlayer_Classify, original, 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;
} }
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)) { Vector vecDirCopy(vecDir);
chain->callNext(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
}
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 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 auto original = [chain](int _pthis, int _pevInflictor, int _pevAttacker, float _flDamage, int _bitsDamageType)
int origresult = 0; // return by call original function {
return chain->callNext(PEV(_pevInflictor), PEV(_pevAttacker), _flDamage, _bitsDamageType);
};
if (callForward_Pre(RH_CBasePlayer_TakeDamage, pthis->entindex(), ENTINDEX(pevInflictor), ENTINDEX(pevAttacker), flDamage, bitsDamageType)) { return callForward<int>(RH_CBasePlayer_TakeDamage, original, pthis->entindex(), indexOfEdict(pevInflictor), indexOfEdict(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;
} }
int CBasePlayer_TakeHealth(IReGameHook_CBasePlayer_TakeHealth *chain, CBasePlayer *pthis, float flHealth, int bitsDamageType) int CBasePlayer_TakeHealth(IReGameHook_CBasePlayer_TakeHealth *chain, CBasePlayer *pthis, float flHealth, int bitsDamageType)
{ {
//int ownresult = 0; // return own for OVERRIDE auto original = [chain](int _pthis, float _flHealth, int _bitsDamageType)
int origresult = 0; // return by call original function {
return chain->callNext(_flHealth, _bitsDamageType);
};
if (callForward_Pre(RH_CBasePlayer_TakeHealth, pthis->entindex(), flHealth, bitsDamageType)) { return callForward<int>(RH_CBasePlayer_TakeHealth, original, 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;
} }
void CBasePlayer_Killed(IReGameHook_CBasePlayer_Killed *chain, CBasePlayer *pthis, entvars_t *pevAttacker, int iGib) 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)) { auto original = [chain](int _pthis, int _pevAttacker, int _iGib)
chain->callNext(pevAttacker, 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) void CBasePlayer_AddPoints(IReGameHook_CBasePlayer_AddPoints *chain, CBasePlayer *pthis, int score, BOOL bAllowNegativeScore)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_AddPoints, pthis->entindex(), score, bAllowNegativeScore)) { auto original = [chain](int _pthis, int _score, BOOL _bAllowNegativeScore)
chain->callNext(score, 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) void CBasePlayer_AddPointsToTeam(IReGameHook_CBasePlayer_AddPointsToTeam *chain, CBasePlayer *pthis, int score, BOOL bAllowNegativeScore)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_AddPointsToTeam, pthis->entindex(), score, bAllowNegativeScore)) { auto original = [chain](int _pthis, int _score, BOOL _bAllowNegativeScore)
chain->callNext(score, 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 CBasePlayer_AddPlayerItem(IReGameHook_CBasePlayer_AddPlayerItem *chain, CBasePlayer *pthis, CBasePlayerItem *pItem)
{ {
//BOOL ownresult = 0; // return own for OVERRIDE auto original = [chain](int _pthis, int _pItem)
BOOL origresult = 0; // return by call original function {
return chain->callNext(getPrivate<CBasePlayerItem>(_pItem));
};
if (callForward_Pre(RH_CBasePlayer_AddPlayerItem, pthis->entindex(), pItem->entindex())) { return callForward<BOOL>(RH_CBasePlayer_AddPlayerItem, original, 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;
} }
BOOL CBasePlayer_RemovePlayerItem(IReGameHook_CBasePlayer_RemovePlayerItem *chain, CBasePlayer *pthis, CBasePlayerItem *pItem) BOOL CBasePlayer_RemovePlayerItem(IReGameHook_CBasePlayer_RemovePlayerItem *chain, CBasePlayer *pthis, CBasePlayerItem *pItem)
{ {
//BOOL ownresult = 0; // return own for OVERRIDE auto original = [chain](int _pthis, int _pItem)
BOOL origresult = 0; // return by call original function {
return chain->callNext(getPrivate<CBasePlayerItem>(_pItem));
};
if (callForward_Pre(RH_CBasePlayer_RemovePlayerItem, pthis->entindex(), pItem->entindex())) { return callForward<BOOL>(RH_CBasePlayer_RemovePlayerItem, original, 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;
} }
int CBasePlayer_GiveAmmo(IReGameHook_CBasePlayer_GiveAmmo *chain, CBasePlayer *pthis, int iAmount, char *szName, int iMax) int CBasePlayer_GiveAmmo(IReGameHook_CBasePlayer_GiveAmmo *chain, CBasePlayer *pthis, int iAmount, char *szName, int iMax)
{ {
//int ownresult = 0; // return own for OVERRIDE auto original = [chain](int _pthis, int _iAmount, char *_szName, int _iMax)
int origresult = 0; // return by call original function {
return chain->callNext(_iAmount, _szName, _iMax);
};
if (callForward_Pre(RH_CBasePlayer_GiveAmmo, pthis->entindex(), iAmount, szName, iMax)) { return callForward<int>(RH_CBasePlayer_GiveAmmo, original, 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;
} }
void CBasePlayer_ResetMaxSpeed(IReGameHook_CBasePlayer_ResetMaxSpeed *chain, CBasePlayer *pthis) void CBasePlayer_ResetMaxSpeed(IReGameHook_CBasePlayer_ResetMaxSpeed *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_ResetMaxSpeed, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); 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) void CBasePlayer_Jump(IReGameHook_CBasePlayer_Jump *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_Jump, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); 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) void CBasePlayer_Duck(IReGameHook_CBasePlayer_Duck *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_Duck, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); 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) void CBasePlayer_PreThink(IReGameHook_CBasePlayer_PreThink *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_PreThink, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); 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) void CBasePlayer_PostThink(IReGameHook_CBasePlayer_PostThink *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_PostThink, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); 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) void CBasePlayer_UpdateClientData(IReGameHook_CBasePlayer_UpdateClientData *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_UpdateClientData, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); 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) void CBasePlayer_ImpulseCommands(IReGameHook_CBasePlayer_ImpulseCommands *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_ImpulseCommands, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); chain->callNext();
} };
callVoidForward(RH_CBasePlayer_ImpulseCommands, original, pthis->entindex());
callVoidForward_Post(RH_CBasePlayer_ImpulseCommands, pthis->entindex());
} }
void CBasePlayer_RoundRespawn(IReGameHook_CBasePlayer_RoundRespawn *chain, CBasePlayer *pthis) void CBasePlayer_RoundRespawn(IReGameHook_CBasePlayer_RoundRespawn *chain, CBasePlayer *pthis)
{ {
if (callVoidForward_Pre(RH_CBasePlayer_RoundRespawn, pthis->entindex())) { auto original = [chain](int _pthis)
{
chain->callNext(); 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) 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)) { auto original = [chain](int _pthis, float _flUntilTime, float _flHoldTime, float _flFadeTime, int _iAlpha)
chain->callNext(flUntilTime, flHoldTime, flFadeTime, 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 *CBasePlayer_Observer_IsValidTarget(IReGameHook_CBasePlayer_Observer_IsValidTarget *chain, CBasePlayer *pthis, int iPlayerIndex, bool bSameTeam)
{ {
//CBaseEntity *ownresult = nullptr; // return own for OVERRIDE auto original = [chain](int _pthis, int _iPlayerIndex, bool _bSameTeam)
CBaseEntity *origresult = nullptr; // return by call original function {
return chain->callNext(_iPlayerIndex, _bSameTeam);
};
if (callForward_Pre(RH_CBasePlayer_Observer_IsValidTarget, pthis->entindex(), iPlayerIndex, bSameTeam)) { return callForward<CBaseEntity *>(RH_CBasePlayer_Observer_IsValidTarget, original, 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;
} }
int GetForceCamera(IReGameHook_GetForceCamera *chain, CBasePlayer *pObserver) int GetForceCamera(IReGameHook_GetForceCamera *chain, CBasePlayer *pObserver)
{ {
//int ownresult = 0; // return own for OVERRIDE auto original = [chain](int _pObserver)
int origresult = 0; // return by call original function {
return chain->callNext(getPrivate<CBasePlayer>(_pObserver));
};
if (callForward_Pre(RH_GetForceCamera, pObserver->entindex())) { return callForward<int>(RH_GetForceCamera, original, 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;
} }

View File

@ -1,119 +1,176 @@
#pragma once #pragma once
enum // hookchain return type
enum HookChainState
{ {
RH_UNSET = 0, HC_CONTINUE = 0,
RH_IGNORED, // plugin didn't take any action HC_OVERRIDE,
RH_HANDLED, // plugin did something, but real function should still be called HC_SUPERCEDE,
RH_OVERRIDE, // call real function, but use my return value HC_BREAK
RH_SUPERCEDE // skip real function; use my return value
}; };
// for hookchain return // api types
enum HookChainReturn enum AType : uint8
{ {
RHV_STRING = 0, ATYPE_INTEGER = 0,
RHV_FLOAT, ATYPE_FLOAT,
RHV_INTEGER, ATYPE_STRING,
RHV_CLASSPTR ATYPE_CLASSPTR
}; };
extern CHook *g_currentHookChain; struct retval_t
{
template <typename ...t_args> bool set;
inline bool callVoidForward_Pre(int func, t_args... args) 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> #define MAX_ARGS 10u
inline void callVoidForward_Post(int func, t_args... args)
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]; args_type[current] = getApiType(arg);
for (auto it = hook->post.begin(), end = hook->post.end(); it != end; ++it) if (sizeof...(args) && current + 1 < MAX_ARGS)
{ setupArgTypes<current + 1>(args_type, args...);
if ((*it)->GetState() == FSTATE_OK)
{
g_currentHookChain = (*it);
g_amxxapi.ExecuteForward((*it)->GetForwardID(), args...);
}
}
} }
template <typename t_chain, typename ...t_args> struct hookctx_t
inline void callVoidForward(t_chain chain, int func, t_args... args)
{ {
auto hook = hooklist[func]; template<typename ...t_args>
register int ret = RH_UNSET; hookctx_t(size_t count, size_t ptr, t_args... args)
for (auto it = hook->pre.begin(), end = hook->pre.end(); it != end; ++it)
{ {
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 (hc_state != HC_SUPERCEDE)
if (ret < RH_SUPERCEDE) original(args...);
{
chain->callNext(args...);
}
// Post for (auto& fwd : hook->post)
for (auto it = hook->post.begin(), end = hook->post.end(); it != end; ++it)
{ {
if ((*it)->GetState() == FSTATE_OK) if (fwd->GetState() == FSTATE_ENABLED)
{ {
g_currentHookChain = (*it); auto ret = g_amxxapi.ExecuteForward(fwd->m_forward, args...);
g_amxxapi.ExecuteForward((*it)->GetForwardID(), args...);
if (ret == HC_BREAK)
break;
} }
} }
g_hookCtx = nullptr;
} }
template <typename ...t_args> template <typename R, typename original_t, typename ...f_args>
inline bool callForward_Pre(int func, t_args... args) R callForward(int func, original_t original, f_args... args)
{ {
auto hook = hooklist[func]; hookctx_t hookCtx(sizeof...(args), size_t(&original) + sizeof(original), args...);
register int ret = RH_UNSET; hookCtx.retVal.set = false;
for (auto it = hook->pre.begin(), end = hook->pre.end(); it != end; ++it) 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 if (hc_state != HC_SUPERCEDE)
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 ((*it)->GetState() == FSTATE_OK) auto retVal = original(args...);
{
g_currentHookChain = (*it); if (hc_state != HC_OVERRIDE)
ret = g_amxxapi.ExecuteForward((*it)->GetForwardID(), args...); 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 g_hookCtx = nullptr;
return (ret < RH_OVERRIDE); return (R)hookCtx.retVal._interger;
} }
// rehlds functions // rehlds functions
@ -130,7 +187,7 @@ void CBasePlayer_Spawn(IReGameHook_CBasePlayer_Spawn *chain, CBasePlayer *pthis)
void CBasePlayer_Precache(IReGameHook_CBasePlayer_Precache *chain, CBasePlayer *pthis); void CBasePlayer_Precache(IReGameHook_CBasePlayer_Precache *chain, CBasePlayer *pthis);
int CBasePlayer_ObjectCaps(IReGameHook_CBasePlayer_ObjectCaps *chain, CBasePlayer *pthis); int CBasePlayer_ObjectCaps(IReGameHook_CBasePlayer_ObjectCaps *chain, CBasePlayer *pthis);
int CBasePlayer_Classify(IReGameHook_CBasePlayer_Classify *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_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); 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); void CBasePlayer_Killed(IReGameHook_CBasePlayer_Killed *chain, CBasePlayer *pthis, entvars_t *pevAttacker, int iGib);

View File

@ -41,14 +41,12 @@ hook_t hooklist_player[] = {
DLL(CBasePlayer_Observer_IsValidTarget), DLL(CBasePlayer_Observer_IsValidTarget),
}; };
hooklist_t hooklist;
hook_t *hooklist_t::operator[](size_t hook) const 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; #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 table = hooks_tables_e(hook / MAX_REGION_RANGE);
const auto index = hook & (MAX_RANGE_REGION - 1); const auto index = hook & (MAX_REGION_RANGE - 1);
switch (table) { switch (table) {
CASE(engine) CASE(engine)

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "reapi_utils.h"
#define MAX_RANGE_REGION 1024 #define MAX_REGION_RANGE 1024
#define BEGIN_FUNC_REGION(x) (MAX_RANGE_REGION * hooklist_t::hooks_tables_e::ht_##x) #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 bool (*ablfunc_t)();
typedef int (*regfunc_t)(AMX *, const char *); typedef int (*regfunc_t)(AMX *, const char *);
@ -36,7 +36,7 @@ struct regfunc
} }
template<typename T, typename R> 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); }; 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 struct hook_t
{ {
std::vector<class CHook *> pre; // array pre forward std::vector<class CAmxxHook *> pre; // pre forwards
std::vector<class CHook *> post; // array post forward 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 const char *depend_name; // platform dependency
ablfunc_t availableFunc; ablfunc_t checkRequirements;
regfunc_t registerForward; // register AMXX forward and get ID regfunc_t registerForward; // AMXX forward registration function
regchain_t registerHookchain; // register function-hook API regchain_t registerHookchain; // register re* API hook
regchain_t unregisterHookchain; // unregister function-hook API regchain_t unregisterHookchain; // unregister re* API hook
}; };
struct hooklist_t struct hooklist_t
@ -200,4 +200,3 @@ enum GamedllFunc_CBasePlayer
extern hook_t hooklist_engine[]; extern hook_t hooklist_engine[];
extern hook_t hooklist_player[]; extern hook_t hooklist_player[];
extern hooklist_t hooklist;

View File

@ -2,39 +2,67 @@
CHookManager g_hookManager; 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 // API hookchain
hooklist[func]->registerHookchain(); m_hooklist[func]->registerHookchain();
} }
CHook *hook = new CHook(forward); auto& dest = post ? m_hooklist[func]->post : m_hooklist[func]->pre;
if (post) dest.push_back(new CAmxxHook(amx, forward));
{ int id = func * MAX_HOOK_FORWARDS + dest.size();
hooklist[func]->post.push_back(hook); return post ? -id : id; // use unsigned ids for post hooks
}
else
{
hooklist[func]->pre.push_back(hook);
}
return hook;
} }
void CHookManager::clearHandlers() AMX* CAmxxHook::GetAmx() const
{
return m_amx;
}
void CHookManager::clearHandlers() const
{ {
#define CLEAR_HOOKLIST(__END__, __START__)\ #define CLEAR_HOOKLIST(__END__, __START__)\
for (size_t i = BEGIN_FUNC_REGION(__START__); i < RH_##__END__##_End; ++i) {\ for (size_t i = BEGIN_FUNC_REGION(__START__); i < RH_##__END__##_End; ++i) {\
if (hooklist[i] == nullptr)\ if (m_hooklist[i] == nullptr)\
continue;\ continue;\
hooklist[i]->pre.clear();\ m_hooklist[i]->pre.clear();\
hooklist[i]->post.clear();\ m_hooklist[i]->post.clear();\
hooklist[i]->unregisterHookchain();\ m_hooklist[i]->unregisterHookchain();\
} }
CLEAR_HOOKLIST(EngineFunc, engine); CLEAR_HOOKLIST(EngineFunc, engine);
CLEAR_HOOKLIST(GameDLL, gamedll); CLEAR_HOOKLIST(GameDLL, gamedll);
CLEAR_HOOKLIST(CBasePlayer, player); 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;
}

View File

@ -6,38 +6,36 @@
enum fwdstate enum fwdstate
{ {
FSTATE_INVALID = 0, FSTATE_INVALID = 0,
FSTATE_OK, FSTATE_ENABLED,
FSTATE_PAUSE, FSTATE_PAUSED,
FSTATE_STOP FSTATE_STOPPED
}; };
class CHook class CAmxxHook
{ {
public: 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; } int GetForwardID() const { return m_forward; }
fwdstate GetState() const { return m_state; } fwdstate GetState() const { return m_state; }
AMX* GetAmx() const;
public: public:
int m_forward; int m_forward;
fwdstate m_state; fwdstate m_state;
AMX* m_amx;
struct data_return_t
{
char* m_string;
float m_float;
int m_interger;
CBaseEntity* m_classptr;
};
data_return_t m_data;
}; };
class CHookManager class CHookManager
{ {
public: public:
void clearHandlers(); void clearHandlers() const;
CHook *addHandler(int func, int forward, bool post); 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; extern CHookManager g_hookManager;

View File

@ -1,5 +1,7 @@
#include "precompiled.h" #include "precompiled.h"
edict_t* g_pEdicts;
bool OnMetaAttach() bool OnMetaAttach()
{ {
// initialize API // initialize API
@ -15,7 +17,14 @@ void OnMetaDetach()
g_hookManager.clearHandlers(); g_hookManager.clearHandlers();
} }
void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax)
{
g_pEdicts = pEdictList;
RETURN_META(MRES_IGNORED);
}
void ServerDeactivate_Post() void ServerDeactivate_Post()
{ {
g_hookManager.clearHandlers(); g_hookManager.clearHandlers();
RETURN_META(MRES_IGNORED);
} }

View File

@ -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; #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 table = members_tables_e(members / MAX_REGION_RANGE);
const auto index = members & (MAX_RANGE_REGION - 1); const auto index = members & (MAX_REGION_RANGE - 1);
switch (table) { switch (table) {
CASE(gamerules) CASE(gamerules)

View File

@ -1,6 +1,6 @@
#pragma once #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 enum enum_membertypes
{ {

View File

@ -7,7 +7,7 @@
* @param function The function to hook. * @param function The function to hook.
* @param callback The forward to call. * @param callback The forward to call.
* @param post Whether or not to forward this in post. * @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); * 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 func = params[arg_func];
int post = params[arg_post]; 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; 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; 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); const char *funcname = g_amxxapi.GetAmxString(amx, params[arg_handler], 0, &len);
if (g_amxxapi.amx_FindPublic(amx, funcname, &funcid) != AMX_ERR_NONE) 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; return 0;
} }
int fwid = hooklist[func]->registerForward(amx, funcname); int fwid = hook->registerForward(amx, funcname);
if (fwid == -1) 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 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! * Use the return value from RegisterHookChain as the parameter here!
* *
* @param fwd The hook to re-enable. * @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); * 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 }; 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) if (hook == nullptr)
{ {
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid HookChain handle."); MF_LogError(amx, AMX_ERR_NATIVE, "EnableHookChain: invalid HookChain handle.");
return 0; return 0;
} }
hook->m_state = FSTATE_OK; hook->m_state = FSTATE_ENABLED;
return 1; return 1;
} }
/* /*
* Stops a hook from triggering. * Enable hook by handle.
* Use the return value from RegisterHookChain as the parameter here! * Use the return value from RegisterHookChain as the parameter here!
* *
* @param fwd The hook to stop. * @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 }; 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) if (hook == nullptr)
{ {
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid HookChain handle."); MF_LogError(amx, AMX_ERR_NATIVE, "DisableHookChain: invalid HookChain handle.");
return 0; return 0;
} }
hook->m_state = FSTATE_STOP; hook->m_state = FSTATE_STOPPED;
return 1; return 1;
} }
@ -104,49 +105,164 @@ static cell AMX_NATIVE_CALL DisableHookChain(AMX *amx, cell *params)
* Sets the return value of a hookchain. * Sets the return value of a hookchain.
* This needs to be used in conjunction with RH_OVERRIDE or RH_SUPERCEDE. * 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. * @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) 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; return 0;
} }
enum args_e { arg_count, arg_type, arg_value }; 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: MF_LogError(amx, AMX_ERR_NATIVE, "Trying to set incompatible return type.");
{ return 0;
if (g_currentHookChain->m_data.m_string != NULL) { }
delete [] g_currentHookChain->m_data.m_string;
}
int len; cell* srcAddr = getAmxAddr(amx, params[arg_value]);
char *dest = g_amxxapi.GetAmxString(amx, params[arg_value], 0, &len);
g_currentHookChain->m_data.m_string = new char [len + 1]; switch (retVal.type)
strcpy(g_currentHookChain->m_data.m_string, dest); {
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; break;
} }
case RHV_FLOAT: case ATYPE_CLASSPTR:
g_currentHookChain->m_data.m_float = *(float *)g_amxxapi.GetAmxAddr(amx, params[arg_value]); retVal._classptr = CBaseEntity::Instance(INDEXENT(*srcAddr));
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])));
break; break;
default: default:
return 0; 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; return 1;
} }
@ -158,6 +274,9 @@ AMX_NATIVE_INFO Func_Natives[] =
{ "DisableHookChain", DisableHookChain }, { "DisableHookChain", DisableHookChain },
{ "SetHookChainReturn", SetHookChainReturn }, { "SetHookChainReturn", SetHookChainReturn },
{ "GetHookChainReturn", GetHookChainReturn },
{ "SetHookChainArg", SetHookChainArg },
{ nullptr, nullptr } { nullptr, nullptr }
}; };

View File

@ -7,17 +7,18 @@ static cell AMX_NATIVE_CALL set_member(AMX *amx, cell *params)
member_t *member = memberlist[params[arg_member]]; member_t *member = memberlist[params[arg_member]];
if (member == nullptr) { 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; return 0;
} }
edict_t *pEdict = INDEXENT(params[arg_index]); edict_t *pEdict = INDEXENT(params[arg_index]);
if (pEdict == nullptr || pEdict->pvPrivateData == nullptr) { if (pEdict == nullptr || pEdict->pvPrivateData == nullptr) {
MF_LogError(amx, AMX_ERR_NATIVE, "set_member: invalid or uninitialized entity", params[arg_member]);
return 0; return 0;
} }
size_t value = *g_amxxapi.GetAmxAddr(amx, params[arg_value]); size_t value = *getAmxAddr(amx, params[arg_value]);
size_t element = *g_amxxapi.GetAmxAddr(amx, params[arg_elem]); size_t element = *getAmxAddr(amx, params[arg_elem]);
switch (member->type) switch (member->type)
{ {
@ -122,6 +123,12 @@ static cell AMX_NATIVE_CALL set_member(AMX *amx, cell *params)
signal.Signal(value); signal.Signal(value);
return 1; 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: case MEBMER_REBUYSTRUCT:
return -1; 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); // native any:get_member(_index, any:_member, element);
edict_t *pEntity = get_member<edict_t *>(pEdict, member->offset, element); edict_t *pEntity = get_member<edict_t *>(pEdict, member->offset, element);
if (pEntity != nullptr) { if (pEntity != nullptr) {
return ENTINDEX(pEntity); return indexOfEdict(pEntity);
} }
return 0; return 0;

View File

@ -10,6 +10,7 @@
#include <vector> // std::vector #include <vector> // std::vector
#include <extdll.h> #include <extdll.h>
#include "reapi_utils.h"
#include <cbase.h> #include <cbase.h>
#include "osdep.h" // win32 vsnprintf, etc #include "osdep.h" // win32 vsnprintf, etc

View File

@ -4,6 +4,37 @@ template <typename T, size_t N>
char(&ArraySizeHelper(T(&array)[N]))[N]; char(&ArraySizeHelper(T(&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array))) #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 // HLTypeConversion.h -> AMXModX
template <typename T> template <typename T>
inline T &ref_member(void *ptr, int offset, int element = 0) inline T &ref_member(void *ptr, int offset, int element = 0)