diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformDifficultyCalculator.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformDifficultyCalculator.cs index 312d3d5e9a..2178941fd8 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformDifficultyCalculator.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformDifficultyCalculator.cs @@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.EmptyFreeform { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { - return new DifficultyAttributes(mods, 0); + return new IDifficultyAttributes(mods, 0); } protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>(); diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs index f6addab279..55cf4fb42d 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs @@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Pippidon { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { - return new DifficultyAttributes(mods, 0); + return new IDifficultyAttributes(mods, 0); } protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>(); diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingDifficultyCalculator.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingDifficultyCalculator.cs index a4dc1762d5..47215ce7d9 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingDifficultyCalculator.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingDifficultyCalculator.cs @@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.EmptyScrolling { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { - return new DifficultyAttributes(mods, 0); + return new IDifficultyAttributes(mods, 0); } protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>(); diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs index f6addab279..55cf4fb42d 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonDifficultyCalculator.cs @@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Pippidon { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { - return new DifficultyAttributes(mods, 0); + return new IDifficultyAttributes(mods, 0); } protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>(); diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs index 5c64643fd4..3ff1c0dd01 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs @@ -1,15 +1,28 @@ // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Catch.Difficulty { - public class CatchDifficultyAttributes : DifficultyAttributes + public struct CatchDifficultyAttributes : IDifficultyAttributes { + public CatchDifficultyAttributes() { } + + /// <inheritdoc/> + public Mod[] Mods { get; set; } = Array.Empty<Mod>(); + + /// <inheritdoc/> + public double StarRating { get; set; } + + /// <inheritdoc/> + public int MaxCombo { get; set; } + /// <summary> /// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc). /// </summary> @@ -19,22 +32,19 @@ namespace osu.Game.Rulesets.Catch.Difficulty [JsonProperty("approach_rate")] public double ApproachRate { get; set; } - public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() + public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() { - foreach (var v in base.ToDatabaseAttributes()) - yield return v; - + yield return (IDifficultyAttributes.ATTRIB_ID_MAX_COMBO, MaxCombo); // Todo: osu!catch should not output star rating in the 'aim' attribute. - yield return (ATTRIB_ID_AIM, StarRating); - yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate); + yield return (IDifficultyAttributes.ATTRIB_ID_AIM, StarRating); + yield return (IDifficultyAttributes.ATTRIB_ID_APPROACH_RATE, ApproachRate); } - public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) + public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) { - base.FromDatabaseAttributes(values, onlineInfo); - - StarRating = values[ATTRIB_ID_AIM]; - ApproachRate = values[ATTRIB_ID_APPROACH_RATE]; + MaxCombo = (int)values[IDifficultyAttributes.ATTRIB_ID_MAX_COMBO]; + StarRating = values[IDifficultyAttributes.ATTRIB_ID_AIM]; + ApproachRate = values[IDifficultyAttributes.ATTRIB_ID_APPROACH_RATE]; } } } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 7d21409ee8..4637fd3c0a 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { if (beatmap.HitObjects.Count == 0) return new CatchDifficultyAttributes { Mods = mods }; diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs index efca1e5e77..a8a0e3c444 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { } - protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes) + protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes) { var catchAttributes = (CatchDifficultyAttributes)attributes; diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs index db60e757e1..8244334748 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs @@ -1,15 +1,28 @@ // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Difficulty { - public class ManiaDifficultyAttributes : DifficultyAttributes + public struct ManiaDifficultyAttributes : IDifficultyAttributes { + public ManiaDifficultyAttributes() { } + + /// <inheritdoc/> + public Mod[] Mods { get; set; } = Array.Empty<Mod>(); + + /// <inheritdoc/> + public double StarRating { get; set; } + + /// <inheritdoc/> + public int MaxCombo { get; set; } + /// <summary> /// The hit window for a GREAT hit inclusive of rate-adjusting mods (DT/HT/etc). /// </summary> @@ -19,21 +32,18 @@ namespace osu.Game.Rulesets.Mania.Difficulty [JsonProperty("great_hit_window")] public double GreatHitWindow { get; set; } - public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() + public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() { - foreach (var v in base.ToDatabaseAttributes()) - yield return v; - - yield return (ATTRIB_ID_DIFFICULTY, StarRating); - yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow); + yield return (IDifficultyAttributes.ATTRIB_ID_MAX_COMBO, MaxCombo); + yield return (IDifficultyAttributes.ATTRIB_ID_DIFFICULTY, StarRating); + yield return (IDifficultyAttributes.ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow); } - public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) + public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) { - base.FromDatabaseAttributes(values, onlineInfo); - - StarRating = values[ATTRIB_ID_DIFFICULTY]; - GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW]; + MaxCombo = (int)values[IDifficultyAttributes.ATTRIB_ID_MAX_COMBO]; + StarRating = values[IDifficultyAttributes.ATTRIB_ID_DIFFICULTY]; + GreatHitWindow = values[IDifficultyAttributes.ATTRIB_ID_GREAT_HIT_WINDOW]; } } } diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index ff9aa4aa7b..ae49c495c5 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty originalOverallDifficulty = beatmap.BeatmapInfo.Difficulty.OverallDifficulty; } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { if (beatmap.HitObjects.Count == 0) return new ManiaDifficultyAttributes { Mods = mods }; diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index 4d1b9b5766..b01bcc2d04 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty { } - protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes) + protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes) { var maniaAttributes = (ManiaDifficultyAttributes)attributes; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index a3c0209a08..315b7b5fbc 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -11,8 +12,19 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Osu.Difficulty { - public class OsuDifficultyAttributes : DifficultyAttributes + public struct OsuDifficultyAttributes : IDifficultyAttributes { + public OsuDifficultyAttributes() { } + + /// <inheritdoc/> + public Mod[] Mods { get; set; } = Array.Empty<Mod>(); + + /// <inheritdoc/> + public double StarRating { get; set; } + + /// <inheritdoc/> + public int MaxCombo { get; set; } + /// <summary> /// The difficulty corresponding to the aim skill. /// </summary> @@ -90,41 +102,38 @@ namespace osu.Game.Rulesets.Osu.Difficulty /// </summary> public int SpinnerCount { get; set; } - public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() + public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() { - foreach (var v in base.ToDatabaseAttributes()) - yield return v; - - yield return (ATTRIB_ID_AIM, AimDifficulty); - yield return (ATTRIB_ID_SPEED, SpeedDifficulty); - yield return (ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty); - yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate); - yield return (ATTRIB_ID_DIFFICULTY, StarRating); + yield return (IDifficultyAttributes.ATTRIB_ID_MAX_COMBO, MaxCombo); + yield return (IDifficultyAttributes.ATTRIB_ID_AIM, AimDifficulty); + yield return (IDifficultyAttributes.ATTRIB_ID_SPEED, SpeedDifficulty); + yield return (IDifficultyAttributes.ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty); + yield return (IDifficultyAttributes.ATTRIB_ID_APPROACH_RATE, ApproachRate); + yield return (IDifficultyAttributes.ATTRIB_ID_DIFFICULTY, StarRating); if (ShouldSerializeFlashlightDifficulty()) - yield return (ATTRIB_ID_FLASHLIGHT, FlashlightDifficulty); + yield return (IDifficultyAttributes.ATTRIB_ID_FLASHLIGHT, FlashlightDifficulty); - yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor); + yield return (IDifficultyAttributes.ATTRIB_ID_SLIDER_FACTOR, SliderFactor); - yield return (ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT, AimDifficultStrainCount); - yield return (ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT, SpeedDifficultStrainCount); - yield return (ATTRIB_ID_SPEED_NOTE_COUNT, SpeedNoteCount); + yield return (IDifficultyAttributes.ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT, AimDifficultStrainCount); + yield return (IDifficultyAttributes.ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT, SpeedDifficultStrainCount); + yield return (IDifficultyAttributes.ATTRIB_ID_SPEED_NOTE_COUNT, SpeedNoteCount); } - public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) + public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) { - base.FromDatabaseAttributes(values, onlineInfo); - - AimDifficulty = values[ATTRIB_ID_AIM]; - SpeedDifficulty = values[ATTRIB_ID_SPEED]; - OverallDifficulty = values[ATTRIB_ID_OVERALL_DIFFICULTY]; - ApproachRate = values[ATTRIB_ID_APPROACH_RATE]; - StarRating = values[ATTRIB_ID_DIFFICULTY]; - FlashlightDifficulty = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT); - SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR]; - AimDifficultStrainCount = values[ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT]; - SpeedDifficultStrainCount = values[ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT]; - SpeedNoteCount = values[ATTRIB_ID_SPEED_NOTE_COUNT]; + MaxCombo = (int)values[IDifficultyAttributes.ATTRIB_ID_MAX_COMBO]; + AimDifficulty = values[IDifficultyAttributes.ATTRIB_ID_AIM]; + SpeedDifficulty = values[IDifficultyAttributes.ATTRIB_ID_SPEED]; + OverallDifficulty = values[IDifficultyAttributes.ATTRIB_ID_OVERALL_DIFFICULTY]; + ApproachRate = values[IDifficultyAttributes.ATTRIB_ID_APPROACH_RATE]; + StarRating = values[IDifficultyAttributes.ATTRIB_ID_DIFFICULTY]; + FlashlightDifficulty = values.GetValueOrDefault(IDifficultyAttributes.ATTRIB_ID_FLASHLIGHT); + SliderFactor = values[IDifficultyAttributes.ATTRIB_ID_SLIDER_FACTOR]; + AimDifficultStrainCount = values[IDifficultyAttributes.ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT]; + SpeedDifficultStrainCount = values[IDifficultyAttributes.ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT]; + SpeedNoteCount = values[IDifficultyAttributes.ATTRIB_ID_SPEED_NOTE_COUNT]; DrainRate = onlineInfo.DrainRate; HitCircleCount = onlineInfo.CircleCount; SliderCount = onlineInfo.SliderCount; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index acf01b2a83..97603bb16a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { if (beatmap.HitObjects.Count == 0) return new OsuDifficultyAttributes { Mods = mods }; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 8425f437cc..b79a8feb96 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { } - protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes) + protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes) { var osuAttributes = (OsuDifficultyAttributes)attributes; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index 451aed183d..337e1c1488 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -1,15 +1,29 @@ // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Taiko.Difficulty { - public class TaikoDifficultyAttributes : DifficultyAttributes + public struct TaikoDifficultyAttributes : IDifficultyAttributes { + public TaikoDifficultyAttributes() { } + + /// <inheritdoc/> + public Mod[] Mods { get; set; } = Array.Empty<Mod>(); + + /// <inheritdoc/> + public double StarRating { get; set; } + + /// <inheritdoc/> + [JsonProperty("max_combo", Order = -2)] + public int MaxCombo { get; set; } + /// <summary> /// The difficulty corresponding to the stamina skill. /// </summary> @@ -52,23 +66,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty [JsonProperty("ok_hit_window")] public double OkHitWindow { get; set; } - public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() + public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() { - foreach (var v in base.ToDatabaseAttributes()) - yield return v; - - yield return (ATTRIB_ID_DIFFICULTY, StarRating); - yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow); - yield return (ATTRIB_ID_OK_HIT_WINDOW, OkHitWindow); + yield return (IDifficultyAttributes.ATTRIB_ID_MAX_COMBO, MaxCombo); + yield return (IDifficultyAttributes.ATTRIB_ID_DIFFICULTY, StarRating); + yield return (IDifficultyAttributes.ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow); + yield return (IDifficultyAttributes.ATTRIB_ID_OK_HIT_WINDOW, OkHitWindow); } - public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) + public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) { - base.FromDatabaseAttributes(values, onlineInfo); - - StarRating = values[ATTRIB_ID_DIFFICULTY]; - GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW]; - OkHitWindow = values[ATTRIB_ID_OK_HIT_WINDOW]; + MaxCombo = (int)values[IDifficultyAttributes.ATTRIB_ID_MAX_COMBO]; + StarRating = values[IDifficultyAttributes.ATTRIB_ID_DIFFICULTY]; + GreatHitWindow = values[IDifficultyAttributes.ATTRIB_ID_GREAT_HIT_WINDOW]; + OkHitWindow = values[IDifficultyAttributes.ATTRIB_ID_OK_HIT_WINDOW]; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 18223e74fa..4b86620b39 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty return difficultyHitObjects; } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { if (beatmap.HitObjects.Count == 0) return new TaikoDifficultyAttributes { Mods = mods }; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 29eadf417f..7373993629 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { } - protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes) + protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes) { var taikoAttributes = (TaikoDifficultyAttributes)attributes; diff --git a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs index 6b1b883ce7..7c63bbd9a3 100644 --- a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs +++ b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs @@ -222,7 +222,7 @@ namespace osu.Game.Tests.NonVisual protected override Mod[] DifficultyAdjustmentMods { get; } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { throw new NotImplementedException(); } diff --git a/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs b/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs index f860cd097a..5db37dd810 100644 --- a/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs +++ b/osu.Game.Tests/NonVisual/TestSceneTimedDifficultyCalculation.cs @@ -172,7 +172,7 @@ namespace osu.Game.Tests.NonVisual { } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) + protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) => new TestDifficultyAttributes { Objects = beatmap.HitObjects.ToArray() }; protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) @@ -208,7 +208,7 @@ namespace osu.Game.Tests.NonVisual } } - private class TestDifficultyAttributes : DifficultyAttributes + private class TestDifficultyAttributes : IDifficultyAttributes { public HitObject[] Objects = Array.Empty<HitObject>(); } diff --git a/osu.Game/Beatmaps/StarDifficulty.cs b/osu.Game/Beatmaps/StarDifficulty.cs index 6aac275a6a..e0a7e724a3 100644 --- a/osu.Game/Beatmaps/StarDifficulty.cs +++ b/osu.Game/Beatmaps/StarDifficulty.cs @@ -26,13 +26,13 @@ namespace osu.Game.Beatmaps /// Might not be available if the star difficulty is associated with a beatmap that's not locally available. /// </summary> [CanBeNull] - public readonly DifficultyAttributes Attributes; + public readonly IDifficultyAttributes Attributes; /// <summary> - /// Creates a <see cref="StarDifficulty"/> structure based on <see cref="DifficultyAttributes"/> computed + /// Creates a <see cref="StarDifficulty"/> structure based on <see cref="IDifficultyAttributes"/> computed /// by a <see cref="DifficultyCalculator"/>. /// </summary> - public StarDifficulty([NotNull] DifficultyAttributes attributes) + public StarDifficulty([NotNull] IDifficultyAttributes attributes) { Stars = double.IsFinite(attributes.StarRating) ? attributes.StarRating : 0; MaxCombo = attributes.MaxCombo; @@ -42,7 +42,7 @@ namespace osu.Game.Beatmaps /// <summary> /// Creates a <see cref="StarDifficulty"/> structure with a pre-populated star difficulty and max combo - /// in scenarios where computing <see cref="DifficultyAttributes"/> is not feasible (i.e. when working with online sources). + /// in scenarios where computing <see cref="IDifficultyAttributes"/> is not feasible (i.e. when working with online sources). /// </summary> public StarDifficulty(double starDifficulty, int maxCombo) { diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 63b27243d0..39340776f0 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Difficulty /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A structure describing the difficulty of the beatmap.</returns> - public DifficultyAttributes Calculate(CancellationToken cancellationToken = default) + public IDifficultyAttributes Calculate(CancellationToken cancellationToken = default) => Calculate(Array.Empty<Mod>(), cancellationToken); /// <summary> @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Difficulty /// <param name="mods">The mods that should be applied to the beatmap.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A structure describing the difficulty of the beatmap.</returns> - public DifficultyAttributes Calculate([NotNull] IEnumerable<Mod> mods, CancellationToken cancellationToken = default) + public IDifficultyAttributes Calculate([NotNull] IEnumerable<Mod> mods, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); preProcess(mods, cancellationToken); @@ -140,7 +140,7 @@ namespace osu.Game.Rulesets.Difficulty /// This can only be used to compute difficulties for legacy mod combinations. /// </remarks> /// <returns>A collection of structures describing the difficulty of the beatmap for each mod combination.</returns> - public IEnumerable<DifficultyAttributes> CalculateAllLegacyCombinations(CancellationToken cancellationToken = default) + public IEnumerable<IDifficultyAttributes> CalculateAllLegacyCombinations(CancellationToken cancellationToken = default) { var rulesetInstance = ruleset.CreateInstance(); @@ -263,14 +263,14 @@ namespace osu.Game.Rulesets.Difficulty protected virtual Mod[] DifficultyAdjustmentMods => Array.Empty<Mod>(); /// <summary> - /// Creates <see cref="DifficultyAttributes"/> to describe beatmap's calculated difficulty. + /// Creates <see cref="IDifficultyAttributes"/> to describe beatmap's calculated difficulty. /// </summary> /// <param name="beatmap">The <see cref="IBeatmap"/> whose difficulty was calculated. /// This may differ from <see cref="Beatmap"/> in the case of timed calculation.</param> /// <param name="mods">The <see cref="Mod"/>s that difficulty was calculated with.</param> /// <param name="skills">The skills which processed the beatmap.</param> /// <param name="clockRate">The rate at which the gameplay clock is run at.</param> - protected abstract DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate); + protected abstract IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate); /// <summary> /// Enumerates <see cref="DifficultyHitObject"/>s to be processed from <see cref="HitObject"/>s in the <see cref="IBeatmap"/>. diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/IDifficultyAttributes.cs similarity index 65% rename from osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs rename to osu.Game/Rulesets/Difficulty/IDifficultyAttributes.cs index ae4239c148..b951b5fb11 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/IDifficultyAttributes.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Beatmaps; @@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Difficulty /// Describes the difficulty of a beatmap, as output by a <see cref="DifficultyCalculator"/>. /// </summary> [JsonObject(MemberSerialization.OptIn)] - public class DifficultyAttributes + public interface IDifficultyAttributes { protected const int ATTRIB_ID_AIM = 1; protected const int ATTRIB_ID_SPEED = 3; @@ -33,7 +32,7 @@ namespace osu.Game.Rulesets.Difficulty /// <summary> /// The mods which were applied to the beatmap. /// </summary> - public Mod[] Mods { get; set; } = Array.Empty<Mod>(); + public Mod[] Mods { get; set; } /// <summary> /// The combined star rating of all skills. @@ -48,42 +47,18 @@ namespace osu.Game.Rulesets.Difficulty public int MaxCombo { get; set; } /// <summary> - /// Creates new <see cref="DifficultyAttributes"/>. - /// </summary> - public DifficultyAttributes() - { - } - - /// <summary> - /// Creates new <see cref="DifficultyAttributes"/>. - /// </summary> - /// <param name="mods">The mods which were applied to the beatmap.</param> - /// <param name="starRating">The combined star rating of all skills.</param> - public DifficultyAttributes(Mod[] mods, double starRating) - { - Mods = mods; - StarRating = starRating; - } - - /// <summary> - /// Converts this <see cref="DifficultyAttributes"/> to osu-web compatible database attribute mappings. + /// Converts this <see cref="IDifficultyAttributes"/> to osu-web compatible database attribute mappings. /// </summary> /// <remarks> /// See: osu_difficulty_attribs table. /// </remarks> - public virtual IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() - { - yield return (ATTRIB_ID_MAX_COMBO, MaxCombo); - } + public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes(); /// <summary> - /// Reads osu-web database attribute mappings into this <see cref="DifficultyAttributes"/> object. + /// Reads osu-web database attribute mappings into this <see cref="IDifficultyAttributes"/> object. /// </summary> /// <param name="values">The attribute mappings.</param> /// <param name="onlineInfo">The <see cref="IBeatmapOnlineInfo"/> where more information about the beatmap may be extracted from (such as AR/CS/OD/etc).</param> - public virtual void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) - { - MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO]; - } + public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo); } } diff --git a/osu.Game/Rulesets/Difficulty/PerformanceAttributes.cs b/osu.Game/Rulesets/Difficulty/IPerformanceAttributes.cs similarity index 100% rename from osu.Game/Rulesets/Difficulty/PerformanceAttributes.cs rename to osu.Game/Rulesets/Difficulty/IPerformanceAttributes.cs diff --git a/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs b/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs index ee7f02f9be..b7ff4b9812 100644 --- a/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs @@ -17,10 +17,10 @@ namespace osu.Game.Rulesets.Difficulty Ruleset = ruleset; } - public Task<IPerformanceAttributes> CalculateAsync(ScoreInfo score, DifficultyAttributes attributes, CancellationToken cancellationToken) + public Task<IPerformanceAttributes> CalculateAsync(ScoreInfo score, IDifficultyAttributes attributes, CancellationToken cancellationToken) => Task.Run(() => CreatePerformanceAttributes(score, attributes), cancellationToken); - public IPerformanceAttributes Calculate(ScoreInfo score, DifficultyAttributes attributes) + public IPerformanceAttributes Calculate(ScoreInfo score, IDifficultyAttributes attributes) => CreatePerformanceAttributes(score, attributes); public IPerformanceAttributes Calculate(ScoreInfo score, IWorkingBeatmap beatmap) @@ -31,6 +31,6 @@ namespace osu.Game.Rulesets.Difficulty /// </summary> /// <param name="score">The score to create the attributes for.</param> /// <param name="attributes">The difficulty attributes for the beatmap relating to the score.</param> - protected abstract IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes); + protected abstract IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes); } } diff --git a/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs index a07827d50b..b6a7aa26da 100644 --- a/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs @@ -8,7 +8,7 @@ using System; namespace osu.Game.Rulesets.Difficulty { /// <summary> - /// Wraps a <see cref="DifficultyAttributes"/> object and adds a time value for which the attribute is valid. + /// Wraps a <see cref="IDifficultyAttributes"/> object and adds a time value for which the attribute is valid. /// Output by DifficultyCalculator.CalculateTimed methods. /// </summary> public class TimedDifficultyAttributes : IComparable<TimedDifficultyAttributes> @@ -21,14 +21,14 @@ namespace osu.Game.Rulesets.Difficulty /// <summary> /// The attributes. /// </summary> - public readonly DifficultyAttributes Attributes; + public readonly IDifficultyAttributes Attributes; /// <summary> /// Creates new <see cref="TimedDifficultyAttributes"/>. /// </summary> /// <param name="time">The non-clock-adjusted time value at which the attributes take effect.</param> /// <param name="attributes">The attributes.</param> - public TimedDifficultyAttributes(double time, DifficultyAttributes attributes) + public TimedDifficultyAttributes(double time, IDifficultyAttributes attributes) { Time = time; Attributes = attributes; diff --git a/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs b/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs index 25c1387220..a48124fb68 100644 --- a/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs +++ b/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs @@ -106,7 +106,7 @@ namespace osu.Game.Screens.Play.HUD } [CanBeNull] - private DifficultyAttributes getAttributeAtTime(JudgementResult judgement) + private IDifficultyAttributes getAttributeAtTime(JudgementResult judgement) { if (timedAttributes == null || timedAttributes.Count == 0) return null;