From abf1a0059103e511fb8ddde4e71ff9580b9bf4c5 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 16 Mar 2026 19:32:34 +0000 Subject: [PATCH] Apply a few minor fixes to flow aim evaluation (#36999) Contains: - A small bug fix from initial separation merge. Snap aim only applies this bonus when slider travel distance is passed, so it should be the same for flow. Cannot find any cases where values are affected, but in theory the only difference this can make is slider factor calculations. - Apply overlapping note factor to the acute bonus, so that direction changes that overlap are awarded less. A small speed multiplier increase is included to offset this - Move angular velocity calculation out of ODHO into the flow evaluator, and fix it referencing the wrong angle (2 objects back instead of the previous object) - 2 tiny code refactors --------- Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com> --- .../Evaluators/Aim/FlowAimEvaluator.cs | 18 ++++++++++++------ .../Preprocessing/OsuDifficultyHitObject.cs | 9 --------- .../Difficulty/Skills/Speed.cs | 2 +- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs index ccc4d219d5..d50e84f00b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs @@ -50,10 +50,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim flowDifficulty *= 1 + Math.Min(0.25, Math.Pow((Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) - Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) / 50, 4)); - if (osuCurrObj.AngularVelocity != null) + if (osuCurrObj.Angle != null && osuLastObj.Angle != null) { + double angleDifference = Math.Abs(osuCurrObj.Angle.Value - osuLastObj.Angle.Value); + double angleDifferenceAdjusted = Math.Sin(angleDifference / 2) * 180.0; + double angularVelocity = angleDifferenceAdjusted / (osuCurrObj.AdjustedDeltaTime * 0.1); + // Low angular velocity flow (angles are consistent) is easier to follow than erratic flow - flowDifficulty *= 0.8 + Math.Sqrt(osuCurrObj.AngularVelocity.Value / 270.0); + flowDifficulty *= 0.8 + Math.Sqrt(angularVelocity / 270.0); } // If all three notes are overlapping - don't reward bonuses as you don't have to do additional movement @@ -68,7 +72,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim overlappedNotesWeight = 1 - o1 * o2 * o3; } - if (osuCurrObj.Angle != null && osuLastObj.Angle != null) + if (osuCurrObj.Angle != null) { // Acute angles are also hard to flow // We square root velocity to make acute angle switches in streams aren't having difficulty higher than snap @@ -82,7 +86,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim if (withSliderTravelDistance) { currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime; - prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime; } // Scale with ratio of difference compared to 0.5 * max dist. @@ -92,10 +95,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators.Aim double overlapVelocityBuff = Math.Min(OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25 / Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), Math.Abs(prevVelocity - currVelocity)); - flowDifficulty += overlapVelocityBuff * distRatio * velocity_change_multiplier; + flowDifficulty += overlapVelocityBuff * + distRatio * + overlappedNotesWeight * + velocity_change_multiplier; } - if (osuCurrObj.BaseObject is Slider) + if (osuCurrObj.BaseObject is Slider && withSliderTravelDistance) { // Include slider velocity to make velocity more consistent with snap flowDifficulty += osuCurrObj.TravelDistance / osuCurrObj.TravelTime; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 68950829f3..221b2c6378 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -116,8 +116,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public double? Angle { get; private set; } - public double? AngularVelocity { get; private set; } - /// /// Angle of the vector created between current and current-1 /// normalised to consider symmetrical vectors in any axis to be the same angle. @@ -271,13 +269,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing NormalisedVectorAngle = Math.Atan2(Math.Abs(v.Y), Math.Abs(v.X)); Angle = Math.Min(angle, sliderAngle); - - if (lastLastDifficultyObject.Angle != null) - { - double angleDifference = Math.Abs(Angle.Value - lastLastDifficultyObject.Angle.Value); - double angleDifferenceAdjusted = Math.Sin(angleDifference / 2) * 180.0; - AngularVelocity = angleDifferenceAdjusted / (AdjustedDeltaTime * 0.1); - } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 2462186c78..cdd0118703 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : HarmonicSkill { - private double skillMultiplier => 1.15; + private double skillMultiplier => 1.16; private readonly List sliderStrains = new List();