From 95e2a87932e244ea55c9e4f7865469d386fdf4f4 Mon Sep 17 00:00:00 2001 From: rei-2 <174158077+rei-2@users.noreply.github.com> Date: Sun, 28 Sep 2025 18:54:55 -0400 Subject: [PATCH] resimulate in caimbotmelee::canbackstab to prevent prediction error causing miss --- .../Aimbot/AimbotMelee/AimbotMelee.cpp | 43 ++++++++++++--- .../EnginePrediction/EnginePrediction.cpp | 53 ++++++------------- .../EnginePrediction/EnginePrediction.h | 12 ++--- Amalgam/src/Features/Misc/Misc.cpp | 12 +++-- Amalgam/src/Features/Ticks/Ticks.cpp | 30 +++++++++++ Amalgam/src/Features/Ticks/Ticks.h | 5 ++ Amalgam/src/Hooks/CHLClient_CreateMove.cpp | 39 +++++++------- .../src/Hooks/CPrediction_RunSimulation.cpp | 2 +- .../SDK/Definitions/Interfaces/Prediction.h | 6 +++ .../src/SDK/Definitions/Main/CBaseEntity.h | 1 + 10 files changed, 128 insertions(+), 75 deletions(-) diff --git a/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp b/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp index bd7a0ece..4407865f 100644 --- a/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp +++ b/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp @@ -2,6 +2,7 @@ #include "../Aimbot.h" #include "../../Simulation/MovementSimulation/MovementSimulation.h" +#include "../../EnginePrediction/EnginePrediction.h" #include "../../Ticks/Ticks.h" #include "../../Visuals/Visuals.h" @@ -177,7 +178,13 @@ void CAimbotMelee::UpdateInfo(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCm } if (m_iDoubletapTicks && Vars::Doubletap::AntiWarp.Value && pLocal->m_hGroundEntity()) F::Ticks.AntiWarp(pLocal, pCmd->viewangles.y, tStorage.m_MoveData.m_flForwardMove, tStorage.m_MoveData.m_flSideMove, iMax - i - 1); + F::MoveSim.RunTick(tStorage); + m_mRecordMap[I::EngineClient->GetLocalPlayer()].emplace_front( + pLocal->m_flSimulationTime() + TICKS_TO_TIME(i + 1), + tStorage.m_MoveData.m_vecAbsOrigin, + pLocal->m_vecMins(), pLocal->m_vecMaxs() + ); } if (i < iSimTicks - m_iDoubletapTicks) @@ -246,14 +253,38 @@ bool CAimbotMelee::CanBackstab(CBaseEntity* pTarget, CTFPlayer* pLocal, Vec3 vEy } } - Vec3 vToTarget = (pTarget->GetAbsOrigin() - m_vEyePos).To2D(); + Vec3 vEyePos = m_vEyePos; + const float flCompDist = 0.0625f; + const float flSqCompDist = 0.0884f; + + if (auto pCmd = G::CurrentUserCmd; + m_mRecordMap[pLocal->entindex()].empty() && pCmd->viewangles != vEyeAngles && G::CanPrimaryAttack) + { // repredict, prevent prediction error causing miss + CUserCmd tOldCmd = *pCmd; + Vec3 vOldAngles = I::EngineClient->GetViewAngles(); + int iOldAttacking = G::Attacking; + bool bOldSilent = G::PSilentAngles; + F::EnginePrediction.End(pLocal, pCmd); + + G::Attacking = true; + Aim(pCmd, vEyeAngles); + F::Ticks.Start(pLocal, pCmd); + vEyePos = pLocal->GetShootPos(); + F::EnginePrediction.End(pLocal, pCmd); + + *pCmd = tOldCmd; + I::EngineClient->SetViewAngles(vOldAngles); + G::Attacking = iOldAttacking; + G::PSilentAngles = bOldSilent; + F::Ticks.Start(pLocal, pCmd); + } + + Vec3 vToTarget = (pTarget->GetAbsOrigin() - vEyePos).To2D(); const float flDist = vToTarget.Normalize(); - if (!flDist) + if (flDist < flSqCompDist) return false; - float flTolerance = 0.0625f; - float flExtra = 2.f * flTolerance / flDist; // account for origin compression - + const float flExtra = 2.f * flCompDist / flDist; // account for origin compression float flPosVsTargetViewMinDot = 0.f + 0.0031f + flExtra; float flPosVsOwnerViewMinDot = 0.5f + flExtra; float flViewAnglesMinDot = -0.3f + 0.0031f; // 0.00306795676297 ? @@ -347,7 +378,7 @@ int CAimbotMelee::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBase* pW tTarget.m_pEntity->m_vecMins() = pRecord->m_vMins + 0.125f; // account for origin compression tTarget.m_pEntity->m_vecMaxs() = pRecord->m_vMaxs - 0.125f; - Vec3 vDiff = { 0, 0, std::clamp(m_vEyePos.z - pRecord->m_vOrigin.z, tTarget.m_pEntity->m_vecMins().z, tTarget.m_pEntity->m_vecMaxs().z) }; + Vec3 vDiff = { 0, 0, std::clamp(m_vEyePos.z - pRecord->m_vOrigin.z, pRecord->m_vMins.z, pRecord->m_vMaxs.z) }; tTarget.m_vPos = pRecord->m_vOrigin + vDiff; Aim(G::CurrentUserCmd->viewangles, Math::CalcAngle(m_vEyePos, tTarget.m_vPos), tTarget.m_vAngleTo); diff --git a/Amalgam/src/Features/EnginePrediction/EnginePrediction.cpp b/Amalgam/src/Features/EnginePrediction/EnginePrediction.cpp index e9aaa65f..c99be556 100644 --- a/Amalgam/src/Features/EnginePrediction/EnginePrediction.cpp +++ b/Amalgam/src/Features/EnginePrediction/EnginePrediction.cpp @@ -2,8 +2,8 @@ #include "../Ticks/Ticks.h" -// account for origin compression when simulating local player -void CEnginePrediction::ScalePlayers(CBaseEntity* pLocal) +// account for interp and origin compression when simulating local player +void CEnginePrediction::AdjustPlayers(CBaseEntity* pLocal) { m_mRestore.clear(); @@ -13,8 +13,9 @@ void CEnginePrediction::ScalePlayers(CBaseEntity* pLocal) if (pPlayer == pLocal || !pPlayer->IsAlive() || pPlayer->IsAGhost()) continue; - m_mRestore[pPlayer] = { pPlayer->m_vecMins(), pPlayer->m_vecMaxs() }; + m_mRestore[pPlayer] = { pPlayer->GetAbsOrigin(), pPlayer->m_vecMins(), pPlayer->m_vecMaxs() }; + pPlayer->SetAbsOrigin(pPlayer->m_vecOrigin()); pPlayer->m_vecMins() += 0.125f; pPlayer->m_vecMaxs() -= 0.125f; } @@ -23,16 +24,14 @@ void CEnginePrediction::RestorePlayers() { for (auto& [pPlayer, tRestore] : m_mRestore) { - pPlayer->m_vecMins() = tRestore.m_vecMins; - pPlayer->m_vecMaxs() = tRestore.m_vecMaxs; + pPlayer->SetAbsOrigin(tRestore.m_vOrigin); + pPlayer->m_vecMins() = tRestore.m_vMins; + pPlayer->m_vecMaxs() = tRestore.m_vMaxs; } } void CEnginePrediction::Simulate(CTFPlayer* pLocal, CUserCmd* pCmd) { - if (!I::MoveHelper) - return; - const int nOldTickBase = pLocal->m_nTickBase(); const bool bOldIsFirstPrediction = I::Prediction->m_bFirstTimePredicted; const bool bOldInPrediction = I::Prediction->m_bInPrediction; @@ -45,28 +44,11 @@ void CEnginePrediction::Simulate(CTFPlayer* pLocal, CUserCmd* pCmd) I::Prediction->m_bInPrediction = true; I::Prediction->SetLocalViewAngles(pCmd->viewangles); - Vec2 vOriginalMove; int iOriginalButtons; - if (m_bDoubletap = m_bInPrediction && (F::Ticks.m_bAntiWarp || F::Ticks.GetTicks(H::Entities.GetWeapon()) && Vars::Doubletap::AntiWarp.Value && pLocal->m_hGroundEntity())) - { - m_vOriginalOrigin = pLocal->m_vecOrigin(); - m_vOriginalVelocity = pLocal->m_vecVelocity(); - vOriginalMove = { pCmd->forwardmove, pCmd->sidemove }; - iOriginalButtons = pCmd->buttons; - - F::Ticks.AntiWarp(pLocal, pCmd->viewangles.y, pCmd->forwardmove, pCmd->sidemove); - } - + AdjustPlayers(pLocal); I::Prediction->SetupMove(pLocal, pCmd, I::MoveHelper, &m_MoveData); - ScalePlayers(pLocal); I::GameMovement->ProcessMovement(pLocal, &m_MoveData); - RestorePlayers(); I::Prediction->FinishMove(pLocal, pCmd, &m_MoveData); - - if (m_bDoubletap) - { - pCmd->forwardmove = vOriginalMove.x, pCmd->sidemove = vOriginalMove.y; - pCmd->buttons = iOriginalButtons; - } + RestorePlayers(); I::MoveHelper->SetHost(nullptr); pLocal->m_pCurrentCommand() = nullptr; @@ -76,8 +58,8 @@ void CEnginePrediction::Simulate(CTFPlayer* pLocal, CUserCmd* pCmd) I::Prediction->m_bFirstTimePredicted = bOldIsFirstPrediction; I::Prediction->m_bInPrediction = bOldInPrediction; - m_vOrigin = pLocal->m_vecOrigin(); - m_vVelocity = pLocal->m_vecVelocity(); + m_vOrigin = m_MoveData.m_vecAbsOrigin; + m_vVelocity = m_MoveData.m_vecVelocity; m_vDirection = { m_MoveData.m_flForwardMove, -m_MoveData.m_flSideMove, m_MoveData.m_flUpMove }; m_vAngles = m_MoveData.m_vecViewAngles; } @@ -98,6 +80,9 @@ void CEnginePrediction::Start(CTFPlayer* pLocal, CUserCmd* pCmd) I::GlobalVars->curtime = TICKS_TO_TIME(I::GlobalVars->tickcount); I::GlobalVars->frametime = I::Prediction->m_bEnginePaused ? 0.f : TICK_INTERVAL; + m_vOldOrigin = pLocal->m_vecOrigin(); + m_vOldVelocity = pLocal->m_vecVelocity(); + Simulate(pLocal, pCmd); } @@ -111,12 +96,6 @@ void CEnginePrediction::End(CTFPlayer* pLocal, CUserCmd* pCmd) I::GlobalVars->curtime = m_flOldCurrentTime; I::GlobalVars->frametime = m_flOldFrameTime; - if (m_bDoubletap && !F::Ticks.m_bAntiWarp && !G::Attacking) - { - pLocal->m_vecOrigin() = m_vOriginalOrigin; - pLocal->m_vecVelocity() = m_vOriginalVelocity; - pLocal->SetAbsVelocity(m_vOriginalVelocity); - - Simulate(pLocal, pCmd); - } + pLocal->SetAbsOrigin(pLocal->m_vecOrigin() = m_vOldOrigin); + pLocal->SetAbsVelocity(pLocal->m_vecVelocity() = m_vOldVelocity); } \ No newline at end of file diff --git a/Amalgam/src/Features/EnginePrediction/EnginePrediction.h b/Amalgam/src/Features/EnginePrediction/EnginePrediction.h index 88d4e595..4a386764 100644 --- a/Amalgam/src/Features/EnginePrediction/EnginePrediction.h +++ b/Amalgam/src/Features/EnginePrediction/EnginePrediction.h @@ -3,8 +3,9 @@ struct RestoreInfo_t { - Vec3 m_vecMins = {}; - Vec3 m_vecMaxs = {}; + Vec3 m_vOrigin = {}; + Vec3 m_vMins = {}; + Vec3 m_vMaxs = {}; }; class CEnginePrediction @@ -18,9 +19,8 @@ private: float m_flOldCurrentTime = 0.f; float m_flOldFrameTime = 0.f; - bool m_bDoubletap = false; - Vec3 m_vOriginalOrigin = {}; - Vec3 m_vOriginalVelocity = {}; + Vec3 m_vOldOrigin = {}; + Vec3 m_vOldVelocity = {}; std::unordered_map m_mRestore = {}; @@ -28,7 +28,7 @@ public: void Start(CTFPlayer* pLocal, CUserCmd* pCmd); void End(CTFPlayer* pLocal, CUserCmd* pCmd); - void ScalePlayers(CBaseEntity* pLocal); + void AdjustPlayers(CBaseEntity* pLocal); void RestorePlayers(); bool m_bInPrediction = false; diff --git a/Amalgam/src/Features/Misc/Misc.cpp b/Amalgam/src/Features/Misc/Misc.cpp index b66dff9f..bc6fbf18 100644 --- a/Amalgam/src/Features/Misc/Misc.cpp +++ b/Amalgam/src/Features/Misc/Misc.cpp @@ -483,19 +483,23 @@ int CMisc::AntiBackstab(CTFPlayer* pLocal, CUserCmd* pCmd, bool bSendPacket) { auto TargetIsBehind = [&]() { + const float flCompDist = 0.0625f; + const float flSqCompDist = 0.0884f; + Vec3 vToTarget = (pLocal->m_vecOrigin() - pTargetPos.first).To2D(); const float flDist = vToTarget.Normalize(); - if (!flDist) + if (flDist < flSqCompDist) return true; - float flTolerance = 0.0625f; - float flExtra = 2.f * flTolerance / flDist; // account for origin compression + const float flExtra = 2.f * flCompDist / flDist; // account for origin compression float flPosVsTargetViewMinDot = 0.f - 0.0031f - flExtra; Vec3 vTargetForward; Math::AngleVectors(pCmd->viewangles, &vTargetForward); vTargetForward.Normalize2D(); - return vToTarget.Dot(vTargetForward) > flPosVsTargetViewMinDot; + const float flPosVsTargetViewDot = vToTarget.Dot(vTargetForward); // Behind? + + return flPosVsTargetViewDot > flPosVsTargetViewMinDot; }; if (!TargetIsBehind()) diff --git a/Amalgam/src/Features/Ticks/Ticks.cpp b/Amalgam/src/Features/Ticks/Ticks.cpp index 64e285ce..78c935f1 100644 --- a/Amalgam/src/Features/Ticks/Ticks.cpp +++ b/Amalgam/src/Features/Ticks/Ticks.cpp @@ -2,6 +2,7 @@ #include "../NetworkFix/NetworkFix.h" #include "../PacketManip/AntiAim/AntiAim.h" +#include "../EnginePrediction/EnginePrediction.h" #include "../Aimbot/AutoRocketJump/AutoRocketJump.h" #include "../Backtrack/Backtrack.h" @@ -276,6 +277,35 @@ void CTicks::ManagePacket(CUserCmd* pCmd, bool* pSendPacket) } } +void CTicks::Start(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + Vec2 vOriginalMove; int iOriginalButtons; + if (m_bPredictAntiwarp = m_bAntiWarp || GetTicks(H::Entities.GetWeapon()) && Vars::Doubletap::AntiWarp.Value && pLocal->m_hGroundEntity()) + { + vOriginalMove = { pCmd->forwardmove, pCmd->sidemove }; + iOriginalButtons = pCmd->buttons; + + AntiWarp(pLocal, pCmd->viewangles.y, pCmd->forwardmove, pCmd->sidemove); + } + + F::EnginePrediction.Start(pLocal, pCmd); + + if (m_bPredictAntiwarp) + { + pCmd->forwardmove = vOriginalMove.x, pCmd->sidemove = vOriginalMove.y; + pCmd->buttons = iOriginalButtons; + } +} + +void CTicks::End(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (m_bPredictAntiwarp && !m_bAntiWarp && !G::Attacking) + { + F::EnginePrediction.End(pLocal, pCmd); + F::EnginePrediction.Start(pLocal, pCmd); + } +} + bool CTicks::CanChoke() { static auto sv_maxusrcmdprocessticks = U::ConVars.FindVar("sv_maxusrcmdprocessticks"); diff --git a/Amalgam/src/Features/Ticks/Ticks.h b/Amalgam/src/Features/Ticks/Ticks.h index 6d4cdf2b..cba099c5 100644 --- a/Amalgam/src/Features/Ticks/Ticks.h +++ b/Amalgam/src/Features/Ticks/Ticks.h @@ -21,12 +21,17 @@ private: bool m_bShootAngle = false; Vec3 m_vShootAngle = {}; + bool m_bPredictAntiwarp = false; + public: void Move(float accumulated_extra_samples, bool bFinalTick, CTFPlayer* pLocal); void CreateMove(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket); void Draw(CTFPlayer* pLocal); void Reset(); + void Start(CTFPlayer* pLocal, CUserCmd* pCmd); + void End(CTFPlayer* pLocal, CUserCmd* pCmd); + void AntiWarp(CTFPlayer* pLocal, float flYaw, float& flForwardMove, float& flSideMove, int iTicks = -1); void AntiWarp(CTFPlayer* pLocal, CUserCmd* pCmd); diff --git a/Amalgam/src/Hooks/CHLClient_CreateMove.cpp b/Amalgam/src/Hooks/CHLClient_CreateMove.cpp index ce3ec7d7..deb2bbce 100644 --- a/Amalgam/src/Hooks/CHLClient_CreateMove.cpp +++ b/Amalgam/src/Hooks/CHLClient_CreateMove.cpp @@ -203,7 +203,6 @@ static inline void AntiCheatCompatibility(CUserCmd* pCmd, bool* pSendPacket) pCmd->viewangles = vHistory[0].m_vAngle + Vec3(0.f, REAL_EPSILON * 2); vHistory[0].m_vAngle = pCmd->viewangles; vHistory[0].m_bSendingPacket = *pSendPacket = vHistory[1].m_bSendingPacket; - G::Choking = !*pSendPacket; } // prevent aim snap checks @@ -224,7 +223,6 @@ static inline void AntiCheatCompatibility(CUserCmd* pCmd, bool* pSendPacket) pCmd->viewangles.y += SNAP_NOISE_EPSILON * 2; vHistory[0].m_vAngle = pCmd->viewangles; vHistory[0].m_bSendingPacket = *pSendPacket = vHistory[1].m_bSendingPacket; - G::Choking = !*pSendPacket; } } } @@ -251,27 +249,26 @@ MAKE_HOOK(CHLClient_CreateMove, U::Memory.GetVirtual(I::Client, 21), void, I::Prediction->Update(I::ClientState->m_nDeltaTick, I::ClientState->m_nDeltaTick > 0, I::ClientState->last_command_ack, I::ClientState->lastoutgoingcommand + I::ClientState->chokedcommands); UpdateInfo(pLocal, pWeapon, pCmd); - F::Spectate.CreateMove(pCmd); - F::Backtrack.CreateMove(pCmd); - F::Misc.RunPre(pLocal, pCmd); - - F::EnginePrediction.Start(pLocal, pCmd); - F::Aimbot.Run(pLocal, pWeapon, pCmd); - F::CritHack.Run(pLocal, pWeapon, pCmd); - F::NoSpread.Run(pLocal, pWeapon, pCmd); - F::Resolver.CreateMove(pLocal); + F::Spectate.CreateMove(pCmd); + F::Backtrack.CreateMove(pCmd); + F::Misc.RunPre(pLocal, pCmd); + F::Ticks.Start(pLocal, pCmd); + F::Aimbot.Run(pLocal, pWeapon, pCmd); + F::Ticks.End(pLocal, pCmd); + F::CritHack.Run(pLocal, pWeapon, pCmd); + F::NoSpread.Run(pLocal, pWeapon, pCmd); + F::Resolver.CreateMove(pLocal); + F::Misc.RunPost(pLocal, pCmd, *pSendPacket); + F::PacketManip.Run(pLocal, pWeapon, pCmd, pSendPacket); + F::Visuals.CreateMove(pLocal, pWeapon); + F::Ticks.CreateMove(pLocal, pCmd, pSendPacket); + F::AntiAim.Run(pLocal, pWeapon, pCmd, *pSendPacket); + F::NoSpreadHitscan.AskForPlayerPerf(); F::EnginePrediction.End(pLocal, pCmd); - F::Misc.RunPost(pLocal, pCmd, *pSendPacket); - F::PacketManip.Run(pLocal, pWeapon, pCmd, pSendPacket); - F::Visuals.CreateMove(pLocal, pWeapon); - F::Ticks.CreateMove(pLocal, pCmd, pSendPacket); - F::AntiAim.Run(pLocal, pWeapon, pCmd, *pSendPacket); - F::NoSpreadHitscan.AskForPlayerPerf(); - - G::Choking = !*pSendPacket; - G::LastUserCmd = pCmd; - AntiCheatCompatibility(pCmd, pSendPacket); LocalAnimations(pLocal, pCmd, *pSendPacket); + + G::Choking = !*pSendPacket; + G::LastUserCmd = pCmd; } \ No newline at end of file diff --git a/Amalgam/src/Hooks/CPrediction_RunSimulation.cpp b/Amalgam/src/Hooks/CPrediction_RunSimulation.cpp index 52121bbf..64d7ef12 100644 --- a/Amalgam/src/Hooks/CPrediction_RunSimulation.cpp +++ b/Amalgam/src/Hooks/CPrediction_RunSimulation.cpp @@ -39,7 +39,7 @@ MAKE_HOOK(CPrediction_RunSimulation, S::CPrediction_RunSimulation(), void, ++it; } - F::EnginePrediction.ScalePlayers(localPlayer); + F::EnginePrediction.AdjustPlayers(localPlayer); CALL_ORIGINAL(rcx, current_command, curtime, cmd, localPlayer); F::EnginePrediction.RestorePlayers(); } \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/Prediction.h b/Amalgam/src/SDK/Definitions/Interfaces/Prediction.h index 68f4393e..5a2abb1b 100644 --- a/Amalgam/src/SDK/Definitions/Interfaces/Prediction.h +++ b/Amalgam/src/SDK/Definitions/Interfaces/Prediction.h @@ -2,6 +2,8 @@ #include "IMoveHelper.h" #include "../Misc/IPrediction.h" +MAKE_SIGNATURE(CPrediction_RestoreEntityToPredictedFrame, "client.dll", "40 55 48 83 EC ? 8B EA", 0x0); + class CMoveData; class CUserCmd; class CBasePlayer; @@ -32,6 +34,8 @@ public: virtual void SetIdealPitch(CBasePlayer* player, const Vec3& origin, const Vec3& angles, const Vec3& viewheight) = 0; virtual void _Update(bool received_new_world_update, bool validframe, int incoming_acknowledged, int outgoing_command) = 0; + SIGNATURE_ARGS(RestoreEntityToPredictedFrame, void, CPrediction, (int predicted_frame), this, predicted_frame); + CHandle m_hLastGround; bool m_bInPrediction; bool m_bFirstTimePredicted; @@ -41,6 +45,8 @@ public: int m_nCommandsPredicted; int m_nServerCommandsAcknowledged; int m_bPreviousAckHadErrors; + int m_bPreviousAckErrorTriggersFullLatchReset; + CUtlVector> m_EntsWithPredictionErrorsInLastAck; int m_nIncomingPacketNumber; float m_flIdealPitch; }; diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseEntity.h b/Amalgam/src/SDK/Definitions/Main/CBaseEntity.h index ef5fc9fc..631cf4b0 100644 --- a/Amalgam/src/SDK/Definitions/Main/CBaseEntity.h +++ b/Amalgam/src/SDK/Definitions/Main/CBaseEntity.h @@ -265,6 +265,7 @@ public: return false; } + VIRTUAL(GetPredDescMap, datamap_t*, 15, this); //VIRTUAL(IsPlayer, bool, 132, this); VIRTUAL(IsBaseCombatCharacter, bool, 133, this); //VIRTUAL(IsNPC, bool, 135, this);