1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 15:47:26 +08:00

Split out difficulties in beatmap carousel in a bit of a hacky way

Seems like the simplest path forward for now, without a full rewrite.
This commit is contained in:
Dean Herbert 2023-08-22 17:31:19 +09:00
parent 71ec29041b
commit 290d18ad69
2 changed files with 65 additions and 22 deletions

View File

@ -78,6 +78,8 @@ namespace osu.Game.Screens.Select
private CarouselBeatmapSet? selectedBeatmapSet;
private IEnumerable<BeatmapSetInfo> originalBeatmapSetsDetached = Enumerable.Empty<BeatmapSetInfo>();
/// <summary>
/// Raised when the <see cref="SelectedBeatmapInfo"/> is changed.
/// </summary>
@ -127,13 +129,29 @@ namespace osu.Game.Screens.Select
private void loadBeatmapSets(IEnumerable<BeatmapSetInfo> beatmapSets)
{
originalBeatmapSetsDetached = beatmapSets.Detach();
CarouselRoot newRoot = new CarouselRoot(this);
newRoot.AddItems(beatmapSets.Select(s => createCarouselSet(s.Detach())).OfType<CarouselBeatmapSet>());
if (beatmapsSplitOut)
{
var carouselBeatmapSets = originalBeatmapSetsDetached.SelectMany(s => s.Beatmaps).Select(b =>
{
var set = new BeatmapSetInfo(new[] { b });
return createCarouselSet(set);
}).OfType<CarouselBeatmapSet>();
newRoot.AddItems(carouselBeatmapSets);
}
else
{
var carouselBeatmapSets = originalBeatmapSetsDetached.Select(createCarouselSet).OfType<CarouselBeatmapSet>();
newRoot.AddItems(carouselBeatmapSets);
}
root = newRoot;
if (selectedBeatmapSet != null && !beatmapSets.Contains(selectedBeatmapSet.BeatmapSet))
if (selectedBeatmapSet != null && !originalBeatmapSetsDetached.Contains(selectedBeatmapSet.BeatmapSet))
selectedBeatmapSet = null;
Scroll.Clear(false);
@ -330,8 +348,8 @@ namespace osu.Game.Screens.Select
// Only require to action here if the beatmap is missing.
// This avoids processing these events unnecessarily when new beatmaps are imported, for example.
if (root.BeatmapSetsByID.TryGetValue(beatmapSet.ID, out var existingSet)
&& existingSet.BeatmapSet.Beatmaps.All(b => b.ID != beatmapInfo.ID))
if (root.BeatmapSetsByID.TryGetValue(beatmapSet.ID, out var existingSets)
&& existingSets.SelectMany(s => s.Beatmaps).All(b => b.BeatmapInfo.ID != beatmapInfo.ID))
{
UpdateBeatmapSet(beatmapSet.Detach());
}
@ -345,15 +363,18 @@ namespace osu.Game.Screens.Select
private void removeBeatmapSet(Guid beatmapSetID) => Schedule(() =>
{
if (!root.BeatmapSetsByID.TryGetValue(beatmapSetID, out var existingSet))
if (!root.BeatmapSetsByID.TryGetValue(beatmapSetID, out var existingSets))
return;
foreach (var beatmap in existingSet.Beatmaps)
foreach (var set in existingSets)
{
foreach (var beatmap in set.Beatmaps)
randomSelectedBeatmaps.Remove(beatmap);
previouslyVisitedRandomSets.Remove(set);
previouslyVisitedRandomSets.Remove(existingSet);
root.RemoveItem(set);
}
root.RemoveItem(existingSet);
itemsCache.Invalidate();
if (!Scroll.UserScrolling)
@ -371,13 +392,16 @@ namespace osu.Game.Screens.Select
previouslySelectedID = selectedBeatmap?.BeatmapInfo.ID;
var newSet = createCarouselSet(beatmapSet);
var removedSet = root.RemoveChild(beatmapSet.ID);
var removedSets = root.RemoveChild(beatmapSet.ID);
foreach (var removedSet in removedSets)
{
// If we don't remove this here, it may remain in a hidden state until scrolled off screen.
// Doesn't really affect anything during actual user interaction, but makes testing annoying.
var removedDrawable = Scroll.FirstOrDefault(c => c.Item == removedSet);
if (removedDrawable != null)
expirePanelImmediately(removedDrawable);
}
if (newSet != null)
{
@ -632,6 +656,8 @@ namespace osu.Game.Screens.Select
applyActiveCriteria(debounce);
}
private bool beatmapsSplitOut;
private void applyActiveCriteria(bool debounce, bool alwaysResetScrollPosition = true)
{
PendingFilter?.Cancel();
@ -652,6 +678,13 @@ namespace osu.Game.Screens.Select
{
PendingFilter = null;
if (activeCriteria.SplitOutDifficulties != beatmapsSplitOut)
{
beatmapsSplitOut = activeCriteria.SplitOutDifficulties;
loadBeatmapSets(originalBeatmapSetsDetached);
return;
}
root.Filter(activeCriteria);
itemsCache.Invalidate();
@ -1055,7 +1088,7 @@ namespace osu.Game.Screens.Select
// May only be null during construction (State.Value set causes PerformSelection to be triggered).
private readonly BeatmapCarousel? carousel;
public readonly Dictionary<Guid, CarouselBeatmapSet> BeatmapSetsByID = new Dictionary<Guid, CarouselBeatmapSet>();
public readonly Dictionary<Guid, List<CarouselBeatmapSet>> BeatmapSetsByID = new Dictionary<Guid, List<CarouselBeatmapSet>>();
public CarouselRoot(BeatmapCarousel carousel)
{
@ -1069,20 +1102,25 @@ namespace osu.Game.Screens.Select
public override void AddItem(CarouselItem i)
{
CarouselBeatmapSet set = (CarouselBeatmapSet)i;
BeatmapSetsByID.Add(set.BeatmapSet.ID, set);
if (BeatmapSetsByID.TryGetValue(set.BeatmapSet.ID, out var sets))
sets.Add(set);
else
BeatmapSetsByID.Add(set.BeatmapSet.ID, new List<CarouselBeatmapSet> { set });
base.AddItem(i);
}
public CarouselBeatmapSet? RemoveChild(Guid beatmapSetID)
public IEnumerable<CarouselBeatmapSet> RemoveChild(Guid beatmapSetID)
{
if (BeatmapSetsByID.TryGetValue(beatmapSetID, out var carouselBeatmapSet))
if (BeatmapSetsByID.TryGetValue(beatmapSetID, out var carouselBeatmapSets))
{
RemoveItem(carouselBeatmapSet);
return carouselBeatmapSet;
foreach (var set in carouselBeatmapSets)
RemoveItem(set);
return carouselBeatmapSets;
}
return null;
return Enumerable.Empty<CarouselBeatmapSet>();
}
public override void RemoveItem(CarouselItem i)

View File

@ -19,6 +19,11 @@ namespace osu.Game.Screens.Select
public GroupMode Group;
public SortMode Sort;
/// <summary>
/// Whether the display of beatmap sets should be split apart per-difficulty for the current criteria.
/// </summary>
public bool SplitOutDifficulties => Sort == SortMode.Difficulty;
public BeatmapSetInfo? SelectedBeatmapSet;
public OptionalRange<double> StarDifficulty;