Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Гайд CS2 Bhop Internal — Рабочий метод после AnimGraph

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
703
Реакции
21
Valve в очередной раз попытались усложнить жизнь разработчикам после апдейта AnimGraph, но база остается базой. Если ваш старый банихоп начал «заикаться» или вовсе перестал прыгать, ловите актуальный сурс внутреннего бхопа, который использует правильный захват инпута в CreateMove.

Основная фишка здесь в сохранении состояния кнопки прыжка до того, как в цепочку вызовов вмешаются другие хуки. Код учитывает предикшн и корректно проверяет флаг FL_ONGROUND, что минимизирует фейковые прыжки и потерю скорости в Premier-режиме.

Что внутри:
  1. Захват сырого инпута (Raw Input) в начале тика.
  2. Интеграция с системой предикшна (Prediction::IsActive).
  3. Работа через ButtonState (PRESS/RELEASE) вместо топорной записи в память.
  4. Проверка здоровья (Health check) — не прыгаем, если отлетели.

Ниже представлен сам неймспейс с логикой. Юзайте под свой SDK, оффсеты обновляйте через дампер.

Код:
Expand Collapse Copy
#pragma once
#include <Windows.h>
#include <cstdint>
#include "game.h"
#include "offsets.h"
#include "sdk/offsets.hpp"
#include "sdk/buttons.hpp"
#include "prediction.h"
 
namespace Bhop
{
    struct BhopConfig
    {
        bool enabled = false;
    };
 
    inline BhopConfig config;
 
    // Raw jump button state captured at the top of CreateMove,
    // BEFORE any writes — reflects the player's actual space key input.
    inline uint32_t savedJumpInput = 0;
 
    inline void CaptureInput()
    {
        if (!Game::clientBase) return;
        savedJumpInput = Game::Read<uint32_t>(
            Game::clientBase + cs2_dumper::buttons::jump);
    }
 
    inline void Tick(uintptr_t localPawn)
    {
        if (!config.enabled) return;
        if (!localPawn || !Game::clientBase) return;
 
        // Player wants to jump when the engine's button state has the
        // held (bit 16) or pressed-edge (bit 0) bits set.
        // Read from the snapshot taken before any hook writes.
        bool wantsJump = (savedJumpInput & 0x10001) != 0;
        if (!wantsJump) return;
 
        int health = Game::Read<int32_t>(localPawn + Offsets::m_iHealth);
        if (health <= 0) return;
 
        uint32_t flags = Prediction::IsActive()
            ? Prediction::GetPredictedFlags()
            : Prediction::GetFlags(localPawn);
 
        uintptr_t jumpAddr = Game::clientBase + cs2_dumper::buttons::jump;
        bool onGround = (flags & 1) != 0; // FL_ONGROUND
 
#ifdef _DEBUG
        {
            static bool s_wasGround = true;
            if (onGround != s_wasGround)
            {
                printf("[Bhop] %s | flags=0x%X pred=%d btn=0x%X\n",
                    onGround ? "LANDED" : "JUMPED (airborne)",
                    flags, Prediction::IsActive() ? 1 : 0, savedJumpInput);
                s_wasGround = onGround;
            }
        }
#endif
 
        if (onGround)
            Game::Write<uint32_t>(jumpAddr, ButtonState::PRESS);
        else
            Game::Write<uint32_t>(jumpAddr, ButtonState::RELEASE);
    }
}

Метод стабильно работает даже после изменений в движке. Главное — убедитесь, что ваш хук CreateMove вызывается в нужном месте, иначе захват инпута `savedJumpInput` будет ловить уже измененные значения. Для легит-игры можно добавить небольшой рандомайзер задержки между прыжками, чтобы античит меньше триггерился на идеальные тайминги.

Интересно, как долго этот костыль продержится до следующей попытки Valve перелопатить систему движений.
 
Назад
Сверху Снизу