diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore_Tooltip.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore_Tooltip.cs index 80ff3513e5..d0a7299597 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore_Tooltip.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore_Tooltip.cs @@ -120,19 +120,12 @@ namespace osu.Game.Screens.SelectV2 var generalStatistics = new[] { + new PerformanceStatisticRow(BeatmapsetsStrings.ShowScoreboardHeaderspp.ToUpper(), colourProvider.Content2, score), new StatisticRow("Score Multiplier", colourProvider.Content2, ModUtils.FormatScoreMultiplier(multiplier)), new StatisticRow(BeatmapsetsStrings.ShowScoreboardHeadersCombo, colourProvider.Content2, value.MaxCombo.ToLocalisableString(@"0\x")), new StatisticRow(BeatmapsetsStrings.ShowScoreboardHeadersAccuracy, colourProvider.Content2, value.Accuracy.FormatAccuracy()), }; - if (value.PP != null) - { - generalStatistics = new[] - { - new StatisticRow(BeatmapsetsStrings.ShowScoreboardHeaderspp.ToUpper(), colourProvider.Content2, value.PP.ToLocalisableString("N0")) - }.Concat(generalStatistics).ToArray(); - } - statistics.ChildrenEnumerable = judgementsStatistics .Append(Empty().With(d => d.Height = 20)) .Concat(generalStatistics); @@ -229,8 +222,10 @@ namespace osu.Game.Screens.SelectV2 => absoluteDate.Text = score.Date.ToLocalTime().ToLocalisableString(prefer24HourTime.Value ? @"d MMMM yyyy HH:mm" : @"d MMMM yyyy h:mm tt"); } - private partial class StatisticRow : CompositeDrawable + public partial class StatisticRow : CompositeDrawable { + protected OsuSpriteText ValueLabel; + public StatisticRow(LocalisableString label, Color4 labelColour, LocalisableString value) { RelativeSizeAxes = Axes.X; @@ -244,7 +239,7 @@ namespace osu.Game.Screens.SelectV2 Colour = labelColour, Font = OsuFont.Style.Caption2.With(weight: FontWeight.SemiBold), }, - new OsuSpriteText + ValueLabel = new OsuSpriteText { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore_Tooltip_PerformanceStatisticRow.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore_Tooltip_PerformanceStatisticRow.cs new file mode 100644 index 0000000000..cefab86edc --- /dev/null +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore_Tooltip_PerformanceStatisticRow.cs @@ -0,0 +1,83 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mods; +using osu.Game.Scoring; +using osuTK.Graphics; + +namespace osu.Game.Screens.SelectV2 +{ + public partial class BeatmapLeaderboardScore + { + public partial class LeaderboardScoreTooltip + { + public partial class PerformanceStatisticRow : StatisticRow + { + private readonly ScoreInfo score; + + public PerformanceStatisticRow(LocalisableString label, Color4 labelColour, ScoreInfo score) + : base(label, labelColour, 0.ToLocalisableString("N0")) + { + this.score = score; + } + + [BackgroundDependencyLoader] + private void load(BeatmapDifficultyCache difficultyCache, CancellationToken? cancellationToken) + { + if (score.PP.HasValue) + { + setPerformanceValue(score, score.PP.Value); + return; + } + + Task.Run(async () => + { + var attributes = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo!, score.Ruleset, score.Mods, cancellationToken ?? default).ConfigureAwait(false); + var performanceCalculator = score.Ruleset.CreateInstance().CreatePerformanceCalculator(); + + // Performance calculation requires the beatmap and ruleset to be locally available. If not, return a default value. + if (attributes?.DifficultyAttributes == null || performanceCalculator == null) + return; + + var result = await performanceCalculator.CalculateAsync(score, attributes.Value.DifficultyAttributes, cancellationToken ?? default).ConfigureAwait(false); + + Schedule(() => setPerformanceValue(score, result.Total)); + }, cancellationToken ?? default); + } + + private void setPerformanceValue(ScoreInfo scoreInfo, double? pp) + { + if (pp.HasValue) + { + int ppValue = (int)Math.Round(pp.Value, MidpointRounding.AwayFromZero); + ValueLabel.Text = ppValue.ToLocalisableString("N0"); + + if (!scoreInfo.BeatmapInfo!.Status.GrantsPerformancePoints() || hasUnrankedMods(scoreInfo)) + Alpha = 0.5f; + else + Alpha = 1f; + } + } + + private static bool hasUnrankedMods(ScoreInfo scoreInfo) + { + IEnumerable modsToCheck = scoreInfo.Mods; + + if (scoreInfo.IsLegacyScore) + modsToCheck = modsToCheck.Where(m => m is not ModClassic); + + return modsToCheck.Any(m => !m.Ranked); + } + } + } + } +}