From 75890005e6f4117c80244884f659ec39318cebb1 Mon Sep 17 00:00:00 2001 From: StanR Date: Sat, 28 Sep 2024 15:33:12 +0500 Subject: [PATCH 1/4] Replace indexed skill access with `skills.First(s is ...)` --- .../Difficulty/CatchDifficultyCalculator.cs | 3 ++- .../Difficulty/ManiaDifficultyCalculator.cs | 2 +- .../Difficulty/OsuDifficultyCalculator.cs | 21 ++++++++++++------- .../Difficulty/Skills/Aim.cs | 2 +- .../Difficulty/Skills/AimWithoutSliders.cs | 18 ++++++++++++++++ 5 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 7d21409ee8c7..50e5bcbef50a 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Difficulty.Preprocessing; @@ -40,7 +41,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat CatchDifficultyAttributes attributes = new CatchDifficultyAttributes { - StarRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier, + StarRating = Math.Sqrt(skills.First(s => s is Movement).DifficultyValue()) * difficulty_multiplier, Mods = mods, ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0, MaxCombo = beatmap.GetMaxCombo(), diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index efe27e8d6bda..61181e1e517a 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -48,7 +48,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat ManiaDifficultyAttributes attributes = new ManiaDifficultyAttributes { - StarRating = skills[0].DifficultyValue() * difficulty_multiplier, + StarRating = skills.First(s => s is Strain).DifficultyValue() * difficulty_multiplier, Mods = mods, // In osu-stable mania, rate-adjustment mods don't affect the hit window. // This is done the way it is to introduce fractional differences in order to match osu-stable for the time being. diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index c4fcd1f760fe..16aceb3b37fc 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -36,15 +36,22 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat if (beatmap.HitObjects.Count == 0) return new OsuDifficultyAttributes { Mods = mods }; - double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; - double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; - double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier; - double speedNotes = ((Speed)skills[2]).RelevantNoteCount(); + var aim = (Aim)skills.First(s => s is Aim); + var aimWithoutSliders = (AimWithoutSliders)skills.First(s => s is AimWithoutSliders); + var speed = (Speed)skills.First(s => s is Speed); + + double aimRating = Math.Sqrt(aim.DifficultyValue()) * difficulty_multiplier; + double aimRatingNoSliders = Math.Sqrt(aimWithoutSliders.DifficultyValue()) * difficulty_multiplier; + double speedRating = Math.Sqrt(speed.DifficultyValue()) * difficulty_multiplier; + double speedNotes = speed.RelevantNoteCount(); double flashlightRating = 0.0; if (mods.Any(h => h is OsuModFlashlight)) - flashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier; + { + var flashlight = (Flashlight)skills.First(s => s is Flashlight); + flashlightRating = Math.Sqrt(flashlight.DifficultyValue()) * difficulty_multiplier; + } double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; @@ -131,8 +138,8 @@ protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clo { var skills = new List { - new Aim(mods, true), - new Aim(mods, false), + new Aim(mods), + new AimWithoutSliders(mods), new Speed(mods) }; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 1fbe03395c90..5faa60e39b99 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Aim : OsuStrainSkill { - public Aim(Mod[] mods, bool withSliders) + public Aim(Mod[] mods, bool withSliders = true) : base(mods) { this.withSliders = withSliders; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs new file mode 100644 index 000000000000..8e494abc5cbd --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs @@ -0,0 +1,18 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Osu.Difficulty.Skills +{ + /// + /// Represents the Aim skill that includes sliders in it's calculation + /// + public class AimWithoutSliders : Aim + { + public AimWithoutSliders(Mod[] mods) + : base(mods, false) + { + } + } +} From b540f0f7131fd85021a2fdd8358a665fa9d35423 Mon Sep 17 00:00:00 2001 From: StanR Date: Sat, 28 Sep 2024 15:34:51 +0500 Subject: [PATCH 2/4] Fix comment --- osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs index 8e494abc5cbd..b3e8e7172d8e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs @@ -6,7 +6,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { /// - /// Represents the Aim skill that includes sliders in it's calculation + /// Represents the Aim skill that does not include sliders length in it's calculation /// public class AimWithoutSliders : Aim { From d67e7ca033cebb13d3f56ad8fcdf2b0ecd8ebb06 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 13 Dec 2024 17:25:31 +0900 Subject: [PATCH 3/4] Further refactoring to remove casts --- .../Difficulty/CatchDifficultyCalculator.cs | 2 +- .../Difficulty/ManiaDifficultyCalculator.cs | 2 +- .../Difficulty/OsuDifficultyCalculator.cs | 30 ++++++++----------- .../Difficulty/Skills/Aim.cs | 10 +++---- .../Difficulty/Skills/AimWithoutSliders.cs | 18 ----------- .../Difficulty/Skills/Stamina.cs | 14 ++++----- .../Difficulty/TaikoDifficultyCalculator.cs | 12 ++++---- 7 files changed, 33 insertions(+), 55 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 50e5bcbef50a..99df2731ff8b 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -41,7 +41,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat CatchDifficultyAttributes attributes = new CatchDifficultyAttributes { - StarRating = Math.Sqrt(skills.First(s => s is Movement).DifficultyValue()) * difficulty_multiplier, + StarRating = Math.Sqrt(skills.OfType().Single().DifficultyValue()) * difficulty_multiplier, Mods = mods, ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0, MaxCombo = beatmap.GetMaxCombo(), diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 636d7b9b41d6..1efa7cb42f1b 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -48,7 +48,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat ManiaDifficultyAttributes attributes = new ManiaDifficultyAttributes { - StarRating = skills.First(s => s is Strain).DifficultyValue() * difficulty_multiplier, + StarRating = skills.OfType().Single().DifficultyValue() * difficulty_multiplier, Mods = mods, // In osu-stable mania, rate-adjustment mods don't affect the hit window. // This is done the way it is to introduce fractional differences in order to match osu-stable for the time being. diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 0163715f2af6..cf45cb3a2524 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -36,27 +36,21 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat if (beatmap.HitObjects.Count == 0) return new OsuDifficultyAttributes { Mods = mods }; - var aim = (Aim)skills.First(s => s is Aim); - var aimWithoutSliders = (AimWithoutSliders)skills.First(s => s is AimWithoutSliders); - var speed = (Speed)skills.First(s => s is Speed); - + var aim = skills.OfType().Single(a => a.IncludeSliders); double aimRating = Math.Sqrt(aim.DifficultyValue()) * difficulty_multiplier; + double aimDifficultyStrainCount = aim.CountTopWeightedStrains(); + + var aimWithoutSliders = skills.OfType().Single(a => !a.IncludeSliders); double aimRatingNoSliders = Math.Sqrt(aimWithoutSliders.DifficultyValue()) * difficulty_multiplier; + double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; + + var speed = skills.OfType().Single(); double speedRating = Math.Sqrt(speed.DifficultyValue()) * difficulty_multiplier; double speedNotes = speed.RelevantNoteCount(); + double speedDifficultyStrainCount = speed.CountTopWeightedStrains(); - double flashlightRating = 0.0; - - if (mods.Any(h => h is OsuModFlashlight)) - { - var flashlight = (Flashlight)skills.First(s => s is Flashlight); - flashlightRating = Math.Sqrt(flashlight.DifficultyValue()) * difficulty_multiplier; - } - - double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; - - double aimDifficultyStrainCount = ((OsuStrainSkill)skills[0]).CountTopWeightedStrains(); - double speedDifficultyStrainCount = ((OsuStrainSkill)skills[2]).CountTopWeightedStrains(); + var flashlight = skills.OfType().SingleOrDefault(); + double flashlightRating = flashlight == null ? 0.0 : Math.Sqrt(flashlight.DifficultyValue()) * difficulty_multiplier; if (mods.Any(m => m is OsuModTouchDevice)) { @@ -143,8 +137,8 @@ protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clo { var skills = new List { - new Aim(mods), - new AimWithoutSliders(mods), + new Aim(mods, true), + new Aim(mods, false), new Speed(mods) }; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 85e49a893bf2..52940f256bef 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -13,14 +13,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Aim : OsuStrainSkill { - public Aim(Mod[] mods, bool withSliders = true) + public readonly bool IncludeSliders; + + public Aim(Mod[] mods, bool includeSliders) : base(mods) { - this.withSliders = withSliders; + IncludeSliders = includeSliders; } - private readonly bool withSliders; - private double currentStrain; private double skillMultiplier => 25.18; @@ -33,7 +33,7 @@ public Aim(Mod[] mods, bool withSliders = true) protected override double StrainValueAt(DifficultyHitObject current) { currentStrain *= strainDecay(current.DeltaTime); - currentStrain += AimEvaluator.EvaluateDifficultyOf(current, withSliders) * skillMultiplier; + currentStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * skillMultiplier; return currentStrain; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs deleted file mode 100644 index b3e8e7172d8e..000000000000 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/AimWithoutSliders.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Mods; - -namespace osu.Game.Rulesets.Osu.Difficulty.Skills -{ - /// - /// Represents the Aim skill that does not include sliders length in it's calculation - /// - public class AimWithoutSliders : Aim - { - public AimWithoutSliders(Mod[] mods) - : base(mods, false) - { - } - } -} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index f6914039f057..44cb7316abac 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -15,22 +15,22 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// public class Stamina : StrainSkill { + public readonly bool MonoColour; + private double skillMultiplier => 1.1; private double strainDecayBase => 0.4; - private readonly bool singleColourStamina; - private double currentStrain; /// /// Creates a skill. /// /// Mods for use in skill calculations. - /// Reads when Stamina is from a single coloured pattern. - public Stamina(Mod[] mods, bool singleColourStamina) + /// Reads when Stamina is from a single coloured pattern. + public Stamina(Mod[] mods, bool monoColour) : base(mods) { - this.singleColourStamina = singleColourStamina; + MonoColour = monoColour; } private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); @@ -44,12 +44,12 @@ protected override double StrainValueAt(DifficultyHitObject current) var currentObject = current as TaikoDifficultyHitObject; int index = currentObject?.Colour.MonoStreak?.HitObjects.IndexOf(currentObject) ?? 0; - if (singleColourStamina) + if (MonoColour) return currentStrain / (1 + Math.Exp(-(index - 10) / 2.0)); return currentStrain; } - protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => singleColourStamina ? 0 : currentStrain * strainDecay(time - current.Previous(0).StartTime); + protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => MonoColour ? 0 : currentStrain * strainDecay(time - current.Previous(0).StartTime); } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 7f2558c406f5..5f960689da1e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -77,14 +77,16 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat if (beatmap.HitObjects.Count == 0) return new TaikoDifficultyAttributes { Mods = mods }; - Colour colour = (Colour)skills.First(x => x is Colour); - Rhythm rhythm = (Rhythm)skills.First(x => x is Rhythm); - Stamina stamina = (Stamina)skills.First(x => x is Stamina); - Stamina singleColourStamina = (Stamina)skills.Last(x => x is Stamina); - + Colour colour = skills.OfType().Single(); double colourRating = colour.DifficultyValue() * colour_skill_multiplier; + + Rhythm rhythm = skills.OfType().Single(); double rhythmRating = rhythm.DifficultyValue() * rhythm_skill_multiplier; + + Stamina stamina = skills.OfType().Single(s => !s.MonoColour); double staminaRating = stamina.DifficultyValue() * stamina_skill_multiplier; + + Stamina singleColourStamina = skills.OfType().Single(s => s.MonoColour); double monoStaminaRating = singleColourStamina.DifficultyValue() * stamina_skill_multiplier; double monoStaminaFactor = staminaRating == 0 ? 1 : Math.Pow(monoStaminaRating / staminaRating, 5); From b7cd38f4c577d45e1d05ccc1a6a376f586b8ebcb Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 20 Jan 2025 14:34:26 +0500 Subject: [PATCH 4/4] Remove `this` --- osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 78dfc729d099..12e1396dd7f3 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -33,7 +33,7 @@ public class Stamina : StrainSkill public Stamina(Mod[] mods, bool singleColourStamina, bool isConvert) : base(mods) { - this.SingleColourStamina = singleColourStamina; + SingleColourStamina = singleColourStamina; this.isConvert = isConvert; }