From 90bc8865c9a5129963e2ec1b5187c58b8f8b1284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 26 May 2025 12:44:09 +0200 Subject: [PATCH 1/3] Fix profile score display logic not matching website Reported via e-mails. The web-side change that wasn't ported here is https://github.com/ppy/osu-web/pull/11151. I wanted to port it at the time but then ran into issues because this logic should *ideally* also be applied to the beatmap set overlay leaderboards, but those are hard-glued to `ScoreInfo`, cannot be easily weaned off it to use `SoloScoreInfo` instead, and I did not want to make `ScoreInfo` even more of a mess than it already is. This time I'm just ignoring it and adding a TODO instead because I have no confidence I will get review eyes on any refactor of the beatmap set overlay. All I'll say that such refactors would have potentially beneficial effects on results screens too which also (ab)use `ScoreInfo`. --- .../API/Requests/Responses/SoloScoreInfo.cs | 8 +++ .../Sections/Ranks/DrawableProfileScore.cs | 70 ++++++++++--------- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 36f1311f9d..da4122c434 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -121,6 +121,12 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("ranked")] public bool Ranked { get; set; } + [JsonProperty("preserve")] + public bool Preserve { get; set; } + + [JsonProperty("processed")] + public bool Processed { get; set; } + // These properties are calculated or not relevant to any external usage. public bool ShouldSerializeID() => false; public bool ShouldSerializeUser() => false; @@ -129,6 +135,8 @@ namespace osu.Game.Online.API.Requests.Responses public bool ShouldSerializePP() => false; public bool ShouldSerializeOnlineID() => false; public bool ShouldSerializeHasReplay() => false; + public bool ShouldSerializePreserve() => false; + public bool ShouldSerializeProcessed() => false; // These fields only need to be serialised if they hold values. // Generally this is required because this model may be used by server-side components, but diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index 63afca8b74..407e9959f0 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -216,34 +216,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { var font = OsuFont.GetFont(weight: FontWeight.Bold); - if (Score.PP.HasValue) - { - return new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new[] - { - new OsuSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Font = font, - Text = $"{Score.PP:0}", - Colour = colourProvider.Highlight1 - }, - new OsuSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Font = font.With(size: 12), - Text = "pp", - Colour = colourProvider.Light3 - } - } - }; - } - + // cross-reference: https://github.com/ppy/osu-web/blob/a6afee076f4f68bb56dea0cb8f18db63651763a7/resources/js/profile-page/play-detail.tsx#L118-L133 if (Score.Beatmap?.Status.GrantsPerformancePoints() != true) { if (Score.Beatmap?.Status == BeatmapOnlineStatus.Loved) @@ -266,7 +239,8 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }; } - if (!Score.Ranked) + // cross-reference: https://github.com/ppy/osu-web/blob/a6afee076f4f68bb56dea0cb8f18db63651763a7/resources/js/scores/pp-value.tsx#L19-L39 + if (!Score.Ranked || !Score.Preserve || (Score.PP == null && Score.Processed)) { return new SpriteTextWithTooltip { @@ -277,12 +251,40 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }; } - return new SpriteIconWithTooltip + if (Score.PP == null) { - Icon = FontAwesome.Solid.Sync, - Size = new Vector2(font.Size), - TooltipText = ScoresStrings.StatusProcessing, - Colour = colourProvider.Highlight1 + return new SpriteIconWithTooltip + { + Icon = FontAwesome.Solid.Sync, + Size = new Vector2(font.Size), + TooltipText = ScoresStrings.StatusProcessing, + Colour = colourProvider.Highlight1 + }; + } + + return new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new[] + { + new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = font, + Text = $"{Score.PP:0}", + Colour = colourProvider.Highlight1 + }, + new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = font.With(size: 12), + Text = "pp", + Colour = colourProvider.Light3 + } + } }; } From d8546d909dd49c7ebdc9c3338e2f580c60cc1691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 26 May 2025 13:02:40 +0200 Subject: [PATCH 2/3] Adjust tests in line with new logic --- .../Online/TestSceneUserProfileScores.cs | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs index 56e4348b65..7cb5b4fbf5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs @@ -31,7 +31,8 @@ namespace osu.Game.Tests.Visual.Online Title = "JUSTadICE (TV Size)", Artist = "Oomori Seiko", }, - DifficultyName = "Extreme" + DifficultyName = "Extreme", + Status = BeatmapOnlineStatus.Ranked, }, EndedAt = DateTimeOffset.Now, Mods = new[] @@ -42,6 +43,8 @@ namespace osu.Game.Tests.Visual.Online }, Accuracy = 0.9813, Ranked = true, + Preserve = true, + Processed = true, }; var secondScore = new SoloScoreInfo @@ -55,7 +58,8 @@ namespace osu.Game.Tests.Visual.Online Title = "Triumph & Regret", Artist = "typeMARS", }, - DifficultyName = "[4K] Regret" + DifficultyName = "[4K] Regret", + Status = BeatmapOnlineStatus.Ranked, }, EndedAt = DateTimeOffset.Now, Mods = new[] @@ -65,6 +69,8 @@ namespace osu.Game.Tests.Visual.Online }, Accuracy = 0.998546, Ranked = true, + Preserve = true, + Processed = true, }; var thirdScore = new SoloScoreInfo @@ -78,11 +84,14 @@ namespace osu.Game.Tests.Visual.Online Title = "Idolize", Artist = "Creo", }, - DifficultyName = "Insane" + DifficultyName = "Insane", + Status = BeatmapOnlineStatus.Ranked, }, EndedAt = DateTimeOffset.Now, Accuracy = 0.9726, Ranked = true, + Preserve = true, + Processed = true, }; var noPPScore = new SoloScoreInfo @@ -95,11 +104,14 @@ namespace osu.Game.Tests.Visual.Online Title = "C18H27NO3(extend)", Artist = "Team Grimoire", }, - DifficultyName = "[4K] Cataclysmic Hypernova" + DifficultyName = "[4K] Cataclysmic Hypernova", + Status = BeatmapOnlineStatus.Ranked, }, EndedAt = DateTimeOffset.Now, Accuracy = 0.55879, Ranked = true, + Preserve = true, + Processed = true, }; var lovedScore = new SoloScoreInfo @@ -118,6 +130,8 @@ namespace osu.Game.Tests.Visual.Online EndedAt = DateTimeOffset.Now, Accuracy = 0.55879, Ranked = true, + Preserve = true, + Processed = true, }; var unprocessedPPScore = new SoloScoreInfo @@ -136,6 +150,8 @@ namespace osu.Game.Tests.Visual.Online EndedAt = DateTimeOffset.Now, Accuracy = 0.55879, Ranked = true, + Preserve = true, + Processed = false, }; var unrankedPPScore = new SoloScoreInfo @@ -153,7 +169,31 @@ namespace osu.Game.Tests.Visual.Online }, EndedAt = DateTimeOffset.Now, Accuracy = 0.55879, + PP = 96.83, Ranked = false, + Preserve = true, + Processed = true, + }; + + var notPreservedPPScore = new SoloScoreInfo + { + Rank = ScoreRank.B, + Beatmap = new APIBeatmap + { + BeatmapSet = new APIBeatmapSet + { + Title = "C18H27NO3(extend)", + Artist = "Team Grimoire", + }, + DifficultyName = "[4K] Cataclysmic Hypernova", + Status = BeatmapOnlineStatus.Ranked, + }, + EndedAt = DateTimeOffset.Now, + Accuracy = 0.55879, + PP = 96.83, + Ranked = true, + Preserve = false, + Processed = true, }; Add(new FillFlowContainer @@ -172,6 +212,7 @@ namespace osu.Game.Tests.Visual.Online new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(lovedScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(unprocessedPPScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(unrankedPPScore)), + new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(notPreservedPPScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(firstScore, 0.97)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(secondScore, 0.85)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(thirdScore, 0.66)), From bedac98e06de0ca4fd5886f7217998cc9e71b7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 26 May 2025 13:09:06 +0200 Subject: [PATCH 3/3] Add TODO marking incompatible logic Chances are this will not be materially noticed anyway because I'm not even sure that unranked mod scores *can* show up on leaderboards. --- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index be6ad49150..0c8943ba7d 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -200,6 +200,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores content.Add(new StatisticText(count, maxCount, @"N0") { Colour = count == 0 ? Color4.Gray : Color4.White }); } + // TODO: all this should be using the same sort of logic as `DrawableProfileScore` is, but that's not easily done + // unless the ENTIRE overlay can be weaned off of `ScoreInfo` and use `SoloScoreInfo` instead if (showPerformancePoints) { if (!score.Ranked)