1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-02 06:49:54 +08:00

Merge mod validity checks to closer match osu!web

This commit is contained in:
Dan Balasescu
2025-04-10 13:02:25 +09:00
Unverified
parent 1c060f986c
commit 05e70cd938
3 changed files with 44 additions and 69 deletions
+30 -24
View File
@@ -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]
@@ -225,22 +225,18 @@ namespace osu.Game.Screens.OnlinePlay
/// </summary>
/// <param name="mod">The <see cref="Mod"/> to check.</param>
/// <returns>Whether <paramref name="mod"/> is a valid mod for online play.</returns>
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);
/// <summary>
/// Checks whether a given <see cref="Mod"/> is valid for per-player free-mod selection.
/// </summary>
/// <param name="mod">The <see cref="Mod"/> to check.</param>
/// <returns>Whether <paramref name="mod"/> is a selectable free-mod.</returns>
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)
{
+11 -38
View File
@@ -304,56 +304,29 @@ namespace osu.Game.Utils
}
/// <summary>
/// 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.
/// </summary>
/// <param name="mod">The mod to test.</param>
/// <param name="type">The match type.</param>
public static bool IsValidModForMatchType(Mod mod, MatchType type)
/// <param name="matchType">The room match type.</param>
/// <param name="isRequired">Whether the mod is intended as a "required" (room-global) mod.</param>
/// <param name="isFreestyle">Whether freestyle is enabled for the playlist item.</param>
/// <seealso href="https://github.com/ppy/osu-web/blob/40936b514c6485b874f6c6496d55d9e8b1b88fd4/app/Singletons/Mods.php#L95-L113">Related osu!web function.</seealso>
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;
}
}
/// <summary>
/// Determines whether a mod can be applied as a free mod to playlist items in the given match type.
/// </summary>
/// <param name="mod">The mod to test.</param>
/// <param name="type">The match type.</param>
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;
}
}
/// <summary>
/// Determines whether a mod can be applied in the given freestyle mode.
/// </summary>
/// <param name="mod">The mod to test.</param>
/// <param name="freestyle">Whether freestyle is enabled.</param>
public static bool IsValidModForFreestyleMode(Mod mod, bool freestyle)
{
if (mod.Type == ModType.System || !mod.UserPlayable || !mod.HasImplementation)
return false;
return !freestyle || mod.ValidForFreestyle;
}
}
}