From 2e79fcc0d312e6ac9f402522caad6cbeb7b75589 Mon Sep 17 00:00:00 2001 From: BenCat07 Date: Mon, 7 Dec 2020 15:40:54 +0100 Subject: [PATCH] Improve Hitrate on rapidfire --- include/core/interfaces.hpp | 2 + include/core/netvars.hpp | 1 + include/core/offsets.hpp | 4 ++ include/core/sdk.hpp | 1 + include/hooks.hpp | 1 + include/hooks/HookTools.hpp | 1 + include/hooks/HookedMethods.hpp | 2 + include/hooks/Think.hpp | 6 +++ include/localplayer.hpp | 2 + include/reclasses/C_TFWeaponBase.hpp | 7 +++ src/core/interfaces.cpp | 78 ++++++++++++++-------------- src/core/netvars.cpp | 1 + src/hack.cpp | 4 ++ src/hacks/Bunnyhop.cpp | 2 +- src/hacks/FollowBot.cpp | 2 +- src/hacks/Walkbot.cpp | 2 +- src/hacks/Warp.cpp | 67 ++++++++++-------------- src/helpers.cpp | 36 ++++++++----- src/hooks.cpp | 1 + src/hooks/CMakeLists.txt | 1 + src/hooks/CreateMove.cpp | 23 +++++++- src/hooks/Think.cpp | 28 ++++++++++ src/localplayer.cpp | 5 ++ src/navparser.cpp | 2 +- 24 files changed, 183 insertions(+), 96 deletions(-) create mode 100644 include/hooks/Think.hpp create mode 100644 src/hooks/Think.cpp diff --git a/include/core/interfaces.hpp b/include/core/interfaces.hpp index c3a17366..c9294bac 100644 --- a/include/core/interfaces.hpp +++ b/include/core/interfaces.hpp @@ -17,6 +17,7 @@ class ISurface; class IPanel; } // namespace vgui +class IToolFrameworkInternal; class ISteamClient; class ISteamFriends; class IVEngineClient013; @@ -95,6 +96,7 @@ extern IUniformRandomStream *g_pUniformStream; extern int *g_PredictionRandomSeed; extern IFileSystem *g_IFileSystem; extern IMDLCache *g_IMDLCache; +extern IToolFrameworkInternal *g_IToolFramework; void CreateInterfaces(); void CreateEarlyInterfaces(); diff --git a/include/core/netvars.hpp b/include/core/netvars.hpp index 9869961d..9f72fdf6 100644 --- a/include/core/netvars.hpp +++ b/include/core/netvars.hpp @@ -207,6 +207,7 @@ public: offset_t m_iPlayerIndex; offset_t m_hTargetPlayer; offset_t m_flResetTime; + offset_t m_flMaxspeed; }; extern NetVars netvar; diff --git a/include/core/offsets.hpp b/include/core/offsets.hpp index 68b268bd..4fa583cb 100644 --- a/include/core/offsets.hpp +++ b/include/core/offsets.hpp @@ -228,4 +228,8 @@ struct offsets { return PlatformOffset(0x2fb8, undefined, undefined); } + static constexpr uint32_t Think() + { + return PlatformOffset(27, undefined, undefined); + } }; diff --git a/include/core/sdk.hpp b/include/core/sdk.hpp index c2a58ee6..9a3e1f2f 100755 --- a/include/core/sdk.hpp +++ b/include/core/sdk.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/include/hooks.hpp b/include/hooks.hpp index 4841c07c..9ebc5966 100644 --- a/include/hooks.hpp +++ b/include/hooks.hpp @@ -75,4 +75,5 @@ extern VMTHook materialsystem; extern VMTHook enginevgui; extern VMTHook vstd; extern VMTHook eventmanager2; +extern VMTHook toolbox; } // namespace hooks diff --git a/include/hooks/HookTools.hpp b/include/hooks/HookTools.hpp index 5ae73f74..3e1d1358 100644 --- a/include/hooks/HookTools.hpp +++ b/include/hooks/HookTools.hpp @@ -15,6 +15,7 @@ enum ec_types CreateMoveLate, /* This kind of CreateMove will run earlier than "CreateMove" events * and guranteed to run before EnginePrediction + * This is NEEDED for any kind of movement */ CreateMove_NoEnginePred, /* Note: this is still CreateMove, just ran before original is called, needed in some cases like changing tickcount before original gets called*/ diff --git a/include/hooks/HookedMethods.hpp b/include/hooks/HookedMethods.hpp index f61c0056..a9da7c9d 100644 --- a/include/hooks/HookedMethods.hpp +++ b/include/hooks/HookedMethods.hpp @@ -94,6 +94,8 @@ DECLARE_HOOKED_METHOD(EmitSound2, void, void *, IRecipientFilter &, int, int, co DECLARE_HOOKED_METHOD(EmitSound3, void, void *, IRecipientFilter &, int, int, int, float, soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector *, bool, float, int); // g_IPrediction DECLARE_HOOKED_METHOD(RunCommand, void, IPrediction *, IClientEntity *, CUserCmd *, IMoveHelper *); +// g_IToolFramework +DECLARE_HOOKED_METHOD(Think, void, IToolFrameworkInternal *, bool); } // namespace hooked_methods // TODO diff --git a/include/hooks/Think.hpp b/include/hooks/Think.hpp new file mode 100644 index 00000000..52c39a61 --- /dev/null +++ b/include/hooks/Think.hpp @@ -0,0 +1,6 @@ +#pragma once +namespace hooked_methods +{ +// Update Prediction, Used by warp/Doubletap aswell +void UpdatePred(); +} // namespace hooked_methods diff --git a/include/localplayer.hpp b/include/localplayer.hpp index d3a99bce..cde34813 100644 --- a/include/localplayer.hpp +++ b/include/localplayer.hpp @@ -26,6 +26,8 @@ public: // Start of CM void Update(); + // After prediction + void UpdateEye(); // End of CM void UpdateEnd(); int team; diff --git a/include/reclasses/C_TFWeaponBase.hpp b/include/reclasses/C_TFWeaponBase.hpp index dd1714f3..a362e4c7 100644 --- a/include/reclasses/C_TFWeaponBase.hpp +++ b/include/reclasses/C_TFWeaponBase.hpp @@ -82,6 +82,13 @@ public: typedef bool (*fn_t)(IClientEntity *, bool, IClientEntity *); return vfunc(self, offsets::PlatformOffset(490, offsets::undefined, 490), 0)(self, unknown1, unknown2); } + inline static float ApplyFireDelay(IClientEntity *self, float delay) + { + typedef float (*ApplyFireDelay_t)(IClientEntity *, float); + static auto signature = gSignatures.GetClientSignature("55 89 E5 57 56 53 83 EC 6C C7 45 ? 00 00 00 00 A1 ? ? ? ? C7 45 ? 00 00 00 00 8B 5D ? 85 C0 0F 84 ? ? ? ? 8D 55 ? 89 04 24 31 F6 89 54 24 ? C7 44 24 ? ? ? ? ? C7 44 24 ? ? ? ? ? C7 44 24 ? ? ? ? ? C7 44 24 ? ? ? ? ? C7 44 24 ? 6B 00 00 00 C7 44 24 ? ? ? ? ? C7 44 24 ? 00 00 00 00 C7 44 24 ? 00 00 00 00 C7 44 24 ? 00 00 00 00 C7 44 24 ? 00 00 00 00 FF 50 ? A1 ? ? ? ? 8B 0D ? ? ? ? 8B 55 ? 89 45 ? 8B 45 ? 85 C9 89 55 ? 89 45 ? 0F 85 ? ? ? ? 85 DB 0F 84 ? ? ? ? 8B 7B ? 85 FF 0F 84 ? ? ? ? C7 04 24 ? ? ? ? E8 ? ? ? ? 89 45 ? 8B 07 89 3C 24 FF 10 8B 7D ? 8B 10 C7 44 24 ? 00 00 00 00 89 5C 24 ? C7 44 24 ? ? ? ? ? 89 7C 24 ? 89 04 24 FF 52 ? D9 5D ? F3 0F 10 45 ? F3 0F 11 04 24 E8 ? ? ? ? D9 5D"); + static ApplyFireDelay_t ApplyFireDelay_fn = (ApplyFireDelay_t) signature; + return ApplyFireDelay_fn(self, delay); + } inline static void AddToCritBucket(IClientEntity *self, float value) { constexpr float max_bucket_capacity = 1000.0f; diff --git a/src/core/interfaces.cpp b/src/core/interfaces.cpp index 81970343..a3d586d4 100644 --- a/src/core/interfaces.cpp +++ b/src/core/interfaces.cpp @@ -18,44 +18,45 @@ // class ISteamFriends002; -IVModelRender *g_IVModelRender = nullptr; -ISteamClient *g_ISteamClient = nullptr; -ISteamFriends *g_ISteamFriends = nullptr; -IVEngineClient013 *g_IEngine = nullptr; -void *demoplayer = nullptr; -IEngineSound *g_ISoundEngine = nullptr; -vgui::ISurface *g_ISurface = nullptr; -vgui::IPanel *g_IPanel = nullptr; -IClientEntityList *g_IEntityList = nullptr; -ICvar *g_ICvar = nullptr; -IGameEventManager2 *g_IEventManager2 = nullptr; -IBaseClientDLL *g_IBaseClient = nullptr; -IEngineTrace *g_ITrace = nullptr; -IVModelInfoClient *g_IModelInfo = nullptr; -IInputSystem *g_IInputSystem = nullptr; -CGlobalVarsBase **rg_GlobalVars = nullptr; -IPrediction *g_IPrediction = nullptr; -IGameMovement *g_IGameMovement = nullptr; -IInput *g_IInput = nullptr; -ISteamUser *g_ISteamUser = nullptr; -IAchievementMgr *g_IAchievementMgr = nullptr; -ISteamUserStats *g_ISteamUserStats = nullptr; -IStudioRender *g_IStudioRender = nullptr; -IVDebugOverlay *g_IVDebugOverlay = nullptr; -IMaterialSystemFixed *g_IMaterialSystem = nullptr; -IVRenderView *g_IVRenderView = nullptr; -IMaterialSystem *g_IMaterialSystemHL = nullptr; -IMoveHelperServer *g_IMoveHelperServer = nullptr; -CBaseClientState *g_IBaseClientState = nullptr; -IGameEventManager *g_IGameEventManager = nullptr; -TFGCClientSystem *g_TFGCClientSystem = nullptr; -CHud *g_CHUD = nullptr; -CGameRules *g_pGameRules = nullptr; -IEngineVGui *g_IEngineVGui = nullptr; -IUniformRandomStream *g_pUniformStream = nullptr; -int *g_PredictionRandomSeed = nullptr; -IFileSystem *g_IFileSystem = nullptr; -IMDLCache *g_IMDLCache = nullptr; +IVModelRender *g_IVModelRender = nullptr; +ISteamClient *g_ISteamClient = nullptr; +ISteamFriends *g_ISteamFriends = nullptr; +IVEngineClient013 *g_IEngine = nullptr; +void *demoplayer = nullptr; +IEngineSound *g_ISoundEngine = nullptr; +vgui::ISurface *g_ISurface = nullptr; +vgui::IPanel *g_IPanel = nullptr; +IClientEntityList *g_IEntityList = nullptr; +ICvar *g_ICvar = nullptr; +IGameEventManager2 *g_IEventManager2 = nullptr; +IBaseClientDLL *g_IBaseClient = nullptr; +IEngineTrace *g_ITrace = nullptr; +IVModelInfoClient *g_IModelInfo = nullptr; +IInputSystem *g_IInputSystem = nullptr; +CGlobalVarsBase **rg_GlobalVars = nullptr; +IPrediction *g_IPrediction = nullptr; +IGameMovement *g_IGameMovement = nullptr; +IInput *g_IInput = nullptr; +ISteamUser *g_ISteamUser = nullptr; +IAchievementMgr *g_IAchievementMgr = nullptr; +ISteamUserStats *g_ISteamUserStats = nullptr; +IStudioRender *g_IStudioRender = nullptr; +IVDebugOverlay *g_IVDebugOverlay = nullptr; +IMaterialSystemFixed *g_IMaterialSystem = nullptr; +IVRenderView *g_IVRenderView = nullptr; +IMaterialSystem *g_IMaterialSystemHL = nullptr; +IMoveHelperServer *g_IMoveHelperServer = nullptr; +CBaseClientState *g_IBaseClientState = nullptr; +IGameEventManager *g_IGameEventManager = nullptr; +TFGCClientSystem *g_TFGCClientSystem = nullptr; +CHud *g_CHUD = nullptr; +CGameRules *g_pGameRules = nullptr; +IEngineVGui *g_IEngineVGui = nullptr; +IUniformRandomStream *g_pUniformStream = nullptr; +int *g_PredictionRandomSeed = nullptr; +IFileSystem *g_IFileSystem = nullptr; +IMDLCache *g_IMDLCache = nullptr; +IToolFrameworkInternal *g_IToolFramework = nullptr; template T *BruteforceInterface(std::string name, sharedobj::SharedObject &object, int start = 0) { @@ -169,6 +170,7 @@ void CreateInterfaces() g_IStudioRender = BruteforceInterface("VStudioRender", sharedobj::studiorender()); g_IVRenderView = BruteforceInterface("VEngineRenderView", sharedobj::engine()); g_IMaterialSystemHL = (IMaterialSystem *) g_IMaterialSystem; + g_IToolFramework = BruteforceInterface("VTOOLFRAMEWORKVERSION", sharedobj::engine()); IF_GAME(IsTF2()) { g_pScreenSpaceEffects = **(IScreenSpaceEffectManager ***) (gSignatures.GetClientSignature("8D 74 26 00 55 89 E5 57 56 53 83 EC 1C 8B 5D 08 8B 7D 0C 8B 75 10 ") + 0x1c3); diff --git a/src/core/netvars.cpp b/src/core/netvars.cpp index 7b001cc8..27dc2d87 100644 --- a/src/core/netvars.cpp +++ b/src/core/netvars.cpp @@ -33,6 +33,7 @@ void NetVars::Init() IF_GAME(IsTF2()) { + this->m_flMaxspeed = gNetvars.get_offset("DT_BasePlayer", "m_flMaxspeed"); res_iTeam = gNetvars.get_offset("DT_TFPlayerResource", "baseclass", "m_iTeam"); res_bAlive = gNetvars.get_offset("DT_TFPlayerResource", "baseclass", "m_bAlive"); this->res_iMaxBuffedHealth = gNetvars.get_offset("DT_TFPlayerResource", "m_iMaxBuffedHealth"); diff --git a/src/hack.cpp b/src/hack.cpp index f0f11b15..621ea3d1 100644 --- a/src/hack.cpp +++ b/src/hack.cpp @@ -257,6 +257,10 @@ void hack::Hook() hooks::prediction.HookMethod(HOOK_ARGS(RunCommand)); hooks::prediction.Apply(); + hooks::toolbox.Set(g_IToolFramework); + hooks::toolbox.HookMethod(HOOK_ARGS(Think)); + hooks::toolbox.Apply(); + #if ENABLE_VISUALS sdl_hooks::applySdlHooks(); #endif diff --git a/src/hacks/Bunnyhop.cpp b/src/hacks/Bunnyhop.cpp index 95388bc1..3596fdf8 100644 --- a/src/hacks/Bunnyhop.cpp +++ b/src/hacks/Bunnyhop.cpp @@ -56,5 +56,5 @@ static void CreateMove() if (!jump) ticks_last_jump = 0; } -static InitRoutine EC([]() { EC::Register(EC::CreateMove_NoEnginePred, CreateMove, "Bunnyhop", EC::average); }); +static InitRoutine EC([]() { EC::Register(EC::CreateMove_NoEnginePred, CreateMove, "Bunnyhop", EC::early); }); } // namespace hacks::shared::bunnyhop diff --git a/src/hacks/FollowBot.cpp b/src/hacks/FollowBot.cpp index 833b17f4..c6764258 100644 --- a/src/hacks/FollowBot.cpp +++ b/src/hacks/FollowBot.cpp @@ -774,7 +774,7 @@ void rvarCallback(settings::VariableBase &var, int after) } static InitRoutine runinit([]() { - EC::Register(EC::CreateMove, cm, "cm_followbot", EC::average); + EC::Register(EC::CreateMove_NoEnginePred, cm, "cm_followbot", EC::average); #if ENABLE_VISUALS EC::Register(EC::Draw, draw, "draw_followbot", EC::average); #endif diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index b340d65b..cc5ec9ff 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -1219,7 +1219,7 @@ static void cm() } static InitRoutine init([]() { - EC::Register(EC::CreateMove, cm, "cm_walkbot", EC::average); + EC::Register(EC::CreateMove_NoEnginePred, cm, "cm_walkbot", EC::average); EC::Register(EC::LevelInit, OnLevelInit, "init_walkbot", EC::average); #if ENABLE_VISUALS EC::Register(EC::Draw, Draw, "draw_walkbot", EC::average); diff --git a/src/hacks/Warp.cpp b/src/hacks/Warp.cpp index a889736e..1652e80e 100644 --- a/src/hacks/Warp.cpp +++ b/src/hacks/Warp.cpp @@ -14,6 +14,7 @@ #include "DetourHook.hpp" #include "WeaponData.hpp" #include "MiscTemporary.hpp" +#include "Think.hpp" namespace hacks::tf2::warp { @@ -109,6 +110,12 @@ bool UpdateRFKey() return allow_key; } +float getFireDelay() +{ + auto weapon_data = GetWeaponData(RAW_ENT(LOCAL_W)); + return re::C_TFWeaponBase::ApplyFireDelay(RAW_ENT(LOCAL_W), weapon_data->m_flTimeFireDelay); +} + bool shouldRapidfire() { if (!rapidfire) @@ -139,8 +146,7 @@ bool shouldRapidfire() return false; // We do not have the amount of ticks needed, don't try it - auto weapon_data = GetWeaponData(RAW_ENT(LOCAL_W)); - if (warp_amount < TIME_TO_TICKS(weapon_data->m_flTimeFireDelay) && (TIME_TO_TICKS(weapon_data->m_flTimeFireDelay) < *maxusrcmdprocessticks - 1 || (wait_full && warp_amount != GetMaxWarpTicks()))) + if (warp_amount < TIME_TO_TICKS(getFireDelay()) && (TIME_TO_TICKS(getFireDelay()) < *maxusrcmdprocessticks - 1 || (wait_full && warp_amount != GetMaxWarpTicks()))) return false; // Mouse 1 is held, do it. @@ -175,9 +181,17 @@ int GetWarpAmount(bool finalTick) { int max_extra_ticks = *maxusrcmdprocessticks - 1; - // Rapidfire ignores speed + // Rapidfire ignores speed, and we send 15 + 7, aka maximum new + backup commands if (in_rapidfire) - return max_extra_ticks; + { + // Warp right before the next shot + float shot_time = getFireDelay(); + // This is to prevent Minigun/Pistol from only shooting once + if (TICKS_TO_TIME(22) / shot_time >= 2) + shot_time = TICKS_TO_TIME(23); + return std::min(22, TIME_TO_TICKS(shot_time) - 2); + // return 22; + } // No limit set if (!*maxusrcmdprocessticks) max_extra_ticks = INT_MAX; @@ -239,6 +253,8 @@ void Warp(float accumulated_extra_samples, bool finalTick) choke_packet = false; packets_sent = -1; } + else + hooked_methods::UpdatePred(); original(accumulated_extra_samples, finalTick); // Only decrease ticks for the final CL_Move tick @@ -346,11 +362,6 @@ static bool was_overridden = false; static int ticks_in_revved = 0; static bool replaced_last_tick = false; -// Original Player origin and velocity, needed to not break because our engine pred. -// We adjust it as the ticks go. -static Vector original_origin; -static Vector original_velocity; - // Reset all the revv data void resetRevvstate() { @@ -414,15 +425,7 @@ void CL_Move_hook(float accumulated_extra_samples, bool bFinalTick) { in_warp = true; if (shouldRapidfire()) - { in_rapidfire = true; - // Store original info - original_origin = LOCAL_E->m_vecOrigin(); - velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), original_velocity); - // Zero out non z movement, it will just get messy else - original_velocity.x = 0.0f; - original_velocity.y = 0.0f; - } Warp(accumulated_extra_samples, bFinalTick); if (warp_amount < GetMaxWarpTicks()) @@ -449,26 +452,12 @@ void CreateMoveEarly() } } -// Fix the player origin after engine prediction, as it tries to predict the local -// player linearly and just breaks doubletap when falling/moving -void CreateMoveFixPrediction() +// Run before prediction so we can do Faststop logic +void CreateMovePrePredict() { - if (hacks::tf2::warp::in_rapidfire && current_user_cmd) - { - // Run very simple gravity calculations to ensure we do not miss - if (no_movement) - { - static ConVar *sv_gravity = g_ICvar->FindVar("sv_gravity"); - Vector gravity{ 0.0f, 0.0f, -sv_gravity->GetFloat() }; - - auto mins = RAW_ENT(LOCAL_E)->GetCollideable()->OBBMins(); - auto maxs = RAW_ENT(LOCAL_E)->GetCollideable()->OBBMaxs(); - std::pair minmax{ mins, maxs }; - PredictStep(original_origin, original_velocity, gravity, &minmax); - // Restore from the engine prediction - const_cast(RAW_ENT(LOCAL_E)->GetAbsOrigin()) = original_origin; - } - } + // Attempt to stop fast in place to make movement smoother + if (in_rapidfire && no_movement) + FastStop(); } // This calls the warp logic and applies some rapidfire specific logic afterwards @@ -490,10 +479,6 @@ void CreateMove() was_in_warp = false; } - - // Attempt to stop fast in place to make movement smoother - if (in_rapidfire && no_movement) - FastStop(); } // Does all the logic related to charging and mode/settings specific actions like peek warp @@ -948,8 +933,8 @@ static InitRoutine init([]() { cl_move_detour.Init(cl_move_addr, (void *) CL_Move_hook); EC::Register(EC::LevelShutdown, LevelShutdown, "warp_levelshutdown"); - EC::Register(EC::CreateMove, CreateMoveFixPrediction, "warp_createmove_fixpred", EC::very_early); EC::Register(EC::CreateMove, CreateMove, "warp_createmove", EC::very_late); + EC::Register(EC::CreateMove_NoEnginePred, CreateMovePrePredict, "warp_prepredict"); EC::Register(EC::CreateMoveEarly, CreateMoveEarly, "warp_createmove_early", EC::very_early); g_IEventManager2->AddListener(&listener, "player_hurt", false); EC::Register( diff --git a/src/helpers.cpp b/src/helpers.cpp index 1541acd9..3529113d 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -1621,28 +1621,40 @@ void AimAtHitbox(CachedEntity *ent, int hitbox, CUserCmd *cmd, bool compensate_p AimAt(g_pLocalPlayer->v_Eye, r, cmd, compensate_punch); } -// Thanks to "copypaste" on UnknownCheats, this really helped void FastStop() { // Get velocity Vector vel; velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), vel); - Vector direction; - VectorAngles(vel, direction); - float speed = vel.Length(); + static auto sv_friction = g_ICvar->FindVar("sv_friction"); + static auto sv_stopspeed = g_ICvar->FindVar("sv_stopspeed"); - // Prevent overshooting - speed *= 0.5f; + auto speed = vel.Length2D(); + auto friction = sv_friction->GetFloat() * CE_FLOAT(LOCAL_E, 0x12b8); + auto control = (speed < sv_stopspeed->GetFloat()) ? sv_stopspeed->GetFloat() : speed; + auto drop = control * friction * g_GlobalVars->interval_per_tick; - direction.y = current_user_cmd->viewangles.y - direction.y; + if (speed > drop - 1.0f) + { + Vector velocity = vel; + Vector direction; + VectorAngles(vel, direction); + float speed = velocity.Length(); - Vector negated_direction; - AngleVectors2(VectorToQAngle(direction), &negated_direction); - negated_direction *= -speed; + direction.y = current_user_cmd->viewangles.y - direction.y; - current_user_cmd->forwardmove = negated_direction.x; - current_user_cmd->sidemove = negated_direction.y; + Vector forward; + AngleVectors2(VectorToQAngle(direction), &forward); + Vector negated_direction = forward * -speed; + + current_user_cmd->forwardmove = negated_direction.x; + current_user_cmd->sidemove = negated_direction.y; + } + else + { + current_user_cmd->forwardmove = current_user_cmd->sidemove = 0.0f; + } } bool IsEntityVisiblePenetration(CachedEntity *entity, int hb) diff --git a/src/hooks.cpp b/src/hooks.cpp index 1ceb18df..2cb4e90a 100644 --- a/src/hooks.cpp +++ b/src/hooks.cpp @@ -118,4 +118,5 @@ VMTHook soundclient{}; VMTHook enginevgui{}; VMTHook vstd{}; VMTHook eventmanager2{}; +VMTHook toolbox{}; } // namespace hooks diff --git a/src/hooks/CMakeLists.txt b/src/hooks/CMakeLists.txt index 343961a2..b00156eb 100755 --- a/src/hooks/CMakeLists.txt +++ b/src/hooks/CMakeLists.txt @@ -15,6 +15,7 @@ set(files "${CMAKE_CURRENT_LIST_DIR}/CanPacket.cpp" "${CMAKE_CURRENT_LIST_DIR}/RunCommand.cpp" "${CMAKE_CURRENT_LIST_DIR}/SendNetMsg.cpp" "${CMAKE_CURRENT_LIST_DIR}/Shutdown.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Think.cpp" "${CMAKE_CURRENT_LIST_DIR}/FireEvent.cpp" "${CMAKE_CURRENT_LIST_DIR}/FireEventClientSide.cpp" "${CMAKE_CURRENT_LIST_DIR}/IsPlayingTimeDemo.cpp" diff --git a/src/hooks/CreateMove.cpp b/src/hooks/CreateMove.cpp index ff754c4c..5a77fda9 100644 --- a/src/hooks/CreateMove.cpp +++ b/src/hooks/CreateMove.cpp @@ -23,7 +23,7 @@ static settings::Boolean minigun_jump{ "misc.minigun-jump-tf2c", "false" }; static settings::Boolean roll_speedhack{ "misc.roll-speedhack", "false" }; static settings::Boolean forward_speedhack{ "misc.roll-speedhack.forward", "false" }; -static settings::Boolean engine_pred{ "misc.engine-prediction", "true" }; +settings::Boolean engine_pred{ "misc.engine-prediction", "true" }; static settings::Boolean debug_projectiles{ "debug.projectiles", "false" }; static settings::Int fullauto{ "misc.full-auto", "0" }; static settings::Boolean fuckmode{ "misc.fuckmode", "false" }; @@ -31,6 +31,7 @@ static settings::Boolean fuckmode{ "misc.fuckmode", "false" }; class CMoveData; namespace engine_prediction { +static Vector original_origin; void RunEnginePrediction(IClientEntity *ent, CUserCmd *ucmd) { @@ -51,6 +52,8 @@ void RunEnginePrediction(IClientEntity *ent, CUserCmd *ucmd) // Backup float frameTime = g_GlobalVars->frametime; float curTime = g_GlobalVars->curtime; + int tickcount = g_GlobalVars->tickcount; + original_origin = ent->GetAbsOrigin(); CUserCmd defaultCmd{}; if (ucmd == nullptr) @@ -79,11 +82,19 @@ void RunEnginePrediction(IClientEntity *ent, CUserCmd *ucmd) g_GlobalVars->frametime = frameTime; g_GlobalVars->curtime = curTime; + g_GlobalVars->tickcount = tickcount; // Adjust tickbase NET_INT(ent, netvar.nTickBase)++; + return; } +// Restore Origin +void FinishEnginePrediction(IClientEntity *ent, CUserCmd *ucmd) +{ + const_cast(ent->GetAbsOrigin()) = original_origin; + original_origin.Invalidate(); +} } // namespace engine_prediction void PrecalculateCanShoot() @@ -317,8 +328,12 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, CUs { PROF_SECTION(CM_WRAPPER); EC::run(EC::CreateMove_NoEnginePred); + if (engine_pred) + { engine_prediction::RunEnginePrediction(RAW_ENT(LOCAL_E), current_user_cmd); + g_pLocalPlayer->UpdateEye(); + } EC::run(EC::CreateMove); } @@ -464,6 +479,12 @@ DEFINE_HOOKED_METHOD(CreateMoveInput, void, IInput *this_, int sequence_nr, floa // Run EC EC::run(EC::CreateMoveLate); + if (CE_GOOD(LOCAL_E)) + { + // Restore prediction + if (engine_prediction::original_origin.IsValid()) + engine_prediction::FinishEnginePrediction(RAW_ENT(LOCAL_E), current_late_user_cmd); + } // Write the usercmd WriteCmd(this_, current_late_user_cmd, sequence_nr); } diff --git a/src/hooks/Think.cpp b/src/hooks/Think.cpp new file mode 100644 index 00000000..165bcd6d --- /dev/null +++ b/src/hooks/Think.cpp @@ -0,0 +1,28 @@ +#include "HookedMethods.hpp" + +extern settings::Boolean engine_pred; +namespace hooked_methods +{ +// Update Prediction, Used by warp/Doubletap aswell +void UpdatePred() +{ + if (isHackActive() && g_IEngine->IsInGame() && CE_GOOD(LOCAL_E) && engine_pred) + { + int signon_state = *(int *) (*(unsigned *) &g_IBaseClientState + 304); + int m_nDeltaTick = *(int *) (*(unsigned *) &g_IBaseClientState + 408); + int lastoutgoingcommand = *(int *) (*(unsigned *) &g_IBaseClientState + offsets::lastoutgoingcommand()); + int chokedcommands = *(int *) (*(unsigned *) &g_IBaseClientState + offsets::lastoutgoingcommand() + 4); + int last_command_ack = *(int *) (*(unsigned *) &g_IBaseClientState + offsets::lastoutgoingcommand() + 8); + + // Only run if fully connected + if (signon_state == 6 && m_nDeltaTick > 0) + g_IPrediction->Update(m_nDeltaTick ? m_nDeltaTick + 1 : 0, m_nDeltaTick > 0, last_command_ack, lastoutgoingcommand + chokedcommands); + } +} +DEFINE_HOOKED_METHOD(Think, void, IToolFrameworkInternal *_this, bool finaltick) +{ + UpdatePred(); + return original::Think(_this, finaltick); +} + +} // namespace hooked_methods diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 6c4bd9d5..05d9ba27 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -156,6 +156,11 @@ void LocalPlayer::Update() } } +void LocalPlayer::UpdateEye() +{ + v_Eye = entity->m_vecOrigin() + CE_VECTOR(entity, netvar.vViewOffset); +} + void LocalPlayer::UpdateEnd() { if (!isFakeAngleCM) diff --git a/src/navparser.cpp b/src/navparser.cpp index 4d467915..31496ffb 100644 --- a/src/navparser.cpp +++ b/src/navparser.cpp @@ -807,7 +807,7 @@ static void drawcrumbs() #endif static InitRoutine runinit([]() { - EC::Register(EC::CreateMove, cm, "cm_navparser", EC::average); + EC::Register(EC::CreateMove_NoEnginePred, cm, "cm_navparser", EC::average); #if ENABLE_VISUALS EC::Register(EC::Draw, drawcrumbs, "draw_navparser", EC::average); #endif