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

Гайд Bullet_tracer

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
1 Авг 2024
Сообщения
147
Реакции
3
всем ку делаем bullet_tracer для нашей любимой игры кунтер струк 2


bullet_tracer.cpp:
Expand Collapse Copy
CBulletTracer* g_BulletTracer = &CBulletTracer::Instance();

CBulletTracer& CBulletTracer::Instance() {
    static CBulletTracer instance;
    return instance;
}

void CBulletTracer::Register() {
    if (m_bRegistered || !I::eventmanager) return;
    I::eventmanager->AddListener(this, "bullet_impact", false);
    m_bRegistered = true;
    printf("[+] BulletTracer listener registered\n");
}

void CBulletTracer::Unregister() {
    if (!m_bRegistered || !I::eventmanager) return;
    I::eventmanager->RemoveListener(this);
    m_bRegistered = false;
}


static inline Vector_t VecLerp(const Vector_t& a, const Vector_t& b, float t) {
    return { a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t };
}

static void SpawnParticleTracer(const Vector_t& start, const Vector_t& end, const ImVec4& color) {
    if (!I::ParticleManager || !I::ParticleSystemManager) {
        printf("[BT] SKIP: Mgr=%p SysMgr=%p\n", (void*)I::ParticleManager, (void*)I::ParticleSystemManager);
        return;
    }


    const char* szPath = "particles/entity/spectator_utility_trail.vpcf";

    TracerInfo_t bullet{};
    __int64 ret = I::ParticleManager->CreateParticle(&bullet.m_iEffectIndex, szPath);
    printf("[BT] CreateParticle ret=%lld idx=%u\n", ret, bullet.m_iEffectIndex);
    if (ret == 0) return;

 
    ParticleColor_t tColor(color.x * 255.f, color.y * 255.f, color.z * 255.f);
    I::ParticleManager->SetEffect(bullet.m_iEffectIndex, PARTICLE_SETTING_COLOR, &tColor);


    ParticleParams_t info{};
    info.width = Config::bulletTracerThickness > 0.f ? Config::bulletTracerThickness : 1.5f;
    info.lifetime = Config::bulletTracerLifetime > 0.f ? Config::bulletTracerLifetime : 0.5f;
    info.scale = color.w;
    I::ParticleManager->SetEffect(bullet.m_iEffectIndex, PARTICLE_SETTING_INFO, &info);


    Vector_t mid = VecLerp(start, end, 0.5f);
    static Vector_t positions[5];
    positions[0] = start;
    positions[1] = VecLerp(start, mid, 0.05f);
    positions[2] = mid;
    positions[3] = VecLerp(mid, end, 0.95f);
    positions[4] = end;

    bullet.m_ParticleData = {};
    bullet.m_ParticleData.m_Positions = positions;

    I::ParticleSystemManager->CreateSnapshot(&bullet.m_SnapshotParticle);
    printf("[BT] Snapshot=%p\n", bullet.m_SnapshotParticle ? (void*)bullet.m_SnapshotParticle.pBinding : nullptr);
    if (!bullet.m_SnapshotParticle) return;

    I::ParticleManager->SetParticleControlSnapshot(
        static_cast<int>(bullet.m_iEffectIndex), 0u, &bullet.m_SnapshotParticle);

    bullet.m_SnapshotParticle->Draw(5, &bullet.m_ParticleData);

    printf("[BT] Tracer spawned: (%.1f,%.1f,%.1f)->(%.1f,%.1f,%.1f)\n",
        start.x, start.y, start.z, end.x, end.y, end.z);
}

void CBulletTracer::FireGameEvent(CGameEvent* event) {
    if (!Config::bulletTracersEnabled) return;
    if (!event) return;

    const char* name = event->GetName();
    if (!name || strcmp(name, "bullet_impact") != 0) return;

    if (!I::EngineClient || !I::EngineClient->in_game()) return;

    auto local = CCSPlayerController::GetLocalPlayerController();
    if (!local) return;

    int attackerIdx = -1;
    {
        CBuffer buf; buf.name = "userid";
        event->GetControllerId(attackerIdx, &buf);
    }

    if (attackerIdx >= 0) {
        auto pAttacker = I::gameresource->pGameEntitySystem->Get<CCSPlayerController>(attackerIdx + 1);
        if (!pAttacker || pAttacker != local) return;
    }

    float ix = event->GetFloat2("x", 0.f);
    float iy = event->GetFloat2("y", 0.f);
    float iz = event->GetFloat2("z", 0.f);

    if (ix == 0.f && iy == 0.f && iz == 0.f) return;

    auto pPawn = H::oGetLocalPlayer ? H::oGetLocalPlayer(0) : nullptr;
    if (!pPawn) return;

    Vector_t startPos = pPawn->getEyePosition();
    if (startPos.x == 0.f && startPos.y == 0.f && startPos.z == 0.f) return;

    Vector_t endPos = { ix, iy, iz };

    if (I::ParticleManager && I::ParticleSystemManager) {
        SpawnParticleTracer(startPos, endPos, Config::bulletTracerColor);
    }
    else {
        BulletTracerEntry entry;
        entry.start = startPos;
        entry.end = endPos;
        entry.spawnTime = GetTickCount64();
        m_Tracers.push_back(entry);
    }
}

void CBulletTracer::Render() {
    if (!Config::bulletTracersEnabled) return;
    if (m_Tracers.empty()) return;


    if (I::ParticleManager) {
        m_Tracers.clear();
        return;
    }

    auto drawList = ImGui::GetBackgroundDrawList();
    if (!drawList) return;

    unsigned long long now = GetTickCount64();
    float lifetime = Config::bulletTracerLifetime > 0.f ? Config::bulletTracerLifetime : 0.5f;

    for (auto it = m_Tracers.begin(); it != m_Tracers.end(); ) {
        float elapsed = (float)(now - it->spawnTime) / 1000.f;
        if (elapsed > lifetime) { it = m_Tracers.erase(it); continue; }

        float alpha = 1.f - (elapsed / lifetime);
        ImVec4 c = Config::bulletTracerColor;
        ImU32 col = ImColor(c.x, c.y, c.z, c.w * alpha);
        ImU32 outline = ImColor(0.f, 0.f, 0.f, 0.6f * alpha);

        Vector_t screenStart, screenEnd;
        bool s1 = Esp::Visuals::viewMatrix.WorldToScreen(it->start, screenStart);
        bool s2 = Esp::Visuals::viewMatrix.WorldToScreen(it->end, screenEnd);

        if (s1 && s2) {
            float thick = Config::bulletTracerThickness > 0.f ? Config::bulletTracerThickness : 1.5f;
            drawList->AddLine(ImVec2(screenStart.x, screenStart.y), ImVec2(screenEnd.x, screenEnd.y), outline, thick + 1.f);
            drawList->AddLine(ImVec2(screenStart.x, screenStart.y), ImVec2(screenEnd.x, screenEnd.y), col, thick);
        }
        ++it;
    }
}


bullet_tracer.h:
Expand Collapse Copy
struct BulletTracerEntry {
    Vector_t start;
    Vector_t end;
    unsigned long long spawnTime;
};

class CBulletTracer : public IGameEventListener {
public:
    static CBulletTracer& Instance();

    void FireGameEvent(CGameEvent* event) override;

    void Register();
    void Unregister();
    void Render();

    std::vector<BulletTracerEntry> m_Tracers;

private:
    CBulletTracer() = default;
    bool m_bRegistered = false;
};

extern CBulletTracer* g_BulletTracer;


particle_system.h:
Expand Collapse Copy
struct ParticleColor_t {
    float r, g, b;
    ParticleColor_t(float _r, float _g, float _b) : r(_r), g(_g), b(_b) {}
};

struct ParticleParams_t {
    float lifetime;
    float width;
    float scale;
};

enum EParticleSetting : int {
    PARTICLE_SETTING_COLOR = 16,
    PARTICLE_SETTING_INFO = 3,
};

class CParticleSnapshot {
public:
    void Draw(int nCount, void* pData) {
        using fn_t = void(__fastcall*)(CParticleSnapshot*, int, void*);
        (*reinterpret_cast<fn_t**>(this))[1](this, nCount, pData);
    }
};

class CParticleData {
public:
    Vector_t* m_Positions{};
    char      pad[0x74]{};
    float* m_flTimes{};
    void* m_pUnkPtr{};
    char      pad2[0x28]{};
    float* m_flTimes2{};
    char      pad3[0x98]{};
    void* m_pUnkPtr2{};
};

struct TracerInfo_t {
    uint32_t                              m_iEffectIndex = 8;
    Vector_t* m_Positions = nullptr;
    float* m_flTimes = nullptr;
    CStrongHandle<CParticleSnapshot>      m_SnapshotParticle{};
    CParticleData                         m_ParticleData;
};

namespace ParticleFn {

    inline __int64(__fastcall* fnCreateParticle)(void*, uint32_t*, const char*, int, __int64, __int64, __int64, int) = nullptr;

    inline void(__fastcall* fnSetEffect)(void*, uint32_t, int, void*, int) = nullptr;


    inline bool(__fastcall* fnSetParticleControlSnapshot)(void*, int, uint32_t, const CStrongHandle<CParticleSnapshot>*) = nullptr;


    inline bool(__fastcall* fnSetControlPoint)(void*, uint32_t, int, void*, float) = nullptr;


    inline void(__fastcall* fnDestroyParticle)(void*, int, bool, bool) = nullptr;

    inline void Init() {

        if (!fnCreateParticle)
            fnCreateParticle = reinterpret_cast<decltype(fnCreateParticle)>(
                M::patternScan("client", "4C 8B DC 53 48 81 EC ? ? ? ? F2 0F 10 05"));
        {
            uintptr_t clientBase = (uintptr_t)M::GetModuleBaseHandle(L"client.dll");
            if (clientBase && !fnCreateParticle) {
                uintptr_t candidate = clientBase + 0x425270;
                uint8_t* p = reinterpret_cast<uint8_t*>(candidate);
                if (p[0] != 0x00 && p[0] != 0xCC) {
                    fnCreateParticle = reinterpret_cast<decltype(fnCreateParticle)>(candidate);
                    printf("[ParticleFn] fnCreateParticle via offset fallback\n");
                }
            }
        }
        printf("[ParticleFn] fnCreateParticle: %p\n", (void*)fnCreateParticle);

        if (!fnSetEffect)
            fnSetEffect = reinterpret_cast<decltype(fnSetEffect)>(
                M::patternScan("client", "48 89 5C 24 ? 48 89 74 24 10 57 48 83 EC ? ? ? ? ? ? ? ? ? 41 8B F8 8B DA 4C"));
        if (!fnSetEffect)
            fnSetEffect = reinterpret_cast<decltype(fnSetEffect)>(
                M::patternScan("client", "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? ? ? ? ? ? ? ? ? ? 41 8B F8 8B DA 4C"));
        if (!fnSetEffect)
            fnSetEffect = reinterpret_cast<decltype(fnSetEffect)>(
                M::patternScan("client", "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? 41 8B F8 8B DA"));
        printf("[ParticleFn] fnSetEffect: %p\n", (void*)fnSetEffect);


        if (!fnSetParticleControlSnapshot)
            fnSetParticleControlSnapshot = reinterpret_cast<decltype(fnSetParticleControlSnapshot)>(
                M::patternScan("client", "48 89 74 24 ? 57 48 83 EC ? 4C 8B D9 49 8B F9 33 C9 41 8B F0 83 FA ? 0F 84"));
        printf("[ParticleFn] fnSetParticleControlSnapshot: %p\n", (void*)fnSetParticleControlSnapshot);

        if (!fnSetControlPoint)
            fnSetControlPoint = reinterpret_cast<decltype(fnSetControlPoint)>(
                M::patternScan("client", "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 49 8B E9 41 8B F0"));
        printf("[ParticleFn] fnSetControlPoint: %p\n", (void*)fnSetControlPoint);


        if (!fnDestroyParticle)
            fnDestroyParticle = reinterpret_cast<decltype(fnDestroyParticle)>(
                M::patternScan("client", "83 FA ? 0F 84 ? ? ? ? 41 54"));
        printf("[ParticleFn] fnDestroyParticle: %p\n", (void*)fnDestroyParticle);
    }
}

class CParticleManager {
public:
    __int64 CreateParticle(uint32_t* pEffectIndex, const char* szName) {
        if (!ParticleFn::fnCreateParticle) return 0;
        return ParticleFn::fnCreateParticle(this, pEffectIndex, szName, 8, 0ll, 0ll, 0ll, 0);
    }

    void SetEffect(uint32_t nEffectIndex, int nSetting, void* pData, int nUnk = 0) {
        if (!ParticleFn::fnSetEffect) return;
        ParticleFn::fnSetEffect(this, nEffectIndex, nSetting, pData, nUnk);
    }

    bool SetParticleControlSnapshot(int nEffectIndex, uint32_t nUnk0, const CStrongHandle<CParticleSnapshot>* pSnapshot) {
        if (!ParticleFn::fnSetParticleControlSnapshot) return false;
        return ParticleFn::fnSetParticleControlSnapshot(this, nEffectIndex, nUnk0, pSnapshot);
    }


    void SetControlPoint(uint32_t nEffectIndex, int nFlag, Vector_t& pos) {
        if (!ParticleFn::fnSetControlPoint) {
            printf("[ParticleFn] SetControlPoint fn not found!\n");
            return;
        }
        ParticleFn::fnSetControlPoint(this, nEffectIndex, nFlag, &pos, 0.f);
    }

    void DestroyParticle(int nIndex, bool bA1 = true, bool bA2 = true) {
        if (!ParticleFn::fnDestroyParticle) return;
        ParticleFn::fnDestroyParticle(this, nIndex, bA1, bA2);
    }

    void ReleaseParticleIndex(int nIndex) {
        using fn_t = void(__fastcall*)(CParticleManager*, int);
        (*reinterpret_cast<fn_t**>(this))[3](this, nIndex);
    }
};

class CParticleSystemManager {
public:
    void CreateSnapshot(CStrongHandle<CParticleSnapshot>* pOut) {
        __int64 unk = 0;
        using fn_t = void(__fastcall*)(CParticleSystemManager*, CStrongHandle<CParticleSnapshot>*, __int64*);
        (*reinterpret_cast<fn_t**>(this))[41](this, pOut, &unk);
    }
};




interfaces.cpp:
Expand Collapse Copy
static CParticleManager* SafeCallParticleMgr(void* pFn) {
    using fn_t = CParticleManager*(__fastcall*)();
    __try { return reinterpret_cast<fn_t>(pFn)(); }
    __except (EXCEPTION_EXECUTE_HANDLER) { return nullptr; }
}


ParticleSystemManager = I::Get<CParticleSystemManager>("particles.dll", "ParticleSystemMgr003");
if (!ParticleSystemManager)
    printf("[WARNING] ParticleSystemMgr not found - bullet tracers disabled\n");

ParticleFn::Init();

{
    auto pRaw = M::FindPattern("client.dll", "E8 ? ? ? ? F3 0F 10 45 ? 4C 8D 4C 24 ? 8B 93");
    if (pRaw) {
        auto pFn = M::GetAbsoluteAddress(reinterpret_cast<std::uint8_t*>(pRaw), 0x1);
        if (pFn) {
            ParticleManager = SafeCallParticleMgr(reinterpret_cast<void*>(pFn));
        }
    }
    printf("[%s] CParticleManager: 0x%p\n",
        ParticleManager ? "+" : "-", reinterpret_cast<void*>(ParticleManager));
}




hkLevelInit:
Expand Collapse Copy
hkLevelInit - (client.dll)  E8 ? ? ? ? C6 83 ? ? ? ? ? C6 83

static CParticleManager* SafeCallParticleMgr(void* pFn) {
    using fn_t = CParticleManager*(__fastcall*)();
    __try { return reinterpret_cast<fn_t>(pFn)(); }
    __except (EXCEPTION_EXECUTE_HANDLER) { return nullptr; }
}

void* __fastcall H::hkLevelInit(void* pClientModeShared, const char* szNewMap) {

    static void* g_pPVS = (void*)M::getAbsoluteAddress(M::patternScan("engine2", "48 8D 0D ? ? ? ? 33 D2 FF 50"), 0x3);
    M::vfunc<void*, 6U, void>(g_pPVS, false);


    if (!I::ParticleManager) {
        auto pRaw = M::FindPattern("client.dll", "E8 ? ? ? ? F3 0F 10 45 ? 4C 8D 4C 24 ? 8B 93");
        if (pRaw) {
            auto pFn = M::GetAbsoluteAddress(reinterpret_cast<std::uint8_t*>(pRaw), 0x1);
            if (pFn)
                I::ParticleManager = SafeCallParticleMgr(reinterpret_cast<void*>(pFn));
        }
        if (I::ParticleManager)
            printf("[+] CParticleManager updated on LevelInit: 0x%p\n", (void*)I::ParticleManager);
    }

    auto ret = LevelInit.GetOriginal()(pClientModeShared, szNewMap);
    return ret;
}

hkLevelShutdown:
Expand Collapse Copy
hkLevelShutdown - (client.dll) 48 83 EC ? 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? 45 33 C9 45 33 C0 48 8B 01 FF 50 ? 48 85 C0 74 ? 48 8B 0D ? ? ? ? 48 8B D0 4C 8B 01 41 FF 50 ? 48 83 C4

__int64 __fastcall H::hkLevelShutdown(void* pClientModeShared) {

    I::ParticleManager = nullptr;
    printf("[*] LevelShutdown: ParticleManager reset\n");
    return LevelShutdown.GetOriginal()(pClientModeShared);
}

utlstronghandle.h:
Expand Collapse Copy
#pragma once
struct ResourceBinding_t
{
    void* pData;
};
template <typename T>
class CStrongHandle
{
public:
    operator T* () const
    {
        if (pBinding == nullptr)
            return nullptr;
        return static_cast<T*>(pBinding->pData);
    }
    T* operator->() const
    {
        if (pBinding == nullptr)
            return nullptr;
        return static_cast<T*>(pBinding->pData);
    }
    const ResourceBinding_t* pBinding;
};
 

Вложения

  • Снимок экрана 2026-03-18 120736.png
    Снимок экрана 2026-03-18 120736.png
    922.9 KB · Просмотры: 152
Последнее редактирование:

этот Bullet_tracer актуален под ласт кс2 также паттерны там тоже​

а после ласт обновлений ломалась партикл система???

этот Bullet_tracer актуален под ласт кс2 также паттерны там тоже​

Одно дело скинуть обновленные паттерны классы индексы и тд, а другое выложить ГАЙД на булет трейс который давным давно слит.
 
а после ласт обновлений ломалась партикл система???

Одно дело скинуть обновленные паттерны классы индексы и тд, а другое выложить ГАЙД на булет трейс который давным давно слит.
ну слил тип и слил, чё с того? или это тебя как то ущемило?
 

этот Bullet_tracer актуален под ласт кс2 также паттерны там тоже​

а зачем делать буллет трейсеры если можно просто партикл менеджер сделать а потом на изи сделать буллет трейсера??
 
Назад
Сверху Снизу