1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-28 04:03:06 +08:00

Merge pull request #17359 from frenzibyte/fix-score-panel-max-combo

Improve method of retrieving beatmap maximum combo for results score panels
This commit is contained in:
Dan Balasescu 2022-03-22 06:28:30 +09:00 committed by GitHub
commit aea03ca21d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 52 additions and 42 deletions

View File

@ -133,7 +133,6 @@ namespace osu.Game.Tests.Resources
StarRating = diff,
Length = length,
BPM = bpm,
MaxCombo = 1000,
Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
Ruleset = rulesetInfo,
Metadata = metadata,

View File

@ -9,6 +9,7 @@ using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Models;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using Realms;
@ -169,7 +170,12 @@ namespace osu.Game.Beatmaps
[Ignored]
public APIBeatmap? OnlineInfo { get; set; }
/// <summary>
/// The maximum achievable combo on this beatmap, populated for online info purposes only.
/// Todo: This should never be used nor exist, but is still relied on in <see cref="ScoresContainer.Scores"/> since <see cref="IBeatmapInfo"/> can't be used yet. For now this is obsoleted until it is removed.
/// </summary>
[Ignored]
[Obsolete("Use ScoreManager.GetMaximumAchievableComboAsync instead.")]
public int? MaxCombo { get; set; }
[Ignored]

View File

@ -53,9 +53,6 @@ namespace osu.Game.Beatmaps
[NotMapped]
public APIBeatmap OnlineInfo { get; set; }
[NotMapped]
public int? MaxCombo { get; set; }
/// <summary>
/// The playable length in milliseconds of this beatmap.
/// </summary>

View File

@ -295,7 +295,6 @@ namespace osu.Game.Database
TimelineZoom = beatmap.TimelineZoom,
Countdown = beatmap.Countdown,
CountdownOffset = beatmap.CountdownOffset,
MaxCombo = beatmap.MaxCombo,
Bookmarks = beatmap.Bookmarks,
BeatmapSet = realmBeatmapSet,
};

View File

@ -173,7 +173,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
Text = score.MaxCombo.ToLocalisableString(@"0\x"),
Font = OsuFont.GetFont(size: text_size),
#pragma warning disable 618
Colour = score.MaxCombo == score.BeatmapInfo.MaxCombo ? highAccuracyColour : Color4.White
#pragma warning restore 618
}
};

View File

@ -78,7 +78,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
// TODO: temporary. should be removed once `OrderByTotalScore` can accept `IScoreInfo`.
var beatmapInfo = new BeatmapInfo
{
#pragma warning disable 618
MaxCombo = apiBeatmap.MaxCombo,
#pragma warning restore 618
Status = apiBeatmap.Status,
MD5Hash = apiBeatmap.MD5Hash
};

View File

@ -157,7 +157,7 @@ namespace osu.Game.Scoring
public LocalisableString DisplayAccuracy => Accuracy.FormatAccuracy();
/// <summary>
/// Whether this <see cref="EFScoreInfo"/> represents a legacy (osu!stable) score.
/// Whether this <see cref="ScoreInfo"/> represents a legacy (osu!stable) score.
/// </summary>
[Ignored]
public bool IsLegacyScore => Mods.OfType<ModClassic>().Any();

View File

@ -134,35 +134,9 @@ namespace osu.Game.Scoring
if (string.IsNullOrEmpty(score.BeatmapInfo.MD5Hash))
return score.TotalScore;
int beatmapMaxCombo;
if (score.IsLegacyScore)
{
// This score is guaranteed to be an osu!stable score.
// The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used.
if (score.BeatmapInfo.MaxCombo != null)
beatmapMaxCombo = score.BeatmapInfo.MaxCombo.Value;
else
{
if (difficulties == null)
return score.TotalScore;
// We can compute the max combo locally after the async beatmap difficulty computation.
var difficulty = await difficulties().GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false);
// Something failed during difficulty calculation. Fall back to provided score.
if (difficulty == null)
return score.TotalScore;
beatmapMaxCombo = difficulty.Value.MaxCombo;
}
}
else
{
// This is guaranteed to be a non-legacy score.
// The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values.
beatmapMaxCombo = Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum();
}
int? beatmapMaxCombo = await GetMaximumAchievableComboAsync(score, cancellationToken).ConfigureAwait(false);
if (beatmapMaxCombo == null)
return score.TotalScore;
if (beatmapMaxCombo == 0)
return 0;
@ -171,7 +145,37 @@ namespace osu.Game.Scoring
var scoreProcessor = ruleset.CreateScoreProcessor();
scoreProcessor.Mods.Value = score.Mods;
return (long)Math.Round(scoreProcessor.ComputeFinalLegacyScore(mode, score, beatmapMaxCombo));
return (long)Math.Round(scoreProcessor.ComputeFinalLegacyScore(mode, score, beatmapMaxCombo.Value));
}
/// <summary>
/// Retrieves the maximum achievable combo for the provided score.
/// </summary>
/// <param name="score">The <see cref="ScoreInfo"/> to compute the maximum achievable combo for.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the process.</param>
/// <returns>The maximum achievable combo. A <see langword="null"/> return value indicates the difficulty cache has failed to retrieve the combo.</returns>
public async Task<int?> GetMaximumAchievableComboAsync([NotNull] ScoreInfo score, CancellationToken cancellationToken = default)
{
if (score.IsLegacyScore)
{
// This score is guaranteed to be an osu!stable score.
// The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used.
#pragma warning disable CS0618
if (score.BeatmapInfo.MaxCombo != null)
return score.BeatmapInfo.MaxCombo.Value;
#pragma warning restore CS0618
if (difficulties == null)
return null;
// We can compute the max combo locally after the async beatmap difficulty computation.
var difficulty = await difficulties().GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false);
return difficulty?.MaxCombo;
}
// This is guaranteed to be a non-legacy score.
// The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values.
return Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum();
}
/// <summary>

View File

@ -65,10 +65,12 @@ namespace osu.Game.Screens.Ranking.Expanded
var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata;
string creator = metadata.Author.Username;
int? beatmapMaxCombo = scoreManager.GetMaximumAchievableComboAsync(score).GetResultSafely();
var topStatistics = new List<StatisticDisplay>
{
new AccuracyStatistic(score.Accuracy),
new ComboStatistic(score.MaxCombo, beatmap.MaxCombo, score.Statistics.All(stat => !stat.Key.BreaksCombo() || stat.Value == 0)),
new ComboStatistic(score.MaxCombo, beatmapMaxCombo),
new PerformanceStatistic(score),
};
@ -80,8 +82,6 @@ namespace osu.Game.Screens.Ranking.Expanded
statisticDisplays.AddRange(topStatistics);
statisticDisplays.AddRange(bottomStatistics);
var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).GetResultSafely();
AddInternal(new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
@ -224,6 +224,8 @@ namespace osu.Game.Screens.Ranking.Expanded
if (score.Date != default)
AddInternal(new PlayedOnText(score.Date));
var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).GetResultSafely();
if (starDifficulty != null)
{
starAndModDisplay.Add(new StarRatingDisplay(starDifficulty.Value)

View File

@ -26,11 +26,10 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics
/// </summary>
/// <param name="combo">The combo to be displayed.</param>
/// <param name="maxCombo">The maximum value of <paramref name="combo"/>.</param>
/// <param name="isPerfect">Whether this is a perfect combo.</param>
public ComboStatistic(int combo, int? maxCombo, bool isPerfect)
public ComboStatistic(int combo, int? maxCombo)
: base("combo", combo, maxCombo)
{
this.isPerfect = isPerfect;
isPerfect = combo == maxCombo;
}
public override void Appear()