Skip to content

Commit 040bb1b

Browse files
committed
Fix solo leaderboard sometimes not showing user position while it technically could
The "partial" leaderboard logic in `SoloGameplayLeaderboardProvider` always assumed the online fetch would request 50 scores, which is no longer the case after #33100.
1 parent dcb30ed commit 040bb1b

File tree

6 files changed

+52
-16
lines changed

6 files changed

+52
-16
lines changed

osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public void TestDisplay()
105105
new ScoreInfo { User = new APIUser { Username = "Top", Id = 2 }, TotalScore = 900_000, Accuracy = 0.99, MaxCombo = 999 },
106106
new ScoreInfo { User = new APIUser { Username = "Second", Id = 14 }, TotalScore = 800_000, Accuracy = 0.9, MaxCombo = 888 },
107107
new ScoreInfo { User = friend, TotalScore = 700_000, Accuracy = 0.88, MaxCombo = 777 },
108-
}, 3, null);
108+
}, scoresRequested: 50, totalScores: 3, null);
109109
});
110110

111111
createLeaderboard();
@@ -144,7 +144,7 @@ public void TestLongScores()
144144
new ScoreInfo { User = new APIUser { Username = "Top", Id = 2 }, TotalScore = 900_000_000, Accuracy = 0.99, MaxCombo = 999999 },
145145
new ScoreInfo { User = new APIUser { Username = "Second", Id = 14 }, TotalScore = 800_000_000, Accuracy = 0.9, MaxCombo = 888888 },
146146
new ScoreInfo { User = friend, TotalScore = 700_000_000, Accuracy = 0.88, MaxCombo = 777777 },
147-
}, 3, null);
147+
}, scoresRequested: 50, totalScores: 3, null);
148148
});
149149

150150
createLeaderboard();
@@ -170,7 +170,7 @@ public void TestLayoutWithManyScores()
170170
scores.Add(new ScoreInfo { User = new APIUser { Username = $"Player {i + 1}" }, TotalScore = RNG.Next(700_000, 1_000_000) });
171171

172172
// this is dodgy but anything less dodgy is a lot of work
173-
((Bindable<LeaderboardScores?>)leaderboardManager.Scores).Value = LeaderboardScores.Success(scores, scores.Count, null);
173+
((Bindable<LeaderboardScores?>)leaderboardManager.Scores).Value = LeaderboardScores.Success(scores, scoresRequested: 50, scores.Count, null);
174174
gameplayState.ScoreProcessor.TotalScore.Value = 0;
175175
});
176176

@@ -208,7 +208,7 @@ public void TestExistingUsers()
208208
new ScoreInfo { User = new APIUser { Username = "smoogipoo", Id = 1040328 }, TotalScore = 800_000, Accuracy = 0.9, MaxCombo = 888 },
209209
new ScoreInfo { User = new APIUser { Username = "flyte", Id = 3103765 }, TotalScore = 700_000, Accuracy = 0.9, MaxCombo = 888 },
210210
new ScoreInfo { User = new APIUser { Username = "frenzibyte", Id = 14210502 }, TotalScore = 600_000, Accuracy = 0.9, MaxCombo = 777 },
211-
}, 4, null);
211+
}, scoresRequested: 50, totalScores: 4, null);
212212
});
213213

214214
createLeaderboard();
@@ -223,7 +223,7 @@ public void TestQuitScore()
223223
((Bindable<LeaderboardScores?>)leaderboardManager.Scores).Value = LeaderboardScores.Success(new[]
224224
{
225225
new ScoreInfo { User = new APIUser { Username = "Quit", Id = 3 }, TotalScore = 100_000, Accuracy = 0.99, MaxCombo = 999 },
226-
}, 1, null);
226+
}, scoresRequested: 50, totalScores: 1, null);
227227
});
228228

229229
createLeaderboard();

osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboardProvider.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ public void TestLocalLeaderboardHasPositionsAutofilled()
3737
TotalScore = 10_000 * (100 - i),
3838
Position = i,
3939
}).ToArray(),
40-
1337,
40+
scoresRequested: 100,
41+
totalScores: 100,
4142
null
4243
);
4344
});
@@ -84,7 +85,8 @@ public void TestFullGlobalLeaderboard()
8485
TotalScore = 600_000 + 10_000 * (40 - i),
8586
Position = i,
8687
}).ToArray(),
87-
1337,
88+
scoresRequested: 50,
89+
totalScores: 40,
8890
null
8991
);
9092
});
@@ -131,7 +133,8 @@ public void TestPartialGlobalLeaderboard()
131133
TotalScore = 500_000 + 10_000 * (50 - i),
132134
Position = i
133135
}).ToArray(),
134-
1337,
136+
scoresRequested: 50,
137+
totalScores: 1337,
135138
new ScoreInfo { TotalScore = 200_000 }
136139
);
137140
});

osu.Game/Online/API/Requests/GetScoresRequest.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public class GetScoresRequest : APIRequest<APIScoresCollection>, IEquatable<GetS
2020
public const int DEFAULT_SCORES_PER_REQUEST = 50;
2121
public const int MAX_SCORES_PER_REQUEST = 100;
2222

23+
public int ScoresRequested { get; }
24+
2325
private readonly IBeatmapInfo beatmapInfo;
2426
private readonly BeatmapLeaderboardScope scope;
2527
private readonly IRulesetInfo ruleset;
@@ -37,6 +39,8 @@ public GetScoresRequest(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, BeatmapL
3739
this.scope = scope;
3840
this.ruleset = ruleset ?? throw new ArgumentNullException(nameof(ruleset));
3941
this.mods = mods ?? Array.Empty<IMod>();
42+
43+
ScoresRequested = this.scope.RequiresSupporter(this.mods.Any()) ? MAX_SCORES_PER_REQUEST : DEFAULT_SCORES_PER_REQUEST;
4044
}
4145

4246
protected override string Target => $@"beatmaps/{beatmapInfo.OnlineID}/scores";
@@ -51,7 +55,7 @@ protected override WebRequest CreateWebRequest()
5155
foreach (var mod in mods)
5256
req.AddParameter(@"mods[]", mod.Acronym);
5357

54-
req.AddParameter(@"limit", (scope.RequiresSupporter(mods.Any()) ? MAX_SCORES_PER_REQUEST : DEFAULT_SCORES_PER_REQUEST).ToString(CultureInfo.InvariantCulture));
58+
req.AddParameter(@"limit", ScoresRequested.ToString(CultureInfo.InvariantCulture));
5559
return req;
5660
}
5761

osu.Game/Online/Leaderboards/LeaderboardManager.cs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ public void FetchWithCriteria(LeaderboardCriteria newCriteria, bool forceRefresh
144144
return s;
145145
})
146146
.ToArray(),
147-
response.ScoresCount,
147+
scoresRequested: newRequest.ScoresRequested,
148+
totalScores: response.ScoresCount,
148149
response.UserScore?.CreateScoreInfo(rulesets, newCriteria.Beatmap)
149150
);
150151
inFlightOnlineRequest = null;
@@ -194,7 +195,7 @@ private void localScoresChanged(IRealmCollection<ScoreInfo> sender, ChangeSet? c
194195
newScores = newScores.Detach().OrderByCriteria(CurrentCriteria.Sorting);
195196

196197
var newScoresArray = newScores.ToArray();
197-
scores.Value = LeaderboardScores.Success(newScoresArray, newScoresArray.Length, null);
198+
scores.Value = LeaderboardScores.Success(newScoresArray, scoresRequested: newScoresArray.Length, totalScores: newScoresArray.Length, null);
198199
}
199200

200201
protected override void Dispose(bool isDisposing)
@@ -215,9 +216,33 @@ public record LeaderboardCriteria(
215216

216217
public record LeaderboardScores
217218
{
219+
/// <summary>
220+
/// The collection of all scores received through the leaderboard lookup.
221+
/// </summary>
218222
public ICollection<ScoreInfo> TopScores { get; }
223+
224+
/// <summary>
225+
/// The number of scores which was requested.
226+
/// Used to determine whether the returned leaderboard can be judged to be a partial or full leaderboard
227+
/// (i.e. whether <see cref="TopScores"/> contains all scores that it could ever contain).
228+
/// </summary>
229+
public int ScoresRequested { get; }
230+
231+
/// <summary>
232+
/// The number of all scores that exist on the leaderboard.
233+
/// </summary>
219234
public int TotalScores { get; }
235+
236+
public bool IsPartial => ScoresRequested < TotalScores;
237+
238+
/// <summary>
239+
/// The local user's best score.
240+
/// </summary>
220241
public ScoreInfo? UserScore { get; }
242+
243+
/// <summary>
244+
/// The failure state that occurred when attempting to retrieve the leaderboard.
245+
/// </summary>
221246
public LeaderboardFailState? FailState { get; }
222247

223248
public IEnumerable<ScoreInfo> AllScores
@@ -232,16 +257,20 @@ public IEnumerable<ScoreInfo> AllScores
232257
}
233258
}
234259

235-
private LeaderboardScores(ICollection<ScoreInfo> topScores, int totalScores, ScoreInfo? userScore, LeaderboardFailState? failState)
260+
private LeaderboardScores(ICollection<ScoreInfo> topScores, int scoresRequested, int totalScores, ScoreInfo? userScore, LeaderboardFailState? failState)
236261
{
237262
TopScores = topScores;
263+
ScoresRequested = scoresRequested;
238264
TotalScores = totalScores;
239265
UserScore = userScore;
240266
FailState = failState;
241267
}
242268

243-
public static LeaderboardScores Success(ICollection<ScoreInfo> topScores, int totalScores, ScoreInfo? userScore) => new LeaderboardScores(topScores, totalScores, userScore, null);
244-
public static LeaderboardScores Failure(LeaderboardFailState failState) => new LeaderboardScores([], 0, null, failState);
269+
public static LeaderboardScores Success(ICollection<ScoreInfo> topScores, int scoresRequested, int totalScores, ScoreInfo? userScore)
270+
=> new LeaderboardScores(topScores, scoresRequested, totalScores, userScore, null);
271+
272+
public static LeaderboardScores Failure(LeaderboardFailState failState)
273+
=> new LeaderboardScores([], scoresRequested: 0, totalScores: 0, null, failState);
245274
}
246275

247276
public enum LeaderboardFailState

osu.Game/Screens/Ranking/SoloResultsScreen.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ protected override async Task<ScoreInfo[]> FetchScores()
120120
sortedScores = sortedScores.OrderByTotalScore().ToList();
121121

122122
int delta = 0;
123-
bool isPartialLeaderboard = leaderboardManager.CurrentCriteria?.Scope != BeatmapLeaderboardScope.Local && result.TopScores.Count >= 50;
123+
bool isPartialLeaderboard = result.IsPartial;
124124

125125
for (int i = 0; i < sortedScores.Count; i++)
126126
{

osu.Game/Screens/Select/Leaderboards/SoloGameplayLeaderboardProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ protected override void LoadComplete()
3333

3434
var globalScores = leaderboardManager?.Scores.Value;
3535

36-
isPartial = leaderboardManager?.CurrentCriteria?.Scope != BeatmapLeaderboardScope.Local && globalScores?.TopScores.Count >= 50;
36+
isPartial = globalScores == null || globalScores.IsPartial;
3737

3838
List<GameplayLeaderboardScore> newScores = new List<GameplayLeaderboardScore>();
3939

0 commit comments

Comments
 (0)