2
0
mirror of https://github.com/rehlds/reapi.git synced 2025-02-05 10:10:38 +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_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;
}
}

View File

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

View File

@ -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:

View File

@ -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>

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);
}
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*/ );
#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__

View File

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

View File

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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -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
{

View File

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

View File

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

View File

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

View File

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