mirror of
https://github.com/ppy/osu.git
synced 2026-05-13 19:54:15 +08:00
Fix song select scrolling performance when user has many beatmaps loaded (#37666)
Also fixes wrong rank showing briefly in some scenarios. --- I'm quite confused why the overhead is in the post-async-filter collection access, but it is. It occurs when using `MaxBy` (realm snapshot creation), but also when calling `.Count` on the collection, or even just accessing `sender[0]`. I tried everything, and ended up settling on simplifying the realm part enough that we can do post-filtering without much sweat or mess. Before: https://github.com/user-attachments/assets/59aed895-03ed-4923-9515-9a5426156f7e After: https://github.com/user-attachments/assets/9a37f34a-c955-45bf-877f-89f248d8ea72 Tested using [this realm](https://screvillshot.s-ul.eu/YJUJ4SR1). - Closes https://github.com/ppy/osu/issues/37574. - Closes https://github.com/ppy/osu/issues/37661.
This commit is contained in:
committed by
GitHub
Unverified
parent
0457cb924a
commit
08c02e29b9
@@ -76,6 +76,12 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
[Test]
|
||||
public void TestLocalRank()
|
||||
{
|
||||
AddStep("set null rank", () => this.ChildrenOfType<UpdateableRank>().ForEach(p =>
|
||||
{
|
||||
p.Hide();
|
||||
p.Rank = null;
|
||||
}));
|
||||
|
||||
foreach (var rank in Enum.GetValues<ScoreRank>())
|
||||
{
|
||||
AddStep($"set {rank.GetDescription()} rank", () => this.ChildrenOfType<UpdateableRank>().ForEach(p =>
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace osu.Game.Scoring
|
||||
/// <summary>
|
||||
/// The <see cref="osu.Game.Beatmaps.BeatmapInfo.Hash"/> at the point in time when the score was set.
|
||||
/// </summary>
|
||||
[Indexed]
|
||||
public string BeatmapHash { get; set; } = string.Empty;
|
||||
|
||||
public RulesetInfo Ruleset { get; set; } = null!;
|
||||
|
||||
@@ -72,15 +72,12 @@ namespace osu.Game.Screens.Select
|
||||
private void updateSubscription()
|
||||
{
|
||||
scoreSubscription?.Dispose();
|
||||
setRankFromScore(null);
|
||||
|
||||
if (beatmap == null)
|
||||
return;
|
||||
|
||||
scoreSubscription = realm.RegisterForNotifications(r =>
|
||||
r.GetAllLocalScoresForUser(api.LocalUser.Value.Id)
|
||||
.Filter($@"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0"
|
||||
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1", beatmap.ID, ruleset.Value.ShortName),
|
||||
localScoresChanged);
|
||||
scoreSubscription = realm.RegisterForNotifications(r => r.All<ScoreInfo>().Where(s => s.BeatmapHash == beatmap.Hash && !s.DeletePending), localScoresChanged);
|
||||
}
|
||||
|
||||
private void localScoresChanged(IRealmCollection<ScoreInfo> sender, ChangeSet? changes)
|
||||
@@ -90,7 +87,17 @@ namespace osu.Game.Screens.Select
|
||||
if (changes?.HasCollectionChanges() == false)
|
||||
return;
|
||||
|
||||
ScoreInfo? topScore = sender.MaxBy(info => (info.TotalScore, -info.Date.UtcDateTime.Ticks));
|
||||
ScoreInfo? topScore = sender
|
||||
// doing these post realm filter is most efficient.
|
||||
.Where(s => s.UserID == api.LocalUser.Value.Id || s.UserID <= 1)
|
||||
.Where(s => s.Ruleset.ShortName == ruleset.Value.ShortName)
|
||||
.MaxBy(info => (info.TotalScore, -info.Date.UtcDateTime.Ticks));
|
||||
|
||||
setRankFromScore(topScore);
|
||||
}
|
||||
|
||||
private void setRankFromScore(ScoreInfo? topScore)
|
||||
{
|
||||
updateable.Rank = topScore?.Rank;
|
||||
updateable.Alpha = topScore != null ? 1 : 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user