- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 445
- Реакции
- 10
Здарова, реверсеры.
Наткнулся на классическую проблему при написании аима под Тарков. Чел жалуется, что при наводке камеру разворачивает на 180 градусов. Знакомая ситуация? Это база для тех, кто лезет в MovementContext без понимания того, как EFT крутит ротации и как работают локальные координаты в Unity.
Что внутри этого сурса:
Техническое мясо:
Проблема с фликами, которую описывает автор кода, часто связана с тем, что дельта-расчет не учитывает нормализацию углов. В EFT MovementContext довольно капризный: если сетить углы напрямую без учета текущей ротации или с слишком резким шагом, BattlEye может и не сразу, но сервер точно начнет «лагать» для вас.
Кто уже допиливал этот метод, как сейчас обходите проверку на аномальные ротации в RAID?
Наткнулся на классическую проблему при написании аима под Тарков. Чел жалуется, что при наводке камеру разворачивает на 180 градусов. Знакомая ситуация? Это база для тех, кто лезет в MovementContext без понимания того, как EFT крутит ротации и как работают локальные координаты в Unity.
Что внутри этого сурса:
- Полная интеграция с IL2CPP для вызова нативных методов игры.
- Работа через MovementContext::set_Rotation — самый популярный метод для внутренних читов.
- Реализован VisCheck и выбор кости (в данном конфиге выбран Neck для более стабильного попадания).
- Настройки FOV, Smoothing и Sensitivity через ImGui.
- World-to-Screen отрисовка таргета и линий.
Техническое мясо:
Проблема с фликами, которую описывает автор кода, часто связана с тем, что дельта-расчет не учитывает нормализацию углов. В EFT MovementContext довольно капризный: если сетить углы напрямую без учета текущей ротации или с слишком резким шагом, BattlEye может и не сразу, но сервер точно начнет «лагать» для вас.
Код:
#pragma once
#include "../eft_api.h"
#include "../game_state.h"
#include "../Module.h"
#include "../../config/ColorpickerValue.h"
#include "../../config/FloatSliderValue.h"
#include "../../config/IntSliderValue.h"
#include "../../config/KeybindValue.h"
#include "../../il2cpp/il2utils.h"
#include "../../il2cpp/Il2CppObjectInstance.h"
#include "../../il2cpp/unity.h"
#include "../../util/player_utils.h"
static unity::vector3 target_store = {};
static Il2CppObject* stored_player = nullptr;
class AimbotModule : Module
{
public:
AimbotModule() : Module("Aimbot", Aimbot)
{
}
CheckboxValue* aim = conf(new CheckboxValue(false, "Aim"));
KeybindValue* aim_key = conf(new KeybindValue(VK_XBUTTON2, "Aim Key"));
IntSliderValue* fov = conf(new IntSliderValue(200, 50, 400, "Fov"));
CheckboxValue* show_fov = conf(new CheckboxValue(false, "Show Fov"));
ColorpickerValue* fov_color = conf(new ColorpickerValue({ 1, 0, 1, 1 }, "Fov Color"));
CheckboxValue* vis_check = conf(new CheckboxValue(false, "Vis Check"));
FloatSliderValue* smooth = conf(new FloatSliderValue(5, 1, 10, "Smooth"));
FloatSliderValue* sensitivity = conf(new FloatSliderValue(0.01f, 0.001f, 0.05f, "Sensitivity"));
CheckboxValue* invert_x = conf(new CheckboxValue(false, "Invert X"));
CheckboxValue* invert_y = conf(new CheckboxValue(false, "Invert Y"));
CheckboxValue* show_target = conf(new CheckboxValue(true, "Show Target"));
FloatSliderValue* target_size = conf(new FloatSliderValue(3, 1, 10, "Target Size"));
ColorpickerValue* target_color = conf(new ColorpickerValue({ 1, 0, 1, 1 }, "Target Color"));
CheckboxValue* show_line = conf(new CheckboxValue(false, "Show Line"));
ColorpickerValue* line_color = conf(new ColorpickerValue({ 1, 0, 0, 1 }, "Line Color"));
void draw_overlay(ImDrawList* draw_list) override
{
if (!game_state::is_in_raid) return;
Il2CppObject* cam = unity::get_current_camera();
if (!cam) return;
const float screen_center_x = menu::get_width() / 2.0f;
const float screen_center_y = menu::get_height() / 2.0f;
if (aim->get_value() && show_target->get_value())
{
if (!(target_store.x == 0 && target_store.y == 0))
{
if (unity::vector3 screen_pos = eft_api::world_to_screen(cam, target_store, game_state::current_zoom);
eft_api::is_visible(screen_pos))
{
draw_list->AddCircleFilled(
{ screen_pos.x, screen_pos.y },
target_size->get_value() * menu::get_scale_factor(),
ImGui::GetColorU32(target_color->get_value())
);
if (show_line->get_value())
{
draw_list->AddLine(
{ screen_center_x, screen_center_y },
{ screen_pos.x, screen_pos.y },
ImGui::GetColorU32(line_color->get_value()), 2.0f
);
}
}
}
}
if (show_fov->get_value())
{
draw_list->AddCircle(
{ screen_center_x, screen_center_y },
static_cast<float>(fov->get_value()) * menu::get_scale_factor(),
ImGui::GetColorU32(fov_color->get_value())
);
}
if (stored_player && game_state::is_in_raid)
{
Il2CppObjectInstance player_instance(stored_player);
if (!player_instance.is_valid()) return;
auto get_mc_fn = player_instance.get_method<Il2CppObject* (*)(Il2CppObject*)>("get_MovementContext", 0);
if (!get_mc_fn) return;
Il2CppObject* movement_context = get_mc_fn(stored_player);
if (movement_context)
{
Il2CppObjectInstance mc(movement_context);
if (!mc.is_valid()) return;
auto get_rot_fn = mc.get_method<unity::vector2(*)(Il2CppObject*)>("get_Rotation", 0);
if (!get_rot_fn) return;
unity::vector2 rot = get_rot_fn(movement_context);
Il2CppObject* debug_cam = unity::get_current_camera();
unity::vector3 debug_screen = eft_api::world_to_screen(debug_cam, target_store, game_state::current_zoom);
char buf[256];
snprintf(buf, sizeof(buf),
"rot.x=%.2f rot.y=%.2f | diff_x=%.2f diff_y=%.2f",
rot.x, rot.y,
debug_screen.x - screen_center_x,
debug_screen.y - screen_center_y);
draw_list->AddText({ 10, 10 }, IM_COL32(255, 255, 0, 255), buf);
}
}
}
void application_update() override
{
if (!game_state::is_in_raid) return;
if (!aim->get_value()) return;
if (!GetAsyncKeyState(aim_key->get_value())) return;
if (target_store.x == 0 && target_store.y == 0) return;
if (!stored_player) return;
Il2CppObject* cam = unity::get_current_camera();
if (!cam) return;
unity::vector3 screen_pos = eft_api::world_to_screen(cam, target_store, 1.0f);
if (!eft_api::is_visible(screen_pos)) return;
const float screen_center_x = menu::get_width() / 2.0f;
const float screen_center_y = menu::get_height() / 2.0f;
// small left correction for head bone offset, tune if needed
const float bone_offset_x = -5.0f;
const float diff_x = (screen_pos.x + bone_offset_x) - screen_center_x;
const float diff_y = screen_pos.y - screen_center_y;
if (abs(diff_x) < 2.0f && abs(diff_y) < 2.0f) return;
Il2CppObjectInstance player_instance(stored_player);
if (!player_instance.is_valid()) return;
auto get_mc_fn = player_instance.get_method<Il2CppObject* (*)(Il2CppObject*)>("get_MovementContext", 0);
if (!get_mc_fn) return;
Il2CppObject* movement_context = get_mc_fn(stored_player);
if (!movement_context) return;
Il2CppObjectInstance mc(movement_context);
if (!mc.is_valid()) return;
auto get_rot_fn = mc.get_method<unity::vector2(*)(Il2CppObject*)>("get_Rotation", 0);
if (!get_rot_fn) return;
unity::vector2 current_rotation = get_rot_fn(movement_context);
auto set_rot_fn = mc.get_method<void(*)(Il2CppObject*, unity::vector2)>("set_Rotation", 1);
if (!set_rot_fn) return;
const float max_step = 1.5f; // Lowered to prevent hard flickering
float delta_x = diff_x * sensitivity->get_value();
float delta_y = diff_y * sensitivity->get_value();
if (invert_x->get_value()) delta_x = -delta_x;
if (invert_y->get_value()) delta_y = -delta_y;
delta_x = max(-max_step, min(delta_x, max_step));
delta_y = max(-max_step, min(delta_y, max_step));
const float t = 1.0f / smooth->get_value();
current_rotation.x -= delta_x * t;
current_rotation.y += delta_y * t;
current_rotation.y = max(-85.0f, min(current_rotation.y, 85.0f));
set_rot_fn(movement_context, current_rotation);
}
void gameworld_update(const Il2CppClass* game_world_class, Il2CppObjectInstance game_world_instance,
Il2CppObjectInstance main_player) override
{
const auto get_profile = main_player.get_method<Il2CppObject * (*)(Il2CppObject*)>("get_Profile", 0);
Il2CppObjectInstance main_profile(get_profile(main_player.get_instance()));
const std::string main_nickname = eft_api::to_english(il2utils::conv_wstring(
main_profile.get_method<Il2CppString * (*)(Il2CppObject*)>("get_Nickname", 0)(
main_profile.get_instance())));
if (!game_state::is_in_raid || !aim->get_value())
{
target_store = {};
stored_player = nullptr;
return;
}
Il2CppObject* cam = unity::get_current_camera();
if (!cam)
{
target_store = {};
return;
}
const float screen_center_x = menu::get_width() / 2.0f;
const float screen_center_y = menu::get_height() / 2.0f;
const unity::vector3 screen_center = { screen_center_x, screen_center_y, 0 };
const float fov_radius = static_cast<float>(fov->get_value());
float closest = FLT_MAX;
unity::vector3 closest_pos = {};
Il2CppArray* alive_players = game_world_instance.get_field<unity::list*>("RegisteredPlayers")->
m_p_list_array;
for (size_t i = 0; i < alive_players->max_length; ++i)
{
Il2CppObject* player_object =
reinterpret_cast<Il2CppObject**>(&alive_players->data)[i];
if (!player_object) continue;
Il2CppObjectInstance player_instance(player_object);
Il2CppObject* profile_ptr = get_profile(player_instance.get_instance());
std::string nickname;
if (std::string(player_object->klass->name) == "ObservedPlayerView")
{
nickname = player_utils::get_networked_player_name(&player_instance);
}
else
{
Il2CppObjectInstance profile_instance(profile_ptr);
nickname = eft_api::to_english(il2utils::conv_wstring(
profile_instance.get_method<Il2CppString * (*)(Il2CppObject*)>("get_Nickname", 0)(
profile_instance.get_instance())));
}
if (nickname == main_nickname) continue;
Il2CppObjectInstance player_body(
player_instance.get_method<Il2CppObject * (*)(Il2CppObject*)>("get_PlayerBody", 0)(player_object));
Il2CppObjectInstance player_bones(player_body.get_field<Il2CppObject*>("PlayerBones"));
// using Neck instead of Head for better center alignment
Il2CppObjectInstance bifacial_transform_head(player_bones.get_field<Il2CppObject*>("Neck"));
const unity::vector3 head_pos = bifacial_transform_head.get_method<unity::vector3(
*)(Il2CppObject*)>("get_position", 0)(bifacial_transform_head.get_instance());
unity::vector3 screen_pos = eft_api::world_to_screen(cam, head_pos, game_state::current_zoom);
if (!eft_api::is_visible(screen_pos)) continue;
screen_pos.z = 0;
const float dist = screen_pos.distance(screen_center);
if (dist > fov_radius) continue;
if (dist < closest)
{
closest_pos = head_pos;
closest = dist;
}
}
target_store = closest_pos;
}
void init() override
{
}
};
Автор использует BifacialTransform для получения позиции костей. Это надежнее, чем старые методы, но не забывайте, что в последних патчах BSG добавили проверки на скорость изменения вектора взгляда. Если выставить smooth на минимум — аккаунт долго не проживет. Также обратите внимание на bone_offset_x — это костыль для компенсации смещения головы, который лучше настраивать динамически под конкретный FOV.
Кто уже допиливал этот метод, как сейчас обходите проверку на аномальные ротации в RAID?