From e6a74fd1f398c2eafd586e75ae035cb2f0af2d69 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 16 Apr 2026 14:36:02 +0900 Subject: [PATCH] Ranked Play: Work around rating data not always including user (#37310) Fixes https://discord.com/channels/188630481301012481/188630652340404224/1493678774540304505 The rating distribution is updated once every 5 minutes, so there are periods where it may not include the local user's rating. This is simply a workaround where it's considered if it's bounded by it. Am a little surprised this is as easy to handle as it appears to be, even if not the cleanest presentation (it's an edge case). --- .../TestSceneRatingDistributionGraph.cs | 31 +++++++++++++++++++ .../Queue/RatingDistributionGraph.cs | 14 ++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneRatingDistributionGraph.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneRatingDistributionGraph.cs index b9c2e979a5..6f4d9aa9b7 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneRatingDistributionGraph.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneRatingDistributionGraph.cs @@ -61,6 +61,37 @@ namespace osu.Game.Tests.Visual.Matchmaking AddStep("set empty data", () => graph.SetData([], null)); } + [Test] + public void TestOutOfBoundsUserRating() + { + AddStep("set data with max user rating", () => + { + List<(int x, int y)> values = new List<(int x, int y)>(); + for (int i = 400; i <= 2800; i += 100) + values.Add((i, (int)Math.Round(generateCount(i, 1600, 400, 7200)))); + + graph.SetData(values.ToArray(), 4000); + }); + + AddStep("set data with min user rating", () => + { + List<(int x, int y)> values = new List<(int x, int y)>(); + for (int i = 400; i <= 2800; i += 100) + values.Add((i, (int)Math.Round(generateCount(i, 1600, 400, 7200)))); + + graph.SetData(values.ToArray(), 0); + }); + + AddStep("set data with only user rating", () => + { + List<(int x, int y)> values = new List<(int x, int y)>(); + for (int i = 400; i <= 2800; i += 100) + values.Add((i, (int)Math.Round(generateCount(i, 1600, 400, 7200)))); + + graph.SetData([], 1500); + }); + } + private static double generateCount(double x, double mean, double stdDev, double amplitude) { return amplitude * Math.Exp(-Math.Pow(x - mean, 2) / (2 * Math.Pow(stdDev, 2))) + Random.Shared.Next(300); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/RatingDistributionGraph.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/RatingDistributionGraph.cs index aba47e9591..d4d4a83eb6 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/RatingDistributionGraph.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/RatingDistributionGraph.cs @@ -236,9 +236,21 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue data.Zip(data.Skip(1), (a, b) => Math.Abs(b.x - a.x)).DefaultIfEmpty().Min() ); + if (userRating < xRange.min) + { + this.data = this.data.Prepend((userRating.Value, 1)).ToArray(); + xRange.min = userRating.Value; + } + + if (userRating > xRange.max) + { + this.data = this.data.Append((userRating.Value, 1)).ToArray(); + xRange.max = userRating.Value; + } + yRange = ( 0, - (int)roundToSignificant(data.Select(d => d.y).DefaultIfEmpty().Max()) + (int)roundToSignificant(this.data.Select(d => d.y).DefaultIfEmpty().Max()) ); updateGraph();