diff --git a/BunnymodXT/cvars.hpp b/BunnymodXT/cvars.hpp index e7d92843..84bae792 100644 --- a/BunnymodXT/cvars.hpp +++ b/BunnymodXT/cvars.hpp @@ -234,7 +234,9 @@ X(bxt_splits_end_on_last_split, "0") \ X(bxt_ch_hook_speed, "869") \ X(bxt_ch_checkpoint_with_vel, "1") \ - X(bxt_ch_checkpoint_onground_only, "0") + X(bxt_ch_checkpoint_onground_only, "0") \ + X(bxt_ch_fix_sticky_slide, "0") \ + X(bxt_ch_fix_sticky_slide_offset, "0.01") class CVarWrapper { diff --git a/BunnymodXT/modules/ServerDLL.cpp b/BunnymodXT/modules/ServerDLL.cpp index 598d4643..add0ce9a 100644 --- a/BunnymodXT/modules/ServerDLL.cpp +++ b/BunnymodXT/modules/ServerDLL.cpp @@ -24,6 +24,11 @@ extern "C" void __cdecl _Z8CmdStartPK7edict_sPK9usercmd_sj(const edict_t* player return ServerDLL::HOOKED_CmdStart(player, cmd, random_seed); } +extern "C" void __cdecl _Z6CmdEndPK7edict_s(const edict_t* player) +{ + return ServerDLL::HOOKED_CmdEnd(player); +} + extern "C" void __cdecl _ZN10CNihilanth10DyingThinkEv(void* thisptr) { return ServerDLL::HOOKED_CNihilanth__DyingThink_Linux(thisptr); @@ -126,6 +131,7 @@ void ServerDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* m ORIG_PM_AddToTouched, HOOKED_PM_AddToTouched, ORIG_PM_Move, HOOKED_PM_Move, ORIG_CmdStart, HOOKED_CmdStart, + ORIG_CmdEnd, HOOKED_CmdEnd, ORIG_CNihilanth__DyingThink, HOOKED_CNihilanth__DyingThink, ORIG_COFGeneWorm__DyingThink, HOOKED_COFGeneWorm__DyingThink, ORIG_CApache__DyingThink, HOOKED_CApache__DyingThink, @@ -179,6 +185,7 @@ void ServerDLL::Unhook() ORIG_PM_AddToTouched, ORIG_PM_Move, ORIG_CmdStart, + ORIG_CmdEnd, ORIG_CNihilanth__DyingThink, ORIG_COFGeneWorm__DyingThink, ORIG_CApache__DyingThink, @@ -233,6 +240,7 @@ void ServerDLL::Clear() ORIG_PM_Ladder = nullptr; ORIG_PM_Move = nullptr; ORIG_CmdStart = nullptr; + ORIG_CmdEnd = nullptr; ORIG_CNihilanth__DyingThink = nullptr; ORIG_CNihilanth__DyingThink_Linux = nullptr; ORIG_COFGeneWorm__DyingThink = nullptr; @@ -1243,17 +1251,19 @@ void ServerDLL::FindStuff() ORIG_DispatchSpawn = reinterpret_cast<_DispatchSpawn>(MemUtils::GetSymbolAddress(m_Handle, "_Z13DispatchSpawnP7edict_s")); ORIG_DispatchTouch = reinterpret_cast<_DispatchTouch>(MemUtils::GetSymbolAddress(m_Handle, "_Z13DispatchTouchP7edict_sS0_")); ORIG_CmdStart = reinterpret_cast<_CmdStart>(MemUtils::GetSymbolAddress(m_Handle, "_Z8CmdStartPK7edict_sPK9usercmd_sj")); + ORIG_CmdEnd = reinterpret_cast<_CmdEnd>(MemUtils::GetSymbolAddress(m_Handle, "_Z6CmdEndPK7edict_s")); ORIG_AddToFullPack = reinterpret_cast<_AddToFullPack>(MemUtils::GetSymbolAddress(m_Handle, "_Z13AddToFullPackP14entity_state_siP7edict_sS2_iiPh")); ORIG_ClientCommand = reinterpret_cast<_ClientCommand>(MemUtils::GetSymbolAddress(m_Handle, "_Z13ClientCommandP7edict_s")); ORIG_PM_Move = reinterpret_cast<_PM_Move>(MemUtils::GetSymbolAddress(m_Handle, "PM_Move")); - if (ORIG_DispatchSpawn && ORIG_DispatchTouch && ORIG_ClientCommand && ORIG_PM_Move && ORIG_AddToFullPack && ORIG_CmdStart) { + if (ORIG_DispatchSpawn && ORIG_DispatchTouch && ORIG_ClientCommand && ORIG_PM_Move && ORIG_AddToFullPack && ORIG_CmdStart && ORIG_CmdEnd) { EngineDevMsg("[server dll] Found DispatchSpawn at %p.\n", ORIG_DispatchSpawn); EngineDevMsg("[server dll] Found DispatchTouch at %p.\n", ORIG_DispatchTouch); EngineDevMsg("[server dll] Found ClientCommand at %p.\n", ORIG_ClientCommand); EngineDevMsg("[server dll] Found PM_Move at %p.\n", ORIG_PM_Move); EngineDevMsg("[server dll] Found AddToFullPack at %p.\n", ORIG_AddToFullPack); EngineDevMsg("[server dll] Found CmdStart at %p.\n", ORIG_CmdStart); + EngineDevMsg("[server dll] Found CmdEnd at %p.\n", ORIG_CmdEnd); } else { ORIG_GetEntityAPI = reinterpret_cast<_GetEntityAPI>(MemUtils::GetSymbolAddress(m_Handle, "GetEntityAPI")); if (ORIG_GetEntityAPI) { @@ -1271,9 +1281,11 @@ void ServerDLL::FindStuff() ORIG_PM_Move = funcs.pfnPM_Move; ORIG_AddToFullPack = funcs.pfnAddToFullPack; ORIG_CmdStart = funcs.pfnCmdStart; + ORIG_CmdEnd = funcs.pfnCmdEnd; EngineDevMsg("[server dll] Found PM_Move at %p.\n", ORIG_PM_Move); EngineDevMsg("[server dll] Found AddToFullPack at %p.\n", ORIG_AddToFullPack); EngineDevMsg("[server dll] Found CmdStart at %p.\n", ORIG_CmdStart); + EngineDevMsg("[server dll] Found CmdEnd at %p.\n", ORIG_CmdEnd); } } else { EngineDevWarning("[server dll] Could not get the server DLL function table.\n"); @@ -1643,6 +1655,11 @@ void ServerDLL::RegisterCVarsAndCommands() REG(bxt_splits_autorecord_on_first_split); REG(bxt_splits_start_timer_on_first_split); REG(bxt_splits_end_on_last_split); + + if (ORIG_CmdStart && ORIG_CmdEnd) { + REG(bxt_ch_fix_sticky_slide); + REG(bxt_ch_fix_sticky_slide_offset); + } #undef REG } @@ -2109,9 +2126,51 @@ HOOK_DEF_3(ServerDLL, void, __cdecl, CmdStart, const edict_t*, player, const use ALERT(at_console, "-- CmdStart End --\n"); } + cmdStartOrigin = Vector(player->v.origin); + cmdStartVelocity = Vector(player->v.velocity); + return ORIG_CmdStart(player, cmd, seed); } +HOOK_DEF_1(ServerDLL, void, __cdecl, CmdEnd, const edict_t*, player) +{ + if (CVars::bxt_ch_fix_sticky_slide.GetBool() && CVars::sv_cheats.GetBool()) { + entvars_t *pev = const_cast(&player->v); + + Vector end_origin = Vector(pev->origin); + Vector end_velocity = Vector(pev->velocity); + + if (end_velocity.Length2D() == 0.0f // stuck, exclude z vel because it will be -4.0 + && cmdStartVelocity.Length() != 0.0f // not standing still, can include z + && cmdStartOrigin == end_origin // origin doesn't change when stuck + ) { + const auto is_duck = pev->button & (IN_DUCK) || player->v.flags & (FL_DUCKING); + + auto origin_z_offset = CVars::bxt_ch_fix_sticky_slide_offset.GetFloat(); // offset so player isn't "stuck" + auto tr_down = HwDLL::GetInstance().PlayerTrace(end_origin, + end_origin + Vector(0, 0, -2), is_duck ? HLStrafe::HullType::DUCKED : HLStrafe::HullType::NORMAL, 0); + auto tr_up = HwDLL::GetInstance().PlayerTrace(end_origin, + end_origin + Vector(0, 0, 2), is_duck ? HLStrafe::HullType::DUCKED : HLStrafe::HullType::NORMAL, 0); + + // If trace to the bottom and no hit, then it means the slide is up top. + // Already have offset positive by default so there is no need for other case. + if (tr_down.Fraction == 1.0 && tr_up.Fraction != 1.0) + origin_z_offset = -origin_z_offset; + else if (tr_down.Fraction == 1.0 && tr_up.Fraction == 1.0) { + // It is not possible to just get stuck in air so this is edge case of being ramp sandwiched. + // Very rare and stupid case. No changes then so it is more predictable to maneuver. + origin_z_offset = 0; + cmdStartVelocity = Vector(); + } + + pev->origin[2] += origin_z_offset; + pev->velocity = cmdStartVelocity; + } + } + + ORIG_CmdEnd(player); +} + HOOK_DEF_2(ServerDLL, void, __fastcall, CNihilanth__DyingThink, void*, thisptr, int, edx) { DoAutoStopTasks(); diff --git a/BunnymodXT/modules/ServerDLL.hpp b/BunnymodXT/modules/ServerDLL.hpp index 0b584416..c5a86add 100644 --- a/BunnymodXT/modules/ServerDLL.hpp +++ b/BunnymodXT/modules/ServerDLL.hpp @@ -17,6 +17,7 @@ class ServerDLL : public IHookableDirFilter HOOK_DECL(bool, __cdecl, PM_AddToTouched, pmtrace_t tr, float* impactvelocity) HOOK_DECL(void, __cdecl, PM_Move, struct playermove_s* ppmove, int server) HOOK_DECL(void, __cdecl, CmdStart, const edict_t* player, const usercmd_t* cmd, unsigned int random_seed) + HOOK_DECL(void, __cdecl, CmdEnd, const edict_t* player) HOOK_DECL(void, __fastcall, CNihilanth__DyingThink, void* thisptr, int edx) HOOK_DECL(void, __cdecl, CNihilanth__DyingThink_Linux, void* thisptr) HOOK_DECL(void, __fastcall, COFGeneWorm__DyingThink, void* thisptr, int edx) @@ -236,4 +237,7 @@ class ServerDLL : public IHookableDirFilter std::deque traceLineFireBulletsHit; bool insideCBasePlayerJump = false; + + Vector cmdStartOrigin; + Vector cmdStartVelocity; };