mirror of
https://github.com/ppy/osu.git
synced 2024-11-14 15:57:24 +08:00
Remove async calls from ScoreManager
This commit is contained in:
parent
c0b13c7e1f
commit
423f6f90f2
@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
||||||
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
|
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
|
||||||
Dependencies.Cache(new ScoreManager(rulesets, () => beatmaps, LocalStorage, Realm, Scheduler, API));
|
Dependencies.Cache(new ScoreManager(rulesets, () => beatmaps, LocalStorage, Realm, API));
|
||||||
Dependencies.Cache(Realm);
|
Dependencies.Cache(Realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
dependencies.Cache(rulesetStore = new RealmRulesetStore(Realm));
|
dependencies.Cache(rulesetStore = new RealmRulesetStore(Realm));
|
||||||
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
|
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
|
||||||
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, Scheduler, API));
|
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, API));
|
||||||
Dependencies.Cache(Realm);
|
Dependencies.Cache(Realm);
|
||||||
|
|
||||||
return dependencies;
|
return dependencies;
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
||||||
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
|
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
|
||||||
Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, Scheduler, API));
|
Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, API));
|
||||||
Dependencies.Cache(Realm);
|
Dependencies.Cache(Realm);
|
||||||
|
|
||||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||||
|
@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
dependencies.Cache(new RealmRulesetStore(Realm));
|
dependencies.Cache(new RealmRulesetStore(Realm));
|
||||||
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
|
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
|
||||||
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get<RulesetStore>(), () => beatmapManager, LocalStorage, Realm, Scheduler, API));
|
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get<RulesetStore>(), () => beatmapManager, LocalStorage, Realm, API));
|
||||||
Dependencies.Cache(Realm);
|
Dependencies.Cache(Realm);
|
||||||
|
|
||||||
return dependencies;
|
return dependencies;
|
||||||
|
@ -273,7 +273,7 @@ namespace osu.Game
|
|||||||
dependencies.Cache(difficultyCache = new BeatmapDifficultyCache());
|
dependencies.Cache(difficultyCache = new BeatmapDifficultyCache());
|
||||||
|
|
||||||
// ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
|
// ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
|
||||||
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, Scheduler, API, difficultyCache, LocalConfig));
|
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, API, LocalConfig));
|
||||||
|
|
||||||
dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, realm, API, Audio, Resources, Host, defaultBeatmap, difficultyCache, performOnlineLookups: true));
|
dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, realm, API, Audio, Resources, Host, defaultBeatmap, difficultyCache, performOnlineLookups: true));
|
||||||
|
|
||||||
|
@ -6,10 +6,8 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -87,27 +85,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
MD5Hash = apiBeatmap.MD5Hash
|
MD5Hash = apiBeatmap.MD5Hash
|
||||||
};
|
};
|
||||||
|
|
||||||
scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.ToScoreInfo(rulesets, beatmapInfo)).ToArray(), loadCancellationSource.Token)
|
var scores = scoreManager.OrderByTotalScore(value.Scores.Select(s => s.ToScoreInfo(rulesets, beatmapInfo))).ToArray();
|
||||||
.ContinueWith(task => Schedule(() =>
|
var topScore = scores.First();
|
||||||
{
|
|
||||||
if (loadCancellationSource.IsCancellationRequested)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var scores = task.GetResultSafely();
|
scoreTable.DisplayScores(scores, apiBeatmap.Status.GrantsPerformancePoints());
|
||||||
|
scoreTable.Show();
|
||||||
|
|
||||||
var topScore = scores.First();
|
var userScore = value.UserScore;
|
||||||
|
var userScoreInfo = userScore?.Score.ToScoreInfo(rulesets, beatmapInfo);
|
||||||
|
|
||||||
scoreTable.DisplayScores(scores, apiBeatmap.Status.GrantsPerformancePoints());
|
topScoresContainer.Add(new DrawableTopScore(topScore));
|
||||||
scoreTable.Show();
|
|
||||||
|
|
||||||
var userScore = value.UserScore;
|
if (userScoreInfo != null && userScoreInfo.OnlineID != topScore.OnlineID)
|
||||||
var userScoreInfo = userScore?.Score.ToScoreInfo(rulesets, beatmapInfo);
|
topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position));
|
||||||
|
|
||||||
topScoresContainer.Add(new DrawableTopScore(topScore));
|
|
||||||
|
|
||||||
if (userScoreInfo != null && userScoreInfo.OnlineID != topScore.OnlineID)
|
|
||||||
topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position));
|
|
||||||
}), TaskContinuationOptions.OnlyOnRanToCompletion);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,10 +11,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Logging;
|
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Threading;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
@ -28,17 +25,12 @@ namespace osu.Game.Scoring
|
|||||||
{
|
{
|
||||||
public class ScoreManager : ModelManager<ScoreInfo>, IModelImporter<ScoreInfo>
|
public class ScoreManager : ModelManager<ScoreInfo>, IModelImporter<ScoreInfo>
|
||||||
{
|
{
|
||||||
private readonly Scheduler scheduler;
|
|
||||||
private readonly BeatmapDifficultyCache difficultyCache;
|
|
||||||
private readonly OsuConfigManager configManager;
|
private readonly OsuConfigManager configManager;
|
||||||
private readonly ScoreImporter scoreImporter;
|
private readonly ScoreImporter scoreImporter;
|
||||||
|
|
||||||
public ScoreManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, RealmAccess realm, Scheduler scheduler, IAPIProvider api,
|
public ScoreManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, RealmAccess realm, IAPIProvider api, OsuConfigManager configManager = null)
|
||||||
BeatmapDifficultyCache difficultyCache = null, OsuConfigManager configManager = null)
|
|
||||||
: base(storage, realm)
|
: base(storage, realm)
|
||||||
{
|
{
|
||||||
this.scheduler = scheduler;
|
|
||||||
this.difficultyCache = difficultyCache;
|
|
||||||
this.configManager = configManager;
|
this.configManager = configManager;
|
||||||
|
|
||||||
scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api)
|
scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api)
|
||||||
@ -63,27 +55,13 @@ namespace osu.Game.Scoring
|
|||||||
/// Orders an array of <see cref="ScoreInfo"/>s by total score.
|
/// Orders an array of <see cref="ScoreInfo"/>s by total score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scores">The array of <see cref="ScoreInfo"/>s to reorder.</param>
|
/// <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>
|
/// <returns>The given <paramref name="scores"/> ordered by decreasing total score.</returns>
|
||||||
public async Task<ScoreInfo[]> OrderByTotalScoreAsync(ScoreInfo[] scores, CancellationToken cancellationToken = default)
|
public IEnumerable<ScoreInfo> OrderByTotalScore(IEnumerable<ScoreInfo> scores)
|
||||||
{
|
{
|
||||||
if (difficultyCache != null)
|
return scores.Select((score, index) => (score, totalScore: GetTotalScore(score)))
|
||||||
{
|
|
||||||
// Compute difficulties asynchronously first to prevent blocking via the GetTotalScore() call below.
|
|
||||||
foreach (var s in scores)
|
|
||||||
{
|
|
||||||
await difficultyCache.GetDifficultyAsync(s.BeatmapInfo, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false);
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long[] totalScores = await Task.WhenAll(scores.Select(s => GetTotalScoreAsync(s, cancellationToken: cancellationToken))).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return scores.Select((score, index) => (score, totalScore: totalScores[index]))
|
|
||||||
.OrderByDescending(g => g.totalScore)
|
.OrderByDescending(g => g.totalScore)
|
||||||
.ThenBy(g => g.score.OnlineID)
|
.ThenBy(g => g.score.OnlineID)
|
||||||
.Select(g => g.score)
|
.Select(g => g.score);
|
||||||
.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -106,44 +84,18 @@ namespace osu.Game.Scoring
|
|||||||
/// <returns>The bindable containing the formatted total score string.</returns>
|
/// <returns>The bindable containing the formatted total score string.</returns>
|
||||||
public Bindable<string> GetBindableTotalScoreString([NotNull] ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score));
|
public Bindable<string> GetBindableTotalScoreString([NotNull] ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score));
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the total score of a <see cref="ScoreInfo"/> in the given <see cref="ScoringMode"/>.
|
|
||||||
/// The score is returned in a callback that is run on the update thread.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="score">The <see cref="ScoreInfo"/> to calculate the total score of.</param>
|
|
||||||
/// <param name="callback">The callback to be invoked with the total score.</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>
|
|
||||||
public void GetTotalScore([NotNull] ScoreInfo score, [NotNull] Action<long> callback, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
GetTotalScoreAsync(score, mode, cancellationToken)
|
|
||||||
.ContinueWith(task => scheduler.Add(() =>
|
|
||||||
{
|
|
||||||
if (!cancellationToken.IsCancellationRequested)
|
|
||||||
callback(task.GetResultSafely());
|
|
||||||
}), TaskContinuationOptions.OnlyOnRanToCompletion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the total score of a <see cref="ScoreInfo"/> in the given <see cref="ScoringMode"/>.
|
/// Retrieves the total score of a <see cref="ScoreInfo"/> in the given <see cref="ScoringMode"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="score">The <see cref="ScoreInfo"/> to calculate the total score of.</param>
|
/// <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="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>
|
/// <returns>The total score.</returns>
|
||||||
public async Task<long> GetTotalScoreAsync([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default)
|
public long GetTotalScore([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised)
|
||||||
{
|
{
|
||||||
// TODO: This is required for playlist aggregate scores. They should likely not be getting here in the first place.
|
// TODO: This is required for playlist aggregate scores. They should likely not be getting here in the first place.
|
||||||
if (string.IsNullOrEmpty(score.BeatmapInfo.MD5Hash))
|
if (string.IsNullOrEmpty(score.BeatmapInfo.MD5Hash))
|
||||||
return score.TotalScore;
|
return score.TotalScore;
|
||||||
|
|
||||||
int? beatmapMaxCombo = await GetMaximumAchievableComboAsync(score, cancellationToken).ConfigureAwait(false);
|
|
||||||
if (beatmapMaxCombo == null)
|
|
||||||
return score.TotalScore;
|
|
||||||
|
|
||||||
if (beatmapMaxCombo == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
var ruleset = score.Ruleset.CreateInstance();
|
var ruleset = score.Ruleset.CreateInstance();
|
||||||
var scoreProcessor = ruleset.CreateScoreProcessor();
|
var scoreProcessor = ruleset.CreateScoreProcessor();
|
||||||
scoreProcessor.Mods.Value = score.Mods;
|
scoreProcessor.Mods.Value = score.Mods;
|
||||||
@ -155,33 +107,9 @@ namespace osu.Game.Scoring
|
|||||||
/// Retrieves the maximum achievable combo for the provided score.
|
/// Retrieves the maximum achievable combo for the provided score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="score">The <see cref="ScoreInfo"/> to compute the maximum achievable combo for.</param>
|
/// <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>
|
/// <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)
|
public int GetMaximumAchievableCombo([NotNull] ScoreInfo score)
|
||||||
{
|
{
|
||||||
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 (difficultyCache == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// We can compute the max combo locally after the async beatmap difficulty computation.
|
|
||||||
var difficulty = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (difficulty == null)
|
|
||||||
Logger.Log($"Couldn't get beatmap difficulty for beatmap {score.BeatmapInfo.OnlineID}");
|
|
||||||
|
|
||||||
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();
|
return Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,10 +119,6 @@ namespace osu.Game.Scoring
|
|||||||
private class TotalScoreBindable : Bindable<long>
|
private class TotalScoreBindable : Bindable<long>
|
||||||
{
|
{
|
||||||
private readonly Bindable<ScoringMode> scoringMode = new Bindable<ScoringMode>();
|
private readonly Bindable<ScoringMode> scoringMode = new Bindable<ScoringMode>();
|
||||||
private readonly ScoreInfo score;
|
|
||||||
private readonly ScoreManager scoreManager;
|
|
||||||
|
|
||||||
private CancellationTokenSource difficultyCalculationCancellationSource;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="TotalScoreBindable"/>.
|
/// Creates a new <see cref="TotalScoreBindable"/>.
|
||||||
@ -204,19 +128,8 @@ namespace osu.Game.Scoring
|
|||||||
/// <param name="configManager">The config.</param>
|
/// <param name="configManager">The config.</param>
|
||||||
public TotalScoreBindable(ScoreInfo score, ScoreManager scoreManager, OsuConfigManager configManager)
|
public TotalScoreBindable(ScoreInfo score, ScoreManager scoreManager, OsuConfigManager configManager)
|
||||||
{
|
{
|
||||||
this.score = score;
|
|
||||||
this.scoreManager = scoreManager;
|
|
||||||
|
|
||||||
configManager?.BindWith(OsuSetting.ScoreDisplayMode, scoringMode);
|
configManager?.BindWith(OsuSetting.ScoreDisplayMode, scoringMode);
|
||||||
scoringMode.BindValueChanged(onScoringModeChanged, true);
|
scoringMode.BindValueChanged(mode => Value = scoreManager.GetTotalScore(score, mode.NewValue), true);
|
||||||
}
|
|
||||||
|
|
||||||
private void onScoringModeChanged(ValueChangedEvent<ScoringMode> mode)
|
|
||||||
{
|
|
||||||
difficultyCalculationCancellationSource?.Cancel();
|
|
||||||
difficultyCalculationCancellationSource = new CancellationTokenSource();
|
|
||||||
|
|
||||||
scoreManager.GetTotalScore(score, s => Value = s, mode.NewValue, difficultyCalculationCancellationSource.Token);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,31 +180,26 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
/// <param name="callback">The callback to invoke with the final <see cref="ScoreInfo"/>s.</param>
|
/// <param name="callback">The callback to invoke with the final <see cref="ScoreInfo"/>s.</param>
|
||||||
/// <param name="scores">The <see cref="MultiplayerScore"/>s that were retrieved from <see cref="APIRequest"/>s.</param>
|
/// <param name="scores">The <see cref="MultiplayerScore"/>s that were retrieved from <see cref="APIRequest"/>s.</param>
|
||||||
/// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
|
/// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
|
||||||
private void performSuccessCallback([NotNull] Action<IEnumerable<ScoreInfo>> callback, [NotNull] List<MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null)
|
private void performSuccessCallback([NotNull] Action<IEnumerable<ScoreInfo>> callback, [NotNull] List<MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null) => Schedule(() =>
|
||||||
{
|
{
|
||||||
var scoreInfos = scores.Select(s => s.CreateScoreInfo(rulesets, playlistItem, Beatmap.Value.BeatmapInfo)).ToArray();
|
var scoreInfos = scoreManager.OrderByTotalScore(scores.Select(s => s.CreateScoreInfo(rulesets, playlistItem, Beatmap.Value.BeatmapInfo))).ToArray();
|
||||||
|
|
||||||
// Score panels calculate total score before displaying, which can take some time. In order to count that calculation as part of the loading spinner display duration,
|
// Select a score if we don't already have one selected.
|
||||||
// calculate the total scores locally before invoking the success callback.
|
// Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll).
|
||||||
scoreManager.OrderByTotalScoreAsync(scoreInfos).ContinueWith(_ => Schedule(() =>
|
if (SelectedScore.Value == null)
|
||||||
{
|
{
|
||||||
// Select a score if we don't already have one selected.
|
Schedule(() =>
|
||||||
// Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll).
|
|
||||||
if (SelectedScore.Value == null)
|
|
||||||
{
|
{
|
||||||
Schedule(() =>
|
// Prefer selecting the local user's score, or otherwise default to the first visible score.
|
||||||
{
|
SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.OnlineID == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault();
|
||||||
// Prefer selecting the local user's score, or otherwise default to the first visible score.
|
});
|
||||||
SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.OnlineID == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault();
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke callback to add the scores. Exclude the user's current score which was added previously.
|
// Invoke callback to add the scores. Exclude the user's current score which was added previously.
|
||||||
callback.Invoke(scoreInfos.Where(s => s.OnlineID != Score?.OnlineID));
|
callback.Invoke(scoreInfos.Where(s => s.OnlineID != Score?.OnlineID));
|
||||||
|
|
||||||
hideLoadingSpinners(pivot);
|
hideLoadingSpinners(pivot);
|
||||||
}));
|
});
|
||||||
}
|
|
||||||
|
|
||||||
private void hideLoadingSpinners([CanBeNull] MultiplayerScores pivot = null)
|
private void hideLoadingSpinners([CanBeNull] MultiplayerScores pivot = null)
|
||||||
{
|
{
|
||||||
|
@ -67,12 +67,10 @@ namespace osu.Game.Screens.Ranking.Expanded
|
|||||||
var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata;
|
var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata;
|
||||||
string creator = metadata.Author.Username;
|
string creator = metadata.Author.Username;
|
||||||
|
|
||||||
int? beatmapMaxCombo = scoreManager.GetMaximumAchievableComboAsync(score).GetResultSafely();
|
|
||||||
|
|
||||||
var topStatistics = new List<StatisticDisplay>
|
var topStatistics = new List<StatisticDisplay>
|
||||||
{
|
{
|
||||||
new AccuracyStatistic(score.Accuracy),
|
new AccuracyStatistic(score.Accuracy),
|
||||||
new ComboStatistic(score.MaxCombo, beatmapMaxCombo),
|
new ComboStatistic(score.MaxCombo, scoreManager.GetMaximumAchievableCombo(score)),
|
||||||
new PerformanceStatistic(score),
|
new PerformanceStatistic(score),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,11 +8,9 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
@ -151,32 +149,27 @@ namespace osu.Game.Screens.Ranking
|
|||||||
|
|
||||||
var score = trackingContainer.Panel.Score;
|
var score = trackingContainer.Panel.Score;
|
||||||
|
|
||||||
// Calculating score can take a while in extreme scenarios, so only display scores after the process completes.
|
flow.SetLayoutPosition(trackingContainer, scoreManager.GetTotalScore(score));
|
||||||
scoreManager.GetTotalScoreAsync(score)
|
|
||||||
.ContinueWith(task => Schedule(() =>
|
|
||||||
{
|
|
||||||
flow.SetLayoutPosition(trackingContainer, task.GetResultSafely());
|
|
||||||
|
|
||||||
trackingContainer.Show();
|
trackingContainer.Show();
|
||||||
|
|
||||||
if (SelectedScore.Value?.Equals(score) == true)
|
if (SelectedScore.Value?.Equals(score) == true)
|
||||||
{
|
{
|
||||||
SelectedScore.TriggerChange();
|
SelectedScore.TriggerChange();
|
||||||
}
|
}
|
||||||
else
|
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.
|
// 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.
|
// 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))
|
if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score))
|
||||||
{
|
{
|
||||||
// A somewhat hacky property is used here because we need to:
|
// A somewhat hacky property is used here because we need to:
|
||||||
// 1) Scroll after the scroll container's visible range is updated.
|
// 1) Scroll after the scroll container's visible range is updated.
|
||||||
// 2) Scroll before the scroll container's scroll position 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.
|
// 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;
|
scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}), TaskContinuationOptions.OnlyOnRanToCompletion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -8,10 +8,8 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Extensions;
|
using osu.Game.Extensions;
|
||||||
@ -150,17 +148,12 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
|
|
||||||
var req = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods);
|
var req = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods);
|
||||||
|
|
||||||
req.Success += r =>
|
req.Success += r => Schedule(() =>
|
||||||
{
|
{
|
||||||
scoreManager.OrderByTotalScoreAsync(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo)).ToArray(), cancellationToken)
|
SetScores(
|
||||||
.ContinueWith(task => Schedule(() =>
|
scoreManager.OrderByTotalScore(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))),
|
||||||
{
|
r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo));
|
||||||
if (cancellationToken.IsCancellationRequested)
|
});
|
||||||
return;
|
|
||||||
|
|
||||||
SetScores(task.GetResultSafely(), r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo));
|
|
||||||
}), TaskContinuationOptions.OnlyOnRanToCompletion);
|
|
||||||
};
|
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
@ -213,16 +206,9 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym)));
|
scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym)));
|
||||||
}
|
}
|
||||||
|
|
||||||
scores = scores.Detach();
|
scores = scoreManager.OrderByTotalScore(scores.Detach());
|
||||||
|
|
||||||
scoreManager.OrderByTotalScoreAsync(scores.ToArray(), cancellationToken)
|
Schedule(() => SetScores(scores));
|
||||||
.ContinueWith(ordered => Schedule(() =>
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SetScores(ordered.GetResultSafely());
|
|
||||||
}), TaskContinuationOptions.OnlyOnRanToCompletion);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user