diff --git a/data/menu/nullifiedcat/warp.xml b/data/menu/nullifiedcat/warp.xml index 7b196cac..c51f31b3 100644 --- a/data/menu/nullifiedcat/warp.xml +++ b/data/menu/nullifiedcat/warp.xml @@ -5,7 +5,10 @@ - + + + + @@ -25,6 +28,8 @@ + + @@ -35,6 +40,14 @@ + + + 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/hacks/Warp.hpp b/include/hacks/Warp.hpp index 920cf2c7..6955efba 100644 --- a/include/hacks/Warp.hpp +++ b/include/hacks/Warp.hpp @@ -3,6 +3,8 @@ class INetMessage; namespace hacks::tf2::warp { +extern bool in_rapidfire; +extern bool in_warp; void SendNetMessage(INetMessage &msg); void CL_SendMove_hook(); } // namespace hacks::tf2::warp diff --git a/include/helpers.hpp b/include/helpers.hpp index 5a6638d6..99474f0b 100644 --- a/include/helpers.hpp +++ b/include/helpers.hpp @@ -121,6 +121,7 @@ Vector getShootPos(Vector angle); Vector GetForwardVector(Vector origin, Vector viewangles, float distance, CachedEntity *punch_entity = nullptr); Vector GetForwardVector(float distance, CachedEntity *punch_entity = nullptr); CachedEntity *getClosestEntity(Vector vec); +CachedEntity *getClosestNonlocalEntity(Vector vec); bool IsSentryBuster(CachedEntity *ent); std::unique_ptr strfmt(const char *fmt, ...); // TODO move that to weaponid.h @@ -218,7 +219,7 @@ template void format_internal(std::stringstream stream << value; format_internal(stream, args...); } -template std::string format(const Args &... args) +template std::string format(const Args &...args) { std::stringstream stream; format_internal(stream, args...); 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..435b6184 100644 --- a/include/hooks/HookTools.hpp +++ b/include/hooks/HookTools.hpp @@ -15,10 +15,13 @@ 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*/ CreateMoveEarly, + /* Note: This will replace the normal CreateMove when we are warping. Used for performance purposes. */ + CreateMoveWarp, #if ENABLE_VISUALS Draw, #endif 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..b8634f07 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) { @@ -163,6 +164,7 @@ void CreateInterfaces() g_IPanel = BruteforceInterface("VGUI_Panel", sharedobj::vgui2()); g_pUniformStream = **(IUniformRandomStream ***) (gSignatures.GetVstdSignature("A3 ? ? ? ? C3 89 F6") + 0x1); + g_IToolFramework = BruteforceInterface("VTOOLFRAMEWORKVERSION", sharedobj::engine()); #if ENABLE_VISUALS g_IVDebugOverlay = BruteforceInterface("VDebugOverlay", sharedobj::engine()); g_ISurface = BruteforceInterface("VGUI_Surface", sharedobj::vguimatsurface()); 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/Aimbot.cpp b/src/hacks/Aimbot.cpp index ba7da296..3d8dad2d 100644 --- a/src/hacks/Aimbot.cpp +++ b/src/hacks/Aimbot.cpp @@ -1594,6 +1594,7 @@ static InitRoutine EC([]() { EC::Register(EC::LevelInit, Reset, "INIT_Aimbot", EC::average); EC::Register(EC::LevelShutdown, Reset, "RESET_Aimbot", EC::average); EC::Register(EC::CreateMove, CreateMove, "CM_Aimbot", EC::late); + EC::Register(EC::CreateMoveWarp, CreateMove, "CMW_Aimbot", EC::late); #if ENABLE_VISUALS EC::Register(EC::Draw, DrawText, "DRAW_Aimbot", EC::average); #endif diff --git a/src/hacks/AntiAntiAim.cpp b/src/hacks/AntiAntiAim.cpp index 7c383c97..3ccebfb4 100644 --- a/src/hacks/AntiAntiAim.cpp +++ b/src/hacks/AntiAntiAim.cpp @@ -14,7 +14,7 @@ static settings::Boolean debug{ "anti-anti-aim.debug.enable", "false" }; std::unordered_map resolver_map; std::array sniperdot_array; -static inline void modifyAnlges() +static inline void modifyAngles() { for (int i = 1; i <= g_IEngine->GetMaxClients(); i++) { @@ -55,7 +55,7 @@ void frameStageNotify(ClientFrameStage_t stage) return; if (stage == FRAME_NET_UPDATE_POSTDATAUPDATE_START) { - modifyAnlges(); + modifyAngles(); } #endif } @@ -259,8 +259,10 @@ static InitRoutine init([]() { hook(); EC::Register(EC::Shutdown, shutdown, "antiantiaim_shutdown"); EC::Register(EC::CreateMove, CreateMove, "cm_antiantiaim"); + EC::Register(EC::CreateMoveWarp, CreateMove, "cmw_antiantiaim"); #if ENABLE_TEXTMODE - EC::Register(EC::CreateMove, modifyAnlges, "cm_textmodeantiantiaim"); + EC::Register(EC::CreateMove, modifyAngles, "cm_textmodeantiantiaim"); + EC::Register(EC::CreateMoveWarp, modifyAngles, "cmw_textmodeantiantiaim"); #endif }); } // namespace hacks::shared::anti_anti_aim diff --git a/src/hacks/AntiBackstab.cpp b/src/hacks/AntiBackstab.cpp index 1f7c132e..f577fc02 100644 --- a/src/hacks/AntiBackstab.cpp +++ b/src/hacks/AntiBackstab.cpp @@ -133,5 +133,8 @@ void CreateMove() noaa = false; } -static InitRoutine EC([]() { EC::Register(EC::CreateMove, CreateMove, "antibackstab", EC::late); }); +static InitRoutine EC([]() { + EC::Register(EC::CreateMove, CreateMove, "antibackstab", EC::late); + EC::Register(EC::CreateMoveWarp, CreateMove, "antibackstab_w", EC::late); +}); } // namespace hacks::tf2::antibackstab diff --git a/src/hacks/AntiDisguise.cpp b/src/hacks/AntiDisguise.cpp index 67032543..3d82d66d 100644 --- a/src/hacks/AntiDisguise.cpp +++ b/src/hacks/AntiDisguise.cpp @@ -35,5 +35,8 @@ void cm() } } } -static InitRoutine EC([]() { EC::Register(EC::CreateMove, cm, "antidisguise", EC::average); }); +static InitRoutine EC([]() { + EC::Register(EC::CreateMove, cm, "antidisguise", EC::average); + EC::Register(EC::CreateMoveWarp, cm, "antidisguise_w", EC::average); +}); } // namespace hacks::tf2::antidisguise diff --git a/src/hacks/AutoBackstab.cpp b/src/hacks/AutoBackstab.cpp index dd1c8aa9..5ec6425a 100644 --- a/src/hacks/AutoBackstab.cpp +++ b/src/hacks/AutoBackstab.cpp @@ -356,5 +356,8 @@ void CreateMove() } } -static InitRoutine EC([]() { EC::Register(EC::CreateMove, CreateMove, "autobackstab", EC::average); }); +static InitRoutine EC([]() { + EC::Register(EC::CreateMove, CreateMove, "autobackstab", EC::average); + EC::Register(EC::CreateMoveWarp, CreateMove, "autobackstab_w", EC::average); +}); } // namespace hacks::tf2::autobackstab diff --git a/src/hacks/AutoReflect.cpp b/src/hacks/AutoReflect.cpp index c55d8ccc..82d99c24 100644 --- a/src/hacks/AutoReflect.cpp +++ b/src/hacks/AutoReflect.cpp @@ -238,6 +238,7 @@ void Draw() static InitRoutine EC([]() { EC::Register(EC::CreateMove, CreateMove, "cm_auto_reflect", EC::average); + EC::Register(EC::CreateMoveWarp, CreateMove, "cmw_auto_reflect", EC::average); #if ENABLE_VISUALS EC::Register(EC::Draw, Draw, "draw_auto_reflect", EC::average); #endif diff --git a/src/hacks/Backtrack.cpp b/src/hacks/Backtrack.cpp index e155fce7..7796aa85 100644 --- a/src/hacks/Backtrack.cpp +++ b/src/hacks/Backtrack.cpp @@ -549,7 +549,9 @@ std::optional> getClosestTick(Vector ve static InitRoutine init([]() { EC::Register(EC::CreateMove, CreateMove, "backtrack_cm", EC::early); + EC::Register(EC::CreateMoveWarp, CreateMove, "backtrack_cmw", EC::early); EC::Register(EC::CreateMove, CreateMoveLate, "backtrack_cmlate", EC::very_late); + EC::Register(EC::CreateMoveWarp, CreateMoveLate, "backtrack_cmwlate", EC::very_late); #if ENABLE_VISUALS EC::Register(EC::Draw, Draw, "backtrack_draw"); #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/Misc.cpp b/src/hacks/Misc.cpp index 56bf915a..3345f797 100644 --- a/src/hacks/Misc.cpp +++ b/src/hacks/Misc.cpp @@ -960,6 +960,7 @@ static InitRoutine init([]() { teammatesPushaway = g_ICvar->FindVar("tf_avoidteammates_pushaway"); EC::Register(EC::Shutdown, Shutdown, "draw_local_player", EC::average); EC::Register(EC::CreateMove, CreateMove, "cm_misc_hacks", EC::average); + EC::Register(EC::CreateMoveWarp, CreateMove, "cmw_misc_hacks", EC::average); #if ENABLE_VISUALS EC::Register(EC::Draw, Draw, "draw_misc_hacks", EC::average); #if !ENFORCE_STREAM_SAFETY diff --git a/src/hacks/MiscAimbot.cpp b/src/hacks/MiscAimbot.cpp index 98c28221..bd72ba1e 100644 --- a/src/hacks/MiscAimbot.cpp +++ b/src/hacks/MiscAimbot.cpp @@ -589,6 +589,7 @@ float CAM_CapYaw_Hook(IInput *this_, float fVal) #define foffset(p, i) ((unsigned char *) &p)[i] static InitRoutine init([]() { EC::Register(EC::CreateMove, CreateMove, "cm_miscaimbot", EC::average); + EC::Register(EC::CreateMoveWarp, CreateMove, "cmw_miscaimbot", EC::average); static auto signature = gSignatures.GetClientSignature("55 89 E5 53 83 EC 14 E8 ? ? ? ? 85 C0 74 ? 8D 98 ? ? ? ? C7 44 24 ? 11 00 00 00"); diff --git a/src/hacks/NavBot.cpp b/src/hacks/NavBot.cpp index 4fc0ee0d..c1d99f14 100644 --- a/src/hacks/NavBot.cpp +++ b/src/hacks/NavBot.cpp @@ -1395,6 +1395,7 @@ ObjectDestroyListener &listener() static InitRoutine runinit([]() { g_IEventManager2->AddListener(&listener(), "object_destroyed", false); EC::Register(EC::CreateMove, CreateMove, "navbot", EC::early); + EC::Register(EC::CreateMoveWarp, CreateMove, "navbot_w", EC::early); EC::Register( EC::Shutdown, []() { g_IEventManager2->RemoveListener(&listener()); }, "navbot_shutdown"); }); diff --git a/src/hacks/Trigger.cpp b/src/hacks/Trigger.cpp index 7b638661..f76b0697 100644 --- a/src/hacks/Trigger.cpp +++ b/src/hacks/Trigger.cpp @@ -627,5 +627,8 @@ void Draw() { } -static InitRoutine EC([]() { EC::Register(EC::CreateMove, CreateMove, "triggerbot", EC::average); }); +static InitRoutine EC([]() { + EC::Register(EC::CreateMove, CreateMove, "triggerbot", EC::average); + EC::Register(EC::CreateMoveWarp, CreateMove, "triggerbot_w", EC::average); +}); } // namespace hacks::shared::triggerbot 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..871a9c83 100644 --- a/src/hacks/Warp.cpp +++ b/src/hacks/Warp.cpp @@ -14,17 +14,22 @@ #include "DetourHook.hpp" #include "WeaponData.hpp" #include "MiscTemporary.hpp" +#include "Think.hpp" namespace hacks::tf2::warp { static settings::Boolean enabled{ "warp.enabled", "false" }; static settings::Boolean no_movement{ "warp.rapidfire.no-movement", "true" }; static settings::Boolean rapidfire{ "warp.rapidfire", "false" }; +static settings::Int distance{ "warp.rapidfire.distance", "0" }; +static settings::Boolean rapidfire_zoom{ "warp.rapidfire.zoom", "true" }; static settings::Boolean wait_full{ "warp.rapidfire.wait-full", "true" }; static settings::Button rapidfire_key{ "warp.rapidfire.key", "" }; static settings::Int rapidfire_key_mode{ "warp.rapidfire.key-mode", "1" }; +static settings::Int rf_disable_on{ "warp.rapidfire.disable-on", "0" }; static settings::Float speed{ "warp.speed", "23" }; static settings::Boolean draw{ "warp.draw", "false" }; +static settings::Boolean draw_bar{ "warp.draw-bar", "false" }; static settings::Button warp_key{ "warp.key", "" }; static settings::Button charge_key{ "warp.charge-key", "" }; static settings::Boolean charge_passively{ "warp.charge-passively", "true" }; @@ -42,13 +47,16 @@ static settings::Boolean warp_right{ "warp.on-hit.right", "true" }; // Hidden control rvars for communtiy servers static settings::Int maxusrcmdprocessticks("warp.maxusrcmdprocessticks", "24"); -bool in_warp = false; -bool in_rapidfire = false; +bool in_warp = false; +bool in_rapidfire = false; +bool in_rapidfire_zoom = false; // Should we choke the packet or not? (in rapidfire) bool choke_packet = false; // Were we warping last tick? // why is this needed at all, why do i have to write this janky bs bool was_in_warp = false; +// Is this the first warp tick? +bool first_warp_tick = false; // How many ticks we have to add to our CreateMove packet int ticks_to_add = 0; @@ -60,6 +68,34 @@ void warpLogic(); static settings::Int size{ "warp.bar-size", "100" }; static settings::Int bar_x{ "warp.bar-x", "50" }; static settings::Int bar_y{ "warp.bar-y", "200" }; +static settings::Int draw_string_x{ "warp.draw-info.x", "8" }; +static settings::Int draw_string_y{ "warp.draw-info.y", "800" }; + +// Need our own Text drawing +static std::array warp_strings; +static size_t warp_strings_count{ 0 }; +static std::array warp_strings_colors{ colors::empty }; + +void AddWarpString(const std::string &string, const rgba_t &color) +{ + warp_strings[warp_strings_count] = string; + warp_strings_colors[warp_strings_count] = color; + ++warp_strings_count; +} + +void DrawWarpStrings() +{ + float x = *draw_string_x; + float y = *draw_string_y; + for (size_t i = 0; i < warp_strings_count; ++i) + { + float sx, sy; + fonts::menu->stringSize(warp_strings[i], &sx, &sy); + draw::String(x, y, warp_strings_colors[i], warp_strings[i].c_str(), *fonts::center_screen); + y += fonts::center_screen->size + 1; + } + warp_strings_count = 0; +} static bool should_charge = false; static int warp_amount = 0; @@ -109,6 +145,39 @@ 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 canInstaZoom() +{ + return in_rapidfire_zoom || (g_pLocalPlayer->holding_sniper_rifle && current_user_cmd->buttons & IN_ATTACK2 && !HasCondition(LOCAL_E) && CE_FLOAT(LOCAL_W, netvar.flNextSecondaryAttack) <= g_GlobalVars->curtime); +} + +// This is needed in order to make zoom/unzoom smooth even with insta zoom +static int ignore_ticks = 0; + +void handleSniper() +{ + // Prevent unzooming + if (in_rapidfire) + { + // Holding ready sniper rifle + if (canInstaZoom()) + { + current_user_cmd->buttons &= ~IN_ATTACK2; + ignore_ticks = TIME_TO_TICKS(0.2f); + } + } + else if (ignore_ticks) + { + ignore_ticks--; + current_user_cmd->buttons &= ~IN_ATTACK2; + } +} + bool shouldRapidfire() { if (!rapidfire) @@ -138,9 +207,16 @@ bool shouldRapidfire() if (LOCAL_W->m_iClassID() == CL_CLASS(CTFMinigun) && CE_INT(LOCAL_W, netvar.iWeaponState) != 3 && CE_INT(LOCAL_W, netvar.iWeaponState) != 2) return false; + // Check if enemies are close enough + if (distance) + { + auto closest = getClosestNonlocalEntity(LOCAL_E->m_vecOrigin()); + if (!closest || closest->m_flDistance() > *distance) + 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. @@ -150,6 +226,33 @@ bool shouldRapidfire() if (LOCAL_W->m_iClassID() == CL_CLASS(CTFFlameThrower)) buttons_pressed = current_user_cmd && current_user_cmd->buttons & IN_ATTACK2; + if (g_pLocalPlayer->holding_sniper_rifle) + { + // Run if m2 is pressed and sniper rifle is ready + buttons_pressed = rapidfire_zoom && current_user_cmd && current_user_cmd->buttons & IN_ATTACK2 && canInstaZoom(); + // Heatmaker is the only exception here, it can also run on m1 + if (!buttons_pressed && HasCondition(LOCAL_E)) + buttons_pressed = current_user_cmd && current_user_cmd->buttons & IN_ATTACK; + } + + switch (*rf_disable_on) + { + case 0: // Always on + return buttons_pressed; + case 1: // Disable on projectile + if (g_pLocalPlayer->weapon_mode == weapon_projectile) + return false; + break; + case 2: // Disable on melee + if (g_pLocalPlayer->weapon_mode == weapon_melee) + return false; + break; + case 3: // Disable on projectile and melee + if (g_pLocalPlayer->weapon_mode == weapon_projectile || g_pLocalPlayer->weapon_mode == weapon_melee) + return false; + break; + } + return buttons_pressed; } @@ -175,9 +278,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; @@ -214,6 +325,8 @@ void Warp(float accumulated_extra_samples, bool finalTick) return; } + PROF_SECTION(warp_profiler); + int warp_ticks = warp_amount; if (warp_amount_override) warp_ticks = warp_amount_override; @@ -230,6 +343,10 @@ void Warp(float accumulated_extra_samples, bool finalTick) int packets_sent = 1; for (int i = 0; i < calls; i++) { + if (!i) + first_warp_tick = true; + else + first_warp_tick = false; // Choke unless we sent too many already choke_packet = true; @@ -239,6 +356,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 +465,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() { @@ -416,20 +530,17 @@ void CL_Move_hook(float accumulated_extra_samples, bool bFinalTick) 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; + if (canInstaZoom()) + in_rapidfire_zoom = true; } Warp(accumulated_extra_samples, bFinalTick); if (warp_amount < GetMaxWarpTicks()) charged = false; - in_warp = false; - in_rapidfire = false; - was_in_warp = true; + in_warp = false; + in_rapidfire = false; + in_rapidfire_zoom = false; + was_in_warp = true; } } @@ -449,24 +560,28 @@ 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() -{ - 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() }; +static float original_curtime = 0.0f; - 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; +// Run before prediction so we can do Faststop logic +void CreateMovePrePredict() +{ + // Attempt to stop fast in place to make movement smoother + if (in_rapidfire && no_movement) + FastStop(); + if (in_rapidfire_zoom) + { + float adjusted_curtime = g_GlobalVars->curtime; + // Original curtime we need to use while in here + if (first_warp_tick) + original_curtime = g_GlobalVars->curtime; + + // Update the data + g_pLocalPlayer->bZoomed = true; + g_pLocalPlayer->flZoomBegin = adjusted_curtime; + // Do not exceed headshot time, we can only hs next tick + if (adjusted_curtime - original_curtime > 0.2f) + { + g_pLocalPlayer->flZoomBegin = original_curtime - 0.2f - TICKS_TO_TIME(1); } } } @@ -490,10 +605,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 @@ -507,6 +618,8 @@ void warpLogic() // Handle minigun in rapidfire handleMinigun(); + // Handle sniper in rapidfire + handleSniper(); // Charge logic if (!shouldWarp(false)) @@ -859,25 +972,44 @@ void SendNetMessage(INetMessage &msg) #if ENABLE_VISUALS void Draw() { - if (!enabled || !draw) + if (!enabled) + return; + if (!draw && !draw_bar) return; if (!g_IEngine->IsInGame()) return; if (CE_BAD(LOCAL_E)) return; + if (!LOCAL_E->m_bAlivePlayer()) + return; - float charge_percent = (float) warp_amount / (float) GetMaxWarpTicks(); - // Draw background - static rgba_t background_color = colors::FromRGBA8(96, 96, 96, 150); - float bar_bg_x_size = *size * 2.0f; - float bar_bg_y_size = *size / 5.0f; - draw::Rectangle(*bar_x - 5.0f, *bar_y - 5.0f, bar_bg_x_size + 10.0f, bar_bg_y_size + 10.0f, background_color); - // Draw bar - rgba_t color_bar = colors::orange; - if (GetMaxWarpTicks() == warp_amount) - color_bar = colors::green; - color_bar.a = 100 / 255.0f; - draw::Rectangle(*bar_x, *bar_y, *size * 2.0f * charge_percent, *size / 5.0f, color_bar); + if (draw) + { + rgba_t color = colors::orange; + if (warp_amount == 0) + color = colors::FromRGBA8(128.0f, 128.0f, 128.0f, 255.0f); + else if (GetMaxWarpTicks() == warp_amount) + color = colors::green; + AddWarpString("Shiftable ticks: " + std::to_string(warp_amount), color); + } + + if (draw_bar) + { + float charge_percent = (float) warp_amount / (float) GetMaxWarpTicks(); + // Draw background + static rgba_t background_color = colors::FromRGBA8(96, 96, 96, 150); + float bar_bg_x_size = *size * 2.0f; + float bar_bg_y_size = *size / 5.0f; + draw::Rectangle(*bar_x - 5.0f, *bar_y - 5.0f, bar_bg_x_size + 10.0f, bar_bg_y_size + 10.0f, background_color); + // Draw bar + rgba_t color_bar = colors::orange; + if (GetMaxWarpTicks() == warp_amount) + color_bar = colors::green; + color_bar.a = 100 / 255.0f; + draw::Rectangle(*bar_x, *bar_y, *size * 2.0f * charge_percent, *size / 5.0f, color_bar); + } + + DrawWarpStrings(); } #endif @@ -948,8 +1080,9 @@ 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::CreateMoveWarp, CreateMove, "warp_createmovew", 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..5bf7a776 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -705,6 +705,22 @@ CachedEntity *getClosestEntity(Vector vec) return best_ent; } +CachedEntity *getClosestNonlocalEntity(Vector vec) +{ + float distance = FLT_MAX; + CachedEntity *best_ent = nullptr; + for (int i = 1; i <= g_IEngine->GetMaxClients(); i++) + { + CachedEntity *ent = ENTITY(i); + if (CE_VALID(ent) && ent->m_IDX != g_pLocalPlayer->entity_idx && ent->m_vecDormantOrigin() && ent->m_bAlivePlayer() && ent->m_bEnemy() && vec.DistTo(ent->m_vecOrigin()) < distance) + { + distance = vec.DistTo(*ent->m_vecDormantOrigin()); + best_ent = ent; + } + } + return best_ent; +} + void VectorTransform(const float *in1, const matrix3x4_t &in2, float *out) { out[0] = (in1[0] * in2[0][0] + in1[1] * in2[0][1] + in1[2] * in2[0][2]) + in2[0][3]; @@ -1621,28 +1637,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..d9336441 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() @@ -222,6 +233,8 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, CUs } // PROF_BEGIN(); + // Do not update if in warp, since the entities will stay identical either way + if (!hacks::tf2::warp::in_warp) { PROF_SECTION(EntityCache); entity_cache::Update(); @@ -317,10 +330,17 @@ 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); - EC::run(EC::CreateMove); + if (engine_pred) + { + engine_prediction::RunEnginePrediction(RAW_ENT(LOCAL_E), current_user_cmd); + g_pLocalPlayer->UpdateEye(); + } + + if (hacks::tf2::warp::in_warp) + EC::run(EC::CreateMoveWarp); + else + EC::run(EC::CreateMove); } if (time_replaced) g_GlobalVars->curtime = curtime_old; @@ -464,6 +484,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 diff --git a/src/nospread.cpp b/src/nospread.cpp index 7001e888..d3c0e640 100644 --- a/src/nospread.cpp +++ b/src/nospread.cpp @@ -845,6 +845,41 @@ void FX_FireBullets_hook(IClientEntity *weapon, int player, Vector *origin, Vect }*/ static Timer update_nospread_timer{}; +void CreateMove2() +{ + if (bullet) + { + static auto sv_usercmd_custom_random_seed = g_ICvar->FindVar("sv_usercmd_custom_random_seed"); + if (!sv_usercmd_custom_random_seed) + sv_usercmd_custom_random_seed = g_ICvar->FindVar("sv_usercmd_custom_random_seed"); + + // Server owner decided it would be a great idea to give the user control over the random seed + else if (!sv_usercmd_custom_random_seed->GetBool()) + { + auto seed = MD5_PseudoRandom(current_user_cmd->command_number) & 0x7FFFFFFF; + prediction_seed = *reinterpret_cast(&seed); + use_usercmd_seed = true; + } + // Normal server + else + use_usercmd_seed = false; + + // Synced, mark as such to other modules + if (no_spread_synced == SYNCED) + is_syncing = false; + // Not synced currently, try to sync + if (no_spread_synced == NOT_SYNCED && !bad_mantissa) + { + is_syncing = true; + should_update_time = true; + update_nospread_timer.update(); + } + // Else if mantissa bad, update every 10 mins + else if (no_spread_synced == NOT_SYNCED && update_nospread_timer.test_and_set(10 * 60 * 1000)) + no_spread_synced = CORRECTING; + } +} + static InitRoutine init_bulletnospread([]() { // Get our detour hooks running static auto writeusercmd_addr = gSignatures.GetClientSignature("55 89 E5 57 56 53 83 EC 2C 8B 45 ? 8B 7D ? 8B 5D ? 89 45 ? 8B 40"); @@ -855,42 +890,8 @@ static InitRoutine init_bulletnospread([]() { net_sendpacket_detour.Init(net_sendpacket_addr, (void *) NET_SendPacket_hook);*/ // Register Event callbacks - EC::Register( - EC::CreateMove, - []() { - if (bullet) - { - static auto sv_usercmd_custom_random_seed = g_ICvar->FindVar("sv_usercmd_custom_random_seed"); - if (!sv_usercmd_custom_random_seed) - sv_usercmd_custom_random_seed = g_ICvar->FindVar("sv_usercmd_custom_random_seed"); - - // Server owner decided it would be a great idea to give the user control over the random seed - else if (!sv_usercmd_custom_random_seed->GetBool()) - { - auto seed = MD5_PseudoRandom(current_user_cmd->command_number) & 0x7FFFFFFF; - prediction_seed = *reinterpret_cast(&seed); - use_usercmd_seed = true; - } - // Normal server - else - use_usercmd_seed = false; - - // Synced, mark as such to other modules - if (no_spread_synced == SYNCED) - is_syncing = false; - // Not synced currently, try to sync - if (no_spread_synced == NOT_SYNCED && !bad_mantissa) - { - is_syncing = true; - should_update_time = true; - update_nospread_timer.update(); - } - // Else if mantissa bad, update every 10 mins - else if (no_spread_synced == NOT_SYNCED && update_nospread_timer.test_and_set(10 * 60 * 1000)) - no_spread_synced = CORRECTING; - } - }, - "nospread_createmove2"); + EC::Register(EC::CreateMove, CreateMove2, "nospread_createmove2"); + EC::Register(EC::CreateMoveWarp, CreateMove2, "nospread_createmove2w"); #if ENABLE_VISUALS EC::Register( EC::Draw,