mirror of
https://github.com/osukey/osukey.git
synced 2025-05-26 07:57:32 +09: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);
|
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 CancellationTokenSource trackedUpdateCancellationSource;
|
||||||
private readonly List<CancellationTokenSource> linkedCancellationSources = new List<CancellationTokenSource>();
|
private readonly List<CancellationTokenSource> linkedCancellationSources = new List<CancellationTokenSource>();
|
||||||
|
|
||||||
@ -307,5 +326,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
// Todo: Add more members (BeatmapInfo.DifficultyRating? Attributes? Etc...)
|
// 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; }
|
public List<ScoreInfo> Scores { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public DifficultyRating DifficultyRating
|
public DifficultyRating DifficultyRating => BeatmapDifficultyManager.GetDifficultyRating(StarDifficulty);
|
||||||
{
|
|
||||||
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 string[] SearchableTerms => new[]
|
public string[] SearchableTerms => new[]
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -14,6 +18,7 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -21,9 +26,6 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
{
|
{
|
||||||
public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip
|
public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip
|
||||||
{
|
{
|
||||||
private readonly BeatmapInfo beatmap;
|
|
||||||
private readonly RulesetInfo ruleset;
|
|
||||||
|
|
||||||
private readonly Container iconContainer;
|
private readonly Container iconContainer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -35,23 +37,49 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
set => iconContainer.Size = value;
|
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.beatmap = beatmap ?? throw new ArgumentNullException(nameof(beatmap));
|
||||||
|
this.shouldShowTooltip = shouldShowTooltip;
|
||||||
this.ruleset = ruleset ?? beatmap.Ruleset;
|
|
||||||
if (shouldShowTooltip)
|
|
||||||
TooltipContent = beatmap;
|
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
InternalChild = iconContainer = new Container { Size = new Vector2(20f) };
|
InternalChild = iconContainer = new Container { Size = new Vector2(20f) };
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITooltip GetCustomTooltip() => new DifficultyIconTooltip();
|
|
||||||
|
|
||||||
public object TooltipContent { get; }
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
@ -70,10 +98,10 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
Type = EdgeEffectType.Shadow,
|
Type = EdgeEffectType.Shadow,
|
||||||
Radius = 5,
|
Radius = 5,
|
||||||
},
|
},
|
||||||
Child = new Box
|
Child = background = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
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
|
new ConstrainedIconContainer
|
||||||
@ -82,16 +110,73 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
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)
|
// 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 class DifficultyIconTooltip : VisibilityContainer, ITooltip
|
||||||
{
|
{
|
||||||
private readonly OsuSpriteText difficultyName, starRating;
|
private readonly OsuSpriteText difficultyName, starRating;
|
||||||
private readonly Box background;
|
private readonly Box background;
|
||||||
|
|
||||||
private readonly FillFlowContainer difficultyFlow;
|
private readonly FillFlowContainer difficultyFlow;
|
||||||
|
|
||||||
public DifficultyIconTooltip()
|
public DifficultyIconTooltip()
|
||||||
@ -159,14 +244,22 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
background.Colour = colours.Gray3;
|
background.Colour = colours.Gray3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly IBindable<StarDifficulty> starDifficulty = new Bindable<StarDifficulty>();
|
||||||
|
|
||||||
public bool SetContent(object content)
|
public bool SetContent(object content)
|
||||||
{
|
{
|
||||||
if (!(content is BeatmapInfo beatmap))
|
if (!(content is DifficultyIconTooltipContent iconContent))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
difficultyName.Text = beatmap.Version;
|
difficultyName.Text = iconContent.Beatmap.Version;
|
||||||
starRating.Text = $"{beatmap.StarDifficulty:0.##}";
|
|
||||||
difficultyFlow.Colour = colours.ForDifficultyRating(beatmap.DifficultyRating, true);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
public class GroupedDifficultyIcon : DifficultyIcon
|
public class GroupedDifficultyIcon : DifficultyIcon
|
||||||
{
|
{
|
||||||
public GroupedDifficultyIcon(List<BeatmapInfo> beatmaps, RulesetInfo ruleset, Color4 counterColour)
|
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
|
AddInternal(new OsuSpriteText
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
if (item?.Beatmap != null)
|
if (item?.Beatmap != null)
|
||||||
{
|
{
|
||||||
drawableRuleset.FadeIn(transition_duration);
|
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
|
else
|
||||||
drawableRuleset.FadeOut(transition_duration);
|
drawableRuleset.FadeOut(transition_duration);
|
||||||
|
@ -103,7 +103,7 @@ namespace osu.Game.Screens.Multi
|
|||||||
|
|
||||||
private void refresh()
|
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.Clear();
|
||||||
beatmapText.AddLink(Item.Beatmap.ToString(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString());
|
beatmapText.AddLink(Item.Beatmap.ToString(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user