CFramework/CFramework/Cheat/Features.cpp

408 lines
12 KiB
C++

#include "Framework.h"
#include <cmath>
// 只实现 dump 明确的对象字段;后座/故障链路等类布局确认后再接入,当前不写内存。
void CFramework::GetESPInfo(const int& SpawnType, std::string& vOutStr, ImColor& vOutColor)
{
switch (SpawnType)
{
case SCAV:
vOutStr = "Scav";
vOutColor = Col_ESP_Scav;
break;
case SNIPER_SCAV:
vOutStr = "Sniper";
vOutColor = Col_ESP_Scav;
break;
case RESHALA_BOSS:
vOutStr = "Reshala";
vOutColor = Col_ESP_Boss;
break;
case RESHALA_FOLLOW:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case KILLA_BOSS:
vOutStr = "Killa";
vOutColor = Col_ESP_Boss;
break;
case SHTURMAN_BOSS:
vOutStr = "Shturman";
vOutColor = Col_ESP_Boss;
break;
case SHTURMAN_FOLLOW:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case GLUKHAR_BOSS:
vOutStr = "Glukhar";
vOutColor = Col_ESP_Boss;
break;
case GLUKHAR_FOLLOW_01:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case GLUKHAR_FOLLOW_02:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case GLUKHAR_FOLLOW_03:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case SANITOR_BOSS:
vOutStr = "Sanitor";
vOutColor = Col_ESP_Boss;
break;
case SANITOR_FOLLOW:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case NORMAL_SCAV:
vOutStr = "Scav";
vOutColor = Col_ESP_Scav;
break;
case CULTIST_01_SCAV:
vOutStr = "Cultist";
vOutColor = Col_ESP_SpecialScav;
break;
case CULTIST_02_SCAV:
vOutStr = "Cultist";
vOutColor = Col_ESP_SpecialScav;
break;
case TAGILLA_BOSS:
vOutStr = "Tagilla";
vOutColor = Col_ESP_Boss;
break;
case ROGUE_SCAV:
vOutStr = "Rogue";
vOutColor = Col_ESP_SpecialScav;
break;
case ZRYACHIY_BOSS:
vOutStr = "Zryachiy";
vOutColor = Col_ESP_Boss;
break;
case ZRYACHIY_FOLLOW:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case KABAN_BOSS:
vOutStr = "Kaban";
vOutColor = Col_ESP_Boss;
break;
case KABAN_FOLLOW_0:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case KABAN_FOLLOW_1:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case KABAN_FOLLOW_2:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case KABAN_FOLLOW_3:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case KOLLONTAY_BOSS:
vOutStr = "Kollontay";
vOutColor = Col_ESP_Boss;
break;
case KOLLONTAY_FOLLOW_01:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case KOLLONTAY_FOLLOW_02:
vOutStr = "follower";
vOutColor = Col_ESP_SpecialScav;
break;
case BTR_VEHICLE:
vOutStr = "BTR-82";
vOutColor = ImColor(1.f, 1.f, 1.f, 1.f);
break;
case SCAV_PARTISAN:
vOutStr = "Partisan";
vOutColor = Col_ESP_Scav;
break;
case RAIDER_SCAV:
vOutStr = "Raider";
vOutColor = Col_ESP_SpecialScav;
break;
case KNIGHT_SCAV:
vOutStr = "Knight";
vOutColor = Col_ESP_SpecialScav;
break;
case BIGPIPE_SCAV:
vOutStr = "BigPipe";
vOutColor = Col_ESP_SpecialScav;
break;
case BRIDEYE_SCAV:
vOutStr = "Birdeye";
vOutColor = Col_ESP_SpecialScav;
break;
case BLOODHOUND_SCAV:
vOutStr = "Bloodhound";
vOutColor = Col_ESP_SpecialScav;
break;
case PMC_BEAR_PvE:
vOutStr = "BEAR";
vOutColor = Col_ESP_PMC;
break;
case PMC_USEC_PvE:
vOutStr = "USEC";
vOutColor = Col_ESP_PMC;
break;
case PMC_BEAR_NEW:
vOutStr = "BEAR";
vOutColor = Col_ESP_PMC;
break;
case PMC_USEC_NEW:
vOutStr = "USEC";
vOutColor = Col_ESP_PMC;
break;
default:
vOutStr = "InValid";
vOutColor = ImColor(1.f, 1.f, 1.f, 1.f);
break;
};
}
namespace
{
bool IsUsableAddress(const uintptr_t address)
{
// x64 user-mode canonical range; reject null/obviously bogus chains before any write.
return address > 0x10000ULL && address < 0x0000800000000000ULL;
}
bool IsFiniteValue(const float value)
{
return std::isfinite(value);
}
bool IsFiniteVector(const Vector3& value)
{
return IsFiniteValue(value.x) && IsFiniteValue(value.y) && IsFiniteValue(value.z);
}
bool IsUsableCapacity(const float value)
{
return IsFiniteValue(value) && value > 0.f && value < 100000.f;
}
}
void CFramework::UpdateFeatures()
{
if (!tarkov->IsInRaid() || !IsUsableAddress(tarkov->m_pLocalGameWorld))
{
ResetFeatureOverrides();
return;
}
// Refresh MainPlayer from the current LocalGameWorld instead of trusting a stale list-thread cache.
uintptr_t currentLocal = 0;
if (!m.TryRead(tarkov->m_pLocalGameWorld + offset::MainPlayer, currentLocal) ||
!IsUsableAddress(currentLocal))
{
ResetFeatureOverrides();
return;
}
local.m_address = currentLocal;
if (g.g_InfStamina)
UpdateStaminaOverride();
else
ResetStaminaOverride();
if (g.g_NoFallDamage)
UpdateFallDamageOverride();
else
ResetFallDamageOverride();
if (g.g_NoSway)
UpdateSwayOverride();
else
ResetSwayOverride();
}
void CFramework::UpdateStaminaOverride()
{
uintptr_t physical = 0;
uintptr_t stamina = 0;
uintptr_t handsStamina = 0;
if (!m.TryRead(local.m_address + offset::Player::pPhysics, physical) ||
!IsUsableAddress(physical) ||
!m.TryRead(physical + offset::Physics::Stamina, stamina) ||
!m.TryRead(physical + offset::Physics::HandsStamina, handsStamina) ||
!IsUsableAddress(stamina) ||
!IsUsableAddress(handsStamina))
{
ResetStaminaOverride();
return;
}
if (m_staminaOverride.captured &&
(m_staminaOverride.player != local.m_address ||
m_staminaOverride.physical != physical ||
m_staminaOverride.stamina != stamina ||
m_staminaOverride.handsStamina != handsStamina))
{
ResetStaminaOverride();
}
float staminaCapacity = 0.f;
float handsCapacity = 0.f;
if (!m.TryRead(physical + offset::Physics::StaminaCapacity, staminaCapacity) ||
!m.TryRead(physical + offset::Physics::HandsCapacity, handsCapacity) ||
!IsUsableCapacity(staminaCapacity) ||
!IsUsableCapacity(handsCapacity))
{
ResetStaminaOverride();
return;
}
if (!m_staminaOverride.captured)
{
float staminaCurrent = 0.f;
float handsCurrent = 0.f;
if (!m.TryRead(stamina + offset::PhysicalState::Current, staminaCurrent) ||
!m.TryRead(handsStamina + offset::PhysicalState::Current, handsCurrent) ||
!IsFiniteValue(staminaCurrent) ||
!IsFiniteValue(handsCurrent))
{
ResetStaminaOverride();
return;
}
m_staminaOverride.player = local.m_address;
m_staminaOverride.physical = physical;
m_staminaOverride.stamina = stamina;
m_staminaOverride.handsStamina = handsStamina;
m_staminaOverride.staminaCurrent = staminaCurrent;
m_staminaOverride.handsCurrent = handsCurrent;
m_staminaOverride.captured = true;
}
// Both current fields and both capacities are dump-confirmed object fields.
m.TryWrite<float>(stamina + offset::PhysicalState::Current, staminaCapacity);
m.TryWrite<float>(handsStamina + offset::PhysicalState::Current, handsCapacity);
}
void CFramework::UpdateFallDamageOverride()
{
uintptr_t physical = 0;
if (!m.TryRead(local.m_address + offset::Player::pPhysics, physical) ||
!IsUsableAddress(physical))
{
ResetFallDamageOverride();
return;
}
if (m_fallDamageOverride.captured &&
(m_fallDamageOverride.player != local.m_address ||
m_fallDamageOverride.physical != physical))
{
ResetFallDamageOverride();
}
if (!m_fallDamageOverride.captured)
{
float multiplier = 0.f;
if (!m.TryRead(physical + offset::Physics::FallDamageMultiplier, multiplier) ||
!IsFiniteValue(multiplier))
{
ResetFallDamageOverride();
return;
}
m_fallDamageOverride.player = local.m_address;
m_fallDamageOverride.physical = physical;
m_fallDamageOverride.multiplier = multiplier;
m_fallDamageOverride.captured = true;
}
m.TryWrite<float>(physical + offset::Physics::FallDamageMultiplier, 0.f);
}
void CFramework::UpdateSwayOverride()
{
uintptr_t weaponAnimation = 0;
uintptr_t motionEffector = 0;
if (!m.TryRead(local.m_address + offset::Player::pWeaponAnimation, weaponAnimation) ||
!IsUsableAddress(weaponAnimation) ||
!m.TryRead(weaponAnimation + offset::WeaponAnimations::MotionReact, motionEffector) ||
!IsUsableAddress(motionEffector))
{
ResetSwayOverride();
return;
}
if (m_swayOverride.captured &&
(m_swayOverride.player != local.m_address ||
m_swayOverride.weaponAnimation != weaponAnimation ||
m_swayOverride.motionEffector != motionEffector))
{
ResetSwayOverride();
}
if (!m_swayOverride.captured)
{
Vector3 swayFactors{};
if (!m.TryRead(motionEffector + offset::MotionEffector::SwayFactors, swayFactors) ||
!IsFiniteVector(swayFactors))
{
ResetSwayOverride();
return;
}
m_swayOverride.player = local.m_address;
m_swayOverride.weaponAnimation = weaponAnimation;
m_swayOverride.motionEffector = motionEffector;
m_swayOverride.swayFactors = swayFactors;
m_swayOverride.captured = true;
}
m.TryWrite<Vector3>(motionEffector + offset::MotionEffector::SwayFactors, Vector3{});
}
void CFramework::ResetStaminaOverride()
{
if (m_staminaOverride.captured)
{
if (IsUsableAddress(m_staminaOverride.stamina))
m.TryWrite<float>(m_staminaOverride.stamina + offset::PhysicalState::Current, m_staminaOverride.staminaCurrent);
if (IsUsableAddress(m_staminaOverride.handsStamina))
m.TryWrite<float>(m_staminaOverride.handsStamina + offset::PhysicalState::Current, m_staminaOverride.handsCurrent);
}
m_staminaOverride = {};
}
void CFramework::ResetFallDamageOverride()
{
if (m_fallDamageOverride.captured && IsUsableAddress(m_fallDamageOverride.physical))
m.TryWrite<float>(m_fallDamageOverride.physical + offset::Physics::FallDamageMultiplier, m_fallDamageOverride.multiplier);
m_fallDamageOverride = {};
}
void CFramework::ResetSwayOverride()
{
if (m_swayOverride.captured && IsUsableAddress(m_swayOverride.motionEffector))
m.TryWrite<Vector3>(m_swayOverride.motionEffector + offset::MotionEffector::SwayFactors, m_swayOverride.swayFactors);
m_swayOverride = {};
}
void CFramework::ResetFeatureOverrides()
{
ResetStaminaOverride();
ResetFallDamageOverride();
ResetSwayOverride();
}