From 632246a3b31eed8c7a52378268a9b814c69a00e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 16 Jan 2022 17:04:59 +0100 Subject: [PATCH 01/20] Add failing test scene --- .../TestSceneDrumRollJudgements.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs new file mode 100644 index 0000000000..fc4fd286f4 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs @@ -0,0 +1,36 @@ +// 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 NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Taiko.Objects; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class TestSceneDrumRollJudgements : TestSceneTaikoPlayer + { + [Test] + public void TestStrongDrumRollFullyJudgedOnKilled() + { + AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted.Value); + AddAssert("all judgements are misses", () => Player.Results.All(r => r.Type == r.Judgement.MinResult)); + } + + protected override bool Autoplay => false; + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap() + { + BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo }, + HitObjects = + { + new DrumRoll + { + StartTime = 1000, + Duration = 1000, + IsStrong = true + } + } + }; + } +} From c6adbdd46f105071c344f48aa8ab997a6a8cad2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 16 Jan 2022 17:15:01 +0100 Subject: [PATCH 02/20] Fix drum rolls nested objects not applying min result on kill --- .../Objects/Drawables/DrawableDrumRoll.cs | 8 ++++++++ .../Objects/Drawables/DrawableDrumRollTick.cs | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 521189d36c..b84db513f7 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -197,6 +197,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); } + public override void OnKilled() + { + base.OnKilled(); + + if (Time.Current > ParentHitObject.HitObject.GetEndTime() && !Judged) + ApplyResult(r => r.Type = r.Judgement.MinResult); + } + public override bool OnPressed(KeyBindingPressEvent e) => false; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index dc2ed200a1..e24923e482 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -5,6 +5,7 @@ using System; using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Input.Events; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; @@ -52,6 +53,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = r.Judgement.MaxResult); } + public override void OnKilled() + { + base.OnKilled(); + + if (Time.Current > HitObject.GetEndTime() && !Judged) + ApplyResult(r => r.Type = r.Judgement.MinResult); + } + protected override void UpdateHitStateTransforms(ArmedState state) { switch (state) @@ -92,6 +101,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); } + public override void OnKilled() + { + base.OnKilled(); + + if (Time.Current > ParentHitObject.HitObject.GetEndTime() && !Judged) + ApplyResult(r => r.Type = r.Judgement.MinResult); + } + public override bool OnPressed(KeyBindingPressEvent e) => false; } } From 34e99968d098d1a86deb3422bd34c754f1e20d02 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 17 Jan 2022 14:06:48 +0900 Subject: [PATCH 03/20] Resolve inspection --- osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs index fc4fd286f4..060c3c9443 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Tests protected override bool Autoplay => false; - protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap() + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap { BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo }, HitObjects = From 51ade3251d68c9222a897852ce20e99b0d676077 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Jan 2022 15:15:20 +0900 Subject: [PATCH 04/20] Improve `ScoresContainer` loading overlay logic to work better with tests --- osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index a40f29abf2..00dedc892b 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -65,6 +65,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores scoreTable.ClearScores(); scoreTable.Hide(); + loading.Hide(); + loading.FinishTransforms(); + if (value?.Scores.Any() != true) return; @@ -258,9 +261,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Scores = null; notSupporterPlaceholder.Show(); - - loading.Hide(); - loading.FinishTransforms(); return; } @@ -272,9 +272,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores getScoresRequest = new GetScoresRequest(Beatmap.Value, Beatmap.Value.Ruleset, scope.Value, modSelector.SelectedMods); getScoresRequest.Success += scores => { - loading.Hide(); - loading.FinishTransforms(); - Scores = scores; if (!scores.Scores.Any()) From 6436b6186f6e3a1ad2262748138576b23334f750 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Jan 2022 15:15:34 +0900 Subject: [PATCH 05/20] Rewrite `TestScenScoresContainer` to work again --- .../Visual/Online/TestSceneScoresContainer.cs | 440 +++++++++--------- 1 file changed, 231 insertions(+), 209 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs index be2db9a8a0..71b60d8842 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs @@ -1,11 +1,14 @@ // 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 System.Collections.Generic; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; @@ -24,224 +27,38 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); - public TestSceneScoresContainer() + private TestScoresContainer scoresContainer; + + [SetUpSteps] + public void SetUpSteps() { - TestScoresContainer scoresContainer; - - Child = new Container + AddStep("Create container", () => { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Both, - Width = 0.8f, - Children = new Drawable[] + Child = new Container { - new Box + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Width = 0.8f, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - scoresContainer = new TestScoresContainer(), - } - }; - - var allScores = new APIScoresCollection - { - Scores = new List - { - new APIScore - { - User = new APIUser + new Box { - Id = 6602580, - Username = @"waaiiru", - Country = new Country - { - FullName = @"Spain", - FlagName = @"ES", - }, + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, }, - Mods = new[] + scoresContainer = new TestScoresContainer { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - new APIMod { Acronym = new OsuModHidden().Acronym }, - new APIMod { Acronym = new OsuModFlashlight().Acronym }, - new APIMod { Acronym = new OsuModHardRock().Acronym }, - }, - Rank = ScoreRank.XH, - PP = 200, - MaxCombo = 1234, - TotalScore = 1234567890, - Accuracy = 1, - }, - new APIScore - { - User = new APIUser - { - Id = 4608074, - Username = @"Skycries", - Country = new Country - { - FullName = @"Brazil", - FlagName = @"BR", - }, - }, - Mods = new[] - { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - new APIMod { Acronym = new OsuModHidden().Acronym }, - new APIMod { Acronym = new OsuModFlashlight().Acronym }, - }, - Rank = ScoreRank.S, - PP = 190, - MaxCombo = 1234, - TotalScore = 1234789, - Accuracy = 0.9997, - }, - new APIScore - { - User = new APIUser - { - Id = 1014222, - Username = @"eLy", - Country = new Country - { - FullName = @"Japan", - FlagName = @"JP", - }, - }, - Mods = new[] - { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - new APIMod { Acronym = new OsuModHidden().Acronym }, - }, - Rank = ScoreRank.B, - PP = 180, - MaxCombo = 1234, - TotalScore = 12345678, - Accuracy = 0.9854, - }, - new APIScore - { - User = new APIUser - { - Id = 1541390, - Username = @"Toukai", - Country = new Country - { - FullName = @"Canada", - FlagName = @"CA", - }, - }, - Mods = new[] - { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - }, - Rank = ScoreRank.C, - PP = 170, - MaxCombo = 1234, - TotalScore = 1234567, - Accuracy = 0.8765, - }, - new APIScore - { - User = new APIUser - { - Id = 7151382, - Username = @"Mayuri Hana", - Country = new Country - { - FullName = @"Thailand", - FlagName = @"TH", - }, - }, - Rank = ScoreRank.D, - PP = 160, - MaxCombo = 1234, - TotalScore = 123456, - Accuracy = 0.6543, - }, - } - }; - - var myBestScore = new APIScoreWithPosition - { - Score = new APIScore - { - User = new APIUser - { - Id = 7151382, - Username = @"Mayuri Hana", - Country = new Country - { - FullName = @"Thailand", - FlagName = @"TH", - }, - }, - Rank = ScoreRank.D, - PP = 160, - MaxCombo = 1234, - TotalScore = 123456, - Accuracy = 0.6543, - }, - Position = 1337, - }; - - var myBestScoreWithNullPosition = new APIScoreWithPosition - { - Score = new APIScore - { - User = new APIUser - { - Id = 7151382, - Username = @"Mayuri Hana", - Country = new Country - { - FullName = @"Thailand", - FlagName = @"TH", - }, - }, - Rank = ScoreRank.D, - PP = 160, - MaxCombo = 1234, - TotalScore = 123456, - Accuracy = 0.6543, - }, - Position = null, - }; - - var oneScore = new APIScoresCollection - { - Scores = new List - { - new APIScore - { - User = new APIUser - { - Id = 6602580, - Username = @"waaiiru", - Country = new Country - { - FullName = @"Spain", - FlagName = @"ES", - }, - }, - Mods = new[] - { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - new APIMod { Acronym = new OsuModHidden().Acronym }, - new APIMod { Acronym = new OsuModFlashlight().Acronym }, - new APIMod { Acronym = new OsuModHardRock().Acronym }, - }, - Rank = ScoreRank.XH, - PP = 200, - MaxCombo = 1234, - TotalScore = 1234567890, - Accuracy = 1, + Beatmap = { Value = CreateAPIBeatmap() } + } } - } - }; + }; + }); + } + [Test] + public void TestDisplay() + { foreach (var s in allScores.Scores) { s.Statistics = new Dictionary @@ -273,6 +90,211 @@ namespace osu.Game.Tests.Visual.Online }); } + private readonly APIScoresCollection allScores = new APIScoresCollection + { + Scores = new List + { + new APIScore + { + Date = DateTimeOffset.Now, + User = new APIUser + { + Id = 6602580, + Username = @"waaiiru", + Country = new Country + { + FullName = @"Spain", + FlagName = @"ES", + }, + }, + Mods = new[] + { + new APIMod { Acronym = new OsuModDoubleTime().Acronym }, + new APIMod { Acronym = new OsuModHidden().Acronym }, + new APIMod { Acronym = new OsuModFlashlight().Acronym }, + new APIMod { Acronym = new OsuModHardRock().Acronym }, + }, + Rank = ScoreRank.XH, + PP = 200, + MaxCombo = 1234, + TotalScore = 1234567890, + Accuracy = 1, + }, + new APIScore + { + Date = DateTimeOffset.Now, + User = new APIUser + { + Id = 4608074, + Username = @"Skycries", + Country = new Country + { + FullName = @"Brazil", + FlagName = @"BR", + }, + }, + Mods = new[] + { + new APIMod { Acronym = new OsuModDoubleTime().Acronym }, + new APIMod { Acronym = new OsuModHidden().Acronym }, + new APIMod { Acronym = new OsuModFlashlight().Acronym }, + }, + Rank = ScoreRank.S, + PP = 190, + MaxCombo = 1234, + TotalScore = 1234789, + Accuracy = 0.9997, + }, + new APIScore + { + Date = DateTimeOffset.Now, + User = new APIUser + { + Id = 1014222, + Username = @"eLy", + Country = new Country + { + FullName = @"Japan", + FlagName = @"JP", + }, + }, + Mods = new[] + { + new APIMod { Acronym = new OsuModDoubleTime().Acronym }, + new APIMod { Acronym = new OsuModHidden().Acronym }, + }, + Rank = ScoreRank.B, + PP = 180, + MaxCombo = 1234, + TotalScore = 12345678, + Accuracy = 0.9854, + }, + new APIScore + { + Date = DateTimeOffset.Now, + User = new APIUser + { + Id = 1541390, + Username = @"Toukai", + Country = new Country + { + FullName = @"Canada", + FlagName = @"CA", + }, + }, + Mods = new[] + { + new APIMod { Acronym = new OsuModDoubleTime().Acronym }, + }, + Rank = ScoreRank.C, + PP = 170, + MaxCombo = 1234, + TotalScore = 1234567, + Accuracy = 0.8765, + }, + new APIScore + { + Date = DateTimeOffset.Now, + User = new APIUser + { + Id = 7151382, + Username = @"Mayuri Hana", + Country = new Country + { + FullName = @"Thailand", + FlagName = @"TH", + }, + }, + Rank = ScoreRank.D, + PP = 160, + MaxCombo = 1234, + TotalScore = 123456, + Accuracy = 0.6543, + }, + } + }; + + private readonly APIScoreWithPosition myBestScore = new APIScoreWithPosition + { + Score = new APIScore + { + Date = DateTimeOffset.Now, + User = new APIUser + { + Id = 7151382, + Username = @"Mayuri Hana", + Country = new Country + { + FullName = @"Thailand", + FlagName = @"TH", + }, + }, + Rank = ScoreRank.D, + PP = 160, + MaxCombo = 1234, + TotalScore = 123456, + Accuracy = 0.6543, + }, + Position = 1337, + }; + + private readonly APIScoreWithPosition myBestScoreWithNullPosition = new APIScoreWithPosition + { + Score = new APIScore + { + Date = DateTimeOffset.Now, + User = new APIUser + { + Id = 7151382, + Username = @"Mayuri Hana", + Country = new Country + { + FullName = @"Thailand", + FlagName = @"TH", + }, + }, + Rank = ScoreRank.D, + PP = 160, + MaxCombo = 1234, + TotalScore = 123456, + Accuracy = 0.6543, + }, + Position = null, + }; + + private readonly APIScoresCollection oneScore = new APIScoresCollection + { + Scores = new List + { + new APIScore + { + Date = DateTimeOffset.Now, + User = new APIUser + { + Id = 6602580, + Username = @"waaiiru", + Country = new Country + { + FullName = @"Spain", + FlagName = @"ES", + }, + }, + Mods = new[] + { + new APIMod { Acronym = new OsuModDoubleTime().Acronym }, + new APIMod { Acronym = new OsuModHidden().Acronym }, + new APIMod { Acronym = new OsuModFlashlight().Acronym }, + new APIMod { Acronym = new OsuModHardRock().Acronym }, + }, + Rank = ScoreRank.XH, + PP = 200, + MaxCombo = 1234, + TotalScore = 1234567890, + Accuracy = 1, + } + } + }; + private class TestScoresContainer : ScoresContainer { public new APIScoresCollection Scores From 12fd279b7df1b3dbac8f1ede8fac3306a3320156 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Jan 2022 15:59:14 +0900 Subject: [PATCH 06/20] Add test to check full flow of rebinding gameplay key bindings Addresses a regression found in realm PR that was not covered by tests. --- .../TestSceneChangeAndUseGameplayBindings.cs | 89 +++++++++++++++++++ .../Sections/Input/KeyBindingsSubsection.cs | 2 +- 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs new file mode 100644 index 0000000000..7dda158ee1 --- /dev/null +++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs @@ -0,0 +1,89 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Input.Bindings; +using osu.Framework.Testing; +using osu.Game.Database; +using osu.Game.Graphics.UserInterface; +using osu.Game.Input.Bindings; +using osu.Game.Overlays.Settings.Sections.Input; +using osu.Game.Screens.Play; +using osu.Game.Screens.Select; +using osu.Game.Tests.Beatmaps.IO; +using osu.Game.Tests.Database; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Navigation +{ + public class TestSceneChangeAndUseGameplayBindings : OsuGameTestScene + { + [Test] + public void TestGameplayKeyBindings() + { + AddAssert("databased key is default", () => firstOsuRulesetKeyBindings.KeyCombination.Keys.SequenceEqual(new[] { InputKey.Z })); + + AddStep("open settings", () => { Game.Settings.Show(); }); + + // Until step requires as settings has a delayed load. + AddUntilStep("wait for button", () => configureBindingsButton?.Enabled.Value == true); + AddStep("scroll to section", () => Game.Settings.SectionsContainer.ScrollTo(configureBindingsButton)); + AddStep("press button", () => configureBindingsButton.TriggerClick()); + AddUntilStep("wait for panel", () => keyBindingPanel?.IsLoaded == true); + AddUntilStep("wait for osu subsection", () => osuBindingSubsection?.IsLoaded == true); + AddStep("scroll to section", () => keyBindingPanel.SectionsContainer.ScrollTo(osuBindingSubsection)); + AddWaitStep("wait for scroll to end", 3); + AddStep("start rebinding first osu! key", () => + { + var button = osuBindingSubsection.ChildrenOfType().First(); + + InputManager.MoveMouseTo(button); + InputManager.Click(MouseButton.Left); + }); + + AddStep("Press 's'", () => InputManager.Key(Key.S)); + + AddUntilStep("wait for database updated", () => firstOsuRulesetKeyBindings.KeyCombination.Keys.SequenceEqual(new[] { InputKey.S })); + + AddStep("close settings", () => Game.Settings.Hide()); + + AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).WaitSafely()); + PushAndConfirm(() => new PlaySongSelect()); + + AddStep("enter gameplay", () => InputManager.Key(Key.Enter)); + + AddUntilStep("wait for gameplay", () => player?.IsBreakTime.Value == false); + + AddStep("press 'z'", () => InputManager.Key(Key.Z)); + AddAssert("key counter didn't increase", () => keyCounter.CountPresses == 0); + + AddStep("press 's'", () => InputManager.Key(Key.S)); + AddAssert("key counter did increase", () => keyCounter.CountPresses == 1); + } + + private KeyBindingsSubsection osuBindingSubsection => keyBindingPanel + .ChildrenOfType() + .FirstOrDefault(s => s.Ruleset.ShortName == "osu"); + + private OsuButton configureBindingsButton => Game.Settings + .ChildrenOfType().SingleOrDefault()? + .ChildrenOfType()? + .First(b => b.Text.ToString() == "Configure"); + + private KeyBindingPanel keyBindingPanel => Game.Settings + .ChildrenOfType().SingleOrDefault(); + + private RealmKeyBinding firstOsuRulesetKeyBindings => Game.Dependencies + .Get().Context + .All() + .AsEnumerable() + .First(k => k.RulesetName == "osu" && k.ActionInt == 0); + + private Player player => Game.ScreenStack.CurrentScreen as Player; + + private KeyCounter keyCounter => player.ChildrenOfType().First(); + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs index 115a7bdc79..94c7c66538 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { protected IEnumerable Defaults; - protected RulesetInfo Ruleset; + public RulesetInfo Ruleset { get; protected set; } private readonly int? variant; From a80e461000737994c24d84ea20fabe34494d5c6d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Jan 2022 16:23:58 +0900 Subject: [PATCH 07/20] Add better test coverage of user top scores --- .../Visual/Online/TestSceneScoresContainer.cs | 455 +++++++++--------- 1 file changed, 235 insertions(+), 220 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs index 71b60d8842..d4af01f772 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -30,36 +31,247 @@ namespace osu.Game.Tests.Visual.Online private TestScoresContainer scoresContainer; [SetUpSteps] - public void SetUpSteps() + public void SetUp() => Schedule(() => { - AddStep("Create container", () => + Child = new Container { - Child = new Container + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Width = 0.8f, + Children = new Drawable[] { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Both, - Width = 0.8f, - Children = new Drawable[] + new Box { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - scoresContainer = new TestScoresContainer - { - Beatmap = { Value = CreateAPIBeatmap() } - } + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + scoresContainer = new TestScoresContainer + { + Beatmap = { Value = CreateAPIBeatmap() } } - }; + } + }; + }); + + [Test] + public void TestNoUserBest() + { + AddStep("Scores with no user best", () => + { + var allScores = createScores(); + + allScores.UserScore = null; + + scoresContainer.Scores = allScores; }); + + AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType().Any()); + AddAssert("no user best displayed", () => scoresContainer.ChildrenOfType().Count() == 1); + + AddStep("Load null scores", () => scoresContainer.Scores = null); + + AddUntilStep("wait for scores not displayed", () => !scoresContainer.ChildrenOfType().Any()); + AddAssert("no best score displayed", () => !scoresContainer.ChildrenOfType().Any()); + + AddStep("Load only one score", () => + { + var allScores = createScores(); + + allScores.Scores.RemoveRange(1, allScores.Scores.Count - 1); + + scoresContainer.Scores = allScores; + }); + + AddUntilStep("wait for scores not displayed", () => scoresContainer.ChildrenOfType().Count() == 1); + AddAssert("no best score displayed", () => scoresContainer.ChildrenOfType().Count() == 1); } [Test] - public void TestDisplay() + public void TestUserBest() { - foreach (var s in allScores.Scores) + AddStep("Load scores with personal best", () => + { + var allScores = createScores(); + allScores.UserScore = createUserBest(); + scoresContainer.Scores = allScores; + }); + + AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType().Any()); + AddAssert("best score displayed", () => scoresContainer.ChildrenOfType().Count() == 2); + + AddStep("Load scores with personal best (null position)", () => + { + var allScores = createScores(); + var userBest = createUserBest(); + userBest.Position = null; + allScores.UserScore = userBest; + scoresContainer.Scores = allScores; + }); + + AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType().Any()); + AddAssert("best score displayed", () => scoresContainer.ChildrenOfType().Count() == 2); + + AddStep("Load scores with personal best (first place)", () => + { + var allScores = createScores(); + allScores.UserScore = new APIScoreWithPosition + { + Score = allScores.Scores.First(), + Position = 1, + }; + scoresContainer.Scores = allScores; + }); + + AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType().Any()); + AddAssert("best score displayed", () => scoresContainer.ChildrenOfType().Count() == 1); + + AddStep("Scores with no user best", () => + { + var allScores = createScores(); + + allScores.UserScore = null; + + scoresContainer.Scores = allScores; + }); + + AddAssert("best score not displayed", () => scoresContainer.ChildrenOfType().Count() == 1); + } + + private int onlineID = 1; + + private APIScoresCollection createScores() + { + var scores = new APIScoresCollection + { + Scores = new List + { + new APIScore + { + Date = DateTimeOffset.Now, + OnlineID = onlineID++, + User = new APIUser + { + Id = 6602580, + Username = @"waaiiru", + Country = new Country + { + FullName = @"Spain", + FlagName = @"ES", + }, + }, + Mods = new[] + { + new APIMod { Acronym = new OsuModDoubleTime().Acronym }, + new APIMod { Acronym = new OsuModHidden().Acronym }, + new APIMod { Acronym = new OsuModFlashlight().Acronym }, + new APIMod { Acronym = new OsuModHardRock().Acronym }, + }, + Rank = ScoreRank.XH, + PP = 200, + MaxCombo = 1234, + TotalScore = 1234567890, + Accuracy = 1, + }, + new APIScore + { + Date = DateTimeOffset.Now, + OnlineID = onlineID++, + User = new APIUser + { + Id = 4608074, + Username = @"Skycries", + Country = new Country + { + FullName = @"Brazil", + FlagName = @"BR", + }, + }, + Mods = new[] + { + new APIMod { Acronym = new OsuModDoubleTime().Acronym }, + new APIMod { Acronym = new OsuModHidden().Acronym }, + new APIMod { Acronym = new OsuModFlashlight().Acronym }, + }, + Rank = ScoreRank.S, + PP = 190, + MaxCombo = 1234, + TotalScore = 1234789, + Accuracy = 0.9997, + }, + new APIScore + { + Date = DateTimeOffset.Now, + OnlineID = onlineID++, + User = new APIUser + { + Id = 1014222, + Username = @"eLy", + Country = new Country + { + FullName = @"Japan", + FlagName = @"JP", + }, + }, + Mods = new[] + { + new APIMod { Acronym = new OsuModDoubleTime().Acronym }, + new APIMod { Acronym = new OsuModHidden().Acronym }, + }, + Rank = ScoreRank.B, + PP = 180, + MaxCombo = 1234, + TotalScore = 12345678, + Accuracy = 0.9854, + }, + new APIScore + { + Date = DateTimeOffset.Now, + OnlineID = onlineID++, + User = new APIUser + { + Id = 1541390, + Username = @"Toukai", + Country = new Country + { + FullName = @"Canada", + FlagName = @"CA", + }, + }, + Mods = new[] + { + new APIMod { Acronym = new OsuModDoubleTime().Acronym }, + }, + Rank = ScoreRank.C, + PP = 170, + MaxCombo = 1234, + TotalScore = 1234567, + Accuracy = 0.8765, + }, + new APIScore + { + Date = DateTimeOffset.Now, + OnlineID = onlineID++, + User = new APIUser + { + Id = 7151382, + Username = @"Mayuri Hana", + Country = new Country + { + FullName = @"Thailand", + FlagName = @"TH", + }, + }, + Rank = ScoreRank.D, + PP = 160, + MaxCombo = 1234, + TotalScore = 123456, + Accuracy = 0.6543, + }, + } + }; + + foreach (var s in scores.Scores) { s.Statistics = new Dictionary { @@ -70,155 +282,15 @@ namespace osu.Game.Tests.Visual.Online }; } - AddStep("Load all scores", () => - { - allScores.UserScore = null; - scoresContainer.Scores = allScores; - }); - AddStep("Load null scores", () => scoresContainer.Scores = null); - AddStep("Load only one score", () => scoresContainer.Scores = oneScore); - AddStep("Load scores with my best", () => - { - allScores.UserScore = myBestScore; - scoresContainer.Scores = allScores; - }); - - AddStep("Load scores with null my best position", () => - { - allScores.UserScore = myBestScoreWithNullPosition; - scoresContainer.Scores = allScores; - }); + return scores; } - private readonly APIScoresCollection allScores = new APIScoresCollection - { - Scores = new List - { - new APIScore - { - Date = DateTimeOffset.Now, - User = new APIUser - { - Id = 6602580, - Username = @"waaiiru", - Country = new Country - { - FullName = @"Spain", - FlagName = @"ES", - }, - }, - Mods = new[] - { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - new APIMod { Acronym = new OsuModHidden().Acronym }, - new APIMod { Acronym = new OsuModFlashlight().Acronym }, - new APIMod { Acronym = new OsuModHardRock().Acronym }, - }, - Rank = ScoreRank.XH, - PP = 200, - MaxCombo = 1234, - TotalScore = 1234567890, - Accuracy = 1, - }, - new APIScore - { - Date = DateTimeOffset.Now, - User = new APIUser - { - Id = 4608074, - Username = @"Skycries", - Country = new Country - { - FullName = @"Brazil", - FlagName = @"BR", - }, - }, - Mods = new[] - { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - new APIMod { Acronym = new OsuModHidden().Acronym }, - new APIMod { Acronym = new OsuModFlashlight().Acronym }, - }, - Rank = ScoreRank.S, - PP = 190, - MaxCombo = 1234, - TotalScore = 1234789, - Accuracy = 0.9997, - }, - new APIScore - { - Date = DateTimeOffset.Now, - User = new APIUser - { - Id = 1014222, - Username = @"eLy", - Country = new Country - { - FullName = @"Japan", - FlagName = @"JP", - }, - }, - Mods = new[] - { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - new APIMod { Acronym = new OsuModHidden().Acronym }, - }, - Rank = ScoreRank.B, - PP = 180, - MaxCombo = 1234, - TotalScore = 12345678, - Accuracy = 0.9854, - }, - new APIScore - { - Date = DateTimeOffset.Now, - User = new APIUser - { - Id = 1541390, - Username = @"Toukai", - Country = new Country - { - FullName = @"Canada", - FlagName = @"CA", - }, - }, - Mods = new[] - { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - }, - Rank = ScoreRank.C, - PP = 170, - MaxCombo = 1234, - TotalScore = 1234567, - Accuracy = 0.8765, - }, - new APIScore - { - Date = DateTimeOffset.Now, - User = new APIUser - { - Id = 7151382, - Username = @"Mayuri Hana", - Country = new Country - { - FullName = @"Thailand", - FlagName = @"TH", - }, - }, - Rank = ScoreRank.D, - PP = 160, - MaxCombo = 1234, - TotalScore = 123456, - Accuracy = 0.6543, - }, - } - }; - - private readonly APIScoreWithPosition myBestScore = new APIScoreWithPosition + private APIScoreWithPosition createUserBest() => new APIScoreWithPosition { Score = new APIScore { Date = DateTimeOffset.Now, + OnlineID = onlineID++, User = new APIUser { Id = 7151382, @@ -238,63 +310,6 @@ namespace osu.Game.Tests.Visual.Online Position = 1337, }; - private readonly APIScoreWithPosition myBestScoreWithNullPosition = new APIScoreWithPosition - { - Score = new APIScore - { - Date = DateTimeOffset.Now, - User = new APIUser - { - Id = 7151382, - Username = @"Mayuri Hana", - Country = new Country - { - FullName = @"Thailand", - FlagName = @"TH", - }, - }, - Rank = ScoreRank.D, - PP = 160, - MaxCombo = 1234, - TotalScore = 123456, - Accuracy = 0.6543, - }, - Position = null, - }; - - private readonly APIScoresCollection oneScore = new APIScoresCollection - { - Scores = new List - { - new APIScore - { - Date = DateTimeOffset.Now, - User = new APIUser - { - Id = 6602580, - Username = @"waaiiru", - Country = new Country - { - FullName = @"Spain", - FlagName = @"ES", - }, - }, - Mods = new[] - { - new APIMod { Acronym = new OsuModDoubleTime().Acronym }, - new APIMod { Acronym = new OsuModHidden().Acronym }, - new APIMod { Acronym = new OsuModFlashlight().Acronym }, - new APIMod { Acronym = new OsuModHardRock().Acronym }, - }, - Rank = ScoreRank.XH, - PP = 200, - MaxCombo = 1234, - TotalScore = 1234567890, - Accuracy = 1, - } - } - }; - private class TestScoresContainer : ScoresContainer { public new APIScoresCollection Scores From f6b9d36acffcbce19314e52bfb1eac45bbb1fc8a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 17 Jan 2022 17:06:04 +0900 Subject: [PATCH 08/20] Remove unused using --- .../Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs index 7dda158ee1..7a44a7643d 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs @@ -14,7 +14,6 @@ using osu.Game.Overlays.Settings.Sections.Input; using osu.Game.Screens.Play; using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; -using osu.Game.Tests.Database; using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation From 0ba0b5f11abb083bcdf29f41b8b229fc160b5e4b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Jan 2022 19:45:32 +0900 Subject: [PATCH 09/20] Fix test step not being `until` when it needs to be --- osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs index d4af01f772..8a304110dd 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs @@ -135,7 +135,7 @@ namespace osu.Game.Tests.Visual.Online scoresContainer.Scores = allScores; }); - AddAssert("best score not displayed", () => scoresContainer.ChildrenOfType().Count() == 1); + AddUntilStep("best score not displayed", () => scoresContainer.ChildrenOfType().Count() == 1); } private int onlineID = 1; From 125439d17760b6ad2ecba6d5ac0a25d404cd5d9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 11:09:26 +0900 Subject: [PATCH 10/20] Update all (non-NET6) nuget packages --- .../osu.Game.Rulesets.EmptyFreeform.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- .../osu.Game.Rulesets.EmptyScrolling.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- osu.Game.Benchmarks/osu.Game.Benchmarks.csproj | 2 +- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- .../osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- .../osu.Game.Tournament.Tests.csproj | 2 +- osu.Game/osu.Game.csproj | 8 ++++---- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj index 3c6aaa39ca..a7078f1c09 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 0719dd30df..c133b0e3f8 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj index d0db43cc81..92b48470e8 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 0719dd30df..c133b0e3f8 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj index 57b914bee6..a8599f2cb6 100644 --- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj +++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj @@ -9,7 +9,7 @@ - + diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 13f2e25f05..d5496b7479 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index d51a6da4f9..2f12b1535e 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index fea2e408f6..e5b2e070d8 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index ad3713e047..e48d80323a 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 3b115d43e5..c64ef918e3 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index 130fcfaca1..fb09a7be1e 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -7,7 +7,7 @@ - + WinExe diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2e5c9f4548..5508cac93e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,9 +18,9 @@ - + - + @@ -35,10 +35,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + From 911a837f62b371ec7b4c119ff43af3f16c2658bb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 11:09:35 +0900 Subject: [PATCH 11/20] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index b2e3b32916..18e63bb219 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5508cac93e..758575e74a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 897be33c18..d6c4533538 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -60,7 +60,7 @@ - + @@ -83,7 +83,7 @@ - + From f9c5000774d08c3f9c7e6f561205d0c082326590 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 11:27:28 +0900 Subject: [PATCH 12/20] Remove obsoleted sentry disposal call and fix incorrectly unbound logger event --- osu.Game/Utils/SentryLogger.cs | 46 ++++++++++++++-------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/osu.Game/Utils/SentryLogger.cs b/osu.Game/Utils/SentryLogger.cs index 8f12760a6b..dbf04283b6 100644 --- a/osu.Game/Utils/SentryLogger.cs +++ b/osu.Game/Utils/SentryLogger.cs @@ -16,6 +16,7 @@ namespace osu.Game.Utils { private SentryClient sentry; private Scope sentryScope; + private Exception lastException; public SentryLogger(OsuGame game) { @@ -30,30 +31,27 @@ namespace osu.Game.Utils sentry = new SentryClient(options); sentryScope = new Scope(options); - Exception lastException = null; + Logger.NewEntry += processLogEntry; + } - Logger.NewEntry += entry => + private void processLogEntry(LogEntry entry) + { + if (entry.Level < LogLevel.Verbose) return; + + var exception = entry.Exception; + + if (exception != null) { - if (entry.Level < LogLevel.Verbose) return; + if (!shouldSubmitException(exception)) return; - var exception = entry.Exception; + // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports. + if (lastException != null && lastException.Message == exception.Message && exception.StackTrace.StartsWith(lastException.StackTrace, StringComparison.Ordinal)) return; - if (exception != null) - { - if (!shouldSubmitException(exception)) - return; - - // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports. - if (lastException != null && - lastException.Message == exception.Message && exception.StackTrace.StartsWith(lastException.StackTrace, StringComparison.Ordinal)) - return; - - lastException = exception; - sentry.CaptureEvent(new SentryEvent(exception) { Message = entry.Message }, sentryScope); - } - else - sentryScope.AddBreadcrumb(DateTimeOffset.Now, entry.Message, entry.Target.ToString(), "navigation"); - }; + lastException = exception; + sentry.CaptureEvent(new SentryEvent(exception) { Message = entry.Message }, sentryScope); + } + else + sentryScope.AddBreadcrumb(DateTimeOffset.Now, entry.Message, entry.Target.ToString(), "navigation"); } private bool shouldSubmitException(Exception exception) @@ -92,15 +90,9 @@ namespace osu.Game.Utils GC.SuppressFinalize(this); } - private bool isDisposed; - protected virtual void Dispose(bool isDisposing) { - if (isDisposed) - return; - - isDisposed = true; - sentry?.Dispose(); + Logger.NewEntry -= processLogEntry; sentry = null; sentryScope = null; } From c725548b9ec7b78ad08ec5beb823e70d6f4672bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 11:42:50 +0900 Subject: [PATCH 13/20] Update stray realm reference in mobile projects --- osu.Android.props | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 18e63bb219..b296c114e9 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -56,6 +56,6 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index d6c4533538..5925581e28 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -88,6 +88,6 @@ - + From a7db793d8c14f1923aeac26aeabda00a2f6aa60b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 11:39:22 +0900 Subject: [PATCH 14/20] Specify realm pipe path location I can't confirm this works yet, since I'm not sure what the preconditions are for the `.note` file to be created. What I can confirm is that a `.note` file hasn't appeared in my game data directory yet. --- osu.Game/Database/RealmContextFactory.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Database/RealmContextFactory.cs b/osu.Game/Database/RealmContextFactory.cs index 96c24837a1..04253ade82 100644 --- a/osu.Game/Database/RealmContextFactory.cs +++ b/osu.Game/Database/RealmContextFactory.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.IO; using System.Linq; using System.Reflection; using System.Threading; @@ -188,10 +189,17 @@ namespace osu.Game.Database private RealmConfiguration getConfiguration() { + // This is currently the only usage of temporary files at the osu! side. + // If we use the temporary folder in more situations in the future, this should be moved to a higher level (helper method or OsuGameBase). + string tempPathLocation = Path.Combine(Path.GetTempPath(), @"lazer"); + if (!Directory.Exists(tempPathLocation)) + Directory.CreateDirectory(tempPathLocation); + return new RealmConfiguration(storage.GetFullPath(Filename, true)) { SchemaVersion = schema_version, MigrationCallback = onMigration, + FallbackPipePath = tempPathLocation, }; } From d26f4d50bd92834f021e89ac56263e426e64e6e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 13:58:12 +0900 Subject: [PATCH 15/20] Add test coverage of aggregate room scores displaying correctly --- .../TestScenePlaylistsRoomCreation.cs | 3 +++ .../Online/Leaderboards/LeaderboardScore.cs | 10 ++++---- .../OnlinePlay/TestRoomRequestsHandler.cs | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs index e59884f4f4..6efdd1b8b6 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs @@ -18,6 +18,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; using osu.Game.Tests.Beatmaps; @@ -71,6 +72,8 @@ namespace osu.Game.Tests.Visual.Playlists AddUntilStep("Progress details are hidden", () => match.ChildrenOfType().FirstOrDefault()?.Parent.Alpha == 0); + AddUntilStep("Leaderboard shows two aggregate scores", () => match.ChildrenOfType().Count(s => s.ScoreText.Text != "0") == 2); + AddStep("start match", () => match.ChildrenOfType().First().TriggerClick()); AddUntilStep("player loader loaded", () => Stack.CurrentScreen is PlayerLoader); } diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 14eec8b388..8f4a103513 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -53,7 +53,9 @@ namespace osu.Game.Online.Leaderboards private Drawable avatar; private Drawable scoreRank; private OsuSpriteText nameLabel; - private GlowingSpriteText scoreLabel; + + public GlowingSpriteText ScoreText { get; private set; } + private Container flagBadgeContainer; private FillFlowContainer modsContainer; @@ -198,7 +200,7 @@ namespace osu.Game.Online.Leaderboards Spacing = new Vector2(5f, 0f), Children = new Drawable[] { - scoreLabel = new GlowingSpriteText + ScoreText = new GlowingSpriteText { TextColour = Color4.White, GlowColour = Color4Extensions.FromHex(@"83ccfa"), @@ -240,7 +242,7 @@ namespace osu.Game.Online.Leaderboards public override void Show() { - foreach (var d in new[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, modsContainer }.Concat(statisticsLabels)) + foreach (var d in new[] { avatar, nameLabel, ScoreText, scoreRank, flagBadgeContainer, modsContainer }.Concat(statisticsLabels)) d.FadeOut(); Alpha = 0; @@ -262,7 +264,7 @@ namespace osu.Game.Online.Leaderboards using (BeginDelayedSequence(250)) { - scoreLabel.FadeIn(200); + ScoreText.FadeIn(200); scoreRank.FadeIn(200); using (BeginDelayedSequence(50)) diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs index 520f2c4585..5a0a7e71d4 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -70,6 +70,29 @@ namespace osu.Game.Tests.Visual.OnlinePlay return true; } + case GetRoomLeaderboardRequest roomLeaderboardRequest: + roomLeaderboardRequest.TriggerSuccess(new APILeaderboard + { + Leaderboard = new List + { + new APIUserScoreAggregate + { + TotalScore = 1000000, + TotalAttempts = 5, + CompletedBeatmaps = 2, + User = new APIUser { Username = "best user" } + }, + new APIUserScoreAggregate + { + TotalScore = 50, + TotalAttempts = 1, + CompletedBeatmaps = 1, + User = new APIUser { Username = "worst user" } + } + } + }); + return true; + case PartRoomRequest partRoomRequest: partRoomRequest.TriggerSuccess(); return true; From 9a43ed742b0260b29dc28d9221676ffce938f3a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 15:21:08 +0900 Subject: [PATCH 16/20] Update automapper spec in line with v11 See https://docs.automapper.org/en/latest/11.0-Upgrade-Guide.html for more details. --- osu.Game/Beatmaps/BeatmapInfo.cs | 4 -- osu.Game/Database/RealmObjectExtensions.cs | 56 +++++++++++++++------- osu.Game/Scoring/ScoreInfo.cs | 3 +- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 224cf60c49..b0e10c2c38 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -3,7 +3,6 @@ using System; using System.Linq; -using AutoMapper; using JetBrains.Annotations; using Newtonsoft.Json; using osu.Framework.Testing; @@ -37,7 +36,6 @@ namespace osu.Game.Beatmaps public BeatmapMetadata Metadata { get; set; } - [IgnoreMap] [Backlink(nameof(ScoreInfo.BeatmapInfo))] public IQueryable Scores { get; } = null!; @@ -155,7 +153,6 @@ namespace osu.Game.Beatmaps #region Compatibility properties [Ignored] - [IgnoreMap] public int RulesetID { get => Ruleset.OnlineID; @@ -169,7 +166,6 @@ namespace osu.Game.Beatmaps } [Ignored] - [IgnoreMap] public BeatmapDifficulty BaseDifficulty { get => Difficulty; diff --git a/osu.Game/Database/RealmObjectExtensions.cs b/osu.Game/Database/RealmObjectExtensions.cs index a162bd64d3..4ddf0077ca 100644 --- a/osu.Game/Database/RealmObjectExtensions.cs +++ b/osu.Game/Database/RealmObjectExtensions.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using AutoMapper; +using AutoMapper.Internal; using osu.Framework.Development; using osu.Game.Beatmaps; using osu.Game.Input.Bindings; @@ -60,7 +62,14 @@ namespace osu.Game.Database } }); - c.AddGlobalIgnore(nameof(RealmObjectBase.ObjectSchema)); + c.Internal().ForAllMaps((typeMap, expression) => + { + expression.ForAllMembers(m => + { + if (m.DestinationMember.Has() || m.DestinationMember.Has() || m.DestinationMember.Has()) + m.Ignore(); + }); + }); }).CreateMapper(); private static readonly IMapper mapper = new MapperConfiguration(c => @@ -80,24 +89,35 @@ namespace osu.Game.Database c.CreateMap(); c.CreateMap(); c.CreateMap(); - c.CreateMap().MaxDepth(2).AfterMap((s, d) => - { - for (int i = 0; i < d.BeatmapSet?.Beatmaps.Count; i++) - { - if (d.BeatmapSet.Beatmaps[i].Equals(d)) - { - d.BeatmapSet.Beatmaps[i] = d; - break; - } - } - }); - c.CreateMap().MaxDepth(2).AfterMap((s, d) => - { - foreach (var beatmap in d.Beatmaps) - beatmap.BeatmapSet = d; - }); + c.CreateMap() + .MaxDepth(2) + .AfterMap((s, d) => + { + for (int i = 0; i < d.BeatmapSet?.Beatmaps.Count; i++) + { + if (d.BeatmapSet.Beatmaps[i].Equals(d)) + { + d.BeatmapSet.Beatmaps[i] = d; + break; + } + } + }); + c.CreateMap() + .MaxDepth(2) + .AfterMap((s, d) => + { + foreach (var beatmap in d.Beatmaps) + beatmap.BeatmapSet = d; + }); - c.AddGlobalIgnore(nameof(RealmObjectBase.ObjectSchema)); + c.Internal().ForAllMaps((typeMap, expression) => + { + expression.ForAllMembers(m => + { + if (m.DestinationMember.Has() || m.DestinationMember.Has() || m.DestinationMember.Has()) + m.Ignore(); + }); + }); }).CreateMapper(); /// diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index fd0f14266a..5614f34f3f 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using AutoMapper; using JetBrains.Annotations; using Newtonsoft.Json; using osu.Framework.Localisation; @@ -85,7 +84,7 @@ namespace osu.Game.Scoring // Eventually we should either persist enough information to realm to not require the API lookups, or perform the API lookups locally. private APIUser? user; - [IgnoreMap] + [Ignored] public APIUser User { get => user ??= new APIUser From 7084183d6c3a3a126d0c5ddc2401df16e264fab8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 15:43:02 +0900 Subject: [PATCH 17/20] Fix test beatmaps created without hash being populated --- osu.Game.Tests/Resources/TestResources.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index d0ffb9c3db..1d99a5c20d 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -130,6 +130,7 @@ namespace osu.Game.Tests.Resources StarRating = diff, Length = length, BPM = bpm, + Hash = Guid.NewGuid().ToString().ComputeMD5Hash(), Ruleset = rulesetInfo, Metadata = metadata, BaseDifficulty = new BeatmapDifficulty From a5862ca00df2e6839abdb47e5dd64f9270d704c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 15:46:27 +0900 Subject: [PATCH 18/20] Improve reliability of mod deserialisation --- osu.Game/Scoring/ScoreInfo.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 5614f34f3f..e1328d8a06 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -186,10 +186,7 @@ namespace osu.Game.Scoring if (mods != null) return mods; - if (apiMods != null) - return APIMods.Select(m => m.ToMod(Ruleset.CreateInstance())).ToArray(); - - return Array.Empty(); + return APIMods.Select(m => m.ToMod(Ruleset.CreateInstance())).ToArray(); } set { @@ -216,7 +213,7 @@ namespace osu.Game.Scoring // then check mods set via Mods property. if (mods != null) - apiMods = mods.Select(m => new APIMod(m)).ToArray(); + apiMods ??= mods.Select(m => new APIMod(m)).ToArray(); return apiMods ?? Array.Empty(); } From 488f0449249951fd204b4551b6beae7e290e43e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 16:46:14 +0900 Subject: [PATCH 19/20] Remove one more outdated comment --- osu.Game/Tests/Visual/OsuTestScene.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index c631286d11..4af8ec3a99 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -294,10 +294,6 @@ namespace osu.Game.Tests.Visual if (MusicController?.TrackLoaded == true) MusicController.Stop(); - // TODO: what should we do here, if anything? should we use an in-memory realm in this instance? - // if (contextFactory?.IsValueCreated == true) - // contextFactory.Value.ResetDatabase(); - RecycleLocalStorage(true); } From 3e9e7a8fb61e6af4279b4ee405e9aa8c42674c95 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 16:48:27 +0900 Subject: [PATCH 20/20] Fix `PLaylistsResultsScreen` tests falling over due to missing beatmap --- .../Visual/Playlists/TestScenePlaylistsResultsScreen.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index e9210496ca..11df115b1a 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -44,6 +44,10 @@ namespace osu.Game.Tests.Visual.Playlists requestComplete = false; totalCount = 0; bindHandler(); + + // beatmap is required to be an actual beatmap so the scores can get their scores correctly calculated for standardised scoring. + // else the tests that rely on ordering will fall over. + Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); }); [Test]