diff --git a/osu.Game/Utils/ModUtils.cs b/osu.Game/Utils/ModUtils.cs index 808dba2900..9e638d4f2f 100644 --- a/osu.Game/Utils/ModUtils.cs +++ b/osu.Game/Utils/ModUtils.cs @@ -83,6 +83,48 @@ namespace osu.Game.Utils .All(m => allowedSet.Contains(m.GetType())); } + /// + /// Check the provided combination of mods are valid for a local gameplay session. + /// + /// The mods to check. + /// Invalid mods, if any where found. Can be null if all mods were valid. + /// Whether the input mods were all valid. If false, will contain all invalid entries. + public static bool CheckValidForGameplay(IEnumerable mods, out Mod[]? invalidMods) + { + mods = mods.ToArray(); + + List? foundInvalid = null; + + void addInvalid(Mod mod) + { + foundInvalid ??= new List(); + foundInvalid.Add(mod); + } + + foreach (var mod in mods) + { + bool valid = mod.Type != ModType.System + && mod.HasImplementation + && !(mod is MultiMod); + + if (!valid) + { + // if this mod was found as invalid, we can exclude it before potentially excluding more incompatible types. + addInvalid(mod); + continue; + } + + foreach (var type in mod.IncompatibleMods) + { + foreach (var invalid in mods.Where(m => type.IsInstanceOfType(m))) + addInvalid(invalid); + } + } + + invalidMods = foundInvalid?.ToArray(); + return foundInvalid == null; + } + /// /// Flattens a set of s, returning a new set with all s removed. ///