- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 737
- Реакции
- 19
Здарова, реверсеры. Столкнулся с плавающим багом в своем проекте под CS2. Суть такая: ESP то работает на ура во всю карту, то видит только пару человек, а порой вообще решает уйти в отпуск и не рисует никого.
Оффсеты перепроверял раза три — всё актуально, база обновлена. Грешу на саму логику прохода по энтити-листу или на то, как забираю павны. Юзаю стандартную схему через контроллер, но где-то явно происходит осечка.
Что уже проверено:
Есть подозрение, что лимит в 64 игрока в цикле — это слишком олдскульно для Source 2 и стоит чекать более широкий диапазон индексов, либо я где-то косячу с маской при получении listEntry2.
Если кто-то ковырял эту структуру недавно, подскажите, не менялась ли логика связки Controller -> Pawn в последних патчах, а то ESP в Premier-режиме превращается в лотерею.
Оффсеты перепроверял раза три — всё актуально, база обновлена. Грешу на саму логику прохода по энтити-листу или на то, как забираю павны. Юзаю стандартную схему через контроллер, но где-то явно происходит осечка.
Код:
void EntitySystem::UpdateEntities()
{
uintptr_t entityListOffset = offsets.getEntityList();
if (!entityListOffset) return;
uintptr_t localPawn = offsets.getLocalPawn();
if (!localPawn) return;
myTeamID = *reinterpret_cast<int*>(localPawn + C_BaseEntity::m_iTeamNum);
{
std::lock_guard<std::mutex> lock(entityMutex);
Vec3 myOrigin = offsets.getOrigin();
for (int playerIndex = 0; playerIndex < 64; ++playerIndex)
{
Entity& entity = playerEntities[playerIndex];
uintptr_t listEntry = *reinterpret_cast<uintptr_t*>(entityListOffset + (0x8 * (playerIndex & 0x7FFF) >> 9) + 16);
if (!listEntry) { entity.isAlive = false; continue; }
uintptr_t currentController = *reinterpret_cast<uintptr_t*>(listEntry + 0x70 * (playerIndex & 0x1FF));
if (!currentController) { entity.isAlive = false; continue; }
uint32_t pawnHandle = *reinterpret_cast<uint32_t*>(currentController + CCSPlayerController::m_hPlayerPawn);
if (!pawnHandle || pawnHandle == 0xFFFFFFFF) { entity.isAlive = false; continue; }
uintptr_t listEntry2 = *reinterpret_cast<uintptr_t*>(entityListOffset + 0x70 * ((pawnHandle & 0x7FFF) >> 9) + 16);
if (!listEntry2) { entity.isAlive = false; continue; }
uintptr_t currentPawn = *reinterpret_cast<uintptr_t*>(listEntry2 + 0x70 * (pawnHandle & 0x1FF));
if (!currentPawn) { entity.isAlive = false; continue; }
const bool isDormant = *reinterpret_cast<bool*>(currentPawn + CGameSceneNode::m_bDormant);
if (isDormant) { entity.isAlive = false; continue; }
const int health = *reinterpret_cast<int*>(currentPawn + C_BaseEntity::m_iHealth);
if (health < 1) { entity.isAlive = false; continue; }
entity.health = health;
if (currentPawn == localPawn) { entity.isAlive = false; continue; }
entity.isAlive = true;
Vec3 origin = *reinterpret_cast<Vec3*>(currentPawn + C_BasePlayerPawn::m_vOldOrigin);
entity.origin = origin;
entity.headPosition = offsets.BonePos(currentPawn, BoneIndices::HEAD);
// ... логика со скелетами
}
}
}
Что уже проверено:
- Оффсеты m_hPlayerPawn и m_iHealth точно те, что нужны.
- Проверка на Dormancy (CGameSceneNode::m_bDormant). Может, в CS2 она работает специфично и отсекает тех, кто за стеной слишком рано?
- Мьютексы и потокобезопасность — тут вроде чисто, локов нет.
Есть подозрение, что лимит в 64 игрока в цикле — это слишком олдскульно для Source 2 и стоит чекать более широкий диапазон индексов, либо я где-то косячу с маской при получении listEntry2.
Если кто-то ковырял эту структуру недавно, подскажите, не менялась ли логика связки Controller -> Pawn в последних патчах, а то ESP в Premier-режиме превращается в лотерею.