diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs index 858c314904..17d31634fc 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Screens.Select.Filter; +using osu.Game.Screens.SelectV2; namespace osu.Game.Tests.Visual.SongSelectV2 { @@ -47,25 +48,42 @@ namespace osu.Game.Tests.Visual.SongSelectV2 AddBeatmaps(10, 3, true); WaitForDrawablePanels(); + GroupDefinition? expanded = null; + + for (int i = 0; i < 2; i++) + { + nextRandom(); + expanded ??= storeExpandedGroup(); + + ensureRandomDidNotRepeat(); + checkExpandedGroupUnchanged(); + } + nextRandom(); - ensureRandomDidNotRepeat(); - nextRandom(); - ensureRandomDidNotRepeat(); - nextRandom(); - ensureRandomDidNotRepeat(); + ensureRandomDidRepeat(); + checkExpandedGroupUnchanged(); prevRandom(); checkRewindCorrectSet(); + checkExpandedGroupUnchanged(); prevRandom(); checkRewindCorrectSet(); + checkExpandedGroupUnchanged(); nextRandom(); ensureRandomDidNotRepeat(); + checkExpandedGroupUnchanged(); nextRandom(); - ensureRandomDidNotRepeat(); + ensureRandomDidRepeat(); + checkExpandedGroupUnchanged(); - nextRandom(); - AddAssert("ensure repeat", () => BeatmapSetRequestedSelections.Contains(Carousel.SelectedBeatmapSet!)); + GroupDefinition? storeExpandedGroup() + { + AddStep("store open group", () => expanded = Carousel.ExpandedGroup); + return null; + } + + void checkExpandedGroupUnchanged() => AddAssert("expanded did not change", () => Carousel.ExpandedGroup, () => Is.EqualTo(expanded)); } /// @@ -76,28 +94,47 @@ namespace osu.Game.Tests.Visual.SongSelectV2 { SortAndGroupBy(SortMode.Difficulty, GroupMode.Difficulty); - AddBeatmaps(10, 3, true); + AddBeatmaps(3, 3, true); WaitForDrawablePanels(); + GroupDefinition? expanded = null; + + for (int i = 0; i < 3; i++) + { + nextRandom(); + expanded ??= storeExpandedGroup(); + + ensureRandomDidNotRepeat(); + checkExpandedGroupUnchanged(); + } + nextRandom(); - ensureRandomDidNotRepeat(); - nextRandom(); - ensureRandomDidNotRepeat(); - nextRandom(); - ensureRandomDidNotRepeat(); + ensureRandomDidRepeat(); + checkExpandedGroupUnchanged(); prevRandom(); checkRewindCorrectSet(); + checkExpandedGroupUnchanged(); + prevRandom(); checkRewindCorrectSet(); + checkExpandedGroupUnchanged(); nextRandom(); ensureRandomDidNotRepeat(); - nextRandom(); - ensureRandomDidNotRepeat(); + checkExpandedGroupUnchanged(); nextRandom(); - AddAssert("ensure repeat", () => BeatmapSetRequestedSelections.Contains(Carousel.SelectedBeatmapSet!)); + ensureRandomDidRepeat(); + checkExpandedGroupUnchanged(); + + GroupDefinition? storeExpandedGroup() + { + AddStep("store open group", () => expanded = Carousel.ExpandedGroup); + return null; + } + + void checkExpandedGroupUnchanged() => AddAssert("expanded did not change", () => Carousel.ExpandedGroup, () => Is.EqualTo(expanded)); } [Test] @@ -174,6 +211,9 @@ namespace osu.Game.Tests.Visual.SongSelectV2 private void nextRandom() => AddStep("select random next", () => Carousel.NextRandom()); + private void ensureRandomDidRepeat() => + AddAssert("did repeat", () => BeatmapSetRequestedSelections.Distinct().Count(), () => Is.LessThan(BeatmapSetRequestedSelections.Count)); + private void ensureRandomDidNotRepeat() => AddAssert("no repeats", () => BeatmapSetRequestedSelections.Distinct().Count(), () => Is.EqualTo(BeatmapSetRequestedSelections.Count)); diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index 24092b8ecd..077a0fb9f8 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -634,6 +634,26 @@ namespace osu.Game.Screens.SelectV2 // This is the fastest way to retrieve sets for randomisation. ICollection visibleSets = grouping.SetItems.Keys; + if (ExpandedGroup != null) + { + // In the case of grouping, users expect random to only operate on the expanded group. + // This is going to incur some overhead as we don't have a group-beatmapset mapping currently. + // + // If this becomes an issue, we could either store a mapping, or run the random algorithm many times + // using the `SetItems` method until we get a group HIT. + if (grouping.BeatmapSetsGroupedTogether) + visibleSets = grouping.GroupItems[ExpandedGroup].Select(i => i.Model).OfType().ToArray(); + else + { + // Note that this is probably not correct in all cases. + // When we aren't grouping sets together, we might want to randomise by beatmaps, not sets. + // + // Imagine the scenario where a single beatmap set has multiple difficulties in the same difficulty grouping, where this + // would always choose the set's user recommended difficulty rather than the visible ones. + visibleSets = grouping.GroupItems[ExpandedGroup].Select(i => i.Model).OfType().Select(b => b.BeatmapSet!).Distinct().ToArray(); + } + } + if (CurrentSelection is BeatmapInfo beatmapInfo) { randomSelectedBeatmaps.Add(beatmapInfo);