Загрузка данных


#include "Aimbot.hpp"

#ifdef USE_VMPROTECT
#include "VMProtectSDK.h"
#endif

// -----------------------------------------------------------------------
// SmoothStep переделан: теперь возвращает значение СТРОГО в [0.0, 1.0].
// SmoothFactor 1   → step ~0.01 (очень плавно, маленький шаг)
// SmoothFactor 100 → step  1.0  (мгновенно, за один тик)
// Формула: step = (SmoothFactor / 100) ^ 2  — квадратичная кривая,
// даёт хорошее ощущение smooth на низких значениях и резкость на высоких.
// -----------------------------------------------------------------------
__declspec(noinline) float GetSmoothStep(float SmoothFactor)
{
    // Нормализуем в [0, 1]
    float t = std::clamp(SmoothFactor, 0.0f, 100.0f) / 100.0f;
    // Квадратичная кривая: плавный старт, резкий финиш
    return t * t;
}

static bool IsValidWorldPosition(const D3DXVECTOR3& pos)
{
    if (std::isnan(pos.x) || std::isnan(pos.y) || std::isnan(pos.z)) return false;
    if (std::isinf(pos.x) || std::isinf(pos.y) || std::isinf(pos.z)) return false;
    if (pos.x == 0.0f && pos.y == 0.0f && pos.z == 0.0f)             return false;
    if (pos.x < -10000.f || pos.x > 10000.f)                          return false;
    if (pos.y < -10000.f || pos.y > 10000.f)                          return false;
    if (pos.z <   -300.f || pos.z >  3000.f)                          return false;
    return true;
}

uintptr_t Core::Features::cAimbot::GetActiveCamera()
{
    const uintptr_t base = Core::SDK::Pointers::pCamGamePlayDirector;

    const uintptr_t ADSCam    = Mem.Read<uintptr_t>(base + 0x2D8);
    const uintptr_t FollowCam = Mem.Read<uintptr_t>(base + 0x2C0);

    if (ADSCam)
    {
        const D3DXVECTOR3 pos = Mem.Read<D3DXVECTOR3>(ADSCam + 0x60);
        if (IsValidWorldPosition(pos))
            return ADSCam;
    }

    if (FollowCam)
    {
        const D3DXVECTOR3 pos = Mem.Read<D3DXVECTOR3>(FollowCam + 0x60);
        if (IsValidWorldPosition(pos))
            return FollowCam;
    }

    return 0;
}

void Core::Features::cAimbot::SetViewAngles(CPed* Ped, D3DXVECTOR3 BonePos)
{
#ifdef USE_VMPROTECT
    VMProtectBeginMutation("SetViewAngles");
#endif

    D3DXVECTOR2 ScreenBonePos = Core::SDK::Game::WorldToScreen(BonePos);

    if (!Core::SDK::Game::IsOnScreen(ScreenBonePos))
        return;

    float dx = ScreenBonePos.x - g_Variables.g_vGameWindowCenter.x;
    float dy = ScreenBonePos.y - g_Variables.g_vGameWindowCenter.y;

    if (std::isnan(dx) || std::isnan(dy) || std::isinf(dx) || std::isinf(dy))
        return;

    // step теперь строго в [0, 1] — никакого overshooting
    const float SmoothFactor    = std::clamp(static_cast<float>(g_Config.Aimbot->AimbotSpeed), 0.0f, 100.0f);
    const float LocalSmoothStep = GetSmoothStep(SmoothFactor);

    // Дробные пиксели накапливаем и отправляем целыми числами
    // чтобы не терять точность на низких значениях smooth
    m_AccumX += dx * LocalSmoothStep;
    m_AccumY += dy * LocalSmoothStep;

    const LONG moveX = static_cast<LONG>(m_AccumX);
    const LONG moveY = static_cast<LONG>(m_AccumY);

    // Вычитаем только то что реально отправили
    m_AccumX -= static_cast<float>(moveX);
    m_AccumY -= static_cast<float>(moveY);

    if (moveX == 0 && moveY == 0)
        return;

    INPUT input      = {};
    input.type       = INPUT_MOUSE;
    input.mi.dwFlags = MOUSEEVENTF_MOVE;
    input.mi.dx      = moveX;
    input.mi.dy      = moveY;

    SendInput(1, &input, sizeof(INPUT));

#ifdef USE_VMPROTECT
    VMProtectEnd();
#endif
}

void Core::Features::cAimbot::Start()
{
#ifdef USE_VMPROTECT
    VMProtectBeginMutation("AimbotLoop");
#endif

    uintptr_t LastKnownCam      = 0;
    auto      LastCamSwitchTime = std::chrono::steady_clock::now();
    const int CAM_COOLDOWN_MS   = 500;

    // Таймер для ограничения частоты тиков аима.
    // Аим должен работать синхронно с игровым рендером (~60-165 Гц),
    // а не на максимальной скорости процессора.
    // 2мс на тик = ~500 Гц — достаточно для любого монитора.
    const auto TICK_INTERVAL = std::chrono::microseconds(2000); // 2мс = 500 Hz
    auto       lastTick      = std::chrono::steady_clock::now();

    while (true)
    {
        // --- Ограничение частоты тиков ---
        auto now = std::chrono::steady_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(now - lastTick);

        if (elapsed < TICK_INTERVAL)
        {
            // Спим оставшееся время с небольшим запасом
            std::this_thread::sleep_for(TICK_INTERVAL - elapsed);
            continue;
        }
        lastTick = std::chrono::steady_clock::now();

        if (!g_Config.Aimbot->Enabled
            || !g_Config.Aimbot->KeyBind
            || !(GetAsyncKeyState(g_Config.Aimbot->KeyBind) & 0x8000)
            || GetForegroundWindow() == g_Variables.g_hCheatWindow)
        {
            // Сбрасываем аккумулятор пока кнопка не зажата
            m_AccumX = 0.0f;
            m_AccumY = 0.0f;
            continue;
        }

        // Детект смены камеры (нажатие V / ADS)
        uintptr_t CurrentCam = GetActiveCamera();
        if (CurrentCam != LastKnownCam)
        {
            LastKnownCam      = CurrentCam;
            LastCamSwitchTime = std::chrono::steady_clock::now();
            m_AccumX = 0.0f;
            m_AccumY = 0.0f;
            continue;
        }

        const auto msSinceSwitch = std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::steady_clock::now() - LastCamSwitchTime).count();

        if (msSinceSwitch < CAM_COOLDOWN_MS)
            continue;

        CPed* Ped = Core::SDK::Game::GetClosestPed(
            g_Config.Aimbot->MaxDistance,
            g_Config.Aimbot->IgnoreNPCs,
            g_Config.Aimbot->OnlyVisible);

        if (!Ped)
        {
            m_AccumX = 0.0f;
            m_AccumY = 0.0f;
            continue;
        }

        D3DXVECTOR3 HeadPos       = Ped->GetBonePosDefault(0 /*Head*/);
        D3DXVECTOR2 ScreenHeadPos = Core::SDK::Game::WorldToScreen(HeadPos);

        if (Core::SDK::Game::IsOnScreen(ScreenHeadPos))
        {
            const int Fov = static_cast<int>(std::hypot(
                ScreenHeadPos.x - g_Variables.g_vGameWindowCenter.x,
                ScreenHeadPos.y - g_Variables.g_vGameWindowCenter.y));

            if (Fov < g_Config.Aimbot->FOV)
            {
                SetViewAngles(Ped, HeadPos + D3DXVECTOR3(0, 0, 0.08f));
            }
            else
            {
                // Цель вышла за FOV — сбрасываем аккумулятор
                m_AccumX = 0.0f;
                m_AccumY = 0.0f;
            }
        }
        else
        {
            m_AccumX = 0.0f;
            m_AccumY = 0.0f;
        }
    }

#ifdef USE_VMPROTECT
    VMProtectEnd();
#endif
}