diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs new file mode 100644 index 0000000000..2d2726bbd3 --- /dev/null +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -0,0 +1,427 @@ +// 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.Audio; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +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.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +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.Background +{ + [TestFixture] + public class TestSceneUserDimBackgrounds : ManualInputManagerTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ScreenWithBeatmapBackground), + typeof(PlayerLoader), + typeof(Player), + typeof(UserDimContainer), + typeof(OsuScreen) + }; + + private DummySongSelect songSelect; + private TestPlayerLoader playerLoader; + private TestPlayer player; + private BeatmapManager manager; + private RulesetStore rulesets; + + [BackgroundDependencyLoader] + private void load(GameHost host, AudioManager audio) + { + Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(new OsuConfigManager(LocalStorage)); + + manager.Import(TestResources.GetTestBeatmapForImport()).Wait(); + + Beatmap.SetDefault(); + } + + [SetUp] + public virtual void SetUp() => Schedule(() => + { + Child = new OsuScreenStack(songSelect = new DummySongSelect()) + { + RelativeSizeAxes = Axes.Both + }; + }); + + /// + /// Check if properly triggers the visual settings preview when a user hovers over the visual settings panel. + /// + [Test] + public void PlayerLoaderSettingsHoverTest() + { + setupUserSettings(); + AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new TestPlayer { BlockLoad = true }))); + AddUntilStep("Wait for Player Loader to load", () => playerLoader?.IsLoaded ?? false); + 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 and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); + AddStep("Stop background preview", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); + waitForDim(); + AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect()); + } + + /// + /// 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 cause visual settings to be unapplied unless checked for in PlayerLoader. + /// We need to check that in this scenario, the dim and blur 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 blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); + } + + /// + /// 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("Enable Storyboard", () => + { + player.ReplacesBackground.Value = true; + player.StoryboardEnabled.Value = true; + }); + waitForDim(); + AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible); + AddStep("Disable Storyboard", () => + { + player.ReplacesBackground.Value = false; + player.StoryboardEnabled.Value = false; + }); + waitForDim(); + AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && !player.IsStoryboardVisible); + } + + /// + /// 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()); + } + + /// + /// Ensure is properly accepting user-defined visual changes for a background. + /// + [Test] + public void DisableUserDimBackgroundTest() + { + performFullSetup(); + waitForDim(); + AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); + AddStep("Enable user dim", () => songSelect.DimEnabled.Value = false); + waitForDim(); + AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsUserBlurDisabled()); + AddStep("Disable user dim", () => songSelect.DimEnabled.Value = true); + waitForDim(); + AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); + } + + /// + /// Ensure is properly accepting user-defined visual changes for a storyboard. + /// + [Test] + public void DisableUserDimStoryboardTest() + { + performFullSetup(); + createFakeStoryboard(); + AddStep("Enable Storyboard", () => + { + player.ReplacesBackground.Value = true; + player.StoryboardEnabled.Value = true; + }); + AddStep("Enable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = true); + AddStep("Set dim level to 1", () => songSelect.DimLevel.Value = 1f); + waitForDim(); + AddAssert("Storyboard is invisible", () => !player.IsStoryboardVisible); + AddStep("Disable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = false); + waitForDim(); + AddAssert("Storyboard is visible", () => player.IsStoryboardVisible); + } + + /// + /// Check if the visual settings container retains dim and blur when pausing + /// + [Test] + public void PauseTest() + { + performFullSetup(true); + AddStep("Pause", () => player.Pause()); + waitForDim(); + AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); + AddStep("Unpause", () => player.Resume()); + waitForDim(); + AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); + } + + /// + /// Check if the visual settings container removes user dim when suspending for + /// + [Test] + public void TransitionTest() + { + performFullSetup(); + FadeAccessibleResults results = null; + AddStep("Transition to Results", () => player.Push(results = + new FadeAccessibleResults(new ScoreInfo { User = new User { Username = "osu!" } }))); + AddUntilStep("Wait for results is current", () => results.IsCurrentScreen()); + waitForDim(); + AddAssert("Screen is undimmed, original background retained", () => + songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect()); + } + + /// + /// Check if background gets undimmed and unblurred when leaving for + /// + [Test] + public void TransitionOutTest() + { + performFullSetup(); + AddStep("Exit to song select", () => player.Exit()); + waitForDim(); + AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsBlurCorrect()); + } + + /// + /// Check if hovering on the visual settings dialogue after resuming from player still previews the background dim. + /// + [Test] + public void ResumeFromPlayerTest() + { + performFullSetup(); + AddStep("Move mouse to Visual Settings", () => InputManager.MoveMouseTo(playerLoader.VisualSettingsPos)); + AddStep("Resume PlayerLoader", () => player.Restart()); + waitForDim(); + AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); + AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); + waitForDim(); + AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect()); + } + + private void waitForDim() => AddWaitStep("Wait for dim", 5); + + private void createFakeStoryboard() => AddStep("Create storyboard", () => + { + player.StoryboardEnabled.Value = false; + player.ReplacesBackground.Value = false; + player.DimmableStoryboard.Add(new OsuSpriteText + { + Size = new Vector2(500, 50), + Alpha = 1, + Colour = Color4.White, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "THIS IS A STORYBOARD", + Font = new FontUsage(size: 50) + }); + }); + + private void performFullSetup(bool allowPause = false) + { + setupUserSettings(); + + AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new TestPlayer(allowPause)))); + + AddUntilStep("Wait for Player Loader to load", () => playerLoader.IsLoaded); + AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); + AddUntilStep("Wait for player to load", () => player.IsLoaded); + } + + private void setupUserSettings() + { + AddUntilStep("Song select has selection", () => songSelect.Carousel.SelectedBeatmap != null); + AddStep("Set default user settings", () => + { + Mods.Value = Mods.Value.Concat(new[] { new OsuModNoFail() }).ToArray(); + songSelect.DimLevel.Value = 0.7f; + songSelect.BlurLevel.Value = 0.4f; + }); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + rulesets?.Dispose(); + } + + 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(1f - ((FadeAccessibleBackground)Background).CurrentDim); + + public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White; + + public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR); + + public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0); + + public bool IsBackgroundInvisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 0; + + public bool IsBackgroundVisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 1; + + public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR); + + /// + /// 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); + + public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR); + } + + private class TestPlayer : Visual.TestPlayer + { + protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + + public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard; + + // Whether or not the player should be allowed to load. + public bool BlockLoad; + + public Bindable StoryboardEnabled; + public readonly Bindable ReplacesBackground = new Bindable(); + public readonly Bindable IsPaused = new Bindable(); + + public TestPlayer(bool allowPause = true) + : base(allowPause) + { + } + + public bool IsStoryboardVisible => DimmableStoryboard.ContentDisplayed; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config, CancellationToken token) + { + while (BlockLoad && !token.IsCancellationRequested) + Thread.Sleep(1); + + StoryboardEnabled = config.GetBindable(OsuSetting.ShowStoryboard); + ReplacesBackground.BindTo(Background.StoryboardReplacesBackground); + DrawableRuleset.IsPaused.BindTo(IsPaused); + } + } + + private class TestPlayerLoader : PlayerLoader + { + public VisualSettings VisualSettingsPos => VisualSettings; + public BackgroundScreen ScreenPos => Background; + + public TestPlayerLoader(Player player) + : base(() => player) + { + } + + public void TriggerOnHover() => OnHover(new HoverEvent(new InputState())); + + public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR); + + protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + } + + private class FadeAccessibleBackground : BackgroundScreenBeatmap + { + protected override DimmableBackground CreateFadeContainer() => dimmable = new TestDimmableBackground { RelativeSizeAxes = Axes.Both }; + + public Color4 CurrentColour => dimmable.CurrentColour; + + public float CurrentAlpha => dimmable.CurrentAlpha; + + public float CurrentDim => dimmable.DimLevel; + + public Vector2 CurrentBlur => Background.BlurSigma; + + private TestDimmableBackground dimmable; + + public FadeAccessibleBackground(WorkingBeatmap beatmap) + : base(beatmap) + { + } + } + + private class TestDimmableBackground : BackgroundScreenBeatmap.DimmableBackground + { + public Color4 CurrentColour => Content.Colour; + public float CurrentAlpha => Content.Alpha; + + public new float DimLevel => base.DimLevel; + } + } +} diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs index 8f71584b4d..472c43096f 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs @@ -1,423 +1,98 @@ // 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.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; -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.Framework.Graphics.Shapes; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -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.Background { - [TestFixture] - public class TestSceneUserDimContainer : ManualInputManagerTestScene + public class TestSceneUserDimContainer : OsuTestScene { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(ScreenWithBeatmapBackground), - typeof(PlayerLoader), - typeof(Player), - typeof(UserDimContainer), - typeof(OsuScreen) - }; + private TestUserDimContainer userDimContainer; - private DummySongSelect songSelect; - private TestPlayerLoader playerLoader; - private TestPlayer player; - private BeatmapManager manager; - private RulesetStore rulesets; + private readonly BindableBool isBreakTime = new BindableBool(); + + private Bindable lightenDuringBreaks = new Bindable(); [BackgroundDependencyLoader] - private void load(GameHost host, AudioManager audio) + private void load(OsuConfigManager config) { - Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); - Dependencies.Cache(new OsuConfigManager(LocalStorage)); - - manager.Import(TestResources.GetTestBeatmapForImport()).Wait(); - - Beatmap.SetDefault(); + lightenDuringBreaks = config.GetBindable(OsuSetting.LightenDuringBreaks); } [SetUp] - public virtual void SetUp() => Schedule(() => + public void SetUp() => Schedule(() => { - Child = new OsuScreenStack(songSelect = new DummySongSelect()) + Child = userDimContainer = new TestUserDimContainer { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + Child = new Box + { + Colour = Color4.White, + RelativeSizeAxes = Axes.Both, + }, }; + + userDimContainer.IsBreakTime.BindTo(isBreakTime); + isBreakTime.Value = false; + + lightenDuringBreaks.Value = false; }); - /// - /// Check if properly triggers the visual settings preview when a user hovers over the visual settings panel. - /// + private const float test_user_dim = 0.6f; + private const float test_user_dim_lightened = test_user_dim - UserDimContainer.BREAK_LIGHTEN_AMOUNT; + + [TestCase(test_user_dim, test_user_dim_lightened)] + [TestCase(0.2f, 0.0f)] + [TestCase(0.0f, 0.0f)] + public void TestBreakLightening(float userDim, float expectedBreakDim) + { + AddStep($"set dim level {userDim}", () => userDimContainer.UserDimLevel.Value = userDim); + AddStep("set lighten during break", () => lightenDuringBreaks.Value = true); + + AddStep("set break", () => isBreakTime.Value = true); + AddUntilStep("has lightened", () => userDimContainer.DimEqual(expectedBreakDim)); + AddStep("clear break", () => isBreakTime.Value = false); + AddUntilStep("not lightened", () => userDimContainer.DimEqual(userDim)); + } + [Test] - public void PlayerLoaderSettingsHoverTest() + public void TestEnableSettingDuringBreak() { - setupUserSettings(); - AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new TestPlayer { BlockLoad = true }))); - AddUntilStep("Wait for Player Loader to load", () => playerLoader?.IsLoaded ?? false); - 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 and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); - AddStep("Stop background preview", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); - waitForDim(); - AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect()); + AddStep("set dim level 0.6", () => userDimContainer.UserDimLevel.Value = test_user_dim); + + AddStep("set break", () => isBreakTime.Value = true); + AddUntilStep("not lightened", () => userDimContainer.DimEqual(test_user_dim)); + AddStep("set lighten during break", () => lightenDuringBreaks.Value = true); + AddUntilStep("has lightened", () => userDimContainer.DimEqual(test_user_dim_lightened)); } - /// - /// 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 cause visual settings to be unapplied unless checked for in PlayerLoader. - /// We need to check that in this scenario, the dim and blur is still properly applied after entering player. - /// [Test] - public void PlayerLoaderTransitionTest() + public void TestDisableSettingDuringBreak() { - performFullSetup(); - AddStep("Trigger hover event", () => playerLoader.TriggerOnHover()); - AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent()); - waitForDim(); - AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); + AddStep("set dim level 0.6", () => userDimContainer.UserDimLevel.Value = test_user_dim); + AddStep("set lighten during break", () => lightenDuringBreaks.Value = true); + + AddStep("set break", () => isBreakTime.Value = true); + AddUntilStep("has lightened", () => userDimContainer.DimEqual(test_user_dim_lightened)); + AddStep("clear lighten during break", () => lightenDuringBreaks.Value = false); + AddUntilStep("not lightened", () => userDimContainer.DimEqual(test_user_dim)); + AddStep("clear break", () => isBreakTime.Value = false); + AddUntilStep("not lightened", () => userDimContainer.DimEqual(test_user_dim)); } - /// - /// Make sure the background is fully invisible (Alpha == 0) when the background should be disabled by the storyboard. - /// - [Test] - public void StoryboardBackgroundVisibilityTest() + private class TestUserDimContainer : UserDimContainer { - performFullSetup(); - createFakeStoryboard(); - AddStep("Enable Storyboard", () => - { - player.ReplacesBackground.Value = true; - player.StoryboardEnabled.Value = true; - }); - waitForDim(); - AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible); - AddStep("Disable Storyboard", () => - { - player.ReplacesBackground.Value = false; - player.StoryboardEnabled.Value = false; - }); - waitForDim(); - AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && !player.IsStoryboardVisible); - } + public bool DimEqual(float expectedDimLevel) => Content.Colour == OsuColour.Gray(1f - expectedDimLevel); - /// - /// 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()); - } - - /// - /// Ensure is properly accepting user-defined visual changes for a background. - /// - [Test] - public void DisableUserDimBackgroundTest() - { - performFullSetup(); - waitForDim(); - AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); - AddStep("Enable user dim", () => songSelect.DimEnabled.Value = false); - waitForDim(); - AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsUserBlurDisabled()); - AddStep("Disable user dim", () => songSelect.DimEnabled.Value = true); - waitForDim(); - AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); - } - - /// - /// Ensure is properly accepting user-defined visual changes for a storyboard. - /// - [Test] - public void DisableUserDimStoryboardTest() - { - performFullSetup(); - createFakeStoryboard(); - AddStep("Enable Storyboard", () => - { - player.ReplacesBackground.Value = true; - player.StoryboardEnabled.Value = true; - }); - AddStep("Enable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = true); - AddStep("Set dim level to 1", () => songSelect.DimLevel.Value = 1f); - waitForDim(); - AddAssert("Storyboard is invisible", () => !player.IsStoryboardVisible); - AddStep("Disable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = false); - waitForDim(); - AddAssert("Storyboard is visible", () => player.IsStoryboardVisible); - } - - /// - /// Check if the visual settings container retains dim and blur when pausing - /// - [Test] - public void PauseTest() - { - performFullSetup(true); - AddStep("Pause", () => player.Pause()); - waitForDim(); - AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); - AddStep("Unpause", () => player.Resume()); - waitForDim(); - AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); - } - - /// - /// Check if the visual settings container removes user dim when suspending for - /// - [Test] - public void TransitionTest() - { - performFullSetup(); - FadeAccessibleResults results = null; - AddStep("Transition to Results", () => player.Push(results = - new FadeAccessibleResults(new ScoreInfo { User = new User { Username = "osu!" } }))); - AddUntilStep("Wait for results is current", () => results.IsCurrentScreen()); - waitForDim(); - AddAssert("Screen is undimmed, original background retained", () => - songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect()); - } - - /// - /// Check if background gets undimmed and unblurred when leaving for - /// - [Test] - public void TransitionOutTest() - { - performFullSetup(); - AddStep("Exit to song select", () => player.Exit()); - waitForDim(); - AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsBlurCorrect()); - } - - /// - /// Check if hovering on the visual settings dialogue after resuming from player still previews the background dim. - /// - [Test] - public void ResumeFromPlayerTest() - { - performFullSetup(); - AddStep("Move mouse to Visual Settings", () => InputManager.MoveMouseTo(playerLoader.VisualSettingsPos)); - AddStep("Resume PlayerLoader", () => player.Restart()); - waitForDim(); - AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); - AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); - waitForDim(); - AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect()); - } - - private void waitForDim() => AddWaitStep("Wait for dim", 5); - - private void createFakeStoryboard() => AddStep("Create storyboard", () => - { - player.StoryboardEnabled.Value = false; - player.ReplacesBackground.Value = false; - player.DimmableStoryboard.Add(new OsuSpriteText - { - Size = new Vector2(500, 50), - Alpha = 1, - Colour = Color4.White, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "THIS IS A STORYBOARD", - Font = new FontUsage(size: 50) - }); - }); - - private void performFullSetup(bool allowPause = false) - { - setupUserSettings(); - - AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new TestPlayer(allowPause)))); - - AddUntilStep("Wait for Player Loader to load", () => playerLoader.IsLoaded); - AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); - AddUntilStep("Wait for player to load", () => player.IsLoaded); - } - - private void setupUserSettings() - { - AddUntilStep("Song select has selection", () => songSelect.Carousel.SelectedBeatmap != null); - AddStep("Set default user settings", () => - { - Mods.Value = Mods.Value.Concat(new[] { new OsuModNoFail() }).ToArray(); - songSelect.DimLevel.Value = 0.7f; - songSelect.BlurLevel.Value = 0.4f; - }); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - rulesets?.Dispose(); - } - - 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 IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White; - - public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR); - - public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0); - - public bool IsBackgroundInvisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 0; - - public bool IsBackgroundVisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 1; - - public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR); - - /// - /// 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); - - public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR); - } - - private class TestPlayer : Visual.TestPlayer - { - protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); - - public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard; - - // Whether or not the player should be allowed to load. - public bool BlockLoad; - - public Bindable StoryboardEnabled; - public readonly Bindable ReplacesBackground = new Bindable(); - public readonly Bindable IsPaused = new Bindable(); - - public TestPlayer(bool allowPause = true) - : base(allowPause) - { - } - - public bool IsStoryboardVisible => DimmableStoryboard.ContentDisplayed; - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config, CancellationToken token) - { - while (BlockLoad && !token.IsCancellationRequested) - Thread.Sleep(1); - - StoryboardEnabled = config.GetBindable(OsuSetting.ShowStoryboard); - ReplacesBackground.BindTo(Background.StoryboardReplacesBackground); - DrawableRuleset.IsPaused.BindTo(IsPaused); - } - } - - private class TestPlayerLoader : PlayerLoader - { - public VisualSettings VisualSettingsPos => VisualSettings; - public BackgroundScreen ScreenPos => Background; - - public TestPlayerLoader(Player player) - : base(() => player) - { - } - - public void TriggerOnHover() => OnHover(new HoverEvent(new InputState())); - - public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR); - - protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); - } - - private class FadeAccessibleBackground : BackgroundScreenBeatmap - { - protected override DimmableBackground CreateFadeContainer() => dimmable = new TestDimmableBackground { RelativeSizeAxes = Axes.Both }; - - public Color4 CurrentColour => dimmable.CurrentColour; - - public float CurrentAlpha => dimmable.CurrentAlpha; - - public Vector2 CurrentBlur => Background.BlurSigma; - - private TestDimmableBackground dimmable; - - public FadeAccessibleBackground(WorkingBeatmap beatmap) - : base(beatmap) - { - } - } - - private class TestDimmableBackground : BackgroundScreenBeatmap.DimmableBackground - { - public Color4 CurrentColour => Content.Colour; - public float CurrentAlpha => Content.Alpha; + public new Bindable UserDimLevel => base.UserDimLevel; } } } diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index b71463841a..947e864a87 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -80,6 +80,7 @@ namespace osu.Game.Configuration // Gameplay Set(OsuSetting.DimLevel, 0.3, 0, 1, 0.01); Set(OsuSetting.BlurLevel, 0, 0, 1, 0.01); + Set(OsuSetting.LightenDuringBreaks, true); Set(OsuSetting.HitLighting, true); @@ -142,6 +143,7 @@ namespace osu.Game.Configuration AutoCursorSize, DimLevel, BlurLevel, + LightenDuringBreaks, ShowStoryboard, ShowVideoBackground, KeyOverlay, diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs index 7683bbcd63..e67cd94d5c 100644 --- a/osu.Game/Graphics/Containers/UserDimContainer.cs +++ b/osu.Game/Graphics/Containers/UserDimContainer.cs @@ -1,11 +1,13 @@ // 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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; +using osu.Game.Screens.Play; namespace osu.Game.Graphics.Containers { @@ -14,7 +16,12 @@ namespace osu.Game.Graphics.Containers /// public abstract class UserDimContainer : Container { - protected const float BACKGROUND_FADE_DURATION = 800; + /// + /// Amount of lightening to apply to current dim level during break times. + /// + public const float BREAK_LIGHTEN_AMOUNT = 0.3f; + + protected const double BACKGROUND_FADE_DURATION = 800; /// /// Whether or not user-configured dim levels should be applied to the container. @@ -26,6 +33,12 @@ namespace osu.Game.Graphics.Containers /// public readonly Bindable StoryboardReplacesBackground = new Bindable(); + /// + /// Whether player is in break time. + /// Must be bound to to allow for dim adjustments in gameplay. + /// + public readonly IBindable IsBreakTime = new Bindable(); + /// /// Whether the content of this container is currently being displayed. /// @@ -33,11 +46,14 @@ namespace osu.Game.Graphics.Containers protected Bindable UserDimLevel { get; private set; } + protected Bindable LightenDuringBreaks { get; private set; } + protected Bindable ShowStoryboard { get; private set; } protected Bindable ShowVideo { get; private set; } - protected double DimLevel => EnableUserDim.Value ? UserDimLevel.Value : 0; + private float breakLightening => LightenDuringBreaks.Value && IsBreakTime.Value ? BREAK_LIGHTEN_AMOUNT : 0; + protected float DimLevel => Math.Max(EnableUserDim.Value ? (float)UserDimLevel.Value - breakLightening : 0, 0); protected override Container Content => dimContent; @@ -55,11 +71,14 @@ namespace osu.Game.Graphics.Containers private void load(OsuConfigManager config) { UserDimLevel = config.GetBindable(OsuSetting.DimLevel); + LightenDuringBreaks = config.GetBindable(OsuSetting.LightenDuringBreaks); ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); ShowVideo = config.GetBindable(OsuSetting.ShowVideoBackground); EnableUserDim.ValueChanged += _ => UpdateVisuals(); UserDimLevel.ValueChanged += _ => UpdateVisuals(); + LightenDuringBreaks.ValueChanged += _ => UpdateVisuals(); + IsBreakTime.ValueChanged += _ => UpdateVisuals(); ShowStoryboard.ValueChanged += _ => UpdateVisuals(); ShowVideo.ValueChanged += _ => UpdateVisuals(); StoryboardReplacesBackground.ValueChanged += _ => UpdateVisuals(); @@ -84,7 +103,7 @@ namespace osu.Game.Graphics.Containers ContentDisplayed = ShowDimContent; dimContent.FadeTo(ContentDisplayed ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint); - dimContent.FadeColour(OsuColour.Gray(1 - (float)DimLevel), BACKGROUND_FADE_DURATION, Easing.OutQuint); + dimContent.FadeColour(OsuColour.Gray(1f - DimLevel), BACKGROUND_FADE_DURATION, Easing.OutQuint); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index f4aa9a0144..3f8bc2b0c7 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -30,6 +30,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay KeyboardStep = 0.01f }, new SettingsCheckbox + { + LabelText = "Lighten playfield during breaks", + Bindable = config.GetBindable(OsuSetting.LightenDuringBreaks) + }, + new SettingsCheckbox { LabelText = "Show score overlay", Bindable = config.GetBindable(OsuSetting.ShowInterface) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index 7b68460e6b..1ab3a5b533 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -38,6 +38,8 @@ namespace osu.Game.Screens.Backgrounds /// public readonly Bindable BlurAmount = new Bindable(); + internal readonly IBindable IsBreakTime = new Bindable(); + private readonly DimmableBackground dimmable; protected virtual DimmableBackground CreateFadeContainer() => new DimmableBackground { RelativeSizeAxes = Axes.Both }; @@ -48,6 +50,7 @@ namespace osu.Game.Screens.Backgrounds InternalChild = dimmable = CreateFadeContainer(); dimmable.EnableUserDim.BindTo(EnableUserDim); + dimmable.IsBreakTime.BindTo(IsBreakTime); dimmable.BlurAmount.BindTo(BlurAmount); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index b65d20dcbb..5735506775 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -511,6 +511,11 @@ namespace osu.Game.Screens.Play Background.EnableUserDim.Value = true; Background.BlurAmount.Value = 0; + // bind component bindables. + Background.IsBreakTime.BindTo(breakOverlay.IsBreakTime); + DimmableStoryboard.IsBreakTime.BindTo(breakOverlay.IsBreakTime); + DimmableVideo.IsBreakTime.BindTo(breakOverlay.IsBreakTime); + Background.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground); DimmableStoryboard.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);