diff --git a/AMBuilder b/AMBuilder index f9b6f51a9..70c426a61 100644 --- a/AMBuilder +++ b/AMBuilder @@ -122,6 +122,18 @@ for sdk_target in MMSPlugin.sdk_targets: mode_binary.compiler.cxxincludes += CXXINCLUDES + if mode_binary.compiler.target.platform == 'linux': + mode_binary.compiler.postlink += [ + os.path.join(sdk['path'], 'lib', 'linux64', 'mathlib.a'), + ] + mode_binary.sources += [ + os.path.join(sdk['path'], 'public', 'tier0', 'memoverride.cpp') + ] + elif mode_binary.compiler.target.platform == 'windows': + mode_binary.compiler.postlink += [ + os.path.join(sdk['path'], 'lib', 'public', 'win64', 'mathlib.lib'), + ] + mode_binary.sources += [ os.path.join(builder.sourcePath, 'src', 'utils', 'schema.cpp'), os.path.join(builder.sourcePath, 'src', 'kz', 'mode', 'kz_mode_ckz.cpp'), diff --git a/src/kz/jumpstats/kz_jumpstats.cpp b/src/kz/jumpstats/kz_jumpstats.cpp index 1dcc4f1bd..ac5f7b95b 100644 --- a/src/kz/jumpstats/kz_jumpstats.cpp +++ b/src/kz/jumpstats/kz_jumpstats.cpp @@ -9,6 +9,7 @@ #define JS_MAX_LADDERJUMP_OFFSET 2.0f #define JS_MAX_BHOP_GROUND_TIME 0.05f #define JS_MAX_DUCKBUG_RESET_TIME 0.05f +#define JS_MAX_NOCLIP_RESET_TIME 0.4f #define JS_MAX_WEIRDJUMP_FALL_OFFSET 64.0f #define JS_TOUCH_GRACE_PERIOD 0.04f #define JS_EPSILON 0.03125f @@ -573,7 +574,7 @@ void KZJumpstatsService::OnProcessMovement() if (this->jumps.Count() == 0) { this->AddJump(); - this->InvalidateJumpstats(); + this->InvalidateJumpstats("First jump"); return; } this->CheckValidMoveType(); @@ -589,7 +590,7 @@ void KZJumpstatsService::OnChangeMoveType(MoveType_t oldMoveType) else if (oldMoveType == MOVETYPE_WALK && this->player->GetPawn()->m_MoveType() == MOVETYPE_LADDER) { // Not really a valid jump for jumpstats purposes. - this->InvalidateJumpstats(); + this->InvalidateJumpstats("Invalid movetype change"); this->EndJump(); } } @@ -645,6 +646,7 @@ void KZJumpstatsService::UpdateJump() this->DetectEdgebug(); this->DetectInvalidCollisions(); this->DetectInvalidGains(); + this->DetectNoclip(); } void KZJumpstatsService::EndJump() @@ -668,7 +670,7 @@ void KZJumpstatsService::EndJump() void KZJumpstatsService::PrintJumpToChat(KZPlayer *target, Jump *jump) { const char *jumpColor = distanceTierColors[jump->GetJumpPlayer()->modeService->GetDistanceTier(jump->GetJumpType(), jump->GetDistance())]; - utils::CPrintChat(target->GetController(), "%s %s%s{grey}: %s%.1f {grey}| {olive}%i {grey}Strafes | {olive}%2.f%% {grey}Sync | {olive}%.2f {grey}Pre | {olive}%.2f {grey}Max\n\ + utils::CPrintChat(target->GetController(), "%s %s%s{grey}: %s%.1f {grey}| {olive}%i {grey}Strafes | {olive}%.0f%% {grey}Sync | {olive}%.2f {grey}Pre | {olive}%.2f {grey}Max\n\ {grey}BA {olive}%.0f%% {grey}| OL {olive}%.0f%% {grey}| DA {olive}%.0f%% {grey}| {olive}%.1f {grey}Deviation | {olive}%.1f {grey}Width | {olive}%.2f {grey}Height", KZ_CHAT_PREFIX, jumpColor, @@ -689,10 +691,16 @@ void KZJumpstatsService::PrintJumpToChat(KZPlayer *target, Jump *jump) void KZJumpstatsService::PrintJumpToConsole(KZPlayer *target, Jump *jump) { - utils::PrintConsole(target->GetController(), "%s jumped %.4f units with a %s", + char invalidateReason[256]{}; + if (jump->invalidateReason[0] != '\0') + { + V_snprintf(invalidateReason, sizeof(invalidateReason), "(%s)", jump->invalidateReason); + } + utils::PrintConsole(target->GetController(), "%s jumped %.4f units with a %s %s", jump->GetJumpPlayer()->GetController()->m_iszPlayerName(), jump->GetDistance(), - jumpTypeStr[jump->GetJumpType()]); + jumpTypeStr[jump->GetJumpType()], + invalidateReason); utils::PrintConsole(target->GetController(), "%s | %i Strafes | %.1f%% Sync | %.2f Pre | %.2f Max | %.0f%% BA | %.0f%% OL | %.0f%% DA | %.2f Height\n%.0f%% GainEff | %.3f Airpath | %.1f Deviation | %.1f Width | %.4f Airtime | %.1f Offset | %.2f/%.2f Crouched", jump->GetJumpPlayer()->modeService->GetModeShortName(), jump->strafes.Count(), @@ -755,11 +763,11 @@ void KZJumpstatsService::PrintJumpToConsole(KZPlayer *target, Jump *jump) angRatioString); } } -void KZJumpstatsService::InvalidateJumpstats() +void KZJumpstatsService::InvalidateJumpstats(const char *reason) { if (this->jumps.Count() > 0 && !this->jumps.Tail().AlreadyEnded()) { - this->jumps.Tail().Invalidate(); + this->jumps.Tail().Invalidate(reason); } } @@ -792,7 +800,15 @@ void KZJumpstatsService::CheckValidMoveType() // Invalidate jumpstats if movetype is invalid. if (this->player->GetPawn()->m_MoveType() != MOVETYPE_WALK && this->player->GetPawn()->m_MoveType() != MOVETYPE_LADDER) { - this->InvalidateJumpstats(); + this->InvalidateJumpstats("Invalid movetype"); + } +} + +void KZJumpstatsService::DetectNoclip() +{ + if (this->lastNoclipTime + JS_MAX_NOCLIP_RESET_TIME > g_pKZUtils->GetServerGlobals()->curtime) + { + this->InvalidateJumpstats("Just noclipped"); } } @@ -802,7 +818,7 @@ void KZJumpstatsService::DetectEdgebug() // If the player suddenly gain speed from negative speed, they probably edgebugged. if (this->player->moveDataPre.m_vecVelocity.z < 0.0f && this->player->currentMoveData->m_vecVelocity.z > this->player->moveDataPre.m_vecVelocity.z) { - this->InvalidateJumpstats(); + this->InvalidateJumpstats("Potential edgebug"); } } @@ -816,7 +832,7 @@ void KZJumpstatsService::DetectInvalidCollisions() // while other collisions do after a certain duration. if (this->jumps.Tail().touchDuration > JS_TOUCH_GRACE_PERIOD) { - this->InvalidateJumpstats(); + this->InvalidateJumpstats("Invalid collisions"); } if (this->player->moveDataPre.m_vecVelocity.z > 0.0f) { @@ -837,7 +853,7 @@ void KZJumpstatsService::DetectInvalidGains() if (actualSpeed - speed > JS_SPEED_MODIFICATION_TOLERANCE && actualSpeed > JS_EPSILON) { - this->InvalidateJumpstats(); + this->InvalidateJumpstats("Invalid gains"); } } @@ -845,7 +861,7 @@ void KZJumpstatsService::DetectExternalModifications() { if ((this->player->currentMoveData->m_vecAbsOrigin - this->player->moveDataPost.m_vecAbsOrigin).LengthSqr() > JS_TELEPORT_DISTANCE_SQUARED) { - this->InvalidateJumpstats(); + this->InvalidateJumpstats("Externally modified"); } } diff --git a/src/kz/jumpstats/kz_jumpstats.h b/src/kz/jumpstats/kz_jumpstats.h index fe0b9f591..3ad5e94b6 100644 --- a/src/kz/jumpstats/kz_jumpstats.h +++ b/src/kz/jumpstats/kz_jumpstats.h @@ -166,6 +166,7 @@ class Jump public: CCopyableUtlVector strafes; f32 touchDuration{}; + char invalidateReason[256]{}; public: Jump() {} @@ -177,7 +178,7 @@ class Jump void UpdateAACallPost(Vector wishdir, f32 wishspeed, f32 accel); void Update(); void End(); - void Invalidate() { this->valid = false; }; + void Invalidate(const char *reason) { this->valid = false; V_strncpy(this->invalidateReason, reason, sizeof(this->invalidateReason)); } void MarkHitHead() { this->hitHead = true; }; Strafe *GetCurrentStrafe(); @@ -221,7 +222,6 @@ class KZJumpstatsService : public KZBaseService f32 lastGroundSpeedCappedTime{}; f32 lastMovementProcessedTime{}; f32 tpmPreSpeed{}; - public: void OnProcessMovement(); void OnChangeMoveType(MoveType_t oldMoveType); @@ -239,13 +239,14 @@ class KZJumpstatsService : public KZBaseService void AddJump(); void UpdateJump(); void EndJump(); - void InvalidateJumpstats(); + void InvalidateJumpstats(const char *reason = NULL); void OnAirAccelerate(); void OnAirAcceleratePost(Vector wishdir, f32 wishspeed, f32 accel); void UpdateAACallPost(); void ToggleJSAlways(); void CheckValidMoveType(); + void DetectNoclip(); void DetectEdgebug(); void DetectInvalidCollisions(); void DetectInvalidGains(); diff --git a/src/kz/kz_player.cpp b/src/kz/kz_player.cpp index 518cf0a59..eedf43967 100644 --- a/src/kz/kz_player.cpp +++ b/src/kz/kz_player.cpp @@ -270,7 +270,7 @@ void KZPlayer::OnChangeMoveType(MoveType_t oldMoveType) void KZPlayer::OnTeleport(const Vector *origin, const QAngle *angles, const Vector *velocity) { - this->jumpstatsService->InvalidateJumpstats(); + this->jumpstatsService->InvalidateJumpstats("Teleported"); } void KZPlayer::EnableGodMode() diff --git a/src/kz/mode/kz_mode_ckz.cpp b/src/kz/mode/kz_mode_ckz.cpp index 81b91f9f7..afd9c15e4 100644 --- a/src/kz/mode/kz_mode_ckz.cpp +++ b/src/kz/mode/kz_mode_ckz.cpp @@ -102,9 +102,27 @@ const char *KZClassicModePlugin::GetURL() /* Actual mode stuff. */ - -#define DUCK_SPEED_NORMAL 8.0 -#define DUCK_SPEED_MINIMUM 6.0234375 // Equal to if you just ducked/unducked for the first time in a while +#define SPEED_NORMAL 250.0f + +#define PS_SPEED_MAX 26.0f +#define PS_MIN_REWARD_RATE 7.0f // Minimum computed turn rate for any prestrafe reward +#define PS_MAX_REWARD_RATE 16.0f // Ideal computed turn rate for maximum prestrafe reward +#define PS_MAX_PS_TIME 0.55f // Time to reach maximum prestrafe speed with optimal turning +#define PS_TURN_RATE_WINDOW 0.02f // Turn rate will be computed over this amount of time +#define PS_DECREMENT_RATIO 3.0f // Prestrafe will lose this fast compared to gaining +#define PS_RATIO_TO_SPEED 0.5f +// Prestrafe ratio will be not go down after landing for this amount of time - helps with small movements after landing +// Ideally should be much higher than the perf window! +#define PS_LANDING_GRACE_PERIOD 0.25f + +#define BH_PERF_WINDOW 0.02f // Any jump performed after landing will be a perf for this much time +#define BH_BASE_MULTIPLIER 51.5f // Multiplier for how much speed would a perf gain in ideal scenario +#define BH_LANDING_DECREMENT_MULTIPLIER 75.0f // How much would a non real perf impact the takeoff speed +// Magic number so that landing speed at max ground prestrafe speed would result in the same takeoff velocity +#define BH_NORMALIZE_FACTOR (BH_BASE_MULTIPLIER * log(SPEED_NORMAL + PS_SPEED_MAX) - (SPEED_NORMAL + PS_SPEED_MAX)) + +#define DUCK_SPEED_NORMAL 8.0f +#define DUCK_SPEED_MINIMUM 6.0234375f // Equal to if you just ducked/unducked for the first time in a while const char *KZClassicModeService::GetModeName() { @@ -138,8 +156,7 @@ DistanceTier KZClassicModeService::GetDistanceTier(JumpType jumpType, f32 distan f32 KZClassicModeService::GetPlayerMaxSpeed() { - // TODO: prestrafe - return 276.0f; + return SPEED_NORMAL + this->GetPrestrafeGain(); } const char **KZClassicModeService::GetModeConVarValues() @@ -189,15 +206,17 @@ void KZClassicModeService::OnStopTouchGround() f32 timeOnGround = this->player->takeoffTime - this->player->landingTime; // Perf - if (timeOnGround <= 0.02) + if (timeOnGround <= BH_PERF_WINDOW) { // Perf speed Vector2D landingVelocity2D(this->player->landingVelocity.x, this->player->landingVelocity.y); landingVelocity2D.NormalizeInPlace(); - float newSpeed = this->player->landingVelocity.Length2D(); - if (newSpeed > 276.0f) + float newSpeed = MAX(this->player->landingVelocity.Length2D(), this->player->takeoffVelocity.Length2D()); + if (newSpeed > SPEED_NORMAL + this->GetPrestrafeGain()) { - newSpeed = MIN(newSpeed, (52 - timeOnGround * 128) * log(newSpeed) - 5.020043); + newSpeed = MIN(newSpeed, (BH_BASE_MULTIPLIER - timeOnGround * BH_LANDING_DECREMENT_MULTIPLIER) * log(newSpeed) - BH_NORMALIZE_FACTOR); + // Make sure it doesn't go lower than the ground speed. + newSpeed = MAX(newSpeed, SPEED_NORMAL + this->GetPrestrafeGain()); } velocity.x = newSpeed * landingVelocity2D.x; velocity.y = newSpeed * landingVelocity2D.y; @@ -215,15 +234,10 @@ void KZClassicModeService::OnStopTouchGround() void KZClassicModeService::OnProcessUsercmds(void *cmds, int numcmds) { -#ifdef _WIN32 - constexpr u32 offset = 0x90; -#else - constexpr u32 offset = 0x88; -#endif this->lastDesiredViewAngleTime = g_pKZUtils->GetServerGlobals()->curtime; for (i32 i = 0; i < numcmds; i++) { - auto address = reinterpret_cast(cmds) + i * offset; + auto address = reinterpret_cast(cmds) + i * offsets::UsercmdOffset; CSGOUserCmdPB *usercmdsPtr = reinterpret_cast(address); this->lastDesiredViewAngle = { usercmdsPtr->base().viewangles().x(), usercmdsPtr->base().viewangles().y(), usercmdsPtr->base().viewangles().z() }; for (i32 j = 0; j < usercmdsPtr->mutable_base()->subtick_moves_size(); j++) @@ -252,14 +266,16 @@ void KZClassicModeService::OnProcessUsercmds(void *cmds, int numcmds) this->InsertSubtickTiming(g_pKZUtils->GetServerGlobals()->tickcount * 0.015625 - 0.0078125, false); } -void KZClassicModeService::OnPlayerMove() +void KZClassicModeService::OnProcessMovement() { this->RemoveCrouchJumpBind(); this->ReduceDuckSlowdown(); this->InterpolateViewAngles(); + this->UpdateAngleHistory(); + this->CalcPrestrafe(); } -void KZClassicModeService::OnPostPlayerMovePost() +void KZClassicModeService::OnProcessMovementPost() { this->InsertSubtickTiming(g_pKZUtils->GetServerGlobals()->tickcount * 0.015625 + 0.0078125, true); this->RestoreInterpolatedViewAngles(); @@ -337,7 +353,7 @@ void KZClassicModeService::RestoreInterpolatedViewAngles() void KZClassicModeService::RemoveCrouchJumpBind() { this->forcedUnduck = false; - if (this->player->GetPawn()->m_fFlags & FL_ONGROUND && !this->oldDuckPressed && !this->player->GetMoveServices()->m_bOldJumpPressed) + if (this->player->GetPawn()->m_fFlags & FL_ONGROUND && !this->oldDuckPressed && !this->player->GetMoveServices()->m_bOldJumpPressed && this->player->IsButtonDown(IN_JUMP)) { this->player->GetMoveServices()->m_nButtons()->m_pButtonStates[0] &= ~IN_DUCK; this->forcedUnduck = true; @@ -354,4 +370,127 @@ void KZClassicModeService::ReduceDuckSlowdown() { this->player->GetMoveServices()->m_flDuckSpeed = DUCK_SPEED_MINIMUM; } +} + +void KZClassicModeService::UpdateAngleHistory() +{ + CMoveData* mv = this->player->currentMoveData; + u32 oldEntries = 0; + FOR_EACH_VEC(this->angleHistory, i) + { + if (this->angleHistory[i].when + PS_TURN_RATE_WINDOW < g_pKZUtils->GetServerGlobals()->curtime) + { + oldEntries++; + continue; + } + break; + } + this->angleHistory.RemoveMultipleFromHead(oldEntries); + if ((this->player->GetPawn()->m_fFlags & FL_ONGROUND) == 0) + return; + + AngleHistory *angHist = this->angleHistory.AddToTailGetPtr(); + angHist->when = g_pKZUtils->GetServerGlobals()->curtime; + angHist->duration = g_pKZUtils->GetServerGlobals()->frametime; + + // Not turning if velocity is null. + if (mv->m_vecVelocity.Length2D() == 0) + { + angHist->rate = 0; + return; + } + + // Copying from WalkMove + Vector forward, right, up; + AngleVectors(mv->m_vecViewAngles, &forward, &right, &up); + + f32 fmove = mv->m_flForwardMove; + f32 smove = -mv->m_flSideMove; + + if (forward[2] != 0) + { + forward[2] = 0; + VectorNormalize(forward); + } + + if (right[2] != 0) + { + right[2] = 0; + VectorNormalize(right); + } + + Vector wishdir; + for (int i = 0; i < 2; i++) + wishdir[i] = forward[i] * fmove + right[i] * smove; + wishdir[2] = 0; + + VectorNormalize(wishdir); + + if (wishdir.Length() == 0) + { + angHist->rate = 0; + return; + } + + Vector velocity = mv->m_vecVelocity; + velocity[2] = 0; + VectorNormalize(velocity); + QAngle accelAngle; + QAngle velAngle; + VectorAngles(wishdir, accelAngle); + VectorAngles(velocity, velAngle); + accelAngle.y = g_pKZUtils->NormalizeDeg(accelAngle.y); + velAngle.y = g_pKZUtils->NormalizeDeg(velAngle.y); + angHist->rate = g_pKZUtils->GetAngleDifference(velAngle.y, accelAngle.y, 180.0, true); +} + +void KZClassicModeService::CalcPrestrafe() +{ + f32 totalDuration = 0; + f32 sumWeightedAngles = 0; + FOR_EACH_VEC(this->angleHistory, i) + { + sumWeightedAngles += this->angleHistory[i].rate * this->angleHistory[i].duration; + totalDuration += this->angleHistory[i].duration; + } + f32 averageRate; + if (totalDuration == 0) averageRate = 0; + else averageRate = sumWeightedAngles / totalDuration; + + f32 rewardRate = Clamp(fabs(averageRate) / PS_MAX_REWARD_RATE, 0.0f, 1.0f) * g_pKZUtils->GetServerGlobals()->frametime; + f32 punishRate = g_pKZUtils->GetServerGlobals()->frametime * PS_DECREMENT_RATIO; + + if (this->player->GetPawn()->m_fFlags & FL_ONGROUND && this->player->landingTime + PS_LANDING_GRACE_PERIOD < g_pKZUtils->GetServerGlobals()->curtime) + { + // Prevent instant full pre from crouched prestrafe. + Vector velocity; + this->player->GetVelocity(&velocity); + + f32 currentPreRatio; + if (velocity.Length2D() <= 0.0f) currentPreRatio = 0.0f; + else currentPreRatio = pow(this->bonusSpeed / PS_SPEED_MAX * SPEED_NORMAL / velocity.Length2D(), 1 / PS_RATIO_TO_SPEED) * PS_MAX_PS_TIME; + + + this->leftPreRatio = MIN(this->leftPreRatio, currentPreRatio); + this->rightPreRatio = MIN(this->rightPreRatio, currentPreRatio); + + this->leftPreRatio += averageRate > PS_MIN_REWARD_RATE ? rewardRate : -punishRate; + this->rightPreRatio += averageRate < -PS_MIN_REWARD_RATE ? rewardRate : -punishRate; + this->leftPreRatio = Clamp(leftPreRatio, 0.0f, PS_MAX_PS_TIME); + this->rightPreRatio = Clamp(rightPreRatio, 0.0f, PS_MAX_PS_TIME); + this->bonusSpeed = this->GetPrestrafeGain() / SPEED_NORMAL * velocity.Length2D(); + } + else + { + rewardRate = g_pKZUtils->GetServerGlobals()->frametime; + // Raise both left and right pre to the same value as the player is in the air. + if (this->leftPreRatio < this->rightPreRatio) + this->leftPreRatio = Clamp(this->leftPreRatio + rewardRate, 0.0f, rightPreRatio); + else this->rightPreRatio = Clamp(this->rightPreRatio + rewardRate, 0.0f, leftPreRatio); + } +} + +f32 KZClassicModeService::GetPrestrafeGain() +{ + return PS_SPEED_MAX * pow(MAX(this->leftPreRatio, this->rightPreRatio) / PS_MAX_PS_TIME, PS_RATIO_TO_SPEED); } \ No newline at end of file diff --git a/src/kz/mode/kz_mode_ckz.h b/src/kz/mode/kz_mode_ckz.h index 0a94e0c0b..99c9ca9e8 100644 --- a/src/kz/mode/kz_mode_ckz.h +++ b/src/kz/mode/kz_mode_ckz.h @@ -76,7 +76,18 @@ class KZClassicModeService : public KZModeService f32 lastJumpReleaseTime{}; bool oldDuckPressed{}; bool forcedUnduck{}; - + + struct AngleHistory + { + f32 rate; + f32 when; + f32 duration; + }; + CUtlVector angleHistory; + f32 leftPreRatio{}; + f32 rightPreRatio{}; + f32 bonusSpeed{}; + f32 maxPre{}; public: virtual const char *GetModeName() override; virtual const char *GetModeShortName() override; @@ -85,10 +96,10 @@ class KZClassicModeService : public KZModeService virtual f32 GetPlayerMaxSpeed() override; virtual void OnProcessUsercmds(void *, int) override; - virtual void OnPlayerMove() override; + virtual void OnProcessMovement() override; + virtual void OnProcessMovementPost() override; virtual void OnJump() override; virtual void OnJumpPost() override; - virtual void OnPostPlayerMovePost() override; virtual void OnStopTouchGround() override; // Insert subtick timing to be called later. @@ -100,6 +111,10 @@ class KZClassicModeService : public KZModeService void InterpolateViewAngles(); void RestoreInterpolatedViewAngles(); + void UpdateAngleHistory(); + void CalcPrestrafe(); + f32 GetPrestrafeGain(); + void RemoveCrouchJumpBind(); /* Ported from DanZay's SimpleKZ: diff --git a/src/movement/datatypes.h b/src/movement/datatypes.h index 96ecff2a7..63fdfd053 100644 --- a/src/movement/datatypes.h +++ b/src/movement/datatypes.h @@ -61,7 +61,7 @@ class CMoveData QAngle m_vecViewAngles; // 0x14 Vector m_vecLastMovementImpulses; float m_flForwardMove; // 0x20 - float m_flSideMove; // 0x24 + float m_flSideMove; // 0x24 Warning! Flipped compared to CS:GO, moving right gives negative value float m_flUpMove; // 0x28 float m_flSubtickFraction; // 0x38 Vector m_vecVelocity; // 0x3c diff --git a/src/movement/mv_player.cpp b/src/movement/mv_player.cpp index 6d4927031..abc5426af 100644 --- a/src/movement/mv_player.cpp +++ b/src/movement/mv_player.cpp @@ -141,7 +141,15 @@ void MovementPlayer::SetAngles(const QAngle &angles) TurnState MovementPlayer::GetTurning() { - QAngle currentAngle = this->moveDataPre.m_vecViewAngles; + QAngle currentAngle; + if (this->processingMovement && this->currentMoveData) + { + currentAngle = this->currentMoveData->m_vecViewAngles; + } + else + { + currentAngle = this->moveDataPre.m_vecViewAngles; + } bool turning = this->oldAngles.y != currentAngle.y; if (!turning) return TURN_NONE; if (currentAngle.y < this->oldAngles.y - 180 diff --git a/src/utils/addresses.h b/src/utils/addresses.h index 2e5acf058..9ead81dd9 100644 --- a/src/utils/addresses.h +++ b/src/utils/addresses.h @@ -47,6 +47,8 @@ namespace offsets // Check sv_fullupdate inline constexpr int ClientOffset = 0x260; inline constexpr int ACKOffset = 0x134; + // Check ProcessUsercmds + inline constexpr int UsercmdOffset = 0x90; #else inline constexpr int GameEntitySystem = 0x50; inline constexpr int IsEntityPawn = 152; @@ -58,6 +60,7 @@ namespace offsets inline constexpr int Respawn = 327; inline constexpr int ClientOffset = 0x270; inline constexpr int ACKOffset = 0x144; + inline constexpr int UsercmdOffset = 0x88; #endif } diff --git a/src/utils/interfaces.h b/src/utils/interfaces.h index 7b132d16a..c1ab1f830 100644 --- a/src/utils/interfaces.h +++ b/src/utils/interfaces.h @@ -49,8 +49,7 @@ class KZUtils virtual f32 NormalizeDeg(f32 a); // Gets the difference in angle between 2 angles. // c can be PI (for radians) or 180.0 (for degrees); - virtual f32 GetAngleDifference(const f32 x, const f32 y, const f32 c); - + virtual f32 GetAngleDifference(const f32 source, const f32 target, const f32 c, bool relative = false); }; extern KZUtils *g_pKZUtils; \ No newline at end of file diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index d4b3c8565..daba45262 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -294,9 +294,11 @@ f32 utils::NormalizeDeg(f32 a) return a; } -f32 utils::GetAngleDifference(const f32 x, const f32 y, const f32 c) +f32 utils::GetAngleDifference(const f32 source, const f32 target, const f32 c, bool relative) { - return fmod(fabs(x - y) + c, 2 * c) - c; + if (relative) + return fmod((fmod(target - source, 2 * c) + 3 * c), 2 * c) - c; + return fmod(fabs(target - source) + c, 2 * c) - c; } void utils::SendConVarValue(CPlayerSlot slot, ConVar *conVar, const char *value) diff --git a/src/utils/utils.h b/src/utils/utils.h index fac0e560b..c9c6fbb34 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -51,7 +51,7 @@ namespace utils f32 NormalizeDeg(f32 a); // Gets the difference in angle between 2 angles. // c can be PI (for radians) or 180.0 (for degrees); - f32 GetAngleDifference(const f32 x, const f32 y, const f32 c); + f32 GetAngleDifference(const f32 x, const f32 y, const f32 c, bool relative = false); // Print functions void PrintConsole(CBaseEntity2 *entity, const char *format, ...); diff --git a/src/utils/utils_interface.cpp b/src/utils/utils_interface.cpp index b3f299437..0050aac3e 100644 --- a/src/utils/utils_interface.cpp +++ b/src/utils/utils_interface.cpp @@ -78,7 +78,7 @@ f32 KZUtils::NormalizeDeg(f32 a) return utils::NormalizeDeg(a); } -f32 KZUtils::GetAngleDifference(const f32 x, const f32 y, const f32 c) +f32 KZUtils::GetAngleDifference(const f32 source, const f32 target, const f32 c, bool relative) { - return utils::GetAngleDifference(x, y, c); + return utils::GetAngleDifference(source, target, c, relative); }