1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 15:07:44 +08:00

Merge branch 'master' into modselect-disable-stacking

This commit is contained in:
Dean Herbert 2021-02-02 21:41:33 +09:00 committed by GitHub
commit b76116d943
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 0 deletions

View File

@ -1,9 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using Moq;
using NUnit.Framework;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Utils;
namespace osu.Game.Tests.Mods
@ -99,6 +102,53 @@ namespace osu.Game.Tests.Mods
Assert.That(ModUtils.CheckAllowed(new[] { mod.Object }, new[] { typeof(Mod) }), Is.False);
}
private static readonly object[] invalid_mod_test_scenarios =
{
// incompatible pair.
new object[]
{
new Mod[] { new OsuModDoubleTime(), new OsuModHalfTime() },
new[] { typeof(OsuModDoubleTime), typeof(OsuModHalfTime) }
},
// incompatible pair with derived class.
new object[]
{
new Mod[] { new OsuModNightcore(), new OsuModHalfTime() },
new[] { typeof(OsuModNightcore), typeof(OsuModHalfTime) }
},
// system mod.
new object[]
{
new Mod[] { new OsuModDoubleTime(), new OsuModTouchDevice() },
new[] { typeof(OsuModTouchDevice) }
},
// multi mod.
new object[]
{
new Mod[] { new MultiMod(new OsuModHalfTime()), new OsuModHalfTime() },
new[] { typeof(MultiMod) }
},
// valid pair.
new object[]
{
new Mod[] { new OsuModDoubleTime(), new OsuModHardRock() },
null
}
};
[TestCaseSource(nameof(invalid_mod_test_scenarios))]
public void TestInvalidModScenarios(Mod[] inputMods, Type[] expectedInvalid)
{
bool isValid = ModUtils.CheckValidForGameplay(inputMods, out var invalid);
Assert.That(isValid, Is.EqualTo(expectedInvalid == null));
if (isValid)
Assert.IsNull(invalid);
else
Assert.That(invalid?.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
}
public abstract class CustomMod1 : Mod
{
}

View File

@ -468,6 +468,12 @@ namespace osu.Game
private void modsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
{
updateModDefaults();
if (!ModUtils.CheckValidForGameplay(mods.NewValue, out var invalid))
{
// ensure we always have a valid set of mods.
SelectedMods.Value = mods.NewValue.Except(invalid).ToArray();
}
}
private void updateModDefaults()

View File

@ -83,6 +83,30 @@ namespace osu.Game.Utils
.All(m => allowedSet.Contains(m.GetType()));
}
/// <summary>
/// Check the provided combination of mods are valid for a local gameplay session.
/// </summary>
/// <param name="mods">The mods to check.</param>
/// <param name="invalidMods">Invalid mods, if any were found. Can be null if all mods were valid.</param>
/// <returns>Whether the input mods were all valid. If false, <paramref name="invalidMods"/> will contain all invalid entries.</returns>
public static bool CheckValidForGameplay(IEnumerable<Mod> mods, out List<Mod>? invalidMods)
{
mods = mods.ToArray();
CheckCompatibleSet(mods, out invalidMods);
foreach (var mod in mods)
{
if (mod.Type == ModType.System || !mod.HasImplementation || mod is MultiMod)
{
invalidMods ??= new List<Mod>();
invalidMods.Add(mod);
}
}
return invalidMods == null;
}
/// <summary>
/// Flattens a set of <see cref="Mod"/>s, returning a new set with all <see cref="MultiMod"/>s removed.
/// </summary>