mirror of
https://github.com/ppy/osu.git
synced 2026-06-07 17:24:10 +08:00
Merge branch 'master' into online-lookups-on-reenter
This commit is contained in:
@@ -181,7 +181,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
AddUntilStep("beatmap in song select", () =>
|
||||
{
|
||||
var songSelect = (SoloSongSelect)Game.ScreenStack.CurrentScreen;
|
||||
return songSelect.ChildrenOfType<BeatmapCarousel>().Single().GetCarouselItems()!.Any(i => i.Model is BeatmapSetInfo bsi && bsi.MatchesOnlineID(getImport()));
|
||||
return songSelect.ChildrenOfType<BeatmapCarousel>().Single().GetCarouselItems()!.Any(i => i.Model is GroupedBeatmapSet gbs && gbs.BeatmapSet.MatchesOnlineID(getImport()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
];
|
||||
|
||||
var results = await runGrouping(GroupMode.None, beatmapSets);
|
||||
Assert.That(results.Select(r => r.Model).OfType<BeatmapSetInfo>(), Is.EquivalentTo(beatmapSets));
|
||||
Assert.That(results.Select(r => r.Model).OfType<GroupedBeatmapSet>().Select(groupedSet => groupedSet.BeatmapSet), Is.EquivalentTo(beatmapSets));
|
||||
Assert.That(results.Select(r => r.Model).OfType<BeatmapInfo>(), Is.EquivalentTo(allBeatmaps));
|
||||
assertTotal(results, beatmapSets.Count + allBeatmaps.Length);
|
||||
}
|
||||
@@ -74,11 +74,11 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
addBeatmapSet(applyBeatmap('_'), beatmapSets, out var underscoreBeatmap);
|
||||
|
||||
var results = await runGrouping(mode, beatmapSets);
|
||||
assertGroup(results, 0, "0-9", new[] { fiveBeatmap, fourBeatmap }, ref total);
|
||||
assertGroup(results, 1, "A", new[] { aBeatmap }, ref total);
|
||||
assertGroup(results, 2, "F", new[] { fBeatmap }, ref total);
|
||||
assertGroup(results, 3, "Z", new[] { zBeatmap }, ref total);
|
||||
assertGroup(results, 4, "Other", new[] { dashBeatmap, underscoreBeatmap }, ref total);
|
||||
assertGroup(results, 0, "0-9", fiveBeatmap.Beatmaps.Concat(fourBeatmap.Beatmaps), ref total);
|
||||
assertGroup(results, 1, "A", aBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 2, "F", fBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 3, "Z", zBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 4, "Other", dashBeatmap.Beatmaps.Concat(underscoreBeatmap.Beatmaps), ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -115,12 +115,12 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
addBeatmapSet(s => s.DateAdded = DateTimeOffset.Now.AddMonths(-2).AddDays(-3), beatmapSets, out var twoMonthsAgoBeatmap);
|
||||
|
||||
var results = await runGrouping(GroupMode.DateAdded, beatmapSets);
|
||||
assertGroup(results, 0, "Today", new[] { todayBeatmap }, ref total);
|
||||
assertGroup(results, 1, "Yesterday", new[] { yesterdayBeatmap }, ref total);
|
||||
assertGroup(results, 2, "Last week", new[] { lastWeekBeatmap }, ref total);
|
||||
assertGroup(results, 3, "Last month", new[] { lastMonthBeatmap }, ref total);
|
||||
assertGroup(results, 4, "1 month ago", new[] { oneMonthAgoBeatmap }, ref total);
|
||||
assertGroup(results, 5, "2 months ago", new[] { twoMonthsAgoBeatmap }, ref total);
|
||||
assertGroup(results, 0, "Today", todayBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 1, "Yesterday", yesterdayBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 2, "Last week", lastWeekBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 3, "Last month", lastMonthBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 4, "1 month ago", oneMonthAgoBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 5, "2 months ago", twoMonthsAgoBeatmap.Beatmaps, ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -139,13 +139,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
addBeatmapSet(applyLastPlayed(null), beatmapSets, out var neverBeatmap);
|
||||
|
||||
var results = await runGrouping(GroupMode.LastPlayed, beatmapSets);
|
||||
assertGroup(results, 0, "Today", new[] { todayBeatmap }, ref total);
|
||||
assertGroup(results, 1, "Yesterday", new[] { yesterdayBeatmap }, ref total);
|
||||
assertGroup(results, 2, "Last week", new[] { lastWeekBeatmap }, ref total);
|
||||
assertGroup(results, 3, "Last month", new[] { lastMonthBeatmap }, ref total);
|
||||
assertGroup(results, 4, "1 month ago", new[] { oneMonthAgoBeatmap }, ref total);
|
||||
assertGroup(results, 5, "2 months ago", new[] { twoMonthsBeatmap }, ref total);
|
||||
assertGroup(results, 6, "Never", new[] { neverBeatmap }, ref total);
|
||||
assertGroup(results, 0, "Today", todayBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 1, "Yesterday", yesterdayBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 2, "Last week", lastWeekBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 3, "Last month", lastMonthBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 4, "1 month ago", oneMonthAgoBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 5, "2 months ago", twoMonthsBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 6, "Never", neverBeatmap.Beatmaps, ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -162,7 +162,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
var results = await runGrouping(GroupMode.LastPlayed, beatmapSets);
|
||||
int total = 0;
|
||||
|
||||
assertGroup(results, 0, "Today", new[] { set }, ref total);
|
||||
assertGroup(results, 0, "Today", [set.Beatmaps[2]], ref total);
|
||||
assertGroup(results, 1, "Never", [set.Beatmaps[0], set.Beatmaps[1]], ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -176,8 +177,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
var results = await runGrouping(GroupMode.LastPlayed, beatmapSets);
|
||||
int total = 0;
|
||||
|
||||
assertGroup(results, 0, "Over 5 months ago", new[] { overFiveMonthsBeatmap }, ref total);
|
||||
assertGroup(results, 1, "Never", new[] { neverBeatmap }, ref total);
|
||||
assertGroup(results, 0, "Over 5 months ago", overFiveMonthsBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 1, "Never", neverBeatmap.Beatmaps, ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -207,14 +208,14 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
addBeatmapSet(s => s.Status = BeatmapOnlineStatus.LocallyModified, beatmapSets, out var localBeatmap);
|
||||
|
||||
var results = await runGrouping(GroupMode.RankedStatus, beatmapSets);
|
||||
assertGroup(results, 0, "Ranked", new[] { rankedBeatmap, approvedBeatmap }, ref total);
|
||||
assertGroup(results, 1, "Qualified", new[] { qualifiedBeatmap }, ref total);
|
||||
assertGroup(results, 2, "WIP", new[] { wipBeatmap }, ref total);
|
||||
assertGroup(results, 3, "Pending", new[] { pendingBeatmap }, ref total);
|
||||
assertGroup(results, 4, "Graveyard", new[] { graveyardBeatmap }, ref total);
|
||||
assertGroup(results, 5, "Local", new[] { localBeatmap }, ref total);
|
||||
assertGroup(results, 6, "Unknown", new[] { noneBeatmap }, ref total);
|
||||
assertGroup(results, 7, "Loved", new[] { lovedBeatmap }, ref total);
|
||||
assertGroup(results, 0, "Ranked", rankedBeatmap.Beatmaps.Concat(approvedBeatmap.Beatmaps), ref total);
|
||||
assertGroup(results, 1, "Qualified", qualifiedBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 2, "WIP", wipBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 3, "Pending", pendingBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 4, "Graveyard", graveyardBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 5, "Local", localBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 6, "Unknown", noneBeatmap.Beatmaps, ref total);
|
||||
assertGroup(results, 7, "Loved", lovedBeatmap.Beatmaps, ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -240,12 +241,12 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
addBeatmapSet(applyBPM(330), beatmapSets, out var beatmap330);
|
||||
|
||||
var results = await runGrouping(GroupMode.BPM, beatmapSets);
|
||||
assertGroup(results, 0, "Under 60 BPM", new[] { beatmap30 }, ref total);
|
||||
assertGroup(results, 1, "60 - 70 BPM", new[] { beatmap59, beatmap60 }, ref total);
|
||||
assertGroup(results, 2, "90 - 100 BPM", new[] { beatmap90, beatmap95 }, ref total);
|
||||
assertGroup(results, 3, "270 - 280 BPM", new[] { beatmap269, beatmap270 }, ref total);
|
||||
assertGroup(results, 4, "290 - 300 BPM", new[] { beatmap299 }, ref total);
|
||||
assertGroup(results, 5, "Over 300 BPM", new[] { beatmap300, beatmap330 }, ref total);
|
||||
assertGroup(results, 0, "Under 60 BPM", beatmap30.Beatmaps, ref total);
|
||||
assertGroup(results, 1, "60 - 70 BPM", (beatmap59.Beatmaps.Concat(beatmap60.Beatmaps)), ref total);
|
||||
assertGroup(results, 2, "90 - 100 BPM", (beatmap90.Beatmaps.Concat(beatmap95.Beatmaps)), ref total);
|
||||
assertGroup(results, 3, "270 - 280 BPM", (beatmap269.Beatmaps.Concat(beatmap270.Beatmaps)), ref total);
|
||||
assertGroup(results, 4, "290 - 300 BPM", beatmap299.Beatmaps, ref total);
|
||||
assertGroup(results, 5, "Over 300 BPM", (beatmap300.Beatmaps.Concat(beatmap330.Beatmaps)), ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -272,10 +273,10 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
addBeatmapSet(applyStars(7), beatmapSets, out var beatmap7);
|
||||
|
||||
var results = await runGrouping(GroupMode.Difficulty, beatmapSets);
|
||||
assertGroup(results, 0, "Below 1 Star", new[] { beatmapBelow1 }, ref total);
|
||||
assertGroup(results, 1, "1 Star", new[] { beatmapAbove1, beatmapAlmost2 }, ref total);
|
||||
assertGroup(results, 2, "2 Stars", new[] { beatmap2, beatmapAbove2 }, ref total);
|
||||
assertGroup(results, 3, "7 Stars", new[] { beatmap7 }, ref total);
|
||||
assertGroup(results, 0, "Below 1 Star", beatmapBelow1.Beatmaps, ref total);
|
||||
assertGroup(results, 1, "1 Star", (beatmapAbove1.Beatmaps.Concat(beatmapAlmost2.Beatmaps)), ref total);
|
||||
assertGroup(results, 2, "2 Stars", (beatmap2.Beatmaps.Concat(beatmapAbove2.Beatmaps)), ref total);
|
||||
assertGroup(results, 3, "7 Stars", beatmap7.Beatmaps, ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -304,11 +305,11 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
addBeatmapSet(applyLength(630_000), beatmapSets, out var beatmap10Min30Sec);
|
||||
|
||||
var results = await runGrouping(GroupMode.Length, beatmapSets);
|
||||
assertGroup(results, 0, "1 minute or less", new[] { beatmap30Sec, beatmap1Min }, ref total);
|
||||
assertGroup(results, 1, "2 minutes or less", new[] { beatmap1Min30Sec, beatmap2Min }, ref total);
|
||||
assertGroup(results, 2, "5 minutes or less", new[] { beatmap5Min }, ref total);
|
||||
assertGroup(results, 3, "10 minutes or less", new[] { beatmap6Min, beatmap10Min }, ref total);
|
||||
assertGroup(results, 4, "Over 10 minutes", new[] { beatmap10Min30Sec }, ref total);
|
||||
assertGroup(results, 0, "1 minute or less", (beatmap30Sec.Beatmaps.Concat(beatmap1Min.Beatmaps)), ref total);
|
||||
assertGroup(results, 1, "2 minutes or less", (beatmap1Min30Sec.Beatmaps.Concat(beatmap2Min.Beatmaps)), ref total);
|
||||
assertGroup(results, 2, "5 minutes or less", beatmap5Min.Beatmaps, ref total);
|
||||
assertGroup(results, 3, "10 minutes or less", (beatmap6Min.Beatmaps.Concat(beatmap10Min.Beatmaps)), ref total);
|
||||
assertGroup(results, 4, "Over 10 minutes", beatmap10Min30Sec.Beatmaps, ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -334,10 +335,10 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
addBeatmapSet(s => s.DateRanked = null, beatmapSets, out var beatmapUnranked);
|
||||
|
||||
var results = await runGrouping(GroupMode.DateRanked, beatmapSets);
|
||||
assertGroup(results, 0, "2025", new[] { beatmap2025 }, ref total);
|
||||
assertGroup(results, 1, "2010", new[] { beatmap2010 }, ref total);
|
||||
assertGroup(results, 2, "2007", new[] { beatmapOct2007, beatmapDec2007 }, ref total);
|
||||
assertGroup(results, 3, "Unranked", new[] { beatmapUnranked }, ref total);
|
||||
assertGroup(results, 0, "2025", beatmap2025.Beatmaps, ref total);
|
||||
assertGroup(results, 1, "2010", beatmap2010.Beatmaps, ref total);
|
||||
assertGroup(results, 2, "2007", (beatmapOct2007.Beatmaps.Concat(beatmapDec2007.Beatmaps)), ref total);
|
||||
assertGroup(results, 3, "Unranked", beatmapUnranked.Beatmaps, ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -357,9 +358,9 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
addBeatmapSet(s => s.Beatmaps[0].Metadata.Source = string.Empty, beatmapSets, out var beatmapUnsourced);
|
||||
|
||||
var results = await runGrouping(GroupMode.Source, beatmapSets);
|
||||
assertGroup(results, 0, "Cool Game", new[] { beatmapCoolGame, beatmapCoolGameB }, ref total);
|
||||
assertGroup(results, 1, "Nice Movie", new[] { beatmapNiceMovie }, ref total);
|
||||
assertGroup(results, 2, "Unsourced", new[] { beatmapUnsourced }, ref total);
|
||||
assertGroup(results, 0, "Cool Game", (beatmapCoolGame.Beatmaps.Concat(beatmapCoolGameB.Beatmaps)), ref total);
|
||||
assertGroup(results, 1, "Nice Movie", beatmapNiceMovie.Beatmaps, ref total);
|
||||
assertGroup(results, 2, "Unsourced", beatmapUnsourced.Beatmaps, ref total);
|
||||
assertTotal(results, total);
|
||||
}
|
||||
|
||||
@@ -375,7 +376,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
return await groupingFilter.Run(beatmapSets.SelectMany(s => s.Beatmaps.Select(b => new CarouselItem(b))).ToList(), CancellationToken.None);
|
||||
}
|
||||
|
||||
private static void assertGroup(List<CarouselItem> items, int index, string expectedTitle, IEnumerable<BeatmapSetInfo> expectedBeatmapSets, ref int totalItems)
|
||||
private static void assertGroup(List<CarouselItem> items, int index, string expectedTitle, IEnumerable<BeatmapInfo> expectedBeatmaps, ref int totalItems)
|
||||
{
|
||||
var groupItem = items.Where(i => i.Model is GroupDefinition).ElementAtOrDefault(index);
|
||||
|
||||
@@ -390,7 +391,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
var groupModel = (GroupDefinition)groupItem.Model;
|
||||
|
||||
Assert.That(groupModel.Title, Is.EqualTo(expectedTitle));
|
||||
Assert.That(itemsInGroup.Select(i => i.Model).OfType<BeatmapInfo>(), Is.EquivalentTo(expectedBeatmapSets.SelectMany(bs => bs.Beatmaps)));
|
||||
Assert.That(itemsInGroup.Select(i => i.Model).OfType<BeatmapInfo>(), Is.EquivalentTo(expectedBeatmaps));
|
||||
|
||||
totalItems += itemsInGroup.Count() + 1;
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
|
||||
// Using groupingFilter.SetItems.Count alone doesn't work.
|
||||
// When sorting by difficulty, there can be more than one set panel for the same set displayed.
|
||||
return groupingFilter.SetItems.Sum(s => s.Value.Count(i => i.Model is BeatmapSetInfo));
|
||||
return groupingFilter.SetItems.Sum(s => s.Value.Count(i => i.Model is GroupedBeatmapSet));
|
||||
}, () => Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
public BeatmapInfo? SelectedBeatmapInfo => CurrentSelection as BeatmapInfo;
|
||||
public BeatmapSetInfo? SelectedBeatmapSet => SelectedBeatmapInfo?.BeatmapSet;
|
||||
|
||||
public new BeatmapSetInfo? ExpandedBeatmapSet => base.ExpandedBeatmapSet;
|
||||
public new GroupedBeatmapSet? ExpandedBeatmapSet => base.ExpandedBeatmapSet;
|
||||
public new GroupDefinition? ExpandedGroup => base.ExpandedGroup;
|
||||
|
||||
public TestBeatmapCarousel()
|
||||
|
||||
@@ -396,7 +396,9 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
ApplyToFilterAndWaitForFilter("filter first away", c => c.UserStarDifficulty.Min = 3);
|
||||
|
||||
SelectNextPanel();
|
||||
AddAssert("keyboard selected is first set", () => GetKeyboardSelectedPanel()?.Item?.Model, () => Is.EqualTo(BeatmapSets.First()));
|
||||
AddAssert("keyboard selected is first set",
|
||||
() => (GetKeyboardSelectedPanel()?.Item?.Model as GroupedBeatmapSet)?.BeatmapSet,
|
||||
() => Is.EqualTo(BeatmapSets.First()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -413,7 +415,9 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
ApplyToFilterAndWaitForFilter("filter first away", c => c.UserStarDifficulty.Min = 3);
|
||||
|
||||
SelectPrevPanel();
|
||||
AddAssert("keyboard selected is last set", () => GetKeyboardSelectedPanel()?.Item?.Model, () => Is.EqualTo(BeatmapSets.Last()));
|
||||
AddAssert("keyboard selected is last set",
|
||||
() => (GetKeyboardSelectedPanel()?.Item?.Model as GroupedBeatmapSet)?.BeatmapSet,
|
||||
() => Is.EqualTo(BeatmapSets.Last()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -428,7 +432,9 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
ApplyToFilterAndWaitForFilter("filter last set away", c => c.SearchText = BeatmapSets.First().Metadata.Title);
|
||||
|
||||
SelectPrevPanel();
|
||||
AddAssert("keyboard selected is first set", () => GetKeyboardSelectedPanel()?.Item?.Model, () => Is.EqualTo(BeatmapSets.First()));
|
||||
AddAssert("keyboard selected is first set",
|
||||
() => (GetKeyboardSelectedPanel()?.Item?.Model as GroupedBeatmapSet)?.BeatmapSet,
|
||||
() => Is.EqualTo(BeatmapSets.First()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -444,7 +450,9 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
|
||||
// Single result is automatically selected for us, so we iterate once backwards to the set header.
|
||||
SelectPrevPanel();
|
||||
AddAssert("keyboard selected is second set", () => GetKeyboardSelectedPanel()?.Item?.Model, () => Is.EqualTo(BeatmapSets.Last()));
|
||||
AddAssert("keyboard selected is second set",
|
||||
() => (GetKeyboardSelectedPanel()?.Item?.Model as GroupedBeatmapSet)?.BeatmapSet,
|
||||
() => Is.EqualTo(BeatmapSets.Last()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
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
|
||||
{
|
||||
[TestFixture]
|
||||
public partial class TestSceneBeatmapCarouselSetsSplitApart : BeatmapCarouselTestScene
|
||||
{
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
RemoveAllBeatmaps();
|
||||
CreateCarousel();
|
||||
|
||||
SortAndGroupBy(SortMode.Title, GroupMode.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSetTraversal()
|
||||
{
|
||||
AddBeatmaps(3, splitApart: true);
|
||||
AddBeatmaps(3, splitApart: false);
|
||||
WaitForDrawablePanels();
|
||||
|
||||
SelectNextSet();
|
||||
WaitForSetSelection(set: 0, diff: 0);
|
||||
|
||||
SelectNextSet();
|
||||
WaitForSetSelection(set: 1, diff: 0);
|
||||
|
||||
SelectPrevSet();
|
||||
WaitForSetSelection(set: 0, diff: 0);
|
||||
|
||||
SelectPrevSet();
|
||||
WaitForSetSelection(set: 5, diff: 0);
|
||||
|
||||
SelectPrevSet();
|
||||
SelectPrevSet();
|
||||
SelectPrevSet();
|
||||
WaitForSetSelection(set: 2, diff: 4);
|
||||
AddAssert("only two beatmap panels visible", () => GetVisiblePanels<PanelBeatmap>().Count(), () => Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapTraversal()
|
||||
{
|
||||
AddBeatmaps(3, splitApart: true);
|
||||
AddBeatmaps(3, splitApart: false);
|
||||
WaitForDrawablePanels();
|
||||
|
||||
SelectNextSet();
|
||||
WaitForSetSelection(set: 0, diff: 0);
|
||||
|
||||
SelectNextPanel();
|
||||
WaitForSetSelection(set: 0, diff: 1);
|
||||
|
||||
SelectNextPanel(); // header of set 1 in group 0
|
||||
Select();
|
||||
WaitForSetSelection(set: 1, diff: 0);
|
||||
|
||||
SelectPrevPanel(); // header of set 1 in group 0
|
||||
SelectPrevPanel(); // header of set 0 in group 0
|
||||
Select();
|
||||
WaitForSetSelection(set: 0, diff: 0);
|
||||
|
||||
SelectPrevPanel(); // header of set 0 in group 0
|
||||
SelectPrevPanel(); // header of group 0
|
||||
SelectPrevPanel(); // header of group 2
|
||||
Select();
|
||||
SelectNextPanel(); // header of set 0 in group 2
|
||||
Select();
|
||||
WaitForSetSelection(set: 0, diff: 4);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRandomStaysInGroup()
|
||||
{
|
||||
AddBeatmaps(2, splitApart: false);
|
||||
AddBeatmaps(1, splitApart: true);
|
||||
WaitForDrawablePanels();
|
||||
|
||||
SelectPrevSet();
|
||||
SelectPrevSet();
|
||||
WaitForSetSelection(set: 1);
|
||||
WaitForExpandedGroup(2);
|
||||
|
||||
AddStep("select next random", () => Carousel.NextRandom());
|
||||
WaitForExpandedGroup(2);
|
||||
AddStep("select next random", () => Carousel.NextRandom());
|
||||
WaitForExpandedGroup(2);
|
||||
}
|
||||
|
||||
protected void AddBeatmaps(int count, bool splitApart) => AddStep($"add {count} beatmaps ({(splitApart ? "" : "not ")}split apart)", () =>
|
||||
{
|
||||
var beatmapSets = new List<BeatmapSetInfo>();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var beatmapSet = CreateTestBeatmapSetInfo(6, false);
|
||||
|
||||
for (int j = 0; j < beatmapSet.Beatmaps.Count; j++)
|
||||
{
|
||||
beatmapSet.Beatmaps[j].Length = splitApart ? 30_000 * (j + 1) : 180_000;
|
||||
}
|
||||
|
||||
beatmapSets.Add(beatmapSet);
|
||||
}
|
||||
|
||||
BeatmapSets.AddRange(beatmapSets);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -75,21 +75,21 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
{
|
||||
new PanelBeatmapSet
|
||||
{
|
||||
Item = new CarouselItem(beatmapSet)
|
||||
Item = new CarouselItem(new GroupedBeatmapSet(null, beatmapSet))
|
||||
},
|
||||
new PanelBeatmapSet
|
||||
{
|
||||
Item = new CarouselItem(beatmapSet),
|
||||
Item = new CarouselItem(new GroupedBeatmapSet(null, beatmapSet)),
|
||||
KeyboardSelected = { Value = true }
|
||||
},
|
||||
new PanelBeatmapSet
|
||||
{
|
||||
Item = new CarouselItem(beatmapSet),
|
||||
Item = new CarouselItem(new GroupedBeatmapSet(null, beatmapSet)),
|
||||
Expanded = { Value = true }
|
||||
},
|
||||
new PanelBeatmapSet
|
||||
{
|
||||
Item = new CarouselItem(beatmapSet),
|
||||
Item = new CarouselItem(new GroupedBeatmapSet(null, beatmapSet)),
|
||||
KeyboardSelected = { Value = true },
|
||||
Expanded = { Value = true }
|
||||
},
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
AddAssert("no-collection group present", () =>
|
||||
{
|
||||
var group = grouping.GroupItems.Single(g => g.Key.Title == "Not in collection");
|
||||
return group.Value.Select(i => i.Model).OfType<BeatmapSetInfo>().Single().Equals(beatmapSet);
|
||||
return group.Value.Select(i => i.Model).OfType<GroupedBeatmapSet>().Single().BeatmapSet.Equals(beatmapSet);
|
||||
});
|
||||
|
||||
AddStep("add beatmap to collection", () =>
|
||||
|
||||
@@ -6,6 +6,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Tournament.Components;
|
||||
using osu.Game.Tournament.IPC;
|
||||
using osu.Game.Tournament.Screens.Gameplay;
|
||||
@@ -66,6 +67,6 @@ namespace osu.Game.Tournament.Tests.Screens
|
||||
() => this.ChildrenOfType<TeamScore>().All(score => score.Alpha == (visible ? 1 : 0)));
|
||||
|
||||
private void toggleWarmup()
|
||||
=> AddStep("toggle warmup", () => this.ChildrenOfType<TourneyButton>().First().TriggerClick());
|
||||
=> AddStep("toggle warmup", () => this.ChildrenOfType<LabelledSwitchButton>().First().ChildrenOfType<SwitchButton>().First().TriggerClick());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,9 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
var bindable = (IBindable)property.GetValue(this)!;
|
||||
|
||||
if (bindable.IsDefault)
|
||||
continue;
|
||||
|
||||
string valueText;
|
||||
|
||||
switch (bindable)
|
||||
@@ -69,8 +72,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bindable.IsDefault)
|
||||
yield return (attr.Label, valueText);
|
||||
yield return (attr.Label, valueText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,10 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return ("Roll speed", $"{SpinSpeed.Value:N2} rpm");
|
||||
yield return ("Direction", Direction.Value.GetDescription());
|
||||
if (!SpinSpeed.IsDefault)
|
||||
yield return ("Roll speed", $"{SpinSpeed.Value:N2} rpm");
|
||||
if (!Direction.IsDefault)
|
||||
yield return ("Direction", Direction.Value.GetDescription());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +57,8 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public virtual void Update(Playfield playfield)
|
||||
{
|
||||
playfieldAdjustmentContainer.Rotation = CurrentRotation = (Direction.Value == RotationDirection.Counterclockwise ? -1 : 1) * 360 * (float)(playfield.Time.Current / 60000 * SpinSpeed.Value);
|
||||
playfieldAdjustmentContainer.Rotation =
|
||||
CurrentRotation = (Direction.Value == RotationDirection.Counterclockwise ? -1 : 1) * 360 * (float)(playfield.Time.Current / 60000 * SpinSpeed.Value);
|
||||
}
|
||||
|
||||
public void ApplyToDrawableRuleset(DrawableRuleset<TObject> drawableRuleset)
|
||||
|
||||
@@ -41,7 +41,8 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return ("Speed change", $"{InitialRate.Value:N2}x to {FinalRate.Value:N2}x");
|
||||
if (!InitialRate.IsDefault || !FinalRate.IsDefault)
|
||||
yield return ("Speed change", $"{InitialRate.Value:N2}x to {FinalRate.Value:N2}x");
|
||||
|
||||
if (!AdjustPitch.IsDefault)
|
||||
yield return ("Adjust pitch", AdjustPitch.Value ? "On" : "Off");
|
||||
|
||||
@@ -160,8 +160,8 @@ namespace osu.Game.Rulesets.Objects.Pooling
|
||||
if (!IsPresent)
|
||||
return false;
|
||||
|
||||
bool aliveChanged = base.CheckChildrenLife();
|
||||
aliveChanged |= lifetimeManager.Update(Time.Current - PastLifetimeExtension, Time.Current + FutureLifetimeExtension);
|
||||
bool aliveChanged = lifetimeManager.Update(Time.Current - PastLifetimeExtension, Time.Current + FutureLifetimeExtension);
|
||||
aliveChanged |= base.CheckChildrenLife();
|
||||
return aliveChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
@@ -69,11 +70,11 @@ namespace osu.Game.Screens.SelectV2
|
||||
if (grouping.BeatmapSetsGroupedTogether)
|
||||
{
|
||||
// Give some space around the expanded beatmap set, at the top..
|
||||
if (bottom.Model is BeatmapSetInfo && bottom.IsExpanded)
|
||||
if (bottom.Model is GroupedBeatmapSet && bottom.IsExpanded)
|
||||
return SPACING * 2;
|
||||
|
||||
// ..and the bottom.
|
||||
if (top.Model is BeatmapInfo && bottom.Model is BeatmapSetInfo)
|
||||
if (top.Model is BeatmapInfo && bottom.Model is GroupedBeatmapSet)
|
||||
return SPACING * 2;
|
||||
|
||||
// Beatmap difficulty panels do not overlap with themselves or any other panel.
|
||||
@@ -209,12 +210,12 @@ namespace osu.Game.Screens.SelectV2
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.Model is BeatmapSetInfo beatmapSetInfo)
|
||||
if (item.Model is GroupedBeatmapSet groupedSet)
|
||||
{
|
||||
if (oldItems.Contains(beatmapSetInfo))
|
||||
if (oldItems.Contains(groupedSet.BeatmapSet))
|
||||
return false;
|
||||
|
||||
RequestRecommendedSelection(beatmapSetInfo.Beatmaps);
|
||||
RequestRecommendedSelection(groupedSet.BeatmapSet.Beatmaps);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -285,7 +286,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
protected GroupDefinition? ExpandedGroup { get; private set; }
|
||||
|
||||
protected BeatmapSetInfo? ExpandedBeatmapSet { get; private set; }
|
||||
protected GroupedBeatmapSet? ExpandedBeatmapSet { get; private set; }
|
||||
|
||||
protected override bool ShouldActivateOnKeyboardSelection(CarouselItem item) =>
|
||||
grouping.BeatmapSetsGroupedTogether && item.Model is BeatmapInfo;
|
||||
@@ -313,8 +314,8 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
return;
|
||||
|
||||
case BeatmapSetInfo setInfo:
|
||||
selectRecommendedDifficultyForBeatmapSet(setInfo);
|
||||
case GroupedBeatmapSet groupedSet:
|
||||
selectRecommendedDifficultyForBeatmapSet(groupedSet);
|
||||
return;
|
||||
|
||||
case BeatmapInfo beatmapInfo:
|
||||
@@ -340,7 +341,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
switch (model)
|
||||
{
|
||||
case BeatmapSetInfo:
|
||||
case GroupedBeatmapSet:
|
||||
case GroupDefinition:
|
||||
throw new InvalidOperationException("Groups should never become selected");
|
||||
|
||||
@@ -351,7 +352,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
setExpandedGroup(containingGroup);
|
||||
|
||||
if (grouping.BeatmapSetsGroupedTogether)
|
||||
setExpandedSet(beatmapInfo);
|
||||
setExpandedSet(new GroupedBeatmapSet(containingGroup, beatmapInfo.BeatmapSet!));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -426,10 +427,10 @@ namespace osu.Game.Screens.SelectV2
|
||||
setExpandedGroup(groupForReselection);
|
||||
}
|
||||
|
||||
private void selectRecommendedDifficultyForBeatmapSet(BeatmapSetInfo beatmapSet)
|
||||
private void selectRecommendedDifficultyForBeatmapSet(GroupedBeatmapSet set)
|
||||
{
|
||||
// Selecting a set isn't valid – let's re-select the first visible difficulty.
|
||||
if (grouping.SetItems.TryGetValue(beatmapSet, out var items))
|
||||
if (grouping.SetItems.TryGetValue(set, out var items))
|
||||
{
|
||||
var beatmaps = items.Select(i => i.Model).OfType<BeatmapInfo>();
|
||||
RequestRecommendedSelection(beatmaps);
|
||||
@@ -477,7 +478,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
switch (item.Model)
|
||||
{
|
||||
case BeatmapSetInfo:
|
||||
case GroupedBeatmapSet:
|
||||
return true;
|
||||
|
||||
case BeatmapInfo:
|
||||
@@ -516,11 +517,11 @@ namespace osu.Game.Screens.SelectV2
|
||||
i.IsExpanded = true;
|
||||
break;
|
||||
|
||||
case BeatmapSetInfo set:
|
||||
case GroupedBeatmapSet groupedSet:
|
||||
// Case where there are set headers, header should be visible
|
||||
// and items should use the set's expanded state.
|
||||
i.IsVisible = true;
|
||||
setExpansionStateOfSetItems(set, i.IsExpanded);
|
||||
setExpansionStateOfSetItems(groupedSet, i.IsExpanded);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -550,21 +551,21 @@ namespace osu.Game.Screens.SelectV2
|
||||
}
|
||||
}
|
||||
|
||||
private void setExpandedSet(BeatmapInfo beatmapInfo)
|
||||
private void setExpandedSet(GroupedBeatmapSet set)
|
||||
{
|
||||
if (ExpandedBeatmapSet != null)
|
||||
setExpansionStateOfSetItems(ExpandedBeatmapSet, false);
|
||||
ExpandedBeatmapSet = beatmapInfo.BeatmapSet!;
|
||||
ExpandedBeatmapSet = set;
|
||||
setExpansionStateOfSetItems(ExpandedBeatmapSet, true);
|
||||
}
|
||||
|
||||
private void setExpansionStateOfSetItems(BeatmapSetInfo set, bool expanded)
|
||||
private void setExpansionStateOfSetItems(GroupedBeatmapSet set, bool expanded)
|
||||
{
|
||||
if (grouping.SetItems.TryGetValue(set, out var items))
|
||||
{
|
||||
foreach (var i in items)
|
||||
{
|
||||
if (i.Model is BeatmapSetInfo)
|
||||
if (i.Model is GroupedBeatmapSet)
|
||||
i.IsExpanded = expanded;
|
||||
else
|
||||
i.IsVisible = expanded;
|
||||
@@ -602,7 +603,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
sampleToggleGroup?.Play();
|
||||
return;
|
||||
|
||||
case BeatmapSetInfo:
|
||||
case GroupedBeatmapSet:
|
||||
sampleChangeSet?.Play();
|
||||
return;
|
||||
|
||||
@@ -741,8 +742,8 @@ namespace osu.Game.Screens.SelectV2
|
||||
// it is doing a Replace operation on the list. If it is, then check the local handling in beatmapSetsChanged
|
||||
// before changing matching requirements here.
|
||||
|
||||
if (x is BeatmapSetInfo beatmapSetX && y is BeatmapSetInfo beatmapSetY)
|
||||
return beatmapSetX.Equals(beatmapSetY);
|
||||
if (x is GroupedBeatmapSet groupedSetX && y is GroupedBeatmapSet groupedSetY)
|
||||
return groupedSetX.Equals(groupedSetY);
|
||||
|
||||
if (x is BeatmapInfo beatmapX && y is BeatmapInfo beatmapY)
|
||||
return beatmapX.Equals(beatmapY);
|
||||
@@ -772,7 +773,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
return beatmapPanelPool.Get();
|
||||
|
||||
case BeatmapSetInfo:
|
||||
case GroupedBeatmapSet:
|
||||
return setPanelPool.Get();
|
||||
}
|
||||
|
||||
@@ -882,30 +883,31 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
private bool nextRandomSet()
|
||||
{
|
||||
ICollection<BeatmapSetInfo> visibleSets = ExpandedGroup != null
|
||||
ICollection<GroupedBeatmapSet> visibleSetsUnderGrouping = 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.
|
||||
? grouping.GroupItems[ExpandedGroup].Select(i => i.Model).OfType<BeatmapSetInfo>().ToArray()
|
||||
? grouping.GroupItems[ExpandedGroup].Select(i => i.Model).OfType<GroupedBeatmapSet>().ToArray()
|
||||
// This is the fastest way to retrieve sets for randomisation.
|
||||
: grouping.SetItems.Keys;
|
||||
|
||||
BeatmapSetInfo set;
|
||||
GroupedBeatmapSet set;
|
||||
|
||||
switch (randomAlgorithm.Value)
|
||||
{
|
||||
case RandomSelectAlgorithm.RandomPermutation:
|
||||
{
|
||||
ICollection<BeatmapSetInfo> notYetVisitedSets = visibleSets.Except(previouslyVisitedRandomBeatmaps.Select(b => b.BeatmapSet!)).ToList();
|
||||
ICollection<GroupedBeatmapSet> notYetVisitedSets =
|
||||
visibleSetsUnderGrouping.ExceptBy(previouslyVisitedRandomBeatmaps.Select(b => b.BeatmapSet!), groupedSet => groupedSet.BeatmapSet).ToList();
|
||||
|
||||
if (!notYetVisitedSets.Any())
|
||||
{
|
||||
previouslyVisitedRandomBeatmaps.RemoveAll(b => visibleSets.Contains(b.BeatmapSet!));
|
||||
notYetVisitedSets = visibleSets;
|
||||
previouslyVisitedRandomBeatmaps.RemoveAll(b => visibleSetsUnderGrouping.Any(groupedSet => groupedSet.BeatmapSet.Equals(b.BeatmapSet!)));
|
||||
notYetVisitedSets = visibleSetsUnderGrouping;
|
||||
if (CurrentSelection is BeatmapInfo beatmapInfo)
|
||||
notYetVisitedSets = notYetVisitedSets.Except([beatmapInfo.BeatmapSet!]).ToList();
|
||||
notYetVisitedSets = notYetVisitedSets.ExceptBy([beatmapInfo.BeatmapSet!], groupedSet => groupedSet.BeatmapSet).ToList();
|
||||
}
|
||||
|
||||
if (notYetVisitedSets.Count == 0)
|
||||
@@ -916,7 +918,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
}
|
||||
|
||||
case RandomSelectAlgorithm.Random:
|
||||
set = visibleSets.ElementAt(RNG.Next(visibleSets.Count));
|
||||
set = visibleSetsUnderGrouping.ElementAt(RNG.Next(visibleSetsUnderGrouping.Count));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1013,4 +1015,10 @@ namespace osu.Game.Screens.SelectV2
|
||||
/// Defines a grouping header for a set of carousel items grouped by star difficulty.
|
||||
/// </summary>
|
||||
public record StarDifficultyGroupDefinition(int Order, string Title, StarDifficulty Difficulty) : GroupDefinition(Order, Title);
|
||||
|
||||
/// <summary>
|
||||
/// Used to represent a portion of a <see cref="BeatmapSetInfo"/> under a <see cref="GroupDefinition"/>.
|
||||
/// The purpose of this model is to support splitting beatmap sets apart when the active grouping mode demands it.
|
||||
/// </summary>
|
||||
public record GroupedBeatmapSet([UsedImplicitly] GroupDefinition? Group, BeatmapSetInfo BeatmapSet);
|
||||
}
|
||||
|
||||
@@ -29,21 +29,22 @@ namespace osu.Game.Screens.SelectV2
|
||||
/// <summary>
|
||||
/// Beatmap sets contain difficulties as related panels. This dictionary holds the relationships between set-difficulties to allow expanding them on selection.
|
||||
/// </summary>
|
||||
public IDictionary<BeatmapSetInfo, HashSet<CarouselItem>> SetItems => setMap;
|
||||
public IDictionary<GroupedBeatmapSet, HashSet<CarouselItem>> SetItems => setMap;
|
||||
|
||||
/// <summary>
|
||||
/// Groups contain children which are group-selectable. This dictionary holds the relationships between groups-panels to allow expanding them on selection.
|
||||
/// </summary>
|
||||
public IDictionary<GroupDefinition, HashSet<CarouselItem>> GroupItems => groupMap;
|
||||
|
||||
private Dictionary<BeatmapSetInfo, HashSet<CarouselItem>> setMap = new Dictionary<BeatmapSetInfo, HashSet<CarouselItem>>();
|
||||
private Dictionary<GroupedBeatmapSet, HashSet<CarouselItem>> setMap = new Dictionary<GroupedBeatmapSet, HashSet<CarouselItem>>();
|
||||
private Dictionary<GroupDefinition, HashSet<CarouselItem>> groupMap = new Dictionary<GroupDefinition, HashSet<CarouselItem>>();
|
||||
|
||||
private readonly Func<FilterCriteria> getCriteria;
|
||||
private readonly Func<List<BeatmapCollection>> getCollections;
|
||||
private readonly Func<FilterCriteria, IReadOnlyDictionary<Guid, ScoreRank>> getLocalUserTopRanks;
|
||||
|
||||
public BeatmapCarouselFilterGrouping(Func<FilterCriteria> getCriteria, Func<List<BeatmapCollection>> getCollections, Func<FilterCriteria, IReadOnlyDictionary<Guid, ScoreRank>> getLocalUserTopRanks)
|
||||
public BeatmapCarouselFilterGrouping(Func<FilterCriteria> getCriteria, Func<List<BeatmapCollection>> getCollections,
|
||||
Func<FilterCriteria, IReadOnlyDictionary<Guid, ScoreRank>> getLocalUserTopRanks)
|
||||
{
|
||||
this.getCriteria = getCriteria;
|
||||
this.getCollections = getCollections;
|
||||
@@ -55,7 +56,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
// preallocate space for the new mappings using last known estimates
|
||||
var newSetMap = new Dictionary<BeatmapSetInfo, HashSet<CarouselItem>>(setMap.Count);
|
||||
var newSetMap = new Dictionary<GroupedBeatmapSet, HashSet<CarouselItem>>(setMap.Count);
|
||||
var newGroupMap = new Dictionary<GroupDefinition, HashSet<CarouselItem>>(groupMap.Count);
|
||||
|
||||
var criteria = getCriteria();
|
||||
@@ -93,11 +94,12 @@ namespace osu.Game.Screens.SelectV2
|
||||
var beatmap = (BeatmapInfo)item.Model;
|
||||
|
||||
bool newBeatmapSet = lastBeatmap?.BeatmapSet!.ID != beatmap.BeatmapSet!.ID;
|
||||
var groupedBeatmapSet = new GroupedBeatmapSet(group, beatmap.BeatmapSet!);
|
||||
|
||||
if (newBeatmapSet)
|
||||
{
|
||||
if (!newSetMap.TryGetValue(beatmap.BeatmapSet!, out currentSetItems))
|
||||
newSetMap[beatmap.BeatmapSet!] = currentSetItems = new HashSet<CarouselItem>();
|
||||
if (!newSetMap.TryGetValue(groupedBeatmapSet, out currentSetItems))
|
||||
newSetMap[groupedBeatmapSet] = currentSetItems = new HashSet<CarouselItem>();
|
||||
}
|
||||
|
||||
if (BeatmapSetsGroupedTogether)
|
||||
@@ -107,7 +109,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
if (groupItem != null)
|
||||
groupItem.NestedItemCount++;
|
||||
|
||||
addItem(new CarouselItem(beatmap.BeatmapSet!)
|
||||
addItem(new CarouselItem(groupedBeatmapSet)
|
||||
{
|
||||
DrawHeight = PanelBeatmapSet.HEIGHT,
|
||||
DepthLayer = -1
|
||||
@@ -134,7 +136,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
currentGroupItems?.Add(i);
|
||||
currentSetItems?.Add(i);
|
||||
|
||||
i.IsVisible = i.Model is GroupDefinition || (group == null && (i.Model is BeatmapSetInfo || !BeatmapSetsGroupedTogether));
|
||||
i.IsVisible = i.Model is GroupDefinition || (group == null && (i.Model is GroupedBeatmapSet || !BeatmapSetsGroupedTogether));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,9 +191,6 @@ namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
var date = b.LastPlayed;
|
||||
|
||||
if (BeatmapSetsGroupedTogether)
|
||||
date = aggregateMax(b, static b => b.LastPlayed ?? DateTimeOffset.MinValue);
|
||||
|
||||
if (date == null || date == DateTimeOffset.MinValue)
|
||||
return new GroupDefinition(int.MaxValue, "Never");
|
||||
|
||||
@@ -202,29 +201,13 @@ namespace osu.Game.Screens.SelectV2
|
||||
return getGroupsBy(b => defineGroupByStatus(b.BeatmapSet!.Status), items);
|
||||
|
||||
case GroupMode.BPM:
|
||||
return getGroupsBy(b =>
|
||||
{
|
||||
double bpm = FormatUtils.RoundBPM(b.BPM);
|
||||
|
||||
if (BeatmapSetsGroupedTogether)
|
||||
bpm = aggregateMax(b, bb => FormatUtils.RoundBPM(bb.BPM));
|
||||
|
||||
return defineGroupByBPM(bpm);
|
||||
}, items);
|
||||
return getGroupsBy(b => defineGroupByBPM(FormatUtils.RoundBPM(b.BPM)), items);
|
||||
|
||||
case GroupMode.Difficulty:
|
||||
return getGroupsBy(b => defineGroupByStars(b.StarRating), items);
|
||||
|
||||
case GroupMode.Length:
|
||||
return getGroupsBy(b =>
|
||||
{
|
||||
double length = b.Length;
|
||||
|
||||
if (BeatmapSetsGroupedTogether)
|
||||
length = aggregateMax(b, bb => bb.Length);
|
||||
|
||||
return defineGroupByLength(length);
|
||||
}, items);
|
||||
return getGroupsBy(b => defineGroupByLength(b.Length), items);
|
||||
|
||||
case GroupMode.Source:
|
||||
return getGroupsBy(b => defineGroupBySource(b.BeatmapSet!.Metadata.Source), items);
|
||||
@@ -433,12 +416,6 @@ namespace osu.Game.Screens.SelectV2
|
||||
return new GroupDefinition(int.MaxValue, "Unplayed");
|
||||
}
|
||||
|
||||
private static T? aggregateMax<T>(BeatmapInfo b, Func<BeatmapInfo, T> func)
|
||||
{
|
||||
var beatmaps = b.BeatmapSet!.Beatmaps.Where(bb => !bb.Hidden);
|
||||
return beatmaps.Max(func);
|
||||
}
|
||||
|
||||
private record GroupMapping(GroupDefinition? Group, List<CarouselItem> ItemsInGroup);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,15 @@ namespace osu.Game.Screens.SelectV2
|
||||
[Resolved]
|
||||
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
|
||||
|
||||
private GroupedBeatmapSet groupedBeatmapSet
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(Item != null);
|
||||
return (GroupedBeatmapSet)Item!.Model;
|
||||
}
|
||||
}
|
||||
|
||||
public PanelBeatmapSet()
|
||||
{
|
||||
PanelXOffset = 20f;
|
||||
@@ -179,9 +188,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
base.PrepareForUse();
|
||||
|
||||
Debug.Assert(Item != null);
|
||||
|
||||
var beatmapSet = (BeatmapSetInfo)Item.Model;
|
||||
var beatmapSet = groupedBeatmapSet.BeatmapSet;
|
||||
|
||||
// Choice of background image matches BSS implementation (always uses the lowest `beatmap_id` from the set).
|
||||
setBackground.Beatmap = beatmaps.GetWorkingBeatmap(beatmapSet.Beatmaps.MinBy(b => b.OnlineID));
|
||||
@@ -215,7 +222,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
if (Item == null)
|
||||
return Array.Empty<MenuItem>();
|
||||
|
||||
var beatmapSet = (BeatmapSetInfo)Item.Model;
|
||||
var beatmapSet = groupedBeatmapSet.BeatmapSet;
|
||||
|
||||
List<MenuItem> items = new List<MenuItem>();
|
||||
|
||||
@@ -268,9 +275,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
private MenuItem createCollectionMenuItem(BeatmapCollection collection)
|
||||
{
|
||||
var beatmapSet = (BeatmapSetInfo)Item!.Model;
|
||||
|
||||
Debug.Assert(beatmapSet != null);
|
||||
var beatmapSet = groupedBeatmapSet.BeatmapSet;
|
||||
|
||||
TernaryState state;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user