diff --git a/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs b/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs new file mode 100644 index 0000000000..d850c58f09 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs @@ -0,0 +1,414 @@ +// 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 System.Linq; +using System.Threading; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Framework.Input.States; +using osu.Framework.Platform; +using osu.Framework.Screens; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Database; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Scoring; +using osu.Game.Screens; +using osu.Game.Screens.Backgrounds; +using osu.Game.Screens.Play; +using osu.Game.Screens.Play.PlayerSettings; +using osu.Game.Screens.Select; +using osu.Game.Tests.Resources; +using osu.Game.Users; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + [TestFixture] + public class TestCaseBackgroundScreenBeatmap : ManualInputManagerTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ScreenWithBeatmapBackground), + typeof(PlayerLoader), + typeof(Player), + typeof(UserDimContainer), + typeof(OsuScreen) + }; + + private DummySongSelect songSelect; + private DimAccessiblePlayerLoader playerLoader; + private DimAccessiblePlayer player; + private DatabaseContextFactory factory; + private BeatmapManager manager; + private RulesetStore rulesets; + + private ScreenStackCacheContainer screenStackContainer; + + [BackgroundDependencyLoader] + private void load(GameHost host) + { + factory = new DatabaseContextFactory(LocalStorage); + factory.ResetDatabase(); + + using (var usage = factory.Get()) + usage.Migrate(); + + factory.ResetDatabase(); + + using (var usage = factory.Get()) + usage.Migrate(); + + Dependencies.Cache(rulesets = new RulesetStore(factory)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null, host, Beatmap.Default)); + Dependencies.Cache(new OsuConfigManager(LocalStorage)); + + Beatmap.SetDefault(); + } + + [SetUp] + public virtual void SetUp() + { + Schedule(() => + { + manager.Delete(manager.GetAllUsableBeatmapSets()); + var temp = TestResources.GetTestBeatmapForImport(); + manager.Import(temp); + Child = screenStackContainer = new ScreenStackCacheContainer { RelativeSizeAxes = Axes.Both }; + screenStackContainer.ScreenStack.Push(songSelect = new DummySongSelect()); + }); + } + + /// + /// Check if properly triggers background dim previews when a user hovers over the visual settings panel. + /// + [Test] + public void PlayerLoaderSettingsHoverTest() + { + setupUserSettings(); + AddStep("Start player loader", () => songSelect.Push(playerLoader = new DimAccessiblePlayerLoader(player = new DimAccessiblePlayer()))); + AddUntilStep(() => playerLoader?.IsLoaded ?? false, "Wait for Player Loader to load"); + AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent()); + AddStep("Trigger background preview", () => + { + InputManager.MoveMouseTo(playerLoader.ScreenPos); + InputManager.MoveMouseTo(playerLoader.VisualSettingsPos); + }); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + AddStep("Stop background preview", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); + waitForDim(); + AddAssert("Screen is undimmed", () => songSelect.IsBackgroundUndimmed()); + } + + /// + /// In the case of a user triggering the dim preview the instant player gets loaded, then moving the cursor off of the visual settings: + /// The OnHover of PlayerLoader will trigger, which could potentially trigger an undim unless checked for in PlayerLoader. + /// We need to check that in this scenario, the dim is still properly applied after entering player. + /// + [Test] + public void PlayerLoaderTransitionTest() + { + performFullSetup(); + AddStep("Trigger hover event", () => playerLoader.TriggerOnHover()); + AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent()); + waitForDim(); + AddAssert("Screen is dimmed and unblurred", () => songSelect.IsBackgroundDimmed() && songSelect.IsBackgroundUnblurred()); + } + + /// + /// Make sure the background is fully invisible (Alpha == 0) when the background should be disabled by the storyboard. + /// + [Test] + public void StoryboardBackgroundVisibilityTest() + { + performFullSetup(); + createFakeStoryboard(); + AddStep("Storyboard Enabled", () => + { + player.ReplacesBackground.Value = true; + player.StoryboardEnabled.Value = true; + }); + waitForDim(); + AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible()); + AddStep("Storyboard Disabled", () => + { + player.ReplacesBackground.Value = false; + player.StoryboardEnabled.Value = false; + }); + waitForDim(); + AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && player.IsStoryboardInvisible()); + } + + /// + /// When exiting player, the screen that it suspends/exits to needs to have a fully visible (Alpha == 1) background. + /// + [Test] + public void StoryboardTransitionTest() + { + performFullSetup(); + createFakeStoryboard(); + AddStep("Exit to song select", () => player.Exit()); + waitForDim(); + AddAssert("Background is visible", () => songSelect.IsBackgroundVisible()); + } + + /// + /// Check if the is properly accepting user dim changes at all. + /// + [Test] + public void DisableUserDimTest() + { + performFullSetup(); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + AddStep("EnableUserDim disabled", () => songSelect.DimEnabled.Value = false); + waitForDim(); + AddAssert("Screen is undimmed", () => songSelect.IsBackgroundUndimmed()); + AddStep("EnableUserDim enabled", () => songSelect.DimEnabled.Value = true); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + } + + /// + /// Check if the fade container retains dim when pausing + /// + [Test] + public void PauseTest() + { + performFullSetup(true); + AddStep("Pause", () => player.CurrentPauseContainer.Pause()); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + AddStep("Unpause", () => player.CurrentPauseContainer.Resume()); + waitForDim(); + AddAssert("Screen is dimmed", () => songSelect.IsBackgroundDimmed()); + } + + /// + /// Check if the fade container removes user dim when suspending for + /// + [Test] + public void TransitionTest() + { + performFullSetup(); + AddStep("Transition to Results", () => player.Push(new FadeAccessibleResults(new ScoreInfo { User = new User { Username = "osu!" } }))); + waitForDim(); + AddAssert("Screen is undimmed and is original background", () => songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent()); + } + + /// + /// Check if background gets undimmed when leaving for + /// + [Test] + public void TransitionOutTest() + { + performFullSetup(); + AddStep("Exit to song select", () => player.Exit()); + waitForDim(); + AddAssert("Screen is undimmed", () => songSelect.IsBackgroundUndimmed()); + } + + private void waitForDim() => AddWaitStep(5, "Wait for dim"); + + private void createFakeStoryboard() => AddStep("Create storyboard", () => + { + player.StoryboardEnabled.Value = false; + player.ReplacesBackground.Value = false; + player.CurrentStoryboardContainer.Add(new SpriteText + { + Size = new Vector2(250, 50), + Alpha = 1, + Colour = Color4.Tomato, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "THIS IS A STORYBOARD", + }); + }); + + private void performFullSetup(bool allowPause = false) + { + setupUserSettings(); + + AddStep("Start player loader", () => + { + songSelect.Push(playerLoader = new DimAccessiblePlayerLoader(player = new DimAccessiblePlayer + { + AllowPause = allowPause, + Ready = true, + })); + }); + AddUntilStep(() => playerLoader.IsLoaded, "Wait for Player Loader to load"); + AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); + AddUntilStep(() => player.IsLoaded, "Wait for player to load"); + } + + private void setupUserSettings() + { + AddUntilStep(() => songSelect.Carousel.SelectedBeatmap != null, "Song select has selection"); + AddStep("Set default user settings", () => + { + Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() }); + songSelect.DimLevel.Value = 0.7f; + songSelect.BlurLevel.Value = 0.0f; + }); + } + + private class DummySongSelect : PlaySongSelect + { + protected override BackgroundScreen CreateBackground() + { + FadeAccessibleBackground background = new FadeAccessibleBackground(Beatmap.Value); + DimEnabled.BindTo(background.EnableUserDim); + return background; + } + + public readonly Bindable DimEnabled = new Bindable(); + public readonly Bindable DimLevel = new Bindable(); + public readonly Bindable BlurLevel = new Bindable(); + + public new BeatmapCarousel Carousel => base.Carousel; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.DimLevel, DimLevel); + config.BindWith(OsuSetting.BlurLevel, BlurLevel); + } + + public bool IsBackgroundDimmed() => ((FadeAccessibleBackground)Background).CurrentColour == OsuColour.Gray(1 - (float)DimLevel.Value); + + public bool IsBackgroundUnblurred() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0); + + public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White; + + public bool IsBackgroundInvisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 0; + + public bool IsBackgroundVisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 1; + + /// + /// Make sure every time a screen gets pushed, the background doesn't get replaced + /// + /// Whether or not the original background (The one created in DummySongSelect) is still the current background + public bool IsBackgroundCurrent() => ((FadeAccessibleBackground)Background).IsCurrentScreen(); + } + + private class FadeAccessibleResults : SoloResults + { + public FadeAccessibleResults(ScoreInfo score) + : base(score) + { + } + + protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + } + + private class DimAccessiblePlayer : Player + { + protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + + protected override UserDimContainer CreateStoryboardContainer() + { + return new TestUserDimContainer(true) + { + RelativeSizeAxes = Axes.Both, + Alpha = 1, + EnableUserDim = { Value = true } + }; + } + + public PauseContainer CurrentPauseContainer => PauseContainer; + + public UserDimContainer CurrentStoryboardContainer => StoryboardContainer; + + // Whether or not the player should be allowed to load. + public bool Ready; + + public Bindable StoryboardEnabled; + public readonly Bindable ReplacesBackground = new Bindable(); + public readonly Bindable IsPaused = new Bindable(); + + public bool IsStoryboardVisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha == 1; + + public bool IsStoryboardInvisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha <= 1; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + while (!Ready) + Thread.Sleep(1); + StoryboardEnabled = config.GetBindable(OsuSetting.ShowStoryboard); + ReplacesBackground.BindTo(Background.StoryboardReplacesBackground); + RulesetContainer.IsPaused.BindTo(IsPaused); + } + } + + private class ScreenStackCacheContainer : Container + { + [Cached] + private BackgroundScreenStack backgroundScreenStack; + + public readonly ScreenStack ScreenStack; + + public ScreenStackCacheContainer() + { + Add(backgroundScreenStack = new BackgroundScreenStack { RelativeSizeAxes = Axes.Both }); + Add(ScreenStack = new ScreenStack { RelativeSizeAxes = Axes.Both }); + } + } + + private class DimAccessiblePlayerLoader : PlayerLoader + { + public VisualSettings VisualSettingsPos => VisualSettings; + public BackgroundScreen ScreenPos => Background; + + public DimAccessiblePlayerLoader(Player player) + : base(() => player) + { + } + + public void TriggerOnHover() => OnHover(new HoverEvent(new InputState())); + + protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + } + + private class FadeAccessibleBackground : BackgroundScreenBeatmap + { + protected override UserDimContainer CreateFadeContainer() => fadeContainer = new TestUserDimContainer { RelativeSizeAxes = Axes.Both }; + + public Color4 CurrentColour => fadeContainer.CurrentColour; + public float CurrentAlpha => fadeContainer.CurrentAlpha; + + public Vector2 CurrentBlur => Background.BlurSigma; + + private TestUserDimContainer fadeContainer; + + public FadeAccessibleBackground(WorkingBeatmap beatmap) + : base(beatmap) + { + } + } + + private class TestUserDimContainer : UserDimContainer + { + public Color4 CurrentColour => DimContainer.Colour; + public float CurrentAlpha => DimContainer.Alpha; + + public TestUserDimContainer(bool isStoryboard = false) + : base(isStoryboard) + { + } + } + } +} diff --git a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs index 16cb94c65e..244f553e97 100644 --- a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs +++ b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Beatmaps; +using osu.Game.Screens; using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual @@ -13,15 +14,22 @@ namespace osu.Game.Tests.Visual public class TestCasePlayerLoader : ManualInputManagerTestCase { private PlayerLoader loader; - private ScreenStack stack; + private readonly ScreenStack stack; + + [Cached] + private BackgroundScreenStack backgroundStack; + + public TestCasePlayerLoader() + { + InputManager.Add(backgroundStack = new BackgroundScreenStack { RelativeSizeAxes = Axes.Both }); + InputManager.Add(stack = new ScreenStack { RelativeSizeAxes = Axes.Both }); + } [BackgroundDependencyLoader] private void load(OsuGameBase game) { Beatmap.Value = new DummyWorkingBeatmap(game); - InputManager.Add(stack = new ScreenStack { RelativeSizeAxes = Axes.Both }); - AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => new Player { AllowPause = false, diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs new file mode 100644 index 0000000000..4c8928e122 --- /dev/null +++ b/osu.Game/Graphics/Containers/UserDimContainer.cs @@ -0,0 +1,88 @@ +// 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.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; +using osuTK.Graphics; + +namespace osu.Game.Graphics.Containers +{ + /// + /// A container that applies user-configured dim levels to its contents. + /// This container specifies behavior that applies to both Storyboards and Backgrounds. + /// + public class UserDimContainer : Container + { + private const float background_fade_duration = 800; + + private Bindable dimLevel { get; set; } + + private Bindable showStoryboard { get; set; } + + /// + /// Whether or not user-configured dim levels should be applied to the container. + /// + public readonly Bindable EnableUserDim = new Bindable(); + + /// + /// Whether or not the storyboard loaded should completely hide the background behind it. + /// + public readonly Bindable StoryboardReplacesBackground = new Bindable(); + + protected Container DimContainer { get; } + + protected override Container Content => DimContainer; + + private readonly bool isStoryboard; + + /// + /// Creates a new . + /// + /// Whether or not this instance of UserDimContainer contains a storyboard. + /// + /// While both backgrounds and storyboards allow user dim levels to be applied, storyboards can be toggled via + /// and can cause backgrounds to become hidden via . + /// + /// + public UserDimContainer(bool isStoryboard = false) + { + this.isStoryboard = isStoryboard; + AddInternal(DimContainer = new Container { RelativeSizeAxes = Axes.Both }); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + dimLevel = config.GetBindable(OsuSetting.DimLevel); + showStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); + EnableUserDim.ValueChanged += _ => updateBackgroundDim(); + dimLevel.ValueChanged += _ => updateBackgroundDim(); + showStoryboard.ValueChanged += _ => updateBackgroundDim(); + StoryboardReplacesBackground.ValueChanged += _ => updateBackgroundDim(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateBackgroundDim(); + } + + private void updateBackgroundDim() + { + if (isStoryboard) + { + DimContainer.FadeTo(!showStoryboard.Value || dimLevel.Value == 1 ? 0 : 1, background_fade_duration, Easing.OutQuint); + } + else + { + // The background needs to be hidden in the case of it being replaced by the storyboard + DimContainer.FadeTo(showStoryboard.Value && StoryboardReplacesBackground.Value ? 0 : 1, background_fade_duration, Easing.OutQuint); + } + + DimContainer.FadeColour(EnableUserDim.Value ? OsuColour.Gray(1 - (float)dimLevel.Value) : Color4.White, background_fade_duration, Easing.OutQuint); + } + } +} diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index 3a49d21b34..13d1ff39ef 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Backgrounds { @@ -13,7 +15,18 @@ namespace osu.Game.Screens.Backgrounds { private WorkingBeatmap beatmap; - public WorkingBeatmap Beatmap + /// + /// Whether or not user dim settings should be applied to this Background. + /// + public readonly Bindable EnableUserDim = new Bindable(); + + public readonly Bindable StoryboardReplacesBackground = new Bindable(); + + private readonly UserDimContainer fadeContainer; + + protected virtual UserDimContainer CreateFadeContainer() => new UserDimContainer { RelativeSizeAxes = Axes.Both }; + + public virtual WorkingBeatmap Beatmap { get => beatmap; set @@ -37,8 +50,9 @@ namespace osu.Game.Screens.Backgrounds } b.Depth = newDepth; - AddInternal(Background = b); + fadeContainer.Add(Background = b); Background.BlurSigma = BlurTarget; + StoryboardReplacesBackground.BindTo(fadeContainer.StoryboardReplacesBackground); })); }); } @@ -47,6 +61,8 @@ namespace osu.Game.Screens.Backgrounds public BackgroundScreenBeatmap(WorkingBeatmap beatmap = null) { Beatmap = beatmap; + InternalChild = fadeContainer = CreateFadeContainer(); + fadeContainer.EnableUserDim.BindTo(EnableUserDim); } public override bool Equals(BackgroundScreen other) @@ -57,7 +73,7 @@ namespace osu.Game.Screens.Backgrounds return base.Equals(other) && beatmap == otherBeatmapBackground.Beatmap; } - private class BeatmapBackground : Background + protected class BeatmapBackground : Background { private readonly WorkingBeatmap beatmap; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index d2f75a0ce1..bb2211a533 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -19,7 +19,6 @@ using osu.Framework.Threading; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Configuration; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; @@ -32,7 +31,6 @@ using osu.Game.Scoring; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Storyboards.Drawables; -using osuTK.Graphics; namespace osu.Game.Screens.Play { @@ -57,6 +55,8 @@ namespace osu.Game.Screens.Play private Bindable mouseWheelDisabled; private Bindable userAudioOffset; + private readonly Bindable storyboardReplacesBackground = new Bindable(); + public int RestartCount; public CursorContainer Cursor => RulesetContainer.Cursor; @@ -72,7 +72,7 @@ namespace osu.Game.Screens.Play [Resolved] private ScoreManager scoreManager { get; set; } - private PauseContainer pauseContainer; + protected PauseContainer PauseContainer { get; private set; } private RulesetInfo ruleset; @@ -80,14 +80,21 @@ namespace osu.Game.Screens.Play private SampleChannel sampleRestart; - protected ScoreProcessor ScoreProcessor; - protected RulesetContainer RulesetContainer; + protected ScoreProcessor ScoreProcessor { get; private set; } + protected RulesetContainer RulesetContainer { get; private set; } - protected HUDOverlay HUDOverlay; + protected HUDOverlay HUDOverlay { get; private set; } private FailOverlay failOverlay; private DrawableStoryboard storyboard; - private Container storyboardContainer; + protected UserDimContainer StoryboardContainer { get; private set; } + + protected virtual UserDimContainer CreateStoryboardContainer() => new UserDimContainer(true) + { + RelativeSizeAxes = Axes.Both, + Alpha = 1, + EnableUserDim = { Value = true } + }; public bool LoadedBeatmapSuccessfully => RulesetContainer?.Objects.Any() == true; @@ -168,19 +175,15 @@ namespace osu.Game.Screens.Play InternalChildren = new Drawable[] { - pauseContainer = new PauseContainer(offsetClock, adjustableClock) + PauseContainer = new PauseContainer(offsetClock, adjustableClock) { Retries = RestartCount, OnRetry = Restart, OnQuit = performUserRequestedExit, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded.Value, - Children = new[] + Children = new Container[] { - storyboardContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - }, + StoryboardContainer = CreateStoryboardContainer(), new ScalingContainer(ScalingMode.Gameplay) { Child = new LocalSkinOverrideContainer(working.Skin) @@ -236,7 +239,7 @@ namespace osu.Game.Screens.Play HUDOverlay.HoldToQuit.Action = performUserRequestedExit; HUDOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); - RulesetContainer.IsPaused.BindTo(pauseContainer.IsPaused); + RulesetContainer.IsPaused.BindTo(PauseContainer.IsPaused); if (ShowStoryboard.Value) initializeStoryboard(false); @@ -346,6 +349,18 @@ namespace osu.Game.Screens.Play .Delay(250) .FadeIn(250); + ShowStoryboard.ValueChanged += enabled => + { + if (enabled.NewValue) initializeStoryboard(true); + }; + + Background.EnableUserDim.Value = true; + + Background.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground); + StoryboardContainer.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground); + + storyboardReplacesBackground.Value = Beatmap.Value.Storyboard.ReplacesBackground && Beatmap.Value.Storyboard.HasDrawable; + Task.Run(() => { sourceClock.Reset(); @@ -357,7 +372,7 @@ namespace osu.Game.Screens.Play this.Delay(750).Schedule(() => { - if (!pauseContainer.IsPaused.Value) + if (!PauseContainer.IsPaused.Value) { adjustableClock.Start(); } @@ -365,8 +380,8 @@ namespace osu.Game.Screens.Play }); }); - pauseContainer.Alpha = 0; - pauseContainer.FadeIn(750, Easing.OutQuint); + PauseContainer.Alpha = 0; + PauseContainer.FadeIn(750, Easing.OutQuint); } public override void OnSuspending(IScreen next) @@ -384,17 +399,16 @@ namespace osu.Game.Screens.Play return true; } - if ((!AllowPause || HasFailed || !ValidForResume || pauseContainer?.IsPaused.Value != false || RulesetContainer?.HasReplayLoaded.Value != false) && (!pauseContainer?.IsResuming ?? true)) + if ((!AllowPause || HasFailed || !ValidForResume || PauseContainer?.IsPaused.Value != false || RulesetContainer?.HasReplayLoaded.Value != false) && (!PauseContainer?.IsResuming ?? true)) { // In the case of replays, we may have changed the playback rate. applyRateFromMods(); - fadeOut(); return base.OnExiting(next); } if (LoadedBeatmapSuccessfully) - pauseContainer?.Pause(); + PauseContainer?.Pause(); return true; } @@ -403,14 +417,16 @@ namespace osu.Game.Screens.Play { float fadeOutDuration = instant ? 0 : 250; this.FadeOut(fadeOutDuration); - Background?.FadeColour(Color4.White, fadeOutDuration, Easing.OutQuint); + + Background.EnableUserDim.Value = false; + storyboardReplacesBackground.Value = false; } - protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !pauseContainer.IsPaused.Value; + protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !PauseContainer.IsPaused.Value; private void initializeStoryboard(bool asyncLoad) { - if (storyboardContainer == null) + if (StoryboardContainer == null || storyboard != null) return; var beatmap = Beatmap.Value; @@ -419,29 +435,9 @@ namespace osu.Game.Screens.Play storyboard.Masking = true; if (asyncLoad) - LoadComponentAsync(storyboard, storyboardContainer.Add); + LoadComponentAsync(storyboard, StoryboardContainer.Add); else - storyboardContainer.Add(storyboard); - } - - protected override void UpdateBackgroundElements() - { - if (!this.IsCurrentScreen()) return; - - base.UpdateBackgroundElements(); - - if (ShowStoryboard.Value && storyboard == null) - initializeStoryboard(true); - - var beatmap = Beatmap.Value; - var storyboardVisible = ShowStoryboard.Value && beatmap.Storyboard.HasDrawable; - - storyboardContainer? - .FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint) - .FadeTo(storyboardVisible && BackgroundOpacity > 0 ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint); - - if (storyboardVisible && beatmap.Storyboard.ReplacesBackground) - Background?.FadeColour(Color4.Black, BACKGROUND_FADE_DURATION, Easing.OutQuint); + StoryboardContainer.Add(storyboard); } protected virtual Results CreateResults(ScoreInfo score) => new SoloResults(score); diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index ac4cc30874..5c9acade7b 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -78,7 +78,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding(25), Children = new PlayerSettingsGroup[] { - visualSettings = new VisualSettings(), + VisualSettings = new VisualSettings(), new InputSettings() } } @@ -151,23 +151,31 @@ namespace osu.Game.Screens.Play } private ScheduledDelegate pushDebounce; - private VisualSettings visualSettings; + protected VisualSettings VisualSettings; private bool readyForPush => player.LoadState == LoadState.Ready && IsHovered && GetContainingInputManager()?.DraggedDrawable == null; protected override bool OnHover(HoverEvent e) { // restore our screen defaults - InitializeBackgroundElements(); + if (this.IsCurrentScreen()) + { + InitializeBackgroundElements(); + Background.EnableUserDim.Value = false; + } + return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - if (GetContainingInputManager()?.HoveredDrawables.Contains(visualSettings) == true) + if (GetContainingInputManager()?.HoveredDrawables.Contains(VisualSettings) == true) { - // show user setting preview + // Update background elements is only being called here because blur logic still exists in Player. + // Will need to be removed when resolving https://github.com/ppy/osu/issues/4322 UpdateBackgroundElements(); + if (this.IsCurrentScreen()) + Background.EnableUserDim.Value = true; } base.OnHoverLost(e); @@ -241,6 +249,8 @@ namespace osu.Game.Screens.Play this.FadeOut(150); cancelLoad(); + Background.EnableUserDim.Value = false; + return base.OnExiting(next); } diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index c28a01155c..328aa1d18e 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -6,7 +6,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Configuration; -using osu.Game.Graphics; using osu.Game.Screens.Backgrounds; using osuTK; @@ -16,15 +15,12 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - protected new BackgroundScreenBeatmap Background => base.Background as BackgroundScreenBeatmap; + protected new BackgroundScreenBeatmap Background => (BackgroundScreenBeatmap)base.Background; protected const float BACKGROUND_FADE_DURATION = 800; - protected float BackgroundOpacity => 1 - (float)DimLevel.Value; - #region User Settings - protected Bindable DimLevel; protected Bindable BlurLevel; protected Bindable ShowStoryboard; @@ -33,7 +29,6 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - DimLevel = config.GetBindable(OsuSetting.DimLevel); BlurLevel = config.GetBindable(OsuSetting.BlurLevel); ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); } @@ -41,9 +36,7 @@ namespace osu.Game.Screens.Play public override void OnEntering(IScreen last) { base.OnEntering(last); - DimLevel.ValueChanged += _ => UpdateBackgroundElements(); BlurLevel.ValueChanged += _ => UpdateBackgroundElements(); - ShowStoryboard.ValueChanged += _ => UpdateBackgroundElements(); InitializeBackgroundElements(); } @@ -66,7 +59,6 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; - Background?.FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint); Background?.BlurTo(new Vector2((float)BlurLevel.Value * 25), BACKGROUND_FADE_DURATION, Easing.OutQuint); } }