diff options
| author | boris <wzn@moneybot.cc> | 2018-11-28 16:00:02 +1300 |
|---|---|---|
| committer | boris <wzn@moneybot.cc> | 2018-11-28 16:00:02 +1300 |
| commit | 3d412a4b30a9f7c7f51ea6562e694315948bd3da (patch) | |
| tree | 26d67dfd1f3e5fd12903ad13e85d0cb8bcf8f21c /cheat/gmod/aimbot.cpp | |
| parent | e4729e4393d90271a3814c7a79950a660c48325a (diff) | |
cleaned up
in short, the cheat and loader are now separate solutions. unused stuff was moved into the legacy solution in case anyone wants to compile it or whatever.
i can change this back if you want to. also, i configured the loader to compile in x64, and have separate build types for linux and win64
Diffstat (limited to 'cheat/gmod/aimbot.cpp')
| -rw-r--r-- | cheat/gmod/aimbot.cpp | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/cheat/gmod/aimbot.cpp b/cheat/gmod/aimbot.cpp new file mode 100644 index 0000000..313b927 --- /dev/null +++ b/cheat/gmod/aimbot.cpp @@ -0,0 +1,404 @@ + +#include "aimbot.hpp" +#include "interface.hpp" +#include "settings.hpp" +#include "context.hpp" +#include "math.hpp" +#include "base_cheat.hpp" +#include "input_system.hpp" + +namespace features +{ + void c_aimbot::operator()( user_cmd_t* cmd ) { + m_cmd = cmd; + run( ); + } + + c_aimbot::aim_target_t c_aimbot::find_best_target( ) const { + aim_target_t ret{ -1, vec3_t{ } }; + vec3_t angle{ }; + + g_gmod.m_engine( )->GetViewAngles( angle ); + + vec3_t angle_dir = math::angle_vectors( angle ); + vec3_t eye_pos = g_ctx.m_local->get_eye_pos( ); + float closest_to = std::numeric_limits< float >::max( ); + + for( int i{ 1 }; i <= g_gmod.m_globals->m_maxclients; ++i ) { + auto ent = g_gmod.m_entlist( )->GetClientEntity( i ); + if( !ent || ent == g_ctx.m_local || !ent->is_valid( ) ) + continue; + + if( g_settings.rage.ignore_team && + g_ctx.m_local->m_iTeamNum( ) == ent->m_iTeamNum( ) ) + continue; + + if( g_settings.rage.ignore_teamcolor && + g_ctx.m_local->get_team_color( ) == ent->get_team_color( ) ) + continue; + + if( g_settings.rage.ignore_spawnprot && + ent->m_clrRender( ).a( ) < 250 ) + continue; + + player_info_t info; + if( !g_gmod.m_engine( )->GetPlayerInfo( i, &info ) ) + continue; + + // whitelisted. + if( g_cheat.m_playerlist.is_friend( info.m_steamid ) ) + continue; + + const auto ent_pos = get_entity_position( ent ); + if( ent_pos.is_zero( ) ) + continue; + + auto dir = ( ent_pos - eye_pos ); + dir.normalize_vector( ); + + const float fov = angle_dir.fov_to( dir ) * M_RADPI; + if( fov > g_settings.rage.fov ) + continue; + + if( g_settings.rage.selection_type( ) == 0 ) { + if( fov < closest_to ) { + closest_to = fov; + ret.m_ent_index = i; + ret.m_position = ent_pos; + } + } + else if( g_settings.rage.selection_type( ) == 1 ) { + float dist = eye_pos.dist_to( ent_pos ); + if( dist < closest_to ) { + closest_to = dist; + ret.m_ent_index = i; + ret.m_position = ent_pos; + } + } + } + return ret; + } + + vec3_t c_aimbot::get_entity_position( c_base_player* ent ) const { + matrix3x4 matrix[ 256 ]{ }; + bool found_valid_hitbox{ }; + // the idea behind this is that some players can have really weird models and our aimbot will not work on them + // so if they don't have a valid hitbox, we then get the OOB center of their model and use that instead. + // fuck gmod. + // const const const const + bool hitscan = g_settings.rage.hitbox == -1; + const char* hitbox_selection[ ] = { + "Head", + "Neck", + "Pelvis", + "Chest" + }; + + + if( !ent->ce( )->SetupBones( matrix, 256, 0x100, g_gmod.m_globals->m_curtime ) ) + return vec3_t{ }; + + const auto model = ent->ce( )->GetModel( ); + if( !model ) + return vec3_t{ }; + + const auto hdr = g_gmod.m_model_info( )->GetStudiomodel( model ); + if( !hdr ) + return vec3_t{ }; + + const auto set = hdr->get_hitbox_set( ent->m_nHitboxSet( ) ); + if( !set ) + return vec3_t{ }; + + for( int i{ }; i < set->numhitboxes; ++i ) { + const auto hitbox = set->get_hitbox( i ); + if( !hitbox ) + continue; + + const auto bone = hdr->get_bone( hitbox->bone ); + if( !bone ) + continue; + + const std::string name = bone->get_name( ); + if( name.empty( ) ) + continue; + + if( hitscan ) { + if( name.find( "Head" ) == std::string::npos ) + continue; + } + else { + if( name.find( hitbox_selection[ g_settings.rage.hitbox ] ) == std::string::npos ) + continue; + } + + const auto pos = math::vector_transform( ( hitbox->min + hitbox->max ) * 0.5f, matrix[ hitbox->bone ] ); + if( pos.is_zero( ) ) + continue; + + found_valid_hitbox = true; + if( ent->is_visible( pos ) ) + return pos; + } + + if( hitscan ) { // ghetto but it works fine. + for( int i{ }; i < set->numhitboxes; ++i ) { + const auto hitbox = set->get_hitbox( i ); + if( !hitbox ) + continue; + + const auto pos = math::vector_transform( ( hitbox->min + hitbox->max ) * 0.5f, matrix[ hitbox->bone ] ); + if( pos.is_zero( ) ) + continue; + + if( ent->is_visible( pos ) ) + return pos; + } + } + + if( !found_valid_hitbox ) { + auto pos = ent->ce( )->GetRenderOrigin( ); + pos += ( ent->m_vecMins( ) + ent->m_vecMaxs( ) ) * 0.5f; + if( ent->is_visible( pos ) ) + return pos; + } + + return vec3_t{ }; + } + + void c_aimbot::fix_accuracy( vec3_t& angle ) { + auto srand = []( double seed ) -> void { + if( !g_ctx.m_lua ) + return; + + const auto lua = g_ctx.m_lua; + + lua->GetField( LUA_GLOBALSINDEX, xors( "math" ) ); + if( !lua->IsType( -1, LUA_TYPE::TYPE_TABLE ) ) { + lua->Pop( 1 ); + return; + } + + lua->GetField( -1, xors( "randomseed" ) ); + if( !lua->IsType( -1, LUA_TYPE::TYPE_FUNCTION ) ) { + lua->Pop( 2 ); + return; + } + + lua->PushNumber( seed ); + lua->Call( 1, 0 ); + + lua->Pop( 1 ); + }; + + auto rand = []( const double low, const double high ) -> double { + if( !g_ctx.m_lua ) + return 0.0; + + const auto lua = g_ctx.m_lua; + + lua->GetField( LUA_GLOBALSINDEX, xors( "math" ) ); + if( !lua->IsType( -1, LUA_TYPE::TYPE_TABLE ) ) { + lua->Pop( 1 ); + return 0.0; + } + + lua->GetField( -1, xors( "Rand" ) ); + if( !lua->IsType( -1, LUA_TYPE::TYPE_FUNCTION ) ) { + lua->Pop( 2 ); + return 0.0; + } + + lua->PushNumber( low ); + lua->PushNumber( high ); + + lua->Call( 2, 1 ); + if( !lua->IsType( -1, LUA_TYPE::TYPE_NUMBER ) ) { + lua->Pop( 2 ); + return 0.0; + } + + double rand = lua->GetNumber( -1 ); + + lua->Pop( 2 ); + + return rand; + }; + + + auto weapon = g_ctx.m_local->get_weapon( ); + if( !weapon ) + return; + + bool is_cw20 = weapon->is_cw20( ); // own spread handling weapon packs (big). + bool is_fas2 = weapon->is_fas2( ); + bool is_custom = is_cw20 || is_fas2; + + auto weapon_name = weapon->get_class_name( ); + if( !is_custom && !weapon_name ) + return; + + auto cone = m_spread[ weapon_name ]; + if( !is_custom && cone.is_zero( ) ) + return; + + float cur_cone = weapon->get_custom_cone( ); + if( is_custom || cur_cone ) { // may be custom weapon similar to FAS2/CW20 + if ( g_settings.rage.norecoil ) + angle -= g_ctx.m_local->m_vecPunchAngle( ); + + if( !g_settings.rage.nospread ) + return; + + if( is_cw20 ) { + srand( m_cmd->m_cmd_nr ); + + if( g_ctx.m_local->m_fFlags( ) & FL_DUCKING ) + cur_cone *= 0.85f; + } + else if ( is_fas2 ) { + srand( g_ctx.m_local->m_nTickBase( ) * g_gmod.m_globals->m_interval_per_tick ); // FPS has to be over tickrate otherwise this fucks up, do not know how to fix. + } + else { + srand( g_ctx.m_local->m_nTickBase( ) * g_gmod.m_globals->m_interval_per_tick ); // some other custom ones based on FAS2 or CW20 use this. + } + + angle.x -= ( float )( rand( -cur_cone, cur_cone ) * 25.0 ); + angle.y -= ( float )( rand( -cur_cone, cur_cone ) * 25.0 ); + } + else { + // if hl2 + // no recoil... figure this out. + + if( !g_settings.rage.nospread ) + return; + + util::set_random_seed( m_cmd->m_random_seed & 0xff ); + + float rand_a = util::get_random_float( -0.5f, 0.5f ) + util::get_random_float( -0.5f, 0.5f ); + float rand_b = util::get_random_float( -0.5f, 0.5f ) + util::get_random_float( -0.5f, 0.5f ); + + float spread_x = cone.x * rand_a; + float spread_y = cone.y * rand_b; + + vec3_t forward, right, up; + math::angle_vectors( angle, &forward, &right, &up ); + + vec3_t spread_dir = forward + ( right * -spread_x ) + ( up * -spread_y ); + spread_dir.normalize_vector( ); + + angle = math::vector_angles( vec3_t{ }, spread_dir ); + } + } + + void c_aimbot::aim_at_target( const c_aimbot::aim_target_t& target ) { + // we're not gonna be checking for m_flNextPrimaryFire due to server side anticheats checking if IN_ATTACK is sent when you can fire, you will get banned. + // I'm gonna do some ghetto autopistol if we find that the weapon is not automatic (we can find this easily using a lua member of the weapon). + vec3_t eye_pos = g_ctx.m_local->get_eye_pos( ); + vec3_t angle_to_target = math::vector_angles( eye_pos, target.m_position ); + auto weapon = g_ctx.m_local->get_weapon( ); + float yaw = m_cmd->m_viewangles.y; + + fix_accuracy( angle_to_target ); + + if( g_settings.rage.silent != 2 || weapon->is_fas2( ) || weapon->is_cw20( ) || weapon->get_custom_cone( ) ) { // These custom weapons cannot do pSilent as they handle shot direction themselves... should probably warn users about this. + m_cmd->m_viewangles = angle_to_target.clamp( ); + + vec3_t delta = m_last_viewangles - ( m_cmd->m_viewangles - m_last_viewangles ); + m_cmd->m_mousedx = -( short )( delta.x / 0.022f ); // serverside anticheats detect this stuff. + m_cmd->m_mousedy = ( short )( delta.y / 0.022f ); + + if( g_settings.rage.silent == 1 ) { + vec3_t move = vec3_t( m_cmd->m_forwardmove, m_cmd->m_sidemove, m_cmd->m_upmove ); + float len = move.length( ); + + if( len ) { + move = math::angle_vectors( ( math::vector_angles( vec3_t{ }, move ) + vec3_t( 0, m_cmd->m_viewangles.y - yaw, 0 ) ) ) * len; + m_cmd->m_forwardmove = move.x; + m_cmd->m_sidemove = move.y; + } + } + } + else { + m_shot_dir = math::angle_vectors( angle_to_target.clamp( ) ); // save for later. this is really inaccurate and i do not know why. + m_shot_dir.normalize_vector( ); + } + + if( g_settings.rage.silent( ) == 0 ) + g_gmod.m_engine( )->SetViewAngles( m_cmd->m_viewangles ); + + if( g_settings.rage.auto_fire ) + m_cmd->m_buttons |= IN_ATTACK; + } + + void c_aimbot::log_shot( c_base_player* ent, fire_bullets_info* info ) { + // we log shot spread cones due to not having a proper function to give us weapon spread... + if( !ent || !info ) + return; + + if( info->spread.is_zero( ) ) + return; + + auto weapon = ent->get_weapon( ); + if( !weapon ) + return; + + auto weapon_name = weapon->get_class_name( ); + if( !weapon_name ) + return; + + m_spread[ weapon_name ] = info->spread; + } + + void c_aimbot::silent( ) { + // the idea behind this was using the context menu used in sandbox and darkrp ( C menu ) + // you can fire anywhere in the menu but it doesn't change your view angles + // worldclick stuff gets set in C_GMOD_Player::CreateMove so we must set it after the call to it. + // however this method has some problems, the weapon back has to be using the lua call player:GetAimVector() for src direction in FireBullets + // otherwise it will not work, 2 of the biggest weapon packs do not use this function so its kinda bork + // another problem is that if you do not aim within a 30 degree cone of your target or are close to them, lag compensation will not take effect ( thanks garry ) + // - kolo + + if( !m_cmd ) + return; + + m_last_viewangles = m_cmd->m_viewangles; // for mousedx garbage. + + if( !g_settings.rage.enabled ) + return; + + if( g_settings.rage.silent != 2 ) + return; + + if( m_shot_dir.is_zero( ) ) + return; + + m_cmd->m_world_clicking = true; + m_cmd->m_world_click_direction = m_shot_dir; + + m_shot_dir = vec3_t{ }; // useless now. + } + + void c_aimbot::run( ) { + if( !g_settings.rage.enabled ) + return; + + if( g_settings.rage.activation_type != 0 && + !g_input.is_key_pressed( ( VirtualKeys_t )g_settings.rage.aimkey( ) ) ) + return; + + auto weapon = g_ctx.m_local->get_weapon( ); + if( !weapon ) + return; + + //auto wpn_data = weapon->get_wpn_data( ); // only works for hl2 weapons.. + //if( !wpn_data ) // however you can get lua weapon data, cast to C_WeaponSWEP and call correct functions. + // return; + + auto target = find_best_target( ); + if( target.m_ent_index != -1 ) { + aim_at_target( target ); + } + } +} + |
