Move score calculation to ScoreManager

This commit is contained in:
smoogipoo
2021-08-30 19:33:09 +09:00
parent b217dd1a65
commit d03950fb37

View File

@ -34,6 +34,7 @@ namespace osu.Game.Scoring
protected override string ImportFromStablePath => Path.Combine("Data", "r");
private readonly Bindable<ScoringMode> scoringMode = new Bindable<ScoringMode>();
private readonly RulesetStore rulesets;
private readonly Func<BeatmapManager> beatmaps;
@ -51,6 +52,8 @@ namespace osu.Game.Scoring
this.beatmaps = beatmaps;
this.difficulties = difficulties;
this.configManager = configManager;
configManager?.BindWith(OsuSetting.ScoreDisplayMode, scoringMode);
}
protected override ScoreInfo CreateModel(ArchiveReader archive)
@ -113,7 +116,7 @@ namespace osu.Game.Scoring
/// <returns>The bindable containing the total score.</returns>
public Bindable<long> GetBindableTotalScore(ScoreInfo score)
{
var bindable = new TotalScoreBindable(score, difficulties);
var bindable = new TotalScoreBindable(score, this);
configManager?.BindWith(OsuSetting.ScoreDisplayMode, bindable.ScoringMode);
return bindable;
}
@ -128,42 +131,12 @@ namespace osu.Game.Scoring
/// <returns>The bindable containing the formatted total score string.</returns>
public Bindable<string> GetBindableTotalScoreString(ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score));
/// <summary>
/// Provides the total score of a <see cref="ScoreInfo"/>. Responds to changes in the currently-selected <see cref="ScoringMode"/>.
/// </summary>
private class TotalScoreBindable : Bindable<long>
public long GetTotalScore(ScoreInfo score) => GetTotalScoreAsync(score).Result;
public async Task<long> GetTotalScoreAsync(ScoreInfo score, CancellationToken cancellationToken = default)
{
public readonly Bindable<ScoringMode> ScoringMode = new Bindable<ScoringMode>();
private readonly ScoreInfo score;
private readonly Func<BeatmapDifficultyCache> difficulties;
/// <summary>
/// Creates a new <see cref="TotalScoreBindable"/>.
/// </summary>
/// <param name="score">The <see cref="ScoreInfo"/> to provide the total score of.</param>
/// <param name="difficulties">A function to retrieve the <see cref="BeatmapDifficultyCache"/>.</param>
public TotalScoreBindable(ScoreInfo score, Func<BeatmapDifficultyCache> difficulties)
{
this.score = score;
this.difficulties = difficulties;
ScoringMode.BindValueChanged(onScoringModeChanged, true);
}
private IBindable<StarDifficulty?> difficultyBindable;
private CancellationTokenSource difficultyCancellationSource;
private void onScoringModeChanged(ValueChangedEvent<ScoringMode> mode)
{
difficultyCancellationSource?.Cancel();
difficultyCancellationSource = null;
if (score.Beatmap == null)
{
Value = score.TotalScore;
return;
}
return score.TotalScore;
int beatmapMaxCombo;
double accuracy = score.Accuracy;
@ -183,27 +156,20 @@ namespace osu.Game.Scoring
// 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.Beatmap.MaxCombo == null)
if (score.Beatmap.MaxCombo != null)
beatmapMaxCombo = score.Beatmap.MaxCombo.Value;
else
{
if (score.Beatmap.ID == 0 || difficulties == null)
{
// We don't have enough information (max combo) to compute the score, so use the provided score.
Value = score.TotalScore;
return;
return score.TotalScore;
}
// We can compute the max combo locally after the async beatmap difficulty computation.
difficultyBindable = difficulties().GetBindableDifficulty(score.Beatmap, score.Ruleset, score.Mods, (difficultyCancellationSource = new CancellationTokenSource()).Token);
difficultyBindable.BindValueChanged(d =>
{
if (d.NewValue is StarDifficulty diff)
updateScore(diff.MaxCombo, accuracy);
}, true);
return;
var difficulty = await difficulties().GetDifficultyAsync(score.Beatmap, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false);
beatmapMaxCombo = difficulty.MaxCombo;
}
beatmapMaxCombo = score.Beatmap.MaxCombo.Value;
}
else
{
@ -212,23 +178,47 @@ namespace osu.Game.Scoring
beatmapMaxCombo = Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum();
}
updateScore(beatmapMaxCombo, accuracy);
}
private void updateScore(int beatmapMaxCombo, double accuracy)
{
if (beatmapMaxCombo == 0)
{
Value = 0;
return;
}
return 0;
var ruleset = score.Ruleset.CreateInstance();
var scoreProcessor = ruleset.CreateScoreProcessor();
scoreProcessor.Mods.Value = score.Mods;
Value = (long)Math.Round(scoreProcessor.GetScore(ScoringMode.Value, beatmapMaxCombo, accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics));
return (long)Math.Round(scoreProcessor.GetScore(scoringMode.Value, beatmapMaxCombo, accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics));
}
/// <summary>
/// Provides the total score of a <see cref="ScoreInfo"/>. Responds to changes in the currently-selected <see cref="ScoringMode"/>.
/// </summary>
private class TotalScoreBindable : Bindable<long>
{
public readonly Bindable<ScoringMode> ScoringMode = new Bindable<ScoringMode>();
private readonly ScoreInfo score;
private readonly ScoreManager scoreManager;
/// <summary>
/// Creates a new <see cref="TotalScoreBindable"/>.
/// </summary>
/// <param name="score">The <see cref="ScoreInfo"/> to provide the total score of.</param>
/// <param name="scoreManager">The <see cref="ScoreManager"/>.</param>
public TotalScoreBindable(ScoreInfo score, ScoreManager scoreManager)
{
this.score = score;
this.scoreManager = scoreManager;
ScoringMode.BindValueChanged(onScoringModeChanged, true);
}
private CancellationTokenSource difficultyCancellationSource;
private void onScoringModeChanged(ValueChangedEvent<ScoringMode> mode)
{
difficultyCancellationSource?.Cancel();
difficultyCancellationSource = new CancellationTokenSource();
scoreManager.GetTotalScoreAsync(score, difficultyCancellationSource.Token).ContinueWith(s => Value = s.Result, TaskContinuationOptions.OnlyOnRanToCompletion);
}
}