diff --git a/Amalgam/src/Features/ImGui/Menu/Menu.cpp b/Amalgam/src/Features/ImGui/Menu/Menu.cpp index 66b7b6c..be9eda4 100644 --- a/Amalgam/src/Features/ImGui/Menu/Menu.cpp +++ b/Amalgam/src/Features/ImGui/Menu/Menu.cpp @@ -148,6 +148,14 @@ void CMenu::MenuAimbot() FToggle("Always melee", Vars::CritHack::AlwaysMelee); FToggle("No spread", Vars::Aimbot::General::NoSpread, FToggle_Middle); } 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")) { FToggle("Enabled", Vars::Backtrack::Enabled); diff --git a/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.cpp b/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.cpp index 1e2db12..ec25e9f 100644 --- a/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.cpp +++ b/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.cpp @@ -8,7 +8,8 @@ void CNoSpreadHitscan::Reset(bool bResetPrint) { bWaitingForPlayerPerf = false; flServerTime = 0.f; - flFloatTimeDelta = 0.f; + vTimeDeltas.clear(); + dTimeDelta = 0.f; iSeed = 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"); if (sv_usercmd_custom_random_seed ? sv_usercmd_custom_random_seed->GetBool() : true) { - const float flFloatTime = float(SDK::PlatFloatTime()) + flFloatTimeDelta; - //SDK::Output("Seed Prediction", std::format("{}\n", flFloatTime).c_str()); - - const float flTime = (flFloatTime) * 1000; + double dFloatTime = SDK::PlatFloatTime() + dTimeDelta; + float flTime = float(dFloatTime * 1000.0); return std::bit_cast(flTime) & 255; } else @@ -47,8 +46,8 @@ int CNoSpreadHitscan::GetSeed(CUserCmd* pCmd) float CNoSpreadHitscan::CalcMantissaStep(float val) { // Calculate the delta to the next representable value - const float nextValue = std::nextafter(val, std::numeric_limits::infinity()); - const float mantissaStep = (nextValue - val) * 1000; + float nextValue = std::nextafter(val, std::numeric_limits::infinity()); + float mantissaStep = (nextValue - val) * 1000; // Get the closest mantissa (next power of 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) { - const int iDays = m_ServerTime / 86400; - const int iHours = m_ServerTime / 3600 % 24; - const int iMinutes = m_ServerTime / 60 % 60; - const int iSeconds = m_ServerTime % 60; + int iDays = m_ServerTime / 86400; + int iHours = m_ServerTime / 3600 % 24; + int iMinutes = m_ServerTime / 60 % 60; + int iSeconds = m_ServerTime % 60; if (iDays) return std::format("{}d {}h", iDays, iHours); @@ -77,8 +76,9 @@ void CNoSpreadHitscan::AskForPlayerPerf() static Timer playerperfTimer{}; if (playerperfTimer.Run(50) && !bWaitingForPlayerPerf && I::EngineClient->IsInGame()) { - I::EngineClient->ClientCmd_Unrestricted("playerperf"); + I::ClientState->SendStringCmd("playerperf"); bWaitingForPlayerPerf = true; + dRequestTime = SDK::PlatFloatTime(); } } @@ -103,21 +103,28 @@ bool CNoSpreadHitscan::ParsePlayerPerf(bf_read& msgData) bWaitingForPlayerPerf = false; // credits to kgb for idea - const float flNewServerTime = std::stof(matches[1].str()); + float flNewServerTime = std::stof(matches[1].str()); if (flNewServerTime < flServerTime) return true; 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); - const int iSynced = flMantissaStep < 4.f ? 2 : 1; + const int iSynced = flMantissaStep < /*4*/1.f ? 2 : 1; bSynced = iSynced == 1; if (!iBestSync || iBestSync == 2 && bSynced) { 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); } @@ -134,7 +141,7 @@ void CNoSpreadHitscan::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* return; // credits to cathook for average spread stuff - const float flSpread = pWeapon->GetWeaponSpread(); + float flSpread = pWeapon->GetWeaponSpread(); auto tfWeaponInfo = pWeapon->GetWeaponInfo(); int iBulletsPerShot = tfWeaponInfo ? tfWeaponInfo->GetWeaponData(0).m_nBulletsPerShot : 1; iBulletsPerShot = static_cast(SDK::AttribHookValue(static_cast(iBulletsPerShot), "mult_bullets_per_shot", pWeapon)); @@ -158,7 +165,7 @@ void CNoSpreadHitscan::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* 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)) return; } diff --git a/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h b/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h index a094c5f..140303b 100644 --- a/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h +++ b/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h @@ -20,8 +20,10 @@ public: bool bWaitingForPlayerPerf = false; int bSynced = 0, iBestSync = 0; + double dRequestTime = 0.0; float flServerTime = 0.f; - float flFloatTimeDelta = 0.f; + double dTimeDelta = 0.0; + std::deque vTimeDeltas = {}; int iSeed = 0; float flMantissaStep = 0; diff --git a/Amalgam/src/Features/Visuals/Visuals.cpp b/Amalgam/src/Features/Visuals/Visuals.cpp index 01f9ff5..3428fb5 100644 --- a/Amalgam/src/Features/Visuals/Visuals.cpp +++ b/Amalgam/src/Features/Visuals/Visuals.cpp @@ -218,7 +218,7 @@ void CVisuals::DrawSeedPrediction(CTFPlayer* pLocal) 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("{}", 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()); } } diff --git a/Amalgam/src/SDK/Definitions/Interfaces/CClientState.h b/Amalgam/src/SDK/Definitions/Interfaces/CClientState.h index c04100f..b77c37d 100644 --- a/Amalgam/src/SDK/Definitions/Interfaces/CClientState.h +++ b/Amalgam/src/SDK/Definitions/Interfaces/CClientState.h @@ -2,35 +2,7 @@ #include "Interface.h" #include "../Main/INetChannel.h" -/* -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{}; -}; -*/ +MAKE_SIGNATURE(CBaseClientState_SendStringCmd, "engine.dll", "48 81 EC ? ? ? ? 48 8B 49", 0x0); struct CUtlString { @@ -94,6 +66,12 @@ public: CUtlString demos[32]; byte gap8EE8[344184]; bool m_bMarkedCRCsUnverified; + +public: + void SendStringCmd(const char* command) + { + reinterpret_cast(S::CBaseClientState_SendStringCmd())(this, command); + } }; MAKE_INTERFACE_SIGNATURE(CClientState, ClientState, "engine.dll", "48 8D 0D ? ? ? ? E8 ? ? ? ? F3 0F 5E 05", 0x0, 0); \ No newline at end of file diff --git a/Amalgam/src/SDK/Vars.h b/Amalgam/src/SDK/Vars.h index 060d5fa..1755bfd 100644 --- a/Amalgam/src/SDK/Vars.h +++ b/Amalgam/src/SDK/Vars.h @@ -118,6 +118,9 @@ namespace Vars CVar(AutoShoot, true) CVar(FOVCircle, true) CVar(NoSpread, false) + + CVar(NoSpreadOffset, 0.f, NOSAVE) // debug + CVar(NoSpreadAverage, 5, NOSAVE) // debug SUBNAMESPACE_END(Global) SUBNAMESPACE_BEGIN(Hitscan)