From 712bc7c279bbd6d490d6b3cfb3a49539a0144a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20H=C3=A0n=20Minh=20Khang?= Date: Fri, 12 Jul 2024 13:55:55 -0400 Subject: [PATCH] Add bxt_ch_trigger_tp_keeps_momentum (#502) * Add bxt_ch_trigger_tp_keeps_momentum * changes suggested --- BunnymodXT/cvars.hpp | 6 +- BunnymodXT/modules/ServerDLL.cpp | 146 ++++++++++++++++++++++++++++++- BunnymodXT/modules/ServerDLL.hpp | 4 + 3 files changed, 152 insertions(+), 4 deletions(-) diff --git a/BunnymodXT/cvars.hpp b/BunnymodXT/cvars.hpp index 81a2db96..c218ecf9 100644 --- a/BunnymodXT/cvars.hpp +++ b/BunnymodXT/cvars.hpp @@ -237,7 +237,11 @@ X(bxt_ch_checkpoint_onground_only, "0") \ X(bxt_ch_fix_sticky_slide, "0") \ X(bxt_ch_fix_sticky_slide_offset, "0.01") \ - X(bxt_ch_noclip_speed, "0") + X(bxt_ch_noclip_speed, "0") \ + X(bxt_ch_trigger_tp_keeps_momentum, "0") \ + X(bxt_ch_trigger_tp_keeps_momentum_velocity, "1") \ + X(bxt_ch_trigger_tp_keeps_momentum_velocity_redirect, "0") \ + X(bxt_ch_trigger_tp_keeps_momentum_viewangles, "1") class CVarWrapper { diff --git a/BunnymodXT/modules/ServerDLL.cpp b/BunnymodXT/modules/ServerDLL.cpp index 00428ca7..5a93ccfc 100644 --- a/BunnymodXT/modules/ServerDLL.cpp +++ b/BunnymodXT/modules/ServerDLL.cpp @@ -108,6 +108,11 @@ extern "C" int __cdecl _ZN11CBaseEntity9IsInWorldEv(void *thisptr) { return ServerDLL::HOOKED_CBaseEntity__IsInWorld_Linux(thisptr); } + +extern "C" void __cdecl _ZN12CBaseTrigger13TeleportTouchEP11CBaseEntity(void* thisptr, void* pOther) +{ + return ServerDLL::HOOKED_CBaseTrigger__TeleportTouch_Linux(thisptr, pOther); +} #endif void ServerDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* moduleBase, size_t moduleLength, bool needToIntercept) @@ -172,7 +177,9 @@ void ServerDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* m ORIG_PM_Duck, HOOKED_PM_Duck, ORIG_PM_UnDuck, HOOKED_PM_UnDuck, ORIG_CBaseEntity__IsInWorld, HOOKED_CBaseEntity__IsInWorld, - ORIG_CBaseEntity__IsInWorld_Linux, HOOKED_CBaseEntity__IsInWorld_Linux); + ORIG_CBaseEntity__IsInWorld_Linux, HOOKED_CBaseEntity__IsInWorld_Linux, + ORIG_CBaseTrigger__TeleportTouch, HOOKED_CBaseTrigger__TeleportTouch, + ORIG_CBaseTrigger__TeleportTouch_Linux, HOOKED_CBaseTrigger__TeleportTouch_Linux); } } @@ -227,7 +234,9 @@ void ServerDLL::Unhook() ORIG_PM_Duck, ORIG_PM_UnDuck, ORIG_CBaseEntity__IsInWorld, - ORIG_CBaseEntity__IsInWorld_Linux); + ORIG_CBaseEntity__IsInWorld_Linux, + ORIG_CBaseTrigger__TeleportTouch, + ORIG_CBaseTrigger__TeleportTouch_Linux); } Clear(); @@ -301,6 +310,8 @@ void ServerDLL::Clear() ORIG_PM_UnDuck = nullptr; ORIG_CBaseEntity__IsInWorld = nullptr; ORIG_CBaseEntity__IsInWorld_Linux = nullptr; + ORIG_CBaseTrigger__TeleportTouch = nullptr; + ORIG_CBaseTrigger__TeleportTouch_Linux = nullptr; ppmove = nullptr; offPlayerIndex = 0; offOldbuttons = 0; @@ -1554,6 +1565,19 @@ void ServerDLL::FindStuff() } } + { + ORIG_CBaseTrigger__TeleportTouch = reinterpret_cast<_CBaseTrigger__TeleportTouch>(MemUtils::GetSymbolAddress(m_Handle, "?TeleportTouch@CBaseTrigger@@QAEXPAVCBaseEntity@@@Z")); + if (ORIG_CBaseTrigger__TeleportTouch) + EngineDevMsg("[server dll] Found CBaseTrigger::TriggerTouch at %p.\n", ORIG_CBaseTrigger__TeleportTouch); + else { + ORIG_CBaseTrigger__TeleportTouch_Linux = reinterpret_cast<_CBaseTrigger__TeleportTouch_Linux>(MemUtils::GetSymbolAddress(m_Handle, "_ZN12CBaseTrigger13TeleportTouchEP11CBaseEntity")); + if (ORIG_CBaseTrigger__TeleportTouch_Linux) + EngineDevMsg("[server dll] Found CBaseTrigger::TriggerTouch [Linux] at %p.\n", ORIG_CBaseTrigger__TeleportTouch_Linux); + else + EngineDevWarning("[server dll] Could not find CBaseTrigger::TriggerTouch.\n"); + } + } + if (!pEngfuncs) { pEngfuncs = reinterpret_cast(MemUtils::GetSymbolAddress(m_Handle, "g_engfuncs")); @@ -1617,6 +1641,12 @@ void ServerDLL::RegisterCVarsAndCommands() REG(bxt_cof_allow_skipping_all_cutscenes); if (ORIG_PM_Move) REG(bxt_ch_noclip_speed); + if (ORIG_CBaseTrigger__TeleportTouch || ORIG_CBaseTrigger__TeleportTouch_Linux) { + REG(bxt_ch_trigger_tp_keeps_momentum); + REG(bxt_ch_trigger_tp_keeps_momentum_velocity); + REG(bxt_ch_trigger_tp_keeps_momentum_velocity_redirect); + REG(bxt_ch_trigger_tp_keeps_momentum_viewangles); + } REG(bxt_splits_print); REG(bxt_splits_print_times_at_end); @@ -3347,4 +3377,114 @@ HOOK_DEF_1(ServerDLL, int, __cdecl, CBaseEntity__IsInWorld_Linux, void*, thisptr return ORIG_CBaseEntity__IsInWorld_Linux(thisptr); } -#undef ALERT +bool ServerDLL::IsPlayer(edict_t *ent) +{ + // https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/player.cpp#L2850 + + auto &hw = HwDLL::GetInstance(); + + if (strcmp(hw.GetString(ent->v.classname), "player") != 0) + return false; + + if (!(ent->v.flags & FL_CLIENT)) + return false; + + if (pEngfuncs && hw.ppGlobals) + { + int index = pEngfuncs->pfnIndexOfEdict(ent); + + if ((index < 1) || (index > hw.ppGlobals->maxClients)) // gGlobalVariables.maxClients = svs.maxclients + return false; + } + + return true; +} + +void TriggerTpKeepsMomentumRestore(Vector prev_vel, Vector prev_view, Vector prev_angles, Vector prev_basevelocity, entvars_t *pev, enginefuncs_t *pEngfuncs) +{ + // Set velocity before viewangles because viewangles will mess with the velocity angle for redirection + if (CVars::bxt_ch_trigger_tp_keeps_momentum_velocity.GetBool()) { + if (CVars::bxt_ch_trigger_tp_keeps_momentum_velocity_redirect.GetBool()) { + // https://github.com/fireblizzard/agmod/blob/bf06e4ffd31c1427784685118820e15552803bcb/dlls/triggers.cpp#L1935 + // After teleportation, pevToucher has the same viewangles as pentTarget. + Vector vecAngles = Vector(0, pev->v_angle.y, 0); + Vector vecForward; + + pEngfuncs->pfnAngleVectors(vecAngles, vecForward, nullptr, nullptr); + + // For velocity + float xy_vel = prev_vel.Length2D(); + + pev->velocity.x = vecForward.x * xy_vel; + pev->velocity.y = vecForward.y * xy_vel; + + // For base velocity + float xy_basevel = prev_basevelocity.Length2D(); + + pev->basevelocity.x = vecForward.x * xy_basevel; + pev->basevelocity.y = vecForward.y * xy_basevel; + } else { + pev->velocity = prev_vel; + pev->basevelocity = prev_basevelocity; + } + } + + if (CVars::bxt_ch_trigger_tp_keeps_momentum_viewangles.GetBool()) { + // In HLSDK, due to some inheritance stuffs, pevToucher's viewangles is changed differently. + // In and only in TeleportTouch, pev->fixangle is set to 1. + // If not set back to 0, we cannot set our viewangles, due to inheritance stuffs. + pev->fixangle = 0; + pev->v_angle = prev_view; + pev->angles = prev_angles; + } +} + +HOOK_DEF_3(ServerDLL, void, __fastcall, CBaseTrigger__TeleportTouch, void*, thisptr, int, edx, void*, pOther) +{ + auto is_bxt_ch_trigger_tp_keeps_momentum_enabled = CVars::sv_cheats.GetBool() && CVars::bxt_ch_trigger_tp_keeps_momentum.GetBool(); + + entvars_t *pev = *reinterpret_cast(reinterpret_cast(pOther) + 4); + Vector prev_vel; + Vector prev_view; + Vector prev_angles; + Vector prev_basevelocity; + + if (pev) { + prev_vel = pev->velocity; + prev_view = pev->v_angle; + prev_angles = pev->angles; + prev_basevelocity = pev->basevelocity; + } + + ORIG_CBaseTrigger__TeleportTouch(thisptr, edx, pOther); + + if (is_bxt_ch_trigger_tp_keeps_momentum_enabled && pev && pEngfuncs && IsPlayer(pev->pContainingEntity)) { + TriggerTpKeepsMomentumRestore(prev_vel, prev_vel, prev_angles, prev_basevelocity, pev, pEngfuncs); + } +} + +HOOK_DEF_2(ServerDLL, void, __cdecl, CBaseTrigger__TeleportTouch_Linux, void*, thisptr, void*, pOther) +{ + auto is_bxt_ch_trigger_tp_keeps_momentum_enabled = CVars::sv_cheats.GetBool() && CVars::bxt_ch_trigger_tp_keeps_momentum.GetBool(); + + entvars_t *pev = *reinterpret_cast(reinterpret_cast(pOther) + 4); + Vector prev_vel; + Vector prev_view; + Vector prev_angles; + Vector prev_basevelocity; + + if (pev) { + prev_vel = pev->velocity; + prev_view = pev->v_angle; + prev_angles = pev->angles; + prev_basevelocity = pev->basevelocity; + } + + ORIG_CBaseTrigger__TeleportTouch_Linux(thisptr, pOther); + + if (is_bxt_ch_trigger_tp_keeps_momentum_enabled && pev && pEngfuncs && IsPlayer(pev->pContainingEntity)) { + TriggerTpKeepsMomentumRestore(prev_vel, prev_vel, prev_angles, prev_basevelocity, pev, pEngfuncs); + } +} + +#undef ALERT \ No newline at end of file diff --git a/BunnymodXT/modules/ServerDLL.hpp b/BunnymodXT/modules/ServerDLL.hpp index 5e201f3a..44a93e8f 100644 --- a/BunnymodXT/modules/ServerDLL.hpp +++ b/BunnymodXT/modules/ServerDLL.hpp @@ -64,6 +64,8 @@ class ServerDLL : public IHookableDirFilter HOOK_DECL(void, __fastcall, CTriggerCamera__FollowTarget, void* thisptr) HOOK_DECL(int, __fastcall, CBaseEntity__IsInWorld, void* thisptr) HOOK_DECL(int, __cdecl, CBaseEntity__IsInWorld_Linux, void* thisptr) + HOOK_DECL(void, __fastcall, CBaseTrigger__TeleportTouch, void* thisptr, int edx, void* pOther) + HOOK_DECL(void, __cdecl, CBaseTrigger__TeleportTouch_Linux, void* thisptr, void* pOther) public: static ServerDLL& GetInstance() @@ -117,6 +119,8 @@ class ServerDLL : public IHookableDirFilter void GiveNamedItem(entvars_t *pev, int istr); + bool IsPlayer(edict_t *ent); + private: ServerDLL() : IHookableDirFilter({ L"dlls", L"cl_dlls"}) {}; ServerDLL(const ServerDLL&);