1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-17 08:02:38 +08:00
Files
osu-lazer/osu.Game/Screens/SelectV2/BeatmapDetailsArea.cs
T
Bartłomiej Dach d176ce7916 Ensure scores are re-fetched with correct criteria on re-entering song select
Closes https://github.com/ppy/osu/issues/34445.

The primary issue is that song select is the only one that supports
non-score sort mode, and therefore if any other component changes the
sort mode in a way opaque to song select to score, then song select will
lose the sort mode because it's using the global leaderboard manager's
state which will contain scores sorted by total.

Notably, the bug this is fixing requires specific circumstances. For
instance, it is not enough to just *start gameplay* for the bug to
manifest, because starting gameplay causes a working beatmap refetch:

https://github.com/ppy/osu/blob/4b73afd1957a9161e2956fc4191c8114d9958372/osu.Game/Screens/SelectV2/SongSelect.cs#L456-L457

which will trigger a *delayed schedule refetch* of the scores:

https://github.com/ppy/osu/blob/d2d3d14f1572ff8fc68fd01ea43c2ef68b5882fa/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs#L235-L253

and because the refetch is thusly delayed, there's a very high chance it
*will not run before the screen is resumed* because the wedge will not
have its scheduler run until that point in time.

This conundrum is also because there is no test coverage for this,
because the above makes test coverage setup rather annoying.
2025-07-31 10:09:07 +02:00

108 lines
3.2 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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.SelectV2
{
/// <summary>
/// The left portion of the song select screen which houses the metadata or leaderboards wedge, along with controls
/// to switch between them and adjust specifics.
/// </summary>
public partial class BeatmapDetailsArea : VisibilityContainer
{
private Header header = null!;
private Container contentContainer = null!;
public BeatmapDetailsArea()
{
RelativeSizeAxes = Axes.X;
}
[BackgroundDependencyLoader]
private void load()
{
const float header_height = 35f;
InternalChildren = new Drawable[]
{
new ShearAligningWrapper(header = new Header
{
Shear = -OsuGame.SHEAR,
RelativeSizeAxes = Axes.X,
Height = header_height,
}),
new ShearAligningWrapper(contentContainer = new Container
{
Shear = -OsuGame.SHEAR,
Padding = new MarginPadding { Top = header_height },
RelativeSizeAxes = Axes.Both,
})
{
Depth = 1f,
},
};
}
protected override void LoadComplete()
{
base.LoadComplete();
header.Type.BindValueChanged(_ => updateDisplay(), true);
}
protected override void PopIn()
{
this.MoveToX(0, SongSelect.ENTER_DURATION, Easing.OutQuint)
.FadeIn(SongSelect.ENTER_DURATION / 3, Easing.In);
}
protected override void PopOut()
{
this.MoveToX(-150, SongSelect.ENTER_DURATION, Easing.OutQuint)
.FadeOut(SongSelect.ENTER_DURATION / 3, Easing.In);
}
private Drawable? currentContent;
private void updateDisplay()
{
if (currentContent != null)
{
currentContent.Hide();
currentContent.Expire();
}
switch (header.Type.Value)
{
default:
case Header.Selection.Details:
currentContent = new BeatmapMetadataWedge();
break;
case Header.Selection.Ranking:
currentContent = new BeatmapLeaderboardWedge
{
Scope = { BindTarget = header.Scope },
Sorting = { BindTarget = header.Sorting },
FilterBySelectedMods = { BindTarget = header.FilterBySelectedMods },
};
break;
}
contentContainer.Add(currentContent);
currentContent.Show();
}
public void Refresh()
{
if (currentContent is BeatmapLeaderboardWedge leaderboardWedge)
leaderboardWedge.RefetchScores();
}
}
}