From 2896612c5cd09cc4c6436f2f307d60218b13b8f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 May 2022 16:06:04 +0900 Subject: [PATCH 1/9] Make exiting multiplayer a dangerous operation, requiring hold --- .../Containers/HoldToConfirmContainer.cs | 8 ++++-- .../Dialog/PopupDialogDangerousButton.cs | 4 ++- .../Screens/Play/HUD/HoldForMenuButton.cs | 27 ++++++++++++++----- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index 1b802a0a14..c74245461d 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -40,9 +40,13 @@ namespace osu.Game.Graphics.Containers private Bindable holdActivationDelay; - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + [Resolved] + private OsuConfigManager config { get; set; } + + protected override void LoadComplete() { + base.LoadComplete(); + holdActivationDelay = HoldActivationDelay != null ? new Bindable(HoldActivationDelay.Value) : config.GetBindable(OsuSetting.UIHoldActivationDelay); diff --git a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs index adc627e15b..6c775f44f8 100644 --- a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs +++ b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs @@ -12,6 +12,8 @@ namespace osu.Game.Overlays.Dialog { public class PopupDialogDangerousButton : PopupDialogButton { + public const double DANGEROUS_HOLD_ACTIVATION_DELAY = 500; + private Box progressBox; private DangerousConfirmContainer confirmContainer; @@ -42,7 +44,7 @@ namespace osu.Game.Overlays.Dialog private class DangerousConfirmContainer : HoldToConfirmContainer { - protected override double? HoldActivationDelay => 500; + protected override double? HoldActivationDelay => DANGEROUS_HOLD_ACTIVATION_DELAY; protected override bool OnMouseDown(MouseDownEvent e) { diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 3da63ec2cc..c6aa3fbe08 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -18,6 +18,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; +using osu.Game.Overlays.Dialog; using osuTK; namespace osu.Game.Screens.Play.HUD @@ -37,6 +38,14 @@ namespace osu.Game.Screens.Play.HUD private readonly OsuSpriteText text; + [Resolved] + private OsuConfigManager config { get; set; } + + [Resolved(canBeNull: true)] + private Player player { get; set; } + + private readonly Bindable activationDelay = new Bindable(); + public HoldForMenuButton() { Direction = FillDirection.Horizontal; @@ -60,14 +69,15 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both; } - [Resolved] - private OsuConfigManager config { get; set; } - - private Bindable activationDelay; - protected override void LoadComplete() { - activationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); + if (player?.Configuration.AllowRestart == false) + { + activationDelay.Value = PopupDialogDangerousButton.DANGEROUS_HOLD_ACTIVATION_DELAY; + } + else + config.BindWith(OsuSetting.UIHoldActivationDelay, activationDelay); + activationDelay.BindValueChanged(v => { text.Text = v.NewValue > 0 @@ -115,6 +125,11 @@ namespace osu.Game.Screens.Play.HUD public Action HoverGained; public Action HoverLost; + [Resolved(canBeNull: true)] + private Player player { get; set; } + + protected override double? HoldActivationDelay => player?.Configuration.AllowRestart == false ? PopupDialogDangerousButton.DANGEROUS_HOLD_ACTIVATION_DELAY : (double?)null; + [BackgroundDependencyLoader] private void load(OsuColour colours) { From be960eb092aacf2f8651d5099b1eb2d1eb09a8a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 May 2022 14:34:31 +0900 Subject: [PATCH 2/9] Move dangerous hold specification to base class --- .../Containers/HoldToConfirmContainer.cs | 32 ++++++++++---- .../Dialog/PopupDialogDangerousButton.cs | 7 ++-- .../Screens/Play/HUD/HoldForMenuButton.cs | 42 +++++++------------ 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index c74245461d..078721ec77 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -12,6 +12,13 @@ namespace osu.Game.Graphics.Containers { public abstract class HoldToConfirmContainer : Container { + public const double DANGEROUS_HOLD_ACTIVATION_DELAY = 500; + + /// + /// Whether the associated action is considered dangerous, warranting a longer hold. + /// + public bool IsDangerousAction { get; } + public Action Action; private const int fadeout_delay = 200; @@ -29,12 +36,9 @@ namespace osu.Game.Graphics.Containers protected virtual bool AllowMultipleFires => false; /// - /// Specify a custom activation delay, overriding the game-wide user setting. + /// The current activation delay for this control. /// - /// - /// 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; + protected IBindable HoldActivationDelay => holdActivationDelay; public Bindable Progress = new BindableDouble(); @@ -43,13 +47,25 @@ namespace osu.Game.Graphics.Containers [Resolved] private OsuConfigManager config { get; set; } + protected HoldToConfirmContainer(bool isDangerousAction = false) + { + IsDangerousAction = isDangerousAction; + } + protected override void LoadComplete() { base.LoadComplete(); - holdActivationDelay = HoldActivationDelay != null - ? new Bindable(HoldActivationDelay.Value) - : config.GetBindable(OsuSetting.UIHoldActivationDelay); + if (IsDangerousAction) + { + holdActivationDelay.Value = DANGEROUS_HOLD_ACTIVATION_DELAY; + } + else + { + holdActivationDelay = HoldActivationDelay != null + ? new Bindable(HoldActivationDelay.Value) + : config.GetBindable(OsuSetting.UIHoldActivationDelay); + } } protected void BeginConfirm() diff --git a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs index 6c775f44f8..6239c5e409 100644 --- a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs +++ b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs @@ -12,8 +12,6 @@ namespace osu.Game.Overlays.Dialog { public class PopupDialogDangerousButton : PopupDialogButton { - public const double DANGEROUS_HOLD_ACTIVATION_DELAY = 500; - private Box progressBox; private DangerousConfirmContainer confirmContainer; @@ -44,7 +42,10 @@ namespace osu.Game.Overlays.Dialog private class DangerousConfirmContainer : HoldToConfirmContainer { - protected override double? HoldActivationDelay => DANGEROUS_HOLD_ACTIVATION_DELAY; + public DangerousConfirmContainer() + : base(isDangerousAction: true) + { + } protected override bool OnMouseDown(MouseDownEvent e) { diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index c6aa3fbe08..9d280a1737 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -13,12 +13,10 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Utils; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; -using osu.Game.Overlays.Dialog; using osuTK; namespace osu.Game.Screens.Play.HUD @@ -29,20 +27,11 @@ namespace osu.Game.Screens.Play.HUD public readonly Bindable IsPaused = new Bindable(); - private readonly Button button; + private Button button; - public Action Action - { - set => button.Action = value; - } + public Action Action { get; set; } - private readonly OsuSpriteText text; - - [Resolved] - private OsuConfigManager config { get; set; } - - [Resolved(canBeNull: true)] - private Player player { get; set; } + private OsuSpriteText text; private readonly Bindable activationDelay = new Bindable(); @@ -51,6 +40,11 @@ namespace osu.Game.Screens.Play.HUD Direction = FillDirection.Horizontal; Spacing = new Vector2(20, 0); Margin = new MarginPadding(10); + } + + [BackgroundDependencyLoader(true)] + private void load(Player player) + { Children = new Drawable[] { text = new OsuSpriteText @@ -59,11 +53,12 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft }, - button = new Button + button = new Button(player?.Configuration.AllowRestart == false) { HoverGained = () => text.FadeIn(500, Easing.OutQuint), HoverLost = () => text.FadeOut(500, Easing.OutQuint), - IsPaused = { BindTarget = IsPaused } + IsPaused = { BindTarget = IsPaused }, + Action = () => Action(), } }; AutoSizeAxes = Axes.Both; @@ -71,13 +66,6 @@ namespace osu.Game.Screens.Play.HUD protected override void LoadComplete() { - if (player?.Configuration.AllowRestart == false) - { - activationDelay.Value = PopupDialogDangerousButton.DANGEROUS_HOLD_ACTIVATION_DELAY; - } - else - config.BindWith(OsuSetting.UIHoldActivationDelay, activationDelay); - activationDelay.BindValueChanged(v => { text.Text = v.NewValue > 0 @@ -125,10 +113,10 @@ namespace osu.Game.Screens.Play.HUD public Action HoverGained; public Action HoverLost; - [Resolved(canBeNull: true)] - private Player player { get; set; } - - protected override double? HoldActivationDelay => player?.Configuration.AllowRestart == false ? PopupDialogDangerousButton.DANGEROUS_HOLD_ACTIVATION_DELAY : (double?)null; + public Button(bool isDangerousAction) + : base(isDangerousAction) + { + } [BackgroundDependencyLoader] private void load(OsuColour colours) From a11771c11b82992c2b5dfdda3acfcc09c59121e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 May 2022 14:37:50 +0900 Subject: [PATCH 3/9] Better encapsulate exposed bindables of `HoldToConfirmContainer` --- .../Containers/HoldToConfirmContainer.cs | 40 ++++++++++--------- .../Screens/Play/HUD/HoldForMenuButton.cs | 2 +- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index 078721ec77..540f9b97a7 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -14,15 +14,18 @@ namespace osu.Game.Graphics.Containers { public const double DANGEROUS_HOLD_ACTIVATION_DELAY = 500; + private const int fadeout_delay = 200; + /// /// Whether the associated action is considered dangerous, warranting a longer hold. /// public bool IsDangerousAction { get; } + /// + /// The action to perform when a hold successfully completes. + /// public Action Action; - private const int fadeout_delay = 200; - /// /// Whether currently in a fired state (and the confirm has been sent). /// @@ -30,19 +33,24 @@ namespace osu.Game.Graphics.Containers private bool confirming; + /// + /// The current activation delay for this control. + /// + public IBindable HoldActivationDelay => holdActivationDelay; + + /// + /// The progress of any ongoing hold operation. 0 means no hold has started; 1 means a hold has been completed. + /// + public IBindable Progress => progress; + /// /// Whether the overlay should be allowed to return from a fired state. /// protected virtual bool AllowMultipleFires => false; - /// - /// The current activation delay for this control. - /// - protected IBindable HoldActivationDelay => holdActivationDelay; + private readonly Bindable progress = new BindableDouble(); - public Bindable Progress = new BindableDouble(); - - private Bindable holdActivationDelay; + private readonly Bindable holdActivationDelay = new Bindable(); [Resolved] private OsuConfigManager config { get; set; } @@ -57,15 +65,9 @@ namespace osu.Game.Graphics.Containers base.LoadComplete(); if (IsDangerousAction) - { holdActivationDelay.Value = DANGEROUS_HOLD_ACTIVATION_DELAY; - } else - { - holdActivationDelay = HoldActivationDelay != null - ? new Bindable(HoldActivationDelay.Value) - : config.GetBindable(OsuSetting.UIHoldActivationDelay); - } + config.BindWith(OsuSetting.UIHoldActivationDelay, holdActivationDelay); } protected void BeginConfirm() @@ -74,7 +76,7 @@ namespace osu.Game.Graphics.Containers confirming = true; - this.TransformBindableTo(Progress, 1, holdActivationDelay.Value * (1 - Progress.Value), Easing.Out).OnComplete(_ => Confirm()); + this.TransformBindableTo(progress, 1, holdActivationDelay.Value * (1 - progress.Value), Easing.Out).OnComplete(_ => Confirm()); } protected virtual void Confirm() @@ -91,9 +93,9 @@ namespace osu.Game.Graphics.Containers Fired = false; this - .TransformBindableTo(Progress, Progress.Value) + .TransformBindableTo(progress, progress.Value) .Delay(200) - .TransformBindableTo(Progress, 0, fadeout_delay, Easing.InSine); + .TransformBindableTo(progress, 0, fadeout_delay, Easing.InSine); } } } diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 9d280a1737..678c4256b4 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -164,7 +164,7 @@ namespace osu.Game.Screens.Play.HUD private void bind() { - circularProgress.Current.BindTo(Progress); + ((IBindable)circularProgress.Current).BindTo(Progress); Progress.ValueChanged += progress => icon.Scale = new Vector2(1 + (float)progress.NewValue * 0.2f); } From c38e97c9ecb390496c576ab815911a87d17c1a04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 May 2022 14:43:24 +0900 Subject: [PATCH 4/9] Add full xmldoc to `HoldToConfirmContainer` --- .../Containers/HoldToConfirmContainer.cs | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index 540f9b97a7..28afd082c3 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -10,6 +10,16 @@ using osu.Game.Configuration; namespace osu.Game.Graphics.Containers { + /// + /// A container which adds a common "hold-to-perform" pattern to a container. + /// + /// + /// This container does not handle triggering the hold/abort operations. + /// To use this class, please call and when necessary. + /// + /// The is exposed as a transforming bindable which smoothly tracks the progress of a hold operation. + /// It can be used for animating and displaying progress directly. + /// public abstract class HoldToConfirmContainer : Container { public const double DANGEROUS_HOLD_ACTIVATION_DELAY = 500; @@ -70,6 +80,12 @@ namespace osu.Game.Graphics.Containers config.BindWith(OsuSetting.UIHoldActivationDelay, holdActivationDelay); } + /// + /// Begin a new confirmation. Should be called when the container is interacted with (ie. the user presses a key). + /// + /// + /// Calling this method when already in the process of confirming has no effect. + /// protected void BeginConfirm() { if (confirming || (!AllowMultipleFires && Fired)) return; @@ -79,12 +95,9 @@ namespace osu.Game.Graphics.Containers this.TransformBindableTo(progress, 1, holdActivationDelay.Value * (1 - progress.Value), Easing.Out).OnComplete(_ => Confirm()); } - protected virtual void Confirm() - { - Action?.Invoke(); - Fired = true; - } - + /// + /// Abort any ongoing confirmation. Should be called when the container's interaction is no longer valid (ie. the user releases a key). + /// protected void AbortConfirm() { if (!AllowMultipleFires && Fired) return; @@ -97,5 +110,15 @@ namespace osu.Game.Graphics.Containers .Delay(200) .TransformBindableTo(progress, 0, fadeout_delay, Easing.InSine); } + + /// + /// A method which is invoked when the confirmation sequence completes successfully. + /// By default, will fire the associated . + /// + protected virtual void Confirm() + { + Action?.Invoke(); + Fired = true; + } } } From 1c4aa125859d2de65858661b38bc207706a65625 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 May 2022 14:44:10 +0900 Subject: [PATCH 5/9] Rename non-descript `Button` nested class --- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 678c4256b4..e3283062ef 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play.HUD public readonly Bindable IsPaused = new Bindable(); - private Button button; + private HoldButton button; public Action Action { get; set; } @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft }, - button = new Button(player?.Configuration.AllowRestart == false) + button = new HoldButton(player?.Configuration.AllowRestart == false) { HoverGained = () => text.FadeIn(500, Easing.OutQuint), HoverLost = () => text.FadeOut(500, Easing.OutQuint), @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Play.HUD } } - private class Button : HoldToConfirmContainer, IKeyBindingHandler + private class HoldButton : HoldToConfirmContainer, IKeyBindingHandler { private SpriteIcon icon; private CircularProgress circularProgress; @@ -113,7 +113,7 @@ namespace osu.Game.Screens.Play.HUD public Action HoverGained; public Action HoverLost; - public Button(bool isDangerousAction) + public HoldButton(bool isDangerousAction) : base(isDangerousAction) { } From 78959a6e05a4cf753dfc59d480b2fdf041296c33 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 May 2022 15:01:24 +0900 Subject: [PATCH 6/9] Add animation to denote a dangerous player exit --- .../Screens/Play/HUD/HoldForMenuButton.cs | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index e3283062ef..f892ea1049 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -12,12 +12,14 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { @@ -113,6 +115,11 @@ namespace osu.Game.Screens.Play.HUD public Action HoverGained; public Action HoverLost; + private const double shake_duration = 20; + + private bool pendingAnimation; + private ScheduledDelegate shakeOperation; + public HoldButton(bool isDangerousAction) : base(isDangerousAction) { @@ -165,10 +172,38 @@ namespace osu.Game.Screens.Play.HUD private void bind() { ((IBindable)circularProgress.Current).BindTo(Progress); - Progress.ValueChanged += progress => icon.Scale = new Vector2(1 + (float)progress.NewValue * 0.2f); + Progress.ValueChanged += progress => + { + icon.Scale = new Vector2(1 + (float)progress.NewValue * 0.2f); + + if (IsDangerousAction) + { + //Child.Scale = new Vector2(1 + (float)progress.NewValue); + Colour = Interpolation.ValueAt(progress.NewValue, Color4.White, Color4.Red, 0, 1, Easing.OutQuint); + + if (progress.NewValue > 0 && progress.NewValue < 1) + { + shakeOperation ??= Scheduler.AddDelayed(shake, shake_duration, true); + } + else + { + Child.MoveTo(Vector2.Zero, shake_duration * 2, Easing.OutQuint); + shakeOperation?.Cancel(); + shakeOperation = null; + } + } + }; } - private bool pendingAnimation; + private void shake() + { + const float shake_magnitude = 8; + + Child.MoveTo(new Vector2( + RNG.NextSingle(-1, 1) * (float)Progress.Value * shake_magnitude, + RNG.NextSingle(-1, 1) * (float)Progress.Value * shake_magnitude + ), shake_duration); + } protected override void Confirm() { From 060461a431a3fe99a46786b652cba234933fbc85 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 May 2022 15:22:22 +0900 Subject: [PATCH 7/9] Add test coverage of multiplayer gameplay exit flow --- .../Multiplayer/TestSceneMultiplayer.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 6a69917fb4..8e45d99eae 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -7,6 +7,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Containers; @@ -17,6 +18,7 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; @@ -56,6 +58,9 @@ namespace osu.Game.Tests.Visual.Multiplayer private TestMultiplayerClient multiplayerClient => multiplayerComponents.MultiplayerClient; private TestMultiplayerRoomManager roomManager => multiplayerComponents.RoomManager; + [Resolved] + private OsuConfigManager config { get; set; } + [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { @@ -668,6 +673,43 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for results", () => multiplayerComponents.CurrentScreen is ResultsScreen); } + [Test] + public void TestGameplayExitFlow() + { + Bindable holdDelay = null; + + AddStep("Set hold delay to zero", () => + { + holdDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); + holdDelay.Value = 0; + }); + + createRoom(() => new Room + { + Name = { Value = "Test Room" }, + Playlist = + { + new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo) + { + RulesetID = new OsuRuleset().RulesetInfo.OnlineID, + } + } + }); + + enterGameplay(); + + AddUntilStep("wait for playing", () => this.ChildrenOfType().FirstOrDefault()?.LocalUserPlaying.Value == true); + + AddStep("attempt exit without hold", () => InputManager.Key(Key.Escape)); + AddAssert("still in gameplay", () => multiplayerComponents.CurrentScreen is Player); + + AddStep("attempt exit with hold", () => InputManager.PressKey(Key.Escape)); + AddUntilStep("wait for lounge", () => multiplayerComponents.CurrentScreen is Screens.OnlinePlay.Multiplayer.Multiplayer); + + AddStep("stop holding", () => InputManager.ReleaseKey(Key.Escape)); + AddStep("set hold delay to default", () => holdDelay.SetDefault()); + } + [Test] public void TestGameplayDoesntStartWithNonLoadedUser() { From f39fcee41bae044337bca75e5619f88772b50a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 May 2022 10:04:00 +0200 Subject: [PATCH 8/9] Remove commented-out code --- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index f892ea1049..8ed7260aac 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -178,7 +178,6 @@ namespace osu.Game.Screens.Play.HUD if (IsDangerousAction) { - //Child.Scale = new Vector2(1 + (float)progress.NewValue); Colour = Interpolation.ValueAt(progress.NewValue, Color4.White, Color4.Red, 0, 1, Easing.OutQuint); if (progress.NewValue > 0 && progress.NewValue < 1) From f5026bbbeb579dfe72325fbbab92647ceafcafd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 May 2022 10:04:36 +0200 Subject: [PATCH 9/9] Bind to button's activation delay directly --- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 8ed7260aac..2ba76d0896 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -35,8 +35,6 @@ namespace osu.Game.Screens.Play.HUD private OsuSpriteText text; - private readonly Bindable activationDelay = new Bindable(); - public HoldForMenuButton() { Direction = FillDirection.Horizontal; @@ -68,7 +66,7 @@ namespace osu.Game.Screens.Play.HUD protected override void LoadComplete() { - activationDelay.BindValueChanged(v => + button.HoldActivationDelay.BindValueChanged(v => { text.Text = v.NewValue > 0 ? "hold for menu"