1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-13 20:33:35 +08:00

Add warning display when player loading is paused due to user interaction (#37091)

As touched on in https://github.com/ppy/osu/discussions/37082.

15 minute task fixing a UX which was definitely not as visible as it
should have been.


https://github.com/user-attachments/assets/c7e39f65-e8d4-4b05-b64c-d37fde379f77
This commit is contained in:
Dean Herbert
2026-03-25 22:37:37 +09:00
committed by GitHub
Unverified
parent 4a476e1952
commit dca9396f90
3 changed files with 69 additions and 9 deletions
@@ -43,6 +43,11 @@ Leaderboards may be reset.");
public static LocalisableString QualifiedBeatmapDisclaimerContent => new TranslatableString(getKey(@"qualified_beatmap_disclaimer_content"), @"No performance points will be awarded.
Leaderboards will be reset when the beatmap is ranked.");
/// <summary>
/// "Loading paused..."
/// </summary>
public static LocalisableString LoadingPaused => new TranslatableString(getKey(@"loading_paused"), @"Loading paused...");
private static string getKey(string key) => $@"{prefix}:{key}";
}
}
@@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
@@ -15,6 +16,7 @@ using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play.HUD;
@@ -32,6 +34,7 @@ namespace osu.Game.Screens.Play
private readonly Bindable<IReadOnlyList<Mod>> mods;
private readonly Drawable logoFacade;
private LoadingSpinner loading;
private Drawable blockingLoadLayer;
public IBindable<IReadOnlyList<Mod>> Mods => mods;
@@ -46,6 +49,35 @@ namespace osu.Game.Screens.Play
}
}
private bool userBlocked;
public bool UserBlocked
{
set
{
if (value == userBlocked)
return;
userBlocked = value;
if (userBlocked)
{
using (BeginDelayedSequence(500))
{
blockingLoadLayer
// Slight delay to avoid this flashing briefly during multiplayer load and other scenarios where
// load may be blocked for a short period.
.FadeIn(300, Easing.Out)
.Then()
.FadeTo(0.6f, 1000, Easing.In)
.Loop();
}
}
else
blockingLoadLayer.FadeOut(500, Easing.OutQuint);
}
}
public BeatmapMetadataDisplay(IWorkingBeatmap beatmap, Bindable<IReadOnlyList<Mod>> mods, Drawable logoFacade)
{
this.beatmap = beatmap;
@@ -61,7 +93,7 @@ namespace osu.Game.Screens.Play
private StarRatingDisplay starRatingDisplay;
[BackgroundDependencyLoader]
private void load(BeatmapDifficultyCache difficultyCache)
private void load(BeatmapDifficultyCache difficultyCache, OsuColour colours)
{
var metadata = beatmap.BeatmapInfo.Metadata;
@@ -117,7 +149,28 @@ namespace osu.Game.Screens.Play
loading = new LoadingLayer(dimBackground: true)
{
BlockPositionalInput = false,
}
},
blockingLoadLayer = new Container
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
Children = new Drawable[]
{
new Box
{
Colour = colours.PinkDarker,
Alpha = 0.5f,
RelativeSizeAxes = Axes.Both,
},
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.Style.Heading2,
Text = PlayerLoaderStrings.LoadingPaused
}
}
},
}
},
versionFlow = new FillFlowContainer
+9 -7
View File
@@ -120,13 +120,6 @@ namespace osu.Game.Screens.Play
}
}
private bool readyForPush =>
!playerConsumed
// don't push unless the player is completely loaded
&& CurrentPlayer?.LoadState == LoadState.Ready
// don't push unless the player is ready to start gameplay
&& ReadyForGameplay;
protected virtual bool ReadyForGameplay =>
// not ready if the user is hovering one of the panes (logo is excluded), unless they are idle.
(IsHovered || osuLogo?.IsHovered == true || idleTracker.IsIdle.Value)
@@ -490,6 +483,8 @@ namespace osu.Game.Screens.Play
if (!this.IsCurrentScreen())
return;
MetadataInfo.UserBlocked = !ReadyForGameplay && CurrentPlayer?.LoadState == LoadState.Ready;
// We need to perform this check here rather than in OnHover as any number of children of VisualSettings
// may also be handling the hover events.
if (inputManager.HoveredDrawables.Contains(VisualSettings) || QuickRestart)
@@ -654,6 +649,13 @@ namespace osu.Game.Screens.Play
if (!this.IsCurrentScreen()) return;
bool readyForPush =
!playerConsumed
// don't push unless the player is completely loaded
&& CurrentPlayer?.LoadState == LoadState.Ready
// don't push unless the player is ready to start gameplay
&& ReadyForGameplay;
if (!readyForPush)
{
// as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce