Начинающий
- Статус
- Оффлайн
- Регистрация
- 15 Окт 2019
- Сообщения
- 44
- Реакции
- 6
resolver.cpp:
void Resolver::OnBodyUpdate(Player* player, float body) {
// validate player entity.
if (!player || !player->alive() || player->IsDormant())
return;
// ignore local player and teammates.
if (player == g_cl.m_local || player->IsTeammate(g_cl.m_local))
return;
// get lag compensation data for this player.
AimPlayer* lag_data = g_lagcomp.GetLagData(player->m_entIndex);
if (!lag_data || lag_data->m_records.empty())
return;
// get the most recent record.
LagRecord* current_record = &lag_data->m_records.front();
if (!current_record)
return;
// get resolver data for this player.
auto& resolver_data = m_resolver_data[player->m_entIndex];
// reset dormancy flag since we're receiving updates.
resolver_data.m_is_dormant = false;
// store previous body yaw for delta calculations.
const float previous_body = current_record->m_body;
// update the body yaw in the record.
current_record->m_body = body;
current_record->m_old_body = previous_body;
// normalize the body yaw.
body = math::NormalizedAngle(body);
// calculate body yaw delta from previous update.
const float body_delta = std::fabs(math::AngleDiff(body, previous_body));
// detect significant body yaw changes lby updates.
const bool is_lby_update = body_delta > 25.0f;
// constants
constexpr float LBY_UPDATE_PERIOD = 1.1f; // time between forced lby updates.
constexpr float FIRST_UNLOCK_DELAY = 0.22f; // delay after stopping movement.
// handle lby update detection and timing.
if (is_lby_update) {
// mark this as an lby update.
resolver_data.m_detect_body_update = 1;
resolver_data.m_last_lby_update_time = current_record->m_anim_time;
// schedule next expected lby update.
resolver_data.m_lower_body_realign_timer = current_record->m_anim_time + LBY_UPDATE_PERIOD;
// reset missed shots for lby prediction since we got a valid update.
resolver_data.m_missed_shots_lby = std::max(0, resolver_data.m_missed_shots_lby - 1);
// update lby prediction state.
resolver_data.m_in_prediction_state = true;
}
else {
// small body changes might indicate micro-adjustments.
if (body_delta > 1.0f && body_delta < 25.0f) {
resolver_data.m_micro_movement_detected = true;
}
}
// handle first-time body update after movement stops.
if (resolver_data.m_last_move_anim_time > 0.0f) {
const float time_since_stop = current_record->m_anim_time - resolver_data.m_last_move_anim_time;
// if this is the first body update after stopping, schedule unlock window.
if (time_since_stop >= FIRST_UNLOCK_DELAY && time_since_stop <= 0.5f) {
if (resolver_data.m_lower_body_realign_timer > current_record->m_anim_time + LBY_UPDATE_PERIOD) {
resolver_data.m_lower_body_realign_timer = current_record->m_anim_time + FIRST_UNLOCK_DELAY;
resolver_data.m_detect_body_update = 2; // mark as stop-based update.
}
}
}
// update body yaw history for pattern analysis.
resolver_data.m_body_history.push_front(body);
// limit history size to prevent memory bloat.
while (resolver_data.m_body_history.size() > 8) {
resolver_data.m_body_history.pop_back();
}
// analyze body yaw patterns for exploit detection.
AnalyzeBodyPatterns(player, resolver_data);
// store this body update for future reference.
resolver_data.m_previous_lower_body_yaw = body;
resolver_data.m_last_body_update_time = current_record->m_anim_time;
// increment body update counter for statistical analysis.
resolver_data.m_body_update_count++;
// validate body yaw consistency across choked packets.
ValidateBodyConsistency(player, current_record, resolver_data);
}
void Resolver::ValidateBodyConsistency(Player* player, LagRecord* record, resolver_data_t& data) {
// skip validation if not enough data.
if (!record || data.m_body_history.size() < 2)
return;
// get lag compensation data.
AimPlayer* lag_data = g_lagcomp.GetLagData(player->m_entIndex);
if (!lag_data || lag_data->m_records.size() < 2)
return;
// check consistency across recent records.
const auto& recent_record = lag_data->m_records.at(1);
const float time_delta = record->m_anim_time - recent_record.m_anim_time;
// if time delta suggests choked packets, validate body consistency.
if (time_delta > m_global_vars->m_interval * 1.5f) {
const float body_delta = std::fabs(math::AngleDiff(record->m_body, recent_record.m_body));
// large body changes over choked packets might indicate breaking.
if (body_delta > 120.0f) {
data.m_breaking_lc_detected = true;
data.m_last_lc_break_time = record->m_anim_time;
}
}
// validate against animation layers for additional consistency checks.
if (player->m_PlayerAnimState()) {
const auto& move_layer = player->m_AnimOverlay()[ANIMATION_LAYER_MOVEMENT_MOVE];
// if player is moving, body should be more stable.
if (move_layer.m_weight > 0.1f) {
const float expected_stability = 1.0f - (move_layer.m_weight * 0.8f);
const float actual_delta = data.m_body_history.size() > 1 ?
std::fabs(math::AngleDiff(data.m_body_history[0], data.m_body_history[1])) : 0.0f;
// if body is changing too much while moving, mark as suspicious.
if (actual_delta > (180.0f * expected_stability)) {
data.m_body_while_moving_detected = true;
}
}
}
}
void Resolver::AnalyzeBodyPatterns(Player* player, resolver_data_t& data) {
// need at least 3 samples for pattern analysis.
if (data.m_body_history.size() < 3)
return;
// check for jitter patterns.
bool is_jittering = true;
float total_delta = 0.0f;
for (size_t i = 1; i < data.m_body_history.size(); ++i) {
const float delta = std::fabs(math::AngleDiff(data.m_body_history[i], data.m_body_history[i - 1]));
total_delta += delta;
// if any delta is too small, it's probably not jittering.
if (delta < 5.0f) {
is_jittering = false;
break;
}
}
// detect body yaw jitter exploit.
if (is_jittering && total_delta > 180.0f) {
data.m_body_jitter_detected = true;
data.m_jitter_intensity = total_delta / (data.m_body_history.size() - 1);
}
else {
data.m_body_jitter_detected = false;
data.m_jitter_intensity = 0.0f;
}
// detect fake body patterns (rapidly switching between two values).
if (data.m_body_history.size() >= 4) {
const float first = data.m_body_history[0];
const float third = data.m_body_history[2];
const float delta_13 = std::fabs(math::AngleDiff(first, third));
// if alternating between similar angles, mark as fake body.
if (delta_13 < 5.0f) {
const float second = data.m_body_history[1];
const float delta_12 = std::fabs(math::AngleDiff(first, second));
if (delta_12 > 35.0f) {
data.m_fake_body_detected = true;
}
}
}
// reset fake body detection if pattern breaks.
if (data.m_body_history.size() >= 6) {
bool consistent_pattern = true;
for (size_t i = 2; i < std::min<size_t>(6, data.m_body_history.size()); i += 2) {
const float delta = std::fabs(math::AngleDiff(data.m_body_history[0], data.m_body_history[i]));
if (delta > 15.0f) {
consistent_pattern = false;
break;
}
}
if (!consistent_pattern) {
data.m_fake_body_detected = false;
}
}
}