From e0019c46a56c6c008164cdb7ae3cdb20720a00ad Mon Sep 17 00:00:00 2001 From: danielthirtle Date: Sun, 22 Dec 2024 04:03:52 +1300 Subject: [PATCH] scale misscount by proportion of difficult sliders --- .../Difficulty/OsuDifficultyAttributes.cs | 4 ++++ .../Difficulty/OsuDifficultyCalculator.cs | 7 +++++++ .../Difficulty/OsuPerformanceCalculator.cs | 4 ++-- .../Difficulty/Skills/Aim.cs | 3 +++ .../Difficulty/Skills/OsuStrainSkill.cs | 19 +++++++++++++++++++ .../Difficulty/Skills/Speed.cs | 2 ++ 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index a3c0209a08..0c47521ae8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -45,6 +45,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty /// [JsonProperty("slider_factor")] public double SliderFactor { get; set; } + [JsonProperty("aim_top_weighted_slider_factor")] + public double AimTopWeightedSliderFactor { get; set; } + [JsonProperty("speed_top_weighted_slider_factor")] + public double SpeedTopWeightedSliderFactor { get; set; } [JsonProperty("aim_difficult_strain_count")] public double AimDifficultStrainCount { get; set; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 575e03051c..d904285613 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -50,6 +50,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimDifficultyStrainCount = ((OsuStrainSkill)skills[0]).CountTopWeightedStrains(); double speedDifficultyStrainCount = ((OsuStrainSkill)skills[2]).CountTopWeightedStrains(); + (double hitCircles, double sliders) aimTypedDifficultyStrainCount = ((OsuStrainSkill)skills[0]).CountTypedTopWeightedStrains(); + (double hitCircles, double sliders) speedTypedDifficultyStrainCount = ((OsuStrainSkill)skills[2]).CountTypedTopWeightedStrains(); + + double aimTopWeightedSliderFactor = aimTypedDifficultyStrainCount.sliders / aimTypedDifficultyStrainCount.hitCircles; + double speedTopWeightedSliderFactor = speedTypedDifficultyStrainCount.sliders / speedTypedDifficultyStrainCount.hitCircles; if (mods.Any(m => m is OsuModTouchDevice)) { @@ -105,6 +110,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty SliderFactor = sliderFactor, AimDifficultStrainCount = aimDifficultyStrainCount, SpeedDifficultStrainCount = speedDifficultyStrainCount, + AimTopWeightedSliderFactor = aimTopWeightedSliderFactor, + SpeedTopWeightedSliderFactor = speedTopWeightedSliderFactor, ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5, OverallDifficulty = (80 - hitWindowGreat) / 6, DrainRate = drainRate, diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 31b00dba2b..ce3d6aeec1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -142,7 +142,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty aimValue *= lengthBonus; if (effectiveMissCount > 0) - aimValue *= calculateMissPenalty(effectiveMissCount, attributes.AimDifficultStrainCount); + aimValue *= calculateMissPenalty(effectiveMissCount * (1 + (usingClassicSliderAccuracy ? attributes.AimTopWeightedSliderFactor : 0)), attributes.AimDifficultStrainCount); double approachRateFactor = 0.0; if (attributes.ApproachRate > 10.33) @@ -206,7 +206,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty speedValue *= lengthBonus; if (effectiveMissCount > 0) - speedValue *= calculateMissPenalty(effectiveMissCount, attributes.SpeedDifficultStrainCount); + speedValue *= calculateMissPenalty(effectiveMissCount * (1 + (usingClassicSliderAccuracy ? attributes.SpeedTopWeightedSliderFactor : 0)), attributes.SpeedDifficultStrainCount); double approachRateFactor = 0.0; if (attributes.ApproachRate > 10.33) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index faf91e4652..233e45de6e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -5,6 +5,7 @@ using System; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; +using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { @@ -35,6 +36,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills currentStrain *= strainDecay(current.DeltaTime); currentStrain += AimEvaluator.EvaluateDifficultyOf(current, withSliders) * skillMultiplier; + typedObjectStrains.Add((currentStrain, current.BaseObject is Slider)); + return currentStrain; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index 6823512cef..8d9f3c9b56 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -22,6 +22,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// The baseline multiplier applied to the section with the biggest strain. /// protected virtual double ReducedStrainBaseline => 0.75; + protected List<(double difficulty, bool isSlider)> typedObjectStrains = new List<(double, bool)>(); protected OsuStrainSkill(Mod[] mods) : base(mods) @@ -56,6 +57,24 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills return difficulty; } + public (double hitCircles, double sliders) CountTypedTopWeightedStrains() + { + if (typedObjectStrains.Count == 0) + return (0.0, 0.0); + + double consistentTopStrain = DifficultyValue() / 10; // What would the top strain be if all strain values were identical + List sliderStrains = typedObjectStrains.Where(typedObjectStrain => typedObjectStrain.isSlider).Select(typedObjectStrain => typedObjectStrain.difficulty).ToList(); + List circleStrains = typedObjectStrains.Where(typedObjectStrain => !typedObjectStrain.isSlider).Select(typedObjectStrain => typedObjectStrain.difficulty).ToList(); + + + if (consistentTopStrain == 0) + return (circleStrains.Count, sliderStrains.Count); + + // Use a weighted sum of all strains. Constants are arbitrary and give nice values + double sliderObjects = sliderStrains.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88)))); + double circleObjects = circleStrains.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88)))); + return (circleObjects, sliderObjects); + } public static double DifficultyToPerformance(double difficulty) => Math.Pow(5.0 * Math.Max(1.0, difficulty / 0.0675) - 4.0, 3.0) / 100000.0; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index d2c4bbb618..ecf82ec926 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -6,6 +6,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; +using osu.Game.Rulesets.Osu.Objects; using System.Linq; namespace osu.Game.Rulesets.Osu.Difficulty.Skills @@ -40,6 +41,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current); double totalStrain = currentStrain * currentRhythm; + typedObjectStrains.Add((totalStrain, current.BaseObject is Slider)); return totalStrain; }