From d259fbacd045892b749268d4cbcf3f38dbb6daf2 Mon Sep 17 00:00:00 2001 From: BenCat07 Date: Sun, 17 May 2020 17:40:00 +0200 Subject: [PATCH] Alot of warp related stuff (see description) - Add a speed meter - Smoothen Warp Drastically - GIve full control while in warp (Especially useful for bots) - Rewrite the peek mode - Add 22 tick fakelag (as a sideeffect) --- data/menu/nullifiedcat/antiaim.xml | 2 +- data/menu/nullifiedcat/movement.xml | 1 + include/sdk/netmessage.hpp | 23 ++- src/hacks/Warp.cpp | 255 +++++++++++++++++++++------- src/sdk/netmessage.cpp | 5 +- 5 files changed, 217 insertions(+), 69 deletions(-) diff --git a/data/menu/nullifiedcat/antiaim.xml b/data/menu/nullifiedcat/antiaim.xml index 8d24536e..6cbe4109 100755 --- a/data/menu/nullifiedcat/antiaim.xml +++ b/data/menu/nullifiedcat/antiaim.xml @@ -5,7 +5,7 @@ - + diff --git a/data/menu/nullifiedcat/movement.xml b/data/menu/nullifiedcat/movement.xml index 6f3ac2f9..169343f4 100755 --- a/data/menu/nullifiedcat/movement.xml +++ b/data/menu/nullifiedcat/movement.xml @@ -59,6 +59,7 @@ + diff --git a/include/sdk/netmessage.hpp b/include/sdk/netmessage.hpp index b1ddad4a..626e9141 100644 --- a/include/sdk/netmessage.hpp +++ b/include/sdk/netmessage.hpp @@ -14,6 +14,7 @@ #include #include #include "bitvec.h" +#include "CSignature.h" #define DECLARE_BASE_MESSAGE(msgtype) \ public: \ @@ -98,6 +99,26 @@ public: return false; }; // no handler set +public: + // I don't get what it does but we need it + virtual bool BIncomingMessageForProcessing(double param_1, int param_2) + { + // Call original to be sure nothing breaks + typedef bool (*BIncomingMessageForProcessing_t)(CNetMessage *, double, int); + static auto addr = gSignatures.GetEngineSignature("55 89 E5 56 53 83 EC 10 8B 5D ? F2 0F 10 45"); + BIncomingMessageForProcessing_t BIncomingMessageForProcessing_fn = (BIncomingMessageForProcessing_t)addr; + return BIncomingMessageForProcessing_fn(this, param_1, param_2); + }; + // I don't get what it does but we need it + virtual void SetRatePolicy() + { + // Call original to be sure nothing breaks + typedef bool (*SetRatePolicy_t)(CNetMessage *); + static auto addr = gSignatures.GetEngineSignature("55 89 E5 83 EC 18 C7 04 24 2C 00 00 00"); + SetRatePolicy_t SetRatePolicy_fn = (SetRatePolicy_t)addr; + SetRatePolicy_fn(this); + }; + protected: bool m_bReliable; // true if message should be send reliable INetChannel *m_NetChannel; // netchannel this message is from/for @@ -177,7 +198,7 @@ protected: #define MAX_OSPATH 260 -#define NETMSG_TYPE_BITS 5 +#define NETMSG_TYPE_BITS 6 typedef int QueryCvarCookie_t; typedef enum { diff --git a/src/hacks/Warp.cpp b/src/hacks/Warp.cpp index 228ddc2e..00b351e1 100644 --- a/src/hacks/Warp.cpp +++ b/src/hacks/Warp.cpp @@ -11,10 +11,12 @@ #endif #include "MiscAimbot.hpp" #include "PlayerTools.hpp" +#include "DetourHook.hpp" namespace hacks::tf2::warp { static settings::Boolean enabled{ "warp.enabled", "false" }; +static settings::Float speed{ "warp.speed", "10" }; static settings::Boolean draw{ "warp.draw", "false" }; static settings::Button warp_key{ "warp.key", "" }; static settings::Boolean charge_passively{ "warp.charge-passively", "true" }; @@ -34,63 +36,73 @@ 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 bool should_charge = false; -static int warp_amount = 0; -static int warp_amount_override = 0; -static int warp_override_one_tick = 0; -static bool charged = false; - -// Taken from MrSteyk -class clc_move_proto -{ -public: - int VTable; - char reliable; - int netchan; - int field_C; - int field_10; - int m_nBackupCommands; - int m_nNewCommands; - int m_nLength; - bf_write m_DataIn; - bf_write m_DataOut; -}; +static bool should_charge = false; +static int warp_amount = 0; +static int warp_amount_override = 0; +static bool charged = false; +// How many ticks of excess we have (for decimal speeds) +float excess_ticks = 0.0f; int GetWarpAmount() { static auto sv_max_dropped_packets_to_process = g_ICvar->FindVar("sv_max_dropped_packets_to_process"); - return warp_override_one_tick ? warp_override_one_tick : sv_max_dropped_packets_to_process->GetInt(); + float warp_amount_preprocessed = *speed; + // Store excess + excess_ticks += warp_amount_preprocessed - std::floor(warp_amount_preprocessed); + + // How many ticks to warp, add excess too + int warp_amount_processed = std::floor(warp_amount_preprocessed) + std::floor(excess_ticks); + + // Remove the used amount from excess + excess_ticks -= std::floor(excess_ticks); + + // Return smallest of the two + return std::min(warp_amount_processed, sv_max_dropped_packets_to_process->GetInt()); } static bool should_warp = true; static bool was_hurt = false; -// Warping part -void Warp() +DetourHook cl_move_detour; +typedef void (*CL_Move_t)(float accumulated_extra_samples, bool bFinalTick); + +// Warping part, uses CL_Move +void Warp(float accumulated_extra_samples, bool finalTick) { auto ch = g_IEngine->GetNetChannelInfo(); if (!ch) return; if (!should_warp) { - should_warp = true; + if (finalTick) + should_warp = true; return; } - int &m_nOutSequenceNr = *(int *) ((uintptr_t) ch + offsets::m_nOutSequenceNr()); int warp_ticks = warp_amount; if (warp_amount_override) warp_ticks = warp_amount_override; - // Don' add more than the warp_ticks - m_nOutSequenceNr += std::min(warp_ticks, GetWarpAmount()); - warp_amount -= std::min(warp_ticks, GetWarpAmount()); - warp_ticks -= std::min(warp_ticks, GetWarpAmount()); + CL_Move_t original = (CL_Move_t) cl_move_detour.GetOriginalFunc(); + + // Call CL_Move once for every warp tick + int warp_amnt = GetWarpAmount(); + for (int i = 0; i <= std::min(warp_ticks, warp_amnt); i++) + { + original(accumulated_extra_samples, finalTick); + // Only decrease ticks for the final CL_Move tick + if (finalTick) + { + warp_amount--; + warp_ticks--; + } + } + + cl_move_detour.RestorePatch(); + if (warp_amount_override) warp_amount_override = warp_ticks; - // Don't attack while warping - current_user_cmd->buttons &= ~IN_ATTACK; if (warp_ticks <= 0) { was_hurt = false; @@ -122,7 +134,7 @@ void SendNetMessage(INetMessage &msg) if (should_charge && !charged) { int ticks = GetMaxWarpTicks(); - auto movemsg = (clc_move_proto *) &msg; + auto movemsg = (CLC_Move *) &msg; // Just null it :shrug: movemsg->m_nBackupCommands = 0; movemsg->m_nNewCommands = 0; @@ -138,13 +150,6 @@ void SendNetMessage(INetMessage &msg) charged = true; } } - // Warp - if ((warp_key.isKeyDown() || was_hurt) && warp_amount) - { - Warp(); - if (warp_amount < GetMaxWarpTicks()) - charged = false; - } } should_charge = false; } @@ -165,7 +170,19 @@ enum charge_state DONE }; -charge_state current_state = ATTACK; +enum peek_state +{ + IDLE = 0, + MOVE_TOWARDS, + MOVE_BACK, + STOP +}; + +charge_state current_state = ATTACK; +peek_state current_peek_state = IDLE; + +// Used to determine when we should start moving back with peek +static int charge_at_start = 0; // Used to determine when demoknight warp should be over static bool was_overridden = false; @@ -175,11 +192,11 @@ void CreateMove() return; if (CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer()) return; - warp_override_one_tick = 0; if (!warp_key.isKeyDown() && !was_hurt) { - warp_last_tick = false; - current_state = ATTACK; + warp_last_tick = false; + current_state = ATTACK; + current_peek_state = IDLE; Vector velocity{}; velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), velocity); @@ -329,34 +346,59 @@ void CreateMove() // Warp peaking else if (warp_peek) { - // We have Warp - if (warp_amount) + switch (current_peek_state) { - // Warped last tick, time to reverse - if (warp_last_tick) - { - // Wait 1 tick before warping back - if (should_warp && !should_warp_last_tick) - { - should_warp_last_tick = true; - should_warp = false; - } - else - should_warp_last_tick = false; + case IDLE: + { + // Not doing anything, update warp amount + charge_at_start = warp_amount; - // Inverse direction - current_user_cmd->forwardmove = -current_user_cmd->forwardmove; - current_user_cmd->sidemove = -current_user_cmd->sidemove; - } + Vector vel; + velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), vel); + + // if we move more than 1.0 HU/s , go to move towards statement... + if (!vel.IsZero(1.0f)) + current_peek_state = MOVE_TOWARDS; + // ...else don't warp else - warp_override_one_tick = warp_amount / 2; - warp_last_tick = true; + { + should_warp = false; + break; + } + + // No "break;" here is intentional :) } - // Prevent movement so you don't overshoot when you don't want to - else + case MOVE_TOWARDS: { + // Just wait until we used about half of our warp, then we can start going back + if (warp_amount <= charge_at_start / 2.0f) + current_peek_state = MOVE_BACK; + break; + } + case MOVE_BACK: + { + // Inverse direction if we still have warp left + if (warp_amount) + { + current_user_cmd->forwardmove *= -1.0f; + current_user_cmd->sidemove *= -1.0f; + break; + } + // ... Else we stop in our tracks + else + current_peek_state = STOP; + + // Once again, intentionally missing "break;" + } + case STOP: + { + // Stop dead in our tracks while key is still held current_user_cmd->forwardmove = 0.0f; current_user_cmd->sidemove = 0.0f; + break; + } + default: + break; } } was_hurt_last_tick = was_hurt; @@ -438,12 +480,93 @@ void rvarCallback(settings::VariableBase &, bool) yaw_selections.push_back(90.0f); } +DetourHook cl_sendmove_detour; +typedef void (*CL_SendMove_t)(); +void CL_SendMove_hook() +{ + byte data[4000]; + + // the +4 one is choked commands + int nextcommandnr = NET_INT(g_IBaseClientState, offsets::lastoutgoingcommand()) + NET_INT(g_IBaseClientState, offsets::lastoutgoingcommand() + 4) + 1; + + // send the client update packet + + CLC_Move moveMsg; + + moveMsg.m_DataOut.StartWriting(data, sizeof(data)); + + // Determine number of backup commands to send along + int cl_cmdbackup = 2; + + // How many real new commands have queued up + moveMsg.m_nNewCommands = 1 + NET_INT(g_IBaseClientState, offsets::lastoutgoingcommand() + 4); + moveMsg.m_nNewCommands = std::clamp(moveMsg.m_nNewCommands, 0, 15); + + // Excessive commands (Used for longer fakelag, credits to https://www.unknowncheats.me/forum/source-engine/370916-23-tick-guwop-fakelag-break-lag-compensation-running.html) + int extra_commands = NET_INT(g_IBaseClientState, offsets::lastoutgoingcommand() + 4) + 1 - moveMsg.m_nNewCommands; + cl_cmdbackup = std::max(2, extra_commands); + moveMsg.m_nBackupCommands = std::clamp(cl_cmdbackup, 0, 7); + + int numcmds = moveMsg.m_nNewCommands + moveMsg.m_nBackupCommands; + + int from = -1; // first command is deltaed against zeros + + bool bOK = true; + + for (int to = nextcommandnr - numcmds + 1; to <= nextcommandnr; to++) + { + bool isnewcmd = to >= (nextcommandnr - moveMsg.m_nNewCommands + 1); + + // Call the write to buffer + typedef bool (*WriteUsercmdDeltaToBuffer_t)(IBaseClientDLL *, bf_write *, int, int, bool); + + // first valid command number is 1 + bOK = bOK && vfunc(g_IBaseClient, offsets::PlatformOffset(23, offsets::undefined, offsets::undefined), 0)(g_IBaseClient, &moveMsg.m_DataOut, from, to, isnewcmd); + from = to; + } + + if (bOK) + { + // Make fakelag work as we want it to + if (extra_commands > 0) + ((INetChannel *) g_IEngine->GetNetChannelInfo())->m_nChokedPackets -= extra_commands; + + // only write message if all usercmds were written correctly, otherwise parsing would fail + ((INetChannel *) g_IEngine->GetNetChannelInfo())->SendNetMsg(moveMsg); + } +} + +void CL_Move_hook(float accumulated_extra_samples, bool bFinalTick) +{ + CL_Move_t original = (CL_Move_t) cl_move_detour.GetOriginalFunc(); + original(accumulated_extra_samples, bFinalTick); + cl_move_detour.RestorePatch(); + + // Should we warp? + if ((warp_key.isKeyDown() || was_hurt) && warp_amount) + { + Warp(accumulated_extra_samples, bFinalTick); + if (warp_amount < GetMaxWarpTicks()) + charged = false; + } +} + static InitRoutine init([]() { + static auto cl_sendmove_addr = gSignatures.GetEngineSignature("55 89 E5 57 56 53 81 EC 2C 10 00 00 C6 85 ? ? ? ? 01"); + cl_sendmove_detour.Init(cl_sendmove_addr, (void *) CL_SendMove_hook); + static auto cl_move_addr = gSignatures.GetEngineSignature("55 89 E5 57 56 53 81 EC 9C 00 00 00 83 3D ? ? ? ? 01"); + cl_move_detour.Init(cl_move_addr, (void *) CL_Move_hook); + EC::Register(EC::LevelShutdown, LevelShutdown, "warp_levelshutdown"); EC::Register(EC::CreateMove, CreateMove, "warp_createmove", EC::very_late); g_IEventManager2->AddListener(&listener, "player_hurt", false); EC::Register( - EC::Shutdown, []() { g_IEventManager2->RemoveListener(&listener); }, "warp_shutdown"); + EC::Shutdown, + []() { + g_IEventManager2->RemoveListener(&listener); + cl_sendmove_detour.Shutdown(); + }, + "warp_shutdown"); warp_forward.installChangeCallback(rvarCallback); warp_backwards.installChangeCallback(rvarCallback); warp_left.installChangeCallback(rvarCallback); diff --git a/src/sdk/netmessage.cpp b/src/sdk/netmessage.cpp index 92d51c15..7cf3832a 100644 --- a/src/sdk/netmessage.cpp +++ b/src/sdk/netmessage.cpp @@ -20,6 +20,8 @@ bf_write::bf_write() m_pDebugName = NULL; } +static char s_text[1024]; + unsigned long g_LittleBits[32]; // Precalculated bit masks for WriteUBitLong. Using these tables instead of @@ -498,7 +500,8 @@ const char *CLC_ListenEvents::ToString(void) const const char *CLC_Move::ToString(void) const { - return strfmt("%s: backup %i, new %i, bytes %i", GetName(), m_nNewCommands, m_nBackupCommands, Bits2Bytes(m_nLength)).release(); + Q_snprintf(s_text, sizeof(s_text), "%s: backup %i, new %i, bytes %i", GetName(), m_nNewCommands, m_nBackupCommands, Bits2Bytes(m_nLength)); + return s_text; } bool CLC_Move::WriteToBuffer(bf_write &buffer)