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


#include "Aimbot.hpp"

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

__declspec(noinline) float GetSmoothStep(float SmoothFactor) {
    if (SmoothFactor > 0) {
        if (SmoothFactor >= 98 && SmoothFactor <= 100) return 0.5f  / SmoothFactor;
        if (SmoothFactor >= 80 && SmoothFactor < 98)  return 1.8f  / SmoothFactor;
        if (SmoothFactor >= 60 && SmoothFactor < 80)  return 2.0f  / SmoothFactor;
        if (SmoothFactor >= 40 && SmoothFactor < 60)  return 2.2f  / SmoothFactor;
        if (SmoothFactor >= 20 && SmoothFactor < 40)  return 2.5f  / SmoothFactor;
        return 3.0f / SmoothFactor;
    }
    return 1.0f;
}

// -----------------------------------------------------------------------
// Карта GTA5: X/Y в пределах ~[-10000, 10000], Z в [-300, 3000].
// Нулевой вектор тоже невалиден — камера никогда не стоит в (0,0,0).
// Если позиция за этими границами — указатель протух (stale pointer).
// -----------------------------------------------------------------------
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.0f || pos.x > 10000.0f) return false;
    if (pos.y < -10000.0f || pos.y > 10000.0f) return false;
    if (pos.z <   -300.0f || pos.z >  3000.0f) return false;
    return true;
}

// -----------------------------------------------------------------------
// Возвращает указатель на активную камеру.
// Сначала проверяет ADS-камеру (+0x2D8), потом обычную (+0x2C0).
// Обязательно валидирует позицию перед возвратом.
// -----------------------------------------------------------------------
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

    uintptr_t ActiveCam = GetActiveCamera();
    if (!ActiveCam) return;

    // Позиция камеры — точка из которой считаем направление к цели
    D3DXVECTOR3 CamPos = Mem.Read<D3DXVECTOR3>(ActiveCam + 0x60);

    // Текущий forward-вектор камеры — с него начинаем интерполяцию
    D3DXVECTOR3 CurrentViewAngles = Mem.Read<D3DXVECTOR3>(ActiveCam + 0x40);

    // Валидируем позицию камеры (защита от stale pointer)
    if (!IsValidWorldPosition(CamPos))
        return;

    // Валидируем позицию кости цели
    if (!IsValidWorldPosition(BonePos))
        return;

    // Вектор от камеры к кости, нормализуем
    D3DXVECTOR3 TargetViewAngles = BonePos - CamPos;
    D3DXVec3Normalize(&TargetViewAngles, &TargetViewAngles);

    // Проверяем что нормализованный результат не стал NaN/inf
    // (бывает если BonePos == CamPos, длина вектора = 0)
    if (std::isnan(TargetViewAngles.x) || std::isnan(TargetViewAngles.y) || std::isnan(TargetViewAngles.z))
        return;

    // SmoothStep — интерполируем от текущего угла к целевому
    const float SmoothFactor    = std::clamp(static_cast<float>(g_Config.Aimbot->AimbotSpeed), 0.0f, 100.0f);
    volatile float LocalSmoothStep = GetSmoothStep(SmoothFactor);

    D3DXVECTOR3 FinalAngles;
    FinalAngles.x = CurrentViewAngles.x + (TargetViewAngles.x - CurrentViewAngles.x) * LocalSmoothStep;
    FinalAngles.y = CurrentViewAngles.y + (TargetViewAngles.y - CurrentViewAngles.y) * LocalSmoothStep;
    FinalAngles.z = CurrentViewAngles.z + (TargetViewAngles.z - CurrentViewAngles.z) * LocalSmoothStep;

    D3DXVec3Normalize(&FinalAngles, &FinalAngles);

    // Финальная NaN-проверка перед записью в память игры
    if (std::isnan(FinalAngles.x) || std::isnan(FinalAngles.y) || std::isnan(FinalAngles.z))
        return;

    Mem.Write<D3DXVECTOR3>(ActiveCam + 0x40,  FinalAngles);
    Mem.Write<D3DXVECTOR3>(ActiveCam + 0x3D0, FinalAngles);

#ifdef USE_VMPROTECT
    VMProtectEnd();
#endif
}

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

    // Следим за сменой камеры (нажатие V).
    // Сразу после смены даём 500мс — за это время новый объект камеры
    // полностью инициализируется и IsValidWorldPosition начнёт его пропускать.
    uintptr_t LastKnownCam       = 0;
    auto      LastCamSwitchTime  = std::chrono::steady_clock::now();
    const int CAM_COOLDOWN_MS    = 500;

    while (true)
    {
        if (g_Config.Aimbot->Enabled
            && g_Config.Aimbot->KeyBind
            && (GetAsyncKeyState(g_Config.Aimbot->KeyBind) & 0x8000)
            && GetForegroundWindow() != g_Variables.g_hCheatWindow)
        {
            uintptr_t CurrentCam = GetActiveCamera();

            // Детект смены камеры
            if (CurrentCam != LastKnownCam)
            {
                LastKnownCam     = CurrentCam;
                LastCamSwitchTime = std::chrono::steady_clock::now();
                std::this_thread::sleep_for(std::chrono::nanoseconds(1));
                continue;
            }

            // Пауза после смены: новый объект камеры инициализируется не мгновенно
            const auto msSinceSwitch = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::steady_clock::now() - LastCamSwitchTime).count();

            if (msSinceSwitch < CAM_COOLDOWN_MS)
            {
                std::this_thread::sleep_for(std::chrono::nanoseconds(1));
                continue;
            }

            if (!CurrentCam)
            {
                std::this_thread::sleep_for(std::chrono::nanoseconds(1));
                continue;
            }

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

            if (!Ped)
            {
                std::this_thread::sleep_for(std::chrono::nanoseconds(1));
                continue;
            }

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

            if (Core::SDK::Game::IsOnScreen(ScreenHeadPos))
            {
                const int Fov = 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));
                }
            }
        }

        std::this_thread::sleep_for(std::chrono::nanoseconds(1));
    }

#ifdef USE_VMPROTECT
    VMProtectEnd();
#endif
}