Files
marohook/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Features/CMisc/CMisc.cpp
T

1351 lines
34 KiB
C++

#include "CMisc.hpp"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <mmsystem.h>
#pragma comment( lib , "winmm.lib" )
#include <CS2/SDK/SDK.hpp>
#include <CS2/SDK/Interface/IEngineToClient.hpp>
#include <CS2/SDK/Interface/IGameEvent.hpp>
#include <CS2/SDK/Update/CCSGOInput.hpp>
#include <CS2/SDK/Update/CUserCmd.hpp>
#include <CS2/SDK/Types/CEntityData.hpp>
#include <AndromedaClient/Settings/Settings.hpp>
#include <AndromedaClient/Fonts/CFontManager.hpp>
#include <AndromedaClient/Render/CRenderStackSystem.hpp>
#include <GameClient/CL_Players.hpp>
#include <GameClient/CL_Weapons.hpp>
#include <GameClient/CL_Trace.hpp>
#include <GameClient/CL_Bypass.hpp>
#include <GameClient/CEntityCache/CEntityCache.hpp>
#include <CS2/SDK/Types/CBaseTypes.hpp>
#include <CS2/SDK/FunctionListSDK.hpp>
#include <random>
#include <ImGui/imgui.h>
namespace
{
// Deterministic Valve RNG (matches the game's math::random_seed generator).
class CValveRng
{
public:
auto Seed( int s ) -> void
{
m_State = -std::abs( s );
m_Index = 0;
m_bSeeded = false;
}
auto Generate() -> int
{
if ( !m_bSeeded )
{
auto v = -m_State;
if ( v < 1 )
v = 1;
for ( int j = 39; j >= 0; --j )
{
v = LCG( v );
if ( j < 32 )
m_Table[ j ] = v;
}
m_State = v;
m_Index = m_Table[ 0 ];
m_bSeeded = true;
}
m_State = LCG( m_State );
const auto Index = m_Index / 0x4000000;
m_Index = m_Table[ Index ];
m_Table[ Index ] = m_State;
return m_Index;
}
auto RandomFloat( float Min = 0.f , float Max = 1.f ) -> float
{
const auto Raw = Generate();
const auto Norm = std::fminf( 0.99999988f , static_cast<float>( Raw ) * 4.6566129e-10f );
return Min + Norm * ( Max - Min );
}
private:
static auto LCG( int State ) -> int
{
const auto k = State / 127773;
auto Result = 16807 * ( State - k * 127773 ) - 2836 * k;
if ( Result < 0 )
Result += 2147483647;
return Result;
}
int m_State = 0;
int m_Index = 0;
int m_Table[ 32 ]{};
bool m_bSeeded = false;
};
// Minimal SHA-1 (for computing the spread seed from angles + tick).
class CSha1
{
public:
auto Reset() -> void
{
m_State[ 0 ] = 0x67452301;
m_State[ 1 ] = 0xEFCDAB89;
m_State[ 2 ] = 0x98BADCFE;
m_State[ 3 ] = 0x10325476;
m_State[ 4 ] = 0xC3D2E1F0;
m_Count = 0;
}
auto Update( const void* pData , std::size_t Len ) -> void
{
const auto* pBytes = static_cast<const uint8_t*>( pData );
auto Index = static_cast<std::size_t>( m_Count & 63 );
m_Count += Len;
std::size_t i = 0;
if ( Index )
{
auto PartLen = 64 - Index;
if ( Len >= PartLen )
{
std::memcpy( m_Buffer + Index , pBytes , PartLen );
Transform( m_Buffer );
i = PartLen;
}
else
{
std::memcpy( m_Buffer + Index , pBytes , Len );
return;
}
}
for ( ; i + 64 <= Len; i += 64 )
Transform( pBytes + i );
if ( i < Len )
std::memcpy( m_Buffer , pBytes + i , Len - i );
}
auto Final() -> void
{
uint8_t Padding[ 64 ]{};
Padding[ 0 ] = 0x80;
const auto Index = static_cast<std::size_t>( m_Count & 63 );
const auto PadLen = ( Index < 56 ) ? ( 56 - Index ) : ( 120 - Index );
const auto BitCount = m_Count * 8;
Update( Padding , PadLen );
uint8_t Bits[ 8 ]{};
for ( int i = 0; i < 8; ++i )
Bits[ 7 - i ] = static_cast<uint8_t>( BitCount >> ( i * 8 ) );
Update( Bits , 8 );
for ( int i = 0; i < 5; ++i )
{
m_Digest[ i * 4 + 0 ] = static_cast<uint8_t>( m_State[ i ] >> 24 );
m_Digest[ i * 4 + 1 ] = static_cast<uint8_t>( m_State[ i ] >> 16 );
m_Digest[ i * 4 + 2 ] = static_cast<uint8_t>( m_State[ i ] >> 8 );
m_Digest[ i * 4 + 3 ] = static_cast<uint8_t>( m_State[ i ] );
}
}
auto GetFirstUInt32() const -> uint32_t
{
uint32_t Result;
std::memcpy( &Result , m_Digest , sizeof Result );
return Result;
}
private:
static auto RotL( uint32_t v , int n ) -> uint32_t
{
return ( v << n ) | ( v >> ( 32 - n ) );
}
auto Transform( const uint8_t* pBlock ) -> void
{
uint32_t w[ 80 ]{};
for ( int i = 0; i < 16; ++i )
w[ i ] = static_cast<uint32_t>( pBlock[ i * 4 ] ) << 24 | static_cast<uint32_t>( pBlock[ i * 4 + 1 ] ) << 16 | static_cast<uint32_t>( pBlock[ i * 4 + 2 ] ) << 8 | static_cast<uint32_t>( pBlock[ i * 4 + 3 ] );
for ( int i = 16; i < 80; ++i )
w[ i ] = RotL( w[ i - 3 ] ^ w[ i - 8 ] ^ w[ i - 14 ] ^ w[ i - 16 ] , 1 );
auto a = m_State[ 0 ];
auto b = m_State[ 1 ];
auto c = m_State[ 2 ];
auto d = m_State[ 3 ];
auto e = m_State[ 4 ];
for ( int i = 0; i < 80; ++i )
{
uint32_t f , k;
if ( i < 20 )
{
f = ( b & c ) | ( ( ~b ) & d );
k = 0x5A827999;
}
else if ( i < 40 )
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if ( i < 60 )
{
f = ( b & c ) | ( b & d ) | ( c & d );
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
const auto Temp = RotL( a , 5 ) + f + e + k + w[ i ];
e = d;
d = c;
c = RotL( b , 30 );
b = a;
a = Temp;
}
m_State[ 0 ] += a;
m_State[ 1 ] += b;
m_State[ 2 ] += c;
m_State[ 3 ] += d;
m_State[ 4 ] += e;
}
uint32_t m_State[ 5 ]{};
std::uint64_t m_Count = 0;
uint8_t m_Buffer[ 64 ]{};
uint8_t m_Digest[ 20 ]{};
};
auto NormalizeAngle( float Angle ) -> float
{
return Angle - std::floorf( Angle * 0.0027777778f + 0.5f ) * 360.0f;
}
auto QuantizeAngle( float Angle ) -> float
{
return std::floorf( NormalizeAngle( Angle ) * 2.0f ) * 0.5f;
}
auto GetSpreadSeed( const QAngle& ViewAngles , int Tick ) -> uint32_t
{
struct
{
float Pitch;
float Yaw;
int PlayerRenderTick;
} Buffer{};
Buffer.Pitch = QuantizeAngle( ViewAngles.m_x );
Buffer.Yaw = QuantizeAngle( ViewAngles.m_y );
Buffer.PlayerRenderTick = Tick;
CSha1 Hash;
Hash.Reset();
Hash.Update( &Buffer , 12 );
Hash.Final();
return Hash.GetFirstUInt32();
}
struct SeedSpread2_t
{
float x = 0.f;
float y = 0.f;
};
auto CalculateSeedSpread( int Seed , float Inaccuracy , float Spread , int ItemDefIdx ) -> SeedSpread2_t
{
constexpr auto k_RevolverId = 64;
constexpr auto k_NegevId = 28;
constexpr auto k_TwoPi = 6.2831853f;
CValveRng Rng;
Rng.Seed( Seed );
auto InacR = Rng.RandomFloat( 0.f , 1.f );
const auto InacA = Rng.RandomFloat( 0.f , k_TwoPi );
if ( ItemDefIdx == k_RevolverId )
InacR = 1.f - ( InacR * InacR );
else if ( ItemDefIdx == k_NegevId )
InacR = 1.f - ( InacR * InacR );
InacR *= Inaccuracy;
auto SprR = Rng.RandomFloat( 0.f , 1.f );
const auto SprA = Rng.RandomFloat( 0.f , k_TwoPi );
if ( ItemDefIdx == k_RevolverId )
SprR = 1.f - ( SprR * SprR );
else if ( ItemDefIdx == k_NegevId )
SprR = 1.f - ( SprR * SprR );
SprR *= Spread;
return
{
std::cosf( SprA ) * SprR + std::cosf( InacA ) * InacR,
std::sinf( SprA ) * SprR + std::sinf( InacA ) * InacR
};
}
}
static CMisc g_CMisc{};
auto CMisc::OnRender() -> void
{
if ( !Settings::Misc::Watermark && !Settings::Misc::Speedometer )
return;
auto& pFont = GetFontManager()->m_VerdanaFont;
float Y = 8.f;
if ( Settings::Misc::Speedometer )
{
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
if ( pLocalPawn && pLocalPawn->IsAlive() )
{
const float flSpeed = pLocalPawn->m_vecVelocity().Length2D() * 0.05f;
char szBuffer[ 64 ];
std::snprintf( szBuffer , sizeof szBuffer , XorStr( "%.0f u/s" ) , flSpeed );
pFont.DrawString( 8 , Y , ImColor( 255 , 255 , 255 ) , FW1_LEFT , "%s" , szBuffer );
}
Y += pFont.GetFontSize();
}
if ( !Settings::Misc::Watermark )
return;
const auto t = std::time( nullptr );
std::tm tm{};
localtime_s( &tm , &t );
char szBuffer[ 128 ];
std::snprintf( szBuffer , sizeof szBuffer , XorStr( "Evicted | FPS: %.0f | %02d:%02d:%02d" ) , ImGui::GetIO().Framerate , tm.tm_hour , tm.tm_min , tm.tm_sec );
pFont.DrawString( 8 , Y , ImColor( 255 , 255 , 0 ) , FW1_LEFT , "%s" , szBuffer );
}
auto CMisc::OnClientOutput() -> void
{
if ( !SDK::Interfaces::EngineToClient()->IsInGame() )
return;
if ( Settings::Misc::SpectatorList )
{
auto* pLocalController = GetCL_Players()->GetLocalPlayerController();
auto* pFont = &GetFontManager()->m_VerdanaFont;
if ( pLocalController && pFont )
{
const CHandle LocalPawnHandle = pLocalController->m_hPawn();
const auto DisplaySize = ImGui::GetIO().DisplaySize;
const float ListX = DisplaySize.x - 8.f;
float ListY = pFont->GetFontSize() + 12.f;
const auto& CachedVec = GetEntityCache()->GetCachedEntity();
std::scoped_lock Lock( GetEntityCache()->GetLock() );
for ( const auto& CachedEntity : *CachedVec )
{
if ( CachedEntity.m_Type != CachedEntity_t::PLAYER_CONTROLLER )
continue;
auto* pEntity = CachedEntity.m_Handle.Get();
if ( !pEntity )
continue;
auto* pController = reinterpret_cast<CCSPlayerController*>( pEntity );
if ( pController == pLocalController )
continue;
auto* pPawn = pController->m_hPawn().Get<C_CSPlayerPawn>();
if ( !pPawn || !pPawn->IsPlayerPawn() )
continue;
auto* pObserverServices = pPawn->m_pObserverServices();
if ( !pObserverServices )
continue;
const auto ObserverMode = pObserverServices->m_iObserverMode();
if ( ObserverMode != OBS_MODE_IN_EYE && ObserverMode != OBS_MODE_CHASE )
continue;
if ( pObserverServices->m_hObserverTarget() != LocalPawnHandle )
continue;
const char* szName = pController->m_sSanitizedPlayerName();
if ( !szName || !szName[ 0 ] )
continue;
GetRenderStackSystem()->DrawString( pFont , ImVec2( ListX , ListY ) , FW1_RIGHT | FW1_TOP , ImColor( 255 , 255 , 255 ) , "%s" , szName );
ListY += pFont->GetFontSize() + 2.f;
}
}
}
if ( Settings::Triggerbot::Active && Settings::Triggerbot::DrawIndicator )
{
if ( m_bTargetInCrosshair )
{
const auto DisplaySize = ImGui::GetIO().DisplaySize;
const ImVec2 Center( DisplaySize.x * 0.5f , DisplaySize.y * 0.5f );
const ImColor IndicatorColor = m_bTriggerFiring ? ImColor( 0 , 255 , 0 ) : ImColor( 255 , 200 , 0 );
GetRenderStackSystem()->DrawCircleFilled( Center , 3.f , IndicatorColor );
}
}
if ( Settings::Misc::Hitmarker )
{
if ( m_HitTime.time_since_epoch().count() > 0 )
{
const auto Elapsed = std::chrono::duration<float>( std::chrono::steady_clock::now() - m_HitTime ).count();
if ( Elapsed <= 0.25f )
{
const auto DisplaySize = ImGui::GetIO().DisplaySize;
const ImVec2 Center( DisplaySize.x * 0.5f , DisplaySize.y * 0.5f );
const float Size = 6.f;
GetRenderStackSystem()->DrawLine( ImVec2( Center.x - Size , Center.y - Size ) , ImVec2( Center.x - 2.f , Center.y - 2.f ) , ImColor( 255 , 255 , 255 ) , 1.5f );
GetRenderStackSystem()->DrawLine( ImVec2( Center.x + Size , Center.y - Size ) , ImVec2( Center.x + 2.f , Center.y - 2.f ) , ImColor( 255 , 255 , 255 ) , 1.5f );
GetRenderStackSystem()->DrawLine( ImVec2( Center.x - Size , Center.y + Size ) , ImVec2( Center.x - 2.f , Center.y + 2.f ) , ImColor( 255 , 255 , 255 ) , 1.5f );
GetRenderStackSystem()->DrawLine( ImVec2( Center.x + Size , Center.y + Size ) , ImVec2( Center.x + 2.f , Center.y + 2.f ) , ImColor( 255 , 255 , 255 ) , 1.5f );
}
}
}
}
auto CMisc::OnCreateMove( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
{
if ( !pUserCmd )
return;
if ( Settings::Triggerbot::Active )
RunTriggerbot( pInput , pUserCmd );
if ( Settings::Misc::Bunnyhop )
{
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
if ( pLocalPawn && pLocalPawn->IsAlive() )
{
constexpr auto FL_ONGROUND = 1u;
const bool bOnGround = ( pLocalPawn->m_fFlags() & FL_ONGROUND ) != 0;
const bool bHoldingJump = ( pUserCmd->button_states.buttonstate1 & IN_JUMP ) != 0;
if ( bHoldingJump )
{
if ( bOnGround )
{
if ( Settings::Misc::PerfectBhop )
GetCL_Bypass()->SetJump( pUserCmd , true );
else
pUserCmd->button_states.buttonstate1 |= IN_JUMP;
}
else
{
pUserCmd->button_states.buttonstate1 &= ~IN_JUMP;
}
}
}
}
RunMovement( pInput , pUserCmd );
if ( Settings::Misc::FOVChanger )
{
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
if ( pLocalPawn )
{
if ( auto* pCameraServices = pLocalPawn->m_pCameraServices(); pCameraServices )
pCameraServices->m_iFOV() = static_cast<uint32>( Settings::Misc::FOV );
}
}
}
auto CMisc::RunMovement( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
{
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
if ( !pLocalPawn || !pLocalPawn->IsAlive() )
{
m_bWasOnGround = false;
return;
}
const auto flFlags = pLocalPawn->m_fFlags();
constexpr uint32 FL_ONGROUND = 1u;
const bool bOnGround = ( flFlags & FL_ONGROUND ) != 0;
if ( Settings::Misc::SubtickStrafe )
RunSubtickStrafe( pInput , pUserCmd , pLocalPawn , bOnGround );
else if ( Settings::Misc::NullStrafe )
RunNullStrafe( pInput , pUserCmd , pLocalPawn , bOnGround );
else if ( Settings::Misc::AutoStrafe )
RunAutoStrafe( pInput , pUserCmd , pLocalPawn , bOnGround );
if ( Settings::Misc::JumpBug )
{
if ( !bOnGround && pLocalPawn->m_flFallVelocity() > 430.f )
{
pUserCmd->button_states.buttonstate1 &= ~IN_DUCK;
GetCL_Bypass()->SetJump( pUserCmd , true );
}
}
if ( Settings::Misc::EdgeBug )
RunEdgeBug( pInput , pUserCmd , pLocalPawn , bOnGround );
if ( Settings::Misc::EdgeJump )
{
if ( m_bWasOnGround && !bOnGround )
{
if ( pUserCmd->button_states.buttonstate1 & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) )
GetCL_Bypass()->SetJump( pUserCmd , true );
}
}
if ( Settings::Misc::JumpCrouch )
{
if ( bOnGround && ( pUserCmd->button_states.buttonstate1 & IN_JUMP ) )
pUserCmd->button_states.buttonstate1 |= IN_DUCK;
}
if ( Settings::Misc::LongJump )
{
if ( !bOnGround )
pUserCmd->button_states.buttonstate1 |= IN_DUCK;
}
if ( Settings::Misc::PixelSurf )
{
if ( !bOnGround )
{
pUserCmd->button_states.buttonstate1 |= IN_DUCK;
}
else
{
if ( pUserCmd->button_states.buttonstate1 & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) )
GetCL_Bypass()->SetJump( pUserCmd , true );
}
}
if ( Settings::Misc::FastStop )
{
if ( bOnGround )
{
if ( !( pUserCmd->button_states.buttonstate1 & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) ) )
{
const Vector3 Velocity = pLocalPawn->m_vecVelocity();
const float flSpeed = Velocity.Length2D();
if ( flSpeed > 5.f )
{
constexpr float k_Pi = 3.14159265358979f;
const float flVelYaw = std::atan2f( Velocity.m_y , Velocity.m_x ) * ( 180.f / k_Pi );
auto* pViewAngles = CCSGOInput_GetViewAngles( pInput , 0 );
if ( pViewAngles )
{
float flDelta = flVelYaw - pViewAngles->m_y;
while ( flDelta > 180.f )
flDelta -= 360.f;
while ( flDelta < -180.f )
flDelta += 360.f;
if ( flDelta > -45.f && flDelta <= 45.f )
pUserCmd->button_states.buttonstate1 |= IN_BACK;
else if ( flDelta > 45.f && flDelta <= 135.f )
pUserCmd->button_states.buttonstate1 |= IN_MOVELEFT;
else if ( flDelta > 135.f || flDelta <= -135.f )
pUserCmd->button_states.buttonstate1 |= IN_FORWARD;
else
pUserCmd->button_states.buttonstate1 |= IN_MOVERIGHT;
}
}
}
}
}
if ( Settings::Misc::SlowWalk )
pUserCmd->button_states.buttonstate1 |= IN_SPEED;
m_bWasOnGround = bOnGround;
}
auto CMisc::RunAutoStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
{
if ( bOnGround )
return;
if ( pUserCmd->button_states.buttonstate1 & ( IN_FORWARD | IN_BACK ) )
return;
const Vector3 Velocity = pLocalPawn->m_vecVelocity();
const float flSpeed = Velocity.Length2D();
if ( flSpeed < 0.1f )
return;
constexpr float k_Pi = 3.14159265358979f;
const float flVelYaw = std::atan2f( Velocity.m_y , Velocity.m_x ) * ( 180.f / k_Pi );
auto* pViewAngles = CCSGOInput_GetViewAngles( pInput , 0 );
if ( !pViewAngles )
return;
float flDelta = flVelYaw - pViewAngles->m_y;
while ( flDelta > 180.f )
flDelta -= 360.f;
while ( flDelta < -180.f )
flDelta += 360.f;
constexpr float k_TurnSpeed = 5.f;
QAngle NewAngles = *pViewAngles;
if ( flDelta > 0.f )
{
NewAngles.m_y += k_TurnSpeed;
pUserCmd->button_states.buttonstate1 |= IN_MOVERIGHT;
}
else
{
NewAngles.m_y -= k_TurnSpeed;
pUserCmd->button_states.buttonstate1 |= IN_MOVELEFT;
}
GetCL_Bypass()->SetViewAngles( &NewAngles , pInput , pUserCmd );
}
auto CMisc::RunNullStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
{
if ( bOnGround )
return;
if ( !pUserCmd || !pLocalPawn )
return;
auto* pBaseCmd = pUserCmd->cmd.mutable_base();
if ( !pBaseCmd )
return;
auto* pViewAngles = CCSGOInput_GetViewAngles( pInput , 0 );
if ( !pViewAngles )
return;
const Vector3 Velocity = pLocalPawn->m_vecVelocity();
const float flSpeed = Velocity.Length2D();
if ( flSpeed <= 10.f )
return;
constexpr float k_Pi = 3.14159265358979f;
const float flVelYaw = std::atan2f( Velocity.m_y , Velocity.m_x );
const float flViewYaw = pViewAngles->m_y * ( k_Pi / 180.f );
const float flRelativeYaw = flVelYaw - flViewYaw;
const float flForward = std::clamp( -std::cosf( flRelativeYaw ) , -1.f , 1.f );
const float flLeft = std::clamp( -std::sinf( flRelativeYaw ) , -1.f , 1.f );
pBaseCmd->set_forwardmove( flForward );
pBaseCmd->set_leftmove( flLeft );
GetCL_Bypass()->AddProcessSubTick( 0 , false , 0.f , pBaseCmd->forwardmove() - m_flLastForwardMove , pBaseCmd->leftmove() - m_flLastLeftMove );
m_flLastForwardMove = pBaseCmd->forwardmove();
m_flLastLeftMove = pBaseCmd->leftmove();
}
auto CMisc::RunSubtickStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
{
if ( bOnGround )
return;
if ( !pUserCmd || !pLocalPawn )
return;
auto* pBaseCmd = pUserCmd->cmd.mutable_base();
if ( !pBaseCmd )
return;
auto* pViewAngles = CCSGOInput_GetViewAngles( pInput , 0 );
if ( !pViewAngles )
return;
constexpr float k_Pi = 3.14159265358979f;
constexpr int k_SubtickCount = 32;
constexpr float k_TickInterval = 1.f / 64.f;
constexpr float k_FrameTime = k_TickInterval / static_cast<float>( k_SubtickCount );
constexpr float k_SvAiraccelerate = 12.f;
constexpr float k_SvAirMaxWishspeed = 30.f;
constexpr float k_SvGravity = 800.f;
constexpr float k_MaxSpeed = 250.f;
const auto uButtons = pUserCmd->button_states.buttonstate1;
const bool bLeft = ( uButtons & IN_MOVELEFT ) != 0;
const bool bRight = ( uButtons & IN_MOVERIGHT ) != 0;
float flYawOffset = 0.f;
if ( bLeft )
flYawOffset += 90.f;
if ( bRight )
flYawOffset -= 90.f;
if ( uButtons & IN_FORWARD )
flYawOffset *= 0.5f;
else if ( uButtons & IN_BACK )
flYawOffset = -flYawOffset * 0.5f + 180.f;
const float flCmdForward = pBaseCmd->forwardmove();
const float flCmdLeft = pBaseCmd->leftmove();
Vector3 VelocitySim = pLocalPawn->m_vecVelocity();
float flLastImpulseForward = m_flLastForwardMove;
float flLastImpulseLeft = m_flLastLeftMove;
for ( auto i = 0; i < k_SubtickCount; ++i )
{
pBaseCmd->set_forwardmove( flCmdForward );
pBaseCmd->set_leftmove( flCmdLeft );
float flSpeed = VelocitySim.Length2D();
if ( flSpeed > 0.0001f )
{
const float flYawRad = pViewAngles->m_y * ( k_Pi / 180.f );
const Vector3 vForward( std::cosf( flYawRad ) , std::sinf( flYawRad ) , 0.f );
const Vector3 vRight( -std::sinf( flYawRad ) , std::cosf( flYawRad ) , 0.f );
Vector3 vWishDir
{
( vForward.m_x * flCmdForward * k_MaxSpeed ) + ( vRight.m_x * flCmdLeft * k_MaxSpeed ),
( vForward.m_y * flCmdForward * k_MaxSpeed ) + ( vRight.m_y * flCmdLeft * k_MaxSpeed ),
0.f
};
float flWishSpeed = vWishDir.Length2D();
if ( flWishSpeed > 0.0001f )
{
vWishDir.m_x /= flWishSpeed;
vWishDir.m_y /= flWishSpeed;
}
flWishSpeed = std::fminf( flWishSpeed , k_MaxSpeed );
const float flCappedWish = std::fminf( flWishSpeed , k_SvAirMaxWishspeed );
const float flCurrentSpeed = ( VelocitySim.m_x * vWishDir.m_x ) + ( VelocitySim.m_y * vWishDir.m_y );
const float flAddSpeed = flCappedWish - flCurrentSpeed;
if ( flAddSpeed > 0.f )
{
const float flAccelSpeed = k_SvAiraccelerate * k_MaxSpeed * k_FrameTime;
const float flGain = std::fminf( flAccelSpeed * 0.5f , flAddSpeed );
VelocitySim.m_x += vWishDir.m_x * flGain;
VelocitySim.m_y += vWishDir.m_y * flGain;
}
}
VelocitySim.m_z -= k_SvGravity * k_FrameTime;
flSpeed = VelocitySim.Length2D();
if ( flSpeed >= 10.f )
{
pBaseCmd->set_forwardmove( 0.f );
pBaseCmd->set_leftmove( 0.f );
const float flVelocityAngle = std::atan2f( VelocitySim.m_y , VelocitySim.m_x ) * ( 180.f / k_Pi );
const float flAccelSpeed = k_SvAiraccelerate * k_MaxSpeed * k_FrameTime;
const float flOptimalFloor = std::fmaxf( flAccelSpeed * 0.5f , k_SvAirMaxWishspeed - flAccelSpeed * 0.5f );
const float flIdealAngle = std::clamp( std::atanf( flOptimalFloor / flSpeed ) * ( 180.f / k_Pi ) , 0.f , 45.f );
float flTargetYaw = pViewAngles->m_y + flYawOffset;
while ( flTargetYaw > 180.f )
flTargetYaw -= 360.f;
while ( flTargetYaw < -180.f )
flTargetYaw += 360.f;
float flVelocityDelta = flTargetYaw - flVelocityAngle;
while ( flVelocityDelta > 180.f )
flVelocityDelta -= 360.f;
while ( flVelocityDelta < -180.f )
flVelocityDelta += 360.f;
if ( ( std::fabsf( flVelocityDelta ) > 170.f && flSpeed > 80.f ) || ( flVelocityDelta > flIdealAngle && flSpeed > 80.f ) )
{
flTargetYaw = flVelocityAngle + flIdealAngle;
pBaseCmd->set_leftmove( -1.f );
}
else if ( -flIdealAngle <= flVelocityDelta || flSpeed <= 80.f )
{
if ( m_bSideSwitch )
{
flTargetYaw = flTargetYaw - flIdealAngle;
pBaseCmd->set_leftmove( -1.f );
}
else
{
flTargetYaw = flTargetYaw + flIdealAngle;
pBaseCmd->set_leftmove( 1.f );
}
}
else
{
flTargetYaw = flVelocityAngle - flIdealAngle;
pBaseCmd->set_leftmove( 1.f );
}
while ( flTargetYaw > 180.f )
flTargetYaw -= 360.f;
while ( flTargetYaw < -180.f )
flTargetYaw += 360.f;
RotateMoveToYaw( pBaseCmd , flTargetYaw , pViewAngles->m_y );
}
GetCL_Bypass()->AddProcessSubTick( 0 , false , static_cast<float>( i ) / static_cast<float>( k_SubtickCount ) , pBaseCmd->forwardmove() - flLastImpulseForward , pBaseCmd->leftmove() - flLastImpulseLeft );
flLastImpulseForward = pBaseCmd->forwardmove();
flLastImpulseLeft = pBaseCmd->leftmove();
m_bSideSwitch = !m_bSideSwitch;
}
m_flLastForwardMove = flLastImpulseForward;
m_flLastLeftMove = flLastImpulseLeft;
}
auto CMisc::RotateMoveToYaw( CBaseUserCmdPB* pBaseCmd , const float flTargetYaw , const float flViewYaw ) -> void
{
const float k_Pi = 3.14159265358979f;
const float flTargetRad = flTargetYaw * ( k_Pi / 180.f );
const float flViewRad = flViewYaw * ( k_Pi / 180.f );
const float flForwardMove = pBaseCmd->forwardmove();
const float flSideMove = pBaseCmd->leftmove();
const Vector3 vTargetForward( std::cosf( flTargetRad ) , std::sinf( flTargetRad ) , 0.f );
const Vector3 vTargetRight( -std::sinf( flTargetRad ) , std::cosf( flTargetRad ) , 0.f );
const Vector3 vViewForward( std::cosf( flViewRad ) , std::sinf( flViewRad ) , 0.f );
const Vector3 vViewRight( -std::sinf( flViewRad ) , std::cosf( flViewRad ) , 0.f );
const Vector3 vMove = vTargetForward * flForwardMove + vTargetRight * flSideMove;
const float flCorrectedForward = ( vViewForward.m_x * vMove.m_x ) + ( vViewForward.m_y * vMove.m_y );
const float flCorrectedSide = ( vViewRight.m_x * vMove.m_x ) + ( vViewRight.m_y * vMove.m_y );
pBaseCmd->set_forwardmove( std::clamp( -flCorrectedForward , -1.f , 1.f ) );
pBaseCmd->set_leftmove( std::clamp( -flCorrectedSide , -1.f , 1.f ) );
}
auto CMisc::RunEdgeBug( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
{
if ( bOnGround )
return;
if ( !pUserCmd || !pLocalPawn )
return;
const Vector3 Velocity = pLocalPawn->m_vecVelocity();
if ( Velocity.m_z >= 0.f )
return;
constexpr float k_Pi = 3.14159265358979f;
constexpr float k_TickInterval = 1.f / 64.f;
constexpr float k_HalfWidth = 16.f;
constexpr float k_ProbeDist = 32.f;
const Vector3 vOrigin = pLocalPawn->m_vOldOrigin();
const Vector3 vNextPos
{
vOrigin.m_x + Velocity.m_x * k_TickInterval,
vOrigin.m_y + Velocity.m_y * k_TickInterval,
vOrigin.m_z + Velocity.m_z * k_TickInterval
};
const float flVelocityYaw = std::atan2f( Velocity.m_y , Velocity.m_x ) * ( 180.f / k_Pi );
const Vector3 vOffsets[]
{
Vector3( 0.f , 0.f , 0.f ),
Vector3( k_HalfWidth , k_HalfWidth , 0.f ),
Vector3( k_HalfWidth , -k_HalfWidth , 0.f ),
Vector3( -k_HalfWidth , k_HalfWidth , 0.f ),
Vector3( -k_HalfWidth , -k_HalfWidth , 0.f )
};
Ray_t Ray;
CGameTrace GameTrace;
CTraceFilter Filter( 0x1C1003 , pLocalPawn , 3 , 15 );
Vector3 vEdgeNormal;
bool bFoundEdge = false;
for ( const auto& vOffset : vOffsets )
{
const Vector3 vProbeStart
{
vNextPos.m_x + vOffset.m_x,
vNextPos.m_y + vOffset.m_y,
vNextPos.m_z
};
// Ground probe straight down below this corner.
Ray.Start = vProbeStart;
Ray.End = vProbeStart;
Ray.End.m_z -= k_ProbeDist;
if ( !IGamePhysicsQuery_TraceShape( SDK::Pointers::CVPhys2World() , Ray , Ray.Start , Ray.End , &Filter , &GameTrace ) )
continue;
const float flGroundFraction = GameTrace.flFraction;
// Wall probe in the direction of travel at the same height.
Ray.Start = vProbeStart;
Ray.Start.m_z -= 2.f;
Ray.End = Ray.Start;
Ray.End.m_x += std::cosf( flVelocityYaw * ( k_Pi / 180.f ) ) * k_ProbeDist;
Ray.End.m_y += std::sinf( flVelocityYaw * ( k_Pi / 180.f ) ) * k_ProbeDist;
if ( !IGamePhysicsQuery_TraceShape( SDK::Pointers::CVPhys2World() , Ray , Ray.Start , Ray.End , &Filter , &GameTrace ) )
continue;
// Open ground below + wall ahead = pixel / edge surface.
if ( flGroundFraction > 0.9f && GameTrace.flFraction < 0.95f )
{
bFoundEdge = true;
vEdgeNormal = GameTrace.vecNormal;
break;
}
}
if ( !bFoundEdge )
return;
// Only assist when the edge is below us (steep / vertical-ish face).
if ( vEdgeNormal.m_z > 0.7f )
return;
GetCL_Bypass()->SetJump( pUserCmd , true );
}
auto CMisc::RunTriggerbot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
{
auto Reset = [ & ]()
{
m_bTriggerShooting = false;
m_TriggerArmTime = {};
m_ShotStartTime = {};
m_bTargetInCrosshair = false;
m_bTriggerFiring = false;
};
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
if ( !pLocalPawn || !pLocalPawn->IsAlive() )
{
Reset();
return;
}
const auto WeaponType = GetCL_Weapons()->GetLocalWeaponType();
const bool bIsGun = WeaponType == CSWeaponType_t::WEAPONTYPE_PISTOL ||
WeaponType == CSWeaponType_t::WEAPONTYPE_SUBMACHINEGUN ||
WeaponType == CSWeaponType_t::WEAPONTYPE_RIFLE ||
WeaponType == CSWeaponType_t::WEAPONTYPE_SHOTGUN ||
WeaponType == CSWeaponType_t::WEAPONTYPE_SNIPER_RIFLE ||
WeaponType == CSWeaponType_t::WEAPONTYPE_MACHINEGUN ||
WeaponType == CSWeaponType_t::WEAPONTYPE_TASER;
if ( !bIsGun )
{
Reset();
return;
}
if ( Settings::Triggerbot::ScopedOnly )
{
if ( WeaponType == CSWeaponType_t::WEAPONTYPE_SNIPER_RIFLE && !pLocalPawn->m_bIsScoped() )
{
Reset();
return;
}
}
bool bShouldRun = false;
switch ( Settings::Triggerbot::Mode )
{
case 1:
{
bShouldRun = true;
}
break;
case 2:
{
const bool bKeyDown = ( GetAsyncKeyState( Settings::Triggerbot::Key ) & 0x8000 ) != 0;
if ( bKeyDown && !m_bTriggerKeyDown )
m_bTriggerToggledOn = !m_bTriggerToggledOn;
m_bTriggerKeyDown = bKeyDown;
bShouldRun = m_bTriggerToggledOn;
}
break;
default:
{
const bool bKeyDown = ( GetAsyncKeyState( Settings::Triggerbot::Key ) & 0x8000 ) != 0;
bShouldRun = bKeyDown;
}
break;
}
if ( !bShouldRun )
{
Reset();
return;
}
TriggerTraceResult_t Result;
if ( Settings::Triggerbot::SeedTrigger )
{
Vector3 vDirection;
if ( CalculateSeedDirection( pInput , pUserCmd , &vDirection ) )
Result = GetCL_Trace()->TraceDirectionToHitGroup( &vDirection );
}
else
{
Result = GetCL_Trace()->TraceToHitGroup( pInput );
}
auto* pTargetPawn = reinterpret_cast<C_CSPlayerPawn*>( Result.pHitEntity );
bool bTargetValid = false;
if ( pTargetPawn && pTargetPawn->IsPlayerPawn() && pTargetPawn != pLocalPawn && pTargetPawn->IsAlive() )
{
if ( !Settings::Triggerbot::IgnoreTeammates || pTargetPawn->m_iTeamNum() != pLocalPawn->m_iTeamNum() )
{
switch ( Result.nHitGroup )
{
case 1: bTargetValid = Settings::Triggerbot::Hitbox_Head; break;
case 2: bTargetValid = Settings::Triggerbot::Hitbox_Chest; break;
case 3: bTargetValid = Settings::Triggerbot::Hitbox_Stomach; break;
case 4:
case 5: bTargetValid = Settings::Triggerbot::Hitbox_Arms; break;
case 6:
case 7: bTargetValid = Settings::Triggerbot::Hitbox_Legs; break;
default: bTargetValid = true; break;
}
if ( bTargetValid && !Settings::Triggerbot::SeedTrigger && Settings::Triggerbot::Hitchance > 0 )
{
const QAngle ViewAngles = *CCSGOInput_GetViewAngles( pInput , 0 );
const float flHitchance = CalculateHitchance( pInput , pTargetPawn , ViewAngles , Settings::Triggerbot::HitchanceSamples );
if ( ( flHitchance * 100.f ) < static_cast<float>( Settings::Triggerbot::Hitchance ) )
bTargetValid = false;
}
}
}
m_bTargetInCrosshair = bTargetValid;
if ( !bTargetValid )
{
m_bTriggerShooting = false;
m_TriggerArmTime = {};
m_ShotStartTime = {};
m_bTriggerFiring = false;
return;
}
const auto Now = std::chrono::steady_clock::now();
const auto DelayMs = std::chrono::milliseconds( std::max( 0 , Settings::Triggerbot::Delay ) );
const auto HoldMs = std::chrono::milliseconds( std::max( 0 , Settings::Triggerbot::HoldTime ) );
if ( !m_bTriggerShooting )
{
if ( m_TriggerArmTime.time_since_epoch().count() == 0 )
m_TriggerArmTime = Now;
if ( ( Now - m_TriggerArmTime ) >= DelayMs )
{
m_bTriggerShooting = true;
m_ShotStartTime = Now;
m_TriggerArmTime = {};
}
}
else
{
if ( ( Now - m_ShotStartTime ) >= HoldMs )
{
m_bTriggerShooting = false;
m_TriggerArmTime = Now;
}
}
if ( m_bTriggerShooting )
{
GetCL_Bypass()->SetAttack( pUserCmd , true );
m_bTriggerFiring = true;
}
else
{
m_bTriggerFiring = false;
}
}
static thread_local std::mt19937 g_TriggerRng( std::random_device{}() );
auto CMisc::CalculateHitchance( CCSGOInput* pInput , C_CSPlayerPawn* pTarget , const QAngle& ViewAngles , const int Samples ) -> float
{
if ( !pTarget || Samples <= 0 )
return 0.f;
auto* pWeapon = GetCL_Weapons()->GetLocalActiveWeapon();
if ( !pWeapon )
return 0.f;
const float flInaccuracy = C_CSWeaponBaseGun_GetInaccuracy( pWeapon , nullptr , nullptr );
const float flSpread = C_CSWeaponBaseGun_GetSpread( pWeapon );
const float flAccuracy = flInaccuracy + flSpread;
if ( flAccuracy <= 0.f )
return 1.f;
Vector3 vForward , vRight , vUp;
Math::AngleVectors( ViewAngles , vForward , vRight , vUp );
const auto vStart = GetCL_Players()->GetLocalEyeOrigin();
std::uniform_real_distribution<float> distAngle( 0.f , 6.2831853f );
std::uniform_real_distribution<float> distRadius( 0.f , 1.f );
int Hits = 0;
for ( int i = 0; i < Samples; i++ )
{
const float flAngle = distAngle( g_TriggerRng );
const float flRadius = flAccuracy * std::sqrt( distRadius( g_TriggerRng ) );
const Vector3 vDirection = ( vForward + vRight * ( std::cos( flAngle ) * flRadius ) + vUp * ( std::sin( flAngle ) * flRadius ) ).Normalized();
const Vector3 vEnd = vStart + vDirection * 8192.f;
if ( GetCL_Trace()->TraceToEntityEndPos( &vEnd ) == reinterpret_cast<C_BaseEntity*>( pTarget ) )
Hits++;
}
return static_cast<float>( Hits ) / static_cast<float>( Samples );
}
auto CMisc::CalculateSeedDirection( CCSGOInput* pInput , CUserCmd* pUserCmd , Vector3* vOutDirection ) -> bool
{
if ( !pInput || !vOutDirection )
return false;
auto* pWeapon = GetCL_Weapons()->GetLocalActiveWeapon();
if ( !pWeapon )
return false;
const QAngle ViewAngles = *CCSGOInput_GetViewAngles( pInput , 0 );
int iSeed = 0;
if ( pUserCmd && pUserCmd->cmd.base().has_random_seed() )
{
iSeed = pUserCmd->cmd.base().random_seed();
}
else
{
int iTick = 0;
if ( pUserCmd && pUserCmd->cmd.base().has_client_tick() )
iTick = pUserCmd->cmd.base().client_tick();
iSeed = static_cast<int>( GetSpreadSeed( ViewAngles , iTick ) );
}
const float flInaccuracy = C_CSWeaponBaseGun_GetInaccuracy( pWeapon , nullptr , nullptr );
const float flSpread = C_CSWeaponBaseGun_GetSpread( pWeapon );
const auto ItemDefIdx = GetCL_Weapons()->GetLocalWeaponDefinitionIndex();
const auto sv = CalculateSeedSpread( iSeed + 1 , flInaccuracy , flSpread , ItemDefIdx );
Vector3 vForward , vRight , vUp;
Math::AngleVectors( ViewAngles , vForward , vRight , vUp );
*vOutDirection = ( vForward + vRight * -sv.x + vUp * sv.y ).Normalized();
return true;
}
auto CMisc::OnFrameStageNotify( int FrameStage ) -> void
{
if ( FrameStage != 6 )
return;
if ( !Settings::Misc::NoFlash )
return;
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
if ( !pLocalPawn )
return;
pLocalPawn->m_flFlashDuration() = 0.f;
pLocalPawn->m_flFlashMaxAlpha() = 0.f;
}
auto CMisc::OnFireEventClientSide( IGameEvent* pGameEvent ) -> void
{
if ( !pGameEvent )
return;
if ( _strcmpi( pGameEvent->GetName() , XorStr( "player_hurt" ) ) != 0 )
return;
auto* pLocalController = GetCL_Players()->GetLocalPlayerController();
if ( !pLocalController )
return;
auto* pAttackerController = pGameEvent->GetPlayerController( XorStr( "attacker" ) );
if ( pAttackerController != pLocalController )
return;
const auto Now = std::chrono::steady_clock::now();
if ( Settings::Misc::Hitmarker )
m_HitTime = Now;
if ( Settings::Misc::HitSound )
{
if ( ( Now - m_HitSoundTime ) > std::chrono::milliseconds( 50 ) )
{
m_HitSoundTime = Now;
PlaySoundW( L"SystemHand" , nullptr , SND_ALIAS | SND_ASYNC | SND_NODEFAULT );
}
}
}
auto GetMisc() -> CMisc*
{
return &g_CMisc;
}