From 1dbcb5ab63a7d5656c40f370213148011d3c8fbb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 Jan 2022 18:51:15 +0900 Subject: [PATCH 1/4] Add test coverage of intro fail scenario --- osu.Game.Tests/Visual/Menus/IntroTestScene.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs index bfea97410a..40b072c171 100644 --- a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs +++ b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs @@ -5,6 +5,8 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Framework.Threading; +using osu.Game.Overlays; using osu.Game.Screens; using osu.Game.Screens.Menu; using osuTK; @@ -22,6 +24,11 @@ namespace osu.Game.Tests.Visual.Menus private IntroScreen intro; + [Cached] + private NotificationOverlay notifications; + + private ScheduledDelegate trackResetDelegate; + protected IntroTestScene() { Children = new Drawable[] @@ -38,6 +45,11 @@ namespace osu.Game.Tests.Visual.Menus RelativePositionAxes = Axes.Both, Depth = float.MinValue, Position = new Vector2(0.5f), + }, + notifications = new NotificationOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, } }; } @@ -63,6 +75,39 @@ namespace osu.Game.Tests.Visual.Menus AddUntilStep("wait for menu", () => intro.DidLoadMenu); } + [Test] + public virtual void TestPlayIntroWithFailingAudioDevice() + { + AddStep("hide notifications", () => notifications.Hide()); + AddStep("restart sequence", () => + { + logo.FinishTransforms(); + logo.IsTracking = false; + + IntroStack?.Expire(); + + Add(IntroStack = new OsuScreenStack + { + RelativeSizeAxes = Axes.Both, + }); + + IntroStack.Push(intro = CreateScreen()); + }); + + AddStep("trigger failure", () => + { + trackResetDelegate = Scheduler.AddDelayed(() => + { + intro.Beatmap.Value.Track.Seek(0); + }, 0, true); + }); + + AddUntilStep("wait for menu", () => intro.DidLoadMenu); + AddUntilStep("wait for notification", () => notifications.UnreadCount.Value == 1); + + AddStep("uninstall delegate", () => trackResetDelegate?.Cancel()); + } + protected abstract IntroScreen CreateScreen(); } } From 52f1c2bfdbc349259bc817ac3e0a4925f9c78a8e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 Jan 2022 18:37:00 +0900 Subject: [PATCH 2/4] Add failsafe to `IntroScreen` to stop users with incorrect audio configuration getting stuck The most common case of this seems to be linux users with incorrect or unsupported audio driver configurations. It continues to be brought up in discussions as people are unsure of why their game freezes on startup, and unable to easily recover. --- osu.Game/Screens/Menu/IntroScreen.cs | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index fceb083916..98c4b15f7f 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -18,6 +18,7 @@ using osu.Game.Configuration; using osu.Game.Database; using osu.Game.IO.Archives; using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; using osu.Game.Screens.Backgrounds; using osuTK; using osuTK.Graphics; @@ -147,6 +148,36 @@ namespace osu.Game.Screens.Menu } } + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + ensureEventuallyArrivingAtMenu(); + } + + [Resolved] + private NotificationOverlay notifications { get; set; } + + private void ensureEventuallyArrivingAtMenu() + { + // This intends to handle the case where an intro may get stuck. + // Historically, this could happen if the host system's audio device is in a state it can't + // play audio, causing a clock to never elapse time and the intro to never end. + // + // This safety measure gives the user a chance to fix the problem from the settings menu. + Scheduler.AddDelayed(() => + { + if (DidLoadMenu) + return; + + PrepareMenuLoad(); + LoadMenu(); + notifications.Post(new SimpleErrorNotification + { + Text = "osu! doesn't seem to be able to play audio correctly.\n\nPlease try changing your audio device to a working setting." + }); + }, 5000); + } + public override void OnResuming(IScreen last) { this.FadeIn(300); @@ -241,6 +272,9 @@ namespace osu.Game.Screens.Menu protected void PrepareMenuLoad() { + if (nextScreen != null) + return; + nextScreen = createNextScreen?.Invoke(); if (nextScreen != null) @@ -249,6 +283,9 @@ namespace osu.Game.Screens.Menu protected void LoadMenu() { + if (DidLoadMenu) + return; + beatmap.Return(); DidLoadMenu = true; From 6a21d583259b43c0d7865371f34c73d5cba04e04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 Jan 2022 18:59:18 +0900 Subject: [PATCH 3/4] Avoid test failures on non-triangle intro tests --- osu.Game.Tests/Visual/Menus/IntroTestScene.cs | 6 +++++- osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs | 1 + osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs | 1 + osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs index 40b072c171..82accceb23 100644 --- a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs +++ b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs @@ -20,6 +20,8 @@ namespace osu.Game.Tests.Visual.Menus [Cached] private OsuLogo logo; + protected abstract bool IntroReliesOnTrack { get; } + protected OsuScreenStack IntroStack; private IntroScreen intro; @@ -103,7 +105,9 @@ namespace osu.Game.Tests.Visual.Menus }); AddUntilStep("wait for menu", () => intro.DidLoadMenu); - AddUntilStep("wait for notification", () => notifications.UnreadCount.Value == 1); + + if (IntroReliesOnTrack) + AddUntilStep("wait for notification", () => notifications.UnreadCount.Value == 1); AddStep("uninstall delegate", () => trackResetDelegate?.Cancel()); } diff --git a/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs b/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs index ffc99185fb..7ad49b5dcd 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs @@ -9,6 +9,7 @@ namespace osu.Game.Tests.Visual.Menus [TestFixture] public class TestSceneIntroCircles : IntroTestScene { + protected override bool IntroReliesOnTrack => false; protected override IntroScreen CreateScreen() => new IntroCircles(); } } diff --git a/osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs b/osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs index 8f01e0321b..abe8936330 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs @@ -9,6 +9,7 @@ namespace osu.Game.Tests.Visual.Menus [TestFixture] public class TestSceneIntroTriangles : IntroTestScene { + protected override bool IntroReliesOnTrack => true; protected override IntroScreen CreateScreen() => new IntroTriangles(); } } diff --git a/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs b/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs index 9081be3dd6..11cea25865 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs @@ -10,6 +10,7 @@ namespace osu.Game.Tests.Visual.Menus [TestFixture] public class TestSceneIntroWelcome : IntroTestScene { + protected override bool IntroReliesOnTrack => false; protected override IntroScreen CreateScreen() => new IntroWelcome(); public override void TestPlayIntro() From 82806d7aebc5a0a2273575f4efdbbd6d1c7c866f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 Jan 2022 21:32:39 +0900 Subject: [PATCH 4/4] Ensure the background is eventually displayed when `IntroTriangles` suspends --- osu.Game/Screens/Menu/IntroTriangles.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 10f940e9de..b6b6bf2ad7 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -93,6 +93,9 @@ namespace osu.Game.Screens.Menu { base.OnSuspending(next); + // ensure the background is shown, even if the TriangleIntroSequence failed to do so. + background.ApplyToBackground(b => b.Show()); + // important as there is a clock attached to a track which will likely be disposed before returning to this screen. intro.Expire(); }