mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 07:23:14 +08:00
Merge pull request #26502 from frenzibyte/prevent-submission-with-invalid-mods
Add guard against submitting score with invalid mod instances
This commit is contained in:
commit
5cb17bcacf
@ -7,7 +7,9 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Mods;
|
||||
using osu.Game.Utils;
|
||||
|
||||
namespace osu.Game.Tests.Mods
|
||||
@ -310,6 +312,16 @@ namespace osu.Game.Tests.Mods
|
||||
Assert.That(invalid?.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestModBelongsToRuleset()
|
||||
{
|
||||
Assert.That(ModUtils.CheckModsBelongToRuleset(new OsuRuleset(), Array.Empty<Mod>()));
|
||||
Assert.That(ModUtils.CheckModsBelongToRuleset(new OsuRuleset(), new Mod[] { new OsuModDoubleTime() }));
|
||||
Assert.That(ModUtils.CheckModsBelongToRuleset(new OsuRuleset(), new Mod[] { new OsuModDoubleTime(), new OsuModAccuracyChallenge() }));
|
||||
Assert.That(ModUtils.CheckModsBelongToRuleset(new OsuRuleset(), new Mod[] { new OsuModDoubleTime(), new ModAccuracyChallenge() }), Is.False);
|
||||
Assert.That(ModUtils.CheckModsBelongToRuleset(new OsuRuleset(), new Mod[] { new OsuModDoubleTime(), new TaikoModFlashlight() }), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFormatScoreMultiplier()
|
||||
{
|
||||
|
@ -13,7 +13,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
@ -487,13 +486,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
}
|
||||
}
|
||||
|
||||
private class TestMod : Mod, IApplicableToScoreProcessor
|
||||
private class TestMod : OsuModDoubleTime, IApplicableToScoreProcessor
|
||||
{
|
||||
public override string Name => string.Empty;
|
||||
public override string Acronym => string.Empty;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override LocalisableString Description => string.Empty;
|
||||
|
||||
public bool Applied { get; private set; }
|
||||
|
||||
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
|
||||
|
@ -15,11 +15,13 @@ using osu.Game.Online.Rooms;
|
||||
using osu.Game.Online.Solo;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Game.Rulesets.Taiko.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
@ -34,12 +36,19 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private Func<RulesetInfo, IBeatmap> createCustomBeatmap;
|
||||
private Func<Ruleset> createCustomRuleset;
|
||||
private Func<Mod[]> createCustomMods;
|
||||
|
||||
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
|
||||
|
||||
protected override bool HasCustomSteps => true;
|
||||
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new FakeImportingPlayer(false);
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
if (createCustomMods != null)
|
||||
SelectedMods.Value = SelectedMods.Value.Concat(createCustomMods()).ToList();
|
||||
|
||||
return new FakeImportingPlayer(false);
|
||||
}
|
||||
|
||||
protected new FakeImportingPlayer Player => (FakeImportingPlayer)base.Player;
|
||||
|
||||
@ -277,13 +286,28 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("ensure no submission", () => Player.SubmittedScore == null);
|
||||
}
|
||||
|
||||
private void createPlayerTest(bool allowFail = false, Func<RulesetInfo, IBeatmap> createBeatmap = null, Func<Ruleset> createRuleset = null)
|
||||
[Test]
|
||||
public void TestNoSubmissionWithModsOfDifferentRuleset()
|
||||
{
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest(createRuleset: () => new OsuRuleset(), createMods: () => new Mod[] { new TaikoModHidden() });
|
||||
|
||||
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
|
||||
AddAssert("gameplay not loaded", () => Player.DrawableRuleset == null);
|
||||
|
||||
AddStep("exit", () => Player.Exit());
|
||||
AddAssert("ensure no submission", () => Player.SubmittedScore == null);
|
||||
}
|
||||
|
||||
private void createPlayerTest(bool allowFail = false, Func<RulesetInfo, IBeatmap> createBeatmap = null, Func<Ruleset> createRuleset = null, Func<Mod[]> createMods = null)
|
||||
{
|
||||
CreateTest(() => AddStep("set up requirements", () =>
|
||||
{
|
||||
this.allowFail = allowFail;
|
||||
createCustomBeatmap = createBeatmap;
|
||||
createCustomRuleset = createRuleset;
|
||||
createCustomMods = createMods;
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osuTK;
|
||||
|
||||
@ -29,7 +30,7 @@ namespace osu.Game.Tests.Visual.Mods
|
||||
public void TestMaximumAchievableAccuracy() =>
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new ModAccuracyChallenge
|
||||
Mod = new OsuModAccuracyChallenge
|
||||
{
|
||||
MinimumAccuracy = { Value = 0.6 }
|
||||
},
|
||||
@ -49,7 +50,7 @@ namespace osu.Game.Tests.Visual.Mods
|
||||
public void TestStandardAccuracy() =>
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new ModAccuracyChallenge
|
||||
Mod = new OsuModAccuracyChallenge
|
||||
{
|
||||
MinimumAccuracy = { Value = 0.6 },
|
||||
AccuracyJudgeMode = { Value = ModAccuracyChallenge.AccuracyMode.Standard }
|
||||
|
@ -38,6 +38,7 @@ using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Utils;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
@ -213,6 +214,12 @@ namespace osu.Game.Screens.Play
|
||||
if (playableBeatmap == null)
|
||||
return;
|
||||
|
||||
if (!ModUtils.CheckModsBelongToRuleset(ruleset, gameplayMods))
|
||||
{
|
||||
Logger.Log($@"Gameplay was started with a mod belonging to a ruleset different than '{ruleset.Description}'.", level: LogLevel.Important);
|
||||
return;
|
||||
}
|
||||
|
||||
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
||||
|
||||
if (game != null)
|
||||
|
@ -229,6 +229,38 @@ namespace osu.Game.Utils
|
||||
return proposedWereValid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies all mods provided belong to the given ruleset.
|
||||
/// </summary>
|
||||
/// <param name="ruleset">The ruleset to check the proposed mods against.</param>
|
||||
/// <param name="proposedMods">The mods proposed for checking.</param>
|
||||
/// <returns>Whether all <paramref name="proposedMods"/> belong to the given <paramref name="ruleset"/>.</returns>
|
||||
public static bool CheckModsBelongToRuleset(Ruleset ruleset, IEnumerable<Mod> proposedMods)
|
||||
{
|
||||
var rulesetModsTypes = ruleset.AllMods.Select(m => m.GetType()).ToList();
|
||||
|
||||
foreach (var proposedMod in proposedMods)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
var proposedModType = proposedMod.GetType();
|
||||
|
||||
foreach (var rulesetModType in rulesetModsTypes)
|
||||
{
|
||||
if (rulesetModType.IsAssignableFrom(proposedModType))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a value of a score multiplier, returns a string version with special handling for a value near 1.00x.
|
||||
/// </summary>
|
||||
|
Loading…
Reference in New Issue
Block a user