1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 11:27:24 +08:00

Don't select random beatmap when previous was filtered

This commit is contained in:
Endrik Tombak 2021-08-25 21:42:15 +03:00
parent f02b6b3657
commit 52a243afca
3 changed files with 82 additions and 44 deletions

View File

@ -616,55 +616,72 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1);
}
[Test]
public void TestRandomFallbackOnNonMatchingPrevious()
[TestCase(10, 1)]
[TestCase(10, 10)]
public void TestCarouselSelectsNextWhenPreviousIsFiltered(int makeThisManyGroups, int haveThisManySetsInGroup)
{
List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
List<BeatmapSetInfo> sets = new List<BeatmapSetInfo>();
AddStep("populate maps", () =>
for (int i = 0; i < makeThisManyGroups; i++)
{
for (int i = 0; i < 10; i++)
for (int j = 0; j < haveThisManySetsInGroup; j++)
{
var set = createTestBeatmapSet(i);
foreach (var b in set.Beatmaps)
var testBeatmap = createTestBeatmapSet(i * haveThisManySetsInGroup + j + 1);
var rulesetID = i % 3;
testBeatmap.Beatmaps.ForEach(b =>
{
// all taiko except for first
int ruleset = i > 0 ? 1 : 0;
b.Ruleset = rulesets.GetRuleset(ruleset);
b.RulesetID = ruleset;
}
manySets.Add(set);
b.Ruleset = rulesets.AvailableRulesets.ElementAt(rulesetID);
b.RulesetID = rulesetID;
});
sets.Add(testBeatmap);
}
});
loadBeatmaps(manySets);
for (int i = 0; i < 10; i++)
{
AddStep("Reset filter", () => carousel.Filter(new FilterCriteria(), false));
AddStep("select first beatmap", () => carousel.SelectBeatmap(manySets.First().Beatmaps.First()));
AddStep("Toggle non-matching filter", () =>
{
carousel.Filter(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }, false);
});
AddAssert("selection lost", () => carousel.SelectedBeatmap == null);
AddStep("Restore different ruleset filter", () =>
{
carousel.Filter(new FilterCriteria { Ruleset = rulesets.GetRuleset(1) }, false);
eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID);
});
AddAssert("selection changed", () => carousel.SelectedBeatmap != manySets.First().Beatmaps.First());
}
AddAssert("Selection was random", () => eagerSelectedIDs.Count > 2);
loadBeatmaps(sets);
setSelected(1, 1);
advanceSelection(false);
for (int i = 1; i < makeThisManyGroups; i++)
{
var rulesetID = i % 3;
AddStep($"Toggle filter to ruleset {rulesetID}", () =>
{
carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(rulesetID) }, false);
carousel.Filter(new FilterCriteria(), false);
});
waitForSelection(i * haveThisManySetsInGroup + 1);
}
}
[Test]
public void TestCarouselSelectsBackwardsWhenPreviousIsFilteredNearTheEnd()
{
List<BeatmapSetInfo> sets = new List<BeatmapSetInfo>();
for (int i = 1; i <= 40; i++)
{
var testBeatmap = createTestBeatmapSet(i);
var rulesetID = (i - 1) / 10;
testBeatmap.Beatmaps.ForEach(b =>
{
b.Ruleset = rulesets.AvailableRulesets.ElementAt(rulesetID);
b.RulesetID = rulesetID;
});
sets.Add(testBeatmap);
}
loadBeatmaps(sets);
for (int i = 1; i < 4; i++)
{
setSelected(i * 10 + 1, 1);
AddStep("Toggle filter to ruleset 0", () =>
{
carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false);
carousel.Filter(new FilterCriteria(), false);
});
waitForSelection(10);
}
}
[Test]

View File

@ -911,7 +911,7 @@ namespace osu.Game.Screens.Select
protected override void PerformSelection()
{
if (LastSelected == null || LastSelected.Filtered.Value)
if (LastSelected == null)
carousel?.SelectNextRandom();
else
base.PerformSelection();

View File

@ -101,8 +101,29 @@ namespace osu.Game.Screens.Select.Carousel
protected virtual CarouselItem GetNextToSelect()
{
return Children.Skip(lastSelectedIndex).FirstOrDefault(i => !i.Filtered.Value) ??
Children.Reverse().Skip(InternalChildren.Count - lastSelectedIndex).FirstOrDefault(i => !i.Filtered.Value);
// our return value should be the item (that is not filtered and) that is nearest to the previously selected one
// find nearest such item going forwards in selection
int forwardsDistance = 0;
var forwards = Children.Skip(lastSelectedIndex).SkipWhile((c) =>
{
forwardsDistance++;
return c.Filtered.Value;
}).FirstOrDefault();
// and backwards
int backwardsDistance = 0;
var backwards = Children.Reverse().Skip(InternalChildren.Count - lastSelectedIndex - 1).SkipWhile((c) =>
{
backwardsDistance++;
return c.Filtered.Value;
}).FirstOrDefault();
// if only one direction had such an item, return that
if (forwards == null || backwards == null)
return forwards ?? backwards;
// else return the closest item
return forwardsDistance < backwardsDistance ? forwards : backwards;
}
protected virtual void PerformSelection()