Исходник Semi proper animation fix (sup paste ready)

Начинающий
Статус
Оффлайн
Регистрация
22 Сен 2018
Сообщения
25
Реакции[?]
5
Поинты[?]
3K
Начинающий
Статус
Оффлайн
Регистрация
15 Окт 2019
Сообщения
23
Реакции[?]
5
Поинты[?]
5K
edit added "silent updates" fix after comment war lol.

credits: https://yougame.biz/threads/325142/

Пожалуйста, авторизуйтесь для просмотра ссылки.

formated bonzo code, added velocity recalculation and land/fall fix:
#include "includes.h"
// credits: https://yougame.biz/threads/325142/
// https://github.com/LAITHCOOL/laith-legendware-rework/blob/05d18bde61644291e29a5d81f9772c16770fe223/cheats/lagcompensation/animation_system.cpp

void handle_silent_updates(Player* player, c_animstate* state) {
    if (!player || !state) return;

    // Check if the last frame was updated or if there is a significant time difference
    if (state->last_update_frame == g_csgo.m_globals->m_framecount) {
        // No need to update, as the frame was recently updated
        return;
    }

    // If a silent update is detected, reapply or interpolate the last known correct state
    float time_difference = g_csgo.m_globals->m_curtime - state->last_update_time;

    // If the time difference exceeds a threshold, consider it a silent update
    if (time_difference > g_csgo.m_globals->m_interval * 2) {
        // Reapply the last known state or interpolate to the current state
        state->eye_yaw = interpolate(state->eye_yaw, player->m_flLowerBodyYawTarget(), time_difference);
    }

    // Update the state variables to the current frame and time
    state->last_update_frame = g_csgo.m_globals->m_framecount;
    state->last_update_time = g_csgo.m_globals->m_curtime;

// Mini update function for handling animations
void anims::mini_update(Player* player) {
    if (!player) return;  // check for null pointer.

    C_AnimationLayer backup_layers[13];
    player->GetAnimLayers(backup_layers);

    // backup globalvars.
    float curtime = g_csgo.m_globals->m_curtime;
    float frame = g_csgo.m_globals->m_frame;
    float frametime = g_csgo.m_globals->m_frametime;

    // set frametime to IPT just like on the server during simulation.
    g_csgo.m_globals->m_curtime = player->m_flSimulationTime();
    g_csgo.m_globals->m_frame = g_csgo.m_cl->m_server_tick;
    g_csgo.m_globals->m_frametime = g_csgo.m_globals->m_interval;

    // remove abs velocity.
    player->m_iEFlags() &= ~0x1000;
    player->SetAbsVelocity(player->m_vecVelocity());

  // Handle silent updates before updating animations 
   handle_silent_updates(player, player->m_AnimState());

    // update animations.
    g_hooks.m_UpdateClientSideAnimation(player);

    // restore layers to networked.
    player->SetAnimLayers(backup_layers);

    // restore once we're done.
    g_csgo.m_globals->m_frame = frame;
    g_csgo.m_globals->m_curtime = curtime;
    g_csgo.m_globals->m_frametime = frametime;
}

// function to reset state variables.
void reset_state_vars(Player* player, c_animstate* state, LagRecord* record) {
    if (!player || !state || !record) return;

    state->on_ground = !!(player->m_fFlags() & FL_ONGROUND);
    state->landing = false;
    state->abs_yaw_last = state->abs_yaw = player->m_flLowerBodyYawTarget();
    state->eye_yaw = player->m_flLowerBodyYawTarget();
    state->eye_pitch = record->m_eye_angles.x;
    state->primary_cycle = record->m_layers[6].m_cycle;
    state->move_weight = record->m_layers[6].m_weight;
    state->strafe_sequence = record->m_layers[7].m_sequence;
    state->strafe_change_weight = record->m_layers[7].m_weight;
    state->strafe_change_cycle = record->m_layers[7].m_cycle;
    state->acceleration_weight = record->m_layers[12].m_weight;

    player->m_flOldSimulationTime() = state->last_update_time = record->m_sim_time - g_csgo.m_globals->m_interval;
    state->last_update_frame = g_csgo.m_cl->m_server_tick - 1;
    state->duration_in_air = 0.f;

    record->m_anim_velocity = player->m_vecVelocity();
    if (state->on_ground) {
        record->m_anim_velocity.z = 0.f;
        if (state->primary_cycle == 0.f || state->move_weight == 0.f) {
            record->m_anim_velocity = vec3_t();
        }
    }
}

// function to apply previous animation state.
void apply_previous_state(Player* player, c_animstate* state, LagRecord* record,  LagRecord* previous) {
    if (!player || !state || !record || !previous) return;

    player->SetAnimLayers(previous->m_layers);
    player->SetPoseParameters(previous->m_poses);
    state->primary_cycle = previous->m_layers[6].m_cycle;
    state->move_weight = previous->m_layers[6].m_weight;
    state->strafe_sequence = previous->m_layers[7].m_sequence;
    state->strafe_change_weight = previous->m_layers[7].m_weight;
    state->strafe_change_cycle = previous->m_layers[7].m_cycle;
    state->acceleration_weight = previous->m_layers[12].m_weight;

    // https://gitlab.com/KittenPopo/csgo-2018-source/-/blob/main/game/client/c_baseplayer.cpp#L1139
    // void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType )
    record->m_anim_velocity = (record->m_origin - previous->m_origin) * (1.f / game::TICKS_TO_TIME(record->m_lag));

    // task for reader: add proper velocity recalculation
    // hint CCSGOPlayerAnimState::SetUpAliveLoop
    // Ensure the player is on the ground and adjust the z-component of the velocity
    if ((previous->m_flags & FL_ONGROUND) && (record->m_flags & FL_ONGROUND)) {
        record->m_anim_velocity.z = 0.f;

        // Check if the player is in a fake walk state where the animation might have stopped
        if (record->m_layers[6].m_playback_rate == 0.f) {
            record->m_anim_velocity = vec3_t(); // Set velocity to zero if not moving
        }
    }
    else {
        // Handle airborne or jumping states where gravity and falling velocity should be calculated
        if (!(previous->m_flags & FL_ONGROUND)) {
            record->m_anim_velocity.z -= g_csgo.sv_gravity->GetFloat() * g_csgo.m_globals->m_interval;
        }
    }

    // Apply the recalculated velocity to the player's current state
    player->m_vecVelocity() = record->m_anim_velocity;
    player->SetAbsVelocity(record->m_anim_velocity);
}

void SimulatePlayerActivity(Player* pPlayer, LagRecord* m_LagRecord, LagRecord* m_PrevRecord) {
    if (!pPlayer || !m_LagRecord || !m_PrevRecord) return;

    // get animation layers.
    const C_AnimationLayer* m_JumpingLayer = &pPlayer->m_AnimOverlay()[ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL];
    const C_AnimationLayer* m_LandingLayer = &pPlayer->m_AnimOverlay()[ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB];
    const C_AnimationLayer* m_PrevJumpingLayer = &pPlayer->m_AnimOverlay()[ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL];
    const C_AnimationLayer* m_PrevLandingLayer = &pPlayer->m_AnimOverlay()[ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB];

    // detect jump/land, collect its data, rebuild time in air.
    const int nJumpingActivity = pPlayer->GetSequenceActivity(m_JumpingLayer->m_sequence);
    const int nLandingActivity = pPlayer->GetSequenceActivity(m_LandingLayer->m_sequence);

    // collect jump data.
    if (nJumpingActivity == ACT_CSGO_JUMP) {
        // check duration bounds.
        if (m_JumpingLayer->m_weight > 0.0f && m_JumpingLayer->m_playback_rate > 0.0f) {
            // check cycle changed.
            if (m_JumpingLayer->m_cycle < m_PrevJumpingLayer->m_cycle) {
                m_LagRecord->m_flDurationInAir = m_JumpingLayer->m_cycle / m_JumpingLayer->m_playback_rate;
                if (m_LagRecord->m_flDurationInAir > 0.0f) {
                    m_LagRecord->m_nActivityTick = game::TIME_TO_TICKS(m_LagRecord->m_sim_time - m_LagRecord->m_flDurationInAir) + 1;
                    m_LagRecord->m_nActivityType = EPlayerActivityC::CJump;
                }
            }
        }
    }

    // collect land data.
    if (nLandingActivity == ACT_CSGO_LAND_LIGHT || nLandingActivity == ACT_CSGO_LAND_HEAVY) {
        // weight changing everytime on activity switch in this layer.
        if (m_LandingLayer->m_weight > 0.0f && m_PrevLandingLayer->m_weight <= 0.0f) {
            // check cycle changed.
            if (m_LandingLayer->m_cycle > m_PrevLandingLayer->m_cycle) {
                float flLandDuration = m_LandingLayer->m_cycle / m_LandingLayer->m_playback_rate;

                if (flLandDuration > 0.0f) {
                    m_LagRecord->m_nActivityTick = game::TIME_TO_TICKS(m_LagRecord->m_sim_time - flLandDuration) + 1;
                    m_LagRecord->m_nActivityType = EPlayerActivityC::CLand;

                    // determine duration in air.
                    float flDurationInAir = (m_JumpingLayer->m_cycle - m_LandingLayer->m_cycle);
                    if (flDurationInAir < 0.0f)
                        flDurationInAir += 1.0f;

                    // set time in air.
                    m_LagRecord->m_flDurationInAir = flDurationInAir / m_JumpingLayer->m_playback_rate;
                }
            }
        }
    }
}

float ComputeActivityPlayback(Player* pPlayer, LagRecord* m_Record) {
    if (!pPlayer || !m_Record)  return 0.0f;

    // get animation layers.
    C_AnimationLayer* m_JumpingLayer = &pPlayer->m_AnimOverlay()[ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL];
    C_AnimationLayer* m_LandingLayer = &pPlayer->m_AnimOverlay()[ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB];
    C_AnimationLayer* moving = &pPlayer->m_AnimOverlay()[ANIMATION_LAYER_MOVEMENT_MOVE];

    // determine playback.
    float flActivityPlayback = 0.0f;

    switch (m_Record->m_nActivityType) {
    case EPlayerActivityC::CJump:
    {
        flActivityPlayback = pPlayer->GetLayerSequenceCycleRate(m_JumpingLayer, m_JumpingLayer->m_sequence);
    }
    break;

    case EPlayerActivityC::CLand:
    {
        flActivityPlayback = pPlayer->GetLayerSequenceCycleRate(m_LandingLayer, m_LandingLayer->m_sequence);
    }
    break;
    }

    return flActivityPlayback;

}

// Function to recalculate player velocity based on different conditions.
void RecalculateVelocity(Player* player, LagRecord* record, LagRecord* previous) {
    // Check if the player is valid
    if (!player || !record) return;

    // Check if previous record exists
    if (!previous) {
        // Default velocity calculation, using current velocity and potentially other factors.
        record->m_anim_velocity = player->m_vecVelocity();
        return;
    }

    // Calculate the velocity difference between the current and previous records
    vec3_t velocity_diff = record->m_origin - previous->m_origin;
    float time_diff = game::TICKS_TO_TIME(record->m_lag);

    // Handle case where there is no time difference to prevent division by zero
    if (time_diff > 0.f) {
        record->m_anim_velocity = velocity_diff * (1.f / time_diff);
    }
    else {
        // Set velocity to zero if time difference is invalid
        record->m_anim_velocity = vec3_t();
    }

    // Adjust z component for on-ground state
    if (record->m_flags & FL_ONGROUND) {
        record->m_anim_velocity.z = 0.f;
    }
    else {
        // Apply gravity for airborne state
        record->m_anim_velocity.z -= g_csgo.sv_gravity->GetFloat() * g_csgo.m_globals->m_interval;
    }
}

// function to handle the main update logic.
void perform_update_logic(Player* player, LagRecord* record, LagRecord* previous, c_animstate* state) {
    if (!player || !record || !state) return;

    // simulate player activity (jump/land) before processing.
    SimulatePlayerActivity(player, record, previous);

    // Recalculate velocity before updating animations.
    RecalculateVelocity(player, record, previous);

    // compute activity playback ( jump and land ).
    record->m_flActivityPlayback = ComputeActivityPlayback(player, record);

    for (int i = 1; i <= record->m_lag; i++) {
        const float interp = std::clamp(static_cast<float>(i) / static_cast<float>(record->m_lag), 0.f, 1.f);

        if (previous && record->m_lag > 1) {
            g_csgo.m_globals->m_curtime = math::lerp(interp, previous->m_sim_time, record->m_sim_time);
            player->m_vecVelocity() = math::lerp(interp, previous->m_anim_velocity, record->m_anim_velocity);
            player->m_flDuckAmount() = math::lerp(interp, previous->m_duck, record->m_duck);

            // handle jump and land activity.
            if (record->m_nActivityType != EPlayerActivityC::CNoActivity) {
                if (record->m_lag == record->m_nActivityTick) {
                    // compute the correct animation layer.
                    int nLayer = ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL;
                    if (record->m_nActivityType == EPlayerActivityC::CLand)
                        nLayer = ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB;

                    // set the player's animation state based on activity.
                    player->m_AnimOverlay()[nLayer].m_cycle = 0.0f;
                    player->m_AnimOverlay()[nLayer].m_weight = 0.0f;
                    player->m_AnimOverlay()[nLayer].m_playback_rate = record->m_flActivityPlayback;

                    // update player's ground state based on activity.
                    if (record->m_nActivityType == EPlayerActivityC::CJump)
                        player->m_fFlags() &= ~FL_ONGROUND;
                    else if (record->m_nActivityType == EPlayerActivityC::CLand)
                        player->m_fFlags() |= FL_ONGROUND;
                }
                else if (record->m_lag < record->m_nActivityTick) {
                    // force the player's ground state before the activity tick.
                    if (record->m_nActivityType == EPlayerActivityC::CJump)
                        player->m_fFlags() |= FL_ONGROUND;
                    else if (record->m_nActivityType == EPlayerActivityC::CLand)
                        player->m_fFlags() &= ~FL_ONGROUND;
                }
            }
        }
        else {
            player->m_vecVelocity() = record->m_anim_velocity;
        }

        player->m_iEFlags() &= ~0x1000;
        player->SetAbsVelocity(player->m_vecVelocity());
        player->m_angEyeAngles() = record->m_eye_angles;

        g_hooks.m_UpdateClientSideAnimation(player);
        record->m_abs_ang = ang_t(0.f, state->abs_yaw, 0.f);
        player->GetPoseParameters(record->m_poses);
    }

    player->UpdateCollisionBounds();
    record->m_maxs = player->m_vecMaxs();
    record->m_mins = player->m_vecMins();
    player->SetAnimLayers(record->m_layers);
    record->m_setup = player->SetupBones(record->m_bones, 128, BONE_USED_BY_ANYTHING, state->last_update_time);
}

// restore global variables after animation update.
void restore_globals(float frame, float curtime, float frametime) {
    g_csgo.m_globals->m_frame = frame;
    g_csgo.m_globals->m_curtime = curtime;
    g_csgo.m_globals->m_frametime = frametime;
}

// update function for handling detailed player animations.
void anims::update(Player* player, LagRecord* record, LagRecord* previous) {
    c_animstate* state = player->m_PlayerAnimState();

    // backup globalvars.
    float curtime = g_csgo.m_globals->m_curtime;
    float frame = g_csgo.m_globals->m_frame;
    float frametime = g_csgo.m_globals->m_frametime;

    // backup current animation state.
    AnimationBackup_t backup;
    backup.store(player);

    // set timing and simulate player animation state.
    g_csgo.m_globals->m_curtime = record->m_anim_time;
    g_csgo.m_globals->m_frame = g_csgo.m_cl->m_server_tick;
    g_csgo.m_globals->m_frametime = g_csgo.m_globals->m_interval;

    // handle player origins and reset state vars if needed.
    player->SetAbsOrigin(player->m_vecOrigin());

    // fix our animstate vars when animstate resets
    if (state->last_update_time == 0.f || !previous) {
        reset_state_vars(player, state, record);
    }
    // or fix animstate netvars using networked values
    else if (previous) {
        apply_previous_state(player, state, record, previous);
    }

    // resolve angles and update animations.
    if (!previous || (record->m_lag != 1 || previous->m_lag != 1)) {
        g_resolver.ResolveAngles(player, record);
    }

    perform_update_logic(player, record, previous, state);

    // restore backup and globalvars.
    backup.apply(player);
    restore_globals(frame, curtime, frametime);
}

// task: hook C_BasePlayer::PostDataUpdate() and call this in it
// or use FRAME_NET_UPDATE_POSTDATAUPDATE_START
void anims::player_instance(Player* player) {
    if (!player) return;

    c_animstate* state = player->m_PlayerAnimState();
    if (!state)
        return;

    AimPlayer* data = &g_aimbot.m_players[player->index() - 1];

    if (!player->alive() || !g_cl.m_processing) {
        if (player->m_flSimulationTime() != player->m_flOldSimulationTime())
            mini_update(player);

        data->m_records.clear();
        data->m_clear_next = true;
        return;
    }


    if (player->dormant()) {
        if (data->m_records.empty() || !data->m_records[0]->dormant()) {
            data->m_records.emplace_front(std::make_shared< LagRecord >(player));
            LagRecord* current = data->m_records.front().get();
            current->m_dormant = true;
            current->m_setup = false;
        }


        data->m_clear_next = true;
        return;
    }

    const float new_spawn = player->m_flSpawnTime();

    // fix
    if (player != data->m_player || data->m_clear_next || data->m_spawn != new_spawn) {
        // reset animation state and records (they're all invalid).
        game::ResetAnimationState(state);
        data->m_records.clear();
        data->m_walk_record = LagRecordMove{};

        // alternative fix.
        player->m_flOldSimulationTime() = player->m_flSimulationTime() - g_csgo.m_globals->m_interval;
    }

    // update our vars
    data->m_player = player;
    data->m_clear_next = false;
    data->m_spawn = new_spawn;

    // player updated.
    if (data->m_records.empty() || data->m_records[0]->m_sim_time != player->m_flSimulationTime()) {
        // emplace new record.
        data->m_records.emplace_front(std::make_shared< LagRecord >(player));

        // get our new record.
        LagRecord* current = data->m_records.front().get();
        current->m_dormant = false;

        // update animations.
        update(player, current, data->m_records.size() > 1 ? data->m_records[1].get() : nullptr);
    }

    // don't store records that are too old.
    while (data->m_records.size() > 1) {
        if (std::abs(g_csgo.m_cl->m_server_tick - data->m_records.back()->m_tick) < 256)
            break;

        data->m_records.pop_back();
    }
}
 
Последнее редактирование:
Сверху Снизу