mirror of
https://github.com/ppy/osu.git
synced 2026-05-30 16:20:25 +08:00
Merge pull request #16710 from peppy/add-intro-playback-safety
Add failsafe to `IntroScreen` to stop users with incorrect audio configuration getting stuck
This commit is contained in:
@@ -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;
|
||||
@@ -18,10 +20,17 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
[Cached]
|
||||
private OsuLogo logo;
|
||||
|
||||
protected abstract bool IntroReliesOnTrack { get; }
|
||||
|
||||
protected OsuScreenStack IntroStack;
|
||||
|
||||
private IntroScreen intro;
|
||||
|
||||
[Cached]
|
||||
private NotificationOverlay notifications;
|
||||
|
||||
private ScheduledDelegate trackResetDelegate;
|
||||
|
||||
protected IntroTestScene()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
@@ -38,6 +47,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 +77,41 @@ 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);
|
||||
|
||||
if (IntroReliesOnTrack)
|
||||
AddUntilStep("wait for notification", () => notifications.UnreadCount.Value == 1);
|
||||
|
||||
AddStep("uninstall delegate", () => trackResetDelegate?.Cancel());
|
||||
}
|
||||
|
||||
protected abstract IntroScreen CreateScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user