Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor difficulty icons to not suck #18819

Merged
merged 10 commits into from
Jun 24, 2022
4 changes: 2 additions & 2 deletions osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -872,10 +872,10 @@ public void TestGroupedDifficultyIconSelecting()
return set != null;
});

FilterableGroupedDifficultyIcon groupIcon = null;
GroupedDifficultyIcon groupIcon = null;
AddUntilStep("Find group icon for different ruleset", () =>
{
return (groupIcon = set.ChildrenOfType<FilterableGroupedDifficultyIcon>()
return (groupIcon = set.ChildrenOfType<GroupedDifficultyIcon>()
.FirstOrDefault(icon => icon.Items.First().BeatmapInfo.Ruleset.OnlineID == 3)) != null;
});

Expand Down
131 changes: 36 additions & 95 deletions osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

using System;
using System.Collections.Generic;
using System.Threading;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
Expand All @@ -16,19 +10,17 @@
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Beatmaps.Drawables
{
public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip<DifficultyIconTooltipContent>
public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip<DifficultyIconTooltipContent>, IHasCurrentValue<StarDifficulty>
{
private readonly Container iconContainer;

/// <summary>
/// Size of this difficulty icon.
/// </summary>
Expand All @@ -38,58 +30,54 @@ public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip<DifficultyIco
set => iconContainer.Size = value;
}

[NotNull]
private readonly IBeatmapInfo beatmapInfo;
/// <summary>
/// Whether to display a tooltip on hover. Only works if a beatmap was provided at construction time.
/// </summary>
public bool ShowTooltip { get; set; } = true;

private readonly IBeatmapInfo? beatmap;

[CanBeNull]
private readonly IRulesetInfo ruleset;

[CanBeNull]
private readonly IReadOnlyList<Mod> mods;
private Drawable background = null!;

private readonly bool shouldShowTooltip;
private readonly Container iconContainer;

private readonly bool performBackgroundDifficultyLookup;
private readonly BindableWithCurrent<StarDifficulty> difficulty = new BindableWithCurrent<StarDifficulty>();

private readonly Bindable<StarDifficulty> difficultyBindable = new Bindable<StarDifficulty>();
public virtual Bindable<StarDifficulty> Current
{
get => difficulty.Current;
set => difficulty.Current = value;
}

private Drawable background;
[Resolved]
private IRulesetStore rulesets { get; set; } = null!;

/// <summary>
/// Creates a new <see cref="DifficultyIcon"/> with a given <see cref="RulesetInfo"/> and <see cref="Mod"/> combination.
/// Creates a new <see cref="DifficultyIcon"/>. Will use provided beatmap's <see cref="BeatmapInfo.StarRating"/> for initial value.
/// </summary>
/// <param name="beatmapInfo">The beatmap to show the difficulty of.</param>
/// <param name="ruleset">The ruleset to show the difficulty with.</param>
/// <param name="mods">The mods to show the difficulty with.</param>
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
/// <param name="performBackgroundDifficultyLookup">Whether to perform difficulty lookup (including calculation if necessary).</param>
public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList<Mod> mods, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
: this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup)
/// <param name="beatmap">The beatmap to be displayed in the tooltip, and to be used for the initial star rating value.</param>
/// <param name="ruleset">An optional ruleset to be used for the icon display, in place of the beatmap's ruleset.</param>
public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null)
: this(ruleset ?? beatmap.Ruleset)
{
this.ruleset = ruleset ?? beatmapInfo.Ruleset;
this.mods = mods ?? Array.Empty<Mod>();
this.beatmap = beatmap;
Current.Value = new StarDifficulty(beatmap.StarRating, 0);
}

/// <summary>
/// Creates a new <see cref="DifficultyIcon"/> that follows the currently-selected ruleset and mods.
/// Creates a new <see cref="DifficultyIcon"/> without an associated beatmap.
/// </summary>
/// <param name="beatmapInfo">The beatmap to show the difficulty of.</param>
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
/// <param name="performBackgroundDifficultyLookup">Whether to perform difficulty lookup (including calculation if necessary).</param>
public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
/// <param name="ruleset">The ruleset to be used for the icon display.</param>
public DifficultyIcon(IRulesetInfo ruleset)
{
this.beatmapInfo = beatmapInfo ?? throw new ArgumentNullException(nameof(beatmapInfo));
this.shouldShowTooltip = shouldShowTooltip;
this.performBackgroundDifficultyLookup = performBackgroundDifficultyLookup;
this.ruleset = ruleset;

AutoSizeAxes = Axes.Both;

InternalChild = iconContainer = new Container { Size = new Vector2(20f) };
}

[Resolved]
private IRulesetStore rulesets { get; set; }

[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Expand All @@ -111,7 +99,6 @@ private void load(OsuColour colours)
Child = background = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.ForStarDifficulty(beatmapInfo.StarRating) // Default value that will be re-populated once difficulty calculation completes
},
},
new ConstrainedIconContainer
Expand All @@ -124,69 +111,23 @@ private void load(OsuColour colours)
},
};

if (performBackgroundDifficultyLookup)
iconContainer.Add(new DelayedLoadUnloadWrapper(() => new DifficultyRetriever(beatmapInfo, ruleset, mods) { StarDifficulty = { BindTarget = difficultyBindable } }, 0));
else
difficultyBindable.Value = new StarDifficulty(beatmapInfo.StarRating, 0);

difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars));
Current.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars), true);
}

private Drawable getRulesetIcon()
{
int? onlineID = (ruleset ?? beatmapInfo.Ruleset).OnlineID;
int? onlineID = ruleset.OnlineID;

if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance)
return rulesetInstance.CreateIcon();

return new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle };
}

ITooltip<DifficultyIconTooltipContent> IHasCustomTooltip<DifficultyIconTooltipContent>.GetCustomTooltip() => new DifficultyIconTooltip();
ITooltip<DifficultyIconTooltipContent> IHasCustomTooltip<DifficultyIconTooltipContent>.
GetCustomTooltip() => new DifficultyIconTooltip();
Comment on lines -145 to +128
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this automated by rider? I've also seen this happening locally on any file I can touch recently, not sure if something changed in the configuration somewhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say so.


DifficultyIconTooltipContent IHasCustomTooltip<DifficultyIconTooltipContent>.TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmapInfo, difficultyBindable) : null;

private class DifficultyRetriever : Component
{
public readonly Bindable<StarDifficulty> StarDifficulty = new Bindable<StarDifficulty>();

private readonly IBeatmapInfo beatmapInfo;
private readonly IRulesetInfo ruleset;
private readonly IReadOnlyList<Mod> mods;

private CancellationTokenSource difficultyCancellation;

[Resolved]
private BeatmapDifficultyCache difficultyCache { get; set; }

public DifficultyRetriever(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, IReadOnlyList<Mod> mods)
{
this.beatmapInfo = beatmapInfo;
this.ruleset = ruleset;
this.mods = mods;
}

private IBindable<StarDifficulty?> localStarDifficulty;

[BackgroundDependencyLoader]
private void load()
{
difficultyCancellation = new CancellationTokenSource();
localStarDifficulty = ruleset != null
? difficultyCache.GetBindableDifficulty(beatmapInfo, ruleset, mods, difficultyCancellation.Token)
: difficultyCache.GetBindableDifficulty(beatmapInfo, difficultyCancellation.Token);
localStarDifficulty.BindValueChanged(d =>
{
if (d.NewValue is StarDifficulty diff)
StarDifficulty.Value = diff;
});
}

protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
difficultyCancellation?.Cancel();
}
}
DifficultyIconTooltipContent IHasCustomTooltip<DifficultyIconTooltipContent>.
TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current) : null)!;
}
}
39 changes: 0 additions & 39 deletions osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs

This file was deleted.

4 changes: 3 additions & 1 deletion osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,10 @@ public DifficultySelectorButton(APIBeatmap beatmapInfo)
Alpha = 0.5f
}
},
icon = new DifficultyIcon(beatmapInfo, shouldShowTooltip: false)
icon = new DifficultyIcon(beatmapInfo)
{
ShowTooltip = false,
Current = { Value = new StarDifficulty(beatmapInfo.StarRating, 0) },
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(size - tile_icon_padding * 2),
Expand Down
78 changes: 0 additions & 78 deletions osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs

This file was deleted.

2 changes: 1 addition & 1 deletion osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ private void refresh()
}

if (beatmap != null)
difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(icon_height) };
difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset) { Size = new Vector2(icon_height) };
else
difficultyIconContainer.Clear();

Expand Down
7 changes: 6 additions & 1 deletion osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ public class DrawableCarouselBeatmap : DrawableCarouselItem, IHasContextMenu
private Action<BeatmapInfo> hideRequested;

private Triangles triangles;

private StarCounter starCounter;
private DifficultyIcon difficultyIcon;

[Resolved(CanBeNull = true)]
private BeatmapSetOverlay beatmapOverlay { get; set; }
Expand Down Expand Up @@ -113,8 +115,9 @@ private void load(BeatmapManager manager, SongSelect songSelect)
Origin = Anchor.CentreLeft,
Children = new Drawable[]
{
new DifficultyIcon(beatmapInfo, shouldShowTooltip: false)
difficultyIcon = new DifficultyIcon(beatmapInfo)
{
ShowTooltip = false,
Scale = new Vector2(1.8f),
},
new FillFlowContainer
Expand Down Expand Up @@ -216,6 +219,8 @@ protected override void ApplyState()
starDifficultyBindable.BindValueChanged(d =>
{
starCounter.Current = (float)(d.NewValue?.Stars ?? 0);
if (d.NewValue != null)
difficultyIcon.Current.Value = d.NewValue.Value;
}, true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class FilterableDifficultyIcon : DifficultyIcon
public readonly CarouselBeatmap Item;

public FilterableDifficultyIcon(CarouselBeatmap item)
: base(item.BeatmapInfo, performBackgroundDifficultyLookup: false)
: base(item.BeatmapInfo)
{
filtered.BindTo(item.Filtered);
filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100));
Expand Down
Loading