diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs index ab174f303e..656402e713 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs @@ -68,6 +68,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Mania scores", () => createScoreTable(new ManiaRuleset().RulesetInfo)); AddStep("Taiko country scores", () => createCountryTable(new TaikoRuleset().RulesetInfo)); AddStep("Catch US performance page 10", () => createPerformanceTable(new CatchRuleset().RulesetInfo, "US", 10)); + AddStep("Osu spotlight table (chart 271)", () => createSpotlightTable(new OsuRuleset().RulesetInfo, 271)); } private void createCountryTable(RulesetInfo ruleset, int page = 1) @@ -112,6 +113,20 @@ namespace osu.Game.Tests.Visual.Online api.Queue(request); } + private void createSpotlightTable(RulesetInfo ruleset, int spotlight) + { + onLoadStarted(); + + request = new GetSpotlightRankingsRequest(ruleset, spotlight); + ((GetSpotlightRankingsRequest)request).Success += rankings => Schedule(() => + { + var table = new ScoresTable(1, rankings.Users); + loadTable(table); + }); + + api.Queue(request); + } + private void onLoadStarted() { loading.Show(); diff --git a/osu.Game/Online/API/Requests/GetSpotlightRankingsRequest.cs b/osu.Game/Online/API/Requests/GetSpotlightRankingsRequest.cs new file mode 100644 index 0000000000..a279db134f --- /dev/null +++ b/osu.Game/Online/API/Requests/GetSpotlightRankingsRequest.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.IO.Network; +using osu.Game.Rulesets; + +namespace osu.Game.Online.API.Requests +{ + public class GetSpotlightRankingsRequest : GetRankingsRequest + { + private readonly int spotlight; + + public GetSpotlightRankingsRequest(RulesetInfo ruleset, int spotlight) + : base(ruleset, 1) + { + this.spotlight = spotlight; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + + req.AddParameter("spotlight", spotlight.ToString()); + + return req; + } + + protected override string TargetPostfix() => "charts"; + } +} diff --git a/osu.Game/Online/API/Requests/GetSpotlightRankingsResponse.cs b/osu.Game/Online/API/Requests/GetSpotlightRankingsResponse.cs new file mode 100644 index 0000000000..2259314a9f --- /dev/null +++ b/osu.Game/Online/API/Requests/GetSpotlightRankingsResponse.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using Newtonsoft.Json; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users; + +namespace osu.Game.Online.API.Requests +{ + public class GetSpotlightRankingsResponse + { + [JsonProperty("ranking")] + public List Users; + + [JsonProperty("spotlight")] + public APISpotlight Spotlight; + + [JsonProperty("beatmapsets")] + public List BeatmapSets; + } +} diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index e12c977430..bb85b4a37b 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -42,7 +42,12 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding(10), + Padding = new MarginPadding + { + Vertical = 10, + Left = 10, + Right = 25, + }, Children = new Drawable[] { new AutoSizingGrid diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs index 7d410d0d34..8a17fef367 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs @@ -23,6 +23,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public class TopScoreStatisticsSection : CompositeDrawable { private const float margin = 10; + private const float top_columns_min_width = 64; + private const float bottom_columns_min_width = 45; private readonly FontUsage smallFont = OsuFont.GetFont(size: 16); private readonly FontUsage largeFont = OsuFont.GetFont(size: 22); @@ -44,9 +46,24 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Spacing = new Vector2(10, 0), + Direction = FillDirection.Vertical, + Spacing = new Vector2(10, 8), Children = new Drawable[] { + new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(margin, 0), + Children = new Drawable[] + { + totalScoreColumn = new TextColumn("total score", largeFont, top_columns_min_width), + accuracyColumn = new TextColumn("accuracy", largeFont, top_columns_min_width), + maxComboColumn = new TextColumn("max combo", largeFont, top_columns_min_width) + } + }, new FillFlowContainer { Anchor = Anchor.TopRight, @@ -62,24 +79,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Direction = FillDirection.Horizontal, Spacing = new Vector2(margin, 0), }, - ppColumn = new TextColumn("pp", smallFont), + ppColumn = new TextColumn("pp", smallFont, bottom_columns_min_width), modsColumn = new ModsInfoColumn(), } }, - new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(margin, 0), - Children = new Drawable[] - { - totalScoreColumn = new TextColumn("total score", largeFont), - accuracyColumn = new TextColumn("accuracy", largeFont), - maxComboColumn = new TextColumn("max combo", largeFont) - } - }, } }; } @@ -96,12 +99,14 @@ namespace osu.Game.Overlays.BeatmapSet.Scores maxComboColumn.Text = $@"{value.MaxCombo:N0}x"; ppColumn.Text = $@"{value.PP:N0}"; - statisticsColumns.ChildrenEnumerable = value.Statistics.Select(kvp => createStatisticsColumn(kvp.Key, kvp.Value)); + statisticsColumns.ChildrenEnumerable = value.Statistics + .OrderByDescending(pair => pair.Key) + .Select(kvp => createStatisticsColumn(kvp.Key, kvp.Value)); modsColumn.Mods = value.Mods; } } - private TextColumn createStatisticsColumn(HitResult hitResult, int count) => new TextColumn(hitResult.GetDescription(), smallFont) + private TextColumn createStatisticsColumn(HitResult hitResult, int count) => new TextColumn(hitResult.GetDescription(), smallFont, bottom_columns_min_width) { Text = count.ToString() }; @@ -111,7 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly Box separator; private readonly OsuSpriteText text; - public InfoColumn(string title, Drawable content) + public InfoColumn(string title, Drawable content, float? minWidth = null) { AutoSizeAxes = Axes.Both; @@ -119,18 +124,20 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 2), + Spacing = new Vector2(0, 1), Children = new[] { text = new OsuSpriteText { - Font = OsuFont.GetFont(size: 10, weight: FontWeight.Black), + Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold), Text = title.ToUpper() }, separator = new Box { - RelativeSizeAxes = Axes.X, - Height = 1 + RelativeSizeAxes = minWidth == null ? Axes.X : Axes.None, + Width = minWidth ?? 1f, + Height = 2, + Margin = new MarginPadding { Top = 2 } }, content } @@ -140,7 +147,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - separator.Colour = text.Colour = colourProvider.Foreground1; + text.Colour = colourProvider.Foreground1; + separator.Colour = colourProvider.Background3; } } @@ -148,13 +156,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { private readonly SpriteText text; - public TextColumn(string title, FontUsage font) - : this(title, new OsuSpriteText { Font = font }) + public TextColumn(string title, FontUsage font, float? minWidth = null) + : this(title, new OsuSpriteText { Font = font }, minWidth) { } - private TextColumn(string title, SpriteText text) - : base(title, text) + private TextColumn(string title, SpriteText text, float? minWidth = null) + : base(title, text, minWidth) { this.text = text; } diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index 351c4df6b7..0e77d7d764 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Users; +using osu.Game.Scoring; namespace osu.Game.Overlays.Rankings.Tables { @@ -44,9 +45,9 @@ namespace osu.Game.Overlays.Rankings.Tables new ColoredRowText { Text = $@"{item.PlayCount:N0}", }, }.Concat(CreateUniqueContent(item)).Concat(new[] { - new ColoredRowText { Text = $@"{item.GradesCount.SS + item.GradesCount.SSPlus:N0}", }, - new ColoredRowText { Text = $@"{item.GradesCount.S + item.GradesCount.SPlus:N0}", }, - new ColoredRowText { Text = $@"{item.GradesCount.A:N0}", } + new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.XH] + item.GradesCount[ScoreRank.X]:N0}", }, + new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.SH] + item.GradesCount[ScoreRank.S]:N0}", }, + new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.A]:N0}", } }).ToArray(); protected abstract TableColumn[] CreateUniqueHeaders(); diff --git a/osu.Game/Users/UserStatistics.cs b/osu.Game/Users/UserStatistics.cs index e5e77821ab..8b7699d0ad 100644 --- a/osu.Game/Users/UserStatistics.cs +++ b/osu.Game/Users/UserStatistics.cs @@ -30,7 +30,7 @@ namespace osu.Game.Users public decimal? PP; [JsonProperty(@"pp_rank")] // the API sometimes only returns this value in condensed user responses - private int rank + private int? rank { set => Ranks.Global = value; } @@ -71,13 +71,13 @@ namespace osu.Game.Users public struct Grades { [JsonProperty(@"ssh")] - public int SSPlus; + public int? SSPlus; [JsonProperty(@"ss")] public int SS; [JsonProperty(@"sh")] - public int SPlus; + public int? SPlus; [JsonProperty(@"s")] public int S; @@ -92,13 +92,13 @@ namespace osu.Game.Users switch (rank) { case ScoreRank.XH: - return SSPlus; + return SSPlus ?? 0; case ScoreRank.X: return SS; case ScoreRank.SH: - return SPlus; + return SPlus ?? 0; case ScoreRank.S: return S;