diff options
| author | JustSomePwner <crotchyalt@gmail.com> | 2018-08-30 14:01:54 +0200 |
|---|---|---|
| committer | JustSomePwner <crotchyalt@gmail.com> | 2018-08-30 14:01:54 +0200 |
| commit | 7ccb819f867493f8ec202ea3b39c94c198c64584 (patch) | |
| tree | 94622e61af0ff359e3d6689cf274d74f60b2492a /internal_rewrite/ragebot_lagcomp.cpp | |
| parent | 564d979b79e8a5aaa5014eba0ecd36c61575934f (diff) | |
first
Diffstat (limited to 'internal_rewrite/ragebot_lagcomp.cpp')
| -rw-r--r-- | internal_rewrite/ragebot_lagcomp.cpp | 645 |
1 files changed, 645 insertions, 0 deletions
diff --git a/internal_rewrite/ragebot_lagcomp.cpp b/internal_rewrite/ragebot_lagcomp.cpp new file mode 100644 index 0000000..f19828f --- /dev/null +++ b/internal_rewrite/ragebot_lagcomp.cpp @@ -0,0 +1,645 @@ +#include "ragebot.hpp"
+#include "interface.hpp"
+#include "settings.hpp"
+#include "context.hpp"
+#include "base_cheat.hpp"
+#include "mem.hpp"
+#include "hooks.hpp"
+
+namespace features
+{
+ c_ragebot::lag_record_t::lag_record_t( c_base_player* ent ) : m_ent( ent ) {
+ if( !m_ent || !m_ent->is_valid( ) ) return;
+ m_valid = true;
+
+ m_flSimulationTime = m_ent->m_flSimulationTime( );
+ m_flOldSimulationTime = m_ent->m_flOldSimulationTime( );
+ m_tickcount = TIME_TO_TICKS( m_flSimulationTime + util::get_lerptime( ) );
+ m_choked = m_ent->get_choked_ticks( );
+
+ m_flLowerBodyYawTarget = m_ent->m_flLowerBodyYawTarget( );
+ m_flCycle = m_ent->m_flCycle( );
+ m_fFlags = m_ent->m_fFlags( );
+ m_animDuck = m_ent->get_animdata( ).m_last_duck;
+ m_animVelocity = m_ent->get_animdata( ).m_anim_velocity;
+ m_prevVelocity = m_ent->get_animdata( ).m_last_velocity;
+ m_flDuckSpeed = m_ent->m_flDuckSpeed( );
+ m_flDuckAmount = m_ent->m_flDuckAmount( );
+
+ m_vecHeadPos = ent->get_hitbox_pos( 0 );
+ m_vecPelvisPos = ent->get_hitbox_pos( HITBOX_PELVIS );
+
+ //we need mins/maxs because traces check them before checking if it hit a player
+ m_vecMins = *( vec3_t* )( uintptr_t( m_ent ) + 0x318 + 0x8 );
+ m_vecMaxs = *( vec3_t* )( uintptr_t( m_ent ) + 0x318 + 0x14 );
+
+ m_vecOrigin = m_ent->m_vecOrigin( );
+ m_vecAngles = m_ent->m_angEyeAngles( );
+ m_vecRenderAngles = m_ent->ce( )->GetRenderAngles( );
+ m_vecRenderOrigin = m_ent->ce( )->GetRenderOrigin( );
+
+ memcpy( &m_state,
+ m_ent->get_animstate( ),
+ sizeof( CCSGOPlayerAnimState ) );
+
+ memcpy( m_PoseParameters,
+ m_ent->m_flPoseParameter( ),
+ sizeof( float ) * 24 );
+
+ memcpy( m_AnimLayers,
+ m_ent->m_AnimOverlay( ).GetElements( ),
+ sizeof( C_AnimationLayer ) * 13 );
+
+ for( int i{ }; i < 13; ++i )
+ m_ent->m_AnimOverlay( ).GetElements( )[ i ].m_player = ent;
+
+ m_valid = m_ent->ce( )->SetupBones( m_matrix, 128, BONE_USED_BY_HITBOX, m_flSimulationTime );
+ }
+
+ bool c_ragebot::lag_record_t::restore( bool recalculate, bool reanimate ) {
+ if( !m_ent || !m_ent->is_valid( ) ) return false;
+
+ *( vec3_t* )( uintptr_t( m_ent ) + 0x318 + 0x8 ) = m_vecMins;
+ *( vec3_t* )( uintptr_t( m_ent ) + 0x318 + 0x14 ) = m_vecMaxs;
+
+ memcpy( ( void* )( m_ent->m_CachedBoneData( ).GetElements( ) ),
+ m_matrix,
+ sizeof( matrix3x4 ) * m_ent->m_CachedBoneData( ).GetSize( ) );
+
+ if( !recalculate ) {
+ return true;
+ }
+
+ m_ent->set_abs_angles( m_vecRenderAngles );
+
+ //m_ent->m_flDuckAmount( ) = m_flDuckAmount;
+ m_ent->m_flLowerBodyYawTarget( ) = m_flLowerBodyYawTarget;
+ m_ent->m_fFlags( ) = m_fFlags;
+ m_ent->m_flSimulationTime( ) = m_flSimulationTime;
+
+ memcpy( m_ent->m_flPoseParameter( ),
+ m_PoseParameters,
+ sizeof( float ) * 24 );
+
+ memcpy( m_ent->m_AnimOverlay( ).GetElements( ),
+ m_AnimLayers,
+ sizeof( C_AnimationLayer ) * 13 );
+
+ //why?
+ //why not?
+ if( reanimate ) {
+ vec3_t velocity = m_ent->m_vecVelocity( );
+ int backup_eflags = m_ent->get< int >( 0xe4 );
+ int backup_byte = m_ent->get< byte >( 0x35f8 );
+
+ m_ent->m_vecVelocity( ) = m_animVelocity;
+ m_ent->get< vec3_t >( 0x94 ) = m_animVelocity;
+ m_ent->get< byte >( 0x35f8 ) = 1;
+ m_ent->get< int >( 0xe4 ) &= ~0x1000;
+
+ m_state.m_flFeetYawRate = 0.f;
+
+ float backup_curtime = g_csgo.m_globals->m_curtime;
+ float backup_frametime = g_csgo.m_globals->m_frametime;
+
+ g_csgo.m_globals->m_curtime = m_flOldSimulationTime + TICK_INTERVAL( );
+ g_csgo.m_globals->m_frametime = TICK_INTERVAL( );
+
+ m_state.m_iLastClientSideAnimationUpdateFramecount -= 1;
+
+ g_cheat.m_ragebot.m_resolver->brute_force( m_ent );
+
+ float lby_delta = m_flLowerBodyYawTarget - m_ent->m_angEyeAngles( ).y;
+ lby_delta = std::remainderf( lby_delta, 360.f );
+ lby_delta = std::clamp( lby_delta, -60.f, 60.f );
+
+ float feet_yaw = std::remainderf( m_ent->m_angEyeAngles( ).y + lby_delta, 360.f );
+ if( feet_yaw < 0.f )
+ feet_yaw += 360.f;
+
+ m_state.m_flGoalFeetYaw = m_state.m_flCurrentFeetYaw = feet_yaw;
+
+ m_ent->m_flPoseParameter( )[ BODY_YAW ] = std::clamp( ( lby_delta + 180.f ) / 360.f, 0.f, 1.f );
+ m_ent->m_flPoseParameter( )[ LEAN_YAW ] = std::clamp( ( lby_delta + 180.f ) / 360.f, 0.f, 1.f );
+
+ float backup_duck = m_ent->m_flDuckAmount( );
+ float backup_duckspeed = m_ent->m_flDuckSpeed( );
+
+ m_ent->m_flDuckSpeed( ) = m_flDuckSpeed;
+ m_ent->m_flDuckAmount( ) = m_animDuck;
+
+ m_state.m_flLastClientSideAnimationUpdateTime = m_flOldSimulationTime;
+ m_state.update( m_ent->m_angEyeAngles( ).y, m_ent->m_angEyeAngles( ).x );
+
+ m_ent->m_flDuckAmount( ) = backup_duck;
+ m_ent->m_flDuckSpeed( ) = backup_duckspeed;
+
+ g_csgo.m_globals->m_curtime = backup_curtime;
+ g_csgo.m_globals->m_frametime = backup_frametime;
+
+ m_ent->m_vecVelocity( ) = velocity;
+ m_ent->get< vec3_t >( 0x94 ) = velocity;
+ m_ent->get< byte >( 0x35f8 ) = backup_byte;
+ m_ent->get< int >( 0xe4 ) = backup_eflags;
+ }
+
+ m_ent->set_abs_origin( m_vecRenderOrigin );
+
+ byte backup = m_ent->get< byte >( 0x270 );
+
+ m_ent->get< byte >( 0x270 ) = 0;
+ m_ent->invalidate_bone_cache( );
+ bool ret = m_ent->ce( )->SetupBones( m_matrix, 128, BONE_USED_BY_HITBOX, m_flSimulationTime + TICK_INTERVAL( ) );
+
+ m_ent->get< byte >( 0x270 ) = backup;
+
+ return ret;
+ }
+
+ bool c_ragebot::lag_record_t::is_valid( ) {
+ if( !m_valid ) return false;
+
+ return util::is_tick_valid( m_tickcount );
+ }
+
+ void c_ragebot::c_lagcomp::restore_animations( ) {
+ if( g_csgo.m_engine( )->IsInGame( ) ) {
+ if( g_ctx.m_local ) {
+ for( int i{ 1 }; i < 65; ++i ) {
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( i );
+
+ if( ent && ent->is_player( ) ) {
+ ent->set_needs_interpolate( true );
+ ent->invalidate_bone_cache( );
+ ent->ce( )->SetupBones( nullptr, -1, BONE_USED_BY_ANYTHING, 0.f );
+
+ ent->m_bClientSideAnimation( ) = true;
+ }
+ }
+ }
+ }
+ }
+
+ void c_ragebot::c_lagcomp::store_visuals( ) {
+ if( g_csgo.m_engine( )->IsInGame( ) ) {
+ static float last_simtime[ 65 ]{ };
+
+ if( g_ctx.m_local && g_ctx.m_local->is_valid( ) ) {
+ for( int i{ }; i < 65; ++i ) {
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( i );
+ auto& data = m_data_render[ i ];
+
+ if( ent == g_ctx.m_local )
+ continue;
+
+ if( ent && ent->is_valid( ) && !ent->m_bGunGameImmunity( ) &&
+ !!std::abs( last_simtime[ i ] - ent->m_flSimulationTime( ) ) ) {
+ render_record_t new_record;
+ new_record.m_simtime = ent->m_flSimulationTime( ) + util::get_lerptime( );
+ new_record.m_origin = ent->m_vecOrigin( );
+
+ float delta = ent->m_flSimulationTime( ) - ent->m_flOldSimulationTime( );
+ new_record.m_globaltime = g_csgo.m_globals->m_curtime;
+
+ if( g_settings.legit.enabled( ) )
+ new_record.m_globaltime -= util::get_lerptime( );
+ else
+ new_record.m_globaltime -= TICK_INTERVAL( );
+
+ if( ent->ce( )->SetupBones( new_record.m_matrix, 128, BONE_USED_BY_ANYTHING, 0.f ) ) {
+ data.push_front( new_record );
+ }
+
+ last_simtime[ i ] = ent->m_flSimulationTime( );
+ }
+
+ while( !data.empty( ) &&
+ data.size( ) > TIME_TO_TICKS( 1.f ) ) {
+ data.pop_back( );
+ }
+ }
+ }
+ }
+ }
+
+ bool c_ragebot::c_lagcomp::get_render_record( int ent_index, matrix3x4* out ) {
+ auto& data = m_data_render[ ent_index ];
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( ent_index );
+
+ auto is_time_valid = [ & ]( float time ) -> bool {
+ auto nci = g_csgo.m_engine( )->GetNetChannelInfo( );
+ if( !nci ) return false;
+
+ float latency = util::get_total_latency( );
+ float correct = std::clamp( latency + util::get_lerptime( ), 0.f, 1.f );
+ float delta = correct - ( g_csgo.m_globals->m_curtime - time );
+
+ return std::abs( delta ) <= 0.2f;
+ };
+
+ for( auto it = data.rbegin( ); it != data.rend( ) && ( it + 1 ) != data.rend( ); it++ ) {
+ if( is_time_valid( it->m_globaltime ) ) {
+ if( it->m_origin.dist_to( ent->m_vecOrigin( ) ) < 1.f )
+ return false;
+
+ if( ent->is_breaking_lc( ) )
+ return false;
+
+ if( !it->m_validtime )
+ it->m_validtime = g_csgo.m_globals->m_curtime;
+
+ auto nci = g_csgo.m_engine( )->GetNetChannelInfo( );
+ float latency = util::get_total_latency( );
+ float correct = latency + util::get_lerptime( );
+
+ float deadtime = it->m_globaltime + correct + 0.2f;
+ float totaltime = deadtime - it->m_validtime;
+
+ float curtime = g_csgo.m_globals->m_curtime;
+ float delta = ( 0.2f + correct - ( curtime - it->m_globaltime ) ) / totaltime;
+
+ vec3_t next = ( it + 1 )->m_origin;
+ vec3_t lerp = math::lerp( it->m_origin, next, std::clamp( 1.f - delta, 0.f, 1.f ) );
+
+ matrix3x4 ret[ 128 ];
+
+ util::memcpy( ret,
+ it->m_matrix,
+ sizeof( ret ) );
+
+ for( size_t i{ }; i < 128; ++i ) {
+ vec3_t matrix_delta = math::get_matrix_position( it->m_matrix[ i ] ) - it->m_origin;
+ math::set_matrix_position( matrix_delta + lerp, ret[ i ] );
+ }
+
+ util::memcpy( out,
+ ret,
+ sizeof( ret ) );
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void c_ragebot::c_lagcomp::fsn_net_update_start( ) {
+ static bool restored = true;
+
+ if( !g_settings.rage.enabled( ) ) {
+ if( !restored ) {
+ restore_animations( );
+ restored = true;
+ }
+
+ return;
+ }
+
+ restored = false;
+ if( g_csgo.m_engine( )->IsInGame( ) ) {
+ if( g_ctx.m_local && g_ctx.m_local->is_valid( ) ) {
+ for( int i{ 1 }; i < 65; ++i ) {
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( i );
+
+ if( ent && ent->is_valid( ) && ent != g_ctx.m_local ) {
+ ent->set_needs_interpolate( false );
+ }
+ }
+ }
+ }
+ }
+
+ void c_ragebot::c_lagcomp::fsn_render_start( ) {
+ if( !g_settings.rage.enabled( ) )
+ return;
+
+ if( !g_ctx.m_local )
+ return;
+
+ static bool invalidated = true;
+ if( !g_ctx.m_local->is_valid( ) ) {
+ if( !invalidated )
+ restore_animations( );
+
+ invalidated = true;
+ return;
+ }
+
+ invalidated = false;
+
+ static float stored_lby[ 65 ];
+ static bool was_dormant[ 65 ];
+
+ for( int i{ 1 }; i < 65; ++i ) {
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( i );
+
+ if( !ent || !ent->is_player( ) ) {
+ //invalidate_animstate( i );
+ m_first_update[ i ] = true;
+ continue;
+ }
+
+ if( ent == g_ctx.m_local ) {
+ if( g_ctx.m_stage == FRAME_RENDER_START ) {
+ //printf( "ya\n" );
+ //hooks::update_clientside_animation( ent, 0 );
+ }
+ continue;
+ }
+
+ if( !ent->is_alive( ) ) {
+ ent->m_bClientSideAnimation( ) = true;
+ was_dormant[ i ] = true;
+ m_first_update[ i ] = true;
+ continue;
+ }
+
+ if( ent->ce( )->IsDormant( ) ) {
+ ent->m_bClientSideAnimation( ) = true;
+ m_first_update[ i ] = true;
+ was_dormant[ i ] = true;
+ continue;
+ }
+
+ if( ent->m_iTeamNum( ) == g_ctx.m_local->m_iTeamNum( )
+ && !g_settings.rage.friendlies ) {
+ ent->m_bClientSideAnimation( ) = true;
+ continue;
+ }
+
+ ent->restore_anim_data( false );
+ if( was_dormant[ i ] ) {
+ g_cheat.m_ragebot.m_resolver->update_player( i );
+ ent->calc_anim_velocity( true );
+ ent->fix_animations( true );
+ ent->do_ent_interpolation( true );
+ m_last_simtime[ i ] = ent->m_flSimulationTime( );
+ }
+ else if( g_ctx.m_stage == FRAME_RENDER_START ) {
+ ent->m_bClientSideAnimation( ) = false;
+ ent->do_ent_interpolation( was_dormant[ i ] );
+ continue;
+ }
+
+ was_dormant[ i ] = false;
+
+ if( m_data_lby[ i ].size( ) &&
+ m_data_lby[ i ].front( ).m_ent != ent ) {
+ m_data_lby[ i ].clear( );
+ }
+
+ if( m_data_normal[ i ].size( ) &&
+ m_data_normal[ i ].front( ).m_ent != ent ) {
+ m_data_normal[ i ].clear( );
+ }
+
+ auto update_anims = [ this, &ent ]( int e ) {
+ ent->fix_animations( );
+ };
+
+
+
+ float lby = ent->m_flLowerBodyYawTarget( );
+
+ float last_simtime = m_last_simtime[ i ];
+ float simtime = ent->m_flSimulationTime( );
+
+ bool yaw_change = g_cheat.m_ragebot.m_resolver->yaw_change( i );
+
+ if( !!std::abs( simtime - last_simtime ) ) {
+ ent->calc_anim_velocity( was_dormant[ i ] );
+
+ bool is_moving = ent->get_anim_velocity( ).length2d( ) > 0.1f && !ent->is_fakewalking( )
+ && ( ent->m_fFlags( ) & FL_ONGROUND );
+
+ if( ent->m_bGunGameImmunity( ) ) {
+ update_anims( i );
+ }
+
+ else if( is_moving && !was_dormant[ i ] && g_settings.rage.resolver ) {
+ m_first_update[ i ] = false;
+ ent->m_angEyeAngles( ).y = lby;
+
+ update_anims( i );
+ lag_record_t new_record( ent );
+
+ m_data_lby[ i ].push_front( new_record );
+ }
+
+ else if( ( lby != stored_lby[ i ] ) && !was_dormant[ i ] && g_settings.rage.resolver ) {
+ if( !m_first_update[ i ] ) {
+ stored_lby[ i ] = lby;
+ ent->m_angEyeAngles( ).y = lby;
+
+ update_anims( i );
+ lag_record_t new_record( ent );
+
+ m_data_lby[ i ].push_front( new_record );
+ m_flick_time[ i ] = ent->m_flOldSimulationTime( ) + TICK_INTERVAL( );
+ }
+ else {
+ ent->fix_animations( false, yaw_change );
+
+ lag_record_t new_record( ent );
+ new_record.m_sim_record = true;
+
+ new_record.m_shots = g_cheat.m_ragebot.m_resolver->get_shots( i );
+
+ m_data_normal[ i ].push_front( new_record );
+ }
+
+ m_first_update[ i ] = false;
+ }
+ else {
+ bool has_updated = false;
+ if( g_settings.rage.resolver( ) ) {
+ float anim_time = ent->m_flOldSimulationTime( ) + TICK_INTERVAL( );
+
+ if( ent->m_flSimulationTime( ) - m_flick_time[ i ] > 1.1f && !m_first_update[ i ] ) {
+ has_updated = true;
+
+ ent->m_angEyeAngles( ).y = lby;
+ m_flick_time[ i ] = anim_time;
+ update_anims( i );
+ lag_record_t new_record( ent );
+ new_record.m_balanceadjust = true;
+ m_data_lby[ i ].push_front( new_record );
+ }
+ }
+
+ if( !has_updated ) {
+ ent->fix_animations( false, yaw_change );
+
+ lag_record_t new_record( ent );
+ new_record.m_sim_record = true;
+
+ new_record.m_shots = g_cheat.m_ragebot.m_resolver->get_shots( i );
+
+ m_data_normal[ i ].push_front( new_record );
+ }
+ }
+ }
+
+
+ ent->do_ent_interpolation( false );
+ m_last_simtime[ i ] = simtime;
+
+ g_cheat.m_ragebot.m_resolver->yaw_change( i ) = false;
+
+ while( !m_data_lby[ i ].empty( ) &&
+ m_data_lby[ i ].size( ) > TIME_TO_TICKS( 1.0f ) ) {
+ m_data_lby[ i ].pop_back( );
+ }
+
+ while( !m_data_normal[ i ].empty( ) &&
+ m_data_normal[ i ].size( ) > TIME_TO_TICKS( 1.0f ) ) {
+ m_data_normal[ i ].pop_back( );
+ }
+ }
+ }
+
+ RecordType_t c_ragebot::c_lagcomp::can_backtrack_entity( int ent_index ) {
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( ent_index );
+ if( ent->is_breaking_lc( ) ) {
+ return RECORD_NONE;
+ }
+
+ auto data_lby = &m_data_lby[ ent_index ];
+ auto data_normal = &m_data_normal[ ent_index ];
+
+ if( !data_lby->empty( ) ) {
+ for( auto& it : *data_lby ) {
+ if( it.is_valid( ) ) return RECORD_LBY;
+ }
+ }
+
+ if( !data_normal->empty( ) ) {
+ for( auto& it : *data_normal ) {
+ if( it.is_valid( ) ) return RECORD_NORMAL;
+ }
+ }
+
+ return RECORD_NONE;
+ }
+
+ void c_ragebot::c_lagcomp::invalidate_bone_caches( ) {
+ for( int i{ 1 }; i < 65; ++i ) {
+ auto ent = g_csgo.m_entlist( )->GetClientEntity( i );
+ if( !ent || !ent->is_player( ) )
+ continue;
+
+ ent->m_iMostRecentModelBoneCounter( ) -= 1;
+ ent->m_flLastBoneSetupTime( ) = -FLT_MAX;
+ }
+ }
+
+ c_ragebot::lag_record_t* c_ragebot::c_lagcomp::get_newest_record( int ent_index ) {
+ lag_record_t* newest_record{ };
+ if( get_records( ent_index, RECORD_LBY )->size( ) )
+ newest_record = &get_records( ent_index, RECORD_LBY )->front( );
+
+ if( get_records( ent_index, RECORD_NORMAL )->size( ) ) {
+ auto& newest_rec = get_records( ent_index, RECORD_NORMAL )->front( );
+ if( ( newest_record && newest_rec.m_flSimulationTime > newest_record->m_flSimulationTime ) ||
+ !newest_record ) {
+ newest_record = &newest_rec;
+ }
+ }
+
+ return newest_record;
+ }
+
+ c_ragebot::lag_record_t* c_ragebot::c_lagcomp::get_newest_valid_record( int ent_index ) {
+ lag_record_t* last_simtime_record{ };
+ for( auto& it : *get_records( ent_index, RECORD_LBY ) ) {
+ if( !it.is_valid( ) ) continue;
+ last_simtime_record = ⁢
+ break;
+ }
+
+ for( auto& it : *get_records( ent_index, RECORD_NORMAL ) ) {
+ if( !it.is_valid( ) ) continue;
+ if( !last_simtime_record || ( last_simtime_record && it.m_flSimulationTime > last_simtime_record->m_flSimulationTime ) ) {
+ last_simtime_record = ⁢
+ }
+ break;
+ }
+
+ return last_simtime_record;
+ }
+
+ int c_ragebot::c_lagcomp::backtrack_entity( int ent_index, RecordType_t type, lag_record_t** out_record ) {
+ if( type == RECORD_NONE ) return -1;
+
+ auto& data = *get_records( ent_index, type );
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( ent_index );
+
+ auto check_record = [ &ent, &out_record, &ent_index ]( lag_record_t* record, bool check_pelvis ) {
+ if( record->m_balanceadjust && record->m_shot ) return -1;
+
+ vec3_t head_pos = record->m_vecHeadPos;
+ vec3_t pelvis_pos = record->m_vecPelvisPos;
+
+ float damage = g_cheat.m_autowall.run( g_ctx.m_local, ent, head_pos, false ) * 4.f;
+ float min_damage = std::min< float >( ent->m_iHealth( ),
+ g_settings.rage.active->m_damage );
+
+ //g_con->log( xors( "record: %d damage: %f" ), counter++, damage );
+
+ int shots = g_cheat.m_ragebot.m_resolver->get_shots( ent_index );
+ bool recalc = shots != record->m_shots && record->m_sim_record;
+
+
+ if( damage > min_damage ) {
+ if( !record->restore( recalc, recalc ) )
+ return -1;
+
+ if( out_record ) {
+ *out_record = record;
+ }
+ return record->m_tickcount;
+ }
+
+ if( check_pelvis ) {
+ float pelvis_damage = g_cheat.m_autowall.run( g_ctx.m_local, ent, pelvis_pos, false );
+ if( pelvis_damage > min_damage ) {
+ if( !record->restore( recalc, recalc ) )
+ return -1;
+
+ if( out_record ) {
+ *out_record = record;
+ }
+ return record->m_tickcount;
+ }
+ }
+
+ return -1;
+ };
+
+ if( data.empty( ) )
+ return -1;
+
+ auto* back = &data.back( );
+ auto* front = &data.front( );
+
+ for( auto& it : data ) {
+ if( !it.is_valid( ) ) continue;
+ front = ⁢
+ break;
+ }
+
+ for( auto& it : util::reverse_iterator( data ) ) {
+ if( !it.is_valid( ) ) continue;
+ back = ⁢
+ break;
+ }
+
+ int front_result = check_record( front, true );
+ if( front_result != -1 ) return front_result;
+
+ int back_result = check_record( back, true );
+ if( back_result != -1 ) return back_result;
+
+ return -1;
+ }
+}
\ No newline at end of file |
