From 19f516e710b657aacc124d433459bd0ce8fc96ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 31 Jan 2020 19:10:44 +0900 Subject: [PATCH] Ensure OsuScreen level leases are taken out synchronously --- .../Background/TestSceneUserDimBackgrounds.cs | 8 ++-- .../Visual/Gameplay/TestScenePlayerLoader.cs | 6 ++- .../Visual/Gameplay/TestSceneResults.cs | 15 ++++++-- osu.Game.Tests/Visual/Menus/IntroTestScene.cs | 6 ++- .../Multiplayer/TestSceneMultiHeader.cs | 4 +- .../TestSceneScreenBreadcrumbControl.cs | 4 +- .../UserInterface/ScreenBreadcrumbControl.cs | 3 +- osu.Game/Screens/Multi/Multiplayer.cs | 4 +- osu.Game/Screens/OsuScreen.cs | 22 +++++++++-- osu.Game/Screens/OsuScreenStack.cs | 38 +++++++++++-------- osu.Game/Screens/Select/PlaySongSelect.cs | 5 +-- 11 files changed, 79 insertions(+), 36 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index 589ec7e8aa..eff5bd710d 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -68,10 +68,10 @@ namespace osu.Game.Tests.Visual.Background [SetUp] public virtual void SetUp() => Schedule(() => { - Child = new OsuScreenStack(songSelect = new DummySongSelect()) - { - RelativeSizeAxes = Axes.Both - }; + var stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }; + Child = stack; + + stack.Push(songSelect = new DummySongSelect()); }); /// diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index ad5950d9fc..33ecbed62e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -207,9 +207,11 @@ namespace osu.Game.Tests.Visual.Gameplay { RelativeSizeAxes = Axes.Both; + OsuScreenStack stack; + InternalChildren = new Drawable[] { - new OsuScreenStack(screen) + stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both, }, @@ -224,6 +226,8 @@ namespace osu.Game.Tests.Visual.Gameplay Origin = Anchor.TopLeft, } }; + + stack.Push(screen); } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs index 7790126db5..2b7a32ba17 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs @@ -75,10 +75,16 @@ namespace osu.Game.Tests.Visual.Gameplay public void ResultsWithoutPlayer() { TestSoloResults screen = null; + OsuScreenStack stack; - AddStep("load results", () => Child = new OsuScreenStack(screen = createResultsScreen()) + AddStep("load results", () => { - RelativeSizeAxes = Axes.Both + Child = stack = new OsuScreenStack + { + RelativeSizeAxes = Axes.Both + }; + + stack.Push(screen = createResultsScreen()); }); AddUntilStep("wait for loaded", () => screen.IsLoaded); AddAssert("retry overlay not present", () => screen.RetryOverlay == null); @@ -102,11 +108,14 @@ namespace osu.Game.Tests.Visual.Gameplay public TestResultsContainer(IScreen screen) { RelativeSizeAxes = Axes.Both; + OsuScreenStack stack; - InternalChild = new OsuScreenStack(screen) + InternalChild = stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both, }; + + stack.Push(screen); } } diff --git a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs index d03d341ee4..5870ef9813 100644 --- a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs +++ b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Menus protected IntroTestScene() { - Drawable introStack = null; + OsuScreenStack introStack = null; Children = new Drawable[] { @@ -57,10 +57,12 @@ namespace osu.Game.Tests.Visual.Menus introStack?.Expire(); - Add(introStack = new OsuScreenStack(CreateScreen()) + Add(introStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both, }); + + introStack.Push(CreateScreen()); }); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs index 3f89f636b1..76ab402b72 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs @@ -16,7 +16,9 @@ namespace osu.Game.Tests.Visual.Multiplayer { int index = 0; - OsuScreenStack screenStack = new OsuScreenStack(new TestMultiplayerSubScreen(index)) { RelativeSizeAxes = Axes.Both }; + OsuScreenStack screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }; + + screenStack.Push(new TestMultiplayerSubScreen(index)); Children = new Drawable[] { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs index 7386e0fa1f..77a7d819a9 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs @@ -25,7 +25,9 @@ namespace osu.Game.Tests.Visual.UserInterface OsuSpriteText titleText; IScreen startScreen = new TestScreenOne(); - screenStack = new OsuScreenStack(startScreen) { RelativeSizeAxes = Axes.Both }; + + screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }; + screenStack.Push(startScreen); Children = new Drawable[] { diff --git a/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs index 3e0a6c3265..e85525b2f8 100644 --- a/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs @@ -17,7 +17,8 @@ namespace osu.Game.Graphics.UserInterface stack.ScreenPushed += onPushed; stack.ScreenExited += onExited; - onPushed(null, stack.CurrentScreen); + if (stack.CurrentScreen != null) + onPushed(null, stack.CurrentScreen); Current.ValueChanged += current => current.NewValue.MakeCurrent(); } diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 86d52ff791..9d6a459d14 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -96,7 +96,7 @@ namespace osu.Game.Screens.Multi { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Top = Header.HEIGHT }, - Child = screenStack = new OsuScreenStack(loungeSubScreen = new LoungeSubScreen()) { RelativeSizeAxes = Axes.Both } + Child = screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both } }, new Header(screenStack), createButton = new HeaderButton @@ -120,6 +120,8 @@ namespace osu.Game.Screens.Multi } }; + screenStack.Push(loungeSubScreen = new LoungeSubScreen()); + screenStack.ScreenPushed += screenPushed; screenStack.ScreenExited += screenExited; } diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 6394fb8d23..61e94ae969 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -1,6 +1,7 @@ // 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 Microsoft.EntityFrameworkCore.Internal; using osu.Framework.Allocation; @@ -95,15 +96,30 @@ namespace osu.Game.Screens public Bindable> Mods { get; private set; } + private OsuScreenDependencies screenDependencies; + + internal void CreateLeasedDependencies(IReadOnlyDependencyContainer dependencies) => createDependencies(dependencies); + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { - var screenDependencies = new OsuScreenDependencies(DisallowExternalBeatmapRulesetChanges, parent); + if (screenDependencies == null) + { + if (DisallowExternalBeatmapRulesetChanges) + throw new InvalidOperationException($"Screens that specify {nameof(DisallowExternalBeatmapRulesetChanges)} must be pushed immediately."); + + createDependencies(parent); + } + + return base.CreateChildDependencies(screenDependencies); + } + + private void createDependencies(IReadOnlyDependencyContainer dependencies) + { + screenDependencies = new OsuScreenDependencies(DisallowExternalBeatmapRulesetChanges, dependencies); Beatmap = screenDependencies.Beatmap; Ruleset = screenDependencies.Ruleset; Mods = screenDependencies.Mods; - - return base.CreateChildDependencies(screenDependencies); } protected BackgroundScreen Background => backgroundStack?.CurrentScreen as BackgroundScreen; diff --git a/osu.Game/Screens/OsuScreenStack.cs b/osu.Game/Screens/OsuScreenStack.cs index 0844e32d46..db577ea5e9 100644 --- a/osu.Game/Screens/OsuScreenStack.cs +++ b/osu.Game/Screens/OsuScreenStack.cs @@ -18,17 +18,6 @@ namespace osu.Game.Screens protected float ParallaxAmount => parallaxContainer.ParallaxAmount; public OsuScreenStack() - { - initializeStack(); - } - - public OsuScreenStack(IScreen baseScreen) - : base(baseScreen) - { - initializeStack(); - } - - private void initializeStack() { InternalChild = parallaxContainer = new ParallaxContainer { @@ -36,13 +25,32 @@ namespace osu.Game.Screens Child = backgroundScreenStack = new BackgroundScreenStack { RelativeSizeAxes = Axes.Both }, }; - ScreenPushed += onScreenChange; - ScreenExited += onScreenChange; + ScreenPushed += screenPushed; + ScreenExited += screenExited; } - private void onScreenChange(IScreen prev, IScreen next) + private void screenPushed(IScreen prev, IScreen next) { - parallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * ((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f; + if (LoadState < LoadState.Ready) + { + // dependencies must be present to stay in a sane state. + // this is generally only ever hit by test scenes. + Schedule(() => screenPushed(prev, next)); + return; + } + + // create dependencies synchronously to ensure leases are in a sane state. + ((OsuScreen)next).CreateLeasedDependencies((prev as OsuScreen)?.Dependencies ?? Dependencies); + + setParallax(next); } + + private void screenExited(IScreen prev, IScreen next) + { + setParallax(next); + } + + private void setParallax(IScreen next) => + parallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * ((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f; } } diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 9368bac69f..347eae49f0 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -68,10 +68,7 @@ namespace osu.Game.Screens.Select SampleConfirm?.Play(); - LoadComponentAsync(player = new PlayerLoader(() => new Player()), l => - { - if (this.IsCurrentScreen()) this.Push(player); - }); + this.Push(player = new PlayerLoader(() => new Player())); return true; }