Improve/fix a couple things mainly related to doubletap & movesim
Some checks failed
MSBuild / msbuild (Release, x64) (push) Has been cancelled
MSBuild / msbuild (ReleaseAVX2, x64) (push) Has been cancelled

This commit is contained in:
rei-kes 2024-06-09 21:19:50 -04:00
parent c45439c16d
commit 70ca468968
11 changed files with 118 additions and 36 deletions

View File

@ -314,7 +314,10 @@ int CAimbotHitscan::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* p
if (Vars::Aimbot::General::Ignore.Value & UNSIMULATED && G::ChokeMap[target.m_pEntity->entindex()] > Vars::Aimbot::General::TickTolerance.Value)
return false;
Vec3 vEyePos = pLocal->GetShootPos();
Vec3 vEyePos = pLocal->GetShootPos(), vPeekPos = {};
float flSpread = pWeapon->GetWeaponSpread();
if (flSpread)
vPeekPos = pLocal->GetShootPos() + pLocal->GetAbsVelocity() * TICKS_TO_TIME(-Vars::Aimbot::General::HitscanPeek.Value);
const float flMaxRange = powf(GetMaxRange(pWeapon), 2.f);
auto pModel = target.m_pEntity->GetModel();
@ -350,6 +353,16 @@ int CAimbotHitscan::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* p
}
}
static int iPreferredTick = 0; // if we're doubletapping, we can't change viewangles so have a preferred tick to use
if (!I::ClientState->chokedcommands)
iPreferredTick = 0;
if (iPreferredTick)
{
auto pivot = std::find_if(vRecords.begin(), vRecords.end(), [](auto& s) -> bool { return s.iTickCount == iPreferredTick; });
if (pivot != vRecords.end())
std::rotate(vRecords.begin(), pivot, pivot + 1);
}
auto RayToOBB = [](const Vec3& origin, const Vec3& direction, const Vec3& position, const Vec3& min, const Vec3& max, const matrix3x4 orientation) -> bool
{
if (Vars::Aimbot::General::AimType.Value != 2)
@ -446,7 +459,11 @@ int CAimbotHitscan::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* p
Vec3 vForward = {};
Math::AngleVectors(vAngles, &vForward);
if (SDK::VisPos(pLocal, target.m_pEntity, vEyePos, vTransformed))
bool bPeekCheck = flSpread ? SDK::VisPos(pLocal, target.m_pEntity, vPeekPos, vTransformed) : true;
if (bPeekCheck)
flSpread = 0.f; // only use with a single hitbox
if (SDK::VisPos(pLocal, target.m_pEntity, vEyePos, vTransformed) && bPeekCheck)
{
target.m_vAngleTo = vAngles;
if (RayToOBB(vEyePos, vForward, vCenter, vMins, vMaxs, boneMatrix[pair.first->bone])) // for the time being, no vischecks against other hitboxes
@ -460,6 +477,8 @@ int CAimbotHitscan::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* p
}
if (bWillHit)
{
iPreferredTick = pTick.iTickCount;
target.m_Tick = pTick;
target.m_vPos = vTransformed;
if (target.m_TargetType == ETargetType::PLAYER)
@ -510,7 +529,11 @@ int CAimbotHitscan::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* p
Vec3 vForward = {};
Math::AngleVectors(vAngles, &vForward);
if (SDK::VisPos(pLocal, target.m_pEntity, vEyePos, vTransformed))
bool bPeekCheck = flSpread ? SDK::VisPos(pLocal, target.m_pEntity, vPeekPos, vTransformed) : true;
if (bPeekCheck)
flSpread = 0.f; // only use with a single hitbox
if (SDK::VisPos(pLocal, target.m_pEntity, vEyePos, vTransformed) && bPeekCheck)
{
target.m_vAngleTo = vAngles;
if (RayToOBB(vEyePos, vForward, target.m_pEntity->m_vecOrigin(), vMins, vMaxs, transform)) // for the time being, no vischecks against other hitboxes

View File

@ -648,6 +648,7 @@ bool CAimbotMelee::RunSapper(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd
if (pCmd->buttons & IN_ATTACK)
{
G::IsAttacking = true;
target.m_vAngleTo = Aim(pCmd->viewangles, Math::CalcAngle(vLocalPos, target.m_vPos));
target.m_vAngleTo.x = pCmd->viewangles.x; // we don't need to care about pitch
Aim(pCmd, target.m_vAngleTo);

View File

@ -152,15 +152,16 @@ void CMenu::MenuAimbot()
{
if (Section("debug## aimbot"))
{
FSlider("hitscan peek", Vars::Aimbot::General::HitscanPeek, 0, 10);
FSlider("offset## nospread", Vars::Aimbot::General::NoSpreadOffset, -5.f, 5.f, 1.f, "%.1f", FSlider_Precision);
FSlider("average", Vars::Aimbot::General::NoSpreadAverage, 1, 100);
FSlider("average", Vars::Aimbot::General::NoSpreadAverage, 1, 25);
} EndSection();
}
if (Section("Backtrack"))
{
FToggle("Enabled", Vars::Backtrack::Enabled);
FToggle("Prefer on shot", Vars::Backtrack::PreferOnShot, FToggle_Middle);
FSlider("Fake latency", Vars::Backtrack::Latency, 0, F::Backtrack.flMaxUnlag * 1000, 5, "%d", FSlider_Clamp); // unreliable above 900
FSlider("Fake latency", Vars::Backtrack::Latency, 0, F::Backtrack.flMaxUnlag * 1000, 5, "%d", FSlider_Clamp); // unreliable above 1000 - ping probably
FSlider("Fake interp", Vars::Backtrack::Interp, 0, F::Backtrack.flMaxUnlag * 1000, 5, "%d", FSlider_Clamp);
FSlider("Window", Vars::Backtrack::Window, 1, 200, 5, "%d", FSlider_Clamp);
} EndSection();

View File

@ -512,6 +512,24 @@ void CMisc::AntiWarp(CTFPlayer* pLocal, CUserCmd* pCmd)
}
else
vVelocity = pLocal->m_vecVelocity();
/*
static bool bSet = false;
if (!G::AntiWarp)
{
bSet = false;
return;
}
if (!G::IsAttacking && !bSet)
{
bSet = true;
SDK::StopMovement(pLocal, pCmd);
}
else
pCmd->forwardmove = pCmd->sidemove = 0.f;
*/
}
void CMisc::LegJitter(CTFPlayer* pLocal, CUserCmd* pCmd, bool pSendPacket)

View File

@ -125,7 +125,21 @@ void CMovementSimulation::FillVelocities()
if (TIME_TO_TICKS(flSimTime - flOldSimTime) <= 0)
return;
mVelocities[iEntIndex].push_front({ vVelocity, flSimTime });
const VelocityData vRecord = {
vVelocity,
pEntity->IsOnGround(),
flSimTime
};
if (!mVelocities[iEntIndex].empty())
{
const VelocityData vLast = mVelocities[iEntIndex][0];
if (vRecord.m_bGrounded != vLast.m_bGrounded)
mVelocities[iEntIndex].clear();
}
mVelocities[iEntIndex].push_front(vRecord);
if (mVelocities[iEntIndex].size() > 66)
mVelocities[iEntIndex].pop_back();
@ -217,8 +231,8 @@ bool CMovementSimulation::Initialize(CBaseEntity* pEntity, PlayerStorage& player
break;
const auto& pRecord1 = mVelocityRecords[i], &pRecord2 = mVelocityRecords[i + 1];
const float flYaw1 = Math::VelocityToAngles(pRecord1.first).y, flYaw2 = Math::VelocityToAngles(pRecord2.first).y;
const float flTime1 = pRecord1.second, flTime2 = pRecord2.second;
const float flYaw1 = Math::VelocityToAngles(pRecord1.m_vVelocity).y, flYaw2 = Math::VelocityToAngles(pRecord2.m_vVelocity).y;
const float flTime1 = pRecord1.m_flSimTime, flTime2 = pRecord2.m_flSimTime;
float flYaw = (flYaw1 - flYaw2) / TIME_TO_TICKS(flTime1 - flTime2);
flYaw = fmodf(flYaw + 180.f, 360.f);
@ -283,14 +297,14 @@ bool CMovementSimulation::SetupMoveData(PlayerStorage& playerStorage)
return true;
}
bool CMovementSimulation::GetYawDifference(const std::deque<std::pair<Vec3, float>>& mVelocityRecords, size_t i, float* flYaw)
bool CMovementSimulation::GetYawDifference(const std::deque<VelocityData>& mVelocityRecords, size_t i, float* flYaw)
{
if (mVelocityRecords.size() <= i + 2)
return false;
const auto& pRecord1 = mVelocityRecords[i], &pRecord2 = mVelocityRecords[i + 1];
const float flYaw1 = Math::VelocityToAngles(pRecord1.first).y, flYaw2 = Math::VelocityToAngles(pRecord2.first).y;
const float flTime1 = pRecord1.second, flTime2 = pRecord2.second;
const float flYaw1 = Math::VelocityToAngles(pRecord1.m_vVelocity).y, flYaw2 = Math::VelocityToAngles(pRecord2.m_vVelocity).y;
const float flTime1 = pRecord1.m_flSimTime, flTime2 = pRecord2.m_flSimTime;
const int iTicks = std::max(TIME_TO_TICKS(flTime1 - flTime2), 1);
*flYaw = (flYaw1 - flYaw2) / iTicks;
@ -300,7 +314,7 @@ bool CMovementSimulation::GetYawDifference(const std::deque<std::pair<Vec3, floa
static int iSign = 0;
const int iLastSign = iSign;
const int iCurSign = iSign = *flYaw > 0 ? 1 : -1;
if (fabsf(*flYaw) < 640.f / pRecord1.first.Length2D() / iTicks) // dumb way to get straight bool
if (fabsf(*flYaw) < 200.f / pRecord1.m_vVelocity.Length2D() / iTicks) // dumb way to get straight bool
return false;
return !i || iLastSign == iCurSign ? true : false;

View File

@ -66,6 +66,13 @@ struct PlayerStorage
bool m_bInitFailed = false;
};
struct VelocityData
{
Vec3 m_vVelocity = {};
bool m_bGrounded = true;
float m_flSimTime = 0.f;
};
class CMovementSimulation
{
private:
@ -73,7 +80,7 @@ private:
void Reset(PlayerStorage& playerStorage);
bool SetupMoveData(PlayerStorage& playerStorage);
bool GetYawDifference(const std::deque<std::pair<Vec3, float>>& mPositionRecords, size_t i, float* flYaw);
bool GetYawDifference(const std::deque<VelocityData>& mPositionRecords, size_t i, float* flYaw);
float GetAverageYaw(const int iIndex, const int iSamples);
bool StrafePrediction(PlayerStorage& playerStorage, const int iSamples);
@ -81,7 +88,7 @@ private:
bool m_bOldFirstTimePredicted = false;
float m_flOldFrametime = 0.f;
std::unordered_map<int, std::deque<std::pair<Vec3, float>>> mVelocities;
std::unordered_map<int, std::deque<VelocityData>> mVelocities;
public:
void FillVelocities();

View File

@ -334,7 +334,7 @@ void CVisuals::DrawDebugInfo(CTFPlayer* pLocal)
Vec3 vVelocity = pLocal->m_vecVelocity();
H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, "Velocity: %.3f (%.3f, %.3f, %.3f)", vVelocity.Length(), vVelocity.x, vVelocity.y, vVelocity.z);
H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, std::format("Attacking: {}", G::IsAttacking).c_str());
H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, std::format("Attacking: {} ({}, {})", G::IsAttacking, G::CanPrimaryAttack, G::CanSecondaryAttack).c_str());
H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, "RoundState: %i", SDK::GetRoundState());

View File

@ -39,11 +39,11 @@ MAKE_HOOK(BaseClientDLL_FrameStageNotify, U::Memory.GetVFunc(I::BaseClientDLL, 3
H::Entities.Fill();
for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL))
{
G::VelocityMap[pEntity->entindex()] = { pEntity->m_vecOrigin(), pEntity->m_vecMaxs().z - pEntity->m_vecMins().z, pEntity->m_flSimulationTime() };
if (pEntity->entindex() == I::EngineClient->GetLocalPlayer())
continue; // local player managed in CPrediction_RunCommand
G::VelocityMap[pEntity->entindex()] = { pEntity->m_vecOrigin(), pEntity->m_vecMaxs().z - pEntity->m_vecMins().z, pEntity->m_flSimulationTime() };
static auto sv_maxusrcmdprocessticks = U::ConVars.FindVar("sv_maxusrcmdprocessticks");
const int iTicks = sv_maxusrcmdprocessticks ? sv_maxusrcmdprocessticks->GetInt() : 24;
if (auto iDifference = std::min(TIME_TO_TICKS(pEntity->m_flSimulationTime() - pEntity->m_flOldSimulationTime()), iTicks))

View File

@ -44,32 +44,51 @@ MAKE_HOOK(ClientModeShared_CreateMove, U::Memory.GetVFunc(I::ClientModeShared, 2
if (G::WeaponDefIndex != nOldDefIndex || !pWeapon->m_iClip1() || !pLocal->IsAlive() || pLocal->IsTaunting() || pLocal->IsBonked() || pLocal->IsAGhost() || pLocal->IsInBumperKart())
G::WaitForShift = 1;
bool bCanAttack = pLocal->CanAttack() && (pWeapon->m_iWeaponID() == TF_WEAPON_FLAME_BALL ? pLocal->m_flTankPressure() >= 100.f : true);
G::CanPrimaryAttack = bCanAttack && pWeapon->CanPrimaryAttack(pLocal);
G::CanSecondaryAttack = bCanAttack && pWeapon->CanSecondaryAttack(pLocal);
G::CanPrimaryAttack = G::CanSecondaryAttack = false;
bool bCanAttack = pLocal->CanAttack();
switch (SDK::GetRoundState())
{
case GR_STATE_BETWEEN_RNDS:
case GR_STATE_GAME_OVER:
if (pLocal->m_fFlags() & FL_FROZEN)
G::CanPrimaryAttack = G::CanSecondaryAttack = false;
bCanAttack = bCanAttack && !(pLocal->m_fFlags() & FL_FROZEN);
}
if (pWeapon->m_iSlot() != SLOT_MELEE)
if (bCanAttack)
{
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_FLAME_BALL:
G::CanPrimaryAttack = G::CanSecondaryAttack = pLocal->m_flTankPressure() >= 100.f;
break;
case TF_WEAPON_BUILDER:
G::CanPrimaryAttack = true;
break;
default:
G::CanPrimaryAttack = pWeapon->CanPrimaryAttack(pLocal);
G::CanSecondaryAttack = pWeapon->CanSecondaryAttack(pLocal);
if (pWeapon->m_iSlot() == SLOT_MELEE)
break;
if (pWeapon->IsInReload())
G::CanPrimaryAttack = pWeapon->HasPrimaryAmmoForShot();
if (pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN && pWeapon->As<CTFMinigun>()->m_iWeaponState() != AC_STATE_FIRING && pWeapon->As<CTFMinigun>()->m_iWeaponState() != AC_STATE_SPINNING)
G::CanPrimaryAttack = false;
if (pWeapon->m_iWeaponID() == TF_WEAPON_FLAREGUN_REVENGE && pCmd->buttons & IN_ATTACK2)
if (G::WeaponDefIndex != Soldier_m_TheBeggarsBazooka && pWeapon->m_iClip1() == 0)
G::CanPrimaryAttack = false;
if (pWeapon->m_bEnergyWeapon() && !pWeapon->m_flEnergy())
G::CanPrimaryAttack = false;
if (G::WeaponDefIndex != Soldier_m_TheBeggarsBazooka && pWeapon->m_iClip1() == 0)
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_MINIGUN:
if (pWeapon->As<CTFMinigun>()->m_iWeaponState() != AC_STATE_FIRING && pWeapon->As<CTFMinigun>()->m_iWeaponState() != AC_STATE_SPINNING)
G::CanPrimaryAttack = false;
break;
case TF_WEAPON_FLAREGUN_REVENGE:
if (pCmd->buttons & IN_ATTACK2)
G::CanPrimaryAttack = false;
}
}
}
G::IsAttacking = SDK::IsAttacking(pLocal, pWeapon, pCmd);

View File

@ -431,11 +431,9 @@ bool SDK::IsAttacking(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd*
return trace.DidHit() && !(trace.surface.flags & 0x0004) /*SURF_SKY*/;
}
case TF_WEAPON_MINIGUN:
{
return (pWeapon->As<CTFMinigun>()->m_iWeaponState() == AC_STATE_FIRING || pWeapon->As<CTFMinigun>()->m_iWeaponState() == AC_STATE_SPINNING) &&
pCmd->buttons & IN_ATTACK && G::CanPrimaryAttack;
}
}
return pCmd->buttons & IN_ATTACK && G::CanPrimaryAttack;
}
@ -469,7 +467,7 @@ bool SDK::StopMovement(CTFPlayer* pLocal, CUserCmd* pCmd)
if (!G::IsAttacking)
{
const float direction = Math::VelocityToAngles(pLocal->m_vecVelocity()).y;
pCmd->viewangles = { -90, direction, 0 };
pCmd->viewangles = { 90, direction, 0 };
pCmd->sidemove = 0; pCmd->forwardmove = 0;
return true;
}

View File

@ -119,6 +119,7 @@ namespace Vars
CVar(FOVCircle, true)
CVar(NoSpread, false)
CVar(HitscanPeek, 3, NOSAVE) // debug
CVar(NoSpreadOffset, 0.f, NOSAVE) // debug
CVar(NoSpreadAverage, 5, NOSAVE) // debug
SUBNAMESPACE_END(Global)