605 lines
19 KiB
C++
605 lines
19 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()
|
|
{
|
|
const auto snapshot = GetDynamicSnapshot();
|
|
if (!snapshot || !snapshot->inRaid || !snapshot->local.IsValid())
|
|
{
|
|
local = {};
|
|
ResetFeatureOverrides();
|
|
return;
|
|
}
|
|
|
|
// The list thread publishes local player state atomically. Keep a render-thread-only
|
|
// scratch copy for feature writers so no background thread can zero/change it mid-write.
|
|
local = snapshot->local;
|
|
const uintptr_t currentLocal = local.m_address;
|
|
if (!IsUsableAddress(currentLocal))
|
|
{
|
|
local = {};
|
|
ResetFeatureOverrides();
|
|
return;
|
|
}
|
|
|
|
if (g.g_InfStamina)
|
|
|
|
UpdateStaminaOverride();
|
|
else
|
|
ResetStaminaOverride();
|
|
|
|
if (g.g_NoFallDamage)
|
|
UpdateFallDamageOverride();
|
|
else
|
|
ResetFallDamageOverride();
|
|
|
|
if (g.g_NoSway)
|
|
UpdateSwayOverride();
|
|
else
|
|
ResetSwayOverride();
|
|
|
|
if (g.g_NoRecoil)
|
|
UpdateNoRecoilOverride();
|
|
else
|
|
ResetNoRecoilOverride();
|
|
|
|
if (g.g_NoMalfunction)
|
|
UpdateNoMalfunctionOverride();
|
|
else
|
|
ResetNoMalfunctionOverride();
|
|
}
|
|
|
|
bool CFramework::ResolveCurrentWeapon(uintptr_t& weaponAnimation, uintptr_t& shotEffector,
|
|
uintptr_t& weapon, uintptr_t& weaponTemplate)
|
|
{
|
|
weaponAnimation = 0;
|
|
shotEffector = 0;
|
|
weapon = 0;
|
|
weaponTemplate = 0;
|
|
|
|
if (!IsUsableAddress(local.m_address) ||
|
|
!m.TryRead(local.m_address + offset::Player::pWeaponAnimation, weaponAnimation) ||
|
|
!IsUsableAddress(weaponAnimation) ||
|
|
!m.TryRead(weaponAnimation + offset::WeaponAnimations::ShotEffector, shotEffector) ||
|
|
!IsUsableAddress(shotEffector) ||
|
|
!m.TryRead(shotEffector + offset::ShotEffector::MainWeaponInHands, weapon) ||
|
|
!IsUsableAddress(weapon) ||
|
|
!m.TryRead(weapon + offset::Weapon::Template, weaponTemplate) ||
|
|
!IsUsableAddress(weaponTemplate))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CFramework::UpdateNoRecoilOverride()
|
|
{
|
|
uintptr_t weaponAnimation = 0;
|
|
uintptr_t shotEffector = 0;
|
|
uintptr_t weapon = 0;
|
|
uintptr_t weaponTemplate = 0;
|
|
uintptr_t recoilSettings = 0;
|
|
|
|
if (!ResolveCurrentWeapon(weaponAnimation, shotEffector, weapon, weaponTemplate) ||
|
|
!m.TryRead(weaponTemplate + offset::WeaponTemplate::WeaponRecoilSettings, recoilSettings) ||
|
|
!IsUsableAddress(recoilSettings))
|
|
{
|
|
ResetNoRecoilOverride();
|
|
return;
|
|
}
|
|
|
|
if (m_noRecoilOverride.captured &&
|
|
(m_noRecoilOverride.player != local.m_address ||
|
|
m_noRecoilOverride.weaponAnimation != weaponAnimation ||
|
|
m_noRecoilOverride.shotEffector != shotEffector ||
|
|
m_noRecoilOverride.weapon != weapon ||
|
|
m_noRecoilOverride.weaponTemplate != weaponTemplate ||
|
|
m_noRecoilOverride.recoilSettings != recoilSettings))
|
|
{
|
|
ResetNoRecoilOverride();
|
|
}
|
|
|
|
if (!m_noRecoilOverride.captured)
|
|
{
|
|
bool enable = false;
|
|
if (!m.TryRead(recoilSettings + offset::WeaponRecoil::Enable, enable))
|
|
{
|
|
ResetNoRecoilOverride();
|
|
return;
|
|
}
|
|
|
|
m_noRecoilOverride.player = local.m_address;
|
|
m_noRecoilOverride.weaponAnimation = weaponAnimation;
|
|
m_noRecoilOverride.shotEffector = shotEffector;
|
|
m_noRecoilOverride.weapon = weapon;
|
|
m_noRecoilOverride.weaponTemplate = weaponTemplate;
|
|
m_noRecoilOverride.recoilSettings = recoilSettings;
|
|
m_noRecoilOverride.enable = enable;
|
|
m_noRecoilOverride.captured = true;
|
|
}
|
|
|
|
// WeaponRecoil.Enable is a dump-confirmed instance field. Do not touch its Values array yet.
|
|
m.TryWrite<bool>(recoilSettings + offset::WeaponRecoil::Enable, false);
|
|
}
|
|
|
|
void CFramework::UpdateNoMalfunctionOverride()
|
|
{
|
|
uintptr_t weaponAnimation = 0;
|
|
uintptr_t shotEffector = 0;
|
|
uintptr_t weapon = 0;
|
|
uintptr_t weaponTemplate = 0;
|
|
uintptr_t malfunctionState = 0;
|
|
|
|
if (!ResolveCurrentWeapon(weaponAnimation, shotEffector, weapon, weaponTemplate) ||
|
|
!m.TryRead(weapon + offset::Weapon::MalfState, malfunctionState) ||
|
|
!IsUsableAddress(malfunctionState))
|
|
{
|
|
ResetNoMalfunctionOverride();
|
|
return;
|
|
}
|
|
|
|
if (m_noMalfunctionOverride.captured &&
|
|
(m_noMalfunctionOverride.player != local.m_address ||
|
|
m_noMalfunctionOverride.weapon != weapon ||
|
|
m_noMalfunctionOverride.weaponTemplate != weaponTemplate ||
|
|
m_noMalfunctionOverride.malfunctionState != malfunctionState))
|
|
{
|
|
ResetNoMalfunctionOverride();
|
|
}
|
|
|
|
if (!m_noMalfunctionOverride.captured)
|
|
{
|
|
bool allowJam = false;
|
|
bool allowFeed = false;
|
|
bool allowMisfire = false;
|
|
bool allowSlide = false;
|
|
float baseChance = 0.f;
|
|
int state = 0;
|
|
|
|
if (!m.TryRead(weaponTemplate + offset::WeaponTemplate::AllowJam, allowJam) ||
|
|
!m.TryRead(weaponTemplate + offset::WeaponTemplate::AllowFeed, allowFeed) ||
|
|
!m.TryRead(weaponTemplate + offset::WeaponTemplate::AllowMisfire, allowMisfire) ||
|
|
!m.TryRead(weaponTemplate + offset::WeaponTemplate::AllowSlide, allowSlide) ||
|
|
!m.TryRead(weaponTemplate + offset::WeaponTemplate::BaseMalfunctionChance, baseChance) ||
|
|
!m.TryRead(malfunctionState + offset::WeaponMalfunctionState::State, state) ||
|
|
!std::isfinite(baseChance))
|
|
{
|
|
ResetNoMalfunctionOverride();
|
|
return;
|
|
}
|
|
|
|
m_noMalfunctionOverride.player = local.m_address;
|
|
m_noMalfunctionOverride.weapon = weapon;
|
|
m_noMalfunctionOverride.weaponTemplate = weaponTemplate;
|
|
m_noMalfunctionOverride.malfunctionState = malfunctionState;
|
|
m_noMalfunctionOverride.allowJam = allowJam;
|
|
m_noMalfunctionOverride.allowFeed = allowFeed;
|
|
m_noMalfunctionOverride.allowMisfire = allowMisfire;
|
|
m_noMalfunctionOverride.allowSlide = allowSlide;
|
|
m_noMalfunctionOverride.baseChance = baseChance;
|
|
m_noMalfunctionOverride.state = state;
|
|
m_noMalfunctionOverride.captured = true;
|
|
}
|
|
|
|
m.TryWrite<bool>(weaponTemplate + offset::WeaponTemplate::AllowJam, false);
|
|
m.TryWrite<bool>(weaponTemplate + offset::WeaponTemplate::AllowFeed, false);
|
|
m.TryWrite<bool>(weaponTemplate + offset::WeaponTemplate::AllowMisfire, false);
|
|
m.TryWrite<bool>(weaponTemplate + offset::WeaponTemplate::AllowSlide, false);
|
|
m.TryWrite<float>(weaponTemplate + offset::WeaponTemplate::BaseMalfunctionChance, 0.f);
|
|
m.TryWrite<int>(malfunctionState + offset::WeaponMalfunctionState::State, 0);
|
|
}
|
|
|
|
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::ResetNoRecoilOverride()
|
|
{
|
|
if (m_noRecoilOverride.captured && IsUsableAddress(m_noRecoilOverride.recoilSettings))
|
|
{
|
|
m.TryWrite<bool>(m_noRecoilOverride.recoilSettings + offset::WeaponRecoil::Enable,
|
|
m_noRecoilOverride.enable);
|
|
}
|
|
|
|
m_noRecoilOverride = {};
|
|
}
|
|
|
|
void CFramework::ResetNoMalfunctionOverride()
|
|
{
|
|
if (m_noMalfunctionOverride.captured)
|
|
{
|
|
if (IsUsableAddress(m_noMalfunctionOverride.weaponTemplate))
|
|
{
|
|
m.TryWrite<bool>(m_noMalfunctionOverride.weaponTemplate + offset::WeaponTemplate::AllowJam,
|
|
m_noMalfunctionOverride.allowJam);
|
|
m.TryWrite<bool>(m_noMalfunctionOverride.weaponTemplate + offset::WeaponTemplate::AllowFeed,
|
|
m_noMalfunctionOverride.allowFeed);
|
|
m.TryWrite<bool>(m_noMalfunctionOverride.weaponTemplate + offset::WeaponTemplate::AllowMisfire,
|
|
m_noMalfunctionOverride.allowMisfire);
|
|
m.TryWrite<bool>(m_noMalfunctionOverride.weaponTemplate + offset::WeaponTemplate::AllowSlide,
|
|
m_noMalfunctionOverride.allowSlide);
|
|
m.TryWrite<float>(m_noMalfunctionOverride.weaponTemplate + offset::WeaponTemplate::BaseMalfunctionChance,
|
|
m_noMalfunctionOverride.baseChance);
|
|
}
|
|
|
|
if (IsUsableAddress(m_noMalfunctionOverride.malfunctionState))
|
|
{
|
|
m.TryWrite<int>(m_noMalfunctionOverride.malfunctionState + offset::WeaponMalfunctionState::State,
|
|
m_noMalfunctionOverride.state);
|
|
}
|
|
}
|
|
|
|
m_noMalfunctionOverride = {};
|
|
}
|
|
|
|
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();
|
|
ResetNoRecoilOverride();
|
|
ResetNoMalfunctionOverride();
|
|
}
|