diff --git a/reapi/extra/amxmodx/scripting/include/reapi.inc b/reapi/extra/amxmodx/scripting/include/reapi.inc index e356092..9679d9a 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi.inc @@ -17,22 +17,27 @@ #include // NOTE: only for ReHLDS #include // 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; } } diff --git a/reapi/include/cssdk/dlls/regamedll_api.h b/reapi/include/cssdk/dlls/regamedll_api.h index 19ec58d..18a01bc 100644 --- a/reapi/include/cssdk/dlls/regamedll_api.h +++ b/reapi/include/cssdk/dlls/regamedll_api.h @@ -51,8 +51,8 @@ typedef IHookChain IReGameHook_CBasePlayer_Classify; typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Classify; // CBasePlayer::TraceAttack hook -typedef IVoidHookChain IReGameHook_CBasePlayer_TraceAttack; -typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_TraceAttack; +typedef IVoidHookChain IReGameHook_CBasePlayer_TraceAttack; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_TraceAttack; // CBasePlayer::TakeDamage hook typedef IHookChain IReGameHook_CBasePlayer_TakeDamage; diff --git a/reapi/include/cssdk/public/interface.h b/reapi/include/cssdk/public/interface.h index 3349146..c9ce2e6 100644 --- a/reapi/include/cssdk/public/interface.h +++ b/reapi/include/cssdk/public/interface.h @@ -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: diff --git a/reapi/msvc/reapi.vcxproj b/reapi/msvc/reapi.vcxproj index c436554..237f36e 100644 --- a/reapi/msvc/reapi.vcxproj +++ b/reapi/msvc/reapi.vcxproj @@ -358,6 +358,9 @@ AnySuitable Speed false + true + Sync + true Windows diff --git a/reapi/src/amxxmodule.cpp b/reapi/src/amxxmodule.cpp index 3d4ba88..9e3a74d 100644 --- a/reapi/src/amxxmodule.cpp +++ b/reapi/src/amxxmodule.cpp @@ -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; +} diff --git a/reapi/src/amxxmodule.h b/reapi/src/amxxmodule.h index 4104759..320d44e 100644 --- a/reapi/src/amxxmodule.h +++ b/reapi/src/amxxmodule.h @@ -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__ \ No newline at end of file diff --git a/reapi/src/api_config.cpp b/reapi/src/api_config.cpp index bded18e..f82d916 100644 --- a/reapi/src/api_config.cpp +++ b/reapi/src/api_config.cpp @@ -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(); diff --git a/reapi/src/api_config.h b/reapi/src/api_config.h index 204403e..9ef05bd 100644 --- a/reapi/src/api_config.h +++ b/reapi/src/api_config.h @@ -5,6 +5,7 @@ class CAPI_Config { public: + CAPI_Config(); bool Init(); bool hasReHLDS() const { return m_api_rehlds; } diff --git a/reapi/src/dllapi.cpp b/reapi/src/dllapi.cpp index 8b9325a..748c27e 100644 --- a/reapi/src/dllapi.cpp +++ b/reapi/src/dllapi.cpp @@ -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 diff --git a/reapi/src/hook_callback.cpp b/reapi/src/hook_callback.cpp index a76a784..9194d04 100644 --- a/reapi/src/hook_callback.cpp +++ b/reapi/src/hook_callback.cpp @@ -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(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(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(&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(&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(&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(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(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(_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(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(_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(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(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(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(_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(RH_GetForceCamera, original, pObserver->entindex()); } diff --git a/reapi/src/hook_callback.h b/reapi/src/hook_callback.h index f65ca9d..28f8b96 100644 --- a/reapi/src/hook_callback.h +++ b/reapi/src/hook_callback.h @@ -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 -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 +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 -inline void callVoidForward_Post(int func, t_args... args) +#define MAX_ARGS 10u + +template +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(args_type, args...); } -template -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 + 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 +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 -inline bool callForward_Pre(int func, t_args... args) +template +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 -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); diff --git a/reapi/src/hook_list.cpp b/reapi/src/hook_list.cpp index 1c13d4c..cd5000d 100644 --- a/reapi/src/hook_list.cpp +++ b/reapi/src/hook_list.cpp @@ -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) diff --git a/reapi/src/hook_list.h b/reapi/src/hook_list.h index 559ad42..5df7ecf 100644 --- a/reapi/src/hook_list.h +++ b/reapi/src/hook_list.h @@ -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 - 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 pre; // array pre forward - std::vector post; // array post forward + std::vector pre; // pre forwards + std::vector 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; diff --git a/reapi/src/hook_manager.cpp b/reapi/src/hook_manager.cpp index bee7eca..6296562 100644 --- a/reapi/src/hook_manager.cpp +++ b/reapi/src/hook_manager.cpp @@ -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; +} diff --git a/reapi/src/hook_manager.h b/reapi/src/hook_manager.h index 571a2a4..7a31d80 100644 --- a/reapi/src/hook_manager.h +++ b/reapi/src/hook_manager.h @@ -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; diff --git a/reapi/src/main.cpp b/reapi/src/main.cpp index eb40833..c57e893 100644 --- a/reapi/src/main.cpp +++ b/reapi/src/main.cpp @@ -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); } diff --git a/reapi/src/member_list.cpp b/reapi/src/member_list.cpp index ba1e7f7..798c932 100644 --- a/reapi/src/member_list.cpp +++ b/reapi/src/member_list.cpp @@ -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) diff --git a/reapi/src/member_list.h b/reapi/src/member_list.h index 050266c..70c51ec 100644 --- a/reapi/src/member_list.h +++ b/reapi/src/member_list.h @@ -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 { diff --git a/reapi/src/natives.cpp b/reapi/src/natives.cpp index 5fbc443..b9ac847 100644 --- a/reapi/src/natives.cpp +++ b/reapi/src/natives.cpp @@ -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(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(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 } }; diff --git a/reapi/src/natives_member.cpp b/reapi/src/natives_member.cpp index e237957..f75a984 100644 --- a/reapi/src/natives_member.cpp +++ b/reapi/src/natives_member.cpp @@ -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(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(pEdict, member->offset, element); if (pEntity != nullptr) { - return ENTINDEX(pEntity); + return indexOfEdict(pEntity); } return 0; diff --git a/reapi/src/precompiled.h b/reapi/src/precompiled.h index 9d704cf..19363c9 100644 --- a/reapi/src/precompiled.h +++ b/reapi/src/precompiled.h @@ -10,6 +10,7 @@ #include // std::vector #include +#include "reapi_utils.h" #include #include "osdep.h" // win32 vsnprintf, etc diff --git a/reapi/src/reapi_utils.h b/reapi/src/reapi_utils.h index 7523b4a..acd8882 100644 --- a/reapi/src/reapi_utils.h +++ b/reapi/src/reapi_utils.h @@ -4,6 +4,37 @@ template 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 +T* getPrivate(int index) +{ + return (T *)edictByIndex(index)->pvPrivateData; +} + +inline entvars_t* PEV(int index) +{ + return &edictByIndex(index)->v; +} + // HLTypeConversion.h -> AMXModX template inline T &ref_member(void *ptr, int offset, int element = 0)