From 9707fd43f43ba37228308709329ef63137054eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 9 Jun 2025 10:52:10 +0200 Subject: [PATCH 1/3] Add failing test coverage --- .../Ranking/TestSceneSoloResultsScreen.cs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs index 1ea5e13c49..9f77956f4d 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs @@ -218,6 +218,63 @@ namespace osu.Game.Tests.Visual.Ranking AddAssert("previous user best not shown", () => this.ChildrenOfType().All(p => p.Score.OnlineID != 123456)); } + [Test] + public void TestOnlineLeaderboardWithLessThan50Scores_ShowingAnotherUserScore() + { + var scores = new List(); + var soloScores = new List(); + + AddStep("set leaderboard to global", () => leaderboardManager.FetchWithCriteria(new LeaderboardCriteria(importedBeatmap, importedBeatmap.Ruleset, BeatmapLeaderboardScope.Global, null))); + AddStep("set up request handling", () => + { + for (int i = 0; i < 30; ++i) + { + var score = TestResources.CreateTestScoreInfo(importedBeatmap); + score.TotalScore = 10_000 * (30 - i); + score.Position = i + 1; + score.User = new APIUser { Id = i }; + score.BeatmapInfo = new BeatmapInfo + { + OnlineID = 123123, + Status = BeatmapOnlineStatus.Ranked, + }; + score.OnlineID = i; + scores.Add(score); + + var soloScore = SoloScoreInfo.ForSubmission(score); + soloScore.ID = (ulong)i; + soloScores.Add(soloScore); + } + + scores[^1].User = API.LocalUser.Value; + soloScores[^1].UserID = API.LocalUser.Value.OnlineID; + + dummyAPI.HandleRequest = req => + { + switch (req) + { + case GetScoresRequest getScoresRequest: + getScoresRequest.TriggerSuccess(new APIScoresCollection + { + Scores = soloScores, + UserScore = new APIScoreWithPosition + { + Score = soloScores[^1], + Position = 30 + } + }); + return true; + } + + return false; + }; + }); + + AddStep("show results", () => LoadScreen(new SoloResultsScreen(scores[0]))); + AddUntilStep("wait for loaded", () => ((Drawable)Stack.CurrentScreen).IsLoaded); + AddAssert("local user best shown", () => this.ChildrenOfType().Any(p => p.Score.UserID == API.LocalUser.Value.Id)); + } + [Test] public void TestOnlineLeaderboardWithLessThan50Scores_UserIsLast() { From 348c727264cf7bc5e3083ed6f37773ca5ea031f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 9 Jun 2025 11:01:45 +0200 Subject: [PATCH 2/3] Fix oversight in other test --- .../Visual/Ranking/TestSceneSoloResultsScreen.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs index 9f77956f4d..cd8f234f04 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs @@ -90,6 +90,7 @@ namespace osu.Game.Tests.Visual.Ranking localScore = TestResources.CreateTestScoreInfo(importedBeatmap); localScore.TotalScore = 151_000; localScore.Position = null; + localScore.User = API.LocalUser.Value; scoreManager.Import(localScore); localScore = localScore.Detach(); }); @@ -119,6 +120,7 @@ namespace osu.Game.Tests.Visual.Ranking localScore.TotalScore = 151_000; localScore.OnlineID = 30; localScore.Position = null; + localScore.User = API.LocalUser.Value; scoreManager.Import(localScore); localScore = localScore.Detach(); }); @@ -161,6 +163,7 @@ namespace osu.Game.Tests.Visual.Ranking localScore = TestResources.CreateTestScoreInfo(importedBeatmap); localScore.TotalScore = 151_000; localScore.Position = null; + localScore.User = API.LocalUser.Value; LoadScreen(new SoloResultsScreen(localScore)); }); AddUntilStep("wait for loaded", () => ((Drawable)Stack.CurrentScreen).IsLoaded); @@ -211,6 +214,7 @@ namespace osu.Game.Tests.Visual.Ranking localScore = TestResources.CreateTestScoreInfo(importedBeatmap); localScore.TotalScore = 151_000; localScore.Position = null; + localScore.User = API.LocalUser.Value; LoadScreen(new SoloResultsScreen(localScore)); }); AddUntilStep("wait for loaded", () => ((Drawable)Stack.CurrentScreen).IsLoaded); @@ -308,6 +312,7 @@ namespace osu.Game.Tests.Visual.Ranking localScore = TestResources.CreateTestScoreInfo(importedBeatmap); localScore.TotalScore = 151_000; localScore.Position = null; + localScore.User = API.LocalUser.Value; LoadScreen(new SoloResultsScreen(localScore)); }); AddUntilStep("wait for loaded", () => ((Drawable)Stack.CurrentScreen).IsLoaded); @@ -359,6 +364,7 @@ namespace osu.Game.Tests.Visual.Ranking localScore = TestResources.CreateTestScoreInfo(importedBeatmap); localScore.TotalScore = 31_000; localScore.Position = null; + localScore.User = API.LocalUser.Value; LoadScreen(new SoloResultsScreen(localScore)); }); AddUntilStep("wait for loaded", () => ((Drawable)Stack.CurrentScreen).IsLoaded); @@ -412,6 +418,7 @@ namespace osu.Game.Tests.Visual.Ranking localScore = TestResources.CreateTestScoreInfo(importedBeatmap); localScore.TotalScore = 151_000; localScore.Position = null; + localScore.User = API.LocalUser.Value; LoadScreen(new SoloResultsScreen(localScore)); }); AddUntilStep("wait for loaded", () => ((Drawable)Stack.CurrentScreen).IsLoaded); @@ -465,6 +472,7 @@ namespace osu.Game.Tests.Visual.Ranking localScore = TestResources.CreateTestScoreInfo(importedBeatmap); localScore.TotalScore = 651_000; localScore.Position = null; + localScore.User = API.LocalUser.Value; LoadScreen(new SoloResultsScreen(localScore)); }); AddUntilStep("wait for loaded", () => ((Drawable)Stack.CurrentScreen).IsLoaded); @@ -516,6 +524,7 @@ namespace osu.Game.Tests.Visual.Ranking localScore.TotalScore = 151_000; localScore.OnlineID = 12345; localScore.Position = null; + localScore.User = API.LocalUser.Value; LoadScreen(new SoloResultsScreen(localScore)); }); AddUntilStep("wait for loaded", () => ((Drawable)Stack.CurrentScreen).IsLoaded); From 19114c74159a05e09fec6b7851bca8cb54a0a546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 9 Jun 2025 11:11:16 +0200 Subject: [PATCH 3/3] Fix presenting another user's score hiding local user's score on results screen Closes https://github.com/ppy/osu/issues/33567. --- osu.Game/Screens/Ranking/SoloResultsScreen.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/SoloResultsScreen.cs b/osu.Game/Screens/Ranking/SoloResultsScreen.cs index d11e7db178..b967c9de93 100644 --- a/osu.Game/Screens/Ranking/SoloResultsScreen.cs +++ b/osu.Game/Screens/Ranking/SoloResultsScreen.cs @@ -81,8 +81,17 @@ namespace osu.Game.Screens.Ranking Score.Position = clonedScore.Position; sortedScores.Add(Score); } - else if (criteria.Scope == BeatmapLeaderboardScope.Local || clonedScore.UserID != api.LocalUser.Value.OnlineID || clonedScore.TotalScore > Score.TotalScore) + else + { + bool isOnlineLeaderboard = criteria.Scope != BeatmapLeaderboardScope.Local; + bool presentingLocalUserScore = Score.UserID == api.LocalUser.Value.OnlineID; + bool presentedLocalUserScoreIsBetter = presentingLocalUserScore && clonedScore.UserID == api.LocalUser.Value.OnlineID && clonedScore.TotalScore < Score.TotalScore; + + if (isOnlineLeaderboard && presentedLocalUserScoreIsBetter) + continue; + sortedScores.Add(clonedScore); + } } // if we haven't encountered a match for the presented score, we still need to attach it.