1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-30 12:50:24 +08:00
Files
osu-lazer/osu.Game/Screens/Backgrounds/EditorBackgroundScreen.cs
T
Dean Herbert 95648a3d27 Fix editor background taking too long to load with certain storyboards (#37038)
TL;DR the clock was being set too late, causing more transforms to be
created than necessary.

This solves the issue by way of a refactor (sorry). Overall this should
simplify handling of things as more of the logic is shared with the
known good-state `BeatmapBackgroundWithStoryboard`.

I did try without a refactor (just delaying the creation until the clock
arrives) but this version made more sense because background generally
expect to do their main load in BDL to aid in smooth transitions. And we
can't get the clock by there. (although arguably we could just use a
similar method to `BeatmapBackgroundWithStoryboard` and forego using the
editor clock).

Of note, I removed the black background overdraw hack. There are edge
cases where it will lead to weird transitions, but these are far and few
between. Basically you need a storyboard which sets the flag to hide the
beatmap background and has transparency in it. This is no longer as
flagrantly bad as things used to be (which led to the inline fix) as far
as I can tell, but feel free to prove me wrong. If this is a blocker
I'll probably just add a permanent black box (which does fix this).

Closes #36875.
2026-03-23 09:26:34 +01:00

125 lines
4.5 KiB
C#

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Threading;
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.Screens;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Screens.Edit;
using osuTK.Graphics;
namespace osu.Game.Screens.Backgrounds
{
public partial class EditorBackgroundScreen : BackgroundScreen
{
private readonly Container dimContainer;
private CancellationTokenSource? cancellationTokenSource;
private Bindable<float> dimLevel = null!;
private Bindable<bool> showStoryboard = null!;
private BeatmapBackgroundWithStoryboard? background;
private readonly Container content;
private readonly Box blackBox;
// We retrieve IBindable<WorkingBeatmap> from our dependency cache instead of passing WorkingBeatmap directly into EditorBackgroundScreen.
// Otherwise, DummyWorkingBeatmap will be erroneously passed in whenever creating a new beatmap (since the Schedule() in the Editor that populates
// a new WorkingBeatmap with correct values generally runs after EditorBackgroundScreen is created), which causes any background changes to not be displayed.
[Resolved]
private IBindable<WorkingBeatmap> beatmap { get; set; } = null!;
public EditorBackgroundScreen(EditorBeatmap editorBeatmap)
{
InternalChild = dimContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
// This adds overdraw but makes transitions not suck.
// There's probably a better way to do this, but it's high effort.
blackBox = new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
},
content = new EditorSkinProvidingContainer(editorBeatmap)
{
RelativeSizeAxes = Axes.Both,
},
},
};
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
dimLevel = config.GetBindable<float>(OsuSetting.EditorDim);
showStoryboard = config.GetBindable<bool>(OsuSetting.EditorShowStoryboard);
content.Child = createContent();
updateState(withAnimation: false);
}
protected override void LoadComplete()
{
base.LoadComplete();
dimLevel.BindValueChanged(_ => dimContainer.FadeColour(OsuColour.Gray(1 - dimLevel.Value), 500, Easing.OutQuint), true);
showStoryboard.BindValueChanged(_ => updateState());
updateState(withAnimation: false);
}
public override void OnEntering(ScreenTransitionEvent e)
{
base.OnEntering(e);
blackBox.LifetimeEnd = LatestTransformEndTime;
}
public override bool OnExiting(ScreenExitEvent e)
{
// The storyboard will do weird things with clock time changing on exit, so let's just hide it instead.
background?.UnloadStoryboard();
return base.OnExiting(e);
}
public void RefreshBackgroundAsync()
{
cancellationTokenSource?.Cancel();
LoadComponentAsync(createContent(), loaded =>
{
content.Child = loaded;
updateState(withAnimation: false);
}, (cancellationTokenSource = new CancellationTokenSource()).Token);
}
private Drawable createContent() => background = new BeatmapBackgroundWithStoryboard(beatmap.Value)
{
RelativeSizeAxes = Axes.Both,
StoryboardLoaded = () => updateState(withAnimation: false)
};
private void updateState(bool withAnimation = true)
{
background?.Storyboard.FadeTo(showStoryboard.Value ? 1 : 0, withAnimation ? 500 : 0, Easing.OutQuint);
}
public override bool Equals(BackgroundScreen? other)
{
if (other is not EditorBackgroundScreen otherBeatmapBackground)
return false;
return base.Equals(other) && beatmap == otherBeatmapBackground.beatmap;
}
}
}