1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 07:42:57 +08:00

Fix update-thread pauses

This commit is contained in:
smoogipoo 2021-08-31 21:36:31 +09:00
parent cfcf3d7507
commit fee94236de
4 changed files with 99 additions and 51 deletions

View File

@ -7,6 +7,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osuTK;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
@ -49,36 +51,41 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private GetScoresRequest getScoresRequest;
private CancellationTokenSource loadCancellationSource;
protected APILegacyScores Scores
{
set => Schedule(() =>
{
loadCancellationSource?.Cancel();
loadCancellationSource = new CancellationTokenSource();
topScoresContainer.Clear();
scoreTable.ClearScores();
scoreTable.Hide();
if (value?.Scores.Any() != true)
{
scoreTable.ClearScores();
scoreTable.Hide();
return;
}
var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets))
.OrderByDescending(s => scoreManager.GetTotalScore(s))
.ThenBy(s => s.OnlineScoreID)
.ToList();
scoreManager.GetOrderedScoresAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token)
.ContinueWith(ordered => Schedule(() =>
{
if (loadCancellationSource.IsCancellationRequested)
return;
var topScore = scoreInfos.First();
var topScore = ordered.Result.First();
scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status.GrantsPerformancePoints() == true);
scoreTable.Show();
scoreTable.DisplayScores(ordered.Result, topScore.Beatmap?.Status.GrantsPerformancePoints() == true);
scoreTable.Show();
var userScore = value.UserScore;
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets);
var userScore = value.UserScore;
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets);
topScoresContainer.Add(new DrawableTopScore(topScore));
topScoresContainer.Add(new DrawableTopScore(topScore));
if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID)
topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position));
if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID)
topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position));
}), TaskContinuationOptions.OnlyOnRanToCompletion);
});
}

View File

@ -106,6 +106,25 @@ 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)
{
var difficultyCache = difficulties?.Invoke();
if (difficultyCache == null)
return orderByTotalScore(scores);
// Compute difficulties asynchronously first to prevent blocks on the main thread.
foreach (var s in scores)
{
await difficultyCache.GetDifficultyAsync(s.Beatmap, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
}
return orderByTotalScore(scores);
ScoreInfo[] orderByTotalScore(IEnumerable<ScoreInfo> incoming) => incoming.OrderByDescending(GetTotalScore).ThenBy(s => s.OnlineScoreID).ToArray();
}
/// <summary>
/// Retrieves a bindable that represents the total score of a <see cref="ScoreInfo"/>.
/// </summary>

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -61,6 +62,10 @@ namespace osu.Game.Screens.Ranking
public readonly Bindable<ScoreInfo> SelectedScore = new Bindable<ScoreInfo>();
[Resolved]
private ScoreManager scoreManager { get; set; }
private readonly CancellationTokenSource loadCancellationSource = new CancellationTokenSource();
private readonly Flow flow;
private readonly Scroll scroll;
private ScorePanel expandedPanel;
@ -115,32 +120,33 @@ namespace osu.Game.Screens.Ranking
};
});
flow.Add(panel.CreateTrackingContainer().With(d =>
{
d.Anchor = Anchor.Centre;
d.Origin = Anchor.Centre;
}));
scoreManager.GetOrderedScoresAsync(new[] { score })
.ContinueWith(_ => Schedule(() =>
{
flow.Add(panel.CreateTrackingContainer().With(d =>
{
d.Anchor = Anchor.Centre;
d.Origin = Anchor.Centre;
}));
if (IsLoaded)
{
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;
}
@ -286,6 +292,12 @@ namespace osu.Game.Screens.Ranking
return base.OnKeyDown(e);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
loadCancellationSource?.Cancel();
}
private class Flow : FillFlowContainer<ScorePanelTrackingContainer>
{
public override IEnumerable<Drawable> FlowingChildren => applySorting(AliveInternalChildren);

View File

@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
@ -66,6 +68,9 @@ namespace osu.Game.Screens.Select.Leaderboards
[Resolved]
private ScoreManager scoreManager { get; set; }
[Resolved]
private BeatmapDifficultyCache difficultyCache { get; set; }
[Resolved]
private IBindable<RulesetInfo> ruleset { get; set; }
@ -120,8 +125,13 @@ namespace osu.Game.Screens.Select.Leaderboards
protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local;
private CancellationTokenSource loadCancellationSource;
protected override APIRequest FetchScores(Action<IEnumerable<ScoreInfo>> scoresCallback)
{
loadCancellationSource?.Cancel();
loadCancellationSource = new CancellationTokenSource();
if (Beatmap == null)
{
PlaceholderState = PlaceholderState.NoneSelected;
@ -146,11 +156,8 @@ namespace osu.Game.Screens.Select.Leaderboards
scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym)));
}
Scores = scores.OrderByDescending(s => scoreManager.GetTotalScore(s))
.ThenBy(s => s.OnlineScoreID)
.ToArray();
PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores;
scoreManager.GetOrderedScoresAsync(scores.ToArray(), loadCancellationSource.Token)
.ContinueWith(ordered => scoresCallback?.Invoke(ordered.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
return null;
}
@ -185,12 +192,15 @@ namespace osu.Game.Screens.Select.Leaderboards
req.Success += r =>
{
scoresCallback?.Invoke(
r.Scores.Select(s => s.CreateScoreInfo(rulesets))
.OrderByDescending(s => scoreManager.GetTotalScore(s))
.ThenBy(s => s.OnlineScoreID));
scoreManager.GetOrderedScoresAsync(r.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token)
.ContinueWith(ordered => Schedule(() =>
{
if (loadCancellationSource.IsCancellationRequested)
return;
TopScore = r.UserScore?.CreateScoreInfo(rulesets);
scoresCallback?.Invoke(ordered.Result);
TopScore = r.UserScore?.CreateScoreInfo(rulesets);
}), TaskContinuationOptions.OnlyOnRanToCompletion);
};
return req;