From 907499f73afacb8cb419fbc2553d04cc26c0bd57 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Nov 2021 16:06:29 +0900 Subject: [PATCH 01/23] Add json properties to difficulty attributes --- .../Difficulty/CatchDifficultyAttributes.cs | 2 ++ .../Difficulty/ManiaDifficultyAttributes.cs | 4 ++++ .../Difficulty/OsuDifficultyAttributes.cs | 20 +++++++++++++++++++ .../Difficulty/TaikoDifficultyAttributes.cs | 10 ++++++++++ .../Difficulty/DifficultyAttributes.cs | 7 +++++++ 5 files changed, 43 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs index 4e05b1e3e0..57305ce62b 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs @@ -1,12 +1,14 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Rulesets.Catch.Difficulty { public class CatchDifficultyAttributes : DifficultyAttributes { + [JsonProperty("approach_rate")] public double ApproachRate { get; set; } } } diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs index 628d77107f..dd966ca859 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs @@ -1,13 +1,17 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Rulesets.Mania.Difficulty { public class ManiaDifficultyAttributes : DifficultyAttributes { + [JsonProperty("great_hit_window")] public double GreatHitWindow { get; set; } + + [JsonProperty("score_multiplier")] public double ScoreMultiplier { get; set; } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index e0a216c8e0..323cda76d4 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -1,21 +1,41 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuDifficultyAttributes : DifficultyAttributes { + [JsonProperty("aim_strain")] public double AimStrain { get; set; } + + [JsonProperty("speed_strain")] public double SpeedStrain { get; set; } + + [JsonProperty("flashlight_rating")] public double FlashlightRating { get; set; } + + [JsonProperty("slider_factor")] public double SliderFactor { get; set; } + + [JsonProperty("approach_rate")] public double ApproachRate { get; set; } + + [JsonProperty("overall_difficulty")] public double OverallDifficulty { get; set; } + + [JsonProperty("drain_rate")] public double DrainRate { get; set; } + + [JsonProperty("hit_circle_count")] public int HitCircleCount { get; set; } + + [JsonProperty("slider_count")] public int SliderCount { get; set; } + + [JsonProperty("spinner_count")] public int SpinnerCount { get; set; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index 36adbd5a5b..171ac89e6f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -1,16 +1,26 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Rulesets.Taiko.Difficulty { public class TaikoDifficultyAttributes : DifficultyAttributes { + [JsonProperty("stamina_strain")] public double StaminaStrain { get; set; } + + [JsonProperty("rhythm_strain")] public double RhythmStrain { get; set; } + + [JsonProperty("colour_strain")] public double ColourStrain { get; set; } + + [JsonProperty("approach_rate")] public double ApproachRate { get; set; } + + [JsonProperty("great_hit_window")] public double GreatHitWindow { get; set; } } } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 6bb780a68b..fb67396718 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; @@ -8,10 +9,16 @@ namespace osu.Game.Rulesets.Difficulty { public class DifficultyAttributes { + [JsonIgnore] public Mod[] Mods { get; set; } + + [JsonIgnore] public Skill[] Skills { get; set; } + [JsonProperty("star_rating")] public double StarRating { get; set; } + + [JsonProperty("max_combo")] public int MaxCombo { get; set; } public DifficultyAttributes() From 0cfd6fdf0455224de5d8a98be1aaae954e0f82c0 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Nov 2021 16:06:46 +0900 Subject: [PATCH 02/23] Add to/from database mapping functions to difficulty attributes --- .../Difficulty/CatchDifficultyAttributes.cs | 21 +++++++++++ .../Difficulty/ManiaDifficultyAttributes.cs | 21 +++++++++++ .../Difficulty/OsuDifficultyAttributes.cs | 37 +++++++++++++++++++ .../Difficulty/TaikoDifficultyAttributes.cs | 20 ++++++++++ .../Difficulty/DifficultyAttributes.cs | 8 ++++ 5 files changed, 107 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs index 57305ce62b..3f03fc102b 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty; @@ -10,5 +11,25 @@ namespace osu.Game.Rulesets.Catch.Difficulty { [JsonProperty("approach_rate")] public double ApproachRate { get; set; } + + public override IEnumerable<(int attributeId, object value)> ToDatabase() + { + foreach (var v in base.ToDatabase()) + yield return v; + + // Todo: Catch should not output star rating in the 'aim' attribute. + yield return (1, StarRating); + yield return (7, ApproachRate); + yield return (9, MaxCombo); + } + + public override void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + { + base.FromDatabase(values, hitCircleCount, spinnerCount); + + StarRating = values[1]; + ApproachRate = values[7]; + MaxCombo = (int)values[9]; + } } } diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs index dd966ca859..d1cb48f728 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty; @@ -13,5 +14,25 @@ namespace osu.Game.Rulesets.Mania.Difficulty [JsonProperty("score_multiplier")] public double ScoreMultiplier { get; set; } + + public override IEnumerable<(int attributeId, object value)> ToDatabase() + { + foreach (var v in base.ToDatabase()) + yield return v; + + // Todo: Mania doesn't output MaxCombo attribute for some reason. + yield return (11, StarRating); + yield return (13, GreatHitWindow); + yield return (15, ScoreMultiplier); + } + + public override void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + { + base.FromDatabase(values, hitCircleCount, spinnerCount); + + StarRating = values[11]; + GreatHitWindow = values[13]; + ScoreMultiplier = values[15]; + } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 323cda76d4..75d1eed1ab 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -1,8 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Osu.Difficulty { @@ -37,5 +40,39 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonProperty("spinner_count")] public int SpinnerCount { get; set; } + + public override IEnumerable<(int attributeId, object value)> ToDatabase() + { + foreach (var v in base.ToDatabase()) + yield return v; + + yield return (1, AimStrain); + yield return (3, SpeedStrain); + yield return (5, OverallDifficulty); + yield return (7, ApproachRate); + yield return (9, MaxCombo); + yield return (11, StarRating); + + if (Mods.Any(m => m is ModFlashlight)) + yield return (17, FlashlightRating); + + yield return (19, SliderFactor); + } + + public override void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + { + base.FromDatabase(values, hitCircleCount, spinnerCount); + + AimStrain = values[1]; + SpeedStrain = values[3]; + OverallDifficulty = values[5]; + ApproachRate = values[7]; + MaxCombo = (int)values[9]; + StarRating = values[11]; + FlashlightRating = values.GetValueOrDefault(17); + SliderFactor = values[19]; + HitCircleCount = hitCircleCount; + SpinnerCount = spinnerCount; + } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index 171ac89e6f..b2208ea617 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty; @@ -22,5 +23,24 @@ namespace osu.Game.Rulesets.Taiko.Difficulty [JsonProperty("great_hit_window")] public double GreatHitWindow { get; set; } + + public override IEnumerable<(int attributeId, object value)> ToDatabase() + { + foreach (var v in base.ToDatabase()) + yield return v; + + yield return (9, MaxCombo); + yield return (11, StarRating); + yield return (13, GreatHitWindow); + } + + public override void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + { + base.FromDatabase(values, hitCircleCount, spinnerCount); + + MaxCombo = (int)values[9]; + StarRating = values[11]; + GreatHitWindow = values[13]; + } } } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index fb67396718..96d52833e0 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; @@ -31,5 +33,11 @@ namespace osu.Game.Rulesets.Difficulty Skills = skills; StarRating = starRating; } + + public virtual IEnumerable<(int attributeId, object value)> ToDatabase() => Enumerable.Empty<(int, object)>(); + + public virtual void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + { + } } } From 45382a81277ae4f5663bded357cc8d9920eacef2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Nov 2021 16:32:25 +0900 Subject: [PATCH 03/23] Ignore some properties --- .../Difficulty/OsuDifficultyAttributes.cs | 8 ++++---- osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 75d1eed1ab..0d76cb855b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -29,16 +29,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonProperty("overall_difficulty")] public double OverallDifficulty { get; set; } - [JsonProperty("drain_rate")] + [JsonIgnore] public double DrainRate { get; set; } - [JsonProperty("hit_circle_count")] + [JsonIgnore] public int HitCircleCount { get; set; } - [JsonProperty("slider_count")] + [JsonIgnore] public int SliderCount { get; set; } - [JsonProperty("spinner_count")] + [JsonIgnore] public int SpinnerCount { get; set; } public override IEnumerable<(int attributeId, object value)> ToDatabase() diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 96d52833e0..6a3b97ab1d 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -17,10 +17,10 @@ namespace osu.Game.Rulesets.Difficulty [JsonIgnore] public Skill[] Skills { get; set; } - [JsonProperty("star_rating")] + [JsonProperty("star_rating", Order = -3)] public double StarRating { get; set; } - [JsonProperty("max_combo")] + [JsonProperty("max_combo", Order = -2)] public int MaxCombo { get; set; } public DifficultyAttributes() From 21c0882b74d3267361ff2c9b55cf00b7408435e6 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Nov 2021 17:24:53 +0900 Subject: [PATCH 04/23] Don't serialize FL rating without FL mod --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 0d76cb855b..089f163dfb 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using Newtonsoft.Json; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; @@ -74,5 +75,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty HitCircleCount = hitCircleCount; SpinnerCount = spinnerCount; } + + [UsedImplicitly] + public bool ShouldSerializeFlashlightRating() => Mods.OfType().Any(); } } From c8a01c35f76fd0a85d242aabb6f788f7d8bd8634 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Nov 2021 18:11:07 +0900 Subject: [PATCH 05/23] Remove extra members from FromDatabaseAttributes --- .../Difficulty/CatchDifficultyAttributes.cs | 8 ++++---- .../Difficulty/ManiaDifficultyAttributes.cs | 8 ++++---- .../Difficulty/OsuDifficultyAttributes.cs | 10 ++++------ .../Difficulty/TaikoDifficultyAttributes.cs | 8 ++++---- osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs | 4 ++-- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs index 3f03fc102b..ca63e87f8d 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs @@ -12,9 +12,9 @@ namespace osu.Game.Rulesets.Catch.Difficulty [JsonProperty("approach_rate")] public double ApproachRate { get; set; } - public override IEnumerable<(int attributeId, object value)> ToDatabase() + public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() { - foreach (var v in base.ToDatabase()) + foreach (var v in base.ToDatabaseAttributes()) yield return v; // Todo: Catch should not output star rating in the 'aim' attribute. @@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Catch.Difficulty yield return (9, MaxCombo); } - public override void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + public override void FromDatabaseAttributes(IReadOnlyDictionary values) { - base.FromDatabase(values, hitCircleCount, spinnerCount); + base.FromDatabaseAttributes(values); StarRating = values[1]; ApproachRate = values[7]; diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs index d1cb48f728..1e663fe103 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs @@ -15,9 +15,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty [JsonProperty("score_multiplier")] public double ScoreMultiplier { get; set; } - public override IEnumerable<(int attributeId, object value)> ToDatabase() + public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() { - foreach (var v in base.ToDatabase()) + foreach (var v in base.ToDatabaseAttributes()) yield return v; // Todo: Mania doesn't output MaxCombo attribute for some reason. @@ -26,9 +26,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty yield return (15, ScoreMultiplier); } - public override void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + public override void FromDatabaseAttributes(IReadOnlyDictionary values) { - base.FromDatabase(values, hitCircleCount, spinnerCount); + base.FromDatabaseAttributes(values); StarRating = values[11]; GreatHitWindow = values[13]; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 089f163dfb..88f26db93c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -42,9 +42,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonIgnore] public int SpinnerCount { get; set; } - public override IEnumerable<(int attributeId, object value)> ToDatabase() + public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() { - foreach (var v in base.ToDatabase()) + foreach (var v in base.ToDatabaseAttributes()) yield return v; yield return (1, AimStrain); @@ -60,9 +60,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty yield return (19, SliderFactor); } - public override void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + public override void FromDatabaseAttributes(IReadOnlyDictionary values) { - base.FromDatabase(values, hitCircleCount, spinnerCount); + base.FromDatabaseAttributes(values); AimStrain = values[1]; SpeedStrain = values[3]; @@ -72,8 +72,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty StarRating = values[11]; FlashlightRating = values.GetValueOrDefault(17); SliderFactor = values[19]; - HitCircleCount = hitCircleCount; - SpinnerCount = spinnerCount; } [UsedImplicitly] diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index b2208ea617..a6057d7952 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -24,9 +24,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty [JsonProperty("great_hit_window")] public double GreatHitWindow { get; set; } - public override IEnumerable<(int attributeId, object value)> ToDatabase() + public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() { - foreach (var v in base.ToDatabase()) + foreach (var v in base.ToDatabaseAttributes()) yield return v; yield return (9, MaxCombo); @@ -34,9 +34,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty yield return (13, GreatHitWindow); } - public override void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + public override void FromDatabaseAttributes(IReadOnlyDictionary values) { - base.FromDatabase(values, hitCircleCount, spinnerCount); + base.FromDatabaseAttributes(values); MaxCombo = (int)values[9]; StarRating = values[11]; diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 6a3b97ab1d..e25a8476f0 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -34,9 +34,9 @@ namespace osu.Game.Rulesets.Difficulty StarRating = starRating; } - public virtual IEnumerable<(int attributeId, object value)> ToDatabase() => Enumerable.Empty<(int, object)>(); + public virtual IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() => Enumerable.Empty<(int, object)>(); - public virtual void FromDatabase(IReadOnlyDictionary values, int hitCircleCount, int spinnerCount) + public virtual void FromDatabaseAttributes(IReadOnlyDictionary values) { } } From 2c45a327bb20713d74368f79a0500a07de860ee0 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Nov 2021 19:54:35 +0900 Subject: [PATCH 06/23] Remove JsonIgnores, require opt-in properties --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs | 4 ---- osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 88f26db93c..7673d08440 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -30,16 +30,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonProperty("overall_difficulty")] public double OverallDifficulty { get; set; } - [JsonIgnore] public double DrainRate { get; set; } - [JsonIgnore] public int HitCircleCount { get; set; } - [JsonIgnore] public int SliderCount { get; set; } - [JsonIgnore] public int SpinnerCount { get; set; } public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index e25a8476f0..cc9d111aa2 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -9,12 +9,11 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Difficulty { + [JsonObject(MemberSerialization.OptIn)] public class DifficultyAttributes { - [JsonIgnore] public Mod[] Mods { get; set; } - [JsonIgnore] public Skill[] Skills { get; set; } [JsonProperty("star_rating", Order = -3)] From 49cdcffa3008897850b0fe1072fa1fecf8c731b5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Nov 2021 16:58:44 +0900 Subject: [PATCH 07/23] Simplify schedule logic in `DrawableRoomPlaylistItem` --- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 85cee46a29..a1e3bfdd8b 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; @@ -87,23 +86,15 @@ namespace osu.Game.Screens.OnlinePlay SelectedItem.BindValueChanged(selected => maskingContainer.BorderThickness = selected.NewValue == Model ? 5 : 0, true); - beatmap.BindValueChanged(_ => scheduleRefresh()); - ruleset.BindValueChanged(_ => scheduleRefresh()); - - requiredMods.CollectionChanged += (_, __) => scheduleRefresh(); + beatmap.BindValueChanged(_ => Scheduler.AddOnce(refresh)); + ruleset.BindValueChanged(_ => Scheduler.AddOnce(refresh)); + requiredMods.CollectionChanged += (_, __) => Scheduler.AddOnce(refresh); refresh(); } - private ScheduledDelegate scheduledRefresh; private PanelBackground panelBackground; - private void scheduleRefresh() - { - scheduledRefresh?.Cancel(); - scheduledRefresh = Schedule(refresh); - } - private void refresh() { difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) }; From aa188d5a52fa5004d5219596af75d9387ad81995 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Nov 2021 17:01:24 +0900 Subject: [PATCH 08/23] Add ability for playlist items to be marked as invalid --- osu.Game/Online/Rooms/PlaylistItem.cs | 7 +++++++ .../Screens/OnlinePlay/DrawableRoomPlaylistItem.cs | 14 +++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Rooms/PlaylistItem.cs b/osu.Game/Online/Rooms/PlaylistItem.cs index cb550281a9..4a94191a34 100644 --- a/osu.Game/Online/Rooms/PlaylistItem.cs +++ b/osu.Game/Online/Rooms/PlaylistItem.cs @@ -30,6 +30,11 @@ namespace osu.Game.Online.Rooms [JsonProperty("expired")] public bool Expired { get; set; } + [JsonIgnore] + public IBindable Valid => valid; + + private readonly Bindable valid = new BindableBool(true); + [JsonIgnore] public readonly Bindable Beatmap = new Bindable(); @@ -69,6 +74,8 @@ namespace osu.Game.Online.Rooms Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.ID ?? 0); } + public void MarkInvalid() => valid.Value = false; + public void MapObjects(RulesetStore rulesets) { Beatmap.Value ??= apiBeatmap; diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index a1e3bfdd8b..90cb362d5c 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -45,6 +45,7 @@ namespace osu.Game.Screens.OnlinePlay private ModDisplay modDisplay; private readonly Bindable beatmap = new Bindable(); + private readonly IBindable valid = new Bindable(); private readonly Bindable ruleset = new Bindable(); private readonly BindableList requiredMods = new BindableList(); @@ -65,14 +66,18 @@ namespace osu.Game.Screens.OnlinePlay this.allowSelection = allowSelection; beatmap.BindTo(item.Beatmap); + valid.BindTo(item.Valid); ruleset.BindTo(item.Ruleset); requiredMods.BindTo(item.RequiredMods); ShowDragHandle.Value = allowEdit; } + [Resolved] + private OsuColour colours { get; set; } + [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { if (!allowEdit) HandleColour = HandleColour.Opacity(0); @@ -88,6 +93,7 @@ namespace osu.Game.Screens.OnlinePlay beatmap.BindValueChanged(_ => Scheduler.AddOnce(refresh)); ruleset.BindValueChanged(_ => Scheduler.AddOnce(refresh)); + valid.BindValueChanged(_ => Scheduler.AddOnce(refresh)); requiredMods.CollectionChanged += (_, __) => Scheduler.AddOnce(refresh); refresh(); @@ -97,6 +103,12 @@ namespace osu.Game.Screens.OnlinePlay private void refresh() { + if (!valid.Value) + { + maskingContainer.BorderThickness = 5; + maskingContainer.BorderColour = colours.Red; + } + difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) }; panelBackground.Beatmap.Value = Item.Beatmap.Value; From e78c5d0858479780a8bafaac5462533f5230738d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Nov 2021 17:13:50 +0900 Subject: [PATCH 09/23] Show `loadingLayer` before calling `CreateRoom` This fixes `TestScenePlaylistsMatchSettingsOverlay` incorrectly leaving the loading layer visible. --- .../OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index c2bd7730e9..3bcfb89aa7 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -339,9 +339,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Duration.Value = DurationField.Current.Value; - manager?.CreateRoom(room, onSuccess, onError); - loadingLayer.Show(); + manager?.CreateRoom(room, onSuccess, onError); } private void hideError() => ErrorText.FadeOut(50); From 6f82e6351fabbeb4adc71b36065a7a942664778a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Nov 2021 17:01:37 +0900 Subject: [PATCH 10/23] Parse osu-web error text to present invalid items to the user in a more approachable format --- .../Playlists/PlaylistsRoomSettingsOverlay.cs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index 3bcfb89aa7..cb4a81f108 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Specialized; +using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -349,9 +350,31 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private void onError(string text) { - ErrorText.Text = text; - ErrorText.FadeIn(50); + // see https://github.com/ppy/osu-web/blob/2c97aaeb64fb4ed97c747d8383a35b30f57428c7/app/Models/Multiplayer/PlaylistItem.php#L48. + const string not_found_prefix = "beatmaps not found:"; + if (text.StartsWith(not_found_prefix, StringComparison.Ordinal)) + { + ErrorText.Text = "One or more beatmap was not available online. Please remove or replaced the highlighted items."; + + int[] invalidBeatmapIDs = text + .Substring(not_found_prefix.Length + 1) + .Split(", ") + .Select(int.Parse) + .ToArray(); + + foreach (var item in Playlist) + { + if (invalidBeatmapIDs.Contains(item.BeatmapID)) + item.MarkInvalid(); + } + } + else + { + ErrorText.Text = text; + } + + ErrorText.FadeIn(50); loadingLayer.Hide(); } } From 2d125893fce2f08702ec31e0fc6704cc25a38f45 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Nov 2021 17:08:21 +0900 Subject: [PATCH 11/23] Add tests and disable selection on invalid items --- .../TestSceneDrawableRoomPlaylist.cs | 13 +++++ .../TestScenePlaylistsMatchSettingsOverlay.cs | 52 +++++++++++++++---- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 2 +- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 8ac0a2cbe5..efc3b07d0a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -67,6 +67,19 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("no item selected", () => playlist.SelectedItem.Value == null); } + [Test] + public void TestMarkInvalid() + { + createPlaylist(true, true); + + AddStep("mark item 0 as invalid", () => playlist.Items[0].MarkInvalid()); + + moveToItem(0); + + AddStep("click", () => InputManager.Click(MouseButton.Left)); + AddAssert("no item selected", () => playlist.SelectedItem.Value == null); + } + [Test] public void TestSelectable() { diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index 48222e6b94..278379c692 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Playlists RoomManager.CreateRequested = r => { createdRoom = r; - return true; + return string.Empty; }; }); @@ -82,28 +82,58 @@ namespace osu.Game.Tests.Visual.Playlists AddAssert("has correct duration", () => createdRoom.Duration.Value == expectedDuration); } + [Test] + public void TestInvalidBeatmapError() + { + const string not_found_prefix = "beatmaps not found:"; + + string errorMesage = null; + + AddStep("setup", () => + { + var beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo; + + SelectedRoom.Value.Name.Value = "Test Room"; + SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = beatmap } }); + + errorMesage = $"{not_found_prefix} {beatmap.OnlineID}"; + + RoomManager.CreateRequested = _ => errorMesage; + }); + + AddAssert("error not displayed", () => !settings.ErrorText.IsPresent); + AddAssert("playlist item valid", () => SelectedRoom.Value.Playlist[0].Valid.Value); + + AddStep("create room", () => settings.ApplyButton.Action.Invoke()); + + AddAssert("error displayed", () => settings.ErrorText.IsPresent); + AddAssert("error has custom text", () => settings.ErrorText.Text != errorMesage); + AddAssert("playlist item marked invalid", () => !SelectedRoom.Value.Playlist[0].Valid.Value); + } + [Test] public void TestCreationFailureDisplaysError() { - bool fail; + const string error_message = "failed"; + + string failText = error_message; AddStep("setup", () => { SelectedRoom.Value.Name.Value = "Test Room"; SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = CreateBeatmap(Ruleset.Value).BeatmapInfo } }); - fail = true; - RoomManager.CreateRequested = _ => !fail; + RoomManager.CreateRequested = _ => failText; }); AddAssert("error not displayed", () => !settings.ErrorText.IsPresent); AddStep("create room", () => settings.ApplyButton.Action.Invoke()); AddAssert("error displayed", () => settings.ErrorText.IsPresent); - AddAssert("error has correct text", () => settings.ErrorText.Text == TestRoomManager.FAILED_TEXT); + AddAssert("error has correct text", () => settings.ErrorText.Text == error_message); AddStep("create room no fail", () => { - fail = false; + failText = string.Empty; settings.ApplyButton.Action.Invoke(); }); @@ -132,9 +162,7 @@ namespace osu.Game.Tests.Visual.Playlists protected class TestRoomManager : IRoomManager { - public const string FAILED_TEXT = "failed"; - - public Func CreateRequested; + public Func CreateRequested; public event Action RoomsUpdated { @@ -157,8 +185,10 @@ namespace osu.Game.Tests.Visual.Playlists if (CreateRequested == null) return; - if (!CreateRequested.Invoke(room)) - onError?.Invoke(FAILED_TEXT); + string error = CreateRequested.Invoke(room); + + if (!string.IsNullOrEmpty(error)) + onError?.Invoke(error); else onSuccess?.Invoke(room); } diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 90cb362d5c..7af858f1f8 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -281,7 +281,7 @@ namespace osu.Game.Screens.OnlinePlay protected override bool OnClick(ClickEvent e) { - if (allowSelection) + if (allowSelection && valid.Value) SelectedItem.Value = Model; return true; } From 8e9b55ef6dbd061666e75b4b1228eeaa43d93bd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Nov 2021 11:28:43 +0900 Subject: [PATCH 12/23] Disallow selection of invalid items --- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 2fa1a79ddd..96ff44fab5 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -90,7 +90,24 @@ namespace osu.Game.Screens.OnlinePlay { base.LoadComplete(); - SelectedItem.BindValueChanged(selected => maskingContainer.BorderThickness = selected.NewValue == Model ? 5 : 0, true); + SelectedItem.BindValueChanged(selected => + { + bool isCurrent = selected.NewValue == Model; + + if (!valid.Value) + { + // Don't allow selection when not valid. + if (isCurrent) + { + SelectedItem.Value = selected.OldValue; + } + + // Don't update border when not valid (the border is displaying this fact). + return; + } + + maskingContainer.BorderThickness = isCurrent ? 5 : 0; + }, true); beatmap.BindValueChanged(_ => Scheduler.AddOnce(refresh)); ruleset.BindValueChanged(_ => Scheduler.AddOnce(refresh)); From d600a7327704dea2bd70a7e2f181c3ecacc8fbf3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Nov 2021 11:38:41 +0900 Subject: [PATCH 13/23] Disable cancelling of update via notification --- osu.Desktop/Updater/SquirrelUpdateManager.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index 910751a723..d48c9e9661 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -183,6 +183,19 @@ namespace osu.Desktop.Updater } }); } + + public override void Close() + { + // cancelling updates is not currently supported by the underlying updater. + // only allow dismissing for now. + + switch (State) + { + case ProgressNotificationState.Cancelled: + base.Close(); + break; + } + } } private class SquirrelLogger : Splat.ILogger, IDisposable From 96e983bbad1cdd70108eb9a37c4a9a205606c6a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Nov 2021 14:40:05 +0900 Subject: [PATCH 14/23] Disallow playlist item selection at playlist room creation screen Wasn't being used for anything, confusing that it's even possible. --- .../OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index cb4a81f108..7d96e5303c 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -205,7 +205,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { new Drawable[] { - playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both } + playlist = new DrawableRoomPlaylist(true, false) { RelativeSizeAxes = Axes.Both } }, new Drawable[] { From abb333299bcddd0ecb5f2b4fe1aed1073f118063 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 17 Nov 2021 20:20:54 +0900 Subject: [PATCH 15/23] Document base class --- .../Difficulty/DifficultyAttributes.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index cc9d111aa2..1073f689dd 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -9,23 +9,47 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Difficulty { + /// + /// Describes the difficulty of a beatmap, as output by a . + /// [JsonObject(MemberSerialization.OptIn)] public class DifficultyAttributes { + /// + /// The mods which were applied to the beatmap. + /// public Mod[] Mods { get; set; } + /// + /// The skills resulting from the difficulty calculation. + /// public Skill[] Skills { get; set; } + /// + /// The combined star rating of all skill. + /// [JsonProperty("star_rating", Order = -3)] public double StarRating { get; set; } + /// + /// The maximum achievable combo. + /// [JsonProperty("max_combo", Order = -2)] public int MaxCombo { get; set; } + /// + /// Creates new . + /// public DifficultyAttributes() { } + /// + /// Creates new . + /// + /// The mods which were applied to the beatmap. + /// The skills resulting from the difficulty calculation. + /// The combined star rating of all skills. public DifficultyAttributes(Mod[] mods, Skill[] skills, double starRating) { Mods = mods; @@ -33,8 +57,18 @@ namespace osu.Game.Rulesets.Difficulty StarRating = starRating; } + /// + /// Converts this to osu-web compatible database attribute mappings. + /// + /// + /// See: osu_difficulty_attribs table. + /// public virtual IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() => Enumerable.Empty<(int, object)>(); + /// + /// Reads osu-web database attribute mappings into this object. + /// + /// The attribute mappings. public virtual void FromDatabaseAttributes(IReadOnlyDictionary values) { } From 2ae46f901e7785adeb064f1a73733787e679c2cf Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 17 Nov 2021 20:22:43 +0900 Subject: [PATCH 16/23] Add comment for implicitly-used method --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 7673d08440..14a5a3e745 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -70,6 +70,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty SliderFactor = values[19]; } + // Used implicitly by Newtonsoft.Json to not serialize flashlight property in some cases. [UsedImplicitly] public bool ShouldSerializeFlashlightRating() => Mods.OfType().Any(); } From 43cbb23b159ad9a3887cdcb63ae1f80a5e7c5695 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 17 Nov 2021 20:23:08 +0900 Subject: [PATCH 17/23] Use ShouldSerializeFlashlightRating() to serialise database attribute --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 14a5a3e745..a22b605176 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty yield return (9, MaxCombo); yield return (11, StarRating); - if (Mods.Any(m => m is ModFlashlight)) + if (ShouldSerializeFlashlightRating()) yield return (17, FlashlightRating); yield return (19, SliderFactor); @@ -72,6 +72,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Used implicitly by Newtonsoft.Json to not serialize flashlight property in some cases. [UsedImplicitly] - public bool ShouldSerializeFlashlightRating() => Mods.OfType().Any(); + public bool ShouldSerializeFlashlightRating() => Mods.Any(m => m is ModFlashlight); } } From 815179f713dd2d1f7b636ebdd0bf387d821fbd35 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 17 Nov 2021 20:31:18 +0900 Subject: [PATCH 18/23] Use consts for attribute IDs --- .../Difficulty/CatchDifficultyAttributes.cs | 14 ++++---- .../Difficulty/ManiaDifficultyAttributes.cs | 14 ++++---- .../Difficulty/OsuDifficultyAttributes.cs | 32 +++++++++---------- .../Difficulty/TaikoDifficultyAttributes.cs | 12 +++---- .../Difficulty/DifficultyAttributes.cs | 11 +++++++ 5 files changed, 47 insertions(+), 36 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs index ca63e87f8d..39a58d336d 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs @@ -17,19 +17,19 @@ namespace osu.Game.Rulesets.Catch.Difficulty foreach (var v in base.ToDatabaseAttributes()) yield return v; - // Todo: Catch should not output star rating in the 'aim' attribute. - yield return (1, StarRating); - yield return (7, ApproachRate); - yield return (9, 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 (ATTRIB_ID_MAX_COMBO, MaxCombo); } public override void FromDatabaseAttributes(IReadOnlyDictionary values) { base.FromDatabaseAttributes(values); - StarRating = values[1]; - ApproachRate = values[7]; - MaxCombo = (int)values[9]; + StarRating = values[ATTRIB_ID_AIM]; + ApproachRate = values[ATTRIB_ID_APPROACH_RATE]; + MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO]; } } } diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs index 1e663fe103..bfdef893e9 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs @@ -20,19 +20,19 @@ namespace osu.Game.Rulesets.Mania.Difficulty foreach (var v in base.ToDatabaseAttributes()) yield return v; - // Todo: Mania doesn't output MaxCombo attribute for some reason. - yield return (11, StarRating); - yield return (13, GreatHitWindow); - yield return (15, ScoreMultiplier); + // Todo: osu!mania doesn't output MaxCombo attribute for some reason. + yield return (ATTRIB_ID_STRAIN, StarRating); + yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow); + yield return (ATTRIB_ID_SCORE_MULTIPLIER, ScoreMultiplier); } public override void FromDatabaseAttributes(IReadOnlyDictionary values) { base.FromDatabaseAttributes(values); - StarRating = values[11]; - GreatHitWindow = values[13]; - ScoreMultiplier = values[15]; + StarRating = values[ATTRIB_ID_STRAIN]; + GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW]; + ScoreMultiplier = values[ATTRIB_ID_SCORE_MULTIPLIER]; } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index a22b605176..4b2e54da17 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -43,31 +43,31 @@ namespace osu.Game.Rulesets.Osu.Difficulty foreach (var v in base.ToDatabaseAttributes()) yield return v; - yield return (1, AimStrain); - yield return (3, SpeedStrain); - yield return (5, OverallDifficulty); - yield return (7, ApproachRate); - yield return (9, MaxCombo); - yield return (11, StarRating); + yield return (ATTRIB_ID_AIM, AimStrain); + yield return (ATTRIB_ID_SPEED, SpeedStrain); + yield return (ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty); + yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate); + yield return (ATTRIB_ID_MAX_COMBO, MaxCombo); + yield return (ATTRIB_ID_STRAIN, StarRating); if (ShouldSerializeFlashlightRating()) - yield return (17, FlashlightRating); + yield return (ATTRIB_ID_FLASHLIGHT, FlashlightRating); - yield return (19, SliderFactor); + yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor); } public override void FromDatabaseAttributes(IReadOnlyDictionary values) { base.FromDatabaseAttributes(values); - AimStrain = values[1]; - SpeedStrain = values[3]; - OverallDifficulty = values[5]; - ApproachRate = values[7]; - MaxCombo = (int)values[9]; - StarRating = values[11]; - FlashlightRating = values.GetValueOrDefault(17); - SliderFactor = values[19]; + AimStrain = values[ATTRIB_ID_AIM]; + SpeedStrain = values[ATTRIB_ID_SPEED]; + OverallDifficulty = values[ATTRIB_ID_OVERALL_DIFFICULTY]; + ApproachRate = values[ATTRIB_ID_APPROACH_RATE]; + MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO]; + StarRating = values[ATTRIB_ID_STRAIN]; + FlashlightRating = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT); + SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR]; } // Used implicitly by Newtonsoft.Json to not serialize flashlight property in some cases. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index a6057d7952..b2b5d056c3 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -29,18 +29,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty foreach (var v in base.ToDatabaseAttributes()) yield return v; - yield return (9, MaxCombo); - yield return (11, StarRating); - yield return (13, GreatHitWindow); + yield return (ATTRIB_ID_MAX_COMBO, MaxCombo); + yield return (ATTRIB_ID_STRAIN, StarRating); + yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow); } public override void FromDatabaseAttributes(IReadOnlyDictionary values) { base.FromDatabaseAttributes(values); - MaxCombo = (int)values[9]; - StarRating = values[11]; - GreatHitWindow = values[13]; + MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO]; + StarRating = values[ATTRIB_ID_STRAIN]; + GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW]; } } } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 1073f689dd..320321440a 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -72,5 +72,16 @@ namespace osu.Game.Rulesets.Difficulty public virtual void FromDatabaseAttributes(IReadOnlyDictionary values) { } + + protected const int ATTRIB_ID_AIM = 1; + protected const int ATTRIB_ID_SPEED = 3; + protected const int ATTRIB_ID_OVERALL_DIFFICULTY = 5; + protected const int ATTRIB_ID_APPROACH_RATE = 7; + protected const int ATTRIB_ID_MAX_COMBO = 9; + protected const int ATTRIB_ID_STRAIN = 11; + protected const int ATTRIB_ID_GREAT_HIT_WINDOW = 13; + protected const int ATTRIB_ID_SCORE_MULTIPLIER = 15; + protected const int ATTRIB_ID_FLASHLIGHT = 17; + protected const int ATTRIB_ID_SLIDER_FACTOR = 19; } } From 0a7498014fa7125929e93cab6f1682771ec58a32 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Nov 2021 20:47:52 +0900 Subject: [PATCH 19/23] Move `const`s to top of file --- .../Difficulty/DifficultyAttributes.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 320321440a..e0d27799ce 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -15,6 +15,17 @@ namespace osu.Game.Rulesets.Difficulty [JsonObject(MemberSerialization.OptIn)] public class DifficultyAttributes { + protected const int ATTRIB_ID_AIM = 1; + protected const int ATTRIB_ID_SPEED = 3; + protected const int ATTRIB_ID_OVERALL_DIFFICULTY = 5; + protected const int ATTRIB_ID_APPROACH_RATE = 7; + protected const int ATTRIB_ID_MAX_COMBO = 9; + protected const int ATTRIB_ID_STRAIN = 11; + protected const int ATTRIB_ID_GREAT_HIT_WINDOW = 13; + protected const int ATTRIB_ID_SCORE_MULTIPLIER = 15; + protected const int ATTRIB_ID_FLASHLIGHT = 17; + protected const int ATTRIB_ID_SLIDER_FACTOR = 19; + /// /// The mods which were applied to the beatmap. /// @@ -72,16 +83,5 @@ namespace osu.Game.Rulesets.Difficulty public virtual void FromDatabaseAttributes(IReadOnlyDictionary values) { } - - protected const int ATTRIB_ID_AIM = 1; - protected const int ATTRIB_ID_SPEED = 3; - protected const int ATTRIB_ID_OVERALL_DIFFICULTY = 5; - protected const int ATTRIB_ID_APPROACH_RATE = 7; - protected const int ATTRIB_ID_MAX_COMBO = 9; - protected const int ATTRIB_ID_STRAIN = 11; - protected const int ATTRIB_ID_GREAT_HIT_WINDOW = 13; - protected const int ATTRIB_ID_SCORE_MULTIPLIER = 15; - protected const int ATTRIB_ID_FLASHLIGHT = 17; - protected const int ATTRIB_ID_SLIDER_FACTOR = 19; } } From 7c2e79f911b1d09d9c0a022cdf3c4b59cb770367 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Nov 2021 18:46:11 +0900 Subject: [PATCH 20/23] Update all simple cases of switching to `IWorkingBeatmap` --- .../TestSceneDrawableHitObjects.cs | 2 +- .../DrawableTaikoRulesetTestScene.cs | 2 +- .../Skins/TestSceneBeatmapSkinResources.cs | 2 +- .../Editing/TestSceneHitObjectComposer.cs | 4 ++-- .../Visual/Editing/TestSceneWaveform.cs | 2 +- .../Visual/Gameplay/TestScenePlayerLoader.cs | 5 ++-- .../TestScenePlayerReferenceLeaking.cs | 2 +- .../Visual/Gameplay/TestSceneStoryboard.cs | 2 +- .../Menus/TestSceneMusicActionHandling.cs | 4 ++-- .../Navigation/TestScenePresentBeatmap.cs | 3 ++- .../Navigation/TestSceneScreenNavigation.cs | 4 ++-- .../TestSceneBeatmapMetadataDisplay.cs | 2 +- .../SongSelect/TestScenePlaySongSelect.cs | 23 ++++++++++--------- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- .../Drawables/BeatmapBackgroundSprite.cs | 4 ++-- osu.Game/Online/Chat/NowPlayingCommand.cs | 4 ++-- .../Screens/Play/BeatmapMetadataDisplay.cs | 4 ++-- osu.Game/Screens/Play/Player.cs | 4 ++-- .../Select/BeatmapInfoWedgeBackground.cs | 4 ++-- .../Select/Carousel/SetPanelBackground.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- osu.Game/Storyboards/Storyboard.cs | 2 +- osu.Game/Users/UserActivity.cs | 14 +++++------ 24 files changed, 52 insertions(+), 49 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs index 3c61eb19e5..459b8e1f6f 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Tests var controlPointInfo = new ControlPointInfo(); controlPointInfo.Add(0, new TimingControlPoint()); - WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap + IWorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap { HitObjects = new List { new Fruit() }, BeatmapInfo = new BeatmapInfo diff --git a/osu.Game.Rulesets.Taiko.Tests/DrawableTaikoRulesetTestScene.cs b/osu.Game.Rulesets.Taiko.Tests/DrawableTaikoRulesetTestScene.cs index 783636a62d..4bdb85ba60 100644 --- a/osu.Game.Rulesets.Taiko.Tests/DrawableTaikoRulesetTestScene.cs +++ b/osu.Game.Rulesets.Taiko.Tests/DrawableTaikoRulesetTestScene.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Tests var controlPointInfo = new ControlPointInfo(); controlPointInfo.Add(0, new TimingControlPoint()); - WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap + IWorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap { HitObjects = new List { new Hit { Type = HitType.Centre } }, BeatmapInfo = new BeatmapInfo diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs index f03cda1489..1d8b754837 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Skins [Resolved] private BeatmapManager beatmaps { get; set; } - private WorkingBeatmap beatmap; + private IWorkingBeatmap beatmap; [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs index c758bd1707..eee0d6672c 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs @@ -81,11 +81,11 @@ namespace osu.Game.Tests.Visual.Editing public class EditorBeatmapContainer : Container { - private readonly WorkingBeatmap working; + private readonly IWorkingBeatmap working; public EditorBeatmap EditorBeatmap { get; private set; } - public EditorBeatmapContainer(WorkingBeatmap working) + public EditorBeatmapContainer(IWorkingBeatmap working) { this.working = working; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneWaveform.cs b/osu.Game.Tests/Visual/Editing/TestSceneWaveform.cs index c3a5a0e944..eb7e90f0a7 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneWaveform.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneWaveform.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Editing [TestFixture] public class TestSceneWaveform : OsuTestScene { - private WorkingBeatmap waveformBeatmap; + private IWorkingBeatmap waveformBeatmap; [BackgroundDependencyLoader] private void load(AudioManager audio) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index ba0ee5ac6e..06eaa726c9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -95,8 +95,9 @@ namespace osu.Game.Tests.Visual.Gameplay private void prepareBeatmap() { - Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); - Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning; + var workingBeatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); + workingBeatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning; + Beatmap.Value = workingBeatmap; foreach (var mod in SelectedMods.Value.OfType()) mod.ApplyToTrack(Beatmap.Value.Track); diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs index 8f767659c6..7c2f1c5bb2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs @@ -12,7 +12,7 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestScenePlayerReferenceLeaking : TestSceneAllRulesetPlayers { - private readonly WeakList workingWeakReferences = new WeakList(); + private readonly WeakList workingWeakReferences = new WeakList(); private readonly WeakList playerWeakReferences = new WeakList(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs index 5a2b8d22fd..3b6d02c67c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.Gameplay track.Start(); } - private void loadStoryboard(WorkingBeatmap working) + private void loadStoryboard(IWorkingBeatmap working) { if (storyboard != null) storyboardContainer.Remove(storyboard); diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs index 79dfe79299..6dda8df6f0 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Menus public void TestMusicNavigationActions() { int importId = 0; - Queue<(WorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null; + Queue<(IWorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null; // ensure we have at least two beatmaps available to identify the direction the music controller navigated to. AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(new BeatmapSetInfo @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Menus AddStep("bind to track change", () => { - trackChangeQueue = new Queue<(WorkingBeatmap, TrackChangeDirection)>(); + trackChangeQueue = new Queue<(IWorkingBeatmap, TrackChangeDirection)>(); Game.MusicController.TrackChanged += (working, changeDirection) => trackChangeQueue.Enqueue((working, changeDirection)); }); diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs index ff976c7bf6..d1ee984682 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs @@ -7,6 +7,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Screens; using osu.Game.Beatmaps; +using osu.Game.Extensions; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; @@ -139,7 +140,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("present beatmap", () => Game.PresentBeatmap(getImport())); AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect); - AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.ID == getImport().ID); + AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.MatchesOnlineID(getImport())); AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID); } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 5d4594c415..ef71c54e03 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -96,7 +96,7 @@ namespace osu.Game.Tests.Visual.Navigation Player player = null; ResultsScreen results = null; - WorkingBeatmap beatmap() => Game.Beatmap.Value; + IWorkingBeatmap beatmap() => Game.Beatmap.Value; PushAndConfirm(() => new TestPlaySongSelect()); @@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.Navigation { Player player = null; - WorkingBeatmap beatmap() => Game.Beatmap.Value; + IWorkingBeatmap beatmap() => Game.Beatmap.Value; PushAndConfirm(() => new TestPlaySongSelect()); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs index 9473b058cc..11d589f7bc 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs @@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.SongSelect }); } - private void showMetadataForBeatmap(Func getBeatmap) + private void showMetadataForBeatmap(Func getBeatmap) { AddStep("setup display", () => { diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index ee5a61f21f..3646b52cfa 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -17,6 +17,7 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Extensions; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; @@ -360,7 +361,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(target)); // this is an important check, to make sure updateComponentFromBeatmap() was actually run - AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target)); + AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target)); } [Test] @@ -392,7 +393,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("has correct ruleset", () => Ruleset.Value.ID == 0); // this is an important check, to make sure updateComponentFromBeatmap() was actually run - AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target)); + AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target)); } [Test] @@ -672,7 +673,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for selection", () => !Beatmap.IsDefault); - AddStep("record set ID", () => previousSetID = Beatmap.Value.BeatmapSetInfo.ID); + AddStep("record set ID", () => previousSetID = ((IBeatmapSetInfo)Beatmap.Value.BeatmapSetInfo).OnlineID); AddAssert("selection changed once", () => changeCount == 1); AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0); @@ -683,8 +684,8 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("selection changed", () => changeCount > 1); - AddAssert("Selected beatmap still same set", () => Beatmap.Value.BeatmapSetInfo.ID == previousSetID); - AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.ID == 3); + AddAssert("Selected beatmap still same set", () => Beatmap.Value.BeatmapSetInfo.OnlineID == previousSetID); + AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3); AddAssert("selection changed only fired twice", () => changeCount == 2); @@ -727,7 +728,7 @@ namespace osu.Game.Tests.Visual.SongSelect int previousSetID = 0; - AddStep("record set ID", () => previousSetID = Beatmap.Value.BeatmapSetInfo.ID); + AddStep("record set ID", () => previousSetID = ((IBeatmapSetInfo)Beatmap.Value.BeatmapSetInfo).OnlineID); AddStep("Click on a difficulty", () => { @@ -739,7 +740,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet.ID == previousSetID); - AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.ID == 3); + AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3); } [Test] @@ -784,7 +785,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); - AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.Equals(groupIcon.Items.First().BeatmapInfo)); + AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(groupIcon.Items.First().BeatmapInfo)); } [Test] @@ -815,7 +816,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen()); - AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.Equals(getPresentBeatmap())); + AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap())); AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0); } @@ -847,7 +848,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen()); - AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.Equals(getPresentBeatmap())); + AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap())); AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0); } @@ -960,7 +961,7 @@ namespace osu.Game.Tests.Visual.SongSelect public new FilterControl FilterControl => base.FilterControl; public WorkingBeatmap CurrentBeatmap => Beatmap.Value; - public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; + public IWorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; public new BeatmapCarousel Carousel => base.Carousel; public new void PresentScore(ScoreInfo score) => base.PresentScore(score); diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 7231409dc5..0e9a92989c 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -151,7 +151,7 @@ namespace osu.Game.Beatmaps }, token, TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously, updateScheduler); } - public Task> GetTimedDifficultyAttributesAsync(WorkingBeatmap beatmap, Ruleset ruleset, Mod[] mods, CancellationToken token = default) + public Task> GetTimedDifficultyAttributesAsync(IWorkingBeatmap beatmap, Ruleset ruleset, Mod[] mods, CancellationToken token = default) { return Task.Factory.StartNew(() => ruleset.CreateDifficultyCalculator(beatmap).CalculateTimed(mods), token, diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 48a6663adb..c2a2e93caf 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -179,7 +179,7 @@ namespace osu.Game.Beatmaps /// /// A default representation of a WorkingBeatmap to use when no beatmap is available. /// - public WorkingBeatmap DefaultBeatmap => workingBeatmapCache.DefaultBeatmap; + public IWorkingBeatmap DefaultBeatmap => workingBeatmapCache.DefaultBeatmap; /// /// Fired when a notification should be presented to the user. diff --git a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs index 0c59eec1ef..916df429a4 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs @@ -9,9 +9,9 @@ namespace osu.Game.Beatmaps.Drawables { public class BeatmapBackgroundSprite : Sprite { - private readonly WorkingBeatmap working; + private readonly IWorkingBeatmap working; - public BeatmapBackgroundSprite(WorkingBeatmap working) + public BeatmapBackgroundSprite(IWorkingBeatmap working) { if (working == null) throw new ArgumentNullException(nameof(working)); diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 34b12c23e6..2bf35d7973 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -37,7 +37,7 @@ namespace osu.Game.Online.Chat base.LoadComplete(); string verb; - BeatmapInfo beatmapInfo; + IBeatmapInfo beatmapInfo; switch (api.Activity.Value) { @@ -57,7 +57,7 @@ namespace osu.Game.Online.Chat break; } - string beatmapString = beatmapInfo.OnlineID.HasValue ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfo}]" : beatmapInfo.ToString(); + string beatmapString = beatmapInfo.OnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfo}]" : beatmapInfo.ToString(); channelManager.PostMessage($"is {verb} {beatmapString}", true, target); Expire(); diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 430571e1da..795dddfaf5 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Play /// public class BeatmapMetadataDisplay : Container { - private readonly WorkingBeatmap beatmap; + private readonly IWorkingBeatmap beatmap; private readonly Bindable> mods; private readonly Drawable logoFacade; private LoadingSpinner loading; @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Play } } - public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable logoFacade) + public BeatmapMetadataDisplay(IWorkingBeatmap beatmap, Bindable> mods, Drawable logoFacade) { this.beatmap = beatmap; this.logoFacade = logoFacade; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 1381493fdf..4d574dea99 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -354,7 +354,7 @@ namespace osu.Game.Screens.Play private Drawable createUnderlayComponents() => DimmableStoryboard = new DimmableStoryboard(Beatmap.Value.Storyboard) { RelativeSizeAxes = Axes.Both }; - private Drawable createGameplayComponents(WorkingBeatmap working, IBeatmap playableBeatmap) => new ScalingContainer(ScalingMode.Gameplay) + private Drawable createGameplayComponents(IWorkingBeatmap working, IBeatmap playableBeatmap) => new ScalingContainer(ScalingMode.Gameplay) { Children = new Drawable[] { @@ -372,7 +372,7 @@ namespace osu.Game.Screens.Play } }; - private Drawable createOverlayComponents(WorkingBeatmap working) + private Drawable createOverlayComponents(IWorkingBeatmap working) { var container = new Container { diff --git a/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs b/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs index 25056790cc..d9b8a20846 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs @@ -15,9 +15,9 @@ namespace osu.Game.Screens.Select { internal class BeatmapInfoWedgeBackground : CompositeDrawable { - private readonly WorkingBeatmap beatmap; + private readonly IWorkingBeatmap beatmap; - public BeatmapInfoWedgeBackground(WorkingBeatmap beatmap) + public BeatmapInfoWedgeBackground(IWorkingBeatmap beatmap) { this.beatmap = beatmap; } diff --git a/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs b/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs index b4279cce51..2a37969be1 100644 --- a/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs +++ b/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Select.Carousel { public class SetPanelBackground : BufferedContainer { - public SetPanelBackground(WorkingBeatmap working) + public SetPanelBackground(IWorkingBeatmap working) : base(cachedFrameBuffer: true) { RedrawOnScale = false; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 4da15ee53c..aef00a9b00 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -671,7 +671,7 @@ namespace osu.Game.Screens.Select music.TrackChanged -= ensureTrackLooping; } - private void ensureTrackLooping(WorkingBeatmap beatmap, TrackChangeDirection changeDirection) + private void ensureTrackLooping(IWorkingBeatmap beatmap, TrackChangeDirection changeDirection) => beatmap.PrepareTrackForPreviewLooping(); public override bool OnBackButton() diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 9e3d3df915..d3d6797eae 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -89,7 +89,7 @@ namespace osu.Game.Storyboards } } - public DrawableStoryboard CreateDrawable(WorkingBeatmap working = null) => + public DrawableStoryboard CreateDrawable(IWorkingBeatmap working = null) => new DrawableStoryboard(this); public Drawable CreateSpriteFromResourcePath(string path, TextureStore textureStore) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 91bcb37fcc..0874685f49 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -27,11 +27,11 @@ namespace osu.Game.Users public abstract class InGame : UserActivity { - public BeatmapInfo BeatmapInfo { get; } + public IBeatmapInfo BeatmapInfo { get; } public RulesetInfo Ruleset { get; } - protected InGame(BeatmapInfo beatmapInfo, RulesetInfo ruleset) + protected InGame(IBeatmapInfo beatmapInfo, RulesetInfo ruleset) { BeatmapInfo = beatmapInfo; Ruleset = ruleset; @@ -42,7 +42,7 @@ namespace osu.Game.Users public class InMultiplayerGame : InGame { - public InMultiplayerGame(BeatmapInfo beatmapInfo, RulesetInfo ruleset) + public InMultiplayerGame(IBeatmapInfo beatmapInfo, RulesetInfo ruleset) : base(beatmapInfo, ruleset) { } @@ -52,7 +52,7 @@ namespace osu.Game.Users public class InPlaylistGame : InGame { - public InPlaylistGame(BeatmapInfo beatmapInfo, RulesetInfo ruleset) + public InPlaylistGame(IBeatmapInfo beatmapInfo, RulesetInfo ruleset) : base(beatmapInfo, ruleset) { } @@ -60,7 +60,7 @@ namespace osu.Game.Users public class InSoloGame : InGame { - public InSoloGame(BeatmapInfo beatmapInfo, RulesetInfo ruleset) + public InSoloGame(IBeatmapInfo beatmapInfo, RulesetInfo ruleset) : base(beatmapInfo, ruleset) { } @@ -68,9 +68,9 @@ namespace osu.Game.Users public class Editing : UserActivity { - public BeatmapInfo BeatmapInfo { get; } + public IBeatmapInfo BeatmapInfo { get; } - public Editing(BeatmapInfo info) + public Editing(IBeatmapInfo info) { BeatmapInfo = info; } From a4953b5658a9f3dd71a4907fc032837ee6eed15a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Nov 2021 11:34:46 +0900 Subject: [PATCH 21/23] Update some remaining test usage of database ID --- .../Visual/SongSelect/TestScenePlaySongSelect.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 3646b52cfa..0437c1b25b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -508,13 +508,13 @@ namespace osu.Game.Tests.Visual.SongSelect i.IsFiltered || i.Item.BeatmapInfo.Ruleset.ID == targetRuleset || i.Item.BeatmapInfo.Ruleset.ID == 0); }); - AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineID == target.OnlineID); - AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineID == target.OnlineID); + AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true); + AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target)); AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = string.Empty); - AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.OnlineID == target.OnlineID); - AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmapInfo.OnlineID == target.OnlineID); + AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.MatchesOnlineID(target) == true); + AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmapInfo.MatchesOnlineID(target)); } [Test] @@ -545,8 +545,8 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null); - AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineID == target.OnlineID); - AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineID == target.OnlineID); + AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true); + AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target)); AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nononoo"); @@ -739,7 +739,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); - AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet.ID == previousSetID); + AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet.OnlineID == previousSetID); AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3); } From 5fb5baa4c9d5442f8cb14b6c06577e2c829504af Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 17 Nov 2021 21:06:33 +0900 Subject: [PATCH 22/23] Adjust error message --- .../OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index 7d96e5303c..dc773b7762 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -355,7 +355,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists if (text.StartsWith(not_found_prefix, StringComparison.Ordinal)) { - ErrorText.Text = "One or more beatmap was not available online. Please remove or replaced the highlighted items."; + ErrorText.Text = "One or more beatmaps were not available online. Please remove or replaced the highlighted items."; int[] invalidBeatmapIDs = text .Substring(not_found_prefix.Length + 1) From 214705f1e528cc53e820bbc01a33313e61d608da Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Nov 2021 21:11:37 +0900 Subject: [PATCH 23/23] Adjust error message, take 2 --- .../OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index dc773b7762..27c8dc1120 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -355,7 +355,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists if (text.StartsWith(not_found_prefix, StringComparison.Ordinal)) { - ErrorText.Text = "One or more beatmaps were not available online. Please remove or replaced the highlighted items."; + ErrorText.Text = "One or more beatmaps were not available online. Please remove or replace the highlighted items."; int[] invalidBeatmapIDs = text .Substring(not_found_prefix.Length + 1)