From 05e70cd938bbef018be7c9f77d05608c2ac6431f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 10 Apr 2025 13:02:25 +0900 Subject: [PATCH] Merge mod validity checks to closer match osu!web --- osu.Game.Tests/Mods/ModUtilsTest.cs | 54 ++++++++++--------- .../OnlinePlay/OnlinePlaySongSelect.cs | 10 ++-- osu.Game/Utils/ModUtils.cs | 49 ++++------------- 3 files changed, 44 insertions(+), 69 deletions(-) diff --git a/osu.Game.Tests/Mods/ModUtilsTest.cs b/osu.Game.Tests/Mods/ModUtilsTest.cs index 3b4206f5c5..44c5809878 100644 --- a/osu.Game.Tests/Mods/ModUtilsTest.cs +++ b/osu.Game.Tests/Mods/ModUtilsTest.cs @@ -392,44 +392,50 @@ namespace osu.Game.Tests.Mods [Test] public void TestRoomModValidity() { - Assert.IsTrue(ModUtils.IsValidModForMatchType(new OsuModHardRock(), MatchType.Playlists)); - Assert.IsTrue(ModUtils.IsValidModForMatchType(new OsuModDoubleTime(), MatchType.Playlists)); - Assert.IsTrue(ModUtils.IsValidModForMatchType(new ModAdaptiveSpeed(), MatchType.Playlists)); - Assert.IsFalse(ModUtils.IsValidModForMatchType(new OsuModAutoplay(), MatchType.Playlists)); - Assert.IsFalse(ModUtils.IsValidModForMatchType(new OsuModTouchDevice(), MatchType.Playlists)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModHardRock(), MatchType.Playlists, true, false)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModDoubleTime(), MatchType.Playlists, true, false)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new ModAdaptiveSpeed(), MatchType.Playlists, true, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModAutoplay(), MatchType.Playlists, true, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModTouchDevice(), MatchType.Playlists, true, false)); - Assert.IsTrue(ModUtils.IsValidModForMatchType(new OsuModHardRock(), MatchType.HeadToHead)); - Assert.IsTrue(ModUtils.IsValidModForMatchType(new OsuModDoubleTime(), MatchType.HeadToHead)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModHardRock(), MatchType.HeadToHead, true, false)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModDoubleTime(), MatchType.HeadToHead, true, false)); // For now, adaptive speed isn't allowed in multiplayer because it's a per-user rate adjustment. - Assert.IsFalse(ModUtils.IsValidModForMatchType(new ModAdaptiveSpeed(), MatchType.HeadToHead)); - Assert.IsFalse(ModUtils.IsValidModForMatchType(new OsuModAutoplay(), MatchType.HeadToHead)); - Assert.IsFalse(ModUtils.IsValidModForMatchType(new OsuModTouchDevice(), MatchType.HeadToHead)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new ModAdaptiveSpeed(), MatchType.HeadToHead, true, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModAutoplay(), MatchType.HeadToHead, true, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModTouchDevice(), MatchType.HeadToHead, true, false)); } [Test] public void TestRoomFreeModValidity() { - Assert.IsTrue(ModUtils.IsValidFreeModForMatchType(new OsuModHardRock(), MatchType.Playlists)); - Assert.IsTrue(ModUtils.IsValidFreeModForMatchType(new OsuModDoubleTime(), MatchType.Playlists)); - Assert.IsTrue(ModUtils.IsValidFreeModForMatchType(new ModAdaptiveSpeed(), MatchType.Playlists)); - Assert.IsFalse(ModUtils.IsValidFreeModForMatchType(new OsuModAutoplay(), MatchType.Playlists)); - Assert.IsFalse(ModUtils.IsValidFreeModForMatchType(new OsuModTouchDevice(), MatchType.Playlists)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModHardRock(), MatchType.Playlists, false, false)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModDoubleTime(), MatchType.Playlists, false, false)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new ModAdaptiveSpeed(), MatchType.Playlists, false, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModAutoplay(), MatchType.Playlists, false, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModTouchDevice(), MatchType.Playlists, false, false)); - Assert.IsTrue(ModUtils.IsValidFreeModForMatchType(new OsuModHardRock(), MatchType.HeadToHead)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModHardRock(), MatchType.HeadToHead, false, false)); // For now, all rate adjustment mods aren't allowed as free mods in multiplayer. - Assert.IsFalse(ModUtils.IsValidFreeModForMatchType(new OsuModDoubleTime(), MatchType.HeadToHead)); - Assert.IsFalse(ModUtils.IsValidFreeModForMatchType(new ModAdaptiveSpeed(), MatchType.HeadToHead)); - Assert.IsFalse(ModUtils.IsValidFreeModForMatchType(new OsuModAutoplay(), MatchType.HeadToHead)); - Assert.IsFalse(ModUtils.IsValidFreeModForMatchType(new OsuModTouchDevice(), MatchType.HeadToHead)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModDoubleTime(), MatchType.HeadToHead, false, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new ModAdaptiveSpeed(), MatchType.HeadToHead, false, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModAutoplay(), MatchType.HeadToHead, false, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModTouchDevice(), MatchType.HeadToHead, false, false)); } [Test] public void TestFreestyleModValidity() { - Assert.IsTrue(ModUtils.IsValidModForFreestyleMode(new OsuModHardRock(), true)); - Assert.IsTrue(ModUtils.IsValidModForFreestyleMode(new OsuModHardRock(), false)); - Assert.IsTrue(ModUtils.IsValidModForFreestyleMode(new OsuModBarrelRoll(), false)); - Assert.IsFalse(ModUtils.IsValidModForFreestyleMode(new OsuModBarrelRoll(), true)); + foreach (MatchType type in new[] { MatchType.Playlists, MatchType.HeadToHead }) + { + foreach (bool required in new[] { false, true }) + { + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModHardRock(), type, required, true)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModHardRock(), type, required, false)); + Assert.IsFalse(ModUtils.IsValidModForMatch(new OsuModBarrelRoll(), type, required, true)); + Assert.IsTrue(ModUtils.IsValidModForMatch(new OsuModBarrelRoll(), type, required, false)); + } + } } [Test] diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index 33de8d55b8..1d6b4940c3 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -225,22 +225,18 @@ namespace osu.Game.Screens.OnlinePlay /// /// The to check. /// Whether is a valid mod for online play. - private bool isValidGlobalMod(Mod mod) => ModUtils.IsValidModForMatchType(mod, room.Type) - // Mod must be valid in the current freestyle mode. - && ModUtils.IsValidModForFreestyleMode(mod, Freestyle.Value); + private bool isValidGlobalMod(Mod mod) => ModUtils.IsValidModForMatch(mod, room.Type, true, Freestyle.Value); /// /// Checks whether a given is valid for per-player free-mod selection. /// /// The to check. /// Whether is a selectable free-mod. - private bool isValidFreeMod(Mod mod) => ModUtils.IsValidFreeModForMatchType(mod, room.Type) + private bool isValidFreeMod(Mod mod) => ModUtils.IsValidModForMatch(mod, room.Type, false, Freestyle.Value) // Mod must not be contained in the required mods. && Mods.Value.All(m => m.Acronym != mod.Acronym) // Mod must be compatible with all the required mods. - && ModUtils.CheckCompatibleSet(Mods.Value.Append(mod).ToArray()) - // Mod must be valid in the current freestyle mode. - && ModUtils.IsValidModForFreestyleMode(mod, Freestyle.Value); + && ModUtils.CheckCompatibleSet(Mods.Value.Append(mod).ToArray()); protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Utils/ModUtils.cs b/osu.Game/Utils/ModUtils.cs index e4c1d5c1fc..c46e0d9765 100644 --- a/osu.Game/Utils/ModUtils.cs +++ b/osu.Game/Utils/ModUtils.cs @@ -304,56 +304,29 @@ namespace osu.Game.Utils } /// - /// Determines whether a mod can be applied to playlist items in the given match type. + /// Determines whether a mod can be applied to playlist items in the match type. /// /// The mod to test. - /// The match type. - public static bool IsValidModForMatchType(Mod mod, MatchType type) + /// The room match type. + /// Whether the mod is intended as a "required" (room-global) mod. + /// Whether freestyle is enabled for the playlist item. + /// Related osu!web function. + public static bool IsValidModForMatch(Mod mod, MatchType matchType, bool isRequired, bool isFreestyle) { if (mod.Type == ModType.System || !mod.UserPlayable || !mod.HasImplementation) return false; - switch (type) + if (isFreestyle && !mod.ValidForFreestyle) + return false; + + switch (matchType) { case MatchType.Playlists: return true; default: - return mod.ValidForMultiplayer; + return isRequired ? mod.ValidForMultiplayer : mod.ValidForMultiplayerAsFreeMod; } } - - /// - /// Determines whether a mod can be applied as a free mod to playlist items in the given match type. - /// - /// The mod to test. - /// The match type. - public static bool IsValidFreeModForMatchType(Mod mod, MatchType type) - { - if (mod.Type == ModType.System || !mod.UserPlayable || !mod.HasImplementation) - return false; - - switch (type) - { - case MatchType.Playlists: - return true; - - default: - return mod.ValidForMultiplayerAsFreeMod; - } - } - - /// - /// Determines whether a mod can be applied in the given freestyle mode. - /// - /// The mod to test. - /// Whether freestyle is enabled. - public static bool IsValidModForFreestyleMode(Mod mod, bool freestyle) - { - if (mod.Type == ModType.System || !mod.UserPlayable || !mod.HasImplementation) - return false; - - return !freestyle || mod.ValidForFreestyle; - } } }