From b42081dd9bca5e574fa6fe0b0af576a99a53ffa2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 16:06:32 +0900 Subject: [PATCH 01/25] Add `DangerousButton` for use in popup dialogs --- .../UserInterface/TestScenePopupDialog.cs | 4 ++ .../Graphics/UserInterface/DialogButton.cs | 19 +++--- .../Dialog/PopupDialogDangerousButton.cs | 59 +++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs index 8e53c7c402..6bd6115e68 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs @@ -40,6 +40,10 @@ namespace osu.Game.Tests.Visual.UserInterface { Text = @"You're a fake!", }, + new PopupDialogDangerousButton + { + Text = @"Careful with this one..", + }, }; } } diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs index 2f9e4dae51..ad69ec4078 100644 --- a/osu.Game/Graphics/UserInterface/DialogButton.cs +++ b/osu.Game/Graphics/UserInterface/DialogButton.cs @@ -45,8 +45,9 @@ namespace osu.Game.Graphics.UserInterface } } + protected readonly Container ColourContainer; + private readonly Container backgroundContainer; - private readonly Container colourContainer; private readonly Container glowContainer; private readonly Box leftGlow; private readonly Box centerGlow; @@ -113,7 +114,7 @@ namespace osu.Game.Graphics.UserInterface Masking = true, Children = new Drawable[] { - colourContainer = new Container + ColourContainer = new Container { RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, @@ -182,7 +183,7 @@ namespace osu.Game.Graphics.UserInterface { buttonColour = value; updateGlow(); - colourContainer.Colour = value; + ColourContainer.Colour = value; } } @@ -230,11 +231,11 @@ namespace osu.Game.Graphics.UserInterface Alpha = 0.05f }; - colourContainer.Add(flash); + ColourContainer.Add(flash); flash.FadeOutFromOne(100).Expire(); clickAnimating = true; - colourContainer.ResizeWidthTo(colourContainer.Width * 1.05f, 100, Easing.OutQuint) + ColourContainer.ResizeWidthTo(ColourContainer.Width * 1.05f, 100, Easing.OutQuint) .OnComplete(_ => { clickAnimating = false; @@ -246,14 +247,14 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnMouseDown(MouseDownEvent e) { - colourContainer.ResizeWidthTo(hover_width * 0.98f, click_duration * 4, Easing.OutQuad); + ColourContainer.ResizeWidthTo(hover_width * 0.98f, click_duration * 4, Easing.OutQuad); return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { if (State == SelectionState.Selected) - colourContainer.ResizeWidthTo(hover_width, click_duration, Easing.In); + ColourContainer.ResizeWidthTo(hover_width, click_duration, Easing.In); base.OnMouseUp(e); } @@ -279,12 +280,12 @@ namespace osu.Game.Graphics.UserInterface if (newState == SelectionState.Selected) { spriteText.TransformSpacingTo(hoverSpacing, hover_duration, Easing.OutElastic); - colourContainer.ResizeWidthTo(hover_width, hover_duration, Easing.OutElastic); + ColourContainer.ResizeWidthTo(hover_width, hover_duration, Easing.OutElastic); glowContainer.FadeIn(hover_duration, Easing.OutQuint); } else { - colourContainer.ResizeWidthTo(idle_width, hover_duration, Easing.OutElastic); + ColourContainer.ResizeWidthTo(idle_width, hover_duration, Easing.OutElastic); spriteText.TransformSpacingTo(Vector2.Zero, hover_duration, Easing.OutElastic); glowContainer.FadeOut(hover_duration, Easing.OutQuint); } diff --git a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs new file mode 100644 index 0000000000..1911a4fa56 --- /dev/null +++ b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; + +namespace osu.Game.Overlays.Dialog +{ + public class PopupDialogDangerousButton : PopupDialogButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + ButtonColour = colours.Red3; + + ColourContainer.Add(new ConfirmFillBox + { + Action = () => Action(), + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, + }); + } + + private class ConfirmFillBox : HoldToConfirmContainer + { + private Box box; + + protected override double? HoldActivationDelay => 500; + + protected override void LoadComplete() + { + base.LoadComplete(); + + Child = box = new Box + { + RelativeSizeAxes = Axes.Both, + }; + + Progress.BindValueChanged(progress => box.Width = (float)progress.NewValue, true); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + BeginConfirm(); + return true; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + if (!e.HasAnyButtonPressed) + AbortConfirm(); + } + } + } +} From d811a70f4b42cb638a6cc6be169acfb0f99275f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 16:06:58 +0900 Subject: [PATCH 02/25] Change button types on editor exit dialog to match purpose Addresses https://github.com/ppy/osu/discussions/17363. --- osu.Game/Screens/Edit/PromptForSaveDialog.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/PromptForSaveDialog.cs b/osu.Game/Screens/Edit/PromptForSaveDialog.cs index e308a9533d..4f70491ade 100644 --- a/osu.Game/Screens/Edit/PromptForSaveDialog.cs +++ b/osu.Game/Screens/Edit/PromptForSaveDialog.cs @@ -17,12 +17,12 @@ namespace osu.Game.Screens.Edit Buttons = new PopupDialogButton[] { - new PopupDialogCancelButton + new PopupDialogOkButton { Text = @"Save my masterpiece!", Action = saveAndExit }, - new PopupDialogOkButton + new PopupDialogDangerousButton { Text = @"Forget all changes", Action = exit From 36868dbdb4d8f480ebbbd68d268c4e35c8fd4ba0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 16:07:26 +0900 Subject: [PATCH 03/25] Add the ability to override the user setting for hold-to-confirm containers Sometimes the user is not right. --- .../Graphics/Containers/HoldToConfirmContainer.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index 999dd183aa..b2f08eee0a 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -28,6 +28,14 @@ namespace osu.Game.Graphics.Containers /// protected virtual bool AllowMultipleFires => false; + /// + /// Specify a custom activation delay, overriding the game-wide user setting. + /// + /// + /// This should be used in special cases where we want to be extra sure the user knows what they are doing. An example is when changes would be lost. + /// + protected virtual double? HoldActivationDelay => null; + public Bindable Progress = new BindableDouble(); private Bindable holdActivationDelay; @@ -35,7 +43,9 @@ namespace osu.Game.Graphics.Containers [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - holdActivationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); + holdActivationDelay = HoldActivationDelay != null + ? new Bindable(HoldActivationDelay.Value) + : config.GetBindable(OsuSetting.UIHoldActivationDelay); } protected void BeginConfirm() From 3643f879e42fda75f2e2308c098f7fa2fbcf1bd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 17:01:46 +0900 Subject: [PATCH 04/25] Add test coverage of skin editor settings slider not working via keyboard adjustments --- .../Visual/Gameplay/TestSceneSkinEditor.cs | 37 ++++++++- .../Navigation/TestSceneScreenNavigation.cs | 77 ++++++++++++++++++- .../Skinning/Editor/SkinEditorSceneLibrary.cs | 3 +- 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index e74345aae9..38d83058c0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -1,14 +1,19 @@ // 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.Graphics; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Overlays; +using osu.Game.Overlays.Settings; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Skinning.Editor; +using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { @@ -29,7 +34,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("reload skin editor", () => { skinEditor?.Expire(); - Player.ScaleTo(0.8f); + Player.ScaleTo(0.4f); LoadComponentAsync(skinEditor = new SkinEditor(Player), Add); }); } @@ -40,6 +45,36 @@ namespace osu.Game.Tests.Visual.Gameplay AddToggleStep("toggle editor visibility", visible => skinEditor.ToggleVisibility()); } + [Test] + public void TestEditComponent() + { + BarHitErrorMeter hitErrorMeter = null; + + AddStep("select bar hit error blueprint", () => + { + var blueprint = skinEditor.ChildrenOfType().First(b => b.Item is BarHitErrorMeter); + + hitErrorMeter = (BarHitErrorMeter)blueprint.Item; + skinEditor.SelectedComponents.Clear(); + skinEditor.SelectedComponents.Add(blueprint.Item); + }); + + AddAssert("value is default", () => hitErrorMeter.JudgementLineThickness.IsDefault); + + AddStep("hover first slider", () => + { + InputManager.MoveMouseTo( + skinEditor.ChildrenOfType().First() + .ChildrenOfType>().First() + .ChildrenOfType>().First() + ); + }); + + AddStep("adjust slider via keyboard", () => InputManager.Key(Key.Left)); + + AddAssert("value is less than default", () => hitErrorMeter.JudgementLineThickness.Value < hitErrorMeter.JudgementLineThickness.Default); + } + protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); } } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index f2e6aa1e16..46266e844a 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -14,6 +15,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Overlays.Mods; +using osu.Game.Overlays.Settings; using osu.Game.Overlays.Toolbar; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; @@ -21,10 +23,12 @@ using osu.Game.Scoring; using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.Select.Options; +using osu.Game.Skinning.Editor; using osu.Game.Tests.Beatmaps.IO; using osuTK; using osuTK.Input; @@ -66,6 +70,73 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); } + [Test] + public void TestEditComponentDuringGameplay() + { + Screens.Select.SongSelect songSelect = null; + PushAndConfirm(() => songSelect = new TestPlaySongSelect()); + AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded); + + AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely()); + + AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault); + + SkinEditor skinEditor = null; + + AddStep("open skin editor", () => + { + InputManager.PressKey(Key.ControlLeft); + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.S); + InputManager.ReleaseKey(Key.ControlLeft); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + + AddUntilStep("get skin editor", () => (skinEditor = Game.ChildrenOfType().FirstOrDefault()) != null); + + AddStep("Click gameplay scene button", () => + { + skinEditor.ChildrenOfType().First(b => b.Text == "Gameplay").TriggerClick(); + }); + + AddUntilStep("wait for player", () => + { + // dismiss any notifications that may appear (ie. muted notification). + clickMouseInCentre(); + return Game.ScreenStack.CurrentScreen is Player; + }); + + BarHitErrorMeter hitErrorMeter = null; + + AddUntilStep("select bar hit error blueprint", () => + { + var blueprint = skinEditor.ChildrenOfType().FirstOrDefault(b => b.Item is BarHitErrorMeter); + + if (blueprint == null) + return false; + + hitErrorMeter = (BarHitErrorMeter)blueprint.Item; + skinEditor.SelectedComponents.Clear(); + skinEditor.SelectedComponents.Add(blueprint.Item); + return true; + }); + + AddAssert("value is default", () => hitErrorMeter.JudgementLineThickness.IsDefault); + + AddStep("hover first slider", () => + { + InputManager.MoveMouseTo( + skinEditor.ChildrenOfType().First() + .ChildrenOfType>().First() + .ChildrenOfType>().First() + ); + }); + + AddStep("adjust slider via keyboard", () => InputManager.Key(Key.Left)); + + AddAssert("value is less than default", () => hitErrorMeter.JudgementLineThickness.Value < hitErrorMeter.JudgementLineThickness.Default); + } + [Test] public void TestRetryCountIncrements() { @@ -120,7 +191,8 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("press back button", () => Game.ChildrenOfType().First().Action()); - AddStep("show local scores", () => Game.ChildrenOfType().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local)); + AddStep("show local scores", + () => Game.ChildrenOfType().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local)); AddUntilStep("wait for score displayed", () => (scorePanel = Game.ChildrenOfType().FirstOrDefault(s => s.Score.Equals(score))) != null); @@ -152,7 +224,8 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("press back button", () => Game.ChildrenOfType().First().Action()); - AddStep("show local scores", () => Game.ChildrenOfType().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local)); + AddStep("show local scores", + () => Game.ChildrenOfType().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local)); AddUntilStep("wait for score displayed", () => (scorePanel = Game.ChildrenOfType().FirstOrDefault(s => s.Score.Equals(score))) != null); diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index eac13922d7..4a7cce5a97 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -104,7 +105,7 @@ namespace osu.Game.Skinning.Editor }; } - private class SceneButton : OsuButton + public class SceneButton : OsuButton { public SceneButton() { From 2f18c512cd48d594876f9222bb33bc9ca281468c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 16:52:06 +0900 Subject: [PATCH 05/25] Convert `SkinEditorOverlay` to an `OverlayContainer` to allow it to block input --- osu.Game/OsuGame.cs | 4 +++ .../Overlays/Settings/Sections/SkinSection.cs | 2 +- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 30 +++++++------------ 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 25bd3d71de..4cd954a646 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1046,6 +1046,10 @@ namespace osu.Game switch (e.Action) { + case GlobalAction.ToggleSkinEditor: + skinEditor.ToggleVisibility(); + return true; + case GlobalAction.ResetInputSettings: Host.ResetInputHandlers(); frameworkConfig.GetBindable(FrameworkSetting.ConfineMouseMode).SetDefault(); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 475c4bff8d..a34776ddf0 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -64,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections new SettingsButton { Text = SkinSettingsStrings.SkinLayoutEditor, - Action = () => skinEditor?.Toggle(), + Action = () => skinEditor?.ToggleVisibility(), }, new ExportSkinButton(), }; diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 9fc233d3e3..970a27285e 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -19,10 +19,12 @@ namespace osu.Game.Skinning.Editor /// A container which handles loading a skin editor on user request for a specified target. /// This also handles the scaling / positioning adjustment of the target. /// - public class SkinEditorOverlay : CompositeDrawable, IKeyBindingHandler + public class SkinEditorOverlay : OverlayContainer, IKeyBindingHandler { private readonly ScalingContainer scalingContainer; + protected override bool BlockNonPositionalInput => true; + [CanBeNull] private SkinEditor skinEditor; @@ -49,30 +51,12 @@ namespace osu.Game.Skinning.Editor Hide(); return true; - - case GlobalAction.ToggleSkinEditor: - Toggle(); - return true; } return false; } - public void Toggle() - { - if (skinEditor == null) - Show(); - else - skinEditor.ToggleVisibility(); - } - - public override void Hide() - { - // base call intentionally omitted. - skinEditor?.Hide(); - } - - public override void Show() + protected override void PopIn() { // base call intentionally omitted as we have custom behaviour. @@ -106,6 +90,12 @@ namespace osu.Game.Skinning.Editor }); } + protected override void PopOut() + { + // base call intentionally omitted. + skinEditor?.Hide(); + } + private void updateComponentVisibility() { Debug.Assert(skinEditor != null); From 2a696783af33c7af24f100cb68598d080acaa6b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 17:32:56 +0900 Subject: [PATCH 06/25] Remove unused const in `SkinEditorOverlay` --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 970a27285e..f848c07680 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -28,8 +28,6 @@ namespace osu.Game.Skinning.Editor [CanBeNull] private SkinEditor skinEditor; - public const float VISIBLE_TARGET_SCALE = 0.8f; - [Resolved(canBeNull: true)] private OsuGame game { get; set; } From ed66f86ac6073ee655025ddfbddb9726b6cba2a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 17:52:54 +0900 Subject: [PATCH 07/25] Update editor exit-without-safe tests to account for hold behaviour --- .../Editing/TestSceneEditorBeatmapCreation.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index ecd4035edd..b109234fec 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -13,6 +13,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Database; +using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Osu; @@ -23,6 +24,7 @@ using osu.Game.Screens.Edit.Setup; using osu.Game.Storyboards; using osu.Game.Tests.Resources; using osuTK; +using osuTK.Input; using SharpCompress.Archives; using SharpCompress.Archives.Zip; @@ -63,13 +65,19 @@ namespace osu.Game.Tests.Visual.Editing EditorBeatmap editorBeatmap = null; AddStep("store editor beatmap", () => editorBeatmap = EditorBeatmap); - AddStep("exit without save", () => + + AddStep("exit without save", () => Editor.Exit()); + AddStep("hold to confirm", () => { - Editor.Exit(); - DialogOverlay.CurrentDialog.PerformOkAction(); + var confirmButton = DialogOverlay.CurrentDialog.ChildrenOfType().First(); + + InputManager.MoveMouseTo(confirmButton); + InputManager.PressButton(MouseButton.Left); }); AddUntilStep("wait for exit", () => !Editor.IsCurrentScreen()); + AddStep("release", () => InputManager.ReleaseButton(MouseButton.Left)); + AddAssert("new beatmap not persisted", () => beatmapManager.QueryBeatmapSet(s => s.ID == editorBeatmap.BeatmapInfo.BeatmapSet.ID)?.Value.DeletePending == true); } From 058fbbbe6cc0b3422f50a495b7b09dc5049cff1d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 21 Mar 2022 14:06:36 +0300 Subject: [PATCH 08/25] Remove unused using directive --- osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index 4a7cce5a97..d126eff075 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; From 33acc5d720c94eb1754759adc2d3a6079ee9de88 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 21 Mar 2022 14:06:47 +0300 Subject: [PATCH 09/25] Remove no longer valid comments --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index f848c07680..819b0cbc6c 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -56,8 +56,6 @@ namespace osu.Game.Skinning.Editor protected override void PopIn() { - // base call intentionally omitted as we have custom behaviour. - if (skinEditor != null) { skinEditor.Show(); @@ -88,11 +86,7 @@ namespace osu.Game.Skinning.Editor }); } - protected override void PopOut() - { - // base call intentionally omitted. - skinEditor?.Hide(); - } + protected override void PopOut() => skinEditor?.Hide(); private void updateComponentVisibility() { From 9a2691c1bc0b8bf1578996a1cd0a56eb6b865f2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 23:54:47 +0900 Subject: [PATCH 10/25] Remove unnecessary schedule --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 819b0cbc6c..1a427d5f5d 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -63,26 +63,22 @@ namespace osu.Game.Skinning.Editor } var editor = new SkinEditor(); + editor.State.BindValueChanged(visibility => updateComponentVisibility()); skinEditor = editor; - // Schedule ensures that if `Show` is called before this overlay is loaded, - // it will not throw (LoadComponentAsync requires the load target to be in a loaded state). - Schedule(() => + if (editor != skinEditor) + return; + + LoadComponentAsync(editor, _ => { if (editor != skinEditor) return; - LoadComponentAsync(editor, _ => - { - if (editor != skinEditor) - return; + AddInternal(editor); - AddInternal(editor); - - SetTarget(lastTargetScreen); - }); + SetTarget(lastTargetScreen); }); } From 17b639b4045974c255e8525b8f6cdfb6ade74373 Mon Sep 17 00:00:00 2001 From: NAGILSON Date: Mon, 21 Mar 2022 22:42:17 -0400 Subject: [PATCH 11/25] Implement suggested change to wipe mods on multiplayer screen --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index bf1699dca0..c56d04d5ac 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -115,6 +115,8 @@ namespace osu.Game.Screens.OnlinePlay this.FadeIn(); waves.Show(); + Mods.SetDefault(); + if (loungeSubScreen.IsCurrentScreen()) loungeSubScreen.OnEntering(last); else From 74ce009ed8ce926041f4fa60ba0467783761bb59 Mon Sep 17 00:00:00 2001 From: NAGILSON Date: Mon, 21 Mar 2022 22:46:20 -0400 Subject: [PATCH 12/25] [WIP] Multiplayer Mods Regression Test --- .../Multiplayer/TestMultiplayerModLoading.cs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs new file mode 100644 index 0000000000..e9013af412 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs @@ -0,0 +1,52 @@ +// 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 NUnit.Framework; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens.Select; + +// Resolve these names to types because there is a Namespace called "Playlists" and "Multiplayer" which conflicts +using MultiplayerScreenAlias = osu.Game.Screens.OnlinePlay.Multiplayer.Multiplayer; +using PlaylistsScreenAlias = osu.Game.Screens.OnlinePlay.Playlists.Playlists; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestMultiplayerModLoading : OsuGameTestScene + { + + [SetUp] + public void SetUp() => Schedule(() => + { + SelectedMods.Value = Array.Empty(); + }); + + + /// + /// This is a regression test that tests whether a singleplayer mod can transfer over to a multiplayer screen. + /// It should not carry over from these screens, prevents regression on https://github.com/ppy/osu/pull/17352 + /// + [Test] + public void TestSingleplayerModsDontCarryToMultiplayerScreens() + { + PushAndConfirm(() => new PlaySongSelect()); + + // Select Mods while a "singleplayer" screen is active + var osuAutomationMod = new OsuModAutoplay(); + var expectedMods = new[] { osuAutomationMod }; + + AddStep("Toggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); + AddAssert("", () => SelectedMods.Value == expectedMods); + + PushAndConfirm(() => new TestMultiplayerComponents()); + AddAssert("Mods are Empty After A Multiplayer Screen Loads", () => SelectedMods.Value.Count == 0); + + AddStep("Retoggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); + AddAssert("", () => SelectedMods.Value == expectedMods); + + // TODO: Implement TestPlaylistComponents? + //PushAndConfirm(() => new TestPlaylistComponents()); + //AddAssert("Mods are Empty After Playlist Screen Loads", () => !SelectedMods.Value.Any()); + } + } +} From aaf2edace9d43e9cadfcfb874ef5d8a68be660f6 Mon Sep 17 00:00:00 2001 From: NAGILSON Date: Mon, 21 Mar 2022 22:48:08 -0400 Subject: [PATCH 13/25] remove code from old incorrect test --- .../Visual/Multiplayer/TestMultiplayerModLoading.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs index e9013af412..b5609a2841 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs @@ -6,10 +6,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Select; -// Resolve these names to types because there is a Namespace called "Playlists" and "Multiplayer" which conflicts -using MultiplayerScreenAlias = osu.Game.Screens.OnlinePlay.Multiplayer.Multiplayer; -using PlaylistsScreenAlias = osu.Game.Screens.OnlinePlay.Playlists.Playlists; - namespace osu.Game.Tests.Visual.Multiplayer { public class TestMultiplayerModLoading : OsuGameTestScene From 33d97f53cbb5184939e8fde48d40acc3155b8925 Mon Sep 17 00:00:00 2001 From: NAGILSON Date: Mon, 21 Mar 2022 22:58:53 -0400 Subject: [PATCH 14/25] Fill in assert details, remove whitespace --- .../Visual/Multiplayer/TestMultiplayerModLoading.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs index b5609a2841..7c2353513d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs @@ -10,14 +10,12 @@ namespace osu.Game.Tests.Visual.Multiplayer { public class TestMultiplayerModLoading : OsuGameTestScene { - [SetUp] public void SetUp() => Schedule(() => { SelectedMods.Value = Array.Empty(); }); - /// /// This is a regression test that tests whether a singleplayer mod can transfer over to a multiplayer screen. /// It should not carry over from these screens, prevents regression on https://github.com/ppy/osu/pull/17352 @@ -32,13 +30,13 @@ namespace osu.Game.Tests.Visual.Multiplayer var expectedMods = new[] { osuAutomationMod }; AddStep("Toggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); - AddAssert("", () => SelectedMods.Value == expectedMods); + AddAssert("Mods are loaded before the multiplayer screen is pushed.", () => SelectedMods.Value == expectedMods); PushAndConfirm(() => new TestMultiplayerComponents()); AddAssert("Mods are Empty After A Multiplayer Screen Loads", () => SelectedMods.Value.Count == 0); AddStep("Retoggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); - AddAssert("", () => SelectedMods.Value == expectedMods); + AddAssert("Mods are loaded before the playlist screen is pushed", () => SelectedMods.Value == expectedMods); // TODO: Implement TestPlaylistComponents? //PushAndConfirm(() => new TestPlaylistComponents()); From fb7f9a81db99bd547b64c26f331d1dca47c24c11 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Mar 2022 14:35:13 +0900 Subject: [PATCH 15/25] Remove unnecessary equality check in skin editor construction path --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 1a427d5f5d..497283a820 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -68,9 +68,6 @@ namespace osu.Game.Skinning.Editor skinEditor = editor; - if (editor != skinEditor) - return; - LoadComponentAsync(editor, _ => { if (editor != skinEditor) From f95bd8916693ea04a5afb17867cfcbc85709777f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Mar 2022 14:46:57 +0900 Subject: [PATCH 16/25] Revert editor exit behaviour to exit without changes for now --- osu.Game/Overlays/Dialog/PopupDialog.cs | 7 ++++++- osu.Game/Screens/Edit/Editor.cs | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 0f953f92bb..a70a7f26cc 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -219,7 +219,12 @@ namespace osu.Game.Overlays.Dialog /// /// Programmatically clicks the first . /// - public void PerformOkAction() => Buttons.OfType().First().TriggerClick(); + public void PerformOkAction() => PerformAction(); + + /// + /// Programmatically clicks the first button of the provided type. + /// + public void PerformAction() where T : PopupDialogButton => Buttons.OfType().First().TriggerClick(); protected override bool OnKeyDown(KeyDownEvent e) { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index dcb7e3a282..444b2fe6f9 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -28,6 +28,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Online.API; using osu.Game.Overlays; +using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; @@ -598,7 +599,7 @@ namespace osu.Game.Screens.Edit // if the dialog is already displayed, confirm exit with no save. if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) { - saveDialog.PerformOkAction(); + saveDialog.PerformAction(); return true; } From 61ddf1e6cf90a9fb9041afdc9335ac57205b6b83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Mar 2022 15:28:31 +0900 Subject: [PATCH 17/25] Disallow exiting the editor without saving (unless explicitly confirming) --- .../Visual/Editing/TestSceneEditorSaving.cs | 7 +++++++ osu.Game/Screens/Edit/Editor.cs | 13 +++++-------- osu.Game/Tests/Visual/EditorTestScene.cs | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index d1c1558003..e75c7f25a3 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -17,6 +17,13 @@ namespace osu.Game.Tests.Visual.Editing { public class TestSceneEditorSaving : EditorSavingTestScene { + [Test] + public void TestCantExitWithoutSaving() + { + AddRepeatStep("Exit", () => InputManager.Key(Key.Escape), 10); + AddAssert("Editor is still active screen", () => Game.ScreenStack.CurrentScreen is Editor); + } + [Test] public void TestMetadata() { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 444b2fe6f9..7254a9140f 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -98,7 +98,7 @@ namespace osu.Game.Screens.Edit private bool canSave; - private bool exitConfirmed; + protected bool ExitConfirmed { get; private set; } private string lastSavedHash; @@ -587,7 +587,7 @@ namespace osu.Game.Screens.Edit public override bool OnExiting(IScreen next) { - if (!exitConfirmed) + if (!ExitConfirmed) { // dialog overlay may not be available in visual tests. if (dialogOverlay == null) @@ -596,12 +596,9 @@ namespace osu.Game.Screens.Edit return true; } - // if the dialog is already displayed, confirm exit with no save. + // if the dialog is already displayed, block exiting until the user explicitly makes a decision. if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) - { - saveDialog.PerformAction(); return true; - } if (isNewBeatmap || HasUnsavedChanges) { @@ -646,7 +643,7 @@ namespace osu.Game.Screens.Edit { Save(); - exitConfirmed = true; + ExitConfirmed = true; this.Exit(); } @@ -669,7 +666,7 @@ namespace osu.Game.Screens.Edit Beatmap.SetDefault(); } - exitConfirmed = true; + ExitConfirmed = true; this.Exit(); } diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 24015590e2..efaf6f2253 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -7,10 +7,13 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.IO.Stores; using osu.Framework.Platform; +using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Online.API; +using osu.Game.Overlays; +using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; @@ -93,6 +96,9 @@ namespace osu.Game.Tests.Visual protected class TestEditor : Editor { + [Resolved(canBeNull: true)] + private DialogOverlay dialogOverlay { get; set; } + public new void Undo() => base.Undo(); public new void Redo() => base.Redo(); @@ -111,6 +117,18 @@ namespace osu.Game.Tests.Visual public new bool HasUnsavedChanges => base.HasUnsavedChanges; + public override bool OnExiting(IScreen next) + { + // For testing purposes allow the screen to exit without saving on second attempt. + if (!ExitConfirmed && dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) + { + saveDialog.PerformAction(); + return true; + } + + return base.OnExiting(next); + } + public TestEditor(EditorLoader loader = null) : base(loader) { From 804e8561607630f59380659e8cf3e85ce79eb88d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Mar 2022 17:38:43 +0900 Subject: [PATCH 18/25] Move and refactor test in line with functionality changes --- .../Multiplayer/TestMultiplayerModLoading.cs | 46 ------------------- .../Navigation/TestSceneScreenNavigation.cs | 14 ++++++ 2 files changed, 14 insertions(+), 46 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs deleted file mode 100644 index 7c2353513d..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs +++ /dev/null @@ -1,46 +0,0 @@ -// 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 NUnit.Framework; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestMultiplayerModLoading : OsuGameTestScene - { - [SetUp] - public void SetUp() => Schedule(() => - { - SelectedMods.Value = Array.Empty(); - }); - - /// - /// This is a regression test that tests whether a singleplayer mod can transfer over to a multiplayer screen. - /// It should not carry over from these screens, prevents regression on https://github.com/ppy/osu/pull/17352 - /// - [Test] - public void TestSingleplayerModsDontCarryToMultiplayerScreens() - { - PushAndConfirm(() => new PlaySongSelect()); - - // Select Mods while a "singleplayer" screen is active - var osuAutomationMod = new OsuModAutoplay(); - var expectedMods = new[] { osuAutomationMod }; - - AddStep("Toggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); - AddAssert("Mods are loaded before the multiplayer screen is pushed.", () => SelectedMods.Value == expectedMods); - - PushAndConfirm(() => new TestMultiplayerComponents()); - AddAssert("Mods are Empty After A Multiplayer Screen Loads", () => SelectedMods.Value.Count == 0); - - AddStep("Retoggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); - AddAssert("Mods are loaded before the playlist screen is pushed", () => SelectedMods.Value == expectedMods); - - // TODO: Implement TestPlaylistComponents? - //PushAndConfirm(() => new TestPlaylistComponents()); - //AddAssert("Mods are Empty After Playlist Screen Loads", () => !SelectedMods.Value.Any()); - } - } -} diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index f2e6aa1e16..7e1ff08678 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -262,6 +262,20 @@ namespace osu.Game.Tests.Visual.Navigation exitViaBackButtonAndConfirm(); } + [Test] + public void TestModsResetOnEnteringMultiplayer() + { + var osuAutomationMod = new OsuModAutoplay(); + + AddStep("Enable autoplay", () => { Game.SelectedMods.Value = new[] { osuAutomationMod }; }); + + PushAndConfirm(() => new Screens.OnlinePlay.Multiplayer.Multiplayer()); + AddUntilStep("Mods are removed", () => SelectedMods.Value.Count == 0); + + AddStep("Return to menu", () => Game.ScreenStack.CurrentScreen.Exit()); + AddUntilStep("Mods are restored", () => Game.SelectedMods.Value.Contains(osuAutomationMod)); + } + [Test] public void TestExitMultiWithEscape() { From 5631726164afcc70f323f570454c6ebe3e300b1c Mon Sep 17 00:00:00 2001 From: mcpower Date: Tue, 22 Mar 2022 20:30:54 +1100 Subject: [PATCH 19/25] Add C# extension to recommended VS Code extensions The [official C# extension] is maintained by Microsoft and enables IDE-like support for C# in VS Code. If a user opens this repository in VS Code, they will be prompted to install it if they haven't already installed it. After installation, the extension will also prompt the user to install the .NET SDK if it's not found. [official C# extension]: https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp --- .vscode/extensions.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .vscode/extensions.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..5b7a98f4ba --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "ms-dotnettools.csharp" + ] +} From 94c5207f36f162a9a52e5234f12660c5004afbc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 19:04:32 +0100 Subject: [PATCH 20/25] Fix test not actually testing desired scenario anymore The test was checking the test scene's own `SelectedMods` bindable rather than the multiplayer screen's, and the former was never actually being mutated by anything. Therefore the case would pass even on `master` with the fix reverted. --- .../Visual/Navigation/TestSceneScreenNavigation.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 7e1ff08678..034c1b7581 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -269,8 +269,9 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Enable autoplay", () => { Game.SelectedMods.Value = new[] { osuAutomationMod }; }); - PushAndConfirm(() => new Screens.OnlinePlay.Multiplayer.Multiplayer()); - AddUntilStep("Mods are removed", () => SelectedMods.Value.Count == 0); + Screens.OnlinePlay.Multiplayer.Multiplayer multiplayer = null; + PushAndConfirm(() => multiplayer = new Screens.OnlinePlay.Multiplayer.Multiplayer()); + AddUntilStep("Mods are removed", () => multiplayer.Mods.Value.Count == 0); AddStep("Return to menu", () => Game.ScreenStack.CurrentScreen.Exit()); AddUntilStep("Mods are restored", () => Game.SelectedMods.Value.Contains(osuAutomationMod)); From c8d48f89e8a7b7a30af2be41c4ef2590cc41b21e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 19:13:22 +0100 Subject: [PATCH 21/25] Remove unnecessary local --- .../Visual/Navigation/TestSceneScreenNavigation.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 034c1b7581..e4535b6cd6 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -269,9 +269,8 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Enable autoplay", () => { Game.SelectedMods.Value = new[] { osuAutomationMod }; }); - Screens.OnlinePlay.Multiplayer.Multiplayer multiplayer = null; - PushAndConfirm(() => multiplayer = new Screens.OnlinePlay.Multiplayer.Multiplayer()); - AddUntilStep("Mods are removed", () => multiplayer.Mods.Value.Count == 0); + PushAndConfirm(() => new Screens.OnlinePlay.Multiplayer.Multiplayer()); + AddUntilStep("Mods are removed", () => Game.SelectedMods.Value.Count == 0); AddStep("Return to menu", () => Game.ScreenStack.CurrentScreen.Exit()); AddUntilStep("Mods are restored", () => Game.SelectedMods.Value.Contains(osuAutomationMod)); From a38bafab912108a86bea2411350f4413da450af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 22:00:05 +0100 Subject: [PATCH 22/25] Remove unused using directive --- osu.Game/Screens/Edit/Editor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 7254a9140f..4d5e491c60 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -28,7 +28,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Online.API; using osu.Game.Overlays; -using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; From f3aad772399cb786147c3adb9b9d487beada0a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 22:00:24 +0100 Subject: [PATCH 23/25] Remove unused local variable --- osu.Game/Screens/Edit/Editor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 4d5e491c60..57f7429e06 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -596,7 +596,7 @@ namespace osu.Game.Screens.Edit } // if the dialog is already displayed, block exiting until the user explicitly makes a decision. - if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) + if (dialogOverlay.CurrentDialog is PromptForSaveDialog) return true; if (isNewBeatmap || HasUnsavedChanges) From 51a1721bc942b71b768faae474d1a2eaa52a1dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 22:10:05 +0100 Subject: [PATCH 24/25] Fix unprotected access to potentially-null DI'd dialog overlay --- osu.Game/Tests/Visual/EditorTestScene.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index efaf6f2253..51221cb8fe 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -97,6 +97,7 @@ namespace osu.Game.Tests.Visual protected class TestEditor : Editor { [Resolved(canBeNull: true)] + [CanBeNull] private DialogOverlay dialogOverlay { get; set; } public new void Undo() => base.Undo(); @@ -120,7 +121,7 @@ namespace osu.Game.Tests.Visual public override bool OnExiting(IScreen next) { // For testing purposes allow the screen to exit without saving on second attempt. - if (!ExitConfirmed && dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) + if (!ExitConfirmed && dialogOverlay?.CurrentDialog is PromptForSaveDialog saveDialog) { saveDialog.PerformAction(); return true; From 657daf07d745626681d4998eaa84193e8dad43e2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Mar 2022 11:03:24 +0900 Subject: [PATCH 25/25] Update LocalisationAnalyser to support .net6 --- .config/dotnet-tools.json | 2 +- osu.Game/osu.Game.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 985fc09df3..4177c402aa 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -27,7 +27,7 @@ ] }, "ppy.localisationanalyser.tools": { - "version": "2021.1210.0", + "version": "2022.320.0", "commands": [ "localisation" ] diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5e194e2aca..1c1deaae8e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -31,7 +31,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive