From 3d412a4b30a9f7c7f51ea6562e694315948bd3da Mon Sep 17 00:00:00 2001 From: boris Date: Wed, 28 Nov 2018 16:00:02 +1300 Subject: 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 --- cheat/internal_rewrite/c_base_player.cpp | 1144 ++++++++++++++++++++++++++++++ 1 file changed, 1144 insertions(+) create mode 100644 cheat/internal_rewrite/c_base_player.cpp (limited to 'cheat/internal_rewrite/c_base_player.cpp') diff --git a/cheat/internal_rewrite/c_base_player.cpp b/cheat/internal_rewrite/c_base_player.cpp new file mode 100644 index 0000000..11882ea --- /dev/null +++ b/cheat/internal_rewrite/c_base_player.cpp @@ -0,0 +1,1144 @@ +#include "c_base_player.hpp" +#include "interface.hpp" +#include "math.hpp" +#include "mem.hpp" +#include "context.hpp" +#include "base_cheat.hpp" + +#undef max + +ent_animdata_t c_base_player::sm_animdata[ 65 ]; + +void IKContext::Init( void* hdr, vec3_t& angles, vec3_t& origin, float curtime, int framecount, int bone_mask ) { + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 EC 08 8B 45 08 56 57 8B F9 8D 8F" ) ); + + auto fn = ( void( __thiscall* )( void*, void*, vec3_t&, vec3_t&, float, int, int ) )( fn_ptr ); + fn( this, hdr, angles, origin, curtime, framecount, bone_mask ); +} + +void IKContext::UpdateTargets( vec3_t* pos, void* q, matrix3x4* bone_array, char* computed ) { + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F0 81 EC 00 00 00 00 33 D2" ) ); + + auto fn = ( void( __thiscall* )( void*, vec3_t*, void*, matrix3x4*, char* ) )( fn_ptr ); + fn( this, pos, q, bone_array, computed ); +} + +void IKContext::SolveDependencies( vec3_t* pos, void* q, matrix3x4* bone_array, char* computed ) { + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F0 81 EC 00 00 00 00 8B 81" ) ); + + auto fn = ( void( __thiscall* )( void*, vec3_t*, void*, matrix3x4*, char* ) )( fn_ptr ); + fn( this, pos, q, bone_array, computed ); +} + +bool& c_base_player::s_bInvalidateBoneCache( ) { +#ifdef HEADER_MODULE + static auto fn_ptr = g_header.patterns.animstate_update; +#else + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F8 83 EC 18 56 57 8B F9 F3 0F 11 54 24" ) ); +#endif + static auto var = *( bool** )( fn_ptr + 0xda + 2 ); + + return *var; +} + +void CCSGOPlayerAnimState::update( float yaw, float pitch ) { +#ifdef HEADER_MODULE + static auto fn_ptr = g_header.patterns.animstate_update; +#else + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F8 83 EC 18 56 57 8B F9 F3 0F 11 54 24" ) ); +#endif + + uintptr_t alloc = ( uintptr_t )this; + if( !alloc ) + return; + + if( !this->pBaseEntity ) + return; + + //bool* b = &c_base_player::s_bInvalidateBoneCache( ); + //char backup = *b; + + //vectorcall is GAY + if( fn_ptr ) { + __asm { + push 0 + mov ecx, alloc + + movss xmm1, dword ptr[ yaw ] + movss xmm2, dword ptr[ pitch ] + + call fn_ptr + } + } + + //c_base_player::s_bInvalidateBoneCache( ) = backup; +} + +void CCSGOPlayerAnimState::setup_velocity( float a2 ) { + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F8 83 EC 30 56 57 8B 3D" ) ); + if( fn_ptr ) { + auto ptr_ = ( uintptr_t )this; + + __asm { + mov ecx, ptr_ + + fld a2 + call fn_ptr + } + } +} + +bool CCSGOPlayerAnimState::cache_sequences( ) { + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F8 83 EC 34 53 56 8B F1 57 8B 46 60" ) ); + if( fn_ptr ) { + auto fn = ( bool( __thiscall* )( void* ) )( fn_ptr ); + return fn( this ); + } + + return false; +} + +void CCSGOPlayerAnimState::update_ex( float yaw, float pitch ) { +/* static auto unk_func_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "8B 0D ? ? ? ? 8B 01 8B 80 ? ? ? ? FF D0 84 C0 75 14 8B 0D ? ? ? ? 8B 01" ) ); + auto unk_fn = ( bool( *)( ) )( unk_func_ptr ); + + auto player = ( c_base_player* )this->pBaseEntity; + + if( player && cache_sequences( ) ) { + float v7 = *( float* )( uintptr_t( player ) + 0x2e0d ) + pitch; + v7 = std::remainderf( v7, 360.f ); + + float last_update = m_flLastClientSideAnimationUpdateTime; + float cur_time = g_csgo.m_globals->m_curtime; + + if( last_update != cur_time ) { + this->m_flLastUpdateDelta = math::max( cur_time - last_update, 0.f ); + this->m_flEyeYaw = yaw; + this->m_flPitch = pitch; + + this->m_vOrigin = player->m_vecOrigin( ); + this->pActiveWeapon = player->get_weapon( ); + if( pActiveWeapon != pLastActiveWeapon ) { + for( size_t i{ }; i < 13; ++i ) { + C_AnimationLayer* layer = &player->m_AnimOverlay( ).GetElements( )[ i ]; + + layer->m_unk1 = 0; + layer->m_unk2 = layer->m_unk3 = -1; + } + } + + bool using_duck_offset = !unk_fn( ); + + if( using_duck_offset ) { + float total_duck = *( float* )( uintptr_t( player ) + 0xbe7 ) + m_fLandingDuckAdditiveSomething; + + total_duck = std::clamp( total_duck, 0.f, 1.f ); + + float duck_amt = m_fDuckAmount; + + float v28 = this->m_flLastUpdateDelta * 6.0f; + float v29 = 0.f; + + if( total_duck - duck_amt > v28 ) { + if( v28 <= total_duck - duck_amt ) + v29 = total_duck; + else + v29 = duck_amt - v28; + } + else { + v29 = duck_amt + v28; + } + + m_fDuckAmount = std::clamp( v29, 0.f, 1.f ); + } + else { + float duck_amt = m_fDuckAmount; + + float v19 = player->m_fFlags( ) & FL_WATERJUMP ? 1.0 : m_fLandingDuckAdditiveSomething; + float v21 = 0.f; + if( v19 <= duck_amt ) + v21 = 6.0f; + else + v21 = 3.1f; + + float v22 = m_flLastUpdateDelta * v21; + float new_duck = 0.f; + if( v19 - duck_amt <= v22 ) { + if( v22 <= v19 - duck_amt ) + new_duck = v19; + else + new_duck = duck_amt - v22; + } + else { + new_duck = duck_amt = v22; + } + + m_fDuckAmount = std::clamp( new_duck, 0.f, 1.f ); + } + + *( uintptr_t* )( uintptr_t( player ) + 0x286 ) = 0; + player->invalidate_physics_recursive( 8 ); + setup_velocity( v7 ); + setup_aim_matrix( ); + setup_weapon_action( ); + setup_movement( ); + setup_alive_loop( ); + + } + }*/ +} + +void CCSGOPlayerAnimState::reset( ) { + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "56 6A 01 68 ? ? ? ? 8B F1" ) ); + if( fn_ptr ) { + auto fn = ( void( __thiscall* )( void* ) )( fn_ptr ); + fn( this ); + } +} + +void CCSGOPlayerAnimState::setup_aim_matrix( ) { + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 81 EC ? ? ? ? 53 56 57 8B 3D" ) ); + if( fn_ptr ) { + auto fn = ( void( __thiscall* )( void* ) )( fn_ptr ); + fn( this ); + } +} + +void c_base_player::invalidate_physics_recursive( int flags ) { + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F8 83 EC 0C 53 8B 5D 08 8B C3" ) ); + if( fn_ptr ) { + auto fn = ( void( __thiscall* )( void*, int ) )( fn_ptr ); + fn( this, flags ); + } +} + +uintptr_t c_base_player::get_player_resource( ) { + for( int i{ 1 }; i < g_csgo.m_entlist( )->GetHighestEntityIndex( ); ++i ) { + auto ent = g_csgo.m_entlist( )->GetClientEntity< IClientEntity >( i ); + if( !ent ) continue; + auto class_ = ent->GetClientClass( ); + if( class_ ) { + if( class_->m_class_id == CCSPlayerResource ) { + return uintptr_t( ent ); + } + } + } + + return 0; +} + +uintptr_t c_base_player::get_game_rules( ) { + static uintptr_t** game_rules = pattern::first_code_match< uintptr_t** >( g_csgo.m_chl.dll( ), xors( "A1 ? ? ? ? 85 C0 0F 84 ? ? ? ? 80 B8 ? ? ? ? ? 0F 84 ? ? ? ? 0F 10 05" ), 0x1 ); + if( !game_rules ) { + game_rules = pattern::first_code_match< uintptr_t** >( g_csgo.m_chl.dll( ), xors( "A1 ? ? ? ? 85 C0 0F 84 ? ? ? ? 80 B8 ? ? ? ? ? 0F 84 ? ? ? ? 0F 10 05" ), 0x1 ); + } + + return **game_rules; +} + +int& c_base_player::g_iModelBoneCounter( ) { + static auto offset = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "A1 ? ? ? ? 48 C7 81" ), 0x1 ); + return **( int** )( offset ); +} + +//use is_zero( ) on the vector to figure out if it returns a valid value +vec3_t c_base_player::get_hitbox_pos( int hitbox ) { + auto ce = this->ce( ); + + const auto model = ce->GetModel( ); + if( !model ) return vec3_t{ }; + + auto hdr = g_csgo.m_model_info( )->GetStudiomodel( model ); + if( !hdr ) return vec3_t{ }; + + matrix3x4 bone_matrix[ 128 ]; + memcpy( bone_matrix, + m_CachedBoneData( ).GetElements( ), + m_CachedBoneData( ).GetSize( ) * sizeof( matrix3x4 ) ); + + auto set = hdr->pHitboxSet( m_nHitboxSet( ) ); + if( !set ) return vec3_t{ }; + + auto box = set->pHitbox( hitbox ); + if( !box ) return vec3_t{ }; + + vec3_t center = ( box->bbmin + box->bbmax ) * 0.5f; + + return math::vector_transform( center, bone_matrix[ box->bone ] ); +} + +c_base_weapon* c_base_player::get_weapon( ) { + auto weap_handle = m_hActiveWeapon( ); + if( weap_handle ) + return g_csgo.m_entlist( )->GetClientEntityFromHandle< c_base_weapon >( weap_handle ); + + return nullptr; +} + +void c_base_player::set_needs_interpolate( bool interpolate ) { + auto varmap = get< VarMapping_t >( 0x24 ); + auto elements = varmap.m_Entries.GetElements( ); + + for( size_t i{ }; i < varmap.m_nInterpolatedEntries; ++i ) { + auto& e = elements[ i ]; + e.m_bNeedsToInterpolate = interpolate; + } +} + +bool c_base_player::is_visible( int hitbox ) { + vec3_t start = g_ctx.m_local->get_eye_pos( ); + vec3_t end = get_hitbox_pos( hitbox ); + + if( !end ) return false; + return util::trace_ray( start, end, g_ctx.m_local->ce( ), this->ce( ) ); +} + +float c_base_player::get_hitbox_radius( int hitbox ) { + auto model = ce( )->GetModel( ); + auto hdr = g_csgo.m_model_info( )->GetStudiomodel( model ); + auto set = hdr->pHitboxSet( m_nHitboxSet( ) ); + + if( !model || !hdr || !set ) + return 0.f; + + auto box = set->pHitbox( hitbox ); + + if( box ) { + if( box->m_flRadius == -1 ) return box->bbmin.dist_to( box->bbmax ); + return box->m_flRadius; + } + + return 0.f; +} + +vec3_t c_base_player::get_hitbox_mins( int hitbox ) { + auto model = ce( )->GetModel( ); + auto hdr = g_csgo.m_model_info( )->GetStudiomodel( model ); + auto set = hdr->pHitboxSet( m_nHitboxSet( ) ); + + if( !model || !hdr || !set ) + return vec3_t( ); + + matrix3x4 bone_matrix[ 128 ]; + memcpy( bone_matrix, + m_CachedBoneData( ).GetElements( ), + m_CachedBoneData( ).GetSize( ) * sizeof( matrix3x4 ) ); + + auto box = set->pHitbox( hitbox ); + + return math::vector_transform( box->bbmin, bone_matrix[ box->bone ] ); +} + +vec3_t c_base_player::get_hitbox_maxs( int hitbox ) { + auto model = ce( )->GetModel( ); + auto hdr = g_csgo.m_model_info( )->GetStudiomodel( model ); + auto set = hdr->pHitboxSet( m_nHitboxSet( ) ); + + if( !model || !hdr || !set ) + return vec3_t( ); + + matrix3x4 bone_matrix[ 128 ]; + memcpy( bone_matrix, + m_CachedBoneData( ).GetElements( ), + m_CachedBoneData( ).GetSize( ) * sizeof( matrix3x4 ) ); + + auto box = set->pHitbox( hitbox ); + + vec3_t max = math::vector_transform( box->bbmax, bone_matrix[ box->bone ] ); + return max; +} + +bool c_base_player::is_fakewalking( ) { + auto walk_layer = m_AnimOverlay( ).GetElements( )[ 6 ]; + auto some_layer = m_AnimOverlay( ).GetElements( )[ 4 ]; + + auto velocity = m_vecVelocity( ).length2d( ); + bool on_ground = m_fFlags( ) & FL_ONGROUND; + if( walk_layer.m_flWeight < 0.1f + && some_layer.m_flWeight < 0.1f + && velocity > 0.1f && on_ground ) { + return true; + } + + if( velocity <= 0.1f ) + return true; + + return false; +} + +int c_base_player::get_choked_ticks( ) { + auto simtime = m_flSimulationTime( ); + + return TIME_TO_TICKS( g_csgo.m_globals->m_curtime - simtime ) + 1; +} + +int c_base_player::get_ping( ) { + auto resource = get_player_resource( ); + static auto offset = g_netvars.get_netvar( fnv( "DT_CSPlayerResource" ), fnv( "m_iPing" ) ); + int ping = *( int* )( resource + offset + ce( )->GetIndex( ) * 4 ); + + return ping; +} + +bool c_base_player::is_breaking_lc( ) { + return g_cheat.m_prediction.is_breaking_lc( this->ce( )->GetIndex( ) ); +} + +bool c_base_player::can_attack( bool ignore_rapid ) { + if( g_ctx.m_has_fired_this_frame ) return false; + if( !is_alive( ) ) return false; + + auto weapon = get_weapon( ); + if( !weapon ) return false; + + if( weapon->is_sniper( ) && g_cheat.m_lagmgr.has_fired( ) ) + return false; + + float time = g_ctx.pred_time( ); + + float next_attack = m_flNextAttack( ); + if( next_attack > time ) return false; + + float next_primary_attack = weapon->m_flNextPrimaryAttack( ); + if( next_primary_attack > time ) { + if( weapon->is_knife( ) ) { + if( weapon->m_flNextSecondaryAttack( ) > time ) + return false; + } + else { + return false; + } + } + + if( weapon->m_iItemDefinitionIndex( ) == WEAPON_R8REVOLVER ) { + return g_ctx.m_revolver_shot; + } + + return true; +} + +int c_base_player::get_seq_activity( int sequence ) { + static uintptr_t fn_offset = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 7D 08 FF 56 8B F1 74 3D" ) ); + auto fn = ( int( __thiscall* )( void*, int ) )( fn_offset ); + + return fn ? fn( this, sequence ) : -2; +} + +void c_base_player::set_abs_angles( vec3_t angles ) { +#ifdef HEADER_MODULE + static uintptr_t fn_addr = g_header.patterns.set_abs_angles; +#else + static uintptr_t fn_addr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F8 83 EC 64 53 56 57 8B F1 E8" ) ); +#endif + + auto fn = ( void( __thiscall* )( void*, vec3_t& ) )( fn_addr ); + + return fn( this, angles ); +} + +void c_base_player::set_abs_origin( vec3_t origin ) { +#ifdef HEADER_MODULE + static uintptr_t fn_addr = g_header.patterns.set_abs_origin; +#else + static uintptr_t fn_addr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F8 51 53 56 57 8B F1" ) ); +#endif + + auto fn = ( void( __thiscall* )( void*, vec3_t& ) )( fn_addr ); + + return fn( this, origin ); +} + +void c_base_player::create_animstate( CCSGOPlayerAnimState* state ) { + static auto fn_addr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 56 8B F1 B9 ? ? ? ? C7 46" ) ); + auto fn = ( void( __thiscall* )( CCSGOPlayerAnimState*, decltype( this ) ) )( fn_addr ); + + fn( state, this ); + state->pBaseEntity = this; +} + +void c_base_player::set_abs_velocity( vec3_t velocity ) { + static auto fn_addr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F8 83 EC 0C 53 56 57 8B 7D 08 8B F1" ) ); + auto fn = ( void( __thiscall* )( void*, vec3_t& ) )( fn_addr ); + + fn( this, velocity ); +} + +void c_base_player::invalidate_bone_cache( ) { + m_flLastBoneSetupTime( ) = -FLT_MAX; + m_iMostRecentModelBoneCounter( ) = 0; +} + +void c_base_player::handle_taser_animation( ) { + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 EC 08 56 8B F1 80 BE ? ? ? ? ? 0F 84 ? ? ? ? 80 BE ? ? ? ? ? 0F 84 ? ? ? ? A1" ) ); + if( fn_ptr ) { + vec3_t eye_angles = m_angEyeAngles( ); + + __asm { + mov ecx, this + fld eye_angles.y + fld eye_angles.x + + call fn_ptr + } + } +} + +void c_base_player::calculate_duckamount( bool reset ) { + static float last_duckamt[ 65 ]{ }; + static float original_duckamt[ 65 ]{ }; + int idx = ce( )->GetIndex( ); + + if( reset ) { + original_duckamt[ idx ] = m_flDuckAmount( ); + last_duckamt[ idx ] = m_flDuckAmount( ); + return; + } + + float cur_duck = m_flDuckAmount( ); + float delta = m_flOldSimulationTime( ) - m_flSimulationTime( ) + TICK_INTERVAL( ); + + float old_duck = last_duckamt[ idx ]; + float rate = ( cur_duck - old_duck ) * delta; + + m_flDuckAmount( ) = old_duck + rate; + + if( cur_duck != original_duckamt[ idx ] ) + last_duckamt[ idx ] = cur_duck; + original_duckamt[ idx ] = cur_duck; +} + +void c_base_player::cache_anim_data( bool layers ) { + int idx = ce( )->GetIndex( ); + auto& animdata = sm_animdata[ idx ]; + + memcpy( &animdata.m_poseparams, + m_flPoseParameter( ), + sizeof( float ) * 24 ); + + if( layers ) { + memcpy( &animdata.m_animlayers, + m_AnimOverlay( ).GetElements( ), + sizeof( C_AnimationLayer ) * 13 ); + } + + memcpy( animdata.m_bones, + m_CachedBoneData( ).GetElements( ), + sizeof( matrix3x4 ) * m_CachedBoneData( ).GetSize( ) ); +} + +void c_base_player::restore_anim_data( bool layers ) { + int idx = ce( )->GetIndex( ); + auto& animdata = sm_animdata[ idx ]; + + memcpy( m_flPoseParameter( ), + &animdata.m_poseparams, + sizeof( float ) * 24 ); + + if( layers ) { + memcpy( m_AnimOverlay( ).GetElements( ), + &animdata.m_animlayers, + sizeof( C_AnimationLayer ) * 13 ); + } + + memcpy( animdata.m_bones, + m_CachedBoneData( ).GetElements( ), + sizeof( matrix3x4 ) * m_CachedBoneData( ).GetSize( ) ); +} + +void c_base_player::do_ent_interpolation( bool reset ) { + auto idx = ce( )->GetIndex( ); + auto* anim_data = &sm_animdata[ idx ]; + + vec3_t origin = m_vecOrigin( ); + + if( reset ) { + anim_data->m_last_interp_origin = anim_data->m_interp_origin = origin; + anim_data->m_simtime = anim_data->m_last_simtime = g_csgo.m_globals->m_curtime; + return; + } + + if( !anim_data->m_valid ) + return; + + if( origin.dist_to_sqr( anim_data->m_interp_origin ) > FLT_EPSILON ) { + anim_data->m_last_interp_origin = anim_data->m_interp_origin; + anim_data->m_interp_origin = origin; + anim_data->m_last_simtime = anim_data->m_simtime; + anim_data->m_simtime = g_csgo.m_globals->m_curtime; + } + + float lerp = util::get_lerptime( ); + if( !lerp ) + return; + + if( anim_data->m_last_interp_origin.dist_to( anim_data->m_interp_origin ) > 64.f ) + return; + + for( size_t i{ }; i < 3; ++i ) { + if( !std::isfinite( anim_data->m_last_interp_origin[ i ] ) || !std::isfinite( anim_data->m_interp_origin[ i ] ) ) { + char error_msg[ 128 ]; + sprintf_s< 128 >( error_msg, "player origin was NaN\nreport this bug\ndetails:\n %f %f", + g_csgo.m_globals->m_curtime, + anim_data->m_simtime ); + + MessageBoxA( nullptr, error_msg, "error", MB_OK ); + exit( 0 ); + } + } + + float update_delta = anim_data->m_simtime - anim_data->m_last_simtime; + float update_lerp = std::clamp( update_delta - lerp, 0.f, 1.f ); + + if( update_delta < TICK_INTERVAL( ) ) + return; + + lerp = std::clamp( lerp, 0.f, update_delta ); + + float lerp_progress = ( anim_data->m_simtime + lerp - g_csgo.m_globals->m_curtime ) / lerp; + + vec3_t vec_lerp = math::lerp( origin, anim_data->m_last_interp_origin, std::clamp( lerp_progress, 0.f, 1.f ) ); + + for( size_t i{ }; i < 3; ++i ) + if( !isfinite( vec_lerp[ i ] ) ) + return; + + byte backup = *( byte* )( uintptr_t( this ) + 0x270 ); + *( byte* )( uintptr_t( this ) + 0x270 ) = 0; + + restore_anim_data( true ); + + //aaaaAAAAAAAA + //calc_abs_velocity( ); + set_abs_origin( vec_lerp ); + invalidate_bone_cache( ); + + ce( )->SetupBones( anim_data->m_bones, 128, BONE_USED_BY_ANYTHING, g_csgo.m_globals->m_curtime ); + this->m_iMostRecentModelBoneCounter( )++; + + *( byte* )( uintptr_t( this ) + 0x270 ) = backup; +} + +void c_base_player::validate_animation_layers( ) { + for( size_t i{ }; i < m_AnimOverlay( ).GetSize( ); ++i ) { + auto& layer = m_AnimOverlay( ).GetElements( )[ i ]; + layer.m_flCycle = std::clamp( layer.m_flCycle, 0.f, 1.f ); + layer.m_flWeight = std::clamp( layer.m_flWeight, 0.f, 1.f ); + + layer.m_player = this; + } + + for( size_t i{ }; i < 24; ++i ) { + auto& param = m_flPoseParameter( )[ i ]; + if( !isfinite( param ) ) + param = 0.f; + } +} + +void c_base_player::compute_move_cycle( bool reset, bool moving ) { + if( !moving || reset ) + return; + + float eye_yaw = m_angEyeAngles( ).y; + + float blend_ang = math::approach_angle( eye_yaw, + get_animstate( )->m_flCurrentFeetYaw, + get_animstate( )->m_flFeetYawRate * 100.f ); + + //get_animstate( )->m_flCurrentFeetYaw = blend_ang + 360.f; + m_flPoseParameter( )[ LEAN_YAW ] = ( blend_ang + 180.f ) / 360.f; + m_flPoseParameter( )[ BODY_YAW ] = ( blend_ang + 180.f ) / 360.f; +} + +void c_base_player::calc_anim_velocity( bool reset ) { + int idx = ce( )->GetIndex( ); + + auto accelerate = [ & ]( vec3_t velocity, vec3_t direction, float speed, float accel ) { + float addspeed, accelspeed, currentspeed; + + velocity.z = 0.f; + currentspeed = velocity.dot( direction ); + + addspeed = speed - currentspeed; + + if( addspeed <= 0.f ) { + return velocity; + } + + //guess how many fucks i give, this works + accelspeed = std::min( accel * 10.f * TICK_INTERVAL( ) * std::max( speed, 250.f ), currentspeed ); + + for( size_t i{ }; i < 3; ++i ) { + velocity[ i ] += accelspeed * direction[ i ]; + } + + return velocity; + }; + + auto friction = [ & ]( vec3_t velocity ) { + static auto sv_friction = g_csgo.m_cvar( )->FindVar( xors( "sv_friction" ) ); + static auto sv_stopspeed = g_csgo.m_cvar( )->FindVar( xors( "sv_stopspeed" ) ); + + float speed = velocity.length2d( ); + if( speed < 0.1f ) + return vec3_t{ }; + + float friction = sv_friction->get_float( ); + float control = ( speed < sv_stopspeed->get_float( ) ) ? sv_stopspeed->get_float( ) : speed; + float drop = control * friction * TICK_INTERVAL( ); + + float newspeed = speed - drop; + if( newspeed < 0.f ) + newspeed = 0.f; + + if( newspeed != speed ) { + newspeed /= speed; + velocity *= newspeed; + } + + return velocity; + }; + + if( reset ) { + vec3_t velocity = m_vecVelocity( ); + sm_animdata[ idx ].m_last_origin = m_vecOrigin( ); + sm_animdata[ idx ].m_last_velocity = velocity; + sm_animdata[ idx ].m_anim_velocity = velocity; + } + else { + static auto sv_accelerate = g_csgo.m_cvar( )->FindVar( xors( "sv_accelerate" ) ); + + float delta = m_flSimulationTime( ) - m_flOldSimulationTime( ); + delta = std::max( delta, TICK_INTERVAL( ) ); + + bool on_ground = m_fFlags( ) & FL_ONGROUND; + + vec3_t origin = m_vecOrigin( ); + vec3_t origin_delta = origin - sm_animdata[ idx ].m_last_origin; + + vec3_t velocity = origin_delta / delta; + vec3_t last_velocity = sm_animdata[ idx ].m_last_velocity; + + vec3_t anim_vel; + + if( on_ground ) { + vec3_t ang = math::vector_angles( vec3_t( ), velocity ); + + float move_yaw = math::vector_angles( velocity ).y; + float move_delta = math::vector_angles( last_velocity ).y; + move_delta -= move_yaw; + move_delta = std::remainderf( move_delta, 360.f ); + + vec3_t move_dir = math::angle_vectors( vec3_t( 0.f, move_delta, 0.f ) ) * 450.f; + + vec3_t forward, right, up; + math::angle_vectors( ang, &forward, &right, &up ); + + vec3_t wishdir; + for( size_t i{ }; i < 2; ++i ) + wishdir[ i ] = forward[ i ] * move_dir.x + right[ i ] * move_dir.y; + + anim_vel = friction( last_velocity ); + if( anim_vel.length2d( ) < 1.f ) + anim_vel = vec3_t( ); + + int ticks = TIME_TO_TICKS( delta * 0.5f ); + vec3_t est_tick_vel = math::lerp( last_velocity, velocity, .5f ); + for( int i{ }; i < ticks + 1; i++ ) { + if( est_tick_vel.length2d( ) < 5.f ) + break; + + est_tick_vel = friction( est_tick_vel ); + } + + if( velocity.length2d( ) > last_velocity.length2d( ) ) + anim_vel = accelerate( anim_vel, wishdir, 250.f, sv_accelerate->get_float( ) ); + + //assume fakewalk + if( anim_vel.length2d( ) >= sm_animdata[ idx ].m_anim_velocity.length2d( ) && est_tick_vel.length2d( ) < 5.f && delta > TICK_INTERVAL( ) ) + anim_vel = vec3_t( ); + } + else { + anim_vel = math::lerp( + last_velocity, + velocity, + TICK_INTERVAL( ) / delta + ); + } + + sm_animdata[ idx ].m_anim_velocity = anim_vel; + sm_animdata[ idx ].m_last_velocity = velocity; + sm_animdata[ idx ].m_last_origin = origin; + } +} + +void c_base_player::calc_abs_velocity( ) { +#ifdef HEADER_MODULE + static auto fn_ptr = g_header.patterns.calc_abs_velocity; +#else + static auto fn_ptr = pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 E4 F8 83 EC 1C 53 56 57 8B F9 F7 87" ), 0 ); +#endif + + if( fn_ptr ) { + auto fn = ( void( __thiscall* )( void* ) )( fn_ptr ); + fn( this ); + } +} + +void c_base_player::fix_jump_fall( bool reset ) { + if( reset ) + return; + + int prev_flags = get_animdata( ).m_prev_flags; + int flags = m_fFlags( ); + + if( ( prev_flags & FL_ONGROUND ) && ( flags & FL_ONGROUND ) ) { + flags |= FL_ONGROUND; + } + else { + auto layer_weight = m_AnimOverlay( ).GetElements( )[ 4 ].m_flWeight; + auto last_weight = get_animdata( ).m_last_layers.at( 4 ).m_flWeight; + + if( layer_weight != 1.f && last_weight == 1.f && + m_AnimOverlay( ).GetElements( )[ 5 ].m_flWeight != 0.f ) + flags |= FL_ONGROUND; + + if( ( flags & FL_ONGROUND ) && !( prev_flags & FL_ONGROUND ) ) + flags &= ~FL_ONGROUND; + } + + m_fFlags( ) = flags; +} + +void c_base_player::fix_animations( bool reset, bool resolver_change ) { + //todo: legs dont match up when fakelagging <- not anymore + int idx = ce( )->GetIndex( ); + sm_animdata[ idx ].m_valid = false; + + if( !get_animstate( ) ) + return; + + m_angEyeAngles( ).y = std::remainder( m_angEyeAngles( ).y, 360.f ); + + int flags = m_fFlags( ); + auto eye_angles = m_angEyeAngles( ); + auto original_duck = m_flDuckAmount( ); + + //enable animations - time to update + m_bClientSideAnimation( ) = true; + set_needs_interpolate( false ); + + //we need the player data at THIS EXACT moment, somehow + float anim_time = m_flOldSimulationTime( ) + TICK_INTERVAL( ); + + auto backup_curtime = g_csgo.m_globals->m_curtime; + auto backup_frametime = g_csgo.m_globals->m_frametime; + + g_csgo.m_globals->m_curtime = anim_time; + g_csgo.m_globals->m_frametime = TICK_INTERVAL( ); + + if( resolver_change && m_fFlags( ) & FL_ONGROUND && !reset ) { + float lby_delta = m_flLowerBodyYawTarget( ) - eye_angles.y; + lby_delta = std::remainderf( lby_delta, 360.f ); + lby_delta = std::clamp( lby_delta, -60.f, 60.f ); + + float feet_yaw = std::remainderf( eye_angles.y + lby_delta, 360.f ); + if( feet_yaw < 0.f ) + feet_yaw += 360.f; + + get_animstate( )->m_flGoalFeetYaw = get_animstate( )->m_flCurrentFeetYaw = feet_yaw; + } + + get_animstate( )->m_flFeetYawRate = 0.f; + + //why? + //because this calls pAttachmentHelper->CalcAbsVelocity + //aswell as removes EFL_DIRTY_ABSVELOCITY + //which fixes attachments etc + //normally this would be called by animstate->update + //but we prevent that + calc_abs_velocity( ); + + //calc_anim_velocity( reset ); + + set_abs_origin( m_vecOrigin( ) ); + //networked duck amount comes from the last simulation tick instead of the current one + calculate_duckamount( reset ); + fix_jump_fall( reset ); + validate_animation_layers( ); + + float old_cycle = m_AnimOverlay( ).GetElements( )[ 6 ].m_flCycle; + get_animstate( )->m_iLastClientSideAnimationUpdateFramecount -= 1; + + vec3_t velocity = m_vecVelocity( ); + int backup_eflags = get< int >( 0xe4 ); + int backup_byte = get< byte >( 0x35f8 ); + + if( !reset ) { + m_vecVelocity( ) = sm_animdata[ idx ].m_anim_velocity; + get< vec3_t >( 0x94 ) = sm_animdata[ idx ].m_anim_velocity; + get< byte >( 0x35f8 ) = 1; + get< int >( 0xe4 ) &= ~0x1000; + + get_animstate( )->m_flUnknownFraction = sm_animdata[ idx ].m_fraction; + } + + sm_animdata[ idx ].m_last_duck = m_flDuckAmount( ); + + float prev_cycle = m_AnimOverlay( ).GetElements( )[ 6 ].m_flPrevCycle; + float prev_rate = m_AnimOverlay( ).GetElements( )[ 6 ].m_flPlaybackRate; + + if( !reset ) { + auto fraction = get_animstate( )->m_flStopToFullRunningFraction; + bool stopping = sm_animdata[ idx ].m_is_stopping; + + if( fraction > 0.1f && fraction < 1.f ) { + float delta_2x = get_animstate( )->m_flLastUpdateDelta * 2.f; + + if( stopping ) + fraction -= delta_2x; + else + fraction += delta_2x; + + fraction = std::clamp( fraction, 0.f, 1.f ); + } + + auto speed = get_anim_velocity( ).length2d( ); + + if( speed > 135.2f && stopping ) { + sm_animdata[ idx ].m_is_stopping = false; + fraction = std::max( fraction, 0.0099999998f ); + } + if( speed < 135.2f && !stopping ) { + sm_animdata[ idx ].m_is_stopping = true; + fraction = std::min( fraction, 0.99000001f ); + } + + get_animstate( )->m_flStopToFullRunningFraction = fraction; + } + + sm_animdata[ idx ].m_last_animtime = get_animstate( )->m_flLastClientSideAnimationUpdateTime; + get_animstate( )->update( eye_angles.y, eye_angles.x ); + m_AnimOverlay( ).GetElements( )[ 6 ].m_flPrevCycle = m_AnimOverlay( ).GetElements( )[ 6 ].m_flCycle; + + float lerp_rate = math::lerp( + prev_rate, + m_AnimOverlay( ).GetElements( )[ 6 ].m_flPlaybackRate, + TICK_INTERVAL( ) / ( m_flSimulationTime( ) - m_flOldSimulationTime( ) ) ); + + if( !reset ) { + m_AnimOverlay( ).GetElements( )[ 6 ].m_flCycle = prev_cycle + lerp_rate; + } + + get_animdata( ).m_prev_flags = flags; + memcpy( + get_animdata( ).m_last_layers.data( ), + m_AnimOverlay( ).GetElements( ), + sizeof( C_AnimationLayer ) * 13 + ); + + sm_animdata[ idx ].m_fraction = get_animstate( )->m_flUnknownFraction; + + m_vecVelocity( ) = velocity; + get< vec3_t >( 0x94 ) = velocity; + get< int >( 0xe4 ) = backup_eflags; + get< byte >( 0x35f8 ) = backup_byte; + + m_AnimOverlay( ).GetElements( )[ 6 ].m_flPrevCycle = old_cycle; + + //check for any possible mistakes + validate_animation_layers( ); + + sm_animdata[ idx ].m_adjust_rate = m_AnimOverlay( ).GetElements( )[ 3 ].m_flPlaybackRate; + sm_animdata[ idx ].m_adjust_cycle = m_AnimOverlay( ).GetElements( )[ 3 ].m_flCycle; + + if( m_flSimulationTime( ) - m_flOldSimulationTime( ) > TICK_INTERVAL( ) ) { + auto activity = get_seq_activity( m_AnimOverlay( ).GetElements( )[ 3 ].m_nSequence ); + + if( activity == 979 ) { + m_AnimOverlay( ).GetElements( )[ 3 ].m_flWeight = 0.f; + m_AnimOverlay( ).GetElements( )[ 3 ].m_flCycle = 0.f; + } + } + + bool moving = sm_animdata[ idx ].m_anim_velocity.length( ) > 0.1f; + //compute_move_cycle( reset, moving ); + + get_animdata( ).m_anim_flags = m_fFlags( ); + + if( !moving ) + m_AnimOverlay( ).GetElements( )[ 6 ].m_flWeight = 0.f; + + ce( )->GetRenderAngles( ).y = std::remainderf( ce( )->GetRenderAngles( ).y, 360.f ); + + m_flDuckAmount( ) = original_duck; + m_fFlags( ) = flags; + m_angEyeAngles( ) = eye_angles; + m_flDuckAmount( ) = original_duck; + + get_animstate( )->m_flUnknownFraction = 0.f; + + //clear occlusion for setupbones (pvs fix) + *( int* )( uintptr_t( this ) + 0xa30 ) = 0; + + byte backup = get< byte >( 0x270 ); + get< byte >( 0x270 ) = 0; + + invalidate_bone_cache( ); + ce( )->SetupBones( nullptr, -1, BONE_USED_BY_ANYTHING, anim_time ); + cache_anim_data( ); + + g_csgo.m_globals->m_curtime = backup_curtime; + g_csgo.m_globals->m_frametime = backup_frametime; + + if( !reset ) { + sm_animdata[ idx ].m_valid = true; + } + + //disable animations again + m_bClientSideAnimation( ) = false; + get< byte >( 0x270 ) = backup; +} + +player_info_t c_base_player::get_info( ) { + player_info_t info; + g_csgo.m_engine( )->GetPlayerInfo( ce( )->GetIndex( ), &info ); + + return info; +} + +bool c_base_player::is_flashed( ) { + return m_flFlashTime( ) - g_csgo.m_globals->m_curtime > m_flFlashDuration( ) * 0.5f; +} + +bool c_base_player::is_reloading( ) { + auto gun_layer = m_AnimOverlay( ).GetElements( )[ 1 ]; + float playback_rate = gun_layer.m_flPlaybackRate; + if( playback_rate < 0.55f ) { + return gun_layer.m_flCycle < 0.99f; + } + + return false; +} + +void c_base_player::get_name_safe( char* buf ) { + player_info_t info; + if( g_csgo.m_engine( )->GetPlayerInfo( this->ce( )->GetIndex( ), &info ) ) { + for( size_t i{ }; i < 32; ++i ) { + switch( info.name[ i ] ) { + case '"': + case '\\': + case ';': + case '\n': + buf[ i ] = ' '; + break; + default: + buf[ i ] = info.name[ i ]; + break; + } + } + + buf[ 31 ] = 0; + } +} + +void c_base_player::set_local_view_angles( vec3_t *angle ) { + using fn = void( __thiscall * )( void *, vec3_t * ); + util::get_vfunc< fn >( this, 363 )( this, angle ); +} + +bool c_base_player::run_physics_think( int unk01 ) { + static auto impl = reinterpret_cast< bool( __thiscall * )( void *, int ) >( + pattern::first_code_match( g_csgo.m_chl.dll( ), xors( "55 8B EC 83 EC 10 53 56 57 8B F9 8B 87 ? ? ? ? C1 E8 16" ) ) + ); + + return impl( this, unk01 ); +} + +void c_base_player::pre_think( ) { + using fn = void( __thiscall * )( void * ); + util::get_vfunc< fn >( this, 309 )( this ); +} + +void c_base_player::think( ) { + using fn = void( __thiscall * )( void * ); + util::get_vfunc< fn >( this, 137 )( this ); +} + +void c_base_player::setup_bones_ex( matrix3x4* array_out, int bone_mask, float curtime ) { +/* auto hdr = *( studiohdr_t** )( uintptr_t( ce( )->GetClientRenderable( ) ) + 0x2938 ); + auto bone_array = ( matrix3x4* )( m_dwBoneMatrix( ) ); + + auto readable_bones = *( int* )( ( uintptr_t )ce( )->GetClientRenderable( ) + 0x2694 ); + bone_mask |= readable_bones; + + //backup necessary data + matrix3x4 backup_bone_array[ 128 ]; + float backup_pose_params[ 24 ]; + + memcpy( backup_bone_array, + ( void* )( m_dwBoneMatrix( ) ), + sizeof( backup_bone_array ) ); + + memcpy( backup_pose_params, + m_flPoseParameter( ), + sizeof( backup_pose_params ) ); + + vec3_t backup_origin = ce( )->GetRenderOrigin( ); + vec3_t backup_angles = ce( )->GetRenderAngles( ); + + //setup a transform matrix + matrix3x4 transform{ }; + math::angle_imatrix( backup_angles, transform ); + math::set_matrix_position( backup_origin, transform ); + + //set render flags + *( int* )( ( uintptr_t )ce( )->GetClientRenderable( ) + 0xE0 ) |= 8; + + update_ik_locks( m_flSimulationTime( ) ); + IKContext* ik = m_IKContext( ); + + if( ik ) { + ik->ClearTargets( ); + ik->Init( hdr, backup_angles, + backup_origin, + curtime, + g_csgo.m_globals->m_framecount, + bone_mask ); + } + + vec3_t pos[ 128 ]; + float q[ 4 ][ 128 ]; + + standard_blending_rules( hdr, pos, q, curtime, bone_mask ); + + //idk but this is in ida + char computed[ 0x100 ]{ }; + + if( ik ) { + ik->UpdateTargets( pos, q, bone_array, computed ); + calculate_ik_locks( curtime ); + ik->SolveDependencies( pos, q, bone_array, computed ); + } + + build_transformations( hdr, pos, q, transform, bone_mask, computed ); + + //clear render flags + *( int* )( ( uintptr_t )ce( )->GetClientRenderable( ) + 0xE0 ) &= ~8; + + //copy new bone array into the matrix + memcpy( array_out, bone_array, 128 * sizeof( matrix3x4 ) ); + + /* + //restore data + memcpy( bone_array, + backup_bone_array, + sizeof( matrix3x4 ) ); + + memcpy( m_flPoseParameter( ), + backup_pose_params, + sizeof( backup_pose_params ) ); + + set_abs_angles( backup_angles ); + set_abs_origin( backup_origin ); + */ +} \ No newline at end of file -- cgit v1.2.3