1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 07:42:57 +08:00
This commit is contained in:
smoogipoo 2021-09-01 15:41:52 +09:00
parent 2de076a74b
commit 88fc53200e
4 changed files with 59 additions and 40 deletions

View File

@ -14,7 +14,6 @@ using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Framework.Bindables;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
using osu.Game.Scoring;
@ -67,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (value?.Scores.Any() != true)
return;
scoreManager.GetOrderedScoresAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token)
scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token)
.ContinueWith(ordered => Schedule(() =>
{
if (loadCancellationSource.IsCancellationRequested)

View File

@ -34,7 +34,6 @@ 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;
@ -52,8 +51,6 @@ namespace osu.Game.Scoring
this.beatmaps = beatmaps;
this.difficulties = difficulties;
this.configManager = configManager;
configManager?.BindWith(OsuSetting.ScoreDisplayMode, scoringMode);
}
protected override ScoreInfo CreateModel(ArchiveReader archive)
@ -106,14 +103,20 @@ namespace osu.Game.Scoring
=> base.CheckLocalAvailability(model, items)
|| (model.OnlineScoreID != null && items.Any(i => i.OnlineScoreID == model.OnlineScoreID));
public async Task<ScoreInfo[]> GetOrderedScoresAsync(ScoreInfo[] scores, CancellationToken cancellationToken = default)
/// <summary>
/// Orders an array of <see cref="ScoreInfo"/>s by total score.
/// </summary>
/// <param name="scores">The array of <see cref="ScoreInfo"/>s to reorder.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the process.</param>
/// <returns>The given <paramref name="scores"/> ordered by decreasing total score.</returns>
public async Task<ScoreInfo[]> OrderByTotalScoreAsync(ScoreInfo[] scores, CancellationToken cancellationToken = default)
{
var difficultyCache = difficulties?.Invoke();
if (difficultyCache == null)
return orderByTotalScore(scores);
// Compute difficulties asynchronously first to prevent blocks on the main thread.
// Compute difficulties asynchronously first to prevent blocking via the GetTotalScore() call below.
foreach (var s in scores)
{
await difficultyCache.GetDifficultyAsync(s.Beatmap, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false);
@ -122,7 +125,7 @@ namespace osu.Game.Scoring
return orderByTotalScore(scores);
ScoreInfo[] orderByTotalScore(IEnumerable<ScoreInfo> incoming) => incoming.OrderByDescending(GetTotalScore).ThenBy(s => s.OnlineScoreID).ToArray();
ScoreInfo[] orderByTotalScore(IEnumerable<ScoreInfo> incoming) => incoming.OrderByDescending(s => GetTotalScore(s)).ThenBy(s => s.OnlineScoreID).ToArray();
}
/// <summary>
@ -150,9 +153,22 @@ namespace osu.Game.Scoring
/// <returns>The bindable containing the formatted total score string.</returns>
public Bindable<string> GetBindableTotalScoreString(ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score));
public long GetTotalScore(ScoreInfo score) => GetTotalScoreAsync(score).Result;
/// <summary>
/// Retrieves the total score of a <see cref="ScoreInfo"/> in the given <see cref="ScoringMode"/>.
/// </summary>
/// <param name="score">The <see cref="ScoreInfo"/> to calculate the total score of.</param>
/// <param name="mode">The <see cref="ScoringMode"/> to return the total score as.</param>
/// <returns>The total score.</returns>
public long GetTotalScore(ScoreInfo score, ScoringMode mode = ScoringMode.Standardised) => GetTotalScoreAsync(score).Result;
public async Task<long> GetTotalScoreAsync(ScoreInfo score, CancellationToken cancellationToken = default)
/// <summary>
/// Retrieves the total score of a <see cref="ScoreInfo"/> in the given <see cref="ScoringMode"/>.
/// </summary>
/// <param name="score">The <see cref="ScoreInfo"/> to calculate the total score of.</param>
/// <param name="mode">The <see cref="ScoringMode"/> to return the total score as.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the process.</param>
/// <returns>The total score.</returns>
public async Task<long> GetTotalScoreAsync(ScoreInfo score, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default)
{
if (score.Beatmap == null)
return score.TotalScore;
@ -204,7 +220,7 @@ namespace osu.Game.Scoring
var scoreProcessor = ruleset.CreateScoreProcessor();
scoreProcessor.Mods.Value = score.Mods;
return (long)Math.Round(scoreProcessor.GetScore(scoringMode.Value, beatmapMaxCombo, accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics));
return (long)Math.Round(scoreProcessor.GetScore(mode, beatmapMaxCombo, accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics));
}
/// <summary>
@ -221,7 +237,7 @@ namespace osu.Game.Scoring
/// <param name="scoreManager">The <see cref="ScoreManager"/>.</param>
public TotalScoreBindable(ScoreInfo score, ScoreManager scoreManager)
{
ScoringMode.BindValueChanged(_ => Value = scoreManager.GetTotalScore(score), true);
ScoringMode.BindValueChanged(mode => Value = scoreManager.GetTotalScore(score, mode.NewValue), true);
}
}

View File

@ -11,6 +11,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Scoring;
using osuTK;
@ -65,6 +66,9 @@ namespace osu.Game.Screens.Ranking
[Resolved]
private ScoreManager scoreManager { get; set; }
[Resolved]
private BeatmapDifficultyCache difficultyCache { get; set; }
private readonly CancellationTokenSource loadCancellationSource = new CancellationTokenSource();
private readonly Flow flow;
private readonly Scroll scroll;
@ -120,33 +124,33 @@ namespace osu.Game.Screens.Ranking
};
});
scoreManager.GetOrderedScoresAsync(new[] { score })
.ContinueWith(_ => Schedule(() =>
{
flow.Add(panel.CreateTrackingContainer().With(d =>
{
d.Anchor = Anchor.Centre;
d.Origin = Anchor.Centre;
}));
difficultyCache.GetDifficultyAsync(score.Beatmap, score.Ruleset, score.Mods)
.ContinueWith(_ => Schedule(() =>
{
flow.Add(panel.CreateTrackingContainer().With(d =>
{
d.Anchor = Anchor.Centre;
d.Origin = Anchor.Centre;
}));
if (SelectedScore.Value == score)
{
SelectedScore.TriggerChange();
}
else
{
// We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done.
// But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel.
if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score))
{
// A somewhat hacky property is used here because we need to:
// 1) Scroll after the scroll container's visible range is updated.
// 2) Scroll before the scroll container's scroll position is updated.
// Without this, we would have a 1-frame positioning error which looks very jarring.
scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing;
}
}
}));
if (SelectedScore.Value == score)
{
SelectedScore.TriggerChange();
}
else
{
// We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done.
// But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel.
if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score))
{
// A somewhat hacky property is used here because we need to:
// 1) Scroll after the scroll container's visible range is updated.
// 2) Scroll before the scroll container's scroll position is updated.
// Without this, we would have a 1-frame positioning error which looks very jarring.
scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing;
}
}
}));
return panel;
}

View File

@ -156,7 +156,7 @@ namespace osu.Game.Screens.Select.Leaderboards
scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym)));
}
scoreManager.GetOrderedScoresAsync(scores.ToArray(), loadCancellationSource.Token)
scoreManager.OrderByTotalScoreAsync(scores.ToArray(), loadCancellationSource.Token)
.ContinueWith(ordered => scoresCallback?.Invoke(ordered.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
return null;
@ -192,7 +192,7 @@ namespace osu.Game.Screens.Select.Leaderboards
req.Success += r =>
{
scoreManager.GetOrderedScoresAsync(r.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token)
scoreManager.OrderByTotalScoreAsync(r.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token)
.ContinueWith(ordered => Schedule(() =>
{
if (loadCancellationSource.IsCancellationRequested)