From dce4132209eb28f012a6ed7255f811612fc0045b Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Sat, 9 Aug 2025 22:40:37 +0300 Subject: [PATCH] Nerf Low AR HD bonus for slideraim (#34215) * Refactor slider factor calculation * Nerf low AR HD bonus for slideraim * finish merge * Fixes * Fix comment --------- Co-authored-by: James Wilson --- .../Difficulty/OsuDifficultyCalculator.cs | 6 ++---- .../Difficulty/OsuPerformanceCalculator.cs | 2 +- .../Difficulty/OsuRatingCalculator.cs | 15 ++++++++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 337bda3221..8e87610dfb 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -98,11 +98,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty double speedDifficultyValue = speed.DifficultyValue(); double mechanicalDifficultyRating = calculateMechanicalDifficultyRating(aimDifficultyValue, speedDifficultyValue); + double sliderFactor = aimDifficultyValue > 0 ? OsuRatingCalculator.CalculateDifficultyRating(aimNoSlidersDifficultyValue) / OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue) : 1; - var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, approachRate, overallDifficulty, mechanicalDifficultyRating); + var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, approachRate, overallDifficulty, mechanicalDifficultyRating, sliderFactor); double aimRating = osuRatingCalculator.ComputeAimRating(aimDifficultyValue); - double aimRatingNoSliders = osuRatingCalculator.ComputeAimRating(aimNoSlidersDifficultyValue); double speedRating = osuRatingCalculator.ComputeSpeedRating(speedDifficultyValue); double flashlightRating = 0.0; @@ -110,8 +110,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (flashlight is not null) flashlightRating = osuRatingCalculator.ComputeFlashlightRating(flashlight.DifficultyValue()); - double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; - double sliderNestedScorePerObject = LegacyScoreUtils.CalculateNestedScorePerObject(beatmap, totalHits); double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(beatmap); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 7230c52f9c..c076b6cfe6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * attributes.DrainRate * attributes.DrainRate); else if (score.Mods.Any(m => m is OsuModTraceable)) { - aimValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate); + aimValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate, attributes.SliderFactor); } aimValue *= accuracy; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index 8793582847..4d78db4788 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -18,14 +18,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty private readonly double approachRate; private readonly double overallDifficulty; private readonly double mechanicalDifficultyRating; + private readonly double sliderFactor; - public OsuRatingCalculator(Mod[] mods, int totalHits, double approachRate, double overallDifficulty, double mechanicalDifficultyRating) + public OsuRatingCalculator(Mod[] mods, int totalHits, double approachRate, double overallDifficulty, double mechanicalDifficultyRating, double sliderFactor) { this.mods = mods; this.totalHits = totalHits; this.approachRate = approachRate; this.overallDifficulty = overallDifficulty; this.mechanicalDifficultyRating = mechanicalDifficultyRating; + this.sliderFactor = sliderFactor; } public double ComputeAimRating(double aimDifficultyValue) @@ -66,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModHidden)) { double visibilityFactor = calculateAimVisibilityFactor(approachRate); - ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor); + ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor, sliderFactor); } // It is important to consider accuracy difficulty when scaling with accuracy. @@ -179,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty /// /// Calculates a visibility bonus that is applicable to Hidden and Traceable. /// - public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1) + public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1, double sliderFactor = 1) { // NOTE: TC's effect is only noticeable in performance calculations until lazer mods are accounted for server-side. bool isAlwaysPartiallyVisible = mods.OfType().Any(m => m.OnlyFadeApproachCircles.Value) || mods.OfType().Any(); @@ -189,13 +191,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty readingBonus *= visibilityFactor; + // We want to reward slideraim on low AR less + double sliderVisibilityFactor = Math.Pow(sliderFactor, 3); + // For AR up to 0 - reduce reward for very low ARs when object is visible if (approachRate < 7) - readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.045) * (7.0 - Math.Max(approachRate, 0)); + readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.045) * (7.0 - Math.Max(approachRate, 0)) * sliderVisibilityFactor; // Starting from AR0 - cap values so they won't grow to infinity if (approachRate < 0) - readingBonus += (isAlwaysPartiallyVisible ? 0.075 : 0.1) * (1 - Math.Pow(1.5, approachRate)); + readingBonus += (isAlwaysPartiallyVisible ? 0.075 : 0.1) * (1 - Math.Pow(1.5, approachRate)) * sliderVisibilityFactor; return readingBonus; }