diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 83991ad027..d3b88e56ae 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -125,6 +125,8 @@ namespace osu.Game.Screens.Play private GameplayBeatmap gameplayBeatmap; + private ScreenSuspensionHandler screenSuspension; + private DependencyContainer dependencies; protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -179,6 +181,7 @@ namespace osu.Game.Screens.Play InternalChild = GameplayClockContainer = new GameplayClockContainer(Beatmap.Value, Mods.Value, DrawableRuleset.GameplayStartTime); AddInternal(gameplayBeatmap = new GameplayBeatmap(playableBeatmap)); + AddInternal(screenSuspension = new ScreenSuspensionHandler(GameplayClockContainer)); dependencies.CacheAs(gameplayBeatmap); @@ -628,12 +631,16 @@ namespace osu.Game.Screens.Play public override void OnSuspending(IScreen next) { + screenSuspension?.Expire(); + fadeOut(); base.OnSuspending(next); } public override bool OnExiting(IScreen next) { + screenSuspension?.Expire(); + if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed) { // proceed to result screen if beatmap already finished playing diff --git a/osu.Game/Screens/Play/ScreenSuspensionHandler.cs b/osu.Game/Screens/Play/ScreenSuspensionHandler.cs new file mode 100644 index 0000000000..8585a5c309 --- /dev/null +++ b/osu.Game/Screens/Play/ScreenSuspensionHandler.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 System.Diagnostics; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Platform; + +namespace osu.Game.Screens.Play +{ + /// + /// Ensures screen is not suspended / dimmed while gameplay is active. + /// + public class ScreenSuspensionHandler : Component + { + private readonly GameplayClockContainer gameplayClockContainer; + private Bindable isPaused; + + [Resolved] + private GameHost host { get; set; } + + public ScreenSuspensionHandler([NotNull] GameplayClockContainer gameplayClockContainer) + { + this.gameplayClockContainer = gameplayClockContainer ?? throw new ArgumentNullException(nameof(gameplayClockContainer)); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // This is the only usage game-wide of suspension changes. + // Assert to ensure we don't accidentally forget this in the future. + Debug.Assert(host.AllowScreenSuspension.Value); + + isPaused = gameplayClockContainer.IsPaused.GetBoundCopy(); + isPaused.BindValueChanged(paused => host.AllowScreenSuspension.Value = paused.NewValue, true); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + isPaused?.UnbindAll(); + + if (host != null) + host.AllowScreenSuspension.Value = true; + } + } +}