Improve seed prediction

This commit is contained in:
rei-kes 2024-06-09 02:03:42 -04:00
parent 3b5e8e8e36
commit c45439c16d
6 changed files with 47 additions and 49 deletions

View File

@ -148,6 +148,14 @@ void CMenu::MenuAimbot()
FToggle("Always melee", Vars::CritHack::AlwaysMelee); FToggle("Always melee", Vars::CritHack::AlwaysMelee);
FToggle("No spread", Vars::Aimbot::General::NoSpread, FToggle_Middle); FToggle("No spread", Vars::Aimbot::General::NoSpread, FToggle_Middle);
} EndSection(); } EndSection();
if (Vars::Debug::Info.Value)
{
if (Section("debug## aimbot"))
{
FSlider("offset## nospread", Vars::Aimbot::General::NoSpreadOffset, -5.f, 5.f, 1.f, "%.1f", FSlider_Precision);
FSlider("average", Vars::Aimbot::General::NoSpreadAverage, 1, 100);
} EndSection();
}
if (Section("Backtrack")) if (Section("Backtrack"))
{ {
FToggle("Enabled", Vars::Backtrack::Enabled); FToggle("Enabled", Vars::Backtrack::Enabled);

View File

@ -8,7 +8,8 @@ void CNoSpreadHitscan::Reset(bool bResetPrint)
{ {
bWaitingForPlayerPerf = false; bWaitingForPlayerPerf = false;
flServerTime = 0.f; flServerTime = 0.f;
flFloatTimeDelta = 0.f; vTimeDeltas.clear();
dTimeDelta = 0.f;
iSeed = 0; iSeed = 0;
flMantissaStep = 0; flMantissaStep = 0;
@ -34,10 +35,8 @@ int CNoSpreadHitscan::GetSeed(CUserCmd* pCmd)
static auto sv_usercmd_custom_random_seed = U::ConVars.FindVar("sv_usercmd_custom_random_seed"); static auto sv_usercmd_custom_random_seed = U::ConVars.FindVar("sv_usercmd_custom_random_seed");
if (sv_usercmd_custom_random_seed ? sv_usercmd_custom_random_seed->GetBool() : true) if (sv_usercmd_custom_random_seed ? sv_usercmd_custom_random_seed->GetBool() : true)
{ {
const float flFloatTime = float(SDK::PlatFloatTime()) + flFloatTimeDelta; double dFloatTime = SDK::PlatFloatTime() + dTimeDelta;
//SDK::Output("Seed Prediction", std::format("{}\n", flFloatTime).c_str()); float flTime = float(dFloatTime * 1000.0);
const float flTime = (flFloatTime) * 1000;
return std::bit_cast<int32_t>(flTime) & 255; return std::bit_cast<int32_t>(flTime) & 255;
} }
else else
@ -47,8 +46,8 @@ int CNoSpreadHitscan::GetSeed(CUserCmd* pCmd)
float CNoSpreadHitscan::CalcMantissaStep(float val) float CNoSpreadHitscan::CalcMantissaStep(float val)
{ {
// Calculate the delta to the next representable value // Calculate the delta to the next representable value
const float nextValue = std::nextafter(val, std::numeric_limits<float>::infinity()); float nextValue = std::nextafter(val, std::numeric_limits<float>::infinity());
const float mantissaStep = (nextValue - val) * 1000; float mantissaStep = (nextValue - val) * 1000;
// Get the closest mantissa (next power of 2) // Get the closest mantissa (next power of 2)
return powf(2, ceilf(logf(mantissaStep) / logf(2))); return powf(2, ceilf(logf(mantissaStep) / logf(2)));
@ -56,10 +55,10 @@ float CNoSpreadHitscan::CalcMantissaStep(float val)
std::string CNoSpreadHitscan::GetFormat(int m_ServerTime) std::string CNoSpreadHitscan::GetFormat(int m_ServerTime)
{ {
const int iDays = m_ServerTime / 86400; int iDays = m_ServerTime / 86400;
const int iHours = m_ServerTime / 3600 % 24; int iHours = m_ServerTime / 3600 % 24;
const int iMinutes = m_ServerTime / 60 % 60; int iMinutes = m_ServerTime / 60 % 60;
const int iSeconds = m_ServerTime % 60; int iSeconds = m_ServerTime % 60;
if (iDays) if (iDays)
return std::format("{}d {}h", iDays, iHours); return std::format("{}d {}h", iDays, iHours);
@ -77,8 +76,9 @@ void CNoSpreadHitscan::AskForPlayerPerf()
static Timer playerperfTimer{}; static Timer playerperfTimer{};
if (playerperfTimer.Run(50) && !bWaitingForPlayerPerf && I::EngineClient->IsInGame()) if (playerperfTimer.Run(50) && !bWaitingForPlayerPerf && I::EngineClient->IsInGame())
{ {
I::EngineClient->ClientCmd_Unrestricted("playerperf"); I::ClientState->SendStringCmd("playerperf");
bWaitingForPlayerPerf = true; bWaitingForPlayerPerf = true;
dRequestTime = SDK::PlatFloatTime();
} }
} }
@ -103,21 +103,28 @@ bool CNoSpreadHitscan::ParsePlayerPerf(bf_read& msgData)
bWaitingForPlayerPerf = false; bWaitingForPlayerPerf = false;
// credits to kgb for idea // credits to kgb for idea
const float flNewServerTime = std::stof(matches[1].str()); float flNewServerTime = std::stof(matches[1].str());
if (flNewServerTime < flServerTime) if (flNewServerTime < flServerTime)
return true; return true;
flServerTime = flNewServerTime; flServerTime = flNewServerTime;
flFloatTimeDelta = flServerTime - float(SDK::PlatFloatTime());
double dRecieveTime = SDK::PlatFloatTime();
double dResponseTime = dRecieveTime - dRequestTime;
vTimeDeltas.push_back(flServerTime - dRecieveTime + dResponseTime);
while (!vTimeDeltas.empty() && vTimeDeltas.size() > Vars::Aimbot::General::NoSpreadAverage.Value)
vTimeDeltas.pop_front();
dTimeDelta = std::reduce(vTimeDeltas.begin(), vTimeDeltas.end()) / vTimeDeltas.size() + TICKS_TO_TIME(Vars::Aimbot::General::NoSpreadOffset.Value);
flMantissaStep = CalcMantissaStep(flServerTime); flMantissaStep = CalcMantissaStep(flServerTime);
const int iSynced = flMantissaStep < 4.f ? 2 : 1; const int iSynced = flMantissaStep < /*4*/1.f ? 2 : 1;
bSynced = iSynced == 1; bSynced = iSynced == 1;
if (!iBestSync || iBestSync == 2 && bSynced) if (!iBestSync || iBestSync == 2 && bSynced)
{ {
iBestSync = iSynced; iBestSync = iSynced;
SDK::Output("Seed Prediction", bSynced ? std::format("Synced ({})", flFloatTimeDelta).c_str() : "Not synced, step too low", Vars::Menu::Theme::Accent.Value); SDK::Output("Seed Prediction", bSynced ? std::format("Synced ({})", dTimeDelta).c_str() : "Not synced, step too low", Vars::Menu::Theme::Accent.Value);
SDK::Output("Seed Prediction", std::format("Age {}; Step {}", GetFormat(flServerTime), CalcMantissaStep(flServerTime)).c_str(), Vars::Menu::Theme::Accent.Value); SDK::Output("Seed Prediction", std::format("Age {}; Step {}", GetFormat(flServerTime), CalcMantissaStep(flServerTime)).c_str(), Vars::Menu::Theme::Accent.Value);
} }
@ -134,7 +141,7 @@ void CNoSpreadHitscan::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd*
return; return;
// credits to cathook for average spread stuff // credits to cathook for average spread stuff
const float flSpread = pWeapon->GetWeaponSpread(); float flSpread = pWeapon->GetWeaponSpread();
auto tfWeaponInfo = pWeapon->GetWeaponInfo(); auto tfWeaponInfo = pWeapon->GetWeaponInfo();
int iBulletsPerShot = tfWeaponInfo ? tfWeaponInfo->GetWeaponData(0).m_nBulletsPerShot : 1; int iBulletsPerShot = tfWeaponInfo ? tfWeaponInfo->GetWeaponData(0).m_nBulletsPerShot : 1;
iBulletsPerShot = static_cast<int>(SDK::AttribHookValue(static_cast<float>(iBulletsPerShot), "mult_bullets_per_shot", pWeapon)); iBulletsPerShot = static_cast<int>(SDK::AttribHookValue(static_cast<float>(iBulletsPerShot), "mult_bullets_per_shot", pWeapon));
@ -158,7 +165,7 @@ void CNoSpreadHitscan::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd*
if (!bDoubletap) if (!bDoubletap)
{ {
const float flTimeSinceLastShot = (pLocal->m_nTickBase() * TICK_INTERVAL) - pWeapon->m_flLastFireTime(); float flTimeSinceLastShot = (pLocal->m_nTickBase() * TICK_INTERVAL) - pWeapon->m_flLastFireTime();
if ((iBulletsPerShot == 1 && flTimeSinceLastShot > 1.25f) || (iBulletsPerShot > 1 && flTimeSinceLastShot > 0.25f)) if ((iBulletsPerShot == 1 && flTimeSinceLastShot > 1.25f) || (iBulletsPerShot > 1 && flTimeSinceLastShot > 0.25f))
return; return;
} }

View File

@ -20,8 +20,10 @@ public:
bool bWaitingForPlayerPerf = false; bool bWaitingForPlayerPerf = false;
int bSynced = 0, iBestSync = 0; int bSynced = 0, iBestSync = 0;
double dRequestTime = 0.0;
float flServerTime = 0.f; float flServerTime = 0.f;
float flFloatTimeDelta = 0.f; double dTimeDelta = 0.0;
std::deque<double> vTimeDeltas = {};
int iSeed = 0; int iSeed = 0;
float flMantissaStep = 0; float flMantissaStep = 0;

View File

@ -218,7 +218,7 @@ void CVisuals::DrawSeedPrediction(CTFPlayer* pLocal)
if (Vars::Debug::Info.Value) if (Vars::Debug::Info.Value)
{ {
H::Draw.String(fFont, x, y += fFont.m_nTall + 1, cColor, align, std::format("Seed {}", F::NoSpreadHitscan.iSeed).c_str()); H::Draw.String(fFont, x, y += fFont.m_nTall + 1, cColor, align, std::format("Seed {}", F::NoSpreadHitscan.iSeed).c_str());
H::Draw.String(fFont, x, y += fFont.m_nTall + 1, cColor, align, std::format("{}", F::NoSpreadHitscan.flFloatTimeDelta).c_str()); H::Draw.String(fFont, x, y += fFont.m_nTall + 1, cColor, align, std::format("{} ({})", F::NoSpreadHitscan.dTimeDelta, F::NoSpreadHitscan.vTimeDeltas.size()).c_str());
} }
} }

View File

@ -2,35 +2,7 @@
#include "Interface.h" #include "Interface.h"
#include "../Main/INetChannel.h" #include "../Main/INetChannel.h"
/* MAKE_SIGNATURE(CBaseClientState_SendStringCmd, "engine.dll", "48 81 EC ? ? ? ? 48 8B 49", 0x0);
class CClockDriftMgr
{
public:
enum { NUM_CLOCKDRIFT_SAMPLES = 16 };
float m_ClockOffsets[NUM_CLOCKDRIFT_SAMPLES]{};
int m_iCurClockOffset{};
int m_nServerTick{};
int m_nClientTick{};
};
class CClientState
{
public:
byte pad0[0x10]{};
INetChannel* m_NetChannel{};
byte pad1[0x140]{};
CClockDriftMgr m_ClockDriftMgr{};
int m_nDeltaTick{};
byte pad2[0x110]{};
int m_nMaxClients{};
byte pad3[0x4868]{};
float m_frameTime{};
int lastoutgoingcommand{};
int chokedcommands{};
int last_command_ack{};
};
*/
struct CUtlString struct CUtlString
{ {
@ -94,6 +66,12 @@ public:
CUtlString demos[32]; CUtlString demos[32];
byte gap8EE8[344184]; byte gap8EE8[344184];
bool m_bMarkedCRCsUnverified; bool m_bMarkedCRCsUnverified;
public:
void SendStringCmd(const char* command)
{
reinterpret_cast<void(__fastcall*)(void*, const char*)>(S::CBaseClientState_SendStringCmd())(this, command);
}
}; };
MAKE_INTERFACE_SIGNATURE(CClientState, ClientState, "engine.dll", "48 8D 0D ? ? ? ? E8 ? ? ? ? F3 0F 5E 05", 0x0, 0); MAKE_INTERFACE_SIGNATURE(CClientState, ClientState, "engine.dll", "48 8D 0D ? ? ? ? E8 ? ? ? ? F3 0F 5E 05", 0x0, 0);

View File

@ -118,6 +118,9 @@ namespace Vars
CVar(AutoShoot, true) CVar(AutoShoot, true)
CVar(FOVCircle, true) CVar(FOVCircle, true)
CVar(NoSpread, false) CVar(NoSpread, false)
CVar(NoSpreadOffset, 0.f, NOSAVE) // debug
CVar(NoSpreadAverage, 5, NOSAVE) // debug
SUBNAMESPACE_END(Global) SUBNAMESPACE_END(Global)
SUBNAMESPACE_BEGIN(Hitscan) SUBNAMESPACE_BEGIN(Hitscan)