mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 20:22:55 +08:00
Merge pull request #10306 from smoogipoo/dynamic-difficulty-icon
This commit is contained in:
commit
e20c28f166
@ -114,6 +114,25 @@ namespace osu.Game.Beatmaps
|
||||
return computeDifficulty(key, beatmapInfo, rulesetInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the <see cref="DifficultyRating"/> that describes a star rating.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For more information, see: https://osu.ppy.sh/help/wiki/Difficulties
|
||||
/// </remarks>
|
||||
/// <param name="starRating">The star rating.</param>
|
||||
/// <returns>The <see cref="DifficultyRating"/> that best describes <paramref name="starRating"/>.</returns>
|
||||
public static DifficultyRating GetDifficultyRating(double starRating)
|
||||
{
|
||||
if (starRating < 2.0) return DifficultyRating.Easy;
|
||||
if (starRating < 2.7) return DifficultyRating.Normal;
|
||||
if (starRating < 4.0) return DifficultyRating.Hard;
|
||||
if (starRating < 5.3) return DifficultyRating.Insane;
|
||||
if (starRating < 6.5) return DifficultyRating.Expert;
|
||||
|
||||
return DifficultyRating.ExpertPlus;
|
||||
}
|
||||
|
||||
private CancellationTokenSource trackedUpdateCancellationSource;
|
||||
private readonly List<CancellationTokenSource> linkedCancellationSources = new List<CancellationTokenSource>();
|
||||
|
||||
@ -307,5 +326,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
// Todo: Add more members (BeatmapInfo.DifficultyRating? Attributes? Etc...)
|
||||
}
|
||||
|
||||
public DifficultyRating DifficultyRating => BeatmapDifficultyManager.GetDifficultyRating(Stars);
|
||||
}
|
||||
}
|
||||
|
@ -135,21 +135,7 @@ namespace osu.Game.Beatmaps
|
||||
public List<ScoreInfo> Scores { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public DifficultyRating DifficultyRating
|
||||
{
|
||||
get
|
||||
{
|
||||
var rating = StarDifficulty;
|
||||
|
||||
if (rating < 2.0) return DifficultyRating.Easy;
|
||||
if (rating < 2.7) return DifficultyRating.Normal;
|
||||
if (rating < 4.0) return DifficultyRating.Hard;
|
||||
if (rating < 5.3) return DifficultyRating.Insane;
|
||||
if (rating < 6.5) return DifficultyRating.Expert;
|
||||
|
||||
return DifficultyRating.ExpertPlus;
|
||||
}
|
||||
}
|
||||
public DifficultyRating DifficultyRating => BeatmapDifficultyManager.GetDifficultyRating(StarDifficulty);
|
||||
|
||||
public string[] SearchableTerms => new[]
|
||||
{
|
||||
|
@ -2,7 +2,11 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
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;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -14,6 +18,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -21,9 +26,6 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip
|
||||
{
|
||||
private readonly BeatmapInfo beatmap;
|
||||
private readonly RulesetInfo ruleset;
|
||||
|
||||
private readonly Container iconContainer;
|
||||
|
||||
/// <summary>
|
||||
@ -35,23 +37,49 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
set => iconContainer.Size = value;
|
||||
}
|
||||
|
||||
public DifficultyIcon(BeatmapInfo beatmap, RulesetInfo ruleset = null, bool shouldShowTooltip = true)
|
||||
[NotNull]
|
||||
private readonly BeatmapInfo beatmap;
|
||||
|
||||
[CanBeNull]
|
||||
private readonly RulesetInfo ruleset;
|
||||
|
||||
[CanBeNull]
|
||||
private readonly IReadOnlyList<Mod> mods;
|
||||
|
||||
private readonly bool shouldShowTooltip;
|
||||
private readonly IBindable<StarDifficulty> difficultyBindable = new Bindable<StarDifficulty>();
|
||||
|
||||
private Drawable background;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="DifficultyIcon"/> with a given <see cref="RulesetInfo"/> and <see cref="Mod"/> combination.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">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>
|
||||
public DifficultyIcon([NotNull] BeatmapInfo beatmap, [CanBeNull] RulesetInfo ruleset, [CanBeNull] IReadOnlyList<Mod> mods, bool shouldShowTooltip = true)
|
||||
: this(beatmap, shouldShowTooltip)
|
||||
{
|
||||
this.ruleset = ruleset ?? beatmap.Ruleset;
|
||||
this.mods = mods ?? Array.Empty<Mod>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="DifficultyIcon"/> that follows the currently-selected ruleset and mods.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap to show the difficulty of.</param>
|
||||
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
|
||||
public DifficultyIcon([NotNull] BeatmapInfo beatmap, bool shouldShowTooltip = true)
|
||||
{
|
||||
this.beatmap = beatmap ?? throw new ArgumentNullException(nameof(beatmap));
|
||||
|
||||
this.ruleset = ruleset ?? beatmap.Ruleset;
|
||||
if (shouldShowTooltip)
|
||||
TooltipContent = beatmap;
|
||||
this.shouldShowTooltip = shouldShowTooltip;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
InternalChild = iconContainer = new Container { Size = new Vector2(20f) };
|
||||
}
|
||||
|
||||
public ITooltip GetCustomTooltip() => new DifficultyIconTooltip();
|
||||
|
||||
public object TooltipContent { get; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
@ -70,10 +98,10 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 5,
|
||||
},
|
||||
Child = new Box
|
||||
Child = background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.ForDifficultyRating(beatmap.DifficultyRating),
|
||||
Colour = colours.ForDifficultyRating(beatmap.DifficultyRating) // Default value that will be re-populated once difficulty calculation completes
|
||||
},
|
||||
},
|
||||
new ConstrainedIconContainer
|
||||
@ -82,16 +110,73 @@ 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?.CreateInstance()?.CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle }
|
||||
}
|
||||
Icon = (ruleset ?? beatmap.Ruleset)?.CreateInstance()?.CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle }
|
||||
},
|
||||
new DelayedLoadUnloadWrapper(() => new DifficultyRetriever(beatmap, ruleset, mods) { StarDifficulty = { BindTarget = difficultyBindable } }, 0),
|
||||
};
|
||||
|
||||
difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForDifficultyRating(difficulty.NewValue.DifficultyRating));
|
||||
}
|
||||
|
||||
public ITooltip GetCustomTooltip() => new DifficultyIconTooltip();
|
||||
|
||||
public object TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmap, difficultyBindable) : null;
|
||||
|
||||
private class DifficultyRetriever : Component
|
||||
{
|
||||
public readonly Bindable<StarDifficulty> StarDifficulty = new Bindable<StarDifficulty>();
|
||||
|
||||
private readonly BeatmapInfo beatmap;
|
||||
private readonly RulesetInfo ruleset;
|
||||
private readonly IReadOnlyList<Mod> mods;
|
||||
|
||||
private CancellationTokenSource difficultyCancellation;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapDifficultyManager difficultyManager { get; set; }
|
||||
|
||||
public DifficultyRetriever(BeatmapInfo beatmap, RulesetInfo ruleset, IReadOnlyList<Mod> mods)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
this.ruleset = ruleset;
|
||||
this.mods = mods;
|
||||
}
|
||||
|
||||
private IBindable<StarDifficulty> localStarDifficulty;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
difficultyCancellation = new CancellationTokenSource();
|
||||
localStarDifficulty = ruleset != null
|
||||
? difficultyManager.GetBindableDifficulty(beatmap, ruleset, mods, difficultyCancellation.Token)
|
||||
: difficultyManager.GetBindableDifficulty(beatmap, difficultyCancellation.Token);
|
||||
localStarDifficulty.BindValueChanged(difficulty => StarDifficulty.Value = difficulty.NewValue);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
difficultyCancellation?.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private class DifficultyIconTooltipContent
|
||||
{
|
||||
public readonly BeatmapInfo Beatmap;
|
||||
public readonly IBindable<StarDifficulty> Difficulty;
|
||||
|
||||
public DifficultyIconTooltipContent(BeatmapInfo beatmap, IBindable<StarDifficulty> difficulty)
|
||||
{
|
||||
Beatmap = beatmap;
|
||||
Difficulty = difficulty;
|
||||
}
|
||||
}
|
||||
|
||||
private class DifficultyIconTooltip : VisibilityContainer, ITooltip
|
||||
{
|
||||
private readonly OsuSpriteText difficultyName, starRating;
|
||||
private readonly Box background;
|
||||
|
||||
private readonly FillFlowContainer difficultyFlow;
|
||||
|
||||
public DifficultyIconTooltip()
|
||||
@ -159,14 +244,22 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
background.Colour = colours.Gray3;
|
||||
}
|
||||
|
||||
private readonly IBindable<StarDifficulty> starDifficulty = new Bindable<StarDifficulty>();
|
||||
|
||||
public bool SetContent(object content)
|
||||
{
|
||||
if (!(content is BeatmapInfo beatmap))
|
||||
if (!(content is DifficultyIconTooltipContent iconContent))
|
||||
return false;
|
||||
|
||||
difficultyName.Text = beatmap.Version;
|
||||
starRating.Text = $"{beatmap.StarDifficulty:0.##}";
|
||||
difficultyFlow.Colour = colours.ForDifficultyRating(beatmap.DifficultyRating, true);
|
||||
difficultyName.Text = iconContent.Beatmap.Version;
|
||||
|
||||
starDifficulty.UnbindAll();
|
||||
starDifficulty.BindTo(iconContent.Difficulty);
|
||||
starDifficulty.BindValueChanged(difficulty =>
|
||||
{
|
||||
starRating.Text = $"{difficulty.NewValue.Stars:0.##}";
|
||||
difficultyFlow.Colour = colours.ForDifficultyRating(difficulty.NewValue.DifficultyRating, true);
|
||||
}, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
public class GroupedDifficultyIcon : DifficultyIcon
|
||||
{
|
||||
public GroupedDifficultyIcon(List<BeatmapInfo> beatmaps, RulesetInfo ruleset, Color4 counterColour)
|
||||
: base(beatmaps.OrderBy(b => b.StarDifficulty).Last(), ruleset, false)
|
||||
: base(beatmaps.OrderBy(b => b.StarDifficulty).Last(), ruleset, null, false)
|
||||
{
|
||||
AddInternal(new OsuSpriteText
|
||||
{
|
||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Screens.Multi.Components
|
||||
if (item?.Beatmap != null)
|
||||
{
|
||||
drawableRuleset.FadeIn(transition_duration);
|
||||
drawableRuleset.Child = new DifficultyIcon(item.Beatmap.Value, item.Ruleset.Value) { Size = new Vector2(height) };
|
||||
drawableRuleset.Child = new DifficultyIcon(item.Beatmap.Value, item.Ruleset.Value, item.RequiredMods) { Size = new Vector2(height) };
|
||||
}
|
||||
else
|
||||
drawableRuleset.FadeOut(transition_duration);
|
||||
|
@ -103,7 +103,7 @@ namespace osu.Game.Screens.Multi
|
||||
|
||||
private void refresh()
|
||||
{
|
||||
difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value) { Size = new Vector2(32) };
|
||||
difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods) { Size = new Vector2(32) };
|
||||
|
||||
beatmapText.Clear();
|
||||
beatmapText.AddLink(Item.Beatmap.ToString(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString());
|
||||
|
Loading…
Reference in New Issue
Block a user