Skip to content
28 changes: 21 additions & 7 deletions osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
Expand Down Expand Up @@ -245,13 +246,26 @@

// We may want to iterate on the following conditions further in the future

var localUserScore = AchievedScore ?? realm.Run(r =>
r.GetAllLocalScoresForUser(api.LocalUser.Value.Id)
.Filter($@"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0", newScore.BeatmapInfo.ID)
.AsEnumerable()
.OrderByDescending(score => score.Ruleset.MatchesOnlineID(newScore.BeatmapInfo.Ruleset))
.ThenByDescending(score => score.Rank)
.FirstOrDefault());
var localUserScore = AchievedScore;

if (localUserScore == null)
Copy link
Copy Markdown
Collaborator

@bdach bdach Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this makes sense anymore? If the point is to allow tagging if any local score matches, then there's little reason to still prefer the latest set score if the user has already proven themselves capable to tag.

{
var localUserScores = realm.Run(r =>
r.GetAllLocalScoresForUser(api.LocalUser.Value.Id)
.Filter($@"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0", newScore.BeatmapInfo.ID)
.AsEnumerable()
.OrderByDescending(score => score.Ruleset.MatchesOnlineID(newScore.BeatmapInfo.Ruleset))
.ThenByDescending(score => score.Rank)
.ToArray());

localUserScore = Array.Find(localUserScores, score =>
{
return (score.Ruleset.OnlineID == newScore.BeatmapInfo!.Ruleset.OnlineID)
&& (score.Rank >= ScoreRank.C)
&& (!score.Mods.Any(m => (m.Type == ModType.Conversion)
|| m is not ModClassic));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not even sure this is correctly transcribed from code lower down. m.Type == ModTypeConversion || m is not ModClassic is not the same thing as (m.Type == ModType.Conversion) && !(m is ModClassic).

This should either be && in both places or the first should be correctly negated as per generalized De Morgan's laws.

In general there's kind of little reason why this needs to be duplicated like this. I imagine that you could split a method like getReasonForPreventingTagging(ScoreInfo) and then use it here instead in a getReasonForPreventingTagging(score) == null manner.

}) ?? localUserScores.FirstOrDefault();
}

if (localUserScore == null)
preventTaggingReason = "Play the beatmap to contribute to beatmap tags!";
Expand Down
Loading