From 83e6c3efdb32c23f2af26fb2c4661ae49f62275c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 19 Jun 2020 20:31:52 +0900 Subject: [PATCH] Adjust API for returning statistics --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 43 ++++++++----------- osu.Game.Rulesets.Osu/Statistics/Heatmap.cs | 3 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 18 ++++++++ .../TestSceneTimingDistributionGraph.cs | 3 +- osu.Game/Rulesets/Ruleset.cs | 1 + .../HitEventTimingDistributionGraph.cs | 26 +++++++---- .../Ranking/Statistics/StatisticContainer.cs | 2 +- .../Ranking/Statistics/StatisticItem.cs | 23 ++++++++++ .../Ranking/Statistics/StatisticRow.cs | 11 ++--- .../Ranking/Statistics/StatisticsPanel.cs | 5 ++- 10 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 osu.Game/Screens/Ranking/Statistics/StatisticItem.cs diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index d99fee3b15..aa313c92b3 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -29,7 +29,9 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Skinning; using System; +using System.Linq; using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Statistics; using osu.Game.Screens.Ranking.Statistics; @@ -190,36 +192,29 @@ namespace osu.Game.Rulesets.Osu public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new OsuRulesetConfigManager(settings, RulesetInfo); - public override StatisticRow[] CreateStatistics(ScoreInfo score) => new[] + public override StatisticRow[] CreateStatistics(ScoreInfo score) { - new StatisticRow + var hitCircleEvents = score.HitEvents.Where(e => e.HitObject is HitCircle).ToList(); + + return new[] { - Content = new Drawable[] + new StatisticRow { - new StatisticContainer("Timing Distribution") + Columns = new[] { - RelativeSizeAxes = Axes.X, - Height = 130, - Child = new HitEventTimingDistributionGraph(score) + new StatisticItem("Timing Distribution", new HitEventTimingDistributionGraph(hitCircleEvents) { - RelativeSizeAxes = Axes.Both - } - }, - new StatisticContainer("Accuracy Heatmap") - { - RelativeSizeAxes = Axes.Both, - Child = new Heatmap(score) + RelativeSizeAxes = Axes.X, + Height = 130 + }), + new StatisticItem("Accuracy Heatmap", new Heatmap(score) { - RelativeSizeAxes = Axes.Both - } - }, - }, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 130), + RelativeSizeAxes = Axes.X, + Height = 130 + }, new Dimension(GridSizeMode.Absolute, 130)), + } } - } - }; + }; + } } } diff --git a/osu.Game.Rulesets.Osu/Statistics/Heatmap.cs b/osu.Game.Rulesets.Osu/Statistics/Heatmap.cs index 49d7f67b7f..86cb8e682f 100644 --- a/osu.Game.Rulesets.Osu/Statistics/Heatmap.cs +++ b/osu.Game.Rulesets.Osu/Statistics/Heatmap.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -147,7 +148,7 @@ namespace osu.Game.Rulesets.Osu.Statistics // Todo: This should probably not be done like this. float radius = OsuHitObject.OBJECT_RADIUS * (1.0f - 0.7f * (score.Beatmap.BaseDifficulty.CircleSize - 5) / 5) / 2; - foreach (var e in score.HitEvents) + foreach (var e in score.HitEvents.Where(e => e.HitObject is HitCircle)) { if (e.LastHitObject == null || e.PositionOffset == null) continue; diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 4cdd1fbc24..cd4e699262 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -21,9 +21,12 @@ using osu.Game.Rulesets.Taiko.Difficulty; using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Scoring; using System; +using System.Linq; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Taiko.Edit; +using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Skinning; +using osu.Game.Screens.Ranking.Statistics; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko @@ -155,5 +158,20 @@ namespace osu.Game.Rulesets.Taiko public int LegacyID => 1; public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame(); + + public override StatisticRow[] CreateStatistics(ScoreInfo score) => new[] + { + new StatisticRow + { + Columns = new[] + { + new StatisticItem("Timing Distribution", new HitEventTimingDistributionGraph(score.HitEvents.Where(e => e.HitObject is Hit).ToList()) + { + RelativeSizeAxes = Axes.X, + Height = 130 + }), + } + } + }; } } diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneTimingDistributionGraph.cs b/osu.Game.Tests/Visual/Ranking/TestSceneTimingDistributionGraph.cs index bfdc216aa1..b34529cca7 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneTimingDistributionGraph.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneTimingDistributionGraph.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; -using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics; using osuTK; @@ -25,7 +24,7 @@ namespace osu.Game.Tests.Visual.Ranking RelativeSizeAxes = Axes.Both, Colour = Color4Extensions.FromHex("#333") }, - new HitEventTimingDistributionGraph(new ScoreInfo { HitEvents = CreateDistributedHitEvents() }) + new HitEventTimingDistributionGraph(CreateDistributedHitEvents()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index f05685b6e9..52784e354f 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -210,6 +210,7 @@ namespace osu.Game.Rulesets /// An empty frame for the current ruleset, or null if unsupported. public virtual IConvertibleReplayFrame CreateConvertibleReplayFrame() => null; + [NotNull] public virtual StatisticRow[] CreateStatistics(ScoreInfo score) => Array.Empty(); } } diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index b258e92aeb..4acbc7da3c 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -10,10 +11,13 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Scoring; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Ranking.Statistics { + /// + /// A graph which displays the distribution of hit timing in a series of s. + /// public class HitEventTimingDistributionGraph : CompositeDrawable { /// @@ -32,27 +36,31 @@ namespace osu.Game.Screens.Ranking.Statistics private const int timing_distribution_centre_bin_index = timing_distribution_bins; /// - /// The number of data points shown on the axis below the graph. + /// The number of data points shown on each side of the axis below the graph. /// private const float axis_points = 5; - private readonly ScoreInfo score; + private readonly IReadOnlyList hitEvents; - public HitEventTimingDistributionGraph(ScoreInfo score) + /// + /// Creates a new . + /// + /// The s to display the timing distribution of. + public HitEventTimingDistributionGraph(IReadOnlyList hitEvents) { - this.score = score; + this.hitEvents = hitEvents; } [BackgroundDependencyLoader] private void load() { - if (score.HitEvents == null || score.HitEvents.Count == 0) + if (hitEvents == null || hitEvents.Count == 0) return; int[] bins = new int[total_timing_distribution_bins]; - double binSize = score.HitEvents.Max(e => Math.Abs(e.TimeOffset)) / timing_distribution_bins; + double binSize = hitEvents.Max(e => Math.Abs(e.TimeOffset)) / timing_distribution_bins; - foreach (var e in score.HitEvents) + foreach (var e in hitEvents) { int binOffset = (int)(e.TimeOffset / binSize); bins[timing_distribution_centre_bin_index + binOffset]++; @@ -67,6 +75,8 @@ namespace osu.Game.Screens.Ranking.Statistics InternalChild = new GridContainer { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Width = 0.8f, Content = new[] diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs index d7b42c1c2f..b8dde8f85e 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Screens.Ranking.Statistics { - public class StatisticContainer : Container + internal class StatisticContainer : Container { protected override Container Content => content; diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs new file mode 100644 index 0000000000..2605ae9f1b --- /dev/null +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Screens.Ranking.Statistics +{ + public class StatisticItem + { + public readonly string Name; + public readonly Drawable Content; + public readonly Dimension Dimension; + + public StatisticItem([NotNull] string name, [NotNull] Drawable content, [CanBeNull] Dimension dimension = null) + { + Name = name; + Content = content; + Dimension = dimension; + } + } +} diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticRow.cs b/osu.Game/Screens/Ranking/Statistics/StatisticRow.cs index 5d39ef57b2..ebab148fc2 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticRow.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticRow.cs @@ -1,15 +1,16 @@ // 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 osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; +using JetBrains.Annotations; namespace osu.Game.Screens.Ranking.Statistics { public class StatisticRow { - public Drawable[] Content = Array.Empty(); - public Dimension[] ColumnDimensions = Array.Empty(); + /// + /// The columns of this . + /// + [ItemCanBeNull] + public StatisticItem[] Columns; } } diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index acaf91246d..3d81229ac3 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.Linq; using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -80,8 +81,8 @@ namespace osu.Game.Screens.Ranking.Statistics { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Content = new[] { row.Content }, - ColumnDimensions = row.ColumnDimensions, + Content = new[] { row.Columns?.Select(c => c?.Content).ToArray() }, + ColumnDimensions = Enumerable.Range(0, row.Columns?.Length ?? 0).Select(i => row.Columns[i]?.Dimension ?? new Dimension()).ToArray(), RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } }); }