408 lines
12 KiB
C++
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();
|
|
}
|