diff --git a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapInfoExtensions.cs index eab66b9857..e14a44ec58 100644 --- a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs +++ b/osu.Game/Beatmaps/BeatmapInfoExtensions.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; +using System; using osu.Framework.Localisation; namespace osu.Game.Beatmaps @@ -29,10 +29,29 @@ namespace osu.Game.Beatmaps return new RomanisableString($"{metadata.GetPreferred(true)}".Trim(), $"{metadata.GetPreferred(false)}".Trim()); } - public static string[] GetSearchableTerms(this IBeatmapInfo beatmapInfo) => new[] + public static ReadOnlySpan GetSearchableTerms(this IBeatmapInfo beatmapInfo) { - beatmapInfo.DifficultyName - }.Concat(beatmapInfo.Metadata.GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray(); + Span terms = new string[8]; + int i = 0; + if (!string.IsNullOrEmpty(beatmapInfo.DifficultyName)) + terms[i++] = beatmapInfo.DifficultyName; + var metadata = beatmapInfo.Metadata; + if (!string.IsNullOrEmpty(metadata.Author.Username)) + terms[i++] = metadata.Author.Username; + if (!string.IsNullOrEmpty(metadata.Artist)) + terms[i++] = metadata.Artist; + if (!string.IsNullOrEmpty(metadata.ArtistUnicode)) + terms[i++] = metadata.ArtistUnicode; + if (!string.IsNullOrEmpty(metadata.Title)) + terms[i++] = metadata.Title; + if (!string.IsNullOrEmpty(metadata.TitleUnicode)) + terms[i++] = metadata.TitleUnicode; + if (!string.IsNullOrEmpty(metadata.Source)) + terms[i++] = metadata.Source; + if (!string.IsNullOrEmpty(metadata.Tags)) + terms[i++] = metadata.Tags; + return terms[..i]; + } private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]"; } diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 837939716b..75bf8b2bbc 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -55,12 +55,31 @@ namespace osu.Game.Screens.Select.Carousel match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating); - if (match && criteria.SearchTerms.Length > 0) + if (!match) { - string[] terms = BeatmapInfo.GetSearchableTerms(); + Filtered.Value = !match; + return; + } + + if (criteria.SearchTerms.Length > 0) + { + var terms = BeatmapInfo.GetSearchableTerms(); foreach (string criteriaTerm in criteria.SearchTerms) - match &= terms.Any(term => term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase)); + { + bool any = false; + + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (string term in terms) + { + if (!term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase)) continue; + + any = true; + break; + } + + match &= any; + } // if a match wasn't found via text matching of terms, do a second catch-all check matching against online IDs. // this should be done after text matching so we can prioritise matching numbers in metadata. @@ -71,8 +90,13 @@ namespace osu.Game.Screens.Select.Carousel } } - if (match) - match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true; + if (!match) + { + Filtered.Value = !match; + return; + } + + match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true; if (match && criteria.RulesetCriteria != null) match &= criteria.RulesetCriteria.Matches(BeatmapInfo);