Add per-difficulty filtering support

Filters based on selected ruleset
This commit is contained in:
Dean Herbert
2017-12-11 20:22:10 +09:00
parent ce37688cd3
commit f58c554d19
5 changed files with 60 additions and 25 deletions

View File

@ -131,7 +131,7 @@ namespace osu.Game.Screens.Select
var newSelection =
newGroup.BeatmapPanels.Find(p => p.Beatmap.ID == selectedPanel?.Beatmap.ID);
if(newSelection == null && oldGroup != null && selectedPanel != null)
if (newSelection == null && oldGroup != null && selectedPanel != null)
newSelection = newGroup.BeatmapPanels[Math.Min(newGroup.BeatmapPanels.Count - 1, oldGroup.BeatmapPanels.IndexOf(selectedPanel))];
selectGroup(newGroup, newSelection);
@ -178,42 +178,62 @@ namespace osu.Game.Screens.Select
SelectionChanged?.Invoke(null);
}
/// <summary>
/// Increment selection in the carousel in a chosen direction.
/// </summary>
/// <param name="direction">The direction to increment. Negative is backwards.</param>
/// <param name="skipDifficulties">Whether to skip individual difficulties and only increment over full groups.</param>
public void SelectNext(int direction = 1, bool skipDifficulties = true)
{
// todo: we may want to refactor and remove this as an optimisation in the future.
if (groups.All(g => g.State == BeatmapGroupState.Hidden))
{
selectNullBeatmap();
return;
}
if (!skipDifficulties && selectedGroup != null)
{
int i = selectedGroup.BeatmapPanels.IndexOf(selectedPanel) + direction;
int originalIndex = Math.Max(0, groups.IndexOf(selectedGroup));
int currentIndex = originalIndex;
if (i >= 0 && i < selectedGroup.BeatmapPanels.Count)
{
//changing difficulty panel, not set.
selectGroup(selectedGroup, selectedGroup.BeatmapPanels[i]);
return;
}
}
// local function to increment the index in the required direction, wrapping over extremities.
int incrementIndex() => currentIndex = (currentIndex + direction + groups.Count) % groups.Count;
int startIndex = Math.Max(0, groups.IndexOf(selectedGroup));
int index = startIndex;
// in the case we are skipping difficulties, we want to increment the index once before starting to find out new target
// (we don't care about the currently selected group).
if (skipDifficulties)
incrementIndex();
do
{
index = (index + direction + groups.Count) % groups.Count;
if (groups[index].State != BeatmapGroupState.Hidden)
{
if (skipDifficulties)
SelectBeatmap(groups[index].SelectedPanel != null ? groups[index].SelectedPanel.Beatmap : groups[index].BeatmapPanels.First().Beatmap);
else
SelectBeatmap(direction == 1 ? groups[index].BeatmapPanels.First().Beatmap : groups[index].BeatmapPanels.Last().Beatmap);
var group = groups[currentIndex];
if (group.State == BeatmapGroupState.Hidden) continue;
// we are only interested in non-filtered panels.
IEnumerable<BeatmapPanel> validPanels = group.BeatmapPanels.Where(p => !p.Filtered);
// if we are considering difficulties, we need to do a few extrea steps.
if (!skipDifficulties)
{
// we want to reverse the panel order if we are searching backwards.
if (direction < 0)
validPanels = validPanels.Reverse();
// if we are currently on the selected panel, let's try to find a valid difficulty before leaving to the next group.
// the first valid difficulty is found by skipping to the selected panel and then one further.
if (currentIndex == originalIndex)
validPanels = validPanels.SkipWhile(p => p != selectedPanel).Skip(1);
}
var next = validPanels.FirstOrDefault();
// at this point, we can perform the selection change if we have a valid new target, else continue to increment in the specified direction.
if (next != null)
{
selectGroup(group, next);
return;
}
} while (index != startIndex);
} while (incrementIndex() != originalIndex);
}
private IEnumerable<BeatmapGroup> getVisibleGroups() => groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden);
@ -416,6 +436,8 @@ namespace osu.Game.Screens.Select
foreach (BeatmapPanel panel in group.BeatmapPanels)
{
if (panel.Filtered) continue;
if (panel == selectedPanel)
selectedY = currentY + panel.DrawHeight / 2 - DrawHeight / 2;
@ -460,7 +482,7 @@ namespace osu.Game.Screens.Select
try
{
if (panel == null)
panel = group.BeatmapPanels.First();
panel = group.BeatmapPanels.First(p => !p.Filtered);
if (selectedPanel == panel) return;

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Rulesets;
using osu.Game.Screens.Select.Filter;
@ -18,19 +19,26 @@ namespace osu.Game.Screens.Select
public RulesetInfo Ruleset;
public bool AllowConvertedBeatmaps;
private bool canConvert(BeatmapInfo beatmapInfo) => beatmapInfo.RulesetID == Ruleset.ID || beatmapInfo.RulesetID == 0 && Ruleset.ID > 0 && AllowConvertedBeatmaps;
public void Filter(List<BeatmapGroup> groups)
{
foreach (var g in groups)
{
var set = g.BeatmapSet;
bool hasCurrentMode = AllowConvertedBeatmaps || set.Beatmaps.Any(bm => bm.RulesetID == (Ruleset?.ID ?? 0));
// we only support converts from osu! mode to other modes for now.
// in the future this will have to change, at which point this condition will become a touch more complicated.
bool hasCurrentMode = set.Beatmaps.Any(canConvert);
bool match = hasCurrentMode;
if (!string.IsNullOrEmpty(SearchText))
match &= set.Metadata.SearchableTerms.Any(term => term.IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) >= 0);
foreach (var panel in g.BeatmapPanels)
panel.Filtered = !canConvert(panel.Beatmap);
switch (g.State)
{
case BeatmapGroupState.Hidden: