From 730e66f0ee00aec2b6c9f2a2f03ca56ec152a136 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 5 Feb 2021 09:07:59 +0300 Subject: [PATCH 1/8] Make pausing on window focus lose instant --- .../Screens/Play/HUD/HoldForMenuButton.cs | 40 ------------------- osu.Game/Screens/Play/Player.cs | 21 +++++++--- 2 files changed, 16 insertions(+), 45 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 387c0e587b..284ac899ed 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -88,11 +88,6 @@ namespace osu.Game.Screens.Play.HUD return base.OnMouseMove(e); } - public bool PauseOnFocusLost - { - set => button.PauseOnFocusLost = value; - } - protected override void Update() { base.Update(); @@ -120,8 +115,6 @@ namespace osu.Game.Screens.Play.HUD public Action HoverGained; public Action HoverLost; - private readonly IBindable gameActive = new Bindable(true); - [BackgroundDependencyLoader] private void load(OsuColour colours, Framework.Game game) { @@ -164,14 +157,6 @@ namespace osu.Game.Screens.Play.HUD }; bind(); - - gameActive.BindTo(game.IsActive); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - gameActive.BindValueChanged(_ => updateActive(), true); } private void bind() @@ -221,31 +206,6 @@ namespace osu.Game.Screens.Play.HUD base.OnHoverLost(e); } - private bool pauseOnFocusLost = true; - - public bool PauseOnFocusLost - { - set - { - if (pauseOnFocusLost == value) - return; - - pauseOnFocusLost = value; - if (IsLoaded) - updateActive(); - } - } - - private void updateActive() - { - if (!pauseOnFocusLost || IsPaused.Value) return; - - if (gameActive.Value) - AbortConfirm(); - else - BeginConfirm(); - } - public bool OnPressed(GlobalAction action) { switch (action) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index b622f11775..556964bca4 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -59,6 +59,8 @@ namespace osu.Game.Screens.Play // We are managing our own adjustments (see OnEntering/OnExiting). public override bool AllowRateAdjustments => false; + private readonly IBindable gameActive = new Bindable(true); + private readonly Bindable samplePlaybackDisabled = new Bindable(); /// @@ -154,6 +156,9 @@ namespace osu.Game.Screens.Play // replays should never be recorded or played back when autoplay is enabled if (!Mods.Value.Any(m => m is ModAutoplay)) PrepareReplay(); + + // needs to be bound here as the last binding, otherwise starting a replay while not focused causes player to exit. + gameActive.BindValueChanged(_ => updatePauseOnFocusLostState(), true); } [CanBeNull] @@ -170,7 +175,7 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, OsuConfigManager config, OsuGame game) + private void load(AudioManager audio, OsuConfigManager config, OsuGame game, OsuGameBase gameBase) { Mods.Value = base.Mods.Value.Select(m => m.CreateCopy()).ToArray(); @@ -186,6 +191,8 @@ namespace osu.Game.Screens.Play mouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); + gameActive.BindTo(gameBase.IsActive); + if (game != null) LocalUserPlaying.BindTo(game.LocalUserPlaying); @@ -420,10 +427,14 @@ namespace osu.Game.Screens.Play samplePlaybackDisabled.Value = DrawableRuleset.FrameStableClock.IsCatchingUp.Value || GameplayClockContainer.GameplayClock.IsPaused.Value; } - private void updatePauseOnFocusLostState() => - HUDOverlay.HoldToQuit.PauseOnFocusLost = PauseOnFocusLost - && !DrawableRuleset.HasReplayLoaded.Value - && !breakTracker.IsBreakTime.Value; + private void updatePauseOnFocusLostState() + { + if (!IsLoaded || !PauseOnFocusLost || DrawableRuleset.HasReplayLoaded.Value || breakTracker.IsBreakTime.Value) + return; + + if (gameActive.Value == false) + performUserRequestedExit(); + } private IBeatmap loadPlayableBeatmap() { From e1789c29b1a1e01f235b8e6bb9bdcfd131e5d715 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 5 Feb 2021 10:28:13 +0300 Subject: [PATCH 2/8] Use `Pause()` instead of `performUserRequestedExit()` to avoid unexpected operations --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 556964bca4..542839f11d 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -433,7 +433,7 @@ namespace osu.Game.Screens.Play return; if (gameActive.Value == false) - performUserRequestedExit(); + Pause(); } private IBeatmap loadPlayableBeatmap() From 8d18c7e9299cc9c8e4a8b55563c3a9a22d1a99bd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 5 Feb 2021 10:28:33 +0300 Subject: [PATCH 3/8] Fix `BreakTracker.IsBreakTime` not updated properly on breaks set Causes a pause from focus lose when playing a beatmap that has a break section at the beginning, due to `IsBreakTime` incorrectly set to `false` --- osu.Game/Screens/Play/BreakTracker.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/BreakTracker.cs b/osu.Game/Screens/Play/BreakTracker.cs index 51e21656e1..793b6b0ebe 100644 --- a/osu.Game/Screens/Play/BreakTracker.cs +++ b/osu.Game/Screens/Play/BreakTracker.cs @@ -23,16 +23,16 @@ namespace osu.Game.Screens.Play /// public IBindable IsBreakTime => isBreakTime; - private readonly BindableBool isBreakTime = new BindableBool(); + private readonly BindableBool isBreakTime = new BindableBool(true); public IReadOnlyList Breaks { set { - isBreakTime.Value = false; - breaks = new PeriodTracker(value.Where(b => b.HasEffect) .Select(b => new Period(b.StartTime, b.EndTime - BreakOverlay.BREAK_FADE_DURATION))); + + updateBreakTime(); } } @@ -45,8 +45,12 @@ namespace osu.Game.Screens.Play protected override void Update() { base.Update(); + updateBreakTime(); + } - var time = Clock.CurrentTime; + private void updateBreakTime() + { + var time = Clock?.CurrentTime ?? 0; isBreakTime.Value = breaks?.IsInAny(time) == true || time < gameplayStartTime From f29938e15d62bad02c0ff8d0f586bc2764f423a9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 5 Feb 2021 20:39:57 +0300 Subject: [PATCH 4/8] Make last binding game activity more sensible --- osu.Game/Screens/Play/Player.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 542839f11d..f38eba3f27 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -80,6 +80,9 @@ namespace osu.Game.Screens.Play public int RestartCount; + [Resolved] + private OsuGameBase gameBase { get; set; } + [Resolved] private ScoreManager scoreManager { get; set; } @@ -157,7 +160,8 @@ namespace osu.Game.Screens.Play if (!Mods.Value.Any(m => m is ModAutoplay)) PrepareReplay(); - // needs to be bound here as the last binding, otherwise starting a replay while not focused causes player to exit. + // needs to be bound here as the last binding, otherwise cases like starting a replay while not focused causes player to exit, if activity is bound before checks. + gameActive.BindTo(gameBase.IsActive); gameActive.BindValueChanged(_ => updatePauseOnFocusLostState(), true); } @@ -191,8 +195,6 @@ namespace osu.Game.Screens.Play mouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); - gameActive.BindTo(gameBase.IsActive); - if (game != null) LocalUserPlaying.BindTo(game.LocalUserPlaying); @@ -429,7 +431,7 @@ namespace osu.Game.Screens.Play private void updatePauseOnFocusLostState() { - if (!IsLoaded || !PauseOnFocusLost || DrawableRuleset.HasReplayLoaded.Value || breakTracker.IsBreakTime.Value) + if (!PauseOnFocusLost || DrawableRuleset.HasReplayLoaded.Value || breakTracker.IsBreakTime.Value) return; if (gameActive.Value == false) From c9db0bf88651affc9bdd3a165984ad7577770149 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 6 Feb 2021 20:54:13 +0300 Subject: [PATCH 5/8] Call break time update when loaded --- osu.Game/Screens/Play/BreakTracker.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/BreakTracker.cs b/osu.Game/Screens/Play/BreakTracker.cs index 793b6b0ebe..2f3673e91f 100644 --- a/osu.Game/Screens/Play/BreakTracker.cs +++ b/osu.Game/Screens/Play/BreakTracker.cs @@ -32,7 +32,8 @@ namespace osu.Game.Screens.Play breaks = new PeriodTracker(value.Where(b => b.HasEffect) .Select(b => new Period(b.StartTime, b.EndTime - BreakOverlay.BREAK_FADE_DURATION))); - updateBreakTime(); + if (IsLoaded) + updateBreakTime(); } } @@ -50,7 +51,7 @@ namespace osu.Game.Screens.Play private void updateBreakTime() { - var time = Clock?.CurrentTime ?? 0; + var time = Clock.CurrentTime; isBreakTime.Value = breaks?.IsInAny(time) == true || time < gameplayStartTime From 40ddccf0c73904af580d3023b3d79d45a14868f3 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 6 Feb 2021 20:55:55 +0300 Subject: [PATCH 6/8] Do not consider replays for "pause on focus lost" Replays are not pausable as can be seen in the `canPause` check. --- osu.Game/Screens/Play/Player.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index f38eba3f27..81401b08e8 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -160,7 +160,6 @@ namespace osu.Game.Screens.Play if (!Mods.Value.Any(m => m is ModAutoplay)) PrepareReplay(); - // needs to be bound here as the last binding, otherwise cases like starting a replay while not focused causes player to exit, if activity is bound before checks. gameActive.BindTo(gameBase.IsActive); gameActive.BindValueChanged(_ => updatePauseOnFocusLostState(), true); } @@ -267,8 +266,6 @@ namespace osu.Game.Screens.Play DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updateGameplayState()); - DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updatePauseOnFocusLostState(), true); - // bind clock into components that require it DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused); @@ -431,7 +428,7 @@ namespace osu.Game.Screens.Play private void updatePauseOnFocusLostState() { - if (!PauseOnFocusLost || DrawableRuleset.HasReplayLoaded.Value || breakTracker.IsBreakTime.Value) + if (!PauseOnFocusLost || breakTracker.IsBreakTime.Value) return; if (gameActive.Value == false) From d0ca2b99a850f9903eec2f7ac1956e15a73089a2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 6 Feb 2021 20:57:01 +0300 Subject: [PATCH 7/8] Remove unnecessary injected dependency --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 81401b08e8..bd67d3f06a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -178,7 +178,7 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, OsuConfigManager config, OsuGame game, OsuGameBase gameBase) + private void load(AudioManager audio, OsuConfigManager config, OsuGame game) { Mods.Value = base.Mods.Value.Select(m => m.CreateCopy()).ToArray(); From 9e0724b138fd4c251dc61e5daa3e702dd2a77cee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Feb 2021 15:58:41 +0900 Subject: [PATCH 8/8] Remove unnecessary double resolution of OsuGame --- osu.Game/Screens/Play/Player.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index bd67d3f06a..669fa93298 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -80,9 +80,6 @@ namespace osu.Game.Screens.Play public int RestartCount; - [Resolved] - private OsuGameBase gameBase { get; set; } - [Resolved] private ScoreManager scoreManager { get; set; } @@ -160,7 +157,6 @@ namespace osu.Game.Screens.Play if (!Mods.Value.Any(m => m is ModAutoplay)) PrepareReplay(); - gameActive.BindTo(gameBase.IsActive); gameActive.BindValueChanged(_ => updatePauseOnFocusLostState(), true); } @@ -195,7 +191,10 @@ namespace osu.Game.Screens.Play mouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); if (game != null) + { LocalUserPlaying.BindTo(game.LocalUserPlaying); + gameActive.BindTo(game.IsActive); + } DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, Mods.Value);