From 10ceddf3ffcf861f71aee5f4a681441b15913226 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 2 Feb 2021 20:47:50 +0900 Subject: [PATCH] Make IsValidMod adjustable --- .../TestSceneModSelectOverlay.cs | 16 ++++++ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 54 ++++++++++++++++--- .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 +- osu.Game/Screens/Select/MatchSongSelect.cs | 2 +- 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 71c549b433..9cf8b95ddf 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -137,6 +137,22 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("ensure all buttons are spread out", () => modSelect.ChildrenOfType().All(m => m.Mods.Length <= 1)); } + [Test] + public void TestChangeIsValidChangesButtonVisibility() + { + changeRuleset(0); + + AddAssert("double time visible", () => modSelect.ChildrenOfType().Any(b => b.Mods.Any(m => m is OsuModDoubleTime))); + + AddStep("make double time invalid", () => modSelect.IsValidMod = m => !(m is OsuModDoubleTime)); + AddAssert("double time not visible", () => modSelect.ChildrenOfType().All(b => !b.Mods.Any(m => m is OsuModDoubleTime))); + AddAssert("nightcore still visible", () => modSelect.ChildrenOfType().Any(b => b.Mods.Any(m => m is OsuModNightcore))); + + AddStep("make double time valid again", () => modSelect.IsValidMod = m => true); + AddAssert("double time visible", () => modSelect.ChildrenOfType().Any(b => b.Mods.Any(m => m is OsuModDoubleTime))); + AddAssert("nightcore still visible", () => modSelect.ChildrenOfType().Any(b => b.Mods.Any(m => m is OsuModNightcore))); + } + private void testSingleMod(Mod mod) { selectNext(mod); diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 775b0de1c0..61e4b45495 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -31,7 +32,6 @@ namespace osu.Game.Overlays.Mods { public class ModSelectOverlay : WaveOverlayContainer { - private readonly Func isValidMod; public const float HEIGHT = 510; protected readonly TriangleButton DeselectAllButton; @@ -49,6 +49,23 @@ namespace osu.Game.Overlays.Mods /// protected virtual bool Stacked => true; + [NotNull] + private Func isValidMod = m => true; + + /// + /// A function that checks whether a given mod is selectable. + /// + [NotNull] + public Func IsValidMod + { + get => isValidMod; + set + { + isValidMod = value ?? throw new ArgumentNullException(nameof(value)); + updateAvailableMods(); + } + } + protected readonly FillFlowContainer ModSectionsContainer; protected readonly ModSettingsContainer ModSettingsContainer; @@ -67,10 +84,8 @@ namespace osu.Game.Overlays.Mods private SampleChannel sampleOn, sampleOff; - public ModSelectOverlay(Func isValidMod = null) + public ModSelectOverlay() { - this.isValidMod = isValidMod ?? (m => true); - Waves.FirstWaveColour = Color4Extensions.FromHex(@"19b0e2"); Waves.SecondWaveColour = Color4Extensions.FromHex(@"2280a2"); Waves.ThirdWaveColour = Color4Extensions.FromHex(@"005774"); @@ -351,7 +366,7 @@ namespace osu.Game.Overlays.Mods { base.LoadComplete(); - availableMods.BindValueChanged(availableModsChanged, true); + availableMods.BindValueChanged(_ => updateAvailableMods(), true); SelectedMods.BindValueChanged(selectedModsChanged, true); } @@ -406,9 +421,10 @@ namespace osu.Game.Overlays.Mods public override bool OnPressed(GlobalAction action) => false; // handled by back button - private void availableModsChanged(ValueChangedEvent>> mods) + private void updateAvailableMods() { - if (mods.NewValue == null) return; + if (availableMods?.Value == null) + return; foreach (var section in ModSectionsContainer.Children) { @@ -417,10 +433,32 @@ namespace osu.Game.Overlays.Mods if (!Stacked) modEnumeration = ModUtils.FlattenMods(modEnumeration); - section.Mods = modEnumeration.Where(isValidMod); + section.Mods = modEnumeration.Select(getValidModOrNull).Where(m => m != null); } } + /// + /// Returns a valid form of a given if possible, or null otherwise. + /// + /// + /// This is a recursive process during which any invalid mods are culled while preserving structures where possible. + /// + /// The to check. + /// A valid form of if exists, or null otherwise. + [CanBeNull] + private Mod getValidModOrNull([NotNull] Mod mod) + { + if (!(mod is MultiMod multi)) + return IsValidMod(mod) ? mod : null; + + var validSubset = multi.Mods.Select(getValidModOrNull).Where(m => m != null).ToArray(); + + if (validSubset.Length == 0) + return null; + + return validSubset.Length == 1 ? validSubset[0] : new MultiMod(validSubset); + } + private void selectedModsChanged(ValueChangedEvent> mods) { foreach (var section in ModSectionsContainer.Children) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index ebc06d2445..5bf9b1ee7e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -111,7 +111,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); - protected override ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay(isValidMod); + protected override ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay { IsValidMod = isValidMod }; private bool isValidMod(Mod mod) => !(mod is ModAutoplay) && (mod as MultiMod)?.Mods.Any(mm => mm is ModAutoplay) != true; } diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index ed47b5d5ac..1bb7374ce3 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -81,7 +81,7 @@ namespace osu.Game.Screens.Select item.RequiredMods.AddRange(Mods.Value.Select(m => m.CreateCopy())); } - protected override ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay(isValidMod); + protected override ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay { IsValidMod = isValidMod }; private bool isValidMod(Mod mod) => !(mod is ModAutoplay) && (mod as MultiMod)?.Mods.Any(mm => mm is ModAutoplay) != true; }