mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:07:52 +08:00
Bring back separate bool properties as non-cascading
This commit is contained in:
parent
86aa2125fe
commit
8501a41619
@ -324,12 +324,18 @@ namespace osu.Game.Tests.Mods
|
|||||||
public override string Acronym => string.Empty;
|
public override string Acronym => string.Empty;
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override bool HasImplementation => true;
|
public override bool HasImplementation => true;
|
||||||
public override bool IsPlayable(ModUsage usage) => usage == ModUsage.SoloLocal;
|
public override bool ValidForMultiplayer => false;
|
||||||
|
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InvalidMultiplayerFreeMod : InvalidMultiplayerMod
|
private class InvalidMultiplayerFreeMod : Mod
|
||||||
{
|
{
|
||||||
public override bool IsPlayable(ModUsage usage) => usage != ModUsage.MultiplayerLocal;
|
public override string Name => string.Empty;
|
||||||
|
public override string Description => string.Empty;
|
||||||
|
public override string Acronym => string.Empty;
|
||||||
|
public override double ScoreMultiplier => 1;
|
||||||
|
public override bool HasImplementation => true;
|
||||||
|
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IModCompatibilitySpecification
|
public interface IModCompatibilitySpecification
|
||||||
|
@ -6,7 +6,6 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Screens.OnlinePlay;
|
using osu.Game.Screens.OnlinePlay;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Multiplayer
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
@ -29,7 +28,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddUntilStep("all visible mods are playable",
|
AddUntilStep("all visible mods are playable",
|
||||||
() => this.ChildrenOfType<ModPanel>()
|
() => this.ChildrenOfType<ModPanel>()
|
||||||
.Where(panel => panel.IsPresent)
|
.Where(panel => panel.IsPresent)
|
||||||
.All(panel => panel.Mod.HasImplementation && panel.Mod.IsPlayable(ModUsage.SoloLocal)));
|
.All(panel => panel.Mod.HasImplementation && panel.Mod.UserPlayable));
|
||||||
|
|
||||||
AddToggleStep("toggle visibility", visible =>
|
AddToggleStep("toggle visibility", visible =>
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
modsContainer.Add(new ModButton(new ModNoMod()));
|
modsContainer.Add(new ModButton(new ModNoMod()));
|
||||||
modsContainer.AddRange(rulesetInstance.AllMods.Where(m => m.IsPlayable(ModUsage.SoloLocal)).Select(m => new ModButton(m)));
|
modsContainer.AddRange(rulesetInstance.AllMods.Where(m => m.UserPlayable).Select(m => new ModButton(m)));
|
||||||
|
|
||||||
modsContainer.ForEach(button =>
|
modsContainer.ForEach(button =>
|
||||||
{
|
{
|
||||||
|
@ -33,26 +33,24 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
IconUsage? Icon { get; }
|
IconUsage? Icon { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether this mod is playable for the given usage.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <list type="bullet">
|
|
||||||
/// <item>Should be always <c>false</c> for cases where the user is not interacting with the game.</item>
|
|
||||||
/// <item>Should be <c>false</c> in <see cref="ModUsage.MultiplayerGlobal"/> for mods that make gameplay duration dependent on user input (e.g. <see cref="ModAdaptiveSpeed"/>).</item>
|
|
||||||
/// <item>Should be <c>false</c> in <see cref="ModUsage.MultiplayerLocal"/> for mods that affect the gameplay duration (e.g. <see cref="ModRateAdjust"/> and <see cref="ModTimeRamp"/>).</item>
|
|
||||||
/// </list>
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="usage">The mod usage.</param>
|
|
||||||
bool IsPlayable(ModUsage usage);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this mod is playable by an end user.
|
/// Whether this mod is playable by an end user.
|
||||||
/// Should be <c>false</c> for cases where the user is not interacting with the game (so it can be excluded from multiplayer selection, for example).
|
/// Should be <c>false</c> for cases where the user is not interacting with the game (so it can be excluded from multiplayer selection, for example).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Obsolete("Override IsPlayable instead.")] // Can be removed 20221104
|
|
||||||
bool UserPlayable { get; }
|
bool UserPlayable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this mod is valid for multiplayer matches.
|
||||||
|
/// Should be <c>false</c> for mods that make gameplay duration dependent on user input (e.g. <see cref="ModAdaptiveSpeed"/>).
|
||||||
|
/// </summary>
|
||||||
|
bool ValidForMultiplayer { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this mod is valid as a free mod in multiplayer matches.
|
||||||
|
/// Should be <c>false</c> for mods that affect the gameplay duration (e.g. <see cref="ModRateAdjust"/> and <see cref="ModTimeRamp"/>).
|
||||||
|
/// </summary>
|
||||||
|
bool ValidForMultiplayerAsFreeMod { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a fresh <see cref="Mod"/> instance based on this mod.
|
/// Create a fresh <see cref="Mod"/> instance based on this mod.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -91,13 +91,14 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual bool HasImplementation => this is IApplicableMod;
|
public virtual bool HasImplementation => this is IApplicableMod;
|
||||||
|
|
||||||
#pragma warning disable 618
|
[JsonIgnore]
|
||||||
public virtual bool IsPlayable(ModUsage usage) => UserPlayable;
|
public virtual bool UserPlayable => true;
|
||||||
#pragma warning restore 618
|
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
[Obsolete("Override IsPlayable instead.")] // Can be removed 20221104
|
public virtual bool ValidForMultiplayer => true;
|
||||||
public virtual bool UserPlayable => true;
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual bool ValidForMultiplayerAsFreeMod => true;
|
||||||
|
|
||||||
[Obsolete("Going forward, the concept of \"ranked\" doesn't exist. The only exceptions are automation mods, which should now override IsPlayable to false.")] // Can be removed 20211009
|
[Obsolete("Going forward, the concept of \"ranked\" doesn't exist. The only exceptions are automation mods, which should now override IsPlayable to false.")] // Can be removed 20211009
|
||||||
public virtual bool Ranked => false;
|
public virtual bool Ranked => false;
|
||||||
|
@ -31,7 +31,8 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
public override bool IsPlayable(ModUsage usage) => usage == ModUsage.SoloLocal;
|
public override bool ValidForMultiplayer => false;
|
||||||
|
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||||
|
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(ModRateAdjust), typeof(ModTimeRamp) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModRateAdjust), typeof(ModTimeRamp) };
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
public bool RestartOnFail => false;
|
public bool RestartOnFail => false;
|
||||||
|
|
||||||
public override bool IsPlayable(ModUsage usage) => false;
|
public override bool UserPlayable => false;
|
||||||
|
public override bool ValidForMultiplayer => false;
|
||||||
|
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||||
|
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(ModCinema), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModCinema), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail) };
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
{
|
{
|
||||||
public abstract class ModRateAdjust : Mod, IApplicableToRate
|
public abstract class ModRateAdjust : Mod, IApplicableToRate
|
||||||
{
|
{
|
||||||
public override bool IsPlayable(ModUsage usage) => usage != ModUsage.MultiplayerLocal;
|
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||||
|
|
||||||
public abstract BindableNumber<double> SpeedChange { get; }
|
public abstract BindableNumber<double> SpeedChange { get; }
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
||||||
public abstract BindableBool AdjustPitch { get; }
|
public abstract BindableBool AdjustPitch { get; }
|
||||||
|
|
||||||
public override bool IsPlayable(ModUsage usage) => usage != ModUsage.MultiplayerLocal;
|
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||||
|
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(ModRateAdjust), typeof(ModAdaptiveSpeed) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModRateAdjust), typeof(ModAdaptiveSpeed) };
|
||||||
|
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The context in which a <see cref="Mod"/> is playable.
|
|
||||||
/// </summary>
|
|
||||||
public enum ModUsage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This mod can be used for a per-user gameplay session.
|
|
||||||
/// </summary>
|
|
||||||
SoloLocal,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This mod can be used in multiplayer but must be applied to all users.
|
|
||||||
/// This is generally the case for mods which affect the length of gameplay.
|
|
||||||
/// </summary>
|
|
||||||
MultiplayerGlobal,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This mod can be used in multiplayer either at a room or per-player level (i.e. "free mod").
|
|
||||||
/// </summary>
|
|
||||||
MultiplayerLocal,
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,7 +15,9 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override string Description => "This mod could not be resolved by the game.";
|
public override string Description => "This mod could not be resolved by the game.";
|
||||||
public override double ScoreMultiplier => 0;
|
public override double ScoreMultiplier => 0;
|
||||||
|
|
||||||
public override bool IsPlayable(ModUsage usage) => false;
|
public override bool UserPlayable => false;
|
||||||
|
public override bool ValidForMultiplayer => false;
|
||||||
|
public override bool ValidForMultiplayerAsFreeMod => false;
|
||||||
|
|
||||||
public override ModType Type => ModType.System;
|
public override ModType Type => ModType.System;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
public new Func<Mod, bool> IsValidMod
|
public new Func<Mod, bool> IsValidMod
|
||||||
{
|
{
|
||||||
get => base.IsValidMod;
|
get => base.IsValidMod;
|
||||||
set => base.IsValidMod = m => m.HasImplementation && m.IsPlayable(ModUsage.SoloLocal) && value(m);
|
set => base.IsValidMod = m => m.HasImplementation && m.UserPlayable && value(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FreeModSelectOverlay()
|
public FreeModSelectOverlay()
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
public new Func<Mod, bool> IsValidMod
|
public new Func<Mod, bool> IsValidMod
|
||||||
{
|
{
|
||||||
get => base.IsValidMod;
|
get => base.IsValidMod;
|
||||||
set => base.IsValidMod = m => m.IsPlayable(ModUsage.SoloLocal) && value.Invoke(m);
|
set => base.IsValidMod = m => m.UserPlayable && value.Invoke(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FreeModSelectScreen()
|
public FreeModSelectScreen()
|
||||||
|
@ -95,8 +95,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
|
|
||||||
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea();
|
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea();
|
||||||
|
|
||||||
protected override bool IsValidMod(Mod mod) => base.IsValidMod(mod) && mod.IsPlayable(ModUsage.MultiplayerGlobal);
|
protected override bool IsValidMod(Mod mod) => base.IsValidMod(mod) && mod.ValidForMultiplayer;
|
||||||
|
|
||||||
protected override bool IsValidFreeMod(Mod mod) => base.IsValidFreeMod(mod) && mod.IsPlayable(ModUsage.MultiplayerLocal);
|
protected override bool IsValidFreeMod(Mod mod) => base.IsValidFreeMod(mod) && mod.ValidForMultiplayerAsFreeMod;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mod">The <see cref="Mod"/> to check.</param>
|
/// <param name="mod">The <see cref="Mod"/> to check.</param>
|
||||||
/// <returns>Whether <paramref name="mod"/> is a valid mod for online play.</returns>
|
/// <returns>Whether <paramref name="mod"/> is a valid mod for online play.</returns>
|
||||||
protected virtual bool IsValidMod(Mod mod) => mod.HasImplementation && ModUtils.FlattenMod(mod).All(m => m.IsPlayable(ModUsage.SoloLocal));
|
protected virtual bool IsValidMod(Mod mod) => mod.HasImplementation && ModUtils.FlattenMod(mod).All(m => m.UserPlayable);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks whether a given <see cref="Mod"/> is valid for per-player free-mod selection.
|
/// Checks whether a given <see cref="Mod"/> is valid for per-player free-mod selection.
|
||||||
|
@ -20,7 +20,6 @@ using osu.Game.Graphics.Containers;
|
|||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Ranking.Statistics;
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
@ -188,7 +187,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
|
|||||||
if (score.NewValue == null)
|
if (score.NewValue == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (score.NewValue.Mods.Any(m => !m.IsPlayable(ModUsage.SoloLocal)))
|
if (score.NewValue.Mods.Any(m => !m.UserPlayable))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var hitEvents = score.NewValue.HitEvents;
|
var hitEvents = score.NewValue.HitEvents;
|
||||||
|
@ -11,7 +11,6 @@ using osu.Framework.Logging;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
@ -48,7 +47,7 @@ namespace osu.Game.Screens.Play
|
|||||||
// Token request construction should happen post-load to allow derived classes to potentially prepare DI backings that are used to create the request.
|
// Token request construction should happen post-load to allow derived classes to potentially prepare DI backings that are used to create the request.
|
||||||
var tcs = new TaskCompletionSource<bool>();
|
var tcs = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
if (Mods.Value.Any(m => !m.IsPlayable(ModUsage.SoloLocal)))
|
if (Mods.Value.Any(m => !m.UserPlayable))
|
||||||
{
|
{
|
||||||
handleTokenFailure(new InvalidOperationException("Non-user playable mod selected."));
|
handleTokenFailure(new InvalidOperationException("Non-user playable mod selected."));
|
||||||
return false;
|
return false;
|
||||||
|
@ -18,7 +18,6 @@ using osu.Game.Graphics.Containers;
|
|||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking.Statistics;
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
@ -146,7 +145,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
if (Score != null)
|
if (Score != null)
|
||||||
{
|
{
|
||||||
// only show flair / animation when arriving after watching a play that isn't autoplay.
|
// only show flair / animation when arriving after watching a play that isn't autoplay.
|
||||||
bool shouldFlair = player != null && Score.Mods.All(m => m.IsPlayable(ModUsage.SoloLocal));
|
bool shouldFlair = player != null && Score.Mods.All(m => m.UserPlayable);
|
||||||
|
|
||||||
ScorePanelList.AddScore(Score, shouldFlair);
|
ScorePanelList.AddScore(Score, shouldFlair);
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ namespace osu.Game.Utils
|
|||||||
if (!CheckCompatibleSet(mods, out invalidMods))
|
if (!CheckCompatibleSet(mods, out invalidMods))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return checkValid(mods, m => m.Type != ModType.System && m.HasImplementation && m.IsPlayable(ModUsage.MultiplayerGlobal), out invalidMods);
|
return checkValid(mods, m => m.Type != ModType.System && m.HasImplementation && m.ValidForMultiplayer, out invalidMods);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -154,7 +154,7 @@ namespace osu.Game.Utils
|
|||||||
/// <param name="invalidMods">Invalid mods, if any were found. Will be null if all mods were valid.</param>
|
/// <param name="invalidMods">Invalid mods, if any were found. Will 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>
|
/// <returns>Whether the input mods were all valid. If false, <paramref name="invalidMods"/> will contain all invalid entries.</returns>
|
||||||
public static bool CheckValidFreeModsForMultiplayer(IEnumerable<Mod> mods, [NotNullWhen(false)] out List<Mod>? invalidMods)
|
public static bool CheckValidFreeModsForMultiplayer(IEnumerable<Mod> mods, [NotNullWhen(false)] out List<Mod>? invalidMods)
|
||||||
=> checkValid(mods, m => m.Type != ModType.System && m.HasImplementation && m.IsPlayable(ModUsage.MultiplayerLocal) && !(m is MultiMod), out invalidMods);
|
=> checkValid(mods, m => m.Type != ModType.System && m.HasImplementation && m.ValidForMultiplayerAsFreeMod && !(m is MultiMod), out invalidMods);
|
||||||
|
|
||||||
private static bool checkValid(IEnumerable<Mod> mods, Predicate<Mod> valid, [NotNullWhen(false)] out List<Mod>? invalidMods)
|
private static bool checkValid(IEnumerable<Mod> mods, Predicate<Mod> valid, [NotNullWhen(false)] out List<Mod>? invalidMods)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user