Начинающий
-
Автор темы
- #1
-
Код:
#include "resolver.hpp" #include "util_math.hpp" #include "tracing.hpp" #include "game_tools.hpp" #include "profiler.hpp" #include "autowall.hpp" #include "restore_netvars.hpp" namespace lambda { namespace cheat { namespace resolver { //Some namespace global variables float in_coming_latency = 0; float out_going_latency = 0; float server_time = 0; float lerp_time = 0; float correct = 0; //Config values, putting here set once per tick then just get called from here float backtrack_time = 2.0f; bool backtracking = false; bool fake_lag_fix = false; bool lby_resolver = false; bool real_resolver = false; bool in_attack_resolver = false; bool body_hit_resolver = false; int logic_history = 10; int logic_accuracy = 10; bool brute_force_resolver = false; bool pitch_resolve = false; int tick_count_set(const float sim_time) { //std::cout << lerp_time << " " << TIME_TO_TICKS(lerp_time) << std::endl; return TIME_TO_TICKS(sim_time + lerp_time) - 1; } void disable_interp() { //static auto cl_interpolate = interfaces::cvar->FindVar(XORSTRs("cl_interpolate")); //cl_interpolate->SetValue(0); //return; //Must iterate the entire entity list because rendering is on its own thread static const int max_entities = 64;// Interfaces::ClientEntList->GetHighestEntityIndex(); const int localplayerID = interfaces::engine->GetLocalPlayer(); for (int i = 0; i <= max_entities; i++) { if (i == localplayerID) continue; sdk::CCSPlayer* entity = static_cast<sdk::CCSPlayer*>(interfaces::entity_list->GetClientEntity(i)); if (!entity) continue; if (!entity->IsPlayer() || entity->GetDormant() || entity->GetHealth() < 1) continue; entity->disable_interp(); } } void set_up_netchan() { const bool local_player_alive = player_data::local_player_information.health > 0; //We want to set up some global values aaccross resolver for net chan here if (local_player_alive) { sdk::INetChannelInfo* nci = interfaces::engine->GetNetChannelInfo(); if (nci) { in_coming_latency = nci->GetLatency(int(sdk::INetChannelInfo::FlowDirection::FLOW_INCOMING)); out_going_latency = nci->GetLatency(int(sdk::INetChannelInfo::FlowDirection::FLOW_OUTGOING)); } else { in_coming_latency = out_going_latency = 0.0f; } //TODO: add fake ping calcs const float total_out_latency_fake_ping = out_going_latency; server_time = in_coming_latency + out_going_latency + TICKS_TO_TIME(interfaces::globals->tickcount + 1); static sdk::ConVar* cl_interp_ratio = nullptr; static sdk::ConVar* cl_updaterate = nullptr; if (!cl_interp_ratio) cl_interp_ratio = interfaces::cvar->FindVar(XORSTRs("cl_interp_ratio")); if (!cl_updaterate) cl_updaterate = interfaces::cvar->FindVar(XORSTRs("cl_updaterate")); const float interp_ratio = cl_interp_ratio->GetFloat(); const float update_rate = cl_updaterate->GetFloat(); lerp_time = interp_ratio / update_rate; correct = std::clamp(total_out_latency_fake_ping + lerp_time, 0.0f, 1.0f); } } void set_up_idea_points_no_resolve(render::IDrawer* drawer) { set_up_netchan(); for (int i = 0; i < 64; i++) { auto& target = player_data::player_records[i]; if (!target.is_player) continue; if (target.information.size() <= 0) continue; target.ideal_points.clear(); if (target.breaking_lag_comp) { target.ideal_points.push_back(0); continue; } for (size_t a = 0; a < target.information.size(); a++) { if (is_valid_time(target.information[a].sim_time)) target.ideal_points.push_back(a); } const auto& p = static_cast<sdk::CCSPlayer*>(target.client_entity); sdk::Vector middle; if(p->get_hitbox_information_detailed(0, middle)) { sdk::Vector screen; if (game_tools::world_to_screen(middle, screen)) { drawer->rectangle(screen.x, screen.y, 5, 5, 5, sdk::Color::Blue()); } } restore::restore_netvars_fsn(target.information.at(target.ideal_points.back()), static_cast<sdk::CCSPlayer*>(target.client_entity)); if (p->get_hitbox_information_detailed(0, middle)) { sdk::Vector screen; if (game_tools::world_to_screen(middle, screen)) { drawer->rectangle(screen.x, screen.y, 5, 5, 5, sdk::Color::Yellow()); } } } } //Begin resolver void begin_resolver() { PROFILE_FUNCTION(); const bool local_player_alive = player_data::local_player_information.health > 0; const int local_player_team_id = player_data::local_player_information.team_id; set_up_netchan(); //FIXME: move player data logs before this for (int i = 0; i < 64; i++) { auto& target = player_data::player_records[i]; if (target.information.size() < 2) continue; if (!target.is_player || local_player_team_id == target.team_id) continue; PROFILE_CUSTOM(____loop_prof, "Resolver Single Loop"); //FIXME: TODO: //Need to do some fake lag stuff in here, involving sim time updating and current_tick updating //Otherweise we will overwrite some normal information, this is different for if breaking lag comp //As we don't care about simtime updating since we cna't backtrack anyway auto& current_tick = target.information.front(); auto& previous_tick = target.information.at(1); const bool lby_updated = current_tick.lby_value != previous_tick.lby_value; sdk::QAngle resolver_angle = current_tick.original_viewangle; if (CON(resolve_pitch)) { pitch_resolver(resolver_angle.x); } //Leaving it as 64 * 64 just to trigger people const bool breaking_lag_comp = (current_tick.network_origin - previous_tick.network_origin).LengthSqr() > (64.0f * 64.0f ); if (breaking_lag_comp) { FakeLagFix::get()->extrapolation(current_tick.ticks_since_previous_update, i); } LogicResolver::get()->log_angles(current_tick.original_viewangle, sdk::QAngle(resolver_angle.x, current_tick.lby_value, 0), lby_updated, i); if (!local_player_alive) { continue; } //If localplayer isn't alive we don't care about soreing hte backtracking details iircn //If breaking lag comp can't backtrack. //TODO: find this out, and adjust accordingly: /* If they are breaking lag comp On tick 3 but they werne't breaking lag comp on tick 2 can you backtrack them to tick 2. And vice versa If they were breaking lag comp on tick 3, but not tick 4 can you backtrack them to tick 4. */ target.breaking_lag_comp = breaking_lag_comp; current_tick.breaking_lag_comp = breaking_lag_comp; bool found_better_backtrack = false; if (!breaking_lag_comp) { const bool real_angle = target.ticks_since_last_sim_time_update > 1; //NOTE: this could be done with > 0, but i think this is safer if (lby_updated && CON(resolve_backtrack_lby)) { resolver_angle.y = current_tick.lby_value; target.last_lby_update = current_tick.sim_time; current_tick.lby_updated = true; current_tick.lby_update_time = interfaces::globals->curtime - out_going_latency;//TODO: ping calcs maybe? found_better_backtrack = true; } if (real_angle && CON(resolve_backtrack_real)) { current_tick.real_angle = true; found_better_backtrack = true; resolver_angle.y = current_tick.original_viewangle.y; } //This is stuff we are checking from the previous tick and we will be updating previous_tick not current //TODO: add checks to see if last had a real angle resolve or had a lby resolve then don't bother with this //FIXME: TODO: BUG: for (size_t index = 0; index < target.information.size(); index++) { auto& test_tick = target.information.at(index); //Check to see if that tick could be letahl if(test_tick.did_hit) { const int health = target.health; test_tick.lethal_damage = health - test_tick.damage_done <= 0; if(test_tick.hitgroup == autowall::HITGROUP_HEAD) { test_tick.hit_in_head = true; } else if(test_tick.hitgroup > autowall::HITGROUP_HEAD) { test_tick.lethal_baim = health - test_tick.damage_done <= 0; } } else if (!test_tick.lby_updated && CON(resolve_backtrack_real) && !test_tick.real_angle && CON( resolve_backtrack_real)) { if (test_tick.body_hit_perfect) { test_tick.viewangle.y = test_tick.body_angle; } else if (false) { //FIXME: add a check to see if they fired this tick/last tick / how ever this is done } else if (test_tick.body_hit) { test_tick.viewangle.y = test_tick.body_angle; } } } //It is easier to hit a target, on the ground and if pitch is up so why not take advantage of this if (target.on_ground && CON(resolve_prefer_on_ground)) { current_tick.on_ground = true; if ((interfaces::globals->curtime - out_going_latency) - current_tick.lby_update_time > 1.14f) current_tick.lby_update_time_1p1 = true; } if (CON(resolve_prefer_up) && resolver_angle.x < 10 && resolver_angle.x > -90) { //If they are looking up then lets log this since it is so much easier to hit then if they are using a down aa current_tick.pitch_up = true; } } if (!found_better_backtrack || breaking_lag_comp) { //Going to use logic only here, however may want to get brute force added //We use brute force, from logic if it can't resolve any patterns //TODO: //Should apply some logic to do w/ ping fps etc. for future ticks for it //To be more effective //If we get to this point reoslver_angles hasn't been set so is the same as original //angles switch (CON(resolver_type)) { case 1: BruteForceResolver::get()->brute_force_resolver(resolver_angle, i); break; default: LogicResolver::get()->predict_angles(resolver_angle, 1, i); } } current_tick.viewangle = resolver_angle; //Angle has been resolved, now lets create a deque in order of best points to resolve, //Then aimbot can take those and decide based on damage. set_possible_points(i); //Update angles restore::restore_netvars_fsn(target.information.at(target.ideal_points.front()), static_cast<sdk::CCSPlayer*>(target.client_entity)); } } //returns false if resolver angle is not possible bool resolver_sanity_check(float angle, float last_lby_update, float curtime, bool on_ground, float lby) { if (!on_ground) return true; if (curtime - last_lby_update < 1.1f) return true; if (sdk::math::difference_between_yaw(angle, lby) <= 35) return true; return false; } bool has_local_player_updated(int index, int tick) { const auto& local_record = player_data::local_player_information; auto record = player_data::player_records[index].information[tick]; //Maybe add some margin or error in here. if (record.local_player_duck_amount != local_record.duck_amount) return true; if (record.local_player_origin != local_record.origin) return true; return false; } #ifdef ORIGINAL_RESOLVER_ORDER void set_possible_points(int index) { // TODO: this whole thing can be replaced with a std::sort auto& target = player_data::player_records[index]; target.ideal_points.clear(); if (target.breaking_lag_comp) { target.ideal_points.push_back(0); return; } //All possible resolver types, and where we want them std::deque<int> lby_update_on_ground_head_up; std::deque<int> lby_update_on_ground; std::deque<int> lby_update_on_head_up; std::deque<int> lby_update; std::deque<int> real_update_on_ground_head_up; std::deque<int> real_update_on_ground; std::deque<int> real_update_on_head_up; std::deque<int> real_update; std::deque<int> body_shot_perfect_update_on_ground_head_up; std::deque<int> body_shot_perfect_update_on_ground; std::deque<int> body_shot_perfect_update_on_head_up; std::deque<int> body_shot_perfect_update; std::deque<int> in_attack_update_on_ground_head_up; std::deque<int> in_attack_update_on_ground; std::deque<int> in_attack_update_on_head_up; std::deque<int> in_attack_update; std::deque<int> body_shot_update_on_ground_head_up; std::deque<int> body_shot_update_on_ground; std::deque<int> body_shot_updatnoe_on_head_up; std::deque<int> body_shot_update; std::deque<int> lby_1p1_update_on_ground_head_up; std::deque<int> lby_1p1_update; //On_ground is a compolsary component of this std::deque<int> not_breaking_lag_comp_update_on_ground_head_up; std::deque<int> not_breaking_lag_comp_update_on_ground; std::deque<int> not_breaking_lag_comp_update_on_head_up; std::deque<int> not_breaking_lag_comp_update; //once again this needs to be done better will change when way history is stored for (size_t i = 0; i < target.information.size(); i++) { const auto& record = target.information[i]; //Some tweaking will need to be done to deal with has_local_player_updated if (!is_valid_time(record.sim_time)) continue; bool on_ground = record.on_ground; bool head_up = record.pitch_up; if (record.lby_updated) { if (on_ground && head_up) lby_update_on_ground_head_up.push_back(i); else if (on_ground) lby_update_on_ground.push_back(i); else if (head_up) real_update_on_head_up.push_back(i); else lby_update.push_back(i); } else if (record.real_angle) { if (on_ground && head_up) real_update_on_ground_head_up.push_back(i); else if (on_ground) real_update_on_ground.push_back(i); else if (head_up) real_update_on_head_up.push_back(i); else real_update.push_back(i); } else if (record.body_hit_perfect) { if (on_ground && head_up) body_shot_perfect_update_on_ground_head_up.push_back(i); else if (on_ground) body_shot_perfect_update_on_ground.push_back(i); else if (head_up) real_update_on_head_up.push_back(i); else body_shot_perfect_update.push_back(i); } else if (record.shot_fired) { if (on_ground && head_up) in_attack_update_on_ground_head_up.push_back(i); else if (on_ground) in_attack_update_on_ground.push_back(i); else if (head_up) real_update_on_head_up.push_back(i); else in_attack_update.push_back(i); } else if (record.body_hit) { if (on_ground && head_up) body_shot_update_on_ground_head_up.push_back(i); else if (on_ground) body_shot_update_on_ground.push_back(i); else if (head_up) real_update_on_head_up.push_back(i); else body_shot_update.push_back(i); } else if (record.lby_update_time_1p1) { if (on_ground && head_up) lby_1p1_update_on_ground_head_up.push_back(i); else lby_1p1_update.push_back(i); } else { if (on_ground && head_up) not_breaking_lag_comp_update_on_ground_head_up.push_back(i); else if (on_ground) not_breaking_lag_comp_update_on_ground.push_back(i); else if (head_up) not_breaking_lag_comp_update_on_head_up.push_back(i); else not_breaking_lag_comp_update.push_back(i); } } std::deque<int> ideal_order; //Now apply these into a single deque //There is bound to be a more efficent way to do this ideal_order.insert(ideal_order.end(), lby_update_on_ground_head_up.begin(), lby_update_on_ground_head_up.end()); ideal_order.insert(ideal_order.end(), lby_update_on_ground.begin(), lby_update_on_ground.end()); ideal_order.insert(ideal_order.end(), lby_update_on_head_up.begin(), lby_update_on_head_up.end()); ideal_order.insert(ideal_order.end(), lby_update.begin(), lby_update.end()); ideal_order.insert(ideal_order.end(), real_update_on_ground_head_up.begin(), real_update_on_ground_head_up.end()); ideal_order.insert(ideal_order.end(), real_update_on_ground.begin(), real_update_on_ground.end()); ideal_order.insert(ideal_order.end(), real_update_on_head_up.begin(), real_update_on_head_up.end()); ideal_order.insert(ideal_order.end(), real_update.begin(), real_update.end()); ideal_order.insert(ideal_order.end(), body_shot_perfect_update_on_ground_head_up.begin(), body_shot_perfect_update_on_ground_head_up.end()); ideal_order.insert(ideal_order.end(), body_shot_perfect_update_on_ground.begin(), body_shot_perfect_update_on_ground.end()); ideal_order.insert(ideal_order.end(), body_shot_perfect_update_on_head_up.begin(), body_shot_perfect_update_on_head_up.end()); ideal_order.insert(ideal_order.end(), body_shot_perfect_update.begin(), body_shot_perfect_update.end()); ideal_order.insert(ideal_order.end(), in_attack_update_on_ground_head_up.begin(), in_attack_update_on_ground_head_up.end()); ideal_order.insert(ideal_order.end(), in_attack_update_on_ground.begin(), in_attack_update_on_ground.end()); ideal_order.insert(ideal_order.end(), in_attack_update_on_head_up.begin(), in_attack_update_on_head_up.end()); ideal_order.insert(ideal_order.end(), in_attack_update.begin(), in_attack_update.end()); ideal_order.insert(ideal_order.end(), body_shot_update_on_ground_head_up.begin(), body_shot_update_on_ground_head_up.end()); ideal_order.insert(ideal_order.end(), body_shot_update_on_ground.begin(), body_shot_update_on_ground.end()); ideal_order.insert(ideal_order.end(), body_shot_updatnoe_on_head_up.begin(), body_shot_updatnoe_on_head_up.end()); ideal_order.insert(ideal_order.end(), body_shot_update.begin(), body_shot_update.end()); ideal_order.insert(ideal_order.end(), lby_1p1_update_on_ground_head_up.begin(), lby_1p1_update_on_ground_head_up.end()); ideal_order.insert(ideal_order.end(), lby_1p1_update.begin(), lby_1p1_update.end()); ideal_order.insert(ideal_order.end(), not_breaking_lag_comp_update_on_ground_head_up.begin(), not_breaking_lag_comp_update_on_ground_head_up.end()); ideal_order.insert(ideal_order.end(), not_breaking_lag_comp_update_on_ground.begin(), not_breaking_lag_comp_update_on_ground.end()); ideal_order.insert(ideal_order.end(), not_breaking_lag_comp_update_on_head_up.begin(), not_breaking_lag_comp_update_on_head_up.end()); ideal_order.insert(ideal_order.end(), not_breaking_lag_comp_update.begin(), not_breaking_lag_comp_update.end()); //This deque is used by the aimnot to take the ideal hitbox positions target.ideal_points = ideal_order; } #else bool compare_record_quality(const player_data::PlayerInformation& a, const player_data::PlayerInformation& b) { if (a.on_ground && a.pitch_up && b.on_ground && b.pitch_up) return a.sim_time <= b.sim_time; if (a.on_ground && b.on_ground) return a.sim_time <= b.sim_time; if (a.pitch_up && b.pitch_up) return a.sim_time <= b.sim_time; if (a.on_ground && !b.on_ground) return true; if (!a.on_ground && b.on_ground) return false; if (a.pitch_up && b.pitch_up) return a.sim_time <= b.sim_time; if (a.pitch_up && !b.pitch_up) return true; if (!a.pitch_up && b.pitch_up) return false; return a.sim_time <= b.sim_time; } bool compare_tick_records(const player_data::PlayerInformation& a, const player_data::PlayerInformation& b) { if (a.lby_updated && !b.lby_updated) return true; if (!a.lby_updated && b.lby_updated) return false; if (a.lby_updated && b.lby_updated) return compare_record_quality(a, b); // No LBY Updates in either record if (a.real_angle && !b.real_angle) return true; if (!a.real_angle && b.real_angle) return false; if (a.real_angle && b.real_angle) return compare_record_quality(a, b); // No real angle updates in either tick if (a.body_hit_perfect && !b.body_hit_perfect) return true; if (!a.body_hit_perfect && b.body_hit_perfect) return false; if (a.body_hit_perfect && b.body_hit_perfect) return compare_record_quality(a, b); // No perfect body hit in either tick if (a.shot_fired && !b.shot_fired) return true; if (!a.shot_fired && b.shot_fired) return false; if (a.shot_fired && b.shot_fired) return compare_record_quality(a, b); // No shot fired in either tick if (a.body_hit && !b.body_hit) return true; if (!a.body_hit && !b.body_hit) return false; if (a.body_hit && b.body_hit) return compare_record_quality(a, b); // No body hit in either tick if (a.lby_update_time_1p1 && !b.lby_update_time_1p1) return true; if (!a.lby_update_time_1p1 && b.lby_update_time_1p1) return false; if (a.lby_update_time_1p1 && b.lby_update_time_1p1) { if (a.on_ground && b.on_ground && a.pitch_up && b.pitch_up) { return a.sim_time <= b.sim_time; } if (a.on_ground && a.pitch_up && (!b.pitch_up || !b.on_ground)) { return true; } if (b.on_ground && b.pitch_up && (!a.pitch_up || !a.on_ground)) { return false; } return a.sim_time <= b.sim_time; } // No update time 1p1 in either tick return compare_record_quality(a, b); } bool compare_tick_records_lethal(const player_data::PlayerInformation& a, const player_data::PlayerInformation& b) { if (a.lethal_baim && !b.lethal_baim) return true; if (!a.lethal_baim && b.lethal_baim) return false; if (a.lethal_damage && !b.lethal_damage) return true; if (!a.lethal_damage && b.lethal_damage) return false; if (a.hit_in_head && !b.hit_in_head) return true; if (!a.hit_in_head && b.hit_in_head) return false; return compare_tick_records(a, b); } void set_possible_points(const int index) { // TODO: this whole thing can be replaced with a std::sort PROFILE_FUNCTION(); auto& target = player_data::player_records[index]; target.ideal_points.clear(); if (target.breaking_lag_comp) { target.ideal_points.push_back(0); return; } std::deque<int> ideal_order(target.information.size()); size_t n(0); std::generate(begin(ideal_order), end(ideal_order), [&] { return n++; }); // Filter invalid times auto new_end = std::remove_if(ideal_order.begin(), ideal_order.end(), [&](int i) { return !is_valid_time(target.information[i].sim_time); }); // delete invalid records const auto to_delete = new_end - 1; ideal_order.erase(to_delete); // Sort records { PROFILE_CUSTOM(____sort_profiler, "Resolver Sorting"); std::sort(ideal_order.begin(), ideal_order.end(), [&](int i1, int i2) { const auto& a = target.information[i1]; const auto& b = target.information[i2]; return compare_tick_records_lethal(a, b); }); } //This deque is used by the aimbot to take the ideal hitbox positions target.ideal_points = ideal_order; } #endif bool is_valid_time(const float time) { const float target_time = time + lerp_time; const float delta_time = correct - (server_time - target_time); return (fabsf(delta_time) <= 0.2f); } //-------------------------------------- // Start logic reoslver, this resolver // uses history of angles to attempt to // rebuild target's antiaim //-------------------------------------- LogicResolver* LogicResolver::get() { static LogicResolver* s_logic_resolver = new LogicResolver(); return s_logic_resolver; } //This should be called once per tick to record the angles for the resolve to access void LogicResolver::log_angles(const sdk::QAngle& fake, const sdk::QAngle& real, const bool known_real, const int index) { history = int(CON(resolve_logic_history)); if (known_real) { auto& target = player_data::player_records[index]; if (target.information.size() > 0) { const auto& current_tick = target.information.front(); //Add real aka lby target.real_yaw.push_back(real.y); while (int(target.real_yaw.size()) > history) target.real_yaw.pop_back(); target.fake_yaw.push_back(fake.y); while (int(target.fake_yaw.size()) > history) target.fake_yaw.pop_back(); //Add calc angle from target to local player const sdk::Vector angle_to_local = sdk::math::calc_angle(current_tick.eye_position, player_data::local_player_information.eye_position); target.yaw_to_localplayer.push_front(angle_to_local.y); while (int(target.yaw_to_localplayer.size()) > history) target.yaw_to_localplayer.pop_back(); //add target vec velocity here const sdk::Vector velocity = current_tick.velocity; target.direction_of_velocity.push_front(sdk::math::velocity_to_yaw(velocity)); while (int(target.direction_of_velocity.size()) > history) target.direction_of_velocity.pop_back(); //Add tickcount target.real_ticks_count.push_front(current_user_cmd::cmd->tick_count); while (int(target.real_ticks_count.size()) > history) target.real_ticks_count.pop_back(); } } } void pitch_resolver(float& pitch) { if (pitch < -179.f) pitch += 360.f; else if (pitch > 90.0 || pitch < -90.0) pitch = 89.f; else if (pitch > 89.0 && pitch < 91.0) pitch -= 90.f; else if (pitch > 179.0 && pitch < 181.0) pitch -= 180; else if (pitch > -179.0 && pitch < -181.0) pitch += 180; else if (fabs(pitch) == 0) pitch = copysign(89.0f, pitch); } //This is used to predict an entities angle x ticks into the future void LogicResolver::predict_angles(sdk::QAngle& original_angle, int future_ticks, int index) { PROFILE_FUNCTION(); //TODO: compared currently LBY to previous LBY //TODO: predict next fake angle //TODO: bool LogicResolver::set_angle(float &angle, int index, int switch_val, float last_real) //Call this function at the start of the predict angles function if we predicted angles last time and we hit the target //If this were the case for the switch_val use the value of the enum that was set last time. //I think maybe if 2 shots at this 'working' value miss, then move on. auto& target = player_data::player_records[index]; auto& real_yaw_temp = target.real_yaw; const auto& fake_yaw_temp = target.fake_yaw; const auto& yaw_to_localplayer_temp = target.yaw_to_localplayer; const auto& direction_of_velocity_temp = target.direction_of_velocity; const auto& real_ticks_count_temp = target.real_ticks_count; if (fake_yaw_temp.size() < 1) { return; } float value_to_return = 0; for (int i = 0; i < future_ticks; i++) { int slots = real_yaw_temp.size(); float last_lby_update = target.last_lby_update; float current_local_time = 0; //FIXME: get curtime float time_since_lby_update = current_local_time - last_lby_update; float last_real = float(real_ticks_count_temp[0]); current_fake = original_angle.y; current_angle_to_localplayer = yaw_to_localplayer_temp[0]; current_direction_of_velocity = direction_of_velocity_temp[0]; bool on_ground = true; //FIXME: get if target is on ground int shots_missed = 0; //FIXME: get shots missed on target float last_lby = last_real; std::deque<float> test_values; std::vector<int> resolve_type; float angle = 0; float resolved_angle = last_real; //Real vs Fakes //FIXME: set up Real vs Fakes, like Real vs Target and the rest of the checks as seen below for (int j = 0; j < slots; j++) { test_values.push_back( sdk::math::normalise_yaw(sdk::math::difference_between_yaw(real_yaw_temp[j], fake_yaw_temp[j]))); } real_vs_fake_static_mean = 0; int real_vs_fake_level_jitter = 0; real_vs_fake_jitter_mean = 0; int real_vs_fake_level_spin = 0; real_vs_fake_spin_mean = 0; if (check_static(test_values, real_vs_fake_static_mean)) { set_angle(angle, index, LOGIC_REAL_VS_FAKE_STATIC, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) { resolve_type.push_back(LOGIC_REAL_VS_FAKE_STATIC); } } if (check_jitter(test_values, real_ticks_count_temp, real_vs_fake_jitter_mean, real_vs_fake_level_jitter)) { int jitter_level = LOGIC_REAL_VS_FAKE_LEVEL_1_JITTER; if (real_vs_fake_level_jitter == 2) jitter_level = LOGIC_REAL_VS_FAKE_LEVEL_2_JITTER; set_angle(angle, index, jitter_level, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) resolve_type.push_back(jitter_level); } if (check_spin(test_values, real_ticks_count_temp, real_vs_fake_spin_mean, real_vs_fake_level_spin)) { int spin_level = LOGIC_REAL_VS_FAKE_LEVEL_1_SPIN; if (real_vs_fake_level_spin == 2) spin_level = LOGIC_REAL_VS_FAKE_LEVEL_2_SPIN; set_angle(angle, index, spin_level, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) { resolve_type.push_back(spin_level); } } //Real vs Target for (int j = 0; j < slots; j++) { test_values.push_back( sdk::math::normalise_yaw(sdk::math::difference_between_yaw(real_yaw_temp[j], yaw_to_localplayer_temp[j]))); } real_vs_target_static_mean = 0; int real_vs_target_level_jitter = 0; real_vs_target_jitter_mean = 0; int real_vs_target_level_spin = 0; real_vs_target_spin_mean = 0; if (check_static(test_values, real_vs_target_static_mean)) { set_angle(angle, index, LOGIC_REAL_VS_TARGET_STATIC, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) { resolve_type.push_back(LOGIC_REAL_VS_TARGET_STATIC); } } if (check_jitter(test_values, real_ticks_count_temp, real_vs_target_jitter_mean, real_vs_target_level_jitter)) { int jitter_level = LOGIC_REAL_VS_TARGET_LEVEL_1_JITTER; if (real_vs_target_level_jitter == 2) jitter_level = LOGIC_REAL_VS_TARGET_LEVEL_2_JITTER; set_angle(angle, index, jitter_level, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) resolve_type.push_back(jitter_level); } if (check_spin(test_values, real_ticks_count_temp, real_vs_target_spin_mean, real_vs_target_level_spin)) { int spin_level = LOGIC_REAL_VS_TARGET_LEVEL_1_SPIN; if (real_vs_target_level_spin == 2) spin_level = LOGIC_REAL_VS_TARGET_LEVEL_2_SPIN; set_angle(angle, index, spin_level, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) { resolve_type.push_back(spin_level); } } //Real vs Zero for (int j = 0; j < slots; j++) { test_values.push_back(sdk::math::normalise_yaw(sdk::math::difference_between_yaw(real_yaw_temp[j], 0))); } real_vs_zero_static_mean = 0; int real_vs_zero_level_jitter = 0; real_vs_zero_jitter_mean = 0; int real_vs_zero_level_spin = 0; real_vs_zero_spin_mean = 0; if (check_static(test_values, real_vs_zero_static_mean)) { set_angle(angle, index, int(LOGIC_REAL_VS_ZERO_STATIC), last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) { resolve_type.push_back(int(LOGIC_REAL_VS_ZERO_STATIC)); } } if (check_jitter(test_values, real_ticks_count_temp, real_vs_zero_jitter_mean, real_vs_zero_level_jitter)) { int jitter_level = int(LOGIC_REAL_VS_ZERO_LEVEL_1_JITTER); if (real_vs_target_level_jitter == 2) jitter_level = int(LOGIC_REAL_VS_ZERO_LEVEL_2_JITTER); set_angle(angle, index, int(jitter_level), last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) { resolve_type.push_back(jitter_level); } } if (check_spin(test_values, real_ticks_count_temp, real_vs_zero_spin_mean, real_vs_zero_level_spin)) { int spin_level = int(LOGIC_REAL_VS_ZERO_LEVEL_1_SPIN); if (real_vs_target_level_jitter == 2) spin_level = int(LOGIC_REAL_VS_ZERO_LEVEL_2_SPIN); set_angle(angle, index, int(spin_level), last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) resolve_type.push_back(spin_level); } //Real vs perviousReal for (int j = 0; j < slots - 1; j++) { test_values.push_back( sdk::math::normalise_yaw(sdk::math::difference_between_yaw(real_yaw_temp[j], real_yaw_temp[j + 1]))); } real_vs_previous_real_static_mean = 0; int real_vs_previous_real_level_jitter = 0; real_vs_previous_real_jitter_mean = 0; int real_vs_previous_real_level_spin = 0; real_vs_previous_real_spin_mean = 0; if (check_static(test_values, real_vs_previous_real_static_mean)) { set_angle(angle, index, LOGIC_REAL_VS_PERVIOUSREAL_STATIC, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) { resolve_type.push_back(LOGIC_REAL_VS_PERVIOUSREAL_STATIC); } } if (check_jitter(test_values, real_ticks_count_temp, real_vs_previous_real_jitter_mean, real_vs_previous_real_level_jitter)) { int jitter_level = LOGIC_REAL_VS_PERVIOUSREAL_LEVEL_1_JITTER; if (real_vs_target_level_jitter == 2) jitter_level = LOGIC_REAL_VS_PERVIOUSREAL_LEVEL_2_JITTER; set_angle(angle, index, jitter_level, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) resolve_type.push_back(jitter_level); } if (check_spin(test_values, real_ticks_count_temp, real_vs_previous_real_spin_mean, real_vs_previous_real_level_spin)) { int spin_level = LOGIC_REAL_VS_PERVIOUSREAL_LEVEL_1_SPIN; if (real_vs_target_level_jitter == 2) spin_level = LOGIC_REAL_VS_PERVIOUSREAL_LEVEL_2_SPIN; set_angle(angle, index, spin_level, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) resolve_type.push_back(spin_level); } //Real vs Velocity for (int j = 0; j < slots; j++) { test_values.push_back( sdk::math::normalise_yaw(sdk::math::difference_between_yaw(real_yaw_temp[j], direction_of_velocity_temp[j]))); } real_vs_velocity_static_mean = 0; int real_vs_velocity_level_jitter = 0; real_vs_velocity_jitter_mean = 0; int real_vs_velocity_level_spin = 0; real_vs_velocity_spin_mean = 0; if (check_static(test_values, real_vs_velocity_static_mean)) { set_angle(angle, index, LOGIC_REAL_VS_VELOCITY_STATIC, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) { resolve_type.push_back(LOGIC_REAL_VS_VELOCITY_STATIC); } } if (check_jitter(test_values, real_ticks_count_temp, real_vs_velocity_jitter_mean, real_vs_velocity_level_jitter)) { int jitter_level = LOGIC_REAL_VS_VELOCITY_LEVEL_1_JITTER; if (real_vs_target_level_jitter == 2) jitter_level = LOGIC_REAL_VS_VELOCITY_LEVEL_2_JITTER; set_angle(angle, index, jitter_level, last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) resolve_type.push_back(jitter_level); } if (check_spin(test_values, real_ticks_count_temp, real_vs_velocity_spin_mean, real_vs_velocity_level_spin)) { int spin_level = int(LOGIC_REAL_VS_VELOCITY_LEVEL_1_SPIN); if (real_vs_target_level_jitter == 2) spin_level = int(LOGIC_REAL_VS_VELOCITY_LEVEL_2_SPIN); set_angle(angle, index, int(spin_level), last_real); if (is_valid_angle(angle, on_ground, time_since_lby_update, last_lby)) resolve_type.push_back(spin_level); } //Angles have been predicted //Let us brute force and set what we want most :) //Lets check if any of our algorthyms worked //TODO: Check if we used logic reoslver last and we hit, then we want to //call set_angle using same resolver type //FIXME: this can be done much better for logging hits, misses //to use if did hit logic to get best angle. Please can someone //Help me do this. Not sure best way. This will work well enough //I guess if (resolve_type.size() > 0) { int resolve_option = shots_missed % resolve_type.size(); set_angle(resolved_angle, index, resolve_type[resolve_option], last_real); target.last_logic_resolve_type = resolve_type[resolve_option]; } else if (on_ground && time_since_lby_update > 1.1f) { int resolve_type = LOGIC_LBY + shots_missed % 5; target.last_logic_resolve_type = resolve_type; set_angle(resolved_angle, index, resolve_type, last_lby); } else { //Didn't find any algorthym, have no real idea, so //Lets brute force the shit out of this sdk::QAngle angle = sdk::QAngle(0, resolved_angle, 0); BruteForceResolver::get()->brute_force_resolver(angle, i); resolved_angle = angle.y; } value_to_return = resolved_angle; //In theory should do the same as above to fake, velocity angles //etc. etc. but I can't see that being cpu efficent //Maybe just compare fake to velocity and just do that one //Who knows, thoughts? feel free to do it :) real_yaw_temp.push_front(value_to_return); real_yaw_temp.pop_back(); //To make sure deque stays same size, to avoid crashes } original_angle.y = value_to_return; } bool LogicResolver::is_valid_angle(float angle, bool on_ground, float time_since_lby_update, float last_lby) { if (on_ground && time_since_lby_update > 1.1f && sdk::math::difference_between_yaw(angle, last_lby) < 35) return true; if (!on_ground || time_since_lby_update < 1.1f) return true; return false; } //SOMEONE PLEASE CHECK THESE ALGORTHYMS float LogicResolver::set_static(float mean, float grounding_value) { /* Example of a static pattern, comparing real to fake Real: 90, 100, 110, 120, 140 Fake: 0, 10, 20, 30, 40 The static value is +90 from the grounding value, which is fake However, this pattern can also be considered a spin with the real being grounded to any static value This is what this fix is attempting to replicate and fix */ return grounding_value + mean; } float LogicResolver::set_jitter(float mean, float grounding_value, float last_value, float last_jitter_delta, int ticks) { /* Example of a level 1 jitter pattern, comparing real to 0 10, -10, 10, -10 The jitter to the set above is: 20 Example of a level 1 jitter pattern, comparing real to fake Real: -10, 20, 10, 40, 30 Fake: 0, 10, 20, 30, 40 This is what this fix is attempting to replicate and fix */ bool even = !(ticks % 2); bool should_be_addition = last_jitter_delta < 0; if (even) should_be_addition = !should_be_addition; if (should_be_addition) return grounding_value + mean; return grounding_value - mean; } //FIXME: not doing this correctly float LogicResolver::set_jitter_lv2(float mean, float grounding_value, float last_value, float last_jitter_delta, int ticks) { /* Example of a level 2 jitter pattern, comparing real to 0 0, -10, 10, -20, 20 The set of increments each time as seen below 0, -10, 20, -30, 40 The increment to the absolute value set above is: 10 Example of a level 1 jitter pattern, comparing real to fake Real: -10, 30, -10, 70, -10, 110 Fake: 0, 10, 20, 30, 40, 50 The set of increments each time as seen below -10, 20, -30, 40, -50, 60 The increment to the absolute value set above is: 10 This is what this fix is attempting to replicate and fix */ //bool should_be_addition = last_jitter_delta < 0; //for (int i = 0; i < ticks; i++) //{ // should_be_addition = !should_be_addition; // if (should_be_addition) // { // } //} bool even = !(ticks % 2); bool should_be_addition = last_jitter_delta < 0; if (even) should_be_addition = !should_be_addition; if (should_be_addition) return grounding_value + mean; return grounding_value - mean; } float LogicResolver::set_spin(float mean, float grounding_value, float last_spin_amount, int ticks) { /* Example of a level 1 spin pattern, comparing real to 0 0, 10, 20, 30, 40 The increment to the set above is: 10 This is what this fix is attempting to replicate and fix */ return grounding_value + last_spin_amount + mean * ticks; } float LogicResolver::set_spin_lv2(float mean, float grounding_value, float last_spin_amount, float last_lv2_spin_amount, int ticks) { /* Example of a level 2 spin pattern, comparing real to 0 0, 10, 30, 60, 100 The set of increments each time as seen below 0, 10, 20, 30, 40 The increment to the set above is: 10 Example of a level 2 spin pattern, comparing real to fake Real: 0, 30, 20, 50, 40 Fake: 0, 20, 0, 20, 0 The set of increments each time as seen below 0, 10, 20, 30, 40 The increment to the set above is: 10 This is what this fix is attempting to replicate and fix */ for (int i = 0; i < ticks; i++) { last_spin_amount += last_spin_amount + (last_lv2_spin_amount + mean); last_lv2_spin_amount += mean; } return grounding_value + last_spin_amount; } //FIXME: get the required values for the angle setting and add the appropriate information below //Phase the correct information into the set functions //grounding_value is the value the real is being compared against, for example, fake, last real, zero etc. //ticks = ticks between last real update and current tick //rest are pretty self explanitory please someone who isn't jake finish this for him. bool LogicResolver::set_angle(float& angle, int index, int switch_val, float last_real) { switch (switch_val) { case LOGIC_LBY: //Assuming last_real is current lby from the netvar angle = last_real; break; case LOGIC_LBY_P_35: angle = last_real + 35; break; case LOGIC_LBY_M_35: angle = last_real - 35; break; case LOGIC_LBY_P_20: angle = last_real + 20; break; case LOGIC_LBY_M_20: angle = last_real - 20; break; case LOGIC_REAL_VS_FAKE_STATIC: angle = set_static(real_vs_fake_static_mean, current_fake); break; case LOGIC_REAL_VS_FAKE_LEVEL_1_JITTER: angle = set_jitter(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_FAKE_LEVEL_2_JITTER: angle = set_jitter_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_FAKE_LEVEL_1_SPIN: angle = set_spin(real_vs_fake_jitter_mean, current_fake, 0, 0); break; case LOGIC_REAL_VS_FAKE_LEVEL_2_SPIN: angle = set_spin_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_TARGET_STATIC: angle = set_static(real_vs_target_static_mean, current_angle_to_localplayer); break; case LOGIC_REAL_VS_TARGET_LEVEL_1_JITTER: angle = set_jitter(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_TARGET_LEVEL_2_JITTER: angle = set_jitter_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_TARGET_LEVEL_1_SPIN: angle = set_spin(real_vs_fake_jitter_mean, current_fake, 0, 0); break; case LOGIC_REAL_VS_TARGET_LEVEL_2_SPIN: angle = set_spin_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_ZERO_STATIC: angle = set_static(real_vs_target_static_mean, 0); break; case LOGIC_REAL_VS_ZERO_LEVEL_1_JITTER: angle = set_jitter(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_ZERO_LEVEL_2_JITTER: angle = set_jitter_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_ZERO_LEVEL_1_SPIN: angle = set_spin(real_vs_fake_jitter_mean, current_fake, 0, 0); break; case LOGIC_REAL_VS_ZERO_LEVEL_2_SPIN: angle = set_spin_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_PERVIOUSREAL_STATIC: angle = set_static(real_vs_target_static_mean, last_real); break; case LOGIC_REAL_VS_PERVIOUSREAL_LEVEL_1_JITTER: angle = set_jitter(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_PERVIOUSREAL_LEVEL_2_JITTER: angle = set_jitter_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_PERVIOUSREAL_LEVEL_1_SPIN: angle = set_spin(real_vs_fake_jitter_mean, current_fake, 0, 0); break; case LOGIC_REAL_VS_PERVIOUSREAL_LEVEL_2_SPIN: angle = set_spin_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_VELOCITY_STATIC: angle = set_static(real_vs_target_static_mean, current_direction_of_velocity); break; case LOGIC_REAL_VS_VELOCITY_LEVEL_1_JITTER: angle = set_jitter(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_VELOCITY_LEVEL_2_JITTER: angle = set_jitter_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; case LOGIC_REAL_VS_VELOCITY_LEVEL_1_SPIN: angle = set_spin(real_vs_fake_jitter_mean, current_fake, 0, 0); break; case LOGIC_REAL_VS_VELOCITY_LEVEL_2_SPIN: angle = set_spin_lv2(real_vs_fake_jitter_mean, current_fake, 0, 0, 0); break; } return true; } //This function takes a deque of angles finds the standard deviation of these anlges //If this SD is smaller then the accuracy bool LogicResolver::check_static(const std::deque<float>& angle, float& meanvalue) { meanvalue = sdk::math::mean(angle.begin(), angle.end()); if (sdk::math::standard_deviation(angle.begin(), angle.end(), meanvalue) <= accuracy) { return true; } return false; } //This function finds the abs difference between angles for first degree and second //degree polynomials, using the SD to check for accuracy. //Spin does the same just not the ABS check. bool LogicResolver::check_jitter(const std::deque<float>& angle, const std::deque<int>& ticks, float& meanvalue, int& level) { std::deque<float> difference_lv1; int slots = angle.size(); std::deque<float> difference_lv2; std::deque<int> ticks_lv2; for (int i = 0; i < slots - 1; i++) { ticks_lv2.push_back(abs(ticks[i + 1] - ticks[i])); if (ticks_lv2[i] == 0) ticks_lv2[i] = 1; difference_lv1.push_back( sdk::math::normalise_yaw(abs(sdk::math::difference_between_yaw(angle[i], angle[i + 1]) / ticks_lv2[i]))); } meanvalue = sdk::math::mean(difference_lv1.begin(), difference_lv1.begin() + (slots - 1)); difference_lv1.at(slots - 1); if (sdk::math::standard_deviation(difference_lv1.begin(), difference_lv1.begin() + (slots - 1), meanvalue) <= accuracy) { level = 1; return true; } for (int i = 0; i < slots - 2; i++) { int tick_diff = abs(ticks_lv2[i + 1] - ticks_lv2[i]); if (tick_diff == 0) tick_diff = 1; difference_lv2.push_back(sdk::math::normalise_yaw( abs(sdk::math::difference_between_yaw(difference_lv1[i], difference_lv1[i + 1]) / tick_diff))); } meanvalue = sdk::math::mean(difference_lv2.begin(), difference_lv2.begin() + (slots - 2)); if (sdk::math::standard_deviation(difference_lv2.begin(), difference_lv2.begin() + (slots - 2), meanvalue) <= accuracy) { level = 2; return true; } return false; } bool LogicResolver::check_spin(const std::deque<float>& angle, const std::deque<int>& ticks, float& meanvalue, int& level) { std::deque<float> difference_lv1; int slots = angle.size(); std::deque<int> ticks_lv2; std::deque<float> difference_lv2; for (int i = 0; i < slots - 1; i++) { ticks_lv2.push_back(abs(ticks[i + 1] - ticks[i])); if (ticks_lv2[i] == 0) ticks_lv2[i] = 1; difference_lv1.push_back( sdk::math::normalise_yaw(sdk::math::difference_between_yaw(angle[i], angle[i + 1]) / ticks_lv2[i])); } meanvalue = sdk::math::mean(difference_lv1.begin(), difference_lv1.begin() + (slots - 1)); if (sdk::math::standard_deviation(difference_lv1.begin(), difference_lv1.begin() + (slots - 1), meanvalue) <= accuracy) { level = 1; return true; } for (int i = 0; i < slots - 2; i++) { int tick_diff = abs(ticks_lv2[i + 1] - ticks_lv2[i]); if (tick_diff == 0) tick_diff = 1; difference_lv2.push_back( sdk::math::normalise_yaw( sdk::math::difference_between_yaw(difference_lv1[i], difference_lv1[i + 1]) / tick_diff)); } meanvalue = sdk::math::mean(difference_lv2.begin(), difference_lv2.begin() + (slots - 2)); if (sdk::math::standard_deviation(difference_lv2.begin(), difference_lv2.begin() + (slots - 2), meanvalue) <= accuracy) { level = 2; return true; } return false; } BruteForceResolver* BruteForceResolver::get() { static BruteForceResolver* s_brute_force_resolver = new BruteForceResolver(); return s_brute_force_resolver; } void BruteForceResolver::brute_force_resolver(sdk::QAngle& original_angles, int index) { PROFILE_FUNCTION(); auto& target = player_data::player_records[index]; float curtime = 0; //FIXME: get curtime //Check history if (target.brute_force_sticky_point > 0 && set_angle(original_angles, index, target.last_brute_force_resolver_type)) { return; } //Check lby update confitions if (target.on_ground && curtime - target.last_lby_update > 1.1f) lby_brute_force(original_angles, index); int number_of_brute_force_options = LAST_BRUTE_FORCE_TYPE - BRUTE_NONE - 2; int shots_missed = 0; //FIXME: go to shots missed. int switch_value = LAST_BRUTE_FORCE_TYPE - 1 - shots_missed % number_of_brute_force_options; if (!set_angle(original_angles, index, switch_value)) { //Something has really fucked up here, as it shouldn't get to this point if it returning false original_angles.y = target.lby; target.last_brute_force_resolver_type = BRUTE_LBY; } } void BruteForceResolver::lby_brute_force(sdk::QAngle& original_angles, int index) { auto& target = player_data::player_records[index]; int shots_missed = 0; //FIXME: go to shots missed. int switch_value = shots_missed % 5 + BRUTE_LBY; set_angle(original_angles, index, switch_value); } bool BruteForceResolver::set_angle(sdk::QAngle& original_angles, int index, int switch_val) { auto& target = player_data::player_records[index]; switch (switch_val) { case BRUTE_LBY: original_angles.y = target.lby; break; case BRUTE_LBY_P_35: original_angles.y = target.lby + 35; break; case BRUTE_LBY_M_35: original_angles.y = target.lby - 35; break; case BRUTE_LBY_P_17: original_angles.y = target.lby + 17; break; case BRUTE_LBY_M_17: original_angles.y = target.lby - 17; break; case BRUTE_DIRECTION_TO_TARGET_M_135: original_angles.y = target.yaw_to_localplayer[0] - 135; break; case BRUTE_DIRECTION_TO_TARGET_M_45: original_angles.y = target.yaw_to_localplayer[0] - 45; break; case BRUTE_DIRECTION_TO_TARGET_P_45: original_angles.y = target.yaw_to_localplayer[0] + 45; break; case BRUTE_DIRECTION_TO_TARGET_P_135: original_angles.y = target.yaw_to_localplayer[0] + 135; break; case BRUTE_LBY_M_90: original_angles.y = target.lby - 90; break; case BRUTE_LBY_P_90: original_angles.y = target.lby + 90; break; case BRUTE_LBY_P_180: original_angles.y = target.lby + 180; break; case BRUTE_FAKE_M_135: original_angles.y -= 135; break; case BRUTE_FAKE_M_45: original_angles.y -= 45; break; case BRUTE_FAKE_P_45: original_angles.y += 45; break; case BRUTE_FAKE_P_135: original_angles.y += 135; break; case BRUTE_DIRECTION_TO_TARGET: original_angles.y = target.yaw_to_localplayer[0]; break; case BRUTE_DIRECTION_TO_TARGET_M_90: original_angles.y = target.yaw_to_localplayer[0] - 90; break; case BRUTE_DIRECTION_TO_TARGET_P_90: original_angles.y = target.yaw_to_localplayer[0] + 90; break; case BRUTE_DIRECTION_TO_TARGET_P_180: original_angles.y = target.yaw_to_localplayer[0] + 180; break; case BRUTE_LBY_M_135: original_angles.y = target.lby - 135; break; case BRUTE_LBY_M_45: original_angles.y = target.lby - 45; break; case BRUTE_LBY_P_45: original_angles.y = target.lby + 45; break; case BRUTE_LBY_P_135: original_angles.y = target.lby + 135; break; case BRUTE_FAKE: break; case BRUTE_FAKE_M_90: original_angles.y -= 90; break; case BRUTE_FAKE_P_90: original_angles.y += 90; break; case BRUTE_FAKE_P_180: original_angles.y += 180; break; } float curtime = 0;//FIXME if (!resolver_sanity_check(original_angles.y, target.last_lby_update, curtime, target.on_ground, target.lby)) return false; target.last_brute_force_resolver_type = switch_val; return true; } void BruteForceResolver::perfect_resolver(sdk::QAngle& original_angles) { original_angles.y = sdk::math::normalise_yaw(std::uniform_real_distribution<float>(-180, 180)(g_random_engine)); original_angles.x = sdk::math::normalise_pitch(std::uniform_real_distribution<float>(-89, 89)(g_random_engine)); } using namespace sdk; //Fake lag fix, lets simulate movement for 1 tick and make sure they don't go through walls FakeLagFix* FakeLagFix::get() { static FakeLagFix* s_fake_lag_fix = new FakeLagFix(); return s_fake_lag_fix; } void FakeLagFix::SimulateMovement(CSimulationData& data, bool in_air) { float gravity = 9.8f; //FIXME: get gravity float interval_per_tick = interfaces::globals->interval_per_tick; if (!(data.flags & FL_ONGROUND)) data.velocity.z -= interval_per_tick * gravity; else if (in_air) data.velocity.z = sqrt(91200.f); auto mins = data.current_tick.vec_min; auto maxs = data.current_tick.vec_max; auto src = data.network_origin; auto end = src + data.velocity * interval_per_tick; Ray_t ray; ray.Init(src, end, mins, maxs); trace_t trace; CTraceFilter filter; filter.m_icollisionGroup = COLLISION_GROUP_NONE; filter.pSkip = static_cast<IHandleEntity*>(data.entity); interfaces::engine_trace->TraceRay(ray, CONTENTS_SOLID, &filter, &trace); if (trace.fraction != 1.f) { for (int i = 0; i < 2; ++i) { data.velocity -= trace.plane.normal * data.velocity.Dot(trace.plane.normal); float dot = data.velocity.Dot(trace.plane.normal); if (dot < 0.f) { data.velocity.x -= dot * trace.plane.normal.x; data.velocity.y -= dot * trace.plane.normal.y; data.velocity.z -= dot * trace.plane.normal.z; } end = trace.endpos + data.velocity * (interval_per_tick * (1.f - trace.fraction)); ray.Init(trace.endpos, end, mins, maxs); interfaces::engine_trace->TraceRay(ray, CONTENTS_SOLID, &filter, &trace); if (trace.fraction == 1.f) break; } } data.network_origin = trace.endpos; end = trace.endpos; end.z -= 2.f; ray.Init(data.network_origin, end, mins, maxs); interfaces::engine_trace->TraceRay(ray, CONTENTS_SOLID, &filter, &trace); data.flags &= ~FL_ONGROUND; if (trace.fraction != 1.f && trace.plane.normal.z > 0.7f) data.flags |= FL_ONGROUND; } void FakeLagFix::extrapolation(int ticksChoked, int index) { auto target = player_data::player_records[index]; auto current_tick = target.information.front(); auto previous_tick = target.information.at(1); float interval_per_tick = interfaces::globals->interval_per_tick; Vector velocity = current_tick.velocity; Vector current_position = current_tick.network_origin; INetChannelInfo* nci = interfaces::engine->GetNetChannelInfo(); CSimulationData data; data.network_origin = current_position; data.velocity = velocity; data.flags = current_tick.flags; //Not sure if this should be avg or current shouldn't relaly matter float latency = nci->GetAvgLatency(int(INetChannelInfo::FlowDirection::FLOW_INCOMING)) + nci->GetAvgLatency(int(INetChannelInfo::FlowDirection::FLOW_OUTGOING)); float time_until_next_frame = 0;//Use this for FPS issues, iircn //FIXME: need to take into account psilent/fakelag packets. For now, just assume we choked ticksChoked is the amount of ticks the firing packet will be held back float time_when_packet_reaches_server = TICKS_TO_TIME( current_user_cmd::cmd->tick_count + TIME_TO_TICKS(latency + time_until_next_frame) + 1 + ticksChoked); //Time we reach the server - time the player was simulated on the server , clamped to sv_maxunlag (1.0 seconds) float delta_time = fminf(time_when_packet_reaches_server - current_tick.sim_time, 1.0f); int delta_ticks = TIME_TO_TICKS(delta_time); //How many choked ticks to simulate. int ticks = current_tick.ticks_since_previous_update; //Since I am not happy about just using last ticks for tick prediction I'm going to write up a polynomial pattern gusseer int current_choked_ticks = target.ticks_since_last_sim_time_update; if (current_choked_ticks > 15) current_choked_ticks = 15; ticks = predict_ticks_choked(index, current_choked_ticks); if (ticks > 20) //Something has clearly gone wrong with prediction so lets just completlely abort and go to last set ticks = current_tick.ticks_since_previous_update; int choked_ticks = std::clamp(ticks, 1, 15); int target_ticks = delta_ticks - choked_ticks; auto acceleartion = (current_tick.velocity - previous_tick.velocity) / float( TIME_TO_TICKS(current_tick.sim_time - previous_tick.sim_time)) / interval_per_tick; int predicted = 0; while (target_ticks >= 0) { for (int i = 0; i < choked_ticks; i++) { predicted++; bool in_air = false;// !(current_tick.flags & FL_ONGROUND); SimulateMovement(data, in_air); data.velocity.x += acceleartion.x * interval_per_tick; data.velocity.y += acceleartion.y * interval_per_tick; } target_ticks -= choked_ticks; } //FIXME: //TODO: //Update entities origin and flags from data } //Call this every single tick that the player's information updates (ie they send a tick again). //Then compare it to the number of ticks they did choke //If they are the same assume they are using this adaptive //This fake lag is a common method to break lag comp with sending least number of ticks //This is a reverse for [censored]'s adaptive should be similar to all other cheats also int FakeLagFix::using_adapive(int index) { auto& target = player_data::player_records[index]; auto current_tick = target.information.front(); float velocity_y = current_tick.velocity.y; float velocity_x = current_tick.velocity.x; int wish_ticks_1 = 0; int adapt_ticks = 2; double extrapolated_speed = sqrt(velocity_x * velocity_x + velocity_y * velocity_y) * interfaces::globals->interval_per_tick; while (wish_ticks_1 * extrapolated_speed <= 68.0) { if ((adapt_ticks - 1) * extrapolated_speed > 68.0) { ++wish_ticks_1; break; } if (adapt_ticks * extrapolated_speed > 68.0) { wish_ticks_1 += 2; break; } if ((adapt_ticks + 1) * extrapolated_speed > 68.0) { wish_ticks_1 += 3; break; } if ((adapt_ticks + 2) * extrapolated_speed > 68.0) { wish_ticks_1 += 4; break; } adapt_ticks += 5; wish_ticks_1 += 5; if (adapt_ticks > 16) break; } if (wish_ticks_1 > 16) wish_ticks_1 = 15; return wish_ticks_1; } int FakeLagFix::predict_ticks_choked(int index, int current_ticks_chocked) { //Assuming polnomial expansions, lets just keep differentialting the equation until we get something which works ;) //But they probably aren't using a polynomial, it is probably based on lag comp so velocity or step or static or random //Who knows but I'm going to enjoy writting this so fuck you auto& target = player_data::player_records[index]; const auto& choke_history = target.history_ticks_chocked_amounts; auto current_tick = target.information.front(); if (choke_history.size() < 1) return current_ticks_chocked; if (choke_history.size() < 4) return choke_history.front(); const float average = float(round(math::mean(choke_history.begin(), choke_history.end()))); const float standard_deviation = math::standard_deviation(choke_history.begin(), choke_history.end(), average); if (standard_deviation <= 2 && current_ticks_chocked <= average) return (int)average; // Probably average if SD is so low if (target.using_adaptive_fakelag) return using_adapive(index); //See if its a linear step int total_step = 0; //2nd degree step std::deque<int> difference2; int total_step2 = 0; //3rd degree step std::deque<int> difference3; int total_step3 = 0; //4th order polynomial std::deque<int> difference4; for (size_t i = 0; i < choke_history.size() - 1; i++) { difference2.push_back(choke_history[i + 1] - choke_history[i]); total_step += difference2[i]; } const float average_step = (float)(total_step / choke_history.size() - 1); const float standard_deviation_step = math::standard_deviation(difference2.begin(), difference2.end(), average_step); if (standard_deviation_step <= 1 && current_ticks_chocked <= average_step) return (int)average_step; // Probably average if SD is so l for (size_t i = 0; i < difference2.size() - 1; i++) { difference3.push_back(difference2[i + 1] - difference2[i]); total_step2 += difference3[i]; } const float average_step2 = (float)(total_step2 / difference2.size() - 1); const float standard_deviation_step2 = math::standard_deviation(difference3.begin(), difference3.end(), average_step2); if (standard_deviation_step2 <= 1 && current_ticks_chocked <= average_step2) return (int)average_step2; // Probably average if SD is so l for (size_t i = 0; i < difference3.size() - 1; i++) { difference4.push_back(difference3[i + 1] - difference3[i]); total_step3 += difference3[i]; } const float average_step3 = (float)(total_step3 / 17); const float standard_deviation_step3 = math::standard_deviation(difference4.begin(), difference4.end(), average_step3); if (standard_deviation_step3 <= 1 && current_ticks_chocked <= average_step3) return (int)average_step3; // Probably average if SD is so l //We have now checked if they are following a polynomial up to degree 4 //See here for complete complex algorthym http://www.johansens.us/sane/education/formula.htm int lastamount = choke_history.front(); if (current_ticks_chocked <= lastamount) return lastamount; return current_ticks_chocked; } EffectsResolver* EffectsResolver::get() { static EffectsResolver* s_effect_resolver = new EffectsResolver(); return s_effect_resolver; } //DO NOT TELL PEOPLE WE ARE USING THIS FOR A RESOLVER FOR FUCKS SAKE //TODO: check my logic I may be doing it wrong. //We are now getting hitbox, but we need to get actaul time they were hit since this is delayed //Apply ping calculations too //From mutiny credit to sharklazer + myself void EffectsResolver::begin_blood(C_TEEffectDispatch* thisptr, DataUpdateType_t updateType, render::IDrawer* draw) { if (!CON(resolver_enabled)) return; if (thisptr->m_EffectData.m_hEntity <= 0) return; const auto client_entity = interfaces::entity_list->GetClientEntityFromHandle(thisptr->m_EffectData.m_hEntity); auto entity = static_cast<CCSPlayer*>(client_entity); const int player_index = entity->GetIndex(); if (!(entity && entity->IsPlayer() && (CBasePlayer*)entity != player_data::local_player_information.entity)) return; if (player_index > 128) return; auto target = player_data::player_records[player_index]; //prevent access viloation if (target.information.size() <= 0) return; auto& current_tick = target.information.front(); const float simulation_time = current_tick.sim_time; //Since effects are delayed we need to find out how to get actual time for backtracking puroses const float time_player_was_shot = target.simtime_last_get_body_spot; //Santity check to make sure it is dealing with possible values if (simulation_time - time_player_was_shot > 0.5f) return; //Okay so we have established we want to resolve for blood spawning on this target. //Vector startorigin = pEntity->GetOrigin() + thisptr->m_EffectData.m_vStart; //Vector blood_origin = thisptr->m_EffectData.m_vOrigin; //TODO: Check if thi is correct const Vector blood_origin = entity->GetOrigin() + thisptr->m_EffectData.m_vOrigin; const Vector blood_direction = thisptr->m_EffectData.m_vNormal; const int hit_group_player_was_shot = thisptr->m_EffectData.m_nHitBox; //TODO: add some distance calculations in here too //Get start point of trace const Vector trace_start = blood_origin + (blood_direction * 64.0f); const Vector trace_ignore = blood_origin + (blood_direction * 1.0f); //don't count as valid if trace still hits slightly outside of the origin to get a more accurate angle player_data::PlayerInformation history_when_hit; bool found = false; for (auto& info : target.information) { if (info.sim_time != time_player_was_shot) continue; found = true; history_when_hit = info; break; } if (!found) return; entity->SetAbsOrigin(history_when_hit.network_origin); float first_yaw_found = 0; float first_body_yaw_found = 0; bool found_general_head = false; bool found_real_head = false; matrix3x4_t bonematrix[MAXSTUDIOBONES]; float current_yaw = history_when_hit.angle.y; CTraceFilter filter; filter.m_icollisionGroup = COLLISION_GROUP_NONE; Ray_t ray; trace_t tr; //Rotate player angles by i //Run trace from trace_start to origin //If it goes through the target and the ideal hitbox, then we are gucci //Now we want to scan orgin vs trace_ignore. //So if this is true the orgin is inside the hitbox and not actaully as perfect as trace_start. //So this provides a possible point but nowhere near as accurate. This should be considered an okay guess at best //If found good angle set resolver time to that of when the target was hit, the game event and this hook are both delayed so we need to get it more accurately, however in general it doesn't //have to be as acurate as say an in attack resolver, may fuck up if they are using some jitter or w/e for (int angle = 0; angle <= 1080; angle += 4) { float body_yaw = angle <= 360.0f ? 0.0f : angle <= 720.0f ? -1.0f : 1.0f; entity->SetPoseParameterScaled(11, body_yaw); entity->SetAbsAngles(QAngle(history_when_hit.angle.x, current_yaw, history_when_hit.angle.z)); //entity->SetupBones(bonematrix, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, interfaces::globals->curtime); if (!entity->SetupBones_invalid(bonematrix, MAXSTUDIOBONES, BONE_USED_BY_HITBOX, interfaces::engine->GetLastTimeStamp())) return; //Setup custom hitboxs mstudiohitboxset_t* set = interfaces::model_info->GetStudiomodel(entity->GetModel())->GetHitboxSet( entity->GetHitboxSet()); std::vector<tracing::CSphere> m_cSpheres; std::vector<tracing::COBB> m_cOBBs; for (int i = 0; i < set->numHitBoxes; i++) { mstudiobbox_t* pbox = set->GetHitbox(i); if (pbox->group == hit_group_player_was_shot) { if (pbox->radius != -1.0f) { Vector vMin, vMax; math::vector_transform(pbox->bbmin, bonematrix[pbox->bone], vMin); math::vector_transform(pbox->bbmax, bonematrix[pbox->bone], vMax); Vector Screen, Screen1; if (game_tools::world_to_screen(vMin, Screen) && game_tools::world_to_screen(vMax, Screen1)) { draw->line(Vector2D(Screen.x, Screen.y), Vector2D(Screen1.x, Screen1.y), Color::Green(), 6); } SetupCapsule(vMin, vMax, pbox->radius, pbox->group, m_cSpheres); } else { m_cOBBs.push_back(tracing::COBB(pbox->bbmin, pbox->bbmax, &bonematrix[pbox->bone], pbox->group)); } } } ray.Init(trace_start, blood_origin); //TODO: make trace for just one hitbox not all of them. trace_hitbox(entity, ray, tr, m_cSpheres, m_cOBBs); if (tr.m_pEnt == entity && tr.hitgroup == hit_group_player_was_shot) { if (!found_general_head) { first_body_yaw_found = body_yaw; first_yaw_found = current_yaw; found_general_head = true; } //TODO: not sure if this logic is right, I am very tired and a little drunk //Make sure if we trace slightly out of the impact origin, we don't still hit the same thing, otherwise the angle isn't correct ray.Init(trace_start, trace_ignore); //TODO: make trace for just one hitbox not all of them. trace_hitbox(entity, ray, tr, m_cSpheres, m_cOBBs); if (!tr.m_pEnt || tr.hitgroup != hit_group_player_was_shot) { found_real_head = true; break; } } current_yaw++; if (current_yaw > 360.0f) current_yaw -= 360.0f; if (current_yaw < 0.0f) current_yaw += 360.0f; } //We gucci we done all tracing we need, yippie ki ayyy mother fucker if(found_real_head) { history_when_hit.body_hit_perfect = true; history_when_hit.body_hit = true; history_when_hit.body_angle = current_yaw; } else if (!found_real_head && found_general_head) { current_yaw = first_yaw_found; history_when_hit.body_hit = true; history_when_hit.body_angle = current_yaw; } //Apply to resolver logic now } //void EffectsResolver::playerhit33(C_TEEffectDispatch* thisptr, DataUpdateType_t updateType, render::IDrawer* draw) //{ // if (thisptr->m_EffectData.m_hEntity <= 0) // return; // auto client_entity = interfaces::entity_list->GetClientEntityFromHandle(thisptr->m_EffectData.m_hEntity); // auto entity = static_cast<CBasePlayer*>(client_entity); // int player_index = entity->GetIndex(); // if (!(entity && entity->IsPlayer() && entity != player_data::local_player_information.entity)) // return; // if (player_index > 128) // return; // auto& target = player_data::player_records[player_index]; // //prevent access viloation // if (target.information.size() <= 0) // return; // auto& current_tick = target.information.front(); // float simulation_time = current_tick.sim_time; // target.simtime_last_get_body_spot = simulation_time; //} void EffectsResolver::resolver_sanitiser() { /* I'm not really in the mode to even write sudo code for this, it is just an idea. So it is a not boolean hit resolver The idea about it is get bullet impact, get the direction of inpact, trace back a fuck ton way Then trace and see that it doesn't hit the entity as we expected, then we can spin the entity fulll 360 degrees and determin which angle ranges the trace hits the entity, these angles where it hits the entity clealry can't be the real angle. From this we cna apply like 1.1s since lby updated and some other logic or even just to sanities our resolver angles for logic reoslver, backtrack here for some more accuracy This will not tell us the angle, rather it will tell us what angles they couldn't be */ } void enable_interp() { int MaxEntities = 64;// Interfaces::ClientEntList->GetHighestEntityIndex(); for (int i = 0; i <= MaxEntities; i++) { CCSPlayer* Entity = (CCSPlayer*)interfaces::entity_list->GetClientEntity(i); if (Entity && Entity->IsPlayer()) { if (!Entity->GetDormant() && i != interfaces::engine->GetLocalPlayer()) { Entity->enable_interp(); } } } } } } }