From bb21dd0a72d153ee611f6c566bc1f4e1296e418c Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 28 Nov 2024 00:12:09 +0500 Subject: [PATCH 01/13] Simplify osu! high-bpm acute angle jumps bonus --- .../Difficulty/Evaluators/AimEvaluator.cs | 22 +++++++------------ .../Utils/DifficultyCalculationUtils.cs | 13 +++++++++++ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 9816f6d0a412..db2f5e666f9d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; - private const double acute_angle_multiplier = 1.95; + private const double acute_angle_multiplier = 2.5; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; @@ -34,7 +34,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with var osuLastObj = (OsuDifficultyHitObject)current.Previous(0); var osuLastLastObj = (OsuDifficultyHitObject)current.Previous(1); - const int radius = OsuDifficultyHitObject.NORMALISED_RADIUS; const int diameter = OsuDifficultyHitObject.NORMALISED_DIAMETER; // Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle. @@ -79,22 +78,17 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double angleBonus = Math.Min(currVelocity, prevVelocity); wideAngleBonus = calcWideAngleBonus(currAngle); - acuteAngleBonus = calcAcuteAngleBonus(currAngle); - - if (DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.StrainTime, 2) < 300) // Only buff deltaTime exceeding 300 bpm 1/2. - acuteAngleBonus = 0; - else - { - acuteAngleBonus *= calcAcuteAngleBonus(lastAngle) // Multiply by previous angle, we don't want to buff unless this is a wiggle type pattern. - * Math.Min(angleBonus, diameter * 1.25 / osuCurrObj.StrainTime) // The maximum velocity we buff is equal to 125 / strainTime - * Math.Pow(Math.Sin(Math.PI / 2 * Math.Min(1, (100 - osuCurrObj.StrainTime) / 25)), 2) // scale buff from 150 bpm 1/4 to 200 bpm 1/4 - * Math.Pow(Math.Sin(Math.PI / 2 * (Math.Clamp(osuCurrObj.LazyJumpDistance, radius, diameter) - radius) / radius), 2); // Buff distance exceeding radius up to diameter. - } + + // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter + acuteAngleBonus = calcAcuteAngleBonus(currAngle) * + angleBonus * + DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.StrainTime, 2), 300, 400) * + DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); // Penalize wide angles if they're repeated, reducing the penalty as the lastAngle gets more acute. wideAngleBonus *= angleBonus * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); // Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse. - acuteAngleBonus *= 0.5 + 0.5 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3))); + acuteAngleBonus *= 1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3)); } } diff --git a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs index b9efcd683d1c..2f37dd53f79b 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs @@ -46,5 +46,18 @@ public static double MillisecondsToBPM(double ms, int delimiter = 4) /// Exponent /// The output of logistic function public static double Logistic(double exponent, double maxValue = 1) => maxValue / (1 + Math.Exp(exponent)); + + /// + /// Smootherstep function (https://en.wikipedia.org/wiki/Smoothstep#Variations) + /// + /// Value to calculate the function for + /// Value at which function returns 0 + /// Value at which function returns 1 + public static double Smootherstep(double x, double start, double end) + { + x = Math.Clamp((x - start) / (end - start), 0.0, 1.0); + + return x * x * x * (x * (6.0 * x - 15.0) + 10.0); + } } } From d58be00a6ecab64ab3ab832f3f041932fea5dea0 Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 28 Nov 2024 01:42:05 +0500 Subject: [PATCH 02/13] Add aim wiggle bonus --- .../Difficulty/Evaluators/AimEvaluator.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index db2f5e666f9d..318904a4e28c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Utils; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; @@ -34,6 +35,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with var osuLastObj = (OsuDifficultyHitObject)current.Previous(0); var osuLastLastObj = (OsuDifficultyHitObject)current.Previous(1); + const int radius = OsuDifficultyHitObject.NORMALISED_RADIUS; const int diameter = OsuDifficultyHitObject.NORMALISED_DIAMETER; // Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle. @@ -63,6 +65,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double acuteAngleBonus = 0; double sliderBonus = 0; double velocityChangeBonus = 0; + double wiggleBonus = 0; double aimStrain = currVelocity; // Start strain with regular velocity. @@ -89,6 +92,12 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus *= angleBonus * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); // Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse. acuteAngleBonus *= 1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3)); + + wiggleBonus = angleBonus + * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter * 2, diameter) + * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, radius, diameter) + * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) + * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); } } @@ -116,6 +125,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime; } + aimStrain += wiggleBonus * 1.1; // Add in acute angle bonus or wide angle bonus + velocity change bonus, whichever is larger. aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier); From bcebe9662cfcb7a72805e48712525ef54ec9820e Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 28 Nov 2024 02:54:07 +0500 Subject: [PATCH 03/13] Add hitwindow-based aim velocity decrease --- .../Difficulty/Evaluators/AimEvaluator.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 318904a4e28c..96872568fc88 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -38,9 +38,15 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with const int radius = OsuDifficultyHitObject.NORMALISED_RADIUS; const int diameter = OsuDifficultyHitObject.NORMALISED_DIAMETER; + // We take only half of the hitwindow since hitting an object earlier is actually harder + double hitWindow = ((OsuDifficultyHitObject)current).HitWindowGreat * 0.5; + // Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle. double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.StrainTime; + // Calculate velocity with hitwindow leeway added to the strain time + double currHitWindowPenalizedVelocity = osuCurrObj.LazyJumpDistance / (osuCurrObj.StrainTime + hitWindow); + // But if the last object is a slider, then we extend the travel velocity through the slider into the current object. if (osuLastObj.BaseObject is Slider && withSliderTravelDistance) { @@ -52,6 +58,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // As above, do the same for the previous hitobject. double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.StrainTime; + double prevHitWindowPenalizedVelocity = osuLastObj.LazyJumpDistance / (osuCurrObj.StrainTime + hitWindow); if (osuLastLastObj.BaseObject is Slider && withSliderTravelDistance) { @@ -78,7 +85,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double lastLastAngle = osuLastLastObj.Angle.Value; // Rewarding angles, take the smaller velocity as base. - double angleBonus = Math.Min(currVelocity, prevVelocity); + // This includes hitwindow-penalized velocity since you can always hit one object earlier and another later withing the bounds of the 300 hitwindow + double angleBonus = Math.Min(Math.Min(currHitWindowPenalizedVelocity, prevHitWindowPenalizedVelocity), Math.Min(currVelocity, prevVelocity)); wideAngleBonus = calcWideAngleBonus(currAngle); From 852265cb0cd8dc639a58187534bb08de89ed1ddc Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 28 Nov 2024 03:07:37 +0500 Subject: [PATCH 04/13] Revert "Add hitwindow-based aim velocity decrease" This reverts commit bcebe9662cfcb7a72805e48712525ef54ec9820e. --- .../Difficulty/Evaluators/AimEvaluator.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 96872568fc88..318904a4e28c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -38,15 +38,9 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with const int radius = OsuDifficultyHitObject.NORMALISED_RADIUS; const int diameter = OsuDifficultyHitObject.NORMALISED_DIAMETER; - // We take only half of the hitwindow since hitting an object earlier is actually harder - double hitWindow = ((OsuDifficultyHitObject)current).HitWindowGreat * 0.5; - // Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle. double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.StrainTime; - // Calculate velocity with hitwindow leeway added to the strain time - double currHitWindowPenalizedVelocity = osuCurrObj.LazyJumpDistance / (osuCurrObj.StrainTime + hitWindow); - // But if the last object is a slider, then we extend the travel velocity through the slider into the current object. if (osuLastObj.BaseObject is Slider && withSliderTravelDistance) { @@ -58,7 +52,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // As above, do the same for the previous hitobject. double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.StrainTime; - double prevHitWindowPenalizedVelocity = osuLastObj.LazyJumpDistance / (osuCurrObj.StrainTime + hitWindow); if (osuLastLastObj.BaseObject is Slider && withSliderTravelDistance) { @@ -85,8 +78,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double lastLastAngle = osuLastLastObj.Angle.Value; // Rewarding angles, take the smaller velocity as base. - // This includes hitwindow-penalized velocity since you can always hit one object earlier and another later withing the bounds of the 300 hitwindow - double angleBonus = Math.Min(Math.Min(currHitWindowPenalizedVelocity, prevHitWindowPenalizedVelocity), Math.Min(currVelocity, prevVelocity)); + double angleBonus = Math.Min(currVelocity, prevVelocity); wideAngleBonus = calcWideAngleBonus(currAngle); From 8b7d98b11330fde26bb991aed407ef7786bee37c Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 28 Nov 2024 03:19:41 +0500 Subject: [PATCH 05/13] Move wiggle multiplier to a const, slightly decrease acute bonus multiplier --- .../Difficulty/Evaluators/AimEvaluator.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 318904a4e28c..81df315dcd5b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Utils; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; @@ -13,9 +12,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; - private const double acute_angle_multiplier = 2.5; + private const double acute_angle_multiplier = 2.45; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; + private const double wiggle_multiplier = 1.1; /// /// Evaluates the difficulty of aiming the current object, based on: @@ -125,7 +125,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime; } - aimStrain += wiggleBonus * 1.1; + aimStrain += wiggleBonus * wiggle_multiplier; + // Add in acute angle bonus or wide angle bonus + velocity change bonus, whichever is larger. aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier); From a358cdf469f59d3cc6850f81d29a6d1af2df150b Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 28 Nov 2024 16:53:20 +0500 Subject: [PATCH 06/13] Make sure the previous object in the wiggle bonus is also part of the wiggle --- .../Difficulty/Evaluators/AimEvaluator.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 81df315dcd5b..54f533f31905 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -15,7 +15,7 @@ public static class AimEvaluator private const double acute_angle_multiplier = 2.45; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; - private const double wiggle_multiplier = 1.1; + private const double wiggle_multiplier = 1.5; /// /// Evaluates the difficulty of aiming the current object, based on: @@ -93,10 +93,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse. acuteAngleBonus *= 1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3)); + // Apply wiggle bonus for jumps that are [radius, 2*diameter] in distance and with < 110 angle wiggleBonus = angleBonus - * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter * 2, diameter) * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, radius, diameter) + * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter * 2, diameter) * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) + * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, radius, diameter) + * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, diameter * 2, diameter) * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); } } From 0045c838de36a1f722381baeb2fb6639c89de033 Mon Sep 17 00:00:00 2001 From: StanR Date: Fri, 29 Nov 2024 03:15:02 +0500 Subject: [PATCH 07/13] Scale the wiggle bonus multiplayer down --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 54f533f31905..0b44afb3bbc3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -15,7 +15,7 @@ public static class AimEvaluator private const double acute_angle_multiplier = 2.45; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; - private const double wiggle_multiplier = 1.5; + private const double wiggle_multiplier = 1.1; /// /// Evaluates the difficulty of aiming the current object, based on: From 38754c62033ed21b4c78447e091e10e4954ba41e Mon Sep 17 00:00:00 2001 From: StanR Date: Fri, 29 Nov 2024 03:21:55 +0500 Subject: [PATCH 08/13] Increase the acute angle jump bonus multiplier --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 0b44afb3bbc3..27b34a022f67 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; - private const double acute_angle_multiplier = 2.45; + private const double acute_angle_multiplier = 2.5; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; private const double wiggle_multiplier = 1.1; From e91c3707903cc40ba147baa53f3467851d9e50b5 Mon Sep 17 00:00:00 2001 From: StanR Date: Tue, 10 Dec 2024 15:12:34 +0500 Subject: [PATCH 09/13] Make wiggle bonus only apply on >150 bpm streams, make repetitive angle penalty --- .../Difficulty/Evaluators/AimEvaluator.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 27b34a022f67..e079a3eee3de 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -12,10 +12,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; - private const double acute_angle_multiplier = 2.5; + private const double acute_angle_multiplier = 2.35; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; - private const double wiggle_multiplier = 1.1; + private const double wiggle_multiplier = 1.2; /// /// Evaluates the difficulty of aiming the current object, based on: @@ -91,15 +91,16 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Penalize wide angles if they're repeated, reducing the penalty as the lastAngle gets more acute. wideAngleBonus *= angleBonus * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); // Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse. - acuteAngleBonus *= 1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3)); + acuteAngleBonus *= 0.03 + 0.97 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3))); - // Apply wiggle bonus for jumps that are [radius, 2*diameter] in distance and with < 110 angle + // Apply wiggle bonus for jumps that are [radius, 2*diameter] in distance, with < 110 angle and bpm > 150 wiggleBonus = angleBonus + * DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.StrainTime), 150, 200) * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, radius, diameter) - * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter * 2, diameter) + * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter * 2, diameter * 1.1) * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, radius, diameter) - * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, diameter * 2, diameter) + * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, diameter * 2, diameter * 1.1) * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); } } From 7e42fb16881e8e38e3bb124448a527ddb9049367 Mon Sep 17 00:00:00 2001 From: StanR Date: Tue, 10 Dec 2024 15:15:17 +0500 Subject: [PATCH 10/13] Reduce wiggle bonus multiplier to not break velocity>difficulty relation --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index e079a3eee3de..257a6c866e04 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -15,7 +15,7 @@ public static class AimEvaluator private const double acute_angle_multiplier = 2.35; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; - private const double wiggle_multiplier = 1.2; + private const double wiggle_multiplier = 1.0; /// /// Evaluates the difficulty of aiming the current object, based on: From 37a56eee2c73c25a5f982378a93f739deecd9a12 Mon Sep 17 00:00:00 2001 From: StanR Date: Tue, 10 Dec 2024 18:28:59 +0500 Subject: [PATCH 11/13] Adjust wiggle falloff function to fix stability issues --- .../Difficulty/Evaluators/AimEvaluator.cs | 8 ++++---- .../Difficulty/Utils/DifficultyCalculationUtils.cs | 11 +++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 257a6c866e04..9f0c861765ea 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -15,7 +15,7 @@ public static class AimEvaluator private const double acute_angle_multiplier = 2.35; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; - private const double wiggle_multiplier = 1.0; + private const double wiggle_multiplier = 1.035; /// /// Evaluates the difficulty of aiming the current object, based on: @@ -94,13 +94,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with acuteAngleBonus *= 0.03 + 0.97 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3))); // Apply wiggle bonus for jumps that are [radius, 2*diameter] in distance, with < 110 angle and bpm > 150 + // https://www.desmos.com/calculator/iis7lgbppe wiggleBonus = angleBonus - * DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.StrainTime), 150, 200) * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, radius, diameter) - * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter * 2, diameter * 1.1) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuCurrObj.LazyJumpDistance, diameter * 2.5, diameter), 1.5) * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, radius, diameter) - * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, diameter * 2, diameter * 1.1) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuLastObj.LazyJumpDistance, diameter * 2.5, diameter), 1.5) * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); } } diff --git a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs index 2f37dd53f79b..c5fbd398a337 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs @@ -59,5 +59,16 @@ public static double Smootherstep(double x, double start, double end) return x * x * x * (x * (6.0 * x - 15.0) + 10.0); } + + /// + /// Reverse linear interpolation function (https://en.wikipedia.org/wiki/Linear_interpolation) + /// + /// Value to calculate the function for + /// Value at which function returns 0 + /// Value at which function returns 1 + public static double ReverseLerp(double x, double start, double end) + { + return Math.Clamp((x - start) / (end - start), 0.0, 1.0); + } } } From 9858930d76e077836a357e9771a92b817e9d8837 Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 12 Dec 2024 14:32:46 +0500 Subject: [PATCH 12/13] Adjust wiggle consts --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 9f0c861765ea..c3270f25f8e3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -15,7 +15,7 @@ public static class AimEvaluator private const double acute_angle_multiplier = 2.35; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; - private const double wiggle_multiplier = 1.035; + private const double wiggle_multiplier = 1.02; /// /// Evaluates the difficulty of aiming the current object, based on: @@ -97,10 +97,10 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // https://www.desmos.com/calculator/iis7lgbppe wiggleBonus = angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuCurrObj.LazyJumpDistance, diameter * 2.5, diameter), 1.5) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuCurrObj.LazyJumpDistance, diameter * 3, diameter), 1.8) * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuLastObj.LazyJumpDistance, diameter * 2.5, diameter), 1.5) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuLastObj.LazyJumpDistance, diameter * 3, diameter), 1.8) * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); } } From cdeb4c97e5c570134f1021360c6d846418814098 Mon Sep 17 00:00:00 2001 From: StanR Date: Fri, 20 Dec 2024 23:01:41 +0500 Subject: [PATCH 13/13] Update tests --- osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs index efda3fa369f1..979861148884 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs @@ -15,20 +15,20 @@ public class OsuDifficultyCalculatorTest : DifficultyCalculatorTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Osu.Tests"; - [TestCase(6.7171144000821119d, 239, "diffcalc-test")] + [TestCase(6.718709884850683d, 239, "diffcalc-test")] [TestCase(1.4485749025771304d, 54, "zero-length-sliders")] [TestCase(0.42630400627180914d, 4, "very-fast-slider")] [TestCase(0.14143808967817237d, 2, "nan-slider")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(8.9825709931204205d, 239, "diffcalc-test")] + [TestCase(9.4310274277499619d, 239, "diffcalc-test")] [TestCase(1.7550169162648608d, 54, "zero-length-sliders")] [TestCase(0.55231632896800109d, 4, "very-fast-slider")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModDoubleTime()); - [TestCase(6.7171144000821119d, 239, "diffcalc-test")] + [TestCase(6.718709884850683d, 239, "diffcalc-test")] [TestCase(1.4485749025771304d, 54, "zero-length-sliders")] [TestCase(0.42630400627180914d, 4, "very-fast-slider")] public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name)