From 97aea0f39712b337e7bf2ad4fea9a12ac753534e Mon Sep 17 00:00:00 2001 From: FEDERICOMB <41979395+FEDERICOMB96@users.noreply.github.com> Date: Sun, 1 Aug 2021 05:44:46 -0300 Subject: [PATCH] Implement `CBaseEntity::Fire` hooks. (#202) * Implement "CBaseEntity::Fire" hooks. * Added new hook table "GamedllFunc_CBaseEntity". * Added new hookchain argument type "ATYPE_VECTOR" * Added ATYPE_VECTOR case in Get|Set natives * Added ATYPE_VECTOR in SetHookChainArg native --- .../extra/amxmodx/scripting/include/reapi.inc | 8 ++-- .../scripting/include/reapi_gamedll_const.inc | 28 +++++++++++++ reapi/include/cssdk/dlls/regamedll_api.h | 17 ++++++++ reapi/src/hook_callback.cpp | 42 +++++++++++++++++++ reapi/src/hook_callback.h | 31 ++++++++++---- reapi/src/hook_list.cpp | 9 ++++ reapi/src/hook_list.h | 12 ++++++ reapi/src/natives/natives_hookchains.cpp | 23 +++++++--- reapi/src/natives/natives_hookchains.h | 15 +++++++ reapi/src/natives/natives_misc.cpp | 2 +- reapi/src/reapi_utils.cpp | 3 +- 11 files changed, 172 insertions(+), 18 deletions(-) diff --git a/reapi/extra/amxmodx/scripting/include/reapi.inc b/reapi/extra/amxmodx/scripting/include/reapi.inc index 86755b8..4533825 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi.inc @@ -24,7 +24,8 @@ enum hooks_tables_e ht_grenade, ht_weaponbox, ht_weapon, - ht_gib + ht_gib, + ht_cbaseentity }; enum members_tables_e @@ -128,7 +129,8 @@ enum AType ATYPE_CLASSPTR, ATYPE_EDICT, ATYPE_EVARS, - ATYPE_BOOL + ATYPE_BOOL, + ATYPE_VECTOR }; enum HookChain @@ -146,7 +148,7 @@ enum HookChain * * @return Returns a hook handle. Use EnableHookChain/DisableHookChain to toggle the forward on or off */ -native HookChain:RegisterHookChain({EngineFunc, GamedllFunc, GamedllFunc_CBaseAnimating, GamedllFunc_CBasePlayer, GamedllFunc_CSGameRules, GamedllFunc_CGrenade, GamedllFunc_CWeaponBox, ReCheckerFunc, GamedllFunc_CBasePlayerWeapon, GamedllFunc_CGib}:function_id, const callback[], post = 0); +native HookChain:RegisterHookChain({EngineFunc, GamedllFunc, GamedllFunc_CBaseAnimating, GamedllFunc_CBasePlayer, GamedllFunc_CSGameRules, GamedllFunc_CGrenade, GamedllFunc_CWeaponBox, ReCheckerFunc, GamedllFunc_CBasePlayerWeapon, GamedllFunc_CGib, GamedllFunc_CBaseEntity}:function_id, const callback[], post = 0); /* * Stops a hook from triggering. diff --git a/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc b/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc index 0afc09d..d31c51c 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc @@ -844,6 +844,34 @@ enum GamedllFunc_CGib RG_CGib_WaitTillLand, }; +/** +* GamedllFunc CBaseEntity +*/ +enum GamedllFunc_CBaseEntity +{ + /* + * Description: - + * Return type: void + * Params: (pEntity, cShots, Float:vecSrc[3], Float:vecDirShooting[3], Float:vecSpread[3], Float:flDistance, iBulletType, iTracerFreq, iDamage, pevAttacker) + + */ + RG_CBaseEntity_FireBullets = BEGIN_FUNC_REGION(cbaseentity), + + /* + * Description: - + * Return type: void + * Params: (pEntity, cShots, Float:vecSrc[3], Float:vecDirShooting[3], Float:vecSpread[3], Float:flDistance, iTracerFreq, iDamage, pevAttacker) + */ + RG_CBaseEntity_FireBuckshots, + + /* + * Description: - + * Return type: Vector [3] + * Params: (pEntity, Float:vecSrc[3], Float:vecDirShooting[3], Float:vecSpread, Float:flDistance, iPenetration, iBulletType, iDamage, Float:flRangeModifier, pevAttacker, bool:bPistol, shared_rand) + */ + RG_CBaseEntity_FireBullets3, +}; + /** * GamedllFunc CSGameRules */ diff --git a/reapi/include/cssdk/dlls/regamedll_api.h b/reapi/include/cssdk/dlls/regamedll_api.h index e3af302..a3597c8 100644 --- a/reapi/include/cssdk/dlls/regamedll_api.h +++ b/reapi/include/cssdk/dlls/regamedll_api.h @@ -489,6 +489,19 @@ typedef IHookChainRegistryClass IReGameHookRegi typedef IHookChainClass IReGameHook_CGib_WaitTillLand; typedef IHookChainRegistryClass IReGameHookRegistry_CGib_WaitTillLand; +// CBaseEntity::FireBullets hook +typedef IHookChainClass IReGameHook_CBaseEntity_FireBullets; +typedef IHookChainRegistryClass IReGameHookRegistry_CBaseEntity_FireBullets; + +// CBaseEntity::FireBuckshots hook +typedef IHookChainClass IReGameHook_CBaseEntity_FireBuckshots; +typedef IHookChainRegistryClass IReGameHookRegistry_CBaseEntity_FireBuckshots; + +// CBaseEntity::FireBullets3 hook +typedef IHookChainClass IReGameHook_CBaseEntity_FireBullets3; +typedef IHookChainRegistryClass IReGameHookRegistry_CBaseEntity_FireBullets3; + + class IReGameHookchains { public: virtual ~IReGameHookchains() {} @@ -611,6 +624,10 @@ public: virtual IReGameHookRegistry_CGib_Spawn *CGib_Spawn() = 0; virtual IReGameHookRegistry_CGib_BounceGibTouch *CGib_BounceGibTouch() = 0; virtual IReGameHookRegistry_CGib_WaitTillLand *CGib_WaitTillLand() = 0; + + virtual IReGameHookRegistry_CBaseEntity_FireBullets *CBaseEntity_FireBullets() = 0; + virtual IReGameHookRegistry_CBaseEntity_FireBuckshots *CBaseEntity_FireBuckshots() = 0; + virtual IReGameHookRegistry_CBaseEntity_FireBullets3 *CBaseEntity_FireBullets3() = 0; }; struct ReGameFuncs_t { diff --git a/reapi/src/hook_callback.cpp b/reapi/src/hook_callback.cpp index 4ca6a0a..1307ffb 100644 --- a/reapi/src/hook_callback.cpp +++ b/reapi/src/hook_callback.cpp @@ -1165,6 +1165,48 @@ void CGib_WaitTillLand(IReGameHook_CGib_WaitTillLand *chain, CGib *pthis) callVoidForward(RG_CGib_WaitTillLand, original, indexOfEdict(pthis->pev)); } +void CBaseEntity_FireBullets(IReGameHook_CBaseEntity_FireBullets *chain, CBaseEntity *pEntity, ULONG cShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker) +{ + Vector vecSrcCopy(vecSrc), vecDirShootingCopy(vecDirShooting), vecSpreadCopy(vecSpread); + + auto original = [chain, &vecSrcCopy, &vecDirShootingCopy, &vecSpreadCopy](int _pEntity, ULONG _cShots, cell _vecSrc, cell _vecDirShooting, cell _vecSpread, float _flDistance, int _iBulletType, int _iTracerFreq, int _iDamage, int _pevAttacker) + { + chain->callNext(getPrivate(_pEntity), _cShots, vecSrcCopy, vecDirShootingCopy, vecSpreadCopy, _flDistance, _iBulletType, _iTracerFreq, _iDamage, PEV(_pevAttacker)); + }; + + callVoidForward(RG_CBaseEntity_FireBullets, original, indexOfEdict(pEntity->pev), cShots, getAmxVector(vecSrcCopy), getAmxVector(vecDirShootingCopy), getAmxVector(vecSpreadCopy), flDistance, iBulletType, iTracerFreq, iDamage, indexOfEdict(pevAttacker)); +} + +void CBaseEntity_FireBuckshots(IReGameHook_CBaseEntity_FireBuckshots *chain, CBaseEntity *pEntity, ULONG cShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iTracerFreq, int iDamage, entvars_t *pevAttacker) +{ + Vector vecSrcCopy(vecSrc), vecDirShootingCopy(vecDirShooting), vecSpreadCopy(vecSpread); + + auto original = [chain, &vecSrcCopy, &vecDirShootingCopy, &vecSpreadCopy](int _pEntity, ULONG _cShots, cell _vecSrc, cell _vecDirShooting, cell _vecSpread, float _flDistance, int _iTracerFreq, int _iDamage, int _pevAttacker) + { + chain->callNext(getPrivate(_pEntity), _cShots, vecSrcCopy, vecDirShootingCopy, vecSpreadCopy, _flDistance, _iTracerFreq, _iDamage, PEV(_pevAttacker)); + }; + + callVoidForward(RG_CBaseEntity_FireBuckshots, original, indexOfEdict(pEntity->pev), cShots, getAmxVector(vecSrcCopy), getAmxVector(vecDirShootingCopy), getAmxVector(vecSpreadCopy), flDistance, iTracerFreq, iDamage, indexOfEdict(pevAttacker)); +} + +Vector &CBaseEntity_FireBullets3(IReGameHook_CBaseEntity_FireBullets3 *chain, CBaseEntity *pEntity, Vector &vecSrc, Vector &vecDirShooting, float vecSpread, float flDistance, int iPenetration, int iBulletType, int iDamage, float flRangeModifier, entvars_t *pevAttacker, bool bPistol, int shared_rand) +{ + Vector vecSrcCopy(vecSrc), vecDirShootingCopy(vecDirShooting); + + auto original = [chain, &vecSrcCopy, &vecDirShootingCopy](int _pEntity, cell _vecSrc, cell _vecDirShooting, float _vecSpread, float _flDistance, int _iPenetration, int _iBulletType, int _iDamage, float _flRangeModifier, int _pevAttacker, bool _bPistol, int _shared_rand) -> Vector& + { + return chain->callNext(getPrivate(_pEntity), vecSrcCopy, vecDirShootingCopy, _vecSpread, _flDistance, _iPenetration, _iBulletType, _iDamage, _flRangeModifier, PEV(_pevAttacker), _bPistol, _shared_rand); + }; + + return callForward(RG_CBaseEntity_FireBullets3, original, + indexOfEdict(pEntity->pev), + getAmxVector(vecSrcCopy), getAmxVector(vecDirShootingCopy), + vecSpread, flDistance, iPenetration, iBulletType, iDamage, flRangeModifier, + indexOfEdict(pevAttacker), + bPistol, + shared_rand); +} + int g_iClientStartSpeak, g_iClientStopSpeak; void OnClientStartSpeak(size_t clientIndex) diff --git a/reapi/src/hook_callback.h b/reapi/src/hook_callback.h index e329529..32e1182 100644 --- a/reapi/src/hook_callback.h +++ b/reapi/src/hook_callback.h @@ -20,7 +20,8 @@ enum AType : uint8 ATYPE_CLASSPTR, ATYPE_EDICT, ATYPE_EVARS, - ATYPE_BOOL + ATYPE_BOOL, + ATYPE_VECTOR }; struct retval_t @@ -36,11 +37,13 @@ struct retval_t CBaseEntity* _classptr; edict_t* _edict; entvars_t* _pev; + Vector* _vector; }; }; inline AType getApiType(int) { return ATYPE_INTEGER; } inline AType getApiType(unsigned) { return ATYPE_INTEGER; } +inline AType getApiType(ULONG) { return ATYPE_INTEGER; } inline AType getApiType(float) { return ATYPE_FLOAT; } inline AType getApiType(const char *) { return ATYPE_STRING; } inline AType getApiType(char[]) { return ATYPE_STRING; } @@ -48,6 +51,7 @@ inline AType getApiType(CBaseEntity *) { return ATYPE_CLASSPTR; } inline AType getApiType(edict_t *) { return ATYPE_EDICT; } inline AType getApiType(entvars_t *) { return ATYPE_EVARS; } inline AType getApiType(bool) { return ATYPE_BOOL; } +inline AType getApiType(Vector) { return ATYPE_VECTOR; } template inline AType getApiType(T *) { return ATYPE_INTEGER; } @@ -214,8 +218,10 @@ void callVoidForward(size_t func, original_t original, f_args&&... args) template NOINLINE R DLLEXPORT _callForward(hook_t* hook, original_t original, f_args&&... args) { + using R2 = typename std::decay::type; + auto hookCtx = g_hookCtx; - hookCtx->reset(getApiType(R())); + hookCtx->reset(getApiType(R2())); int hc_state = HC_CONTINUE; @@ -239,7 +245,7 @@ NOINLINE R DLLEXPORT _callForward(hook_t* hook, original_t original, f_args&&... } if (unlikely(ret == HC_BREAK)) { - return *(R *)&hookCtx->retVal._integer; + return *(R2 *)&hookCtx->retVal._integer; } if (unlikely(ret > hc_state)) @@ -250,7 +256,7 @@ NOINLINE R DLLEXPORT _callForward(hook_t* hook, original_t original, f_args&&... if (likely(hc_state != HC_SUPERCEDE)) { g_hookCtx = nullptr; - auto retVal = original(std::forward(args)...); + R retVal = original(std::forward(args)...); g_hookCtx = hookCtx; hook->wasCalled = true; @@ -265,6 +271,9 @@ NOINLINE R DLLEXPORT _callForward(hook_t* hook, original_t original, f_args&&... case sizeof(int32): hookCtx->retVal._integer = *(int32 *)&retVal; break; + case sizeof(Vector): + hookCtx->retVal._vector = (Vector *)&retVal; + break; } hookCtx->retVal.set = true; } @@ -285,19 +294,20 @@ NOINLINE R DLLEXPORT _callForward(hook_t* hook, original_t original, f_args&&... hook->wasCalled = false; - return *(R *)&hookCtx->retVal._integer; + if (std::is_reference::value) + return *(R2 *)hookCtx->retVal._integer; + else + return *(R2 *)&hookCtx->retVal._integer; } template R callForward(size_t func, original_t original, f_args&&... args) { - static_assert(sizeof(R) <= sizeof(int), "invalid hookchain return type size > sizeof(int)"); - hookctx_t hookCtx(sizeof...(args), args...); hookctx_t* save = g_hookCtx; g_hookCtx = &hookCtx; - auto ret = _callForward(g_hookManager.getHookFast(func), original, args...); + R ret = _callForward(g_hookManager.getHookFast(func), original, args...); g_hookCtx = save; if (hasStringArgs(args...)) { @@ -465,6 +475,11 @@ void CGib_Spawn(IReGameHook_CGib_Spawn *chain, CGib *pthis, const char *szGibMod void CGib_BounceGibTouch(IReGameHook_CGib_BounceGibTouch *chain, CGib *pthis, CBaseEntity *pOther); void CGib_WaitTillLand(IReGameHook_CGib_WaitTillLand *chain, CGib *pthis); +// regamedll functions - cbaseentity +void CBaseEntity_FireBullets(IReGameHook_CBaseEntity_FireBullets *chain, CBaseEntity *pEntity, ULONG cShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker); +void CBaseEntity_FireBuckshots(IReGameHook_CBaseEntity_FireBuckshots *chain, CBaseEntity *pEntity, ULONG cShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iTracerFreq, int iDamage, entvars_t *pevAttacker); +Vector &CBaseEntity_FireBullets3(IReGameHook_CBaseEntity_FireBullets3 *chain, CBaseEntity *pEntity, Vector &vecSrc, Vector &vecDirShooting, float vecSpread, float flDistance, int iPenetration, int iBulletType, int iDamage, float flRangeModifier, entvars_t *pevAttacker, bool bPistol, int shared_rand); + extern int g_iClientStartSpeak; extern int g_iClientStopSpeak; diff --git a/reapi/src/hook_list.cpp b/reapi/src/hook_list.cpp index 568293e..ffbbe88 100644 --- a/reapi/src/hook_list.cpp +++ b/reapi/src/hook_list.cpp @@ -4,6 +4,7 @@ inline size_t getFwdParamType(void(*)(int)) { return FP_CELL inline size_t getFwdParamType(void(*)(size_t)) { return FP_CELL; } inline size_t getFwdParamType(void(*)(short)) { return FP_CELL; } inline size_t getFwdParamType(void(*)(unsigned short)) { return FP_CELL; } +inline size_t getFwdParamType(void(*)(ULONG)) { return FP_CELL; } inline size_t getFwdParamType(void(*)(bool)) { return FP_CELL; } inline size_t getFwdParamType(void(*)(Vector&)) { return FP_ARRAY; } inline size_t getFwdParamType(void(*)(TeamName)) { return FP_CELL; } @@ -221,6 +222,12 @@ hook_t hooklist_gib[] = { DLL(CGib_WaitTillLand), }; +hook_t hooklist_cbaseentity[] = { + DLL(CBaseEntity_FireBullets), + DLL(CBaseEntity_FireBuckshots), + DLL(CBaseEntity_FireBullets3), +}; + #define RCHECK(h,...) { {}, {}, #h, "ReChecker", [](){ return api_cfg.hasRechecker(); }, ((!(RC_##h & (MAX_REGION_RANGE - 1)) ? regfunc::current_cell = 1, true : false) || (RC_##h & (MAX_REGION_RANGE - 1)) == regfunc::current_cell++) ? regfunc(h##__VA_ARGS__) : regfunc(#h#__VA_ARGS__), [](){ g_RecheckerHookchains->h()->registerHook(&h); }, [](){ g_RecheckerHookchains->h()->unregisterHook(&h); }, false} hook_t hooklist_rechecker[] = { RCHECK(FileConsistencyProcess, _AMXX), @@ -246,6 +253,7 @@ hook_t* hooklist_t::getHookSafe(size_t hook) CASE(weaponbox) CASE(weapon) CASE(gib) + CASE(cbaseentity) } return nullptr; @@ -265,6 +273,7 @@ void hooklist_t::clear() FOREACH_CLEAR(weaponbox); FOREACH_CLEAR(weapon); FOREACH_CLEAR(gib); + FOREACH_CLEAR(cbaseentity); } void hook_t::clear() diff --git a/reapi/src/hook_list.h b/reapi/src/hook_list.h index 59cd4e6..0e4841f 100644 --- a/reapi/src/hook_list.h +++ b/reapi/src/hook_list.h @@ -37,6 +37,7 @@ extern hook_t hooklist_grenade[]; extern hook_t hooklist_weaponbox[]; extern hook_t hooklist_weapon[]; extern hook_t hooklist_gib[]; +extern hook_t hooklist_cbaseentity[]; enum { @@ -63,6 +64,7 @@ struct hooklist_t CASE(weaponbox) CASE(weapon) CASE(gib) + CASE(cbaseentity) } #undef CASE @@ -85,6 +87,7 @@ struct hooklist_t ht_weaponbox, ht_weapon, ht_gib, + ht_cbaseentity, }; }; @@ -262,6 +265,15 @@ enum GamedllFunc_CGib // [...] }; +enum GamedllFunc_CBaseEntity +{ + RG_CBaseEntity_FireBullets = BEGIN_FUNC_REGION(cbaseentity), + RG_CBaseEntity_FireBuckshots, + RG_CBaseEntity_FireBullets3, + + // [...] +}; + enum ReCheckerFunc { RC_FileConsistencyProcess = BEGIN_FUNC_REGION(rechecker), diff --git a/reapi/src/natives/natives_hookchains.cpp b/reapi/src/natives/natives_hookchains.cpp index 058c8e7..e0a1d9c 100644 --- a/reapi/src/natives/natives_hookchains.cpp +++ b/reapi/src/natives/natives_hookchains.cpp @@ -102,6 +102,9 @@ cell AMX_NATIVE_CALL DisableHookChain(AMX *amx, cell *params) return TRUE; } +static CTempAnyData s_tmpVectors; +static CTempAnyData s_tmpStrings; + /* * Sets the return value of a hookchain. * @@ -148,12 +151,9 @@ cell AMX_NATIVE_CALL SetHookChainReturn(AMX *amx, cell *params) case ATYPE_STRING: { - if (retVal._string != nullptr) - delete[] retVal._string; - size_t len; const char *dest = getAmxString(srcAddr, string, &len); - retVal._string = strcpy(new char[len + 1], dest); + retVal._string = strcpy(s_tmpStrings.Alloc(), dest); break; } case ATYPE_CLASSPTR: @@ -165,6 +165,10 @@ cell AMX_NATIVE_CALL SetHookChainReturn(AMX *amx, cell *params) case ATYPE_EVARS: retVal._pev = PEV(*srcAddr); break; + case ATYPE_VECTOR: + retVal._vector = s_tmpVectors.Alloc(); + *retVal._vector = *(Vector *)srcAddr; + break; default: return FALSE; } @@ -224,7 +228,7 @@ cell AMX_NATIVE_CALL GetHookChainReturn(AMX *amx, cell *params) return retVal._integer != 0 ? TRUE : FALSE; case ATYPE_STRING: { - if (PARAMS_COUNT != 2) + if (PARAMS_COUNT != 3) return FALSE; setAmxString(dstAddr, retVal._string, params[arg_maxlen]); @@ -236,6 +240,15 @@ cell AMX_NATIVE_CALL GetHookChainReturn(AMX *amx, cell *params) return indexOfEdict(retVal._edict); case ATYPE_EVARS: return indexOfEdict(retVal._pev); + case ATYPE_VECTOR: + { + if (PARAMS_COUNT != 2) + return FALSE; + + Vector &pDest = *(Vector *)dstAddr; + pDest = *retVal._vector; + return TRUE; + } default: return FALSE; } diff --git a/reapi/src/natives/natives_hookchains.h b/reapi/src/natives/natives_hookchains.h index c6e0c24..ebc7c8f 100644 --- a/reapi/src/natives/natives_hookchains.h +++ b/reapi/src/natives/natives_hookchains.h @@ -4,3 +4,18 @@ #define NATIVE_MEMBER_REQUIRE(a,x) if (!api_cfg.has##x()) { AMXX_LogError(amx, AMX_ERR_NATIVE, "Member (%s) is not available, required %s", memberlist[a]->member_name, #x); return 0; } void RegisterNatives_HookChains(); + +template +class CTempAnyData +{ +public: + T *Alloc() + { + m_current = (m_current + 1) % BUF_MAX; + return m_data[m_current]; + } + +private: + size_t m_current = 0; + T m_data[BUF_MAX][BUF_SIZE]; +}; diff --git a/reapi/src/natives/natives_misc.cpp b/reapi/src/natives/natives_misc.cpp index 456a1df..a626a22 100644 --- a/reapi/src/natives/natives_misc.cpp +++ b/reapi/src/natives/natives_misc.cpp @@ -459,7 +459,7 @@ cell AMX_NATIVE_CALL rg_round_end(AMX *amx, cell *params) { CSGameRules()->EndRoundMessage(message, _event); CSGameRules()->TerminateRound(_tmDelay, _winStatus); - return TRUE; + return true; }, winstatus, event, tmDelay); } diff --git a/reapi/src/reapi_utils.cpp b/reapi/src/reapi_utils.cpp index e0b2016..77c0693 100644 --- a/reapi/src/reapi_utils.cpp +++ b/reapi/src/reapi_utils.cpp @@ -231,7 +231,8 @@ const char *getATypeStr(AType type) "ATYPE_CLASSPTR", "ATYPE_EDICT", "ATYPE_EVARS", - "ATYPE_BOOL" + "ATYPE_BOOL", + "ATYPE_VECTOR" }; if (type >= arraysize(s_ATypes))