diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 02a7d9a39f..0f3c991f07 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -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().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum(); - } + int? beatmapMaxCombo = await GetBeatmapMaximumComboAsync(score, cancellationToken).ConfigureAwait(false); + if (beatmapMaxCombo == null) + return score.TotalScore; if (beatmapMaxCombo == 0) return 0; @@ -171,7 +145,35 @@ 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)); + } + + /// + /// Retrieves the maximum achievable combo on the beatmap of the provided score. + /// + /// The to compute the maximum achievable combo for. + /// A to cancel the process. + /// The maximum achievable combo. + public async Task GetBeatmapMaximumComboAsync([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. + if (score.BeatmapInfo.MaxCombo != null) + return score.BeatmapInfo.MaxCombo.Value; + + 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().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum(); } ///