diff --git a/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestKaraokeScoreInfo.cs b/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestKaraokeScoreInfo.cs new file mode 100644 index 000000000..f759905c8 --- /dev/null +++ b/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestKaraokeScoreInfo.cs @@ -0,0 +1,44 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Game.Rulesets.Karaoke.Mods; +using osu.Game.Rulesets.Karaoke.Tests.Beatmaps; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Users; + +namespace osu.Game.Rulesets.Karaoke.Tests.Ranking +{ + public class TestKaraokeScoreInfo : ScoreInfo + { + public TestKaraokeScoreInfo() + { + var ruleset = new KaraokeRuleset().RulesetInfo; + + User = new User + { + Id = 1030492, + Username = "andy840119", + CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + }; + + Beatmap = new TestKaraokeBeatmap(ruleset).BeatmapInfo; + Ruleset = ruleset; + RulesetID = ruleset.ID ?? 0; + Mods = new Mod[] { new KaraokeModFlashlight(), new KaraokeModSnow() }; + + TotalScore = 2845370; + Accuracy = 0.95; + MaxCombo = 999; + Rank = ScoreRank.S; + Date = DateTimeOffset.Now; + + Statistics[HitResult.Miss] = 1; + Statistics[HitResult.Meh] = 50; + Statistics[HitResult.Good] = 100; + Statistics[HitResult.Great] = 300; + } + } +} diff --git a/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestSceneHitEventTimingDistributionGraph.cs b/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestSceneHitEventTimingDistributionGraph.cs new file mode 100644 index 000000000..6a406b3fc --- /dev/null +++ b/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestSceneHitEventTimingDistributionGraph.cs @@ -0,0 +1,72 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Karaoke.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Ranking.Statistics; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Rulesets.Karaoke.Tests.Ranking +{ + public class TestSceneHitEventTimingDistributionGraph : OsuTestScene + { + [Test] + public void TestManyDistributedEvents() + { + createTest(CreateDistributedHitEvents()); + } + + [Test] + public void TestZeroTimeOffset() + { + createTest(Enumerable.Range(0, 100).Select(_ => new HitEvent(0, HitResult.Perfect, new Note(), new Note(), null)).ToList()); + } + + [Test] + public void TestNoEvents() + { + createTest(new List()); + } + + private void createTest(List events) => AddStep("create test", () => + { + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#333") + }, + new HitEventTimingDistributionGraph(events) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(600, 130) + } + }; + }); + + public static List CreateDistributedHitEvents() + { + var hitEvents = new List(); + + for (int i = 0; i < 50; i++) + { + int count = (int)(Math.Pow(25 - Math.Abs(i - 25), 2)); + + for (int j = 0; j < count; j++) + hitEvents.Add(new HitEvent(i - 25, HitResult.Perfect, new Note(), new Note(), null)); + } + + return hitEvents; + } + } +} diff --git a/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestSceneResultsScreen.cs b/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestSceneResultsScreen.cs new file mode 100644 index 000000000..633d8ee6f --- /dev/null +++ b/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestSceneResultsScreen.cs @@ -0,0 +1,107 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Online.API; +using osu.Game.Rulesets.Karaoke.Tests.Beatmaps; +using osu.Game.Scoring; +using osu.Game.Screens; +using osu.Game.Screens.Play; +using osu.Game.Screens.Ranking; +using osu.Game.Screens.Ranking.Statistics; +using osu.Game.Tests.Visual; +using osuTK.Input; + +namespace osu.Game.Rulesets.Karaoke.Tests.Ranking +{ + [TestFixture] + public class TestSceneResultsScreen : OsuManualInputManagerTestScene + { + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestKaraokeBeatmap(ruleset); + + private TestResultsScreen createResultsScreen() => new TestResultsScreen(new TestKaraokeScoreInfo + { + HitEvents = TestSceneHitEventTimingDistributionGraph.CreateDistributedHitEvents() + }); + + [Test] + public void TestShowStatisticsAndClickOtherPanel() + { + TestResultsScreen screen = null; + + AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen())); + AddUntilStep("wait for loaded", () => screen.IsLoaded); + + ScorePanel expandedPanel = null; + ScorePanel contractedPanel = null; + + AddStep("click expanded panel then contracted panel", () => + { + expandedPanel = this.ChildrenOfType().Single(p => p.State == PanelState.Expanded); + InputManager.MoveMouseTo(expandedPanel); + InputManager.Click(MouseButton.Left); + + contractedPanel = this.ChildrenOfType().First(p => p.State == PanelState.Contracted && p.ScreenSpaceDrawQuad.TopLeft.X > screen.ScreenSpaceDrawQuad.TopLeft.X); + InputManager.MoveMouseTo(contractedPanel); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("statistics shown", () => this.ChildrenOfType().Single().State.Value == Visibility.Visible); + + AddAssert("contracted panel still contracted", () => contractedPanel.State == PanelState.Contracted); + AddAssert("expanded panel still expanded", () => expandedPanel.State == PanelState.Expanded); + } + + private class TestResultsContainer : Container + { + [Cached(typeof(Player))] + private readonly Player player = new TestPlayer(); + + public TestResultsContainer(IScreen screen) + { + RelativeSizeAxes = Axes.Both; + OsuScreenStack stack; + + InternalChild = stack = new OsuScreenStack + { + RelativeSizeAxes = Axes.Both, + }; + + stack.Push(screen); + } + } + + private class TestResultsScreen : ResultsScreen + { + public TestResultsScreen(ScoreInfo score) + : base(score) + { + } + + protected override APIRequest FetchScores(Action> scoresCallback) + { + var scores = new List(); + + for (int i = 0; i < 20; i++) + { + var score = new TestKaraokeScoreInfo(); + score.TotalScore += 10 - i; + scores.Add(score); + } + + scoresCallback?.Invoke(scores); + + return null; + } + } + } +} diff --git a/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestSceneStatisticsPanel.cs b/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestSceneStatisticsPanel.cs new file mode 100644 index 000000000..0cde64945 --- /dev/null +++ b/osu.Game.Rulesets.Karaoke.Tests/Ranking/TestSceneStatisticsPanel.cs @@ -0,0 +1,48 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking.Statistics; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Karaoke.Tests.Ranking +{ + public class TestSceneStatisticsPanel : OsuTestScene + { + [Test] + public void TestScoreWithStatistics() + { + var score = new TestKaraokeScoreInfo + { + HitEvents = TestSceneHitEventTimingDistributionGraph.CreateDistributedHitEvents() + }; + + loadPanel(score); + } + + [Test] + public void TestScoreWithoutStatistics() + { + loadPanel(new TestKaraokeScoreInfo()); + } + + [Test] + public void TestNullScore() + { + loadPanel(null); + } + + private void loadPanel(ScoreInfo score) => AddStep("load panel", () => + { + Child = new StatisticsPanel + { + RelativeSizeAxes = Axes.Both, + State = { Value = Visibility.Visible }, + Score = { Value = score } + }; + }); + } +} diff --git a/osu.Game.Rulesets.Karaoke.Tests/Skinning/KaraokeSkinnableTestScene.cs b/osu.Game.Rulesets.Karaoke.Tests/Skinning/KaraokeSkinnableTestScene.cs index ee9b1148e..e07d4ff9f 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Skinning/KaraokeSkinnableTestScene.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Skinning/KaraokeSkinnableTestScene.cs @@ -1,23 +1,14 @@ // Copyright (c) andy840119 . Licensed under the GPL Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Karaoke.Beatmaps; -using osu.Game.Rulesets.Karaoke.Skinning; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Karaoke.Tests.Skinning { public abstract class KaraokeSkinnableTestScene : SkinnableTestScene { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(KaraokeRuleset), - typeof(KaraokeLegacySkinTransformer), - }; - protected override Ruleset CreateRulesetForSkinProvider() => new KaraokeRuleset(); protected override IBeatmap CreateBeatmapForSkinProvider() => new KaraokeBeatmap(); diff --git a/osu.Game.Rulesets.Karaoke/KaraokeRuleset.cs b/osu.Game.Rulesets.Karaoke/KaraokeRuleset.cs index f5b6c953e..fe36f7c49 100644 --- a/osu.Game.Rulesets.Karaoke/KaraokeRuleset.cs +++ b/osu.Game.Rulesets.Karaoke/KaraokeRuleset.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; @@ -18,6 +19,7 @@ using osu.Game.Rulesets.Karaoke.Difficulty; using osu.Game.Rulesets.Karaoke.Edit; using osu.Game.Rulesets.Karaoke.Mods; +using osu.Game.Rulesets.Karaoke.Objects; using osu.Game.Rulesets.Karaoke.Replays; using osu.Game.Rulesets.Karaoke.Resources.Fonts; using osu.Game.Rulesets.Karaoke.Scoring; @@ -27,6 +29,8 @@ using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking.Statistics; using osu.Game.Skinning; namespace osu.Game.Rulesets.Karaoke @@ -140,6 +144,21 @@ public override IEnumerable GetModsFor(ModType type) public override RulesetSettingsSubsection CreateSettings() => new KaraokeSettingsSubsection(this); + public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) => new[] + { + new StatisticRow + { + Columns = new[] + { + new StatisticItem("Timing Distribution", new HitEventTimingDistributionGraph(score.HitEvents.Where(e => e.HitObject is Note).ToList()) + { + RelativeSizeAxes = Axes.X, + Height = 250 + }), + } + } + }; + public KaraokeRuleset() { // It's a tricky to let osu! to read karaoke testing beatmap diff --git a/osu.Game.Rulesets.Karaoke/osu.Game.Rulesets.Karaoke.csproj b/osu.Game.Rulesets.Karaoke/osu.Game.Rulesets.Karaoke.csproj index 3606e1f46..0f99a7653 100644 --- a/osu.Game.Rulesets.Karaoke/osu.Game.Rulesets.Karaoke.csproj +++ b/osu.Game.Rulesets.Karaoke/osu.Game.Rulesets.Karaoke.csproj @@ -10,9 +10,9 @@ - + - +