Начинающий
- Статус
- Оффлайн
- Регистрация
- 1 Авг 2024
- Сообщения
- 147
- Реакции
- 3
всем ку делаем bullet_tracer для нашей любимой игры кунтер струк 2
bullet_tracer.cpp:
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:
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:
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
interfaces.cpp:
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:
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:
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:
#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;
};
Вложения
Последнее редактирование:
