1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-28 18:12:56 +08:00

Allow unstacking mods

This commit is contained in:
smoogipoo 2021-02-01 13:24:56 +09:00
parent 230b347c1e
commit 797a810287
3 changed files with 45 additions and 7 deletions

View File

@ -22,6 +22,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Screens; using osu.Game.Screens;
using osu.Game.Utils;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osuTK.Input; using osuTK.Input;
@ -46,9 +47,27 @@ namespace osu.Game.Overlays.Mods
protected readonly ModSettingsContainer ModSettingsContainer; protected readonly ModSettingsContainer ModSettingsContainer;
private bool stacked = true;
/// <summary>
/// Whether mod icons should be stacked, or appear as individual buttons.
/// </summary>
public bool Stacked
{
get => stacked;
set
{
stacked = value;
updateAvailableMods();
}
}
[NotNull] [NotNull]
private Func<Mod, bool> isValidMod = m => true; private Func<Mod, bool> isValidMod = m => true;
/// <summary>
/// A function that checks whether a given mod is valid.
/// </summary>
[NotNull] [NotNull]
public Func<Mod, bool> IsValidMod public Func<Mod, bool> IsValidMod
{ {
@ -419,11 +438,18 @@ namespace osu.Game.Overlays.Mods
private void updateAvailableMods() private void updateAvailableMods()
{ {
if (availableMods.Value == null) if (availableMods?.Value == null)
return; return;
foreach (var section in ModSectionsContainer.Children) foreach (var section in ModSectionsContainer.Children)
section.Mods = availableMods.Value[section.ModType].Where(IsValidMod); {
IEnumerable<Mod> modEnumeration = availableMods.Value[section.ModType];
if (!stacked)
modEnumeration = ModValidation.FlattenMods(modEnumeration);
section.Mods = modEnumeration.Where(IsValidMod);
}
} }
private void selectedModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods) private void selectedModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)

View File

@ -14,6 +14,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
{ {
public class FreeModSelectOverlay : ModSelectOverlay public class FreeModSelectOverlay : ModSelectOverlay
{ {
public FreeModSelectOverlay()
{
Stacked = false;
}
protected override ModSection CreateModSection(ModType type) => new FreeModSection(type); protected override ModSection CreateModSection(ModType type) => new FreeModSection(type);
private class FreeModSection : ModSection private class FreeModSection : ModSection

View File

@ -42,7 +42,7 @@ namespace osu.Game.Utils
var incompatibleTypes = new HashSet<Type>(); var incompatibleTypes = new HashSet<Type>();
var incomingTypes = new HashSet<Type>(); var incomingTypes = new HashSet<Type>();
foreach (var mod in combination.SelectMany(flattenMod)) foreach (var mod in combination.SelectMany(FlattenMod))
{ {
// Add the new mod incompatibilities, checking whether any match the existing mod types. // Add the new mod incompatibilities, checking whether any match the existing mod types.
foreach (var t in mod.IncompatibleMods) foreach (var t in mod.IncompatibleMods)
@ -79,7 +79,7 @@ namespace osu.Game.Utils
{ {
var allowedSet = new HashSet<Type>(allowedTypes); var allowedSet = new HashSet<Type>(allowedTypes);
return combination.SelectMany(flattenMod) return combination.SelectMany(FlattenMod)
.All(m => allowedSet.Contains(m.GetType())); .All(m => allowedSet.Contains(m.GetType()));
} }
@ -93,20 +93,27 @@ namespace osu.Game.Utils
/// <param name="incompatibleTypes">The set of incompatible <see cref="Mod"/> types.</param> /// <param name="incompatibleTypes">The set of incompatible <see cref="Mod"/> types.</param>
/// <returns>Whether the given <see cref="Mod"/> is incompatible.</returns> /// <returns>Whether the given <see cref="Mod"/> is incompatible.</returns>
private static bool isModIncompatible(Mod mod, ICollection<Type> incompatibleTypes) private static bool isModIncompatible(Mod mod, ICollection<Type> incompatibleTypes)
=> flattenMod(mod) => FlattenMod(mod)
.SelectMany(m => m.GetType().EnumerateBaseTypes()) .SelectMany(m => m.GetType().EnumerateBaseTypes())
.Any(incompatibleTypes.Contains); .Any(incompatibleTypes.Contains);
/// <summary>
/// Flattens a set of <see cref="Mod"/>s, returning a new set with all <see cref="MultiMod"/>s removed.
/// </summary>
/// <param name="mods">The set of <see cref="Mod"/>s to flatten.</param>
/// <returns>The new set, containing all <see cref="Mod"/>s in <paramref name="mods"/> recursively with all <see cref="MultiMod"/>s removed.</returns>
public static IEnumerable<Mod> FlattenMods(IEnumerable<Mod> mods) => mods.SelectMany(FlattenMod);
/// <summary> /// <summary>
/// Flattens a <see cref="Mod"/>, returning a set of <see cref="Mod"/>s in-place of any <see cref="MultiMod"/>s. /// Flattens a <see cref="Mod"/>, returning a set of <see cref="Mod"/>s in-place of any <see cref="MultiMod"/>s.
/// </summary> /// </summary>
/// <param name="mod">The <see cref="Mod"/> to flatten.</param> /// <param name="mod">The <see cref="Mod"/> to flatten.</param>
/// <returns>A set of singular "flattened" <see cref="Mod"/>s</returns> /// <returns>A set of singular "flattened" <see cref="Mod"/>s</returns>
private static IEnumerable<Mod> flattenMod(Mod mod) public static IEnumerable<Mod> FlattenMod(Mod mod)
{ {
if (mod is MultiMod multi) if (mod is MultiMod multi)
{ {
foreach (var m in multi.Mods.SelectMany(flattenMod)) foreach (var m in multi.Mods.SelectMany(FlattenMod))
yield return m; yield return m;
} }
else else