mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 07:23:14 +08:00
Merge pull request #26385 from peppy/carousel-thing
Fix beatmap carousel not preloading panels when off-screen
This commit is contained in:
commit
70ba5dd0d3
@ -96,18 +96,19 @@ namespace osu.Game.Screens.Select
|
||||
/// <summary>
|
||||
/// Extend the range to retain already loaded pooled drawables.
|
||||
/// </summary>
|
||||
private const float distance_offscreen_before_unload = 1024;
|
||||
private const float distance_offscreen_before_unload = 2048;
|
||||
|
||||
/// <summary>
|
||||
/// Extend the range to update positions / retrieve pooled drawables outside of visible range.
|
||||
/// </summary>
|
||||
private const float distance_offscreen_to_preload = 512; // todo: adjust this appropriately once we can make set panel contents load while off-screen.
|
||||
private const float distance_offscreen_to_preload = 768;
|
||||
|
||||
/// <summary>
|
||||
/// Whether carousel items have completed asynchronously loaded.
|
||||
/// </summary>
|
||||
public bool BeatmapSetsLoaded { get; private set; }
|
||||
|
||||
[Cached]
|
||||
protected readonly CarouselScrollContainer Scroll;
|
||||
|
||||
private readonly NoResultsPlaceholder noResultsPlaceholder;
|
||||
@ -1251,7 +1252,7 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
}
|
||||
|
||||
protected partial class CarouselScrollContainer : UserTrackingScrollContainer<DrawableCarouselItem>
|
||||
public partial class CarouselScrollContainer : UserTrackingScrollContainer<DrawableCarouselItem>
|
||||
{
|
||||
private bool rightMouseScrollBlocked;
|
||||
|
||||
|
@ -5,11 +5,14 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -46,6 +49,8 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
|
||||
private MenuItem[]? mainMenuItems;
|
||||
|
||||
private double timeSinceUnpool;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager manager { get; set; } = null!;
|
||||
|
||||
@ -54,6 +59,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
base.FreeAfterUse();
|
||||
|
||||
Item = null;
|
||||
timeSinceUnpool = 0;
|
||||
|
||||
ClearTransforms();
|
||||
}
|
||||
@ -92,13 +98,21 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
// algorithm for this is taken from ScrollContainer.
|
||||
// while it doesn't necessarily need to match 1:1, as we are emulating scroll in some cases this feels most correct.
|
||||
Y = (float)Interpolation.Lerp(targetY, Y, Math.Exp(-0.01 * Time.Elapsed));
|
||||
|
||||
loadContentIfRequired();
|
||||
}
|
||||
|
||||
private CancellationTokenSource? loadCancellation;
|
||||
|
||||
protected override void UpdateItem()
|
||||
{
|
||||
loadCancellation?.Cancel();
|
||||
loadCancellation = null;
|
||||
|
||||
base.UpdateItem();
|
||||
|
||||
Content.Clear();
|
||||
Header.Clear();
|
||||
|
||||
beatmapContainer = null;
|
||||
beatmapsLoadTask = null;
|
||||
@ -107,32 +121,8 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
return;
|
||||
|
||||
beatmapSet = ((CarouselBeatmapSet)Item).BeatmapSet;
|
||||
|
||||
DelayedLoadWrapper background;
|
||||
DelayedLoadWrapper mainFlow;
|
||||
|
||||
Header.Children = new Drawable[]
|
||||
{
|
||||
// Choice of background image matches BSS implementation (always uses the lowest `beatmap_id` from the set).
|
||||
background = new DelayedLoadWrapper(() => new SetPanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.MinBy(b => b.OnlineID)))
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}, 200)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
mainFlow = new DelayedLoadWrapper(() => new SetPanelContent((CarouselBeatmapSet)Item), 50)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
};
|
||||
|
||||
background.DelayedLoadComplete += fadeContentIn;
|
||||
mainFlow.DelayedLoadComplete += fadeContentIn;
|
||||
}
|
||||
|
||||
private void fadeContentIn(Drawable d) => d.FadeInFromZero(150);
|
||||
|
||||
protected override void Deselected()
|
||||
{
|
||||
base.Deselected();
|
||||
@ -190,6 +180,56 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
}
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private BeatmapCarousel.CarouselScrollContainer scrollContainer { get; set; } = null!;
|
||||
|
||||
private void loadContentIfRequired()
|
||||
{
|
||||
Quad containingSsdq = scrollContainer.ScreenSpaceDrawQuad;
|
||||
|
||||
// Using DelayedLoadWrappers would only allow us to load content when on screen, but we want to preload while off-screen
|
||||
// to provide a better user experience.
|
||||
|
||||
// This is tracking time that this drawable is updating since the last pool.
|
||||
// This is intended to provide a debounce so very fast scrolls (from one end to the other of the carousel)
|
||||
// don't cause huge overheads.
|
||||
//
|
||||
// We increase the delay based on distance from centre, so the beatmaps the user is currently looking at load first.
|
||||
float timeUpdatingBeforeLoad = 50 + Math.Abs(containingSsdq.Centre.Y - ScreenSpaceDrawQuad.Centre.Y) / containingSsdq.Height * 100;
|
||||
|
||||
Debug.Assert(Item != null);
|
||||
|
||||
// A load is already in progress if the cancellation token is non-null.
|
||||
if (loadCancellation != null)
|
||||
return;
|
||||
|
||||
timeSinceUnpool += Time.Elapsed;
|
||||
|
||||
// We only trigger a load after this set has been in an updating state for a set amount of time.
|
||||
if (timeSinceUnpool <= timeUpdatingBeforeLoad)
|
||||
return;
|
||||
|
||||
loadCancellation = new CancellationTokenSource();
|
||||
|
||||
LoadComponentsAsync(new CompositeDrawable[]
|
||||
{
|
||||
// Choice of background image matches BSS implementation (always uses the lowest `beatmap_id` from the set).
|
||||
new SetPanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.MinBy(b => b.OnlineID)))
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new SetPanelContent((CarouselBeatmapSet)Item)
|
||||
{
|
||||
Depth = float.MinValue,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
}, drawables =>
|
||||
{
|
||||
Header.AddRange(drawables);
|
||||
drawables.ForEach(d => d.FadeInFromZero(150));
|
||||
}, loadCancellation.Token);
|
||||
}
|
||||
|
||||
private void updateBeatmapYPositions()
|
||||
{
|
||||
if (beatmapContainer == null)
|
||||
|
Loading…
Reference in New Issue
Block a user