From 34d471522018be48cd9f0e0e4e9e947467c647b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 29 Oct 2021 11:48:36 +0900 Subject: [PATCH 1/6] Allow for `long` online IDs and implement in `ScoreInfo` --- osu.Game/Beatmaps/IBeatmapInfo.cs | 2 +- osu.Game/Beatmaps/IBeatmapSetInfo.cs | 2 +- osu.Game/Database/IHasOnlineID.cs | 4 ++-- osu.Game/Rulesets/IRulesetInfo.cs | 2 +- osu.Game/Scoring/ScoreInfo.cs | 4 +++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/IBeatmapInfo.cs b/osu.Game/Beatmaps/IBeatmapInfo.cs index 3d51c5d4b6..d206cfaaed 100644 --- a/osu.Game/Beatmaps/IBeatmapInfo.cs +++ b/osu.Game/Beatmaps/IBeatmapInfo.cs @@ -11,7 +11,7 @@ namespace osu.Game.Beatmaps /// /// A single beatmap difficulty. /// - public interface IBeatmapInfo : IHasOnlineID + public interface IBeatmapInfo : IHasOnlineID { /// /// The user-specified name given to this beatmap. diff --git a/osu.Game/Beatmaps/IBeatmapSetInfo.cs b/osu.Game/Beatmaps/IBeatmapSetInfo.cs index 0cfb0c4242..20c46d9063 100644 --- a/osu.Game/Beatmaps/IBeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/IBeatmapSetInfo.cs @@ -12,7 +12,7 @@ namespace osu.Game.Beatmaps /// /// A representation of a collection of beatmap difficulties, generally packaged as an ".osz" archive. /// - public interface IBeatmapSetInfo : IHasOnlineID + public interface IBeatmapSetInfo : IHasOnlineID { /// /// The date when this beatmap was imported. diff --git a/osu.Game/Database/IHasOnlineID.cs b/osu.Game/Database/IHasOnlineID.cs index 6e2be7e1f9..36ae4035c4 100644 --- a/osu.Game/Database/IHasOnlineID.cs +++ b/osu.Game/Database/IHasOnlineID.cs @@ -5,7 +5,7 @@ namespace osu.Game.Database { - public interface IHasOnlineID + public interface IHasOnlineID { /// /// The server-side ID representing this instance, if one exists. Any value 0 or less denotes a missing ID. @@ -14,6 +14,6 @@ namespace osu.Game.Database /// Generally we use -1 when specifying "missing" in code, but values of 0 are also considered missing as the online source /// is generally a MySQL autoincrement value, which can never be 0. /// - int OnlineID { get; } + T OnlineID { get; } } } diff --git a/osu.Game/Rulesets/IRulesetInfo.cs b/osu.Game/Rulesets/IRulesetInfo.cs index 779433dc81..c3bc6c1995 100644 --- a/osu.Game/Rulesets/IRulesetInfo.cs +++ b/osu.Game/Rulesets/IRulesetInfo.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets /// /// A representation of a ruleset's metadata. /// - public interface IRulesetInfo : IHasOnlineID + public interface IRulesetInfo : IHasOnlineID { /// /// The user-exposed name of this ruleset. diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 5cf22f7945..8eaec0a477 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -19,7 +19,7 @@ using osu.Game.Utils; namespace osu.Game.Scoring { - public class ScoreInfo : IHasFiles, IHasPrimaryKey, ISoftDelete, IEquatable, IDeepCloneable + public class ScoreInfo : IHasFiles, IHasPrimaryKey, ISoftDelete, IEquatable, IDeepCloneable, IHasOnlineID { public int ID { get; set; } @@ -271,5 +271,7 @@ namespace osu.Game.Scoring return ReferenceEquals(this, other); } + + public long OnlineID => OnlineScoreID ?? -1; } } From be0564f7326960959970c398203bac1e8ed4280f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 29 Oct 2021 17:03:50 +0900 Subject: [PATCH 2/6] Update `DifficultyIcon` classes to use `IBeatmapInfo` --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 23 +++++++++++-------- .../Drawables/DifficultyIconTooltip.cs | 6 ++--- .../Drawables/GroupedDifficultyIcon.cs | 6 ++--- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 880d70aec2..3a55b9261f 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -37,10 +37,10 @@ namespace osu.Game.Beatmaps.Drawables } [NotNull] - private readonly BeatmapInfo beatmapInfo; + private readonly IBeatmapInfo beatmapInfo; [CanBeNull] - private readonly RulesetInfo ruleset; + private readonly IRulesetInfo ruleset; [CanBeNull] private readonly IReadOnlyList mods; @@ -60,7 +60,7 @@ namespace osu.Game.Beatmaps.Drawables /// The ruleset to show the difficulty with. /// The mods to show the difficulty with. /// Whether to display a tooltip when hovered. - public DifficultyIcon([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo ruleset, [CanBeNull] IReadOnlyList mods, bool shouldShowTooltip = true) + public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList mods, bool shouldShowTooltip = true) : this(beatmapInfo, shouldShowTooltip) { this.ruleset = ruleset ?? beatmapInfo.Ruleset; @@ -73,7 +73,7 @@ namespace osu.Game.Beatmaps.Drawables /// The beatmap to show the difficulty of. /// Whether to display a tooltip when hovered. /// Whether to perform difficulty lookup (including calculation if necessary). - public DifficultyIcon([NotNull] BeatmapInfo beatmapInfo, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true) + public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true) { this.beatmapInfo = beatmapInfo ?? throw new ArgumentNullException(nameof(beatmapInfo)); this.shouldShowTooltip = shouldShowTooltip; @@ -84,6 +84,9 @@ namespace osu.Game.Beatmaps.Drawables InternalChild = iconContainer = new Container { Size = new Vector2(20f) }; } + [Resolved] + private RulesetStore rulesets { get; set; } + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -105,7 +108,7 @@ namespace osu.Game.Beatmaps.Drawables Child = background = new Box { RelativeSizeAxes = Axes.Both, - Colour = colours.ForStarDifficulty(beatmapInfo.StarDifficulty) // Default value that will be re-populated once difficulty calculation completes + Colour = colours.ForStarDifficulty(beatmapInfo.StarRating) // Default value that will be re-populated once difficulty calculation completes }, }, new ConstrainedIconContainer @@ -114,14 +117,14 @@ namespace osu.Game.Beatmaps.Drawables Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, // the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment) - Icon = (ruleset ?? beatmapInfo.Ruleset)?.CreateInstance()?.CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle } + Icon = rulesets.GetRuleset((ruleset ?? beatmapInfo.Ruleset).OnlineID)?.CreateInstance()?.CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle } }, }; if (performBackgroundDifficultyLookup) iconContainer.Add(new DelayedLoadUnloadWrapper(() => new DifficultyRetriever(beatmapInfo, ruleset, mods) { StarDifficulty = { BindTarget = difficultyBindable } }, 0)); else - difficultyBindable.Value = new StarDifficulty(beatmapInfo.StarDifficulty, 0); + difficultyBindable.Value = new StarDifficulty(beatmapInfo.StarRating, 0); difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars)); } @@ -134,8 +137,8 @@ namespace osu.Game.Beatmaps.Drawables { public readonly Bindable StarDifficulty = new Bindable(); - private readonly BeatmapInfo beatmapInfo; - private readonly RulesetInfo ruleset; + private readonly IBeatmapInfo beatmapInfo; + private readonly IRulesetInfo ruleset; private readonly IReadOnlyList mods; private CancellationTokenSource difficultyCancellation; @@ -143,7 +146,7 @@ namespace osu.Game.Beatmaps.Drawables [Resolved] private BeatmapDifficultyCache difficultyCache { get; set; } - public DifficultyRetriever(BeatmapInfo beatmapInfo, RulesetInfo ruleset, IReadOnlyList mods) + public DifficultyRetriever(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, IReadOnlyList mods) { this.beatmapInfo = beatmapInfo; this.ruleset = ruleset; diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index d4c9f83a0a..ec4bcbd65f 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -89,7 +89,7 @@ namespace osu.Game.Beatmaps.Drawables public void SetContent(DifficultyIconTooltipContent content) { - difficultyName.Text = content.BeatmapInfo.Version; + difficultyName.Text = content.BeatmapInfo.DifficultyName; starDifficulty.UnbindAll(); starDifficulty.BindTo(content.Difficulty); @@ -109,10 +109,10 @@ namespace osu.Game.Beatmaps.Drawables internal class DifficultyIconTooltipContent { - public readonly BeatmapInfo BeatmapInfo; + public readonly IBeatmapInfo BeatmapInfo; public readonly IBindable Difficulty; - public DifficultyIconTooltipContent(BeatmapInfo beatmapInfo, IBindable difficulty) + public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty) { BeatmapInfo = beatmapInfo; Difficulty = difficulty; diff --git a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs index fcee4c2f1a..799a02579e 100644 --- a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs @@ -19,8 +19,8 @@ namespace osu.Game.Beatmaps.Drawables /// public class GroupedDifficultyIcon : DifficultyIcon { - public GroupedDifficultyIcon(List beatmaps, RulesetInfo ruleset, Color4 counterColour) - : base(beatmaps.OrderBy(b => b.StarDifficulty).Last(), ruleset, null, false) + public GroupedDifficultyIcon(IEnumerable beatmaps, IRulesetInfo ruleset, Color4 counterColour) + : base(beatmaps.OrderBy(b => b.StarRating).Last(), ruleset, null, false) { AddInternal(new OsuSpriteText { @@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps.Drawables Padding = new MarginPadding { Left = Size.X }, Margin = new MarginPadding { Left = 2, Right = 5 }, Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), - Text = beatmaps.Count.ToString(), + Text = beatmaps.Count().ToString(), Colour = counterColour, }); } From 7db8bdfb7c01db278088b8aa45c963eef6fad5ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 29 Oct 2021 18:16:53 +0900 Subject: [PATCH 3/6] Fix fallback logic not considering case where ruleset is not available Occurs only in tests. --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 3a55b9261f..6d1984db5b 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -117,7 +117,7 @@ namespace osu.Game.Beatmaps.Drawables Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, // the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment) - Icon = rulesets.GetRuleset((ruleset ?? beatmapInfo.Ruleset).OnlineID)?.CreateInstance()?.CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle } + Icon = getRulesetIcon() }, }; @@ -129,6 +129,16 @@ namespace osu.Game.Beatmaps.Drawables difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars)); } + private Drawable getRulesetIcon() + { + int? onlineID = (ruleset ?? beatmapInfo.Ruleset)?.OnlineID; + + if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance) + return rulesetInstance.CreateIcon(); + + return new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle }; + } + ITooltip IHasCustomTooltip.GetCustomTooltip() => new DifficultyIconTooltip(); DifficultyIconTooltipContent IHasCustomTooltip.TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmapInfo, difficultyBindable) : null; From 07e3ced315fe457eb97e32879c0c061541e201f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 29 Oct 2021 18:22:23 +0900 Subject: [PATCH 4/6] Fix test scene and remove "impossible" nullable coalesce --- osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs | 2 ++ osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 66f15670f5..1eda3be039 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -15,6 +15,7 @@ using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; @@ -868,6 +869,7 @@ namespace osu.Game.Tests.Visual.SongSelect OnlineBeatmapID = id++ * 10, Version = version, StarDifficulty = diff, + Ruleset = new OsuRuleset().RulesetInfo, BaseDifficulty = new BeatmapDifficulty { OverallDifficulty = diff, diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 6d1984db5b..64412675bb 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -131,7 +131,7 @@ namespace osu.Game.Beatmaps.Drawables private Drawable getRulesetIcon() { - int? onlineID = (ruleset ?? beatmapInfo.Ruleset)?.OnlineID; + int? onlineID = (ruleset ?? beatmapInfo.Ruleset).OnlineID; if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance) return rulesetInstance.CreateIcon(); From 04acc7601c2a96906fb6e462391df4502ee61015 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 29 Oct 2021 18:35:15 +0900 Subject: [PATCH 5/6] Fix one more missed case --- osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 1eda3be039..7a38d213d9 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -685,6 +685,7 @@ namespace osu.Game.Tests.Visual.SongSelect set.Beatmaps.Add(new BeatmapInfo { Version = $"Stars: {i}", + Ruleset = new OsuRuleset().RulesetInfo, StarDifficulty = i, }); } From 6e4f7af8d36dbf59d396fec4d1ccdcbed9a0ea45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 30 Oct 2021 14:15:20 +0200 Subject: [PATCH 6/6] Mark `IHasOnlineID` implementation with region --- osu.Game/Scoring/ScoreInfo.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 8eaec0a477..ed3b27dd22 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -272,6 +272,10 @@ namespace osu.Game.Scoring return ReferenceEquals(this, other); } + #region Implementation of IHasOnlineID + public long OnlineID => OnlineScoreID ?? -1; + + #endregion } }