From c5c4c85006ffd4a34e05ba33d6e81bb9acf8acc8 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 13:29:18 +0800 Subject: [PATCH 01/15] Lazily create content of StatisticItem --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 22 +++++++++------- osu.Game.Rulesets.Osu/OsuRuleset.cs | 25 +++++++++++-------- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 22 +++++++++------- .../Ranking/Statistics/StatisticContainer.cs | 2 +- .../Ranking/Statistics/StatisticItem.cs | 12 +++++++-- .../Ranking/Statistics/StatisticsPanel.cs | 10 +++++--- 6 files changed, 59 insertions(+), 34 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 2098c7f5d8..8ac8001457 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -370,21 +370,25 @@ namespace osu.Game.Rulesets.Mania { Columns = new[] { - new StatisticItem("Timing Distribution", new HitEventTimingDistributionGraph(score.HitEvents) - { - RelativeSizeAxes = Axes.X, - Height = 250 - }), + new StatisticItem("Timing Distribution", + true, + () => new HitEventTimingDistributionGraph(score.HitEvents) + { + RelativeSizeAxes = Axes.X, + Height = 250 + }), } }, new StatisticRow { Columns = new[] { - new StatisticItem(string.Empty, new SimpleStatisticTable(3, new SimpleStatisticItem[] - { - new UnstableRate(score.HitEvents) - })) + new StatisticItem(string.Empty, + true, + () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + { + new UnstableRate(score.HitEvents) + })) } } }; diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 18e4bb259c..b6f417b7fe 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -278,7 +278,8 @@ namespace osu.Game.Rulesets.Osu Columns = new[] { new StatisticItem("Timing Distribution", - new HitEventTimingDistributionGraph(timedHitEvents) + true, + () => new HitEventTimingDistributionGraph(timedHitEvents) { RelativeSizeAxes = Axes.X, Height = 250 @@ -289,21 +290,25 @@ namespace osu.Game.Rulesets.Osu { Columns = new[] { - new StatisticItem("Accuracy Heatmap", new AccuracyHeatmap(score, playableBeatmap) - { - RelativeSizeAxes = Axes.X, - Height = 250 - }), + new StatisticItem("Accuracy Heatmap", + true, + () => new AccuracyHeatmap(score, playableBeatmap) + { + RelativeSizeAxes = Axes.X, + Height = 250 + }), } }, new StatisticRow { Columns = new[] { - new StatisticItem(string.Empty, new SimpleStatisticTable(3, new SimpleStatisticItem[] - { - new UnstableRate(timedHitEvents) - })) + new StatisticItem(string.Empty, + true, + () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + { + new UnstableRate(timedHitEvents) + })) } } }; diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index ca860f24c3..2a64b8dddd 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -213,21 +213,25 @@ namespace osu.Game.Rulesets.Taiko { Columns = new[] { - new StatisticItem("Timing Distribution", new HitEventTimingDistributionGraph(timedHitEvents) - { - RelativeSizeAxes = Axes.X, - Height = 250 - }), + new StatisticItem("Timing Distribution", + true, + () => new HitEventTimingDistributionGraph(timedHitEvents) + { + RelativeSizeAxes = Axes.X, + Height = 250 + }), } }, new StatisticRow { Columns = new[] { - new StatisticItem(string.Empty, new SimpleStatisticTable(3, new SimpleStatisticItem[] - { - new UnstableRate(timedHitEvents) - })) + new StatisticItem(string.Empty, + true, + () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + { + new UnstableRate(timedHitEvents) + })) } } }; diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs index 485d24d024..f3bd2c6fc1 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Ranking.Statistics RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Margin = new MarginPadding { Top = 15 }, - Child = item.Content + Child = item.Content() } }, }, diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index 4903983759..5e6ddf445b 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -20,22 +21,29 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// The content to be displayed. /// - public readonly Drawable Content; + public readonly Func Content; /// /// The of this row. This can be thought of as the column dimension of an encompassing . /// public readonly Dimension Dimension; + /// + /// Whether this item requires hit events. If true, the will not be created if no hit events are available. + /// + public readonly bool RequiresHitEvents; + /// /// Creates a new , to be displayed inside a in the results screen. /// /// The name of the item. Can be to hide the item header. + /// Whether this item requires hit events. If true, the will not be created if no hit events are available. /// The content to be displayed. /// The of this item. This can be thought of as the column dimension of an encompassing . - public StatisticItem([NotNull] string name, [NotNull] Drawable content, [CanBeNull] Dimension dimension = null) + public StatisticItem([NotNull] string name, bool requiresHitEvents, [NotNull] Func content, [CanBeNull] Dimension dimension = null) { Name = name; + RequiresHitEvents = requiresHitEvents; Content = content; Dimension = dimension; } diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 567a2307dd..14cdfe2f03 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -118,6 +118,10 @@ namespace osu.Game.Screens.Ranking.Statistics foreach (var row in newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, playableBeatmap)) { + var columnsToDisplay = newScore.HitEvents.Count == 0 + ? row.Columns?.Where(c => !c.RequiresHitEvents).ToArray() + : row.Columns; + rows.Add(new GridContainer { Anchor = Anchor.TopCentre, @@ -126,14 +130,14 @@ namespace osu.Game.Screens.Ranking.Statistics AutoSizeAxes = Axes.Y, Content = new[] { - row.Columns?.Select(c => new StatisticContainer(c) + columnsToDisplay?.Select(c => new StatisticContainer(c) { Anchor = Anchor.Centre, Origin = Anchor.Centre, }).Cast().ToArray() }, - ColumnDimensions = Enumerable.Range(0, row.Columns?.Length ?? 0) - .Select(i => row.Columns[i].Dimension ?? new Dimension()).ToArray(), + ColumnDimensions = Enumerable.Range(0, columnsToDisplay?.Length ?? 0) + .Select(i => columnsToDisplay?[i].Dimension ?? new Dimension()).ToArray(), RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } }); } From 3ba5d88914d09e1725ee3abaec9fd44699e3973c Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 13:41:51 +0800 Subject: [PATCH 02/15] Update statistics item display logic --- .../Ranking/Statistics/StatisticsPanel.cs | 131 +++++++++--------- 1 file changed, 69 insertions(+), 62 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 14cdfe2f03..9d89aa213c 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -74,85 +74,92 @@ namespace osu.Game.Screens.Ranking.Statistics if (newScore == null) return; - if (newScore.HitEvents.Count == 0) + spinner.Show(); + + var localCancellationSource = loadCancellation = new CancellationTokenSource(); + IBeatmap playableBeatmap = null; + + // Todo: The placement of this is temporary. Eventually we'll both generate the playable beatmap _and_ run through it in a background task to generate the hit events. + Task.Run(() => { - content.Add(new FillFlowContainer + playableBeatmap = beatmapManager.GetWorkingBeatmap(newScore.BeatmapInfo).GetPlayableBeatmap(newScore.Ruleset, newScore.Mods); + }, loadCancellation.Token).ContinueWith(t => Schedule(() => + { + var rows = new FillFlowContainer { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Direction = FillDirection.Vertical, - Children = new Drawable[] + Spacing = new Vector2(30, 15), + Alpha = 0 + }; + + bool panelIsEmpty = true; + bool hitEventsAvailable = newScore.HitEvents.Count != 0; + + foreach (var row in newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, playableBeatmap)) + { + var columnsToDisplay = hitEventsAvailable + ? row.Columns + : row.Columns?.Where(c => !c.RequiresHitEvents).ToArray(); + + if (columnsToDisplay?.Any() ?? false) + panelIsEmpty = false; + + rows.Add(new GridContainer { - new MessagePlaceholder("Extended statistics are only available after watching a replay!"), - new ReplayDownloadButton(newScore) + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Content = new[] { - Scale = new Vector2(1.5f), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + columnsToDisplay?.Select(c => new StatisticContainer(c) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }).Cast().ToArray() }, - } - }); - } - else - { - spinner.Show(); + ColumnDimensions = Enumerable.Range(0, columnsToDisplay?.Length ?? 0) + .Select(i => columnsToDisplay?[i].Dimension ?? new Dimension()).ToArray(), + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } + }); + } - var localCancellationSource = loadCancellation = new CancellationTokenSource(); - IBeatmap playableBeatmap = null; - - // Todo: The placement of this is temporary. Eventually we'll both generate the playable beatmap _and_ run through it in a background task to generate the hit events. - Task.Run(() => + if (!hitEventsAvailable) { - playableBeatmap = beatmapManager.GetWorkingBeatmap(newScore.BeatmapInfo).GetPlayableBeatmap(newScore.Ruleset, newScore.Mods); - }, loadCancellation.Token).ContinueWith(t => Schedule(() => - { - var rows = new FillFlowContainer + rows.Add(new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, Direction = FillDirection.Vertical, - Spacing = new Vector2(30, 15), - Alpha = 0 - }; - - foreach (var row in newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, playableBeatmap)) - { - var columnsToDisplay = newScore.HitEvents.Count == 0 - ? row.Columns?.Where(c => !c.RequiresHitEvents).ToArray() - : row.Columns; - - rows.Add(new GridContainer + Children = new Drawable[] { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Content = new[] + new MessagePlaceholder(panelIsEmpty + ? "Extended statistics are only available after watching a replay!" + : "More statistics available after watching a replay!"), + new ReplayDownloadButton(newScore) { - columnsToDisplay?.Select(c => new StatisticContainer(c) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }).Cast().ToArray() + Scale = new Vector2(1.5f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, }, - ColumnDimensions = Enumerable.Range(0, columnsToDisplay?.Length ?? 0) - .Select(i => columnsToDisplay?[i].Dimension ?? new Dimension()).ToArray(), - RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } - }); - } + } + }); + } - LoadComponentAsync(rows, d => - { - if (!Score.Value.Equals(newScore)) - return; + LoadComponentAsync(rows, d => + { + if (!Score.Value.Equals(newScore)) + return; - spinner.Hide(); - content.Add(d); - d.FadeIn(250, Easing.OutQuint); - }, localCancellationSource.Token); - }), localCancellationSource.Token); - } + spinner.Hide(); + content.Add(d); + d.FadeIn(250, Easing.OutQuint); + }, localCancellationSource.Token); + }), localCancellationSource.Token); } protected override bool OnClick(ClickEvent e) From 5e3d124eef996801dcb315cc48ed7499dc4aa0ef Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 17:20:22 +0800 Subject: [PATCH 03/15] Add scrolling to the extended statistics panel --- .../Ranking/Statistics/StatisticsPanel.cs | 78 +++++++++++++------ 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 9d89aa213c..1c96e640b4 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Placeholders; using osu.Game.Scoring; @@ -85,15 +86,21 @@ namespace osu.Game.Screens.Ranking.Statistics playableBeatmap = beatmapManager.GetWorkingBeatmap(newScore.BeatmapInfo).GetPlayableBeatmap(newScore.Ruleset, newScore.Mods); }, loadCancellation.Token).ContinueWith(t => Schedule(() => { - var rows = new FillFlowContainer + FillFlowContainer rows; + Container container = new OsuScrollContainer(Direction.Vertical) { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Direction = FillDirection.Vertical, - Spacing = new Vector2(30, 15), - Alpha = 0 + Alpha = 0, + Children = new[] + { + rows = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + } + } }; bool panelIsEmpty = true; @@ -107,6 +114,8 @@ namespace osu.Game.Screens.Ranking.Statistics if (columnsToDisplay?.Any() ?? false) panelIsEmpty = false; + else + continue; rows.Add(new GridContainer { @@ -114,6 +123,7 @@ namespace osu.Game.Screens.Ranking.Statistics Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Bottom = 15 }, Content = new[] { columnsToDisplay?.Select(c => new StatisticContainer(c) @@ -130,27 +140,51 @@ namespace osu.Game.Screens.Ranking.Statistics if (!hitEventsAvailable) { - rows.Add(new FillFlowContainer + if (panelIsEmpty) { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] + // Replace the scroll container with fill flow container to get the message centered. + container = new FillFlowContainer { - new MessagePlaceholder(panelIsEmpty - ? "Extended statistics are only available after watching a replay!" - : "More statistics available after watching a replay!"), - new ReplayDownloadButton(newScore) + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Direction = FillDirection.Vertical, + Children = new Drawable[] { - Scale = new Vector2(1.5f), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - } - }); + new MessagePlaceholder("Extended statistics are only available after watching a replay!"), + new ReplayDownloadButton(newScore) + { + Scale = new Vector2(1.5f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + } + }; + } + else + { + rows.Add(new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Children = new Drawable[] + { + new MessagePlaceholder("More statistics available after watching a replay!"), + new ReplayDownloadButton(newScore) + { + Scale = new Vector2(1.5f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + } + }); + } } - LoadComponentAsync(rows, d => + LoadComponentAsync(container, d => { if (!Score.Value.Equals(newScore)) return; From 6a482827fea64cbc0869700489e4feb9389f86d6 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 17:23:03 +0800 Subject: [PATCH 04/15] Fix weird line breaking --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 6 ++---- osu.Game.Rulesets.Osu/OsuRuleset.cs | 9 +++------ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 6 ++---- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 8ac8001457..0ea1cd5fc7 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -370,8 +370,7 @@ namespace osu.Game.Rulesets.Mania { Columns = new[] { - new StatisticItem("Timing Distribution", - true, + new StatisticItem("Timing Distribution", true, () => new HitEventTimingDistributionGraph(score.HitEvents) { RelativeSizeAxes = Axes.X, @@ -383,8 +382,7 @@ namespace osu.Game.Rulesets.Mania { Columns = new[] { - new StatisticItem(string.Empty, - true, + new StatisticItem(string.Empty, true, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] { new UnstableRate(score.HitEvents) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index b6f417b7fe..2bf47100c1 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -277,8 +277,7 @@ namespace osu.Game.Rulesets.Osu { Columns = new[] { - new StatisticItem("Timing Distribution", - true, + new StatisticItem("Timing Distribution", true, () => new HitEventTimingDistributionGraph(timedHitEvents) { RelativeSizeAxes = Axes.X, @@ -290,8 +289,7 @@ namespace osu.Game.Rulesets.Osu { Columns = new[] { - new StatisticItem("Accuracy Heatmap", - true, + new StatisticItem("Accuracy Heatmap", true, () => new AccuracyHeatmap(score, playableBeatmap) { RelativeSizeAxes = Axes.X, @@ -303,8 +301,7 @@ namespace osu.Game.Rulesets.Osu { Columns = new[] { - new StatisticItem(string.Empty, - true, + new StatisticItem(string.Empty, true, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] { new UnstableRate(timedHitEvents) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 2a64b8dddd..fe4116b4a6 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -213,8 +213,7 @@ namespace osu.Game.Rulesets.Taiko { Columns = new[] { - new StatisticItem("Timing Distribution", - true, + new StatisticItem("Timing Distribution", true, () => new HitEventTimingDistributionGraph(timedHitEvents) { RelativeSizeAxes = Axes.X, @@ -226,8 +225,7 @@ namespace osu.Game.Rulesets.Taiko { Columns = new[] { - new StatisticItem(string.Empty, - true, + new StatisticItem(string.Empty, true, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] { new UnstableRate(timedHitEvents) From 90e30bc9e8b3e7058aebfa83336383d52d0e0efb Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 17:26:17 +0800 Subject: [PATCH 05/15] Remove useless null checks --- osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 1c96e640b4..8b69f83055 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -110,9 +110,9 @@ namespace osu.Game.Screens.Ranking.Statistics { var columnsToDisplay = hitEventsAvailable ? row.Columns - : row.Columns?.Where(c => !c.RequiresHitEvents).ToArray(); + : row.Columns.Where(c => !c.RequiresHitEvents).ToArray(); - if (columnsToDisplay?.Any() ?? false) + if (columnsToDisplay.Any()) panelIsEmpty = false; else continue; @@ -132,8 +132,8 @@ namespace osu.Game.Screens.Ranking.Statistics Origin = Anchor.Centre, }).Cast().ToArray() }, - ColumnDimensions = Enumerable.Range(0, columnsToDisplay?.Length ?? 0) - .Select(i => columnsToDisplay?[i].Dimension ?? new Dimension()).ToArray(), + ColumnDimensions = Enumerable.Range(0, columnsToDisplay.Length) + .Select(i => columnsToDisplay[i].Dimension ?? new Dimension()).ToArray(), RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } }); } From 042574660c10d6a28c29a81d6f45f5b8547f956a Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 17:29:03 +0800 Subject: [PATCH 06/15] Rename "Content" to "CreateContent" --- .../Ranking/Statistics/StatisticContainer.cs | 2 +- .../Screens/Ranking/Statistics/StatisticItem.cs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs index f3bd2c6fc1..79f813ef64 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Ranking.Statistics RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Margin = new MarginPadding { Top = 15 }, - Child = item.Content() + Child = item.CreateContent() } }, }, diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index 5e6ddf445b..cb5ba4b9fe 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -19,9 +19,9 @@ namespace osu.Game.Screens.Ranking.Statistics public readonly string Name; /// - /// The content to be displayed. + /// A function returning the content to be displayed. /// - public readonly Func Content; + public readonly Func CreateContent; /// /// The of this row. This can be thought of as the column dimension of an encompassing . @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Ranking.Statistics public readonly Dimension Dimension; /// - /// Whether this item requires hit events. If true, the will not be created if no hit events are available. + /// Whether this item requires hit events. If true, will not be called if no hit events are available. /// public readonly bool RequiresHitEvents; @@ -37,14 +37,14 @@ namespace osu.Game.Screens.Ranking.Statistics /// Creates a new , to be displayed inside a in the results screen. /// /// The name of the item. Can be to hide the item header. - /// Whether this item requires hit events. If true, the will not be created if no hit events are available. - /// The content to be displayed. + /// Whether this item requires hit events. If true, will not be called if no hit events are available. + /// A function returning the content to be displayed. /// The of this item. This can be thought of as the column dimension of an encompassing . - public StatisticItem([NotNull] string name, bool requiresHitEvents, [NotNull] Func content, [CanBeNull] Dimension dimension = null) + public StatisticItem([NotNull] string name, bool requiresHitEvents, [NotNull] Func createContent, [CanBeNull] Dimension dimension = null) { Name = name; RequiresHitEvents = requiresHitEvents; - Content = content; + CreateContent = createContent; Dimension = dimension; } } From 36bfef4f54f4f116ec7f84747db2c4c93a883d0d Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 17:32:16 +0800 Subject: [PATCH 07/15] Dispose container before replacing --- osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 8b69f83055..2327f60f81 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -143,6 +143,7 @@ namespace osu.Game.Screens.Ranking.Statistics if (panelIsEmpty) { // Replace the scroll container with fill flow container to get the message centered. + container.Dispose(); container = new FillFlowContainer { RelativeSizeAxes = Axes.Both, From b0023b9809d15cdb7f19d5a2f6be9c0d047bf9fc Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 19:00:46 +0800 Subject: [PATCH 08/15] Also dispose `rows` --- osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 2327f60f81..62f9eb8506 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -143,6 +143,7 @@ namespace osu.Game.Screens.Ranking.Statistics if (panelIsEmpty) { // Replace the scroll container with fill flow container to get the message centered. + rows.Dispose(); container.Dispose(); container = new FillFlowContainer { From 1e19c7046a71de056cc975deaa045eb2eff46c8b Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 19:02:29 +0800 Subject: [PATCH 09/15] Use spacing instead of bottom margin --- osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 62f9eb8506..68414c4d49 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -98,7 +98,8 @@ namespace osu.Game.Screens.Ranking.Statistics rows = new FillFlowContainer { RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(30, 15) } } }; @@ -123,7 +124,6 @@ namespace osu.Game.Screens.Ranking.Statistics Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Bottom = 15 }, Content = new[] { columnsToDisplay?.Select(c => new StatisticContainer(c) From 3c2a6fe2086a1eb560a4aefe1805a8d402b1d153 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 2 Feb 2022 19:07:14 +0800 Subject: [PATCH 10/15] Don't prompt for a replay if no item requires hit events --- osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 68414c4d49..08be1de652 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -105,6 +105,7 @@ namespace osu.Game.Screens.Ranking.Statistics }; bool panelIsEmpty = true; + bool panelIsComplete = true; bool hitEventsAvailable = newScore.HitEvents.Count != 0; foreach (var row in newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, playableBeatmap)) @@ -113,6 +114,9 @@ namespace osu.Game.Screens.Ranking.Statistics ? row.Columns : row.Columns.Where(c => !c.RequiresHitEvents).ToArray(); + if (columnsToDisplay.Length < row.Columns.Length) + panelIsComplete = false; + if (columnsToDisplay.Any()) panelIsEmpty = false; else @@ -163,7 +167,7 @@ namespace osu.Game.Screens.Ranking.Statistics } }; } - else + else if (!panelIsComplete) { rows.Add(new FillFlowContainer { From 19eb9ad8a7e86b384ca65648b95e35e37c2ce068 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Feb 2022 23:02:38 +0900 Subject: [PATCH 11/15] Reorder `StatisticsItem` constructor to make a touch more sense --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 20 ++++++------ osu.Game.Rulesets.Osu/OsuRuleset.cs | 31 +++++++++---------- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 20 ++++++------ .../Ranking/Statistics/StatisticItem.cs | 4 +-- 4 files changed, 34 insertions(+), 41 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 0ea1cd5fc7..ffb26b224f 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -370,23 +370,21 @@ namespace osu.Game.Rulesets.Mania { Columns = new[] { - new StatisticItem("Timing Distribution", true, - () => new HitEventTimingDistributionGraph(score.HitEvents) - { - RelativeSizeAxes = Axes.X, - Height = 250 - }), + new StatisticItem("Timing Distribution", () => new HitEventTimingDistributionGraph(score.HitEvents) + { + RelativeSizeAxes = Axes.X, + Height = 250 + }, true), } }, new StatisticRow { Columns = new[] { - new StatisticItem(string.Empty, true, - () => new SimpleStatisticTable(3, new SimpleStatisticItem[] - { - new UnstableRate(score.HitEvents) - })) + new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + { + new UnstableRate(score.HitEvents) + }), true) } } }; diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 2bf47100c1..1122a869b7 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -277,35 +277,32 @@ namespace osu.Game.Rulesets.Osu { Columns = new[] { - new StatisticItem("Timing Distribution", true, - () => new HitEventTimingDistributionGraph(timedHitEvents) - { - RelativeSizeAxes = Axes.X, - Height = 250 - }), + new StatisticItem("Timing Distribution", () => new HitEventTimingDistributionGraph(timedHitEvents) + { + RelativeSizeAxes = Axes.X, + Height = 250 + }, true), } }, new StatisticRow { Columns = new[] { - new StatisticItem("Accuracy Heatmap", true, - () => new AccuracyHeatmap(score, playableBeatmap) - { - RelativeSizeAxes = Axes.X, - Height = 250 - }), + new StatisticItem("Accuracy Heatmap", () => new AccuracyHeatmap(score, playableBeatmap) + { + RelativeSizeAxes = Axes.X, + Height = 250 + }, true), } }, new StatisticRow { Columns = new[] { - new StatisticItem(string.Empty, true, - () => new SimpleStatisticTable(3, new SimpleStatisticItem[] - { - new UnstableRate(timedHitEvents) - })) + new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + { + new UnstableRate(timedHitEvents) + }), true) } } }; diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index fe4116b4a6..21c99c0d2f 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -213,23 +213,21 @@ namespace osu.Game.Rulesets.Taiko { Columns = new[] { - new StatisticItem("Timing Distribution", true, - () => new HitEventTimingDistributionGraph(timedHitEvents) - { - RelativeSizeAxes = Axes.X, - Height = 250 - }), + new StatisticItem("Timing Distribution", () => new HitEventTimingDistributionGraph(timedHitEvents) + { + RelativeSizeAxes = Axes.X, + Height = 250 + }, true), } }, new StatisticRow { Columns = new[] { - new StatisticItem(string.Empty, true, - () => new SimpleStatisticTable(3, new SimpleStatisticItem[] - { - new UnstableRate(timedHitEvents) - })) + new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + { + new UnstableRate(timedHitEvents) + }), true) } } }; diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index cb5ba4b9fe..3cfc38e263 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -37,10 +37,10 @@ namespace osu.Game.Screens.Ranking.Statistics /// Creates a new , to be displayed inside a in the results screen. /// /// The name of the item. Can be to hide the item header. - /// Whether this item requires hit events. If true, will not be called if no hit events are available. /// A function returning the content to be displayed. + /// Whether this item requires hit events. If true, will not be called if no hit events are available. /// The of this item. This can be thought of as the column dimension of an encompassing . - public StatisticItem([NotNull] string name, bool requiresHitEvents, [NotNull] Func createContent, [CanBeNull] Dimension dimension = null) + public StatisticItem([NotNull] string name, [NotNull] Func createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) { Name = name; RequiresHitEvents = requiresHitEvents; From aff36d4e163c96c9dd35ea280a1b630806b63d10 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Thu, 3 Feb 2022 11:52:37 +0800 Subject: [PATCH 12/15] Refactor `populateStatistics` to avoid disposing --- .../Ranking/Statistics/StatisticsPanel.cs | 128 +++++++++--------- 1 file changed, 63 insertions(+), 65 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 08be1de652..cbb4e5089d 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -86,88 +86,86 @@ namespace osu.Game.Screens.Ranking.Statistics playableBeatmap = beatmapManager.GetWorkingBeatmap(newScore.BeatmapInfo).GetPlayableBeatmap(newScore.Ruleset, newScore.Mods); }, loadCancellation.Token).ContinueWith(t => Schedule(() => { - FillFlowContainer rows; - Container container = new OsuScrollContainer(Direction.Vertical) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Alpha = 0, - Children = new[] - { - rows = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(30, 15) - } - } - }; - - bool panelIsEmpty = true; - bool panelIsComplete = true; bool hitEventsAvailable = newScore.HitEvents.Count != 0; + Container container; - foreach (var row in newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, playableBeatmap)) + var statisticRows = newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, playableBeatmap); + + if (!hitEventsAvailable && statisticRows.SelectMany(r => r.Columns).All(c => c.RequiresHitEvents)) { - var columnsToDisplay = hitEventsAvailable - ? row.Columns - : row.Columns.Where(c => !c.RequiresHitEvents).ToArray(); - - if (columnsToDisplay.Length < row.Columns.Length) - panelIsComplete = false; - - if (columnsToDisplay.Any()) - panelIsEmpty = false; - else - continue; - - rows.Add(new GridContainer + container = new FillFlowContainer { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Content = new[] + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Direction = FillDirection.Vertical, + Children = new Drawable[] { - columnsToDisplay?.Select(c => new StatisticContainer(c) + new MessagePlaceholder("Extended statistics are only available after watching a replay!"), + new ReplayDownloadButton(newScore) { + Scale = new Vector2(1.5f), Anchor = Anchor.Centre, Origin = Anchor.Centre, - }).Cast().ToArray() - }, - ColumnDimensions = Enumerable.Range(0, columnsToDisplay.Length) - .Select(i => columnsToDisplay[i].Dimension ?? new Dimension()).ToArray(), - RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } - }); + }, + } + }; } - - if (!hitEventsAvailable) + else { - if (panelIsEmpty) + FillFlowContainer rows; + container = new OsuScrollContainer(Direction.Vertical) { - // Replace the scroll container with fill flow container to get the message centered. - rows.Dispose(); - container.Dispose(); - container = new FillFlowContainer + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + Children = new[] { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Direction = FillDirection.Vertical, - Children = new Drawable[] + rows = new FillFlowContainer { - new MessagePlaceholder("Extended statistics are only available after watching a replay!"), - new ReplayDownloadButton(newScore) + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(30, 15) + } + } + }; + + bool panelIsComplete = true; + + foreach (var row in statisticRows) + { + var columnsToDisplay = hitEventsAvailable + ? row.Columns + : row.Columns.Where(c => !c.RequiresHitEvents).ToArray(); + + if (columnsToDisplay.Length < row.Columns.Length) + panelIsComplete = false; + + if (columnsToDisplay.Length == 0) + continue; + + rows.Add(new GridContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Content = new[] + { + columnsToDisplay?.Select(c => new StatisticContainer(c) { - Scale = new Vector2(1.5f), Anchor = Anchor.Centre, Origin = Anchor.Centre, - }, - } - }; + }).Cast().ToArray() + }, + ColumnDimensions = Enumerable.Range(0, columnsToDisplay.Length) + .Select(i => columnsToDisplay[i].Dimension ?? new Dimension()).ToArray(), + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } + }); } - else if (!panelIsComplete) + + if (!hitEventsAvailable && !panelIsComplete) { rows.Add(new FillFlowContainer { From a27d0572ed3d5c8b4c5f082015de2f6c33b86005 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Thu, 3 Feb 2022 17:00:40 +0800 Subject: [PATCH 13/15] Add test cases for manual testing --- .../Ranking/TestSceneStatisticsPanel.cs | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs b/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs index f64b7b2b65..35281a85eb 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs @@ -6,10 +6,18 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; using osu.Game.Tests.Resources; using osuTK; @@ -41,6 +49,24 @@ namespace osu.Game.Tests.Visual.Ranking loadPanel(TestResources.CreateTestScoreInfo()); } + [Test] + public void TestScoreInRulesetWhereAllStatsRequireHitEvents() + { + loadPanel(TestResources.CreateTestScoreInfo(new TestRulesetAllStatsRequireHitEvents().RulesetInfo)); + } + + [Test] + public void TestScoreInRulesetWhereNoStatsRequireHitEvents() + { + loadPanel(TestResources.CreateTestScoreInfo(new TestRulesetNoStatsRequireHitEvents().RulesetInfo)); + } + + [Test] + public void TestScoreInMixedRuleset() + { + loadPanel(TestResources.CreateTestScoreInfo(new TestRulesetMixed().RulesetInfo)); + } + [Test] public void TestNullScore() { @@ -75,5 +101,134 @@ namespace osu.Game.Tests.Visual.Ranking return hitEvents; } + + private class TestRuleset : Ruleset + { + public override IEnumerable GetModsFor(ModType type) + { + throw new NotImplementedException(); + } + + public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) + { + throw new NotImplementedException(); + } + + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) + { + throw new NotImplementedException(); + } + + public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) + { + throw new NotImplementedException(); + } + + public override string Description => string.Empty; + + public override string ShortName => string.Empty; + + protected static Drawable CreatePlaceholderStatistic(string message) => new Container + { + RelativeSizeAxes = Axes.X, + Masking = true, + CornerRadius = 20, + Height = 250, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.5f), + Alpha = 0.5f + }, + new OsuSpriteText + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Text = message, + Margin = new MarginPadding { Left = 20 } + } + } + }; + } + + private class TestRulesetAllStatsRequireHitEvents : TestRuleset + { + public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) + { + return new[] + { + new StatisticRow + { + Columns = new[] + { + new StatisticItem("Statistic Requiring Hit Events 1", + () => CreatePlaceholderStatistic("Placeholder statistic. Requires hit events"), true) + } + }, + new StatisticRow + { + Columns = new[] + { + new StatisticItem("Statistic Requiring Hit Events 2", + () => CreatePlaceholderStatistic("Placeholder statistic. Requires hit events"), true) + } + } + }; + } + } + + private class TestRulesetNoStatsRequireHitEvents : TestRuleset + { + public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) + { + return new[] + { + new StatisticRow + { + Columns = new[] + { + new StatisticItem("Statistic Not Requiring Hit Events 1", + () => CreatePlaceholderStatistic("Placeholder statistic. Does not require hit events")) + } + }, + new StatisticRow + { + Columns = new[] + { + new StatisticItem("Statistic Not Requiring Hit Events 2", + () => CreatePlaceholderStatistic("Placeholder statistic. Does not require hit events")) + } + } + }; + } + } + + private class TestRulesetMixed : TestRuleset + { + public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) + { + return new[] + { + new StatisticRow + { + Columns = new[] + { + new StatisticItem("Statistic Requiring Hit Events", + () => CreatePlaceholderStatistic("Placeholder statistic. Requires hit events"), true) + } + }, + new StatisticRow + { + Columns = new[] + { + new StatisticItem("Statistic Not Requiring Hit Events", + () => CreatePlaceholderStatistic("Placeholder statistic. Does not require hit events")) + } + } + }; + } + } } } From 6974c2d255f400be9401479df9e782c79a2c04b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Feb 2022 19:00:03 +0900 Subject: [PATCH 14/15] Remove weird `panelIsComplete` flag and replace LINQ with simple `foreach` --- .../Ranking/Statistics/StatisticsPanel.cs | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index cbb4e5089d..898bd69b2c 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -1,6 +1,7 @@ // 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 System.Linq; using System.Threading; using System.Threading.Tasks; @@ -131,41 +132,48 @@ namespace osu.Game.Screens.Ranking.Statistics } }; - bool panelIsComplete = true; + bool anyRequiredHitEvents = false; foreach (var row in statisticRows) { - var columnsToDisplay = hitEventsAvailable - ? row.Columns - : row.Columns.Where(c => !c.RequiresHitEvents).ToArray(); + var columns = row.Columns; - if (columnsToDisplay.Length < row.Columns.Length) - panelIsComplete = false; - - if (columnsToDisplay.Length == 0) + if (columns.Length == 0) continue; + var columnContent = new List(); + var dimensions = new List(); + + foreach (var col in columns) + { + if (!hitEventsAvailable && col.RequiresHitEvents) + { + anyRequiredHitEvents = true; + continue; + } + + columnContent.Add(new StatisticContainer(col) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + dimensions.Add(col.Dimension ?? new Dimension()); + } + rows.Add(new GridContainer { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Content = new[] - { - columnsToDisplay?.Select(c => new StatisticContainer(c) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }).Cast().ToArray() - }, - ColumnDimensions = Enumerable.Range(0, columnsToDisplay.Length) - .Select(i => columnsToDisplay[i].Dimension ?? new Dimension()).ToArray(), + Content = new[] { columnContent.ToArray() }, + ColumnDimensions = dimensions.ToArray(), RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } }); } - if (!hitEventsAvailable && !panelIsComplete) + if (anyRequiredHitEvents) { rows.Add(new FillFlowContainer { From 47d577ec9c822edb762c91067fb7c17ea97a766a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Feb 2022 19:17:56 +0900 Subject: [PATCH 15/15] Add back constructor for ruleset compatibility --- osu.Game/Screens/Ranking/Statistics/StatisticItem.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index 3cfc38e263..b43fbbdeee 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -33,6 +33,12 @@ namespace osu.Game.Screens.Ranking.Statistics /// public readonly bool RequiresHitEvents; + [Obsolete("Use constructor which takes creation function instead.")] // Can be removed 20220803. + public StatisticItem([NotNull] string name, [NotNull] Drawable content, [CanBeNull] Dimension dimension = null) + : this(name, () => content, true, dimension) + { + } + /// /// Creates a new , to be displayed inside a in the results screen. ///