diff --git a/osu.Android.props b/osu.Android.props
index 97fc97153c..9aba8e236c 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs
index 062f2ce10c..6b88f21bcd 100644
--- a/osu.Android/OsuGameAndroid.cs
+++ b/osu.Android/OsuGameAndroid.cs
@@ -106,9 +106,9 @@ namespace osu.Android
private class AndroidBatteryInfo : BatteryInfo
{
- public override double ChargeLevel => Battery.ChargeLevel;
+ public override double? ChargeLevel => Battery.ChargeLevel;
- public override bool IsCharging => Battery.PowerSource != BatteryPowerSource.Battery;
+ public override bool OnBattery => Battery.PowerSource == BatteryPowerSource.Battery;
}
}
}
diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs
index d0b6953c30..9cf68d88d9 100644
--- a/osu.Desktop/DiscordRichPresence.cs
+++ b/osu.Desktop/DiscordRichPresence.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Text;
using DiscordRPC;
@@ -26,15 +24,15 @@ namespace osu.Desktop
{
private const string client_id = "367827983903490050";
- private DiscordRpcClient client;
+ private DiscordRpcClient client = null!;
[Resolved]
- private IBindable ruleset { get; set; }
+ private IBindable ruleset { get; set; } = null!;
- private IBindable user;
+ private IBindable user = null!;
[Resolved]
- private IAPIProvider api { get; set; }
+ private IAPIProvider api { get; set; } = null!;
private readonly IBindable status = new Bindable();
private readonly IBindable activity = new Bindable();
@@ -130,7 +128,7 @@ namespace osu.Desktop
presence.Assets.LargeImageText = string.Empty;
else
{
- if (user.Value.RulesetsStatistics != null && user.Value.RulesetsStatistics.TryGetValue(ruleset.Value.ShortName, out UserStatistics statistics))
+ if (user.Value.RulesetsStatistics != null && user.Value.RulesetsStatistics.TryGetValue(ruleset.Value.ShortName, out UserStatistics? statistics))
presence.Assets.LargeImageText = $"{user.Value.Username}" + (statistics.GlobalRank > 0 ? $" (rank #{statistics.GlobalRank:N0})" : string.Empty);
else
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.GlobalRank > 0 ? $" (rank #{user.Value.Statistics.GlobalRank:N0})" : string.Empty);
@@ -164,7 +162,7 @@ namespace osu.Desktop
});
}
- private IBeatmapInfo getBeatmap(UserActivity activity)
+ private IBeatmapInfo? getBeatmap(UserActivity activity)
{
switch (activity)
{
@@ -183,10 +181,10 @@ namespace osu.Desktop
switch (activity)
{
case UserActivity.InGame game:
- return game.BeatmapInfo.ToString();
+ return game.BeatmapInfo.ToString() ?? string.Empty;
case UserActivity.Editing edit:
- return edit.BeatmapInfo.ToString();
+ return edit.BeatmapInfo.ToString() ?? string.Empty;
case UserActivity.InLobby lobby:
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
diff --git a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs
index 7b0bd69363..0ad68919a2 100644
--- a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs
+++ b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Desktop.LegacyIpc
{
///
@@ -13,7 +11,7 @@ namespace osu.Desktop.LegacyIpc
///
public class LegacyIpcDifficultyCalculationRequest
{
- public string BeatmapFile { get; set; }
+ public string BeatmapFile { get; set; } = string.Empty;
public int RulesetId { get; set; }
public int Mods { get; set; }
}
diff --git a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationResponse.cs b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationResponse.cs
index 6d36cbc4b6..7b9fae5797 100644
--- a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationResponse.cs
+++ b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationResponse.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Desktop.LegacyIpc
{
///
diff --git a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs
index 4df477191d..8d0add32d1 100644
--- a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs
+++ b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Platform;
using Newtonsoft.Json.Linq;
@@ -39,17 +37,20 @@ namespace osu.Desktop.LegacyIpc
public new object Value
{
get => base.Value;
- set => base.Value = new Data
- {
- MessageType = value.GetType().Name,
- MessageData = value
- };
+ set => base.Value = new Data(value.GetType().Name, value);
}
public class Data
{
- public string MessageType { get; set; }
- public object MessageData { get; set; }
+ public string MessageType { get; }
+
+ public object MessageData { get; }
+
+ public Data(string messageType, object messageData)
+ {
+ MessageType = messageType;
+ MessageData = messageData;
+ }
}
}
}
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index 524436235e..d9ad95f96a 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -29,6 +29,8 @@ using osu.Game.IPC;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Settings.Sections;
using osu.Game.Overlays.Settings.Sections.Input;
+using osu.Game.Utils;
+using SDL2;
namespace osu.Desktop
{
@@ -166,6 +168,8 @@ namespace osu.Desktop
}
}
+ protected override BatteryInfo CreateBatteryInfo() => new SDL2BatteryInfo();
+
private readonly List importableFiles = new List();
private ScheduledDelegate? importSchedule;
@@ -206,5 +210,23 @@ namespace osu.Desktop
base.Dispose(isDisposing);
osuSchemeLinkIPCChannel?.Dispose();
}
+
+ private class SDL2BatteryInfo : BatteryInfo
+ {
+ public override double? ChargeLevel
+ {
+ get
+ {
+ SDL.SDL_GetPowerInfo(out _, out int percentage);
+
+ if (percentage == -1)
+ return null;
+
+ return percentage / 100.0;
+ }
+ }
+
+ public override bool OnBattery => SDL.SDL_GetPowerInfo(out _, out _) == SDL.SDL_PowerState.SDL_POWERSTATE_ON_BATTERY;
+ }
}
}
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index 19cf7f5d46..5a1373e040 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.IO;
using System.Runtime.Versioning;
@@ -21,9 +19,13 @@ namespace osu.Desktop
{
public static class Program
{
+#if DEBUG
+ private const string base_game_name = @"osu-development";
+#else
private const string base_game_name = @"osu";
+#endif
- private static LegacyTcpIpcProvider legacyIpc;
+ private static LegacyTcpIpcProvider? legacyIpc;
[STAThread]
public static void Main(string[] args)
diff --git a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs
index f0d95ba194..9959b24b35 100644
--- a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs
+++ b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Security.Principal;
using osu.Framework;
@@ -21,7 +19,7 @@ namespace osu.Desktop.Security
public class ElevatedPrivilegesChecker : Component
{
[Resolved]
- private INotificationOverlay notifications { get; set; }
+ private INotificationOverlay notifications { get; set; } = null!;
private bool elevated;
diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs
index 4e5f8d37b1..d53db6c516 100644
--- a/osu.Desktop/Updater/SquirrelUpdateManager.cs
+++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Runtime.Versioning;
using System.Threading.Tasks;
@@ -26,8 +24,8 @@ namespace osu.Desktop.Updater
[SupportedOSPlatform("windows")]
public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager
{
- private UpdateManager updateManager;
- private INotificationOverlay notificationOverlay;
+ private UpdateManager? updateManager;
+ private INotificationOverlay notificationOverlay = null!;
public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited();
@@ -50,12 +48,12 @@ namespace osu.Desktop.Updater
protected override async Task PerformUpdateCheck() => await checkForUpdateAsync().ConfigureAwait(false);
- private async Task checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
+ private async Task checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification? notification = null)
{
// should we schedule a retry on completion of this check?
bool scheduleRecheck = true;
- const string github_token = null; // TODO: populate.
+ const string? github_token = null; // TODO: populate.
try
{
@@ -145,7 +143,7 @@ namespace osu.Desktop.Updater
private class UpdateCompleteNotification : ProgressCompletionNotification
{
[Resolved]
- private OsuGame game { get; set; }
+ private OsuGame game { get; set; } = null!;
public UpdateCompleteNotification(SquirrelUpdateManager updateManager)
{
@@ -154,7 +152,7 @@ namespace osu.Desktop.Updater
Activated = () =>
{
updateManager.PrepareUpdateAsync()
- .ContinueWith(_ => updateManager.Schedule(() => game?.AttemptExit()));
+ .ContinueWith(_ => updateManager.Schedule(() => game.AttemptExit()));
return true;
};
}
diff --git a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs
index 0cb4ba9c04..284d25306d 100644
--- a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs
+++ b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -14,12 +12,12 @@ namespace osu.Desktop.Windows
{
public class GameplayWinKeyBlocker : Component
{
- private Bindable disableWinKey;
- private IBindable localUserPlaying;
- private IBindable isActive;
+ private Bindable disableWinKey = null!;
+ private IBindable localUserPlaying = null!;
+ private IBindable isActive = null!;
[Resolved]
- private GameHost host { get; set; }
+ private GameHost host { get; set; } = null!;
[BackgroundDependencyLoader]
private void load(ILocalUserPlayInfo localUserInfo, OsuConfigManager config)
diff --git a/osu.Desktop/Windows/WindowsKey.cs b/osu.Desktop/Windows/WindowsKey.cs
index c69cce6200..1051e61f2f 100644
--- a/osu.Desktop/Windows/WindowsKey.cs
+++ b/osu.Desktop/Windows/WindowsKey.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Runtime.InteropServices;
@@ -21,7 +19,7 @@ namespace osu.Desktop.Windows
private const int wm_syskeyup = 261;
//Resharper disable once NotAccessedField.Local
- private static LowLevelKeyboardProcDelegate keyboardHookDelegate; // keeping a reference alive for the GC
+ private static LowLevelKeyboardProcDelegate? keyboardHookDelegate; // keeping a reference alive for the GC
private static IntPtr keyHook;
[StructLayout(LayoutKind.Explicit)]
diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/CatchModMirrorTest.cs b/osu.Game.Rulesets.Catch.Tests/Mods/CatchModMirrorTest.cs
index 19321a48b9..fbbfee6b60 100644
--- a/osu.Game.Rulesets.Catch.Tests/Mods/CatchModMirrorTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Mods/CatchModMirrorTest.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Utils;
diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs
index ffc5734f01..bbe543e73e 100644
--- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Utils;
diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs
index 886822f9a5..3e06e78dba 100644
--- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs
index 3209be12d5..c01aff0aa0 100644
--- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs
index 8dd6f82c57..2078e1453f 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs
@@ -9,7 +9,6 @@ using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Framework.Testing;
-using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
using osuTK;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
index c5ca595fd6..50e48101d3 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Replays;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs b/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs
index 10a0809e05..7eda6b37d3 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModClassic.cs b/osu.Game.Rulesets.Catch/Mods/CatchModClassic.cs
index 904656993e..9624e84018 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModClassic.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModClassic.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
index 8d4b57c244..cae19e9468 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
index 6927d7953f..e59a0a0431 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
index c58ce9b07d..57c06e1cd1 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs b/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
index bea9b094fa..16ef56d845 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
index d166646eaf..abe391ba4e 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Configuration;
@@ -39,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Mods
protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield);
- private CatchPlayfield playfield;
+ private CatchPlayfield playfield = null!;
public override void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs
index 1fe892c9b5..63203dd57c 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
index 0c7886be10..ce06b841aa 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
index 39b992b3f5..93eadcc13e 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Beatmaps;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
index b4fbc9d566..51516edacd 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Objects;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs b/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs
index 89fc40356d..a97e940a64 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Beatmaps;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs b/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs
index 6b28d1a127..6d2565440a 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
index 1fd2227eb7..9e38913be7 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
index 89e7e4bcd6..3c02646e99 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs
index 385d4c50c0..a24a6227fe 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Bindables;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
index 0a74ee4fbb..fb92399102 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
index f4d6fb9ab3..60f1614d98 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
@@ -20,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public override string Description => @"Use the mouse to control the catcher.";
- private DrawableRuleset drawableRuleset;
+ private DrawableRuleset drawableRuleset = null!;
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs b/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
index d98829137c..68e01391ce 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods
diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs
index c5e5e59dd2..c06d9f520f 100644
--- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs
@@ -6,7 +6,6 @@
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning;
using osuTK.Graphics;
diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs
index 538c8b13d1..60363aaeef 100644
--- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs
index 4222be0359..7970d5b594 100644
--- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModInvert.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModInvert.cs
index 4c97f65b07..f2cc254e38 100644
--- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModInvert.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModInvert.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Tests.Visual;
diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs
index 9612543483..2e3b21aed7 100644
--- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Objects;
diff --git a/osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs b/osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs
index 0bae893810..410386c9d5 100644
--- a/osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs
+++ b/osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
index 8f8b7cb091..050b302bd8 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs
index f9c51bf6a2..d444c9b634 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs
index 8d54923e7b..f0db742eac 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModClassic.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModClassic.cs
index 603d096ed7..073dda9de8 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModClassic.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModClassic.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs
index 20dfc14f09..614ef76a3b 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mania.Objects;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDaycore.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDaycore.cs
index b166f3ebc3..bec0a6a1d3 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModDaycore.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDaycore.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs
index d053e64315..0817f8f9fc 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDoubleTime.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDoubleTime.cs
index 66627e6ed3..a302f95966 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModDoubleTime.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDoubleTime.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs
index f25a77278b..c78bf72979 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs
index ff236d33bf..4093aeb2a7 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs
index ddbd7c5d6a..f80c9e1f7c 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Game.Rulesets.Mania.UI;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
index 58005df561..8ef5bfd94c 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHalfTime.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHalfTime.cs
index 87c81c2866..014954dd60 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModHalfTime.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHalfTime.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
index 380edca515..d9de06a811 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs
index 698555ddc4..e3ac624a6e 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Game.Rulesets.Mania.UI;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs
index 8c4fd0a8fc..a65938184c 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModInvert.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModInvert.cs
index f202b859b1..4cbdaee323 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModInvert.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModInvert.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
index 9ce4fb6a48..948979505c 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey1 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs
index f378ce3435..684370fc3d 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey10 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
index 5812df80f5..de91902ca8 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey2 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
index 4116ed5ceb..8575a96bde 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey3 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs
index 9879fec686..54ea3afa07 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey4 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs
index 646386b0d8..e9a9bba5bd 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey5 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs
index 56af9ed589..b9606d1cb5 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey6 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs
index a0a7116ed7..b80d794085 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey7 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs
index fc8ecdb9ea..3462d634a4 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey8 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs
index c495a6c82f..83c505c048 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKey9 : ManiaKeyMod
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
index 6e56981fc8..9c3744ea98 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs
index 076f634968..33ebcf303a 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModNightcore.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModNightcore.cs
index 9ae664e1f6..4cc712060c 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModNightcore.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModNightcore.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModNoFail.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModNoFail.cs
index 487f32dc26..e8988be548 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModNoFail.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModNoFail.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPerfect.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPerfect.cs
index 2789a2a06e..2e22e23dbd 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModPerfect.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPerfect.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs
index 5da29e5a1d..3c24e91d54 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Framework.Graphics;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
index 22347d21b8..dfb02408d2 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModSuddenDeath.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModSuddenDeath.cs
index 17759d718e..ecc343ecaa 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModSuddenDeath.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModSuddenDeath.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs b/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs
index 4f005a0c70..d3cb3bcf59 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests.Mods
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs
index 3d59e4fb51..5e46498aca 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs
index 378b71ccf7..3563995234 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs
@@ -1,10 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
@@ -35,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
private void runSpmTest(Mod mod)
{
- SpinnerSpmCalculator spmCalculator = null;
+ SpinnerSpmCalculator? spmCalculator = null;
CreateModTest(new ModTestData
{
@@ -61,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
return spmCalculator != null;
});
- AddUntilStep("SPM is correct", () => Precision.AlmostEquals(spmCalculator.Result.Value, 477, 5));
+ AddUntilStep("SPM is correct", () => Precision.AlmostEquals(spmCalculator.AsNonNull().Result.Value, 477, 5));
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs
index 80dc83d7dc..9d06ff5801 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs
index e1bed5153b..335ef31019 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Framework.Utils;
using osu.Game.Rulesets.Osu.Mods;
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs
index 5ed25baca3..e692f8ecbc 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
@@ -162,7 +160,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
private class TestOsuModHidden : OsuModHidden
{
- public new HitObject FirstObject => base.FirstObject;
+ public new HitObject? FirstObject => base.FirstObject;
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs
index 1f1db04c24..9b49e60363 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Rulesets.Osu.Mods;
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs
index 99c9036ac0..68669d1a53 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
@@ -33,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
[Test]
public void TestModCopy()
{
- OsuModMuted muted = null;
+ OsuModMuted muted = null!;
AddStep("create inversed mod", () => muted = new OsuModMuted
{
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs
index 47e7ad320c..44404ca245 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs
index b7669624ff..985baa8cf5 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs
index 4f6d6376bf..e121e6103d 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -30,8 +28,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
[Test]
public void TestSpinnerAutoCompleted()
{
- DrawableSpinner spinner = null;
- JudgementResult lastResult = null;
+ DrawableSpinner? spinner = null;
+ JudgementResult? lastResult = null;
CreateModTest(new ModTestData
{
@@ -63,11 +61,11 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
[TestCase(null)]
[TestCase(typeof(OsuModDoubleTime))]
[TestCase(typeof(OsuModHalfTime))]
- public void TestSpinRateUnaffectedByMods(Type additionalModType)
+ public void TestSpinRateUnaffectedByMods(Type? additionalModType)
{
var mods = new List { new OsuModSpunOut() };
if (additionalModType != null)
- mods.Add((Mod)Activator.CreateInstance(additionalModType));
+ mods.Add((Mod)Activator.CreateInstance(additionalModType)!);
CreateModTest(new ModTestData
{
@@ -96,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
[Test]
public void TestSpinnerGetsNoBonusScore()
{
- DrawableSpinner spinner = null;
+ DrawableSpinner? spinner = null;
List results = new List();
CreateModTest(new ModTestData
diff --git a/osu.Game.Rulesets.Osu/Mods/IHidesApproachCircles.cs b/osu.Game.Rulesets.Osu/Mods/IHidesApproachCircles.cs
index affc0bae6a..4a3b187e83 100644
--- a/osu.Game.Rulesets.Osu/Mods/IHidesApproachCircles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/IHidesApproachCircles.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Osu.Mods
{
///
diff --git a/osu.Game.Rulesets.Osu/Mods/IRequiresApproachCircles.cs b/osu.Game.Rulesets.Osu/Mods/IRequiresApproachCircles.cs
index a108f5fd14..1458abfe05 100644
--- a/osu.Game.Rulesets.Osu/Mods/IRequiresApproachCircles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/IRequiresApproachCircles.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
namespace osu.Game.Rulesets.Osu.Mods
{
///
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs
index e25845f5ab..e6889403a3 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs
index a3f6448457..872fcf7e9b 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -30,11 +28,11 @@ namespace osu.Game.Rulesets.Osu.Mods
public bool RestartOnFail => false;
- private OsuInputManager inputManager;
+ private OsuInputManager inputManager = null!;
- private IFrameStableClock gameplayClock;
+ private IFrameStableClock gameplayClock = null!;
- private List replayFrames;
+ private List replayFrames = null!;
private int currentFrame;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs
index c4de77b8a3..7c1f6be9ed 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
index 71bdd98457..9e71f657ce 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs
index 17a9a81de8..56665db770 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@@ -33,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
public override Type[] IncompatibleMods => new[] { typeof(OsuModFlashlight) };
- private DrawableOsuBlinds blinds;
+ private DrawableOsuBlinds blinds = null!;
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
@@ -55,9 +53,12 @@ namespace osu.Game.Rulesets.Osu.Mods
///
/// Black background boxes behind blind panel textures.
///
- private Box blackBoxLeft, blackBoxRight;
+ private Box blackBoxLeft = null!, blackBoxRight = null!;
- private Drawable panelLeft, panelRight, bgPanelLeft, bgPanelRight;
+ private Drawable panelLeft = null!;
+ private Drawable panelRight = null!;
+ private Drawable bgPanelLeft = null!;
+ private Drawable bgPanelRight = null!;
private readonly Beatmap beatmap;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs b/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs
index d5096619b9..769694baf4 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs
index 00009f4c3d..e021992f86 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Framework.Bindables;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDaycore.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDaycore.cs
index c4cc0b4f48..371dfe6a1a 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModDaycore.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModDaycore.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs
index e95e61312e..ee6a7815e2 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs
index be159523b7..3a6b232f9f 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDoubleTime.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDoubleTime.cs
index b86efe84ee..700a3f44bc 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModDoubleTime.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModDoubleTime.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs b/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs
index 90b22e8d9c..06b5b6cfb8 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
index b72e6b4dcb..e5a458488e 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Framework.Bindables;
@@ -53,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override float DefaultFlashlightSize => 180;
- private OsuFlashlight flashlight;
+ private OsuFlashlight flashlight = null!;
protected override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight(this);
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs
index 34840de983..182d6eeb4b 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHalfTime.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHalfTime.cs
index 54c5c56ca6..4769e7660b 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModHalfTime.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModHalfTime.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs
index 1f25655c8c..5430929143 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs
index 253eaf473b..97f201b2cc 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Diagnostics;
using System.Linq;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
index f9a74d2a3a..9316f9ed74 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
@@ -28,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel) };
- private IFrameStableClock gameplayClock;
+ private IFrameStableClock gameplayClock = null!;
[SettingSource("Attraction strength", "How strong the pull is.", 0)]
public BindableFloat AttractionStrength { get; } = new BindableFloat(0.5f)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs
index 1d822a2d4c..3faca0b01f 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Bindables;
using osu.Game.Configuration;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs
index 1d4650a379..5e3ee37b61 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNightcore.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNightcore.cs
index b1fe066a1e..b7838ebaa7 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModNightcore.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModNightcore.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoFail.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoFail.cs
index c20fcf0b1b..9f707a5aa6 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModNoFail.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoFail.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs
index fe415cb967..3eb8982f5d 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Framework.Bindables;
@@ -21,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Description => "Where's the cursor?";
- private PeriodTracker spinnerPeriods;
+ private PeriodTracker spinnerPeriods = null!;
[SettingSource(
"Hidden at combo",
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs
index 44942e9e37..59984f9a7b 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModPerfect.cs b/osu.Game.Rulesets.Osu/Mods/OsuModPerfect.cs
index bde7718da5..33581405a6 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModPerfect.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModPerfect.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
index 2030156f2e..908bb34ed6 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -31,9 +29,9 @@ namespace osu.Game.Rulesets.Osu.Mods
private bool isDownState;
private bool wasLeft;
- private OsuInputManager osuInputManager;
+ private OsuInputManager osuInputManager = null!;
- private ReplayState state;
+ private ReplayState state = null!;
private double lastStateChangeTime;
private bool hasReplay;
@@ -134,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Mods
wasLeft = !wasLeft;
}
- state?.Apply(osuInputManager.CurrentState, osuInputManager);
+ state.Apply(osuInputManager.CurrentState, osuInputManager);
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs
index 16e7780af0..95e7d13ee7 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
index 61028a1ee8..d9ab749ad3 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs
index 565ff415be..0b34ab28a3 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using System.Threading;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs
index 4eb7659152..429fe30fc5 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
index f03bcffdc8..623157a427 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -96,11 +94,7 @@ namespace osu.Game.Rulesets.Osu.Mods
#region Private Fields
- private ControlPointInfo controlPointInfo;
-
- private List originalHitObjects;
-
- private Random rng;
+ private ControlPointInfo controlPointInfo = null!;
#endregion
@@ -171,16 +165,17 @@ namespace osu.Game.Rulesets.Osu.Mods
public override void ApplyToBeatmap(IBeatmap beatmap)
{
Seed.Value ??= RNG.Next();
- rng = new Random(Seed.Value.Value);
+
+ var rng = new Random(Seed.Value.Value);
var osuBeatmap = (OsuBeatmap)beatmap;
if (osuBeatmap.HitObjects.Count == 0) return;
controlPointInfo = osuBeatmap.ControlPointInfo;
- originalHitObjects = osuBeatmap.HitObjects.OrderBy(x => x.StartTime).ToList();
- var hitObjects = generateBeats(osuBeatmap)
+ var originalHitObjects = osuBeatmap.HitObjects.OrderBy(x => x.StartTime).ToList();
+ var hitObjects = generateBeats(osuBeatmap, originalHitObjects)
.Select(beat =>
{
var newCircle = new HitCircle();
@@ -189,18 +184,18 @@ namespace osu.Game.Rulesets.Osu.Mods
return (OsuHitObject)newCircle;
}).ToList();
- addHitSamples(hitObjects);
+ addHitSamples(hitObjects, originalHitObjects);
- fixComboInfo(hitObjects);
+ fixComboInfo(hitObjects, originalHitObjects);
- randomizeCirclePos(hitObjects);
+ randomizeCirclePos(hitObjects, rng);
osuBeatmap.HitObjects = hitObjects;
base.ApplyToBeatmap(beatmap);
}
- private IEnumerable generateBeats(IBeatmap beatmap)
+ private IEnumerable generateBeats(IBeatmap beatmap, IReadOnlyCollection originalHitObjects)
{
double startTime = originalHitObjects.First().StartTime;
double endTime = originalHitObjects.Last().GetEndTime();
@@ -213,7 +208,7 @@ namespace osu.Game.Rulesets.Osu.Mods
// Remove beats before startTime
.Where(beat => almostBigger(beat, startTime))
// Remove beats during breaks
- .Where(beat => !isInsideBreakPeriod(beatmap.Breaks, beat))
+ .Where(beat => !isInsideBreakPeriod(originalHitObjects, beatmap.Breaks, beat))
.ToList();
// Remove beats that are too close to the next one (e.g. due to timing point changes)
@@ -228,7 +223,7 @@ namespace osu.Game.Rulesets.Osu.Mods
return beats;
}
- private void addHitSamples(IEnumerable hitObjects)
+ private void addHitSamples(IEnumerable hitObjects, List originalHitObjects)
{
foreach (var obj in hitObjects)
{
@@ -240,7 +235,7 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
- private void fixComboInfo(List hitObjects)
+ private void fixComboInfo(List hitObjects, List originalHitObjects)
{
// Copy combo indices from an original object at the same time or from the closest preceding object
// (Objects lying between two combos are assumed to belong to the preceding combo)
@@ -274,7 +269,7 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
- private void randomizeCirclePos(IReadOnlyList hitObjects)
+ private void randomizeCirclePos(IReadOnlyList hitObjects, Random rng)
{
if (hitObjects.Count == 0) return;
@@ -355,9 +350,10 @@ namespace osu.Game.Rulesets.Osu.Mods
/// The given time is also considered to be inside a break if it is earlier than the
/// start time of the first original hit object after the break.
///
+ /// Hit objects order by time.
/// The breaks of the beatmap.
/// The time to be checked.=
- private bool isInsideBreakPeriod(IEnumerable breaks, double time)
+ private bool isInsideBreakPeriod(IReadOnlyCollection originalHitObjects, IEnumerable breaks, double time)
{
return breaks.Any(breakPeriod =>
{
@@ -405,7 +401,7 @@ namespace osu.Game.Rulesets.Osu.Mods
/// The list of hit objects in a beatmap, ordered by StartTime
/// The point in time to get samples for
/// Hit samples
- private IList getSamplesAtTime(IEnumerable hitObjects, double time)
+ private IList? getSamplesAtTime(IEnumerable hitObjects, double time)
{
// Get a hit object that
// either has StartTime equal to the target time
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
index f8c1e1639d..7276cc753c 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs
index 6e5dd45a7a..d862d36670 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@@ -59,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
- private void applyCirclePieceState(DrawableOsuHitObject hitObject, IDrawable hitCircle = null)
+ private void applyCirclePieceState(DrawableOsuHitObject hitObject, IDrawable? hitCircle = null)
{
var h = hitObject.HitObject;
using (hitObject.BeginAbsoluteSequence(h.StartTime - h.TimePreempt))
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs
index 84906f6eed..4354ecbe9a 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
index 8acd4fc422..3f1c3aa812 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
@@ -1,11 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
+using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
@@ -24,8 +24,15 @@ namespace osu.Game.Rulesets.Osu.Mods
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform), typeof(OsuModMagnetised), typeof(OsuModRepel) };
- private const int wiggle_duration = 90; // (ms) Higher = fewer wiggles
- private const int wiggle_strength = 10; // Higher = stronger wiggles
+ private const int wiggle_duration = 100; // (ms) Higher = fewer wiggles
+
+ [SettingSource("Strength", "Multiplier applied to the wiggling strength.")]
+ public BindableDouble Strength { get; } = new BindableDouble(1)
+ {
+ MinValue = 0.1f,
+ MaxValue = 2f,
+ Precision = 0.1f
+ };
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => drawableOnApplyCustomUpdateState(hitObject, state);
@@ -49,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Mods
void wiggle()
{
float nextAngle = (float)(objRand.NextDouble() * 2 * Math.PI);
- float nextDist = (float)(objRand.NextDouble() * wiggle_strength);
+ float nextDist = (float)(objRand.NextDouble() * Strength.Value * 7);
drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), wiggle_duration);
}
diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs
index b77d4addee..aaace89cd5 100644
--- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.Diagnostics;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -32,37 +30,42 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
};
}
- protected override void OnTrackingChanged(ValueChangedEvent tracking)
+ protected override void OnSliderPress()
{
- Debug.Assert(ParentObject != null);
-
const float duration = 300f;
- if (ParentObject.Judged)
- return;
+ if (Precision.AlmostEquals(0, Alpha))
+ this.ScaleTo(1);
- if (tracking.NewValue)
- {
- if (Precision.AlmostEquals(0, Alpha))
- this.ScaleTo(1);
+ this.ScaleTo(DrawableSliderBall.FOLLOW_AREA, duration, Easing.OutQuint)
+ .FadeIn(duration, Easing.OutQuint);
+ }
- this.ScaleTo(DrawableSliderBall.FOLLOW_AREA, duration, Easing.OutQuint)
- .FadeTo(1f, duration, Easing.OutQuint);
- }
- else
- {
- this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.2f, duration / 2, Easing.OutQuint)
- .FadeTo(0, duration / 2, Easing.OutQuint);
- }
+ protected override void OnSliderRelease()
+ {
+ const float duration = 150;
+
+ this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.2f, duration, Easing.OutQuint)
+ .FadeTo(0, duration, Easing.OutQuint);
}
protected override void OnSliderEnd()
{
- const float fade_duration = 300;
+ const float duration = 300;
- // intentionally pile on an extra FadeOut to make it happen much faster
- this.ScaleTo(1, fade_duration, Easing.OutQuint);
- this.FadeOut(fade_duration / 2, Easing.OutQuint);
+ this.ScaleTo(1, duration, Easing.OutQuint)
+ .FadeOut(duration / 2, Easing.OutQuint);
+ }
+
+ protected override void OnSliderTick()
+ {
+ this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.08f, 40, Easing.OutQuint)
+ .Then()
+ .ScaleTo(DrawableSliderBall.FOLLOW_AREA, 200f, Easing.OutQuint);
+ }
+
+ protected override void OnSliderBreak()
+ {
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs
index 321705d25e..9eb8e66c83 100644
--- a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs
@@ -1,8 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.Diagnostics;
using osu.Framework.Allocation;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
@@ -23,7 +23,17 @@ namespace osu.Game.Rulesets.Osu.Skinning
[BackgroundDependencyLoader]
private void load()
{
- ((DrawableSlider?)ParentObject)?.Tracking.BindValueChanged(OnTrackingChanged, true);
+ ((DrawableSlider?)ParentObject)?.Tracking.BindValueChanged(tracking =>
+ {
+ Debug.Assert(ParentObject != null);
+ if (ParentObject.Judged)
+ return;
+
+ if (tracking.NewValue)
+ OnSliderPress();
+ else
+ OnSliderRelease();
+ }, true);
}
protected override void LoadComplete()
@@ -48,13 +58,46 @@ namespace osu.Game.Rulesets.Osu.Skinning
private void updateStateTransforms(DrawableHitObject drawableObject, ArmedState state)
{
- // Gets called by slider ticks, tails, etc., leading to duplicated
- // animations which may negatively affect performance
- if (drawableObject is not DrawableSlider)
- return;
+ Debug.Assert(ParentObject != null);
- using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
- OnSliderEnd();
+ switch (state)
+ {
+ case ArmedState.Hit:
+ switch (drawableObject)
+ {
+ case DrawableSliderTail:
+ // Use ParentObject instead of drawableObject because slider tail's
+ // HitStateUpdateTime is ~36ms before the actual slider end (aka slider
+ // tail leniency)
+ using (BeginAbsoluteSequence(ParentObject.HitStateUpdateTime))
+ OnSliderEnd();
+ break;
+
+ case DrawableSliderTick:
+ case DrawableSliderRepeat:
+ using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
+ OnSliderTick();
+ break;
+ }
+
+ break;
+
+ case ArmedState.Miss:
+ switch (drawableObject)
+ {
+ case DrawableSliderTail:
+ case DrawableSliderTick:
+ case DrawableSliderRepeat:
+ // Despite above comment, ok to use drawableObject.HitStateUpdateTime
+ // here, since on stable, the break anim plays right when the tail is
+ // missed, not when the slider ends
+ using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
+ OnSliderBreak();
+ break;
+ }
+
+ break;
+ }
}
protected override void Dispose(bool isDisposing)
@@ -68,8 +111,14 @@ namespace osu.Game.Rulesets.Osu.Skinning
}
}
- protected abstract void OnTrackingChanged(ValueChangedEvent tracking);
+ protected abstract void OnSliderPress();
+
+ protected abstract void OnSliderRelease();
protected abstract void OnSliderEnd();
+
+ protected abstract void OnSliderTick();
+
+ protected abstract void OnSliderBreak();
}
}
diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs
index 5b7da5a1ba..0d12fb01f5 100644
--- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs
@@ -3,7 +3,6 @@
using System;
using System.Diagnostics;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
@@ -21,29 +20,20 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
InternalChild = animationContent;
}
- protected override void OnTrackingChanged(ValueChangedEvent tracking)
+ protected override void OnSliderPress()
{
Debug.Assert(ParentObject != null);
- if (ParentObject.Judged)
- return;
-
double remainingTime = Math.Max(0, ParentObject.HitStateUpdateTime - Time.Current);
// Note that the scale adjust here is 2 instead of DrawableSliderBall.FOLLOW_AREA to match legacy behaviour.
// This means the actual tracking area for gameplay purposes is larger than the sprite (but skins may be accounting for this).
- if (tracking.NewValue)
- {
- // TODO: Follow circle should bounce on each slider tick.
- this.ScaleTo(0.5f).ScaleTo(2f, Math.Min(180f, remainingTime), Easing.Out)
- .FadeTo(0).FadeTo(1f, Math.Min(60f, remainingTime));
- }
- else
- {
- // TODO: Should animate only at the next slider tick if we want to match stable perfectly.
- this.ScaleTo(4f, 100)
- .FadeTo(0f, 100);
- }
+ this.ScaleTo(0.5f).ScaleTo(2f, Math.Min(180f, remainingTime), Easing.Out)
+ .FadeTo(0).FadeTo(1f, Math.Min(60f, remainingTime));
+ }
+
+ protected override void OnSliderRelease()
+ {
}
protected override void OnSliderEnd()
@@ -51,5 +41,17 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
this.ScaleTo(1.6f, 200, Easing.Out)
.FadeOut(200, Easing.In);
}
+
+ protected override void OnSliderTick()
+ {
+ this.ScaleTo(2.2f)
+ .ScaleTo(2f, 200);
+ }
+
+ protected override void OnSliderBreak()
+ {
+ this.ScaleTo(4f, 100)
+ .FadeTo(0f, 100);
+ }
}
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TaikoModTestScene.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TaikoModTestScene.cs
index ca2f8102b7..3090facf8c 100644
--- a/osu.Game.Rulesets.Taiko.Tests/Mods/TaikoModTestScene.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TaikoModTestScene.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Taiko.Tests.Mods
diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModHidden.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModHidden.cs
index 0b28bfee2e..7abbb9d186 100644
--- a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModHidden.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModHidden.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
using osu.Game.Rulesets.Taiko.Mods;
diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs
index 917462c128..a83cc16413 100644
--- a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Mods;
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs
index 674ac5670f..c674f87f80 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Reflection;
using NUnit.Framework;
using osu.Framework.IO.Stores;
@@ -17,7 +15,6 @@ namespace osu.Game.Rulesets.Taiko.Tests
protected override IResourceStore RulesetResources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneTaikoHitObjectSamples)));
[TestCase("taiko-normal-hitnormal")]
- [TestCase("normal-hitnormal")]
[TestCase("hitnormal")]
public void TestDefaultCustomSampleFromBeatmap(string expectedSample)
{
@@ -29,7 +26,6 @@ namespace osu.Game.Rulesets.Taiko.Tests
}
[TestCase("taiko-normal-hitnormal")]
- [TestCase("normal-hitnormal")]
[TestCase("hitnormal")]
public void TestDefaultCustomSampleFromUserSkinFallback(string expectedSample)
{
@@ -41,7 +37,6 @@ namespace osu.Game.Rulesets.Taiko.Tests
}
[TestCase("taiko-normal-hitnormal2")]
- [TestCase("normal-hitnormal2")]
public void TestUserSkinLookupIgnoresSampleBank(string unwantedSample)
{
SetupSkins(string.Empty, unwantedSample);
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs
index 6c01bae027..4b74b4991e 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs
index d1c192f7fa..fee0cb2744 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs
index efb67825db..28124d16e1 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs
@@ -167,6 +167,8 @@ namespace osu.Game.Rulesets.Taiko.Mods
public void Update(Playfield playfield)
{
+ Debug.Assert(drawableTaikoRuleset != null);
+
// Classic taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened.
const float scroll_rate = 10;
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDaycore.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDaycore.cs
index 873aa7f992..84aa5e6bba 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModDaycore.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModDaycore.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Taiko.Mods
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs
index 564d023c5a..99a064d35f 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDoubleTime.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDoubleTime.cs
index b19c2eaccf..89581c57bd 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModDoubleTime.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModDoubleTime.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Taiko.Mods
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModEasy.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModEasy.cs
index a37e1c6f5c..ad6fdf59e2 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModEasy.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModEasy.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
index fe02a6caf9..66616486df 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Layout;
@@ -40,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, playfield);
- private TaikoPlayfield playfield;
+ private TaikoPlayfield playfield = null!;
public override void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
@@ -50,7 +48,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
private class TaikoFlashlight : Flashlight
{
- private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
+ private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.RequiredParentSizeToFit | Invalidation.DrawInfo);
private readonly TaikoPlayfield taikoPlayfield;
public TaikoFlashlight(TaikoModFlashlight modFlashlight, TaikoPlayfield taikoPlayfield)
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHalfTime.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHalfTime.cs
index ddfc2d1174..68d6305fbf 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHalfTime.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHalfTime.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Taiko.Mods
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHardRock.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHardRock.cs
index 7780936e7d..ba41175461 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHardRock.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHardRock.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs
index fe3e5ca11c..4c802978e3 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
@@ -32,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
///
private const float fade_out_duration = 0.375f;
- private DrawableTaikoRuleset drawableRuleset;
+ private DrawableTaikoRuleset drawableRuleset = null!;
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs
index 874e15406d..0f1e0b2885 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Objects;
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModNightcore.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModNightcore.cs
index e02a16f62f..7cb14635ff 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModNightcore.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModNightcore.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Objects;
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModNoFail.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModNoFail.cs
index 57ecf0224f..bf1006f1aa 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModNoFail.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModNoFail.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Taiko.Mods
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModPerfect.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModPerfect.cs
index c65dba243b..b107b14a03 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModPerfect.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModPerfect.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Taiko.Mods
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs
index f58f59aaf2..307a37bf2e 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Framework.Utils;
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs
index a3a644ab99..7be70d9ac3 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Taiko.Mods
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSuddenDeath.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSuddenDeath.cs
index 037e376ad2..7a0f6c7cd1 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSuddenDeath.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSuddenDeath.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Taiko.Mods
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs
index c9cba59760..3cb337c41d 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs
index 888271f32d..992316ca53 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using osu.Framework.Audio.Sample;
@@ -24,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
hasExplosion = new Lazy(() => GetTexture(getHitName(TaikoSkinComponents.TaikoExplosionGreat)) != null);
}
- public override Drawable GetDrawableComponent(ISkinComponent component)
+ public override Drawable? GetDrawableComponent(ISkinComponent component)
{
if (component is GameplaySkinComponent)
{
@@ -151,7 +149,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
throw new ArgumentOutOfRangeException(nameof(component), $"Invalid component type: {component}");
}
- public override ISample GetSample(ISampleInfo sampleInfo)
+ public override ISample? GetSample(ISampleInfo sampleInfo)
{
if (sampleInfo is HitSampleInfo hitSampleInfo)
return base.GetSample(new LegacyTaikoSampleInfo(hitSampleInfo));
@@ -173,9 +171,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
{
foreach (string name in base.LookupNames)
yield return name.Insert(name.LastIndexOf('/') + 1, "taiko-");
-
- foreach (string name in base.LookupNames)
- yield return name;
}
}
}
diff --git a/osu.Game.Tests/Audio/SampleInfoEqualityTest.cs b/osu.Game.Tests/Audio/SampleInfoEqualityTest.cs
index d05eb7994b..149096608f 100644
--- a/osu.Game.Tests/Audio/SampleInfoEqualityTest.cs
+++ b/osu.Game.Tests/Audio/SampleInfoEqualityTest.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using NUnit.Framework;
using osu.Game.Audio;
diff --git a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs
new file mode 100644
index 0000000000..f14288e7ba
--- /dev/null
+++ b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs
@@ -0,0 +1,100 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Extensions;
+using osu.Framework.Platform;
+using osu.Framework.Testing;
+using osu.Game.Beatmaps;
+using osu.Game.Database;
+using osu.Game.Rulesets;
+using osu.Game.Tests.Resources;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Tests.Beatmaps
+{
+ [HeadlessTest]
+ public class WorkingBeatmapManagerTest : OsuTestScene
+ {
+ private BeatmapManager beatmaps = null!;
+
+ private BeatmapSetInfo importedSet = null!;
+
+ [BackgroundDependencyLoader]
+ private void load(GameHost host, AudioManager audio, RulesetStore rulesets)
+ {
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
+ }
+
+ [SetUpSteps]
+ public void SetUpSteps()
+ {
+ AddStep("import beatmap", () =>
+ {
+ beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
+ });
+ }
+
+ [Test]
+ public void TestGetWorkingBeatmap() => AddStep("run test", () =>
+ {
+ Assert.That(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()), Is.Not.Null);
+ });
+
+ [Test]
+ public void TestCachedRetrievalNoFiles() => AddStep("run test", () =>
+ {
+ var beatmap = importedSet.Beatmaps.First();
+
+ Assert.That(beatmap.BeatmapSet?.Files, Is.Empty);
+
+ var first = beatmaps.GetWorkingBeatmap(beatmap);
+ var second = beatmaps.GetWorkingBeatmap(beatmap);
+
+ Assert.That(first, Is.SameAs(second));
+ Assert.That(first.BeatmapInfo.BeatmapSet?.Files, Has.Count.GreaterThan(0));
+ });
+
+ [Test]
+ public void TestCachedRetrievalWithFiles() => AddStep("run test", () =>
+ {
+ var beatmap = Realm.Run(r => r.Find(importedSet.Beatmaps.First().ID).Detach());
+
+ Assert.That(beatmap.BeatmapSet?.Files, Has.Count.GreaterThan(0));
+
+ var first = beatmaps.GetWorkingBeatmap(beatmap);
+ var second = beatmaps.GetWorkingBeatmap(beatmap);
+
+ Assert.That(first, Is.SameAs(second));
+ Assert.That(first.BeatmapInfo.BeatmapSet?.Files, Has.Count.GreaterThan(0));
+ });
+
+ [Test]
+ public void TestForcedRefetchRetrievalNoFiles() => AddStep("run test", () =>
+ {
+ var beatmap = importedSet.Beatmaps.First();
+
+ Assert.That(beatmap.BeatmapSet?.Files, Is.Empty);
+
+ var first = beatmaps.GetWorkingBeatmap(beatmap);
+ var second = beatmaps.GetWorkingBeatmap(beatmap, true);
+ Assert.That(first, Is.Not.SameAs(second));
+ });
+
+ [Test]
+ public void TestForcedRefetchRetrievalWithFiles() => AddStep("run test", () =>
+ {
+ var beatmap = Realm.Run(r => r.Find(importedSet.Beatmaps.First().ID).Detach());
+
+ Assert.That(beatmap.BeatmapSet?.Files, Has.Count.GreaterThan(0));
+
+ var first = beatmaps.GetWorkingBeatmap(beatmap);
+ var second = beatmaps.GetWorkingBeatmap(beatmap, true);
+ Assert.That(first, Is.Not.SameAs(second));
+ });
+ }
+}
diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs
index 9a8f29647d..604b87dc4c 100644
--- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs
+++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs
@@ -5,12 +5,15 @@
using System;
using System.IO;
+using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Framework.Testing;
+using osu.Game.Collections;
+using osu.Game.Database;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Collections.IO
@@ -29,7 +32,11 @@ namespace osu.Game.Tests.Collections.IO
await importCollectionsFromStream(osu, new MemoryStream());
- Assert.That(osu.CollectionManager.Collections.Count, Is.Zero);
+ osu.Realm.Run(realm =>
+ {
+ var collections = realm.All().ToList();
+ Assert.That(collections.Count, Is.Zero);
+ });
}
finally
{
@@ -49,18 +56,22 @@ namespace osu.Game.Tests.Collections.IO
await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db"));
- Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
+ osu.Realm.Run(realm =>
+ {
+ var collections = realm.All().ToList();
+ Assert.That(collections.Count, Is.EqualTo(2));
- // Even with no beatmaps imported, collections are tracking the hashes and will continue to.
- // In the future this whole mechanism will be replaced with having the collections in realm,
- // but until that happens it makes rough sense that we want to track not-yet-imported beatmaps
- // and have them associate with collections if/when they become available.
+ // Even with no beatmaps imported, collections are tracking the hashes and will continue to.
+ // In the future this whole mechanism will be replaced with having the collections in realm,
+ // but until that happens it makes rough sense that we want to track not-yet-imported beatmaps
+ // and have them associate with collections if/when they become available.
- Assert.That(osu.CollectionManager.Collections[0].Name.Value, Is.EqualTo("First"));
- Assert.That(osu.CollectionManager.Collections[0].BeatmapHashes.Count, Is.EqualTo(1));
+ Assert.That(collections[0].Name, Is.EqualTo("First"));
+ Assert.That(collections[0].BeatmapMD5Hashes.Count, Is.EqualTo(1));
- Assert.That(osu.CollectionManager.Collections[1].Name.Value, Is.EqualTo("Second"));
- Assert.That(osu.CollectionManager.Collections[1].BeatmapHashes.Count, Is.EqualTo(12));
+ Assert.That(collections[1].Name, Is.EqualTo("Second"));
+ Assert.That(collections[1].BeatmapMD5Hashes.Count, Is.EqualTo(12));
+ });
}
finally
{
@@ -80,13 +91,18 @@ namespace osu.Game.Tests.Collections.IO
await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db"));
- Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
+ osu.Realm.Run(realm =>
+ {
+ var collections = realm.All().ToList();
- Assert.That(osu.CollectionManager.Collections[0].Name.Value, Is.EqualTo("First"));
- Assert.That(osu.CollectionManager.Collections[0].BeatmapHashes.Count, Is.EqualTo(1));
+ Assert.That(collections.Count, Is.EqualTo(2));
- Assert.That(osu.CollectionManager.Collections[1].Name.Value, Is.EqualTo("Second"));
- Assert.That(osu.CollectionManager.Collections[1].BeatmapHashes.Count, Is.EqualTo(12));
+ Assert.That(collections[0].Name, Is.EqualTo("First"));
+ Assert.That(collections[0].BeatmapMD5Hashes.Count, Is.EqualTo(1));
+
+ Assert.That(collections[1].Name, Is.EqualTo("Second"));
+ Assert.That(collections[1].BeatmapMD5Hashes.Count, Is.EqualTo(12));
+ });
}
finally
{
@@ -123,7 +139,11 @@ namespace osu.Game.Tests.Collections.IO
}
Assert.That(exceptionThrown, Is.False);
- Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(0));
+ osu.Realm.Run(realm =>
+ {
+ var collections = realm.All().ToList();
+ Assert.That(collections.Count, Is.EqualTo(0));
+ });
}
finally
{
@@ -148,12 +168,18 @@ namespace osu.Game.Tests.Collections.IO
await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db"));
- // Move first beatmap from second collection into the first.
- osu.CollectionManager.Collections[0].BeatmapHashes.Add(osu.CollectionManager.Collections[1].BeatmapHashes[0]);
- osu.CollectionManager.Collections[1].BeatmapHashes.RemoveAt(0);
+ // ReSharper disable once MethodHasAsyncOverload
+ osu.Realm.Write(realm =>
+ {
+ var collections = realm.All().ToList();
- // Rename the second collecction.
- osu.CollectionManager.Collections[1].Name.Value = "Another";
+ // Move first beatmap from second collection into the first.
+ collections[0].BeatmapMD5Hashes.Add(collections[1].BeatmapMD5Hashes[0]);
+ collections[1].BeatmapMD5Hashes.RemoveAt(0);
+
+ // Rename the second collecction.
+ collections[1].Name = "Another";
+ });
}
finally
{
@@ -168,13 +194,17 @@ namespace osu.Game.Tests.Collections.IO
{
var osu = LoadOsuIntoHost(host, true);
- Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
+ osu.Realm.Run(realm =>
+ {
+ var collections = realm.All().ToList();
+ Assert.That(collections.Count, Is.EqualTo(2));
- Assert.That(osu.CollectionManager.Collections[0].Name.Value, Is.EqualTo("First"));
- Assert.That(osu.CollectionManager.Collections[0].BeatmapHashes.Count, Is.EqualTo(2));
+ Assert.That(collections[0].Name, Is.EqualTo("First"));
+ Assert.That(collections[0].BeatmapMD5Hashes.Count, Is.EqualTo(2));
- Assert.That(osu.CollectionManager.Collections[1].Name.Value, Is.EqualTo("Another"));
- Assert.That(osu.CollectionManager.Collections[1].BeatmapHashes.Count, Is.EqualTo(11));
+ Assert.That(collections[1].Name, Is.EqualTo("Another"));
+ Assert.That(collections[1].BeatmapMD5Hashes.Count, Is.EqualTo(11));
+ });
}
finally
{
@@ -187,7 +217,7 @@ namespace osu.Game.Tests.Collections.IO
{
// intentionally spin this up on a separate task to avoid disposal deadlocks.
// see https://github.com/EventStore/EventStore/issues/1179
- await Task.Factory.StartNew(() => osu.CollectionManager.Import(stream).WaitSafely(), TaskCreationOptions.LongRunning);
+ await Task.Factory.StartNew(() => new LegacyCollectionImporter(osu.Realm).Import(stream).WaitSafely(), TaskCreationOptions.LongRunning);
}
}
}
diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs
index 9ee88c0670..56964aa8b2 100644
--- a/osu.Game.Tests/Database/BeatmapImporterTests.cs
+++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs
@@ -142,7 +142,6 @@ namespace osu.Game.Tests.Database
{
Task.Run(async () =>
{
- // ReSharper disable once AccessToDisposedClosure
var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz"));
Assert.NotNull(beatmapSet);
@@ -311,6 +310,7 @@ namespace osu.Game.Tests.Database
}
finally
{
+ File.Delete(temp);
Directory.Delete(extractedFolder, true);
}
});
@@ -670,6 +670,65 @@ namespace osu.Game.Tests.Database
});
}
+ [Test]
+ public void TestImportThenReimportWithNewDifficulty()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var store = new RealmRulesetStore(realm, storage);
+
+ string? pathOriginal = TestResources.GetTestBeatmapForImport();
+
+ string pathMissingOneBeatmap = pathOriginal.Replace(".osz", "_missing_difficulty.osz");
+
+ string extractedFolder = $"{pathOriginal}_extracted";
+ Directory.CreateDirectory(extractedFolder);
+
+ try
+ {
+ using (var zip = ZipArchive.Open(pathOriginal))
+ zip.WriteToDirectory(extractedFolder);
+
+ // remove one difficulty before first import
+ new FileInfo(Directory.GetFiles(extractedFolder, "*.osu").First()).Delete();
+
+ using (var zip = ZipArchive.Create())
+ {
+ zip.AddAllFromDirectory(extractedFolder);
+ zip.SaveTo(pathMissingOneBeatmap, new ZipWriterOptions(CompressionType.Deflate));
+ }
+
+ var firstImport = await importer.Import(new ImportTask(pathMissingOneBeatmap));
+ Assert.That(firstImport, Is.Not.Null);
+
+ realm.Run(r => r.Refresh());
+
+ Assert.That(realm.Realm.All().Where(s => !s.DeletePending), Has.Count.EqualTo(1));
+ Assert.That(realm.Realm.All().First(s => !s.DeletePending).Beatmaps, Has.Count.EqualTo(11));
+
+ // Second import matches first but contains one extra .osu file.
+ var secondImport = await importer.Import(new ImportTask(pathOriginal));
+ Assert.That(secondImport, Is.Not.Null);
+
+ realm.Run(r => r.Refresh());
+
+ Assert.That(realm.Realm.All(), Has.Count.EqualTo(23));
+ Assert.That(realm.Realm.All(), Has.Count.EqualTo(2));
+
+ Assert.That(realm.Realm.All().Where(s => !s.DeletePending), Has.Count.EqualTo(1));
+ Assert.That(realm.Realm.All().First(s => !s.DeletePending).Beatmaps, Has.Count.EqualTo(12));
+
+ // check the newly "imported" beatmap is not the original.
+ Assert.That(firstImport?.ID, Is.Not.EqualTo(secondImport?.ID));
+ }
+ finally
+ {
+ Directory.Delete(extractedFolder, true);
+ }
+ });
+ }
+
[Test]
public void TestImportThenReimportAfterMissingFiles()
{
@@ -742,7 +801,7 @@ namespace osu.Game.Tests.Database
await realm.Realm.WriteAsync(() =>
{
foreach (var b in imported.Beatmaps)
- b.OnlineID = -1;
+ b.ResetOnlineInfo();
});
deleteBeatmapSet(imported, realm.Realm);
diff --git a/osu.Game.Tests/Database/BeatmapImporterUpdateTests.cs b/osu.Game.Tests/Database/BeatmapImporterUpdateTests.cs
new file mode 100644
index 0000000000..b94cff2a9a
--- /dev/null
+++ b/osu.Game.Tests/Database/BeatmapImporterUpdateTests.cs
@@ -0,0 +1,600 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Game.Beatmaps;
+using osu.Game.Collections;
+using osu.Game.Database;
+using osu.Game.Models;
+using osu.Game.Overlays.Notifications;
+using osu.Game.Rulesets;
+using osu.Game.Scoring;
+using osu.Game.Tests.Resources;
+using Realms;
+using SharpCompress.Archives;
+using SharpCompress.Archives.Zip;
+using SharpCompress.Common;
+using SharpCompress.Writers.Zip;
+
+namespace osu.Game.Tests.Database
+{
+ ///
+ /// Tests the flow where a beatmap is already loaded and an update is applied.
+ ///
+ [TestFixture]
+ public class BeatmapImporterUpdateTests : RealmTest
+ {
+ private const int count_beatmaps = 12;
+
+ [Test]
+ public void TestNewDifficultyAdded()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchiveWithModifications(out string pathMissingOneBeatmap, directory =>
+ {
+ // remove one difficulty before first import
+ directory.GetFiles("*.osu").First().Delete();
+ });
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathMissingOneBeatmap));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, 1, s => !s.DeletePending);
+ Assert.That(importBeforeUpdate.Value.Beatmaps, Has.Count.EqualTo(count_beatmaps - 1));
+
+ // Second import matches first but contains one extra .osu file.
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathOriginal), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, 1);
+
+ // check the newly "imported" beatmap is not the original.
+ Assert.That(importBeforeUpdate.ID, Is.Not.EqualTo(importAfterUpdate.ID));
+
+ // Previous beatmap set has no beatmaps so will be completely purged on the spot.
+ Assert.That(importBeforeUpdate.Value.IsValid, Is.False);
+ });
+ }
+
+ ///
+ /// Regression test covering https://github.com/ppy/osu/issues/19369 (import potentially duplicating if original has no ).
+ ///
+ [Test]
+ public void TestNewDifficultyAddedNoOnlineID()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchiveWithModifications(out string pathMissingOneBeatmap, directory =>
+ {
+ // remove one difficulty before first import
+ directory.GetFiles("*.osu").First().Delete();
+ });
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathMissingOneBeatmap));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ // This test is the same as TestNewDifficultyAdded except for this block.
+ importBeforeUpdate.PerformWrite(s =>
+ {
+ s.OnlineID = -1;
+ foreach (var beatmap in s.Beatmaps)
+ beatmap.ResetOnlineInfo();
+ });
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, 1, s => !s.DeletePending);
+ Assert.That(importBeforeUpdate.Value.Beatmaps, Has.Count.EqualTo(count_beatmaps - 1));
+
+ // Second import matches first but contains one extra .osu file.
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathOriginal), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, 1);
+
+ // check the newly "imported" beatmap is not the original.
+ Assert.That(importBeforeUpdate.ID, Is.Not.EqualTo(importAfterUpdate.ID));
+
+ // Previous beatmap set has no beatmaps so will be completely purged on the spot.
+ Assert.That(importBeforeUpdate.Value.IsValid, Is.False);
+ });
+ }
+
+ [Test]
+ public void TestExistingDifficultyModified()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchiveWithModifications(out string pathModified, directory =>
+ {
+ // Modify one .osu file with different content.
+ var firstOsuFile = directory.GetFiles("*.osu").First();
+
+ string existingContent = File.ReadAllText(firstOsuFile.FullName);
+
+ File.WriteAllText(firstOsuFile.FullName, existingContent + "\n# I am new content");
+ });
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, 1, s => !s.DeletePending);
+ Assert.That(importBeforeUpdate.Value.Beatmaps, Has.Count.EqualTo(count_beatmaps));
+
+ // Second import matches first but contains one extra .osu file.
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathModified), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ // should only contain the modified beatmap (others purged).
+ Assert.That(importBeforeUpdate.Value.Beatmaps, Has.Count.EqualTo(1));
+ Assert.That(importAfterUpdate.Value.Beatmaps, Has.Count.EqualTo(count_beatmaps));
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, count_beatmaps + 1);
+ checkCount(realm, count_beatmaps + 1);
+
+ checkCount(realm, 1, s => !s.DeletePending);
+ checkCount(realm, 1, s => s.DeletePending);
+ });
+ }
+
+ [Test]
+ public void TestExistingDifficultyRemoved()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchiveWithModifications(out string pathMissingOneBeatmap, directory =>
+ {
+ // remove one difficulty before first import
+ directory.GetFiles("*.osu").First().Delete();
+ });
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ Assert.That(importBeforeUpdate.Value.Beatmaps, Has.Count.EqualTo(count_beatmaps));
+ Assert.That(importBeforeUpdate.Value.Beatmaps.First().OnlineID, Is.GreaterThan(-1));
+
+ // Second import matches first but contains one extra .osu file.
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathMissingOneBeatmap), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, 2);
+
+ // previous set should contain the removed beatmap still.
+ Assert.That(importBeforeUpdate.Value.Beatmaps, Has.Count.EqualTo(1));
+ Assert.That(importBeforeUpdate.Value.Beatmaps.First().OnlineID, Is.EqualTo(-1));
+
+ // Previous beatmap set has no beatmaps so will be completely purged on the spot.
+ Assert.That(importAfterUpdate.Value.Beatmaps, Has.Count.EqualTo(count_beatmaps - 1));
+ });
+ }
+
+ [Test]
+ public void TestUpdatedImportContainsNothing()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchiveWithModifications(out string pathEmpty, directory =>
+ {
+ foreach (var file in directory.GetFiles())
+ file.Delete();
+ });
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathEmpty), importBeforeUpdate.Value);
+ Assert.That(importAfterUpdate, Is.Null);
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, 1);
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, count_beatmaps);
+
+ Assert.That(importBeforeUpdate.Value.IsValid, Is.True);
+ });
+ }
+
+ [Test]
+ public void TestNoChanges()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchive(out string pathOriginalSecond);
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathOriginalSecond), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, 1);
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, count_beatmaps);
+
+ Assert.That(importBeforeUpdate.Value.Beatmaps.First().OnlineID, Is.GreaterThan(-1));
+ Assert.That(importBeforeUpdate.ID, Is.EqualTo(importAfterUpdate.ID));
+ });
+ }
+
+ [Test]
+ public void TestScoreTransferredOnUnchanged()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+ string removedFilename = null!;
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchiveWithModifications(out string pathMissingOneBeatmap, directory =>
+ {
+ // arbitrary beatmap removal
+ var fileToRemove = directory.GetFiles("*.osu").First();
+
+ removedFilename = fileToRemove.Name;
+ fileToRemove.Delete();
+ });
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ string scoreTargetBeatmapHash = string.Empty;
+
+ importBeforeUpdate.PerformWrite(s =>
+ {
+ // make sure not to add scores to the same beatmap that is removed in the update.
+ var beatmapInfo = s.Beatmaps.First(b => b.File?.Filename != removedFilename);
+
+ scoreTargetBeatmapHash = beatmapInfo.Hash;
+ s.Realm.Add(new ScoreInfo(beatmapInfo, s.Realm.All().First(), new RealmUser()));
+ });
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, 1);
+
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathMissingOneBeatmap), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, count_beatmaps);
+ checkCount(realm, 2);
+
+ // score is transferred across to the new set
+ checkCount(realm, 1);
+ Assert.That(importAfterUpdate.Value.Beatmaps.First(b => b.Hash == scoreTargetBeatmapHash).Scores, Has.Count.EqualTo(1));
+ });
+ }
+
+ [Test]
+ public void TestScoreLostOnModification()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ string? scoreTargetFilename = string.Empty;
+
+ importBeforeUpdate.PerformWrite(s =>
+ {
+ var beatmapInfo = s.Beatmaps.Last();
+ scoreTargetFilename = beatmapInfo.File?.Filename;
+ s.Realm.Add(new ScoreInfo(beatmapInfo, s.Realm.All().First(), new RealmUser()));
+ });
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, 1);
+
+ using var _ = getBeatmapArchiveWithModifications(out string pathModified, directory =>
+ {
+ // Modify one .osu file with different content.
+ var firstOsuFile = directory.GetFiles(scoreTargetFilename).First();
+
+ string existingContent = File.ReadAllText(firstOsuFile.FullName);
+
+ File.WriteAllText(firstOsuFile.FullName, existingContent + "\n# I am new content");
+ });
+
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathModified), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ realm.Run(r => r.Refresh());
+
+ checkCount(realm, count_beatmaps + 1);
+ checkCount(realm, count_beatmaps + 1);
+ checkCount(realm, 2);
+
+ // score is not transferred due to modifications.
+ checkCount(realm, 1);
+ Assert.That(importBeforeUpdate.Value.Beatmaps.AsEnumerable().First(b => b.File?.Filename == scoreTargetFilename).Scores, Has.Count.EqualTo(1));
+ Assert.That(importAfterUpdate.Value.Beatmaps.AsEnumerable().First(b => b.File?.Filename == scoreTargetFilename).Scores, Has.Count.EqualTo(0));
+ });
+ }
+
+ [Test]
+ public void TestMetadataTransferred()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchiveWithModifications(out string pathMissingOneBeatmap, directory =>
+ {
+ // arbitrary beatmap removal
+ directory.GetFiles("*.osu").First().Delete();
+ });
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathMissingOneBeatmap), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ Assert.That(importBeforeUpdate.ID, Is.Not.EqualTo(importAfterUpdate.ID));
+ Assert.That(importBeforeUpdate.Value.DateAdded, Is.EqualTo(importAfterUpdate.Value.DateAdded));
+ });
+ }
+
+ ///
+ /// If all difficulties in the original beatmap set are in a collection, presume the user also wants new difficulties added.
+ ///
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestCollectionTransferNewBeatmap(bool allOriginalBeatmapsInCollection)
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchiveWithModifications(out string pathMissingOneBeatmap, directory =>
+ {
+ // remove one difficulty before first import
+ directory.GetFiles("*.osu").First().Delete();
+ });
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathMissingOneBeatmap));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ int beatmapsToAddToCollection = 0;
+
+ importBeforeUpdate.PerformWrite(s =>
+ {
+ var beatmapCollection = s.Realm.Add(new BeatmapCollection("test collection"));
+ beatmapsToAddToCollection = s.Beatmaps.Count - (allOriginalBeatmapsInCollection ? 0 : 1);
+
+ for (int i = 0; i < beatmapsToAddToCollection; i++)
+ beatmapCollection.BeatmapMD5Hashes.Add(s.Beatmaps[i].MD5Hash);
+ });
+
+ // Second import matches first but contains one extra .osu file.
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathOriginal), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ importAfterUpdate.PerformRead(updated =>
+ {
+ updated.Realm.Refresh();
+
+ string[] hashes = updated.Realm.All().Single().BeatmapMD5Hashes.ToArray();
+
+ if (allOriginalBeatmapsInCollection)
+ {
+ Assert.That(updated.Beatmaps.Count, Is.EqualTo(beatmapsToAddToCollection + 1));
+ Assert.That(hashes, Has.Length.EqualTo(updated.Beatmaps.Count));
+ }
+ else
+ {
+ // Collection contains one less than the original beatmap, and two less after update (new difficulty included).
+ Assert.That(updated.Beatmaps.Count, Is.EqualTo(beatmapsToAddToCollection + 2));
+ Assert.That(hashes, Has.Length.EqualTo(beatmapsToAddToCollection));
+ }
+ });
+ });
+ }
+
+ ///
+ /// If a difficulty in the original beatmap set is modified, the updated version should remain in any collections it was in.
+ ///
+ [Test]
+ public void TestCollectionTransferModifiedBeatmap()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ var importer = new BeatmapImporter(storage, realm);
+ using var rulesets = new RealmRulesetStore(realm, storage);
+
+ using var __ = getBeatmapArchive(out string pathOriginal);
+ using var _ = getBeatmapArchiveWithModifications(out string pathModified, directory =>
+ {
+ // Modify one .osu file with different content.
+ var firstOsuFile = directory.GetFiles("*[Hard]*.osu").First();
+
+ string existingContent = File.ReadAllText(firstOsuFile.FullName);
+
+ File.WriteAllText(firstOsuFile.FullName, existingContent + "\n# I am new content");
+ });
+
+ var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
+
+ Assert.That(importBeforeUpdate, Is.Not.Null);
+ Debug.Assert(importBeforeUpdate != null);
+
+ string originalHash = string.Empty;
+
+ importBeforeUpdate.PerformWrite(s =>
+ {
+ var beatmapCollection = s.Realm.Add(new BeatmapCollection("test collection"));
+ originalHash = s.Beatmaps.Single(b => b.DifficultyName == "Hard").MD5Hash;
+
+ beatmapCollection.BeatmapMD5Hashes.Add(originalHash);
+ });
+
+ // Second import matches first but contains a modified .osu file.
+ var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathModified), importBeforeUpdate.Value);
+
+ Assert.That(importAfterUpdate, Is.Not.Null);
+ Debug.Assert(importAfterUpdate != null);
+
+ importAfterUpdate.PerformRead(updated =>
+ {
+ updated.Realm.Refresh();
+
+ string[] hashes = updated.Realm.All().Single().BeatmapMD5Hashes.ToArray();
+ string updatedHash = updated.Beatmaps.Single(b => b.DifficultyName == "Hard").MD5Hash;
+
+ Assert.That(hashes, Has.Length.EqualTo(1));
+ Assert.That(hashes.First(), Is.EqualTo(updatedHash));
+
+ Assert.That(updatedHash, Is.Not.EqualTo(originalHash));
+ });
+ });
+ }
+
+ private static void checkCount(RealmAccess realm, int expected, Expression>? condition = null) where T : RealmObject
+ {
+ var query = realm.Realm.All();
+
+ if (condition != null)
+ query = query.Where(condition);
+
+ Assert.That(query, Has.Count.EqualTo(expected));
+ }
+
+ private static IDisposable getBeatmapArchiveWithModifications(out string path, Action applyModifications)
+ {
+ var cleanup = getBeatmapArchive(out path);
+
+ string extractedFolder = $"{path}_extracted";
+ Directory.CreateDirectory(extractedFolder);
+
+ using (var zip = ZipArchive.Open(path))
+ zip.WriteToDirectory(extractedFolder);
+
+ applyModifications(new DirectoryInfo(extractedFolder));
+
+ File.Delete(path);
+
+ using (var zip = ZipArchive.Create())
+ {
+ zip.AddAllFromDirectory(extractedFolder);
+ zip.SaveTo(path, new ZipWriterOptions(CompressionType.Deflate));
+ }
+
+ Directory.Delete(extractedFolder, true);
+
+ return cleanup;
+ }
+
+ private static IDisposable getBeatmapArchive(out string path, bool quick = true)
+ {
+ string beatmapPath = TestResources.GetTestBeatmapForImport(quick);
+
+ path = beatmapPath;
+
+ return new InvokeOnDisposal(() => File.Delete(beatmapPath));
+ }
+ }
+}
diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs
index 3615cebe6a..d853e75db0 100644
--- a/osu.Game.Tests/Database/RealmLiveTests.cs
+++ b/osu.Game.Tests/Database/RealmLiveTests.cs
@@ -32,31 +32,29 @@ namespace osu.Game.Tests.Database
[Test]
public void TestAccessAfterStorageMigrate()
{
- RunTestWithRealm((realm, storage) =>
+ using (var migratedStorage = new TemporaryNativeStorage("realm-test-migration-target"))
{
- var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
-
- Live? liveBeatmap = null;
-
- realm.Run(r =>
+ RunTestWithRealm((realm, storage) =>
{
- r.Write(_ => r.Add(beatmap));
+ var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
- liveBeatmap = beatmap.ToLive(realm);
- });
+ Live? liveBeatmap = null;
+
+ realm.Run(r =>
+ {
+ r.Write(_ => r.Add(beatmap));
+
+ liveBeatmap = beatmap.ToLive(realm);
+ });
- using (var migratedStorage = new TemporaryNativeStorage("realm-test-migration-target"))
- {
migratedStorage.DeleteDirectory(string.Empty);
using (realm.BlockAllOperations("testing"))
- {
storage.Migrate(migratedStorage);
- }
Assert.IsFalse(liveBeatmap?.PerformRead(l => l.Hidden));
- }
- });
+ });
+ }
}
[Test]
@@ -341,14 +339,12 @@ namespace osu.Game.Tests.Database
liveBeatmap.PerformRead(resolved =>
{
// retrieval causes an implicit refresh. even changes that aren't related to the retrieval are fired at this point.
- // ReSharper disable once AccessToDisposedClosure
Assert.AreEqual(2, outerRealm.All().Count());
Assert.AreEqual(1, changesTriggered);
// can access properties without a crash.
Assert.IsFalse(resolved.Hidden);
- // ReSharper disable once AccessToDisposedClosure
outerRealm.Write(r =>
{
// can use with the main context.
diff --git a/osu.Game.Tests/Database/RealmTest.cs b/osu.Game.Tests/Database/RealmTest.cs
index d6b3c1ff44..1b1878942b 100644
--- a/osu.Game.Tests/Database/RealmTest.cs
+++ b/osu.Game.Tests/Database/RealmTest.cs
@@ -4,11 +4,11 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
+using JetBrains.Annotations;
using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Framework.Logging;
using osu.Framework.Platform;
-using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.IO;
@@ -20,22 +20,15 @@ namespace osu.Game.Tests.Database
[TestFixture]
public abstract class RealmTest
{
- private static readonly TemporaryNativeStorage storage;
-
- static RealmTest()
- {
- storage = new TemporaryNativeStorage("realm-test");
- storage.DeleteDirectory(string.Empty);
- }
-
- protected void RunTestWithRealm(Action testAction, [CallerMemberName] string caller = "")
+ protected void RunTestWithRealm([InstantHandle] Action testAction, [CallerMemberName] string caller = "")
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(callingMethodName: caller))
{
host.Run(new RealmTestGame(() =>
{
- // ReSharper disable once AccessToDisposedClosure
- var testStorage = new OsuStorage(host, storage.GetStorageForDirectory(caller));
+ var defaultStorage = host.Storage;
+
+ var testStorage = new OsuStorage(host, defaultStorage);
using (var realm = new RealmAccess(testStorage, OsuGameBase.CLIENT_DATABASE_FILENAME))
{
@@ -58,7 +51,7 @@ namespace osu.Game.Tests.Database
{
host.Run(new RealmTestGame(async () =>
{
- var testStorage = storage.GetStorageForDirectory(caller);
+ var testStorage = host.Storage;
using (var realm = new RealmAccess(testStorage, OsuGameBase.CLIENT_DATABASE_FILENAME))
{
@@ -116,7 +109,7 @@ namespace osu.Game.Tests.Database
private class RealmTestGame : Framework.Game
{
- public RealmTestGame(Func work)
+ public RealmTestGame([InstantHandle] Func work)
{
// ReSharper disable once AsyncVoidLambda
Scheduler.Add(async () =>
@@ -126,7 +119,7 @@ namespace osu.Game.Tests.Database
});
}
- public RealmTestGame(Action work)
+ public RealmTestGame([InstantHandle] Action work)
{
Scheduler.Add(() =>
{
diff --git a/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs b/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs
index 0395ae9d99..5f403f9487 100644
--- a/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs
@@ -41,8 +41,6 @@ namespace osu.Game.Tests.Gameplay
AddStep("create container", () =>
{
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
- working.LoadTrack();
-
Child = gameplayClockContainer = new MasterGameplayClockContainer(working, 0);
});
@@ -58,8 +56,6 @@ namespace osu.Game.Tests.Gameplay
AddStep("create container", () =>
{
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
- working.LoadTrack();
-
Child = gameplayClockContainer = new MasterGameplayClockContainer(working, 0);
});
@@ -102,8 +98,6 @@ namespace osu.Game.Tests.Gameplay
AddStep("create container", () =>
{
working = new ClockBackedTestWorkingBeatmap(new OsuRuleset().RulesetInfo, new FramedClock(new ManualClock()), Audio);
- working.LoadTrack();
-
Child = gameplayClockContainer = new MasterGameplayClockContainer(working, 0);
gameplayClockContainer.Reset(startClock: !whileStopped);
diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
index a9c6bacc65..a432cc9648 100644
--- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
@@ -69,7 +69,6 @@ namespace osu.Game.Tests.Gameplay
AddStep("create container", () =>
{
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
- working.LoadTrack();
Add(gameplayContainer = new MasterGameplayClockContainer(working, 0)
{
@@ -96,7 +95,6 @@ namespace osu.Game.Tests.Gameplay
AddStep("create container", () =>
{
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
- working.LoadTrack();
const double start_time = 1000;
diff --git a/osu.Game.Tests/ImportTest.cs b/osu.Game.Tests/ImportTest.cs
index 32b6dc649c..23ca31ee42 100644
--- a/osu.Game.Tests/ImportTest.cs
+++ b/osu.Game.Tests/ImportTest.cs
@@ -10,7 +10,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Platform;
-using osu.Game.Collections;
+using osu.Game.Database;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests
@@ -47,7 +47,7 @@ namespace osu.Game.Tests
public class TestOsuGameBase : OsuGameBase
{
- public CollectionManager CollectionManager { get; private set; }
+ public RealmAccess Realm => Dependencies.Get();
private readonly bool withBeatmap;
@@ -62,8 +62,6 @@ namespace osu.Game.Tests
// Beatmap must be imported before the collection manager is loaded.
if (withBeatmap)
BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).WaitSafely();
-
- AddInternal(CollectionManager = new CollectionManager(Storage));
}
}
}
diff --git a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
index 185f85513b..67dbcf0ccf 100644
--- a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
+++ b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
@@ -12,7 +12,6 @@ using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
-using osu.Game.Online.Solo;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
@@ -110,30 +109,30 @@ namespace osu.Game.Tests.Online
}
[Test]
- public void TestDeserialiseSubmittableScoreWithEmptyMods()
+ public void TestDeserialiseSoloScoreWithEmptyMods()
{
- var score = new SubmittableScore(new ScoreInfo
+ var score = SoloScoreInfo.ForSubmission(new ScoreInfo
{
User = new APIUser(),
Ruleset = new OsuRuleset().RulesetInfo,
});
- var deserialised = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(score));
+ var deserialised = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(score));
Assert.That(deserialised?.Mods.Length, Is.Zero);
}
[Test]
- public void TestDeserialiseSubmittableScoreWithCustomModSetting()
+ public void TestDeserialiseSoloScoreWithCustomModSetting()
{
- var score = new SubmittableScore(new ScoreInfo
+ var score = SoloScoreInfo.ForSubmission(new ScoreInfo
{
Mods = new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 2 } } },
User = new APIUser(),
Ruleset = new OsuRuleset().RulesetInfo,
});
- var deserialised = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(score));
+ var deserialised = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(score));
Assert.That((deserialised?.Mods[0])?.Settings["speed_change"], Is.EqualTo(2));
}
diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
index 536322805b..3f20f843a7 100644
--- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
+++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
@@ -208,7 +208,7 @@ namespace osu.Game.Tests.Online
public TestBeatmapManager(Storage storage, RealmAccess realm, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore resources,
GameHost host = null, WorkingBeatmap defaultBeatmap = null)
- : base(storage, realm, rulesets, api, audioManager, resources, host, defaultBeatmap)
+ : base(storage, realm, api, audioManager, resources, host, defaultBeatmap)
{
}
diff --git a/osu.Game.Tests/Online/TestSubmittableScoreJsonSerialization.cs b/osu.Game.Tests/Online/TestSoloScoreInfoJsonSerialization.cs
similarity index 79%
rename from osu.Game.Tests/Online/TestSubmittableScoreJsonSerialization.cs
rename to osu.Game.Tests/Online/TestSoloScoreInfoJsonSerialization.cs
index f0f6727393..8ff0b67b5b 100644
--- a/osu.Game.Tests/Online/TestSubmittableScoreJsonSerialization.cs
+++ b/osu.Game.Tests/Online/TestSoloScoreInfoJsonSerialization.cs
@@ -6,7 +6,7 @@
using Newtonsoft.Json;
using NUnit.Framework;
using osu.Game.IO.Serialization;
-using osu.Game.Online.Solo;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Online
@@ -15,12 +15,12 @@ namespace osu.Game.Tests.Online
/// Basic testing to ensure our attribute-based naming is correctly working.
///
[TestFixture]
- public class TestSubmittableScoreJsonSerialization
+ public class TestSoloScoreInfoJsonSerialization
{
[Test]
public void TestScoreSerialisationViaExtensionMethod()
{
- var score = new SubmittableScore(TestResources.CreateTestScoreInfo());
+ var score = SoloScoreInfo.ForSubmission(TestResources.CreateTestScoreInfo());
string serialised = score.Serialize();
@@ -31,7 +31,7 @@ namespace osu.Game.Tests.Online
[Test]
public void TestScoreSerialisationWithoutSettings()
{
- var score = new SubmittableScore(TestResources.CreateTestScoreInfo());
+ var score = SoloScoreInfo.ForSubmission(TestResources.CreateTestScoreInfo());
string serialised = JsonConvert.SerializeObject(score);
diff --git a/osu.Game.Tests/Resources/Archives/modified-classic-20220723.osk b/osu.Game.Tests/Resources/Archives/modified-classic-20220723.osk
new file mode 100644
index 0000000000..8e7a1b42df
Binary files /dev/null and b/osu.Game.Tests/Resources/Archives/modified-classic-20220723.osk differ
diff --git a/osu.Game.Tests/Resources/Archives/modified-classic-20220801.osk b/osu.Game.Tests/Resources/Archives/modified-classic-20220801.osk
new file mode 100644
index 0000000000..9236e1d77f
Binary files /dev/null and b/osu.Game.Tests/Resources/Archives/modified-classic-20220801.osk differ
diff --git a/osu.Game.Tests/Resources/Archives/modified-default-20220723.osk b/osu.Game.Tests/Resources/Archives/modified-default-20220723.osk
new file mode 100644
index 0000000000..7547162165
Binary files /dev/null and b/osu.Game.Tests/Resources/Archives/modified-default-20220723.osk differ
diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs
new file mode 100644
index 0000000000..53639deac3
--- /dev/null
+++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs
@@ -0,0 +1,128 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Audio.Sample;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics.OpenGL.Textures;
+using osu.Framework.Graphics.Textures;
+using osu.Framework.IO.Stores;
+using osu.Game.Audio;
+using osu.Game.IO;
+using osu.Game.IO.Archives;
+using osu.Game.Screens.Play.HUD;
+using osu.Game.Screens.Play.HUD.HitErrorMeters;
+using osu.Game.Skinning;
+using osu.Game.Tests.Resources;
+
+namespace osu.Game.Tests.Skins
+{
+ ///
+ /// Test that the main components (which are serialised based on namespace/class name)
+ /// remain compatible with any changes.
+ ///
+ ///
+ /// If this test breaks, check any naming or class structure changes.
+ /// Migration rules may need to be added to .
+ ///
+ [TestFixture]
+ public class SkinDeserialisationTest
+ {
+ private static readonly string[] available_skins =
+ {
+ // Covers song progress before namespace changes, and most other components.
+ "Archives/modified-default-20220723.osk",
+ "Archives/modified-classic-20220723.osk",
+ // Covers legacy song progress, UR counter, colour hit error metre.
+ "Archives/modified-classic-20220801.osk"
+ };
+
+ ///
+ /// If this test fails, new test resources should be added to include new components.
+ ///
+ [Test]
+ public void TestSkinnableComponentsCoveredByDeserialisationTests()
+ {
+ HashSet instantiatedTypes = new HashSet();
+
+ foreach (string oskFile in available_skins)
+ {
+ using (var stream = TestResources.OpenResource(oskFile))
+ using (var storage = new ZipArchiveReader(stream))
+ {
+ var skin = new TestSkin(new SkinInfo(), null, storage);
+
+ foreach (var target in skin.DrawableComponentInfo)
+ {
+ foreach (var info in target.Value)
+ instantiatedTypes.Add(info.Type);
+ }
+ }
+ }
+
+ var editableTypes = SkinnableInfo.GetAllAvailableDrawables().Where(t => (Activator.CreateInstance(t) as ISkinnableDrawable)?.IsEditable == true);
+
+ Assert.That(instantiatedTypes, Is.EquivalentTo(editableTypes));
+ }
+
+ [Test]
+ public void TestDeserialiseModifiedDefault()
+ {
+ using (var stream = TestResources.OpenResource("Archives/modified-default-20220723.osk"))
+ using (var storage = new ZipArchiveReader(stream))
+ {
+ var skin = new TestSkin(new SkinInfo(), null, storage);
+
+ Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2));
+ Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents], Has.Length.EqualTo(9));
+ }
+ }
+
+ [Test]
+ public void TestDeserialiseModifiedClassic()
+ {
+ using (var stream = TestResources.OpenResource("Archives/modified-classic-20220723.osk"))
+ using (var storage = new ZipArchiveReader(stream))
+ {
+ var skin = new TestSkin(new SkinInfo(), null, storage);
+
+ Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2));
+ Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents], Has.Length.EqualTo(6));
+ Assert.That(skin.DrawableComponentInfo[SkinnableTarget.SongSelect], Has.Length.EqualTo(1));
+
+ var skinnableInfo = skin.DrawableComponentInfo[SkinnableTarget.SongSelect].First();
+
+ Assert.That(skinnableInfo.Type, Is.EqualTo(typeof(SkinnableSprite)));
+ Assert.That(skinnableInfo.Settings.First().Key, Is.EqualTo("sprite_name"));
+ Assert.That(skinnableInfo.Settings.First().Value, Is.EqualTo("ppy_logo-2.png"));
+ }
+
+ using (var stream = TestResources.OpenResource("Archives/modified-classic-20220801.osk"))
+ using (var storage = new ZipArchiveReader(stream))
+ {
+ var skin = new TestSkin(new SkinInfo(), null, storage);
+ Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents], Has.Length.EqualTo(8));
+ Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter)));
+ Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter)));
+ Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress)));
+ }
+ }
+
+ private class TestSkin : Skin
+ {
+ public TestSkin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStore? storage = null, string configurationFilename = "skin.ini")
+ : base(skin, resources, storage, configurationFilename)
+ {
+ }
+
+ public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
+
+ public override IBindable GetConfig(TLookup lookup) => throw new NotImplementedException();
+
+ public override ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
+ }
+ }
+}
diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs
index f4cea2c8cc..e82a5b57d9 100644
--- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs
+++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs
@@ -32,7 +32,6 @@ namespace osu.Game.Tests.Skins
imported?.PerformRead(s =>
{
beatmap = beatmaps.GetWorkingBeatmap(s.Beatmaps[0]);
- beatmap.LoadTrack();
});
}
@@ -40,6 +39,10 @@ namespace osu.Game.Tests.Skins
public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => beatmap.Skin.GetSample(new SampleInfo("sample")) != null);
[Test]
- public void TestRetrieveOggTrack() => AddAssert("track is non-null", () => !(beatmap.Track is TrackVirtual));
+ public void TestRetrieveOggTrack() => AddAssert("track is non-null", () =>
+ {
+ using (var track = beatmap.LoadTrack())
+ return track is not TrackVirtual;
+ });
}
}
diff --git a/osu.Game.Tests/Skins/TestSceneSkinResources.cs b/osu.Game.Tests/Skins/TestSceneSkinResources.cs
index 42c1eeb6d1..d1561c84bf 100644
--- a/osu.Game.Tests/Skins/TestSceneSkinResources.cs
+++ b/osu.Game.Tests/Skins/TestSceneSkinResources.cs
@@ -1,14 +1,24 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Moq;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Audio.Sample;
+using osu.Framework.Bindables;
using osu.Framework.Extensions;
+using osu.Framework.Extensions.ObjectExtensions;
+using osu.Framework.Graphics.OpenGL.Textures;
+using osu.Framework.Graphics.Textures;
+using osu.Framework.IO.Stores;
using osu.Framework.Testing;
using osu.Game.Audio;
using osu.Game.Database;
+using osu.Game.IO;
using osu.Game.Skinning;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual;
@@ -19,9 +29,9 @@ namespace osu.Game.Tests.Skins
public class TestSceneSkinResources : OsuTestScene
{
[Resolved]
- private SkinManager skins { get; set; }
+ private SkinManager skins { get; set; } = null!;
- private ISkin skin;
+ private ISkin skin = null!;
[BackgroundDependencyLoader]
private void load()
@@ -32,5 +42,55 @@ namespace osu.Game.Tests.Skins
[Test]
public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => skin.GetSample(new SampleInfo("sample")) != null);
+
+ [Test]
+ public void TestSampleRetrievalOrder()
+ {
+ Mock mockResourceProvider = null!;
+ Mock> mockResourceStore = null!;
+ List lookedUpFileNames = null!;
+
+ AddStep("setup mock providers provider", () =>
+ {
+ lookedUpFileNames = new List();
+ mockResourceProvider = new Mock();
+ mockResourceProvider.Setup(m => m.AudioManager).Returns(Audio);
+ mockResourceStore = new Mock>();
+ mockResourceStore.Setup(r => r.Get(It.IsAny()))
+ .Callback(n => lookedUpFileNames.Add(n))
+ .Returns(null);
+ });
+
+ AddStep("query sample", () =>
+ {
+ TestSkin testSkin = new TestSkin(new SkinInfo(), mockResourceProvider.Object, new ResourceStore(mockResourceStore.Object));
+ testSkin.GetSample(new SampleInfo());
+ });
+
+ AddAssert("sample lookups were in correct order", () =>
+ {
+ string[] lookups = lookedUpFileNames.Where(f => f.StartsWith(TestSkin.SAMPLE_NAME, StringComparison.Ordinal)).ToArray();
+ return Path.GetExtension(lookups[0]) == string.Empty
+ && Path.GetExtension(lookups[1]) == ".wav"
+ && Path.GetExtension(lookups[2]) == ".mp3"
+ && Path.GetExtension(lookups[3]) == ".ogg";
+ });
+ }
+
+ private class TestSkin : Skin
+ {
+ public const string SAMPLE_NAME = "test-sample";
+
+ public TestSkin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStore? storage = null, string configurationFilename = "skin.ini")
+ : base(skin, resources, storage, configurationFilename)
+ {
+ }
+
+ public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
+
+ public override IBindable GetConfig(TLookup lookup) => throw new NotImplementedException();
+
+ public override ISample GetSample(ISampleInfo sampleInfo) => Samples.AsNonNull().Get(SAMPLE_NAME);
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
index aaccea09d4..5aadd6f56a 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
@@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Background
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(new OsuConfigManager(LocalStorage));
Dependencies.Cache(Realm);
diff --git a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs
index 3f30fa367c..4f7d3a4403 100644
--- a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs
+++ b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@@ -27,38 +25,32 @@ namespace osu.Game.Tests.Visual.Collections
{
protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both };
- private DialogOverlay dialogOverlay;
- private CollectionManager manager;
-
- private RulesetStore rulesets;
- private BeatmapManager beatmapManager;
-
- private ManageCollectionsDialog dialog;
+ private DialogOverlay dialogOverlay = null!;
+ private BeatmapManager beatmapManager = null!;
+ private ManageCollectionsDialog dialog = null!;
[BackgroundDependencyLoader]
private void load(GameHost host)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesets, null, Audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
base.Content.AddRange(new Drawable[]
{
- manager = new CollectionManager(LocalStorage),
Content,
dialogOverlay = new DialogOverlay(),
});
- Dependencies.Cache(manager);
Dependencies.CacheAs(dialogOverlay);
}
[SetUp]
public void SetUp() => Schedule(() =>
{
- manager.Collections.Clear();
+ Realm.Write(r => r.RemoveAll());
Child = dialog = new ManageCollectionsDialog();
});
@@ -78,17 +70,17 @@ namespace osu.Game.Tests.Visual.Collections
[Test]
public void TestLastItemIsPlaceholder()
{
- AddAssert("last item is placeholder", () => !manager.Collections.Contains(dialog.ChildrenOfType().Last().Model));
+ AddAssert("last item is placeholder", () => !dialog.ChildrenOfType().Last().Model.IsManaged);
}
[Test]
public void TestAddCollectionExternal()
{
- AddStep("add collection", () => manager.Collections.Add(new BeatmapCollection { Name = { Value = "First collection" } }));
+ AddStep("add collection", () => Realm.Write(r => r.Add(new BeatmapCollection(name: "First collection"))));
assertCollectionCount(1);
assertCollectionName(0, "First collection");
- AddStep("add another collection", () => manager.Collections.Add(new BeatmapCollection { Name = { Value = "Second collection" } }));
+ AddStep("add another collection", () => Realm.Write(r => r.Add(new BeatmapCollection(name: "Second collection"))));
assertCollectionCount(2);
assertCollectionName(1, "Second collection");
}
@@ -108,7 +100,7 @@ namespace osu.Game.Tests.Visual.Collections
[Test]
public void TestAddCollectionViaPlaceholder()
{
- DrawableCollectionListItem placeholderItem = null;
+ DrawableCollectionListItem placeholderItem = null!;
AddStep("focus placeholder", () =>
{
@@ -116,24 +108,37 @@ namespace osu.Game.Tests.Visual.Collections
InputManager.Click(MouseButton.Left);
});
- // Done directly via the collection since InputManager methods cannot add text to textbox...
- AddStep("change collection name", () => placeholderItem.Model.Name.Value = "a");
- assertCollectionCount(1);
- AddAssert("collection now exists", () => manager.Collections.Contains(placeholderItem.Model));
+ assertCollectionCount(0);
- AddAssert("last item is placeholder", () => !manager.Collections.Contains(dialog.ChildrenOfType().Last().Model));
+ AddStep("change collection name", () =>
+ {
+ placeholderItem.ChildrenOfType().First().Text = "test text";
+ InputManager.Key(Key.Enter);
+ });
+
+ assertCollectionCount(1);
+
+ AddAssert("last item is placeholder", () => !dialog.ChildrenOfType().Last().Model.IsManaged);
}
[Test]
public void TestRemoveCollectionExternal()
{
- AddStep("add two collections", () => manager.Collections.AddRange(new[]
- {
- new BeatmapCollection { Name = { Value = "1" } },
- new BeatmapCollection { Name = { Value = "2" } },
- }));
+ BeatmapCollection first = null!;
- AddStep("remove first collection", () => manager.Collections.RemoveAt(0));
+ AddStep("add two collections", () =>
+ {
+ Realm.Write(r =>
+ {
+ r.Add(new[]
+ {
+ first = new BeatmapCollection(name: "1"),
+ new BeatmapCollection(name: "2"),
+ });
+ });
+ });
+
+ AddStep("remove first collection", () => Realm.Write(r => r.Remove(first)));
assertCollectionCount(1);
assertCollectionName(0, "2");
}
@@ -143,7 +148,7 @@ namespace osu.Game.Tests.Visual.Collections
{
AddStep("add dropdown", () =>
{
- Add(new CollectionFilterDropdown
+ Add(new CollectionDropdown
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
@@ -151,21 +156,27 @@ namespace osu.Game.Tests.Visual.Collections
Width = 0.4f,
});
});
- AddStep("add two collections with same name", () => manager.Collections.AddRange(new[]
+ AddStep("add two collections with same name", () => Realm.Write(r => r.Add(new[]
{
- new BeatmapCollection { Name = { Value = "1" } },
- new BeatmapCollection { Name = { Value = "1" }, BeatmapHashes = { beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps[0].MD5Hash } },
- }));
+ new BeatmapCollection(name: "1"),
+ new BeatmapCollection(name: "1")
+ {
+ BeatmapMD5Hashes = { beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps[0].MD5Hash }
+ },
+ })));
}
[Test]
public void TestRemoveCollectionViaButton()
{
- AddStep("add two collections", () => manager.Collections.AddRange(new[]
+ AddStep("add two collections", () => Realm.Write(r => r.Add(new[]
{
- new BeatmapCollection { Name = { Value = "1" } },
- new BeatmapCollection { Name = { Value = "2" }, BeatmapHashes = { beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps[0].MD5Hash } },
- }));
+ new BeatmapCollection(name: "1"),
+ new BeatmapCollection(name: "2")
+ {
+ BeatmapMD5Hashes = { beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps[0].MD5Hash }
+ },
+ })));
assertCollectionCount(2);
@@ -198,10 +209,13 @@ namespace osu.Game.Tests.Visual.Collections
[Test]
public void TestCollectionNotRemovedWhenDialogCancelled()
{
- AddStep("add two collections", () => manager.Collections.AddRange(new[]
+ AddStep("add collection", () => Realm.Write(r => r.Add(new[]
{
- new BeatmapCollection { Name = { Value = "1" }, BeatmapHashes = { beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps[0].MD5Hash } },
- }));
+ new BeatmapCollection(name: "1")
+ {
+ BeatmapMD5Hashes = { beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps[0].MD5Hash }
+ },
+ })));
assertCollectionCount(1);
@@ -224,34 +238,67 @@ namespace osu.Game.Tests.Visual.Collections
[Test]
public void TestCollectionRenamedExternal()
{
- AddStep("add two collections", () => manager.Collections.AddRange(new[]
+ BeatmapCollection first = null!;
+
+ AddStep("add two collections", () =>
{
- new BeatmapCollection { Name = { Value = "1" } },
- new BeatmapCollection { Name = { Value = "2" } },
- }));
+ Realm.Write(r =>
+ {
+ r.Add(new[]
+ {
+ first = new BeatmapCollection(name: "1"),
+ new BeatmapCollection(name: "2"),
+ });
+ });
+ });
- AddStep("change first collection name", () => manager.Collections[0].Name.Value = "First");
+ assertCollectionName(0, "1");
+ assertCollectionName(1, "2");
- assertCollectionName(0, "First");
+ AddStep("change first collection name", () => Realm.Write(_ => first.Name = "First"));
+
+ // Item will have moved due to alphabetical sorting.
+ assertCollectionName(0, "2");
+ assertCollectionName(1, "First");
}
[Test]
public void TestCollectionRenamedOnTextChange()
{
- AddStep("add two collections", () => manager.Collections.AddRange(new[]
+ BeatmapCollection first = null!;
+ DrawableCollectionListItem firstItem = null!;
+
+ AddStep("add two collections", () =>
{
- new BeatmapCollection { Name = { Value = "1" } },
- new BeatmapCollection { Name = { Value = "2" } },
- }));
+ Realm.Write(r =>
+ {
+ r.Add(new[]
+ {
+ first = new BeatmapCollection(name: "1"),
+ new BeatmapCollection(name: "2"),
+ });
+ });
+ });
assertCollectionCount(2);
- AddStep("change first collection name", () => dialog.ChildrenOfType().First().Text = "First");
- AddAssert("collection has new name", () => manager.Collections[0].Name.Value == "First");
+ AddStep("focus first collection", () =>
+ {
+ InputManager.MoveMouseTo(firstItem = dialog.ChildrenOfType().First());
+ InputManager.Click(MouseButton.Left);
+ });
+
+ AddStep("change first collection name", () =>
+ {
+ firstItem.ChildrenOfType().First().Text = "First";
+ InputManager.Key(Key.Enter);
+ });
+
+ AddUntilStep("collection has new name", () => first.Name == "First");
}
private void assertCollectionCount(int count)
- => AddUntilStep($"{count} collections shown", () => dialog.ChildrenOfType().Count(i => i.IsCreated.Value) == count);
+ => AddUntilStep($"{count} collections shown", () => dialog.ChildrenOfType().Count() == count + 1); // +1 for placeholder
private void assertCollectionName(int index, string name)
=> AddUntilStep($"item {index + 1} has correct name", () => dialog.ChildrenOfType().ElementAt(index).ChildrenOfType().First().Text == name);
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs
index 6ad6f0b299..80a5b4832b 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs
@@ -56,8 +56,10 @@ namespace osu.Game.Tests.Visual.Editing
[Test]
public void TestCreateNewBeatmap()
{
+ AddAssert("status is none", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.None);
AddStep("save beatmap", () => Editor.Save());
AddAssert("new beatmap in database", () => beatmapManager.QueryBeatmapSet(s => s.ID == currentBeatmapSetID)?.Value.DeletePending == false);
+ AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
}
[Test]
@@ -136,6 +138,20 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("track is not virtual", () => Beatmap.Value.Track is not TrackVirtual);
AddAssert("track length changed", () => Beatmap.Value.Track.Length > 60000);
+
+ AddStep("test play", () => Editor.TestGameplay());
+
+ AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog != null);
+ AddStep("confirm save", () => InputManager.Key(Key.Number1));
+
+ AddUntilStep("wait for return to editor", () => Editor.IsCurrentScreen());
+
+ AddAssert("track is still not virtual", () => Beatmap.Value.Track is not TrackVirtual);
+ AddAssert("track length correct", () => Beatmap.Value.Track.Length > 60000);
+
+ AddUntilStep("track not playing", () => !EditorClock.IsRunning);
+ AddStep("play track", () => InputManager.Key(Key.Space));
+ AddUntilStep("wait for track playing", () => EditorClock.IsRunning);
}
[Test]
@@ -194,6 +210,8 @@ namespace osu.Game.Tests.Visual.Editing
});
AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0);
+ AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
+
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = secondDifficultyName);
AddStep("save beatmap", () => Editor.Save());
AddAssert("new beatmap persisted", () =>
@@ -204,7 +222,7 @@ namespace osu.Game.Tests.Visual.Editing
return beatmap != null
&& beatmap.DifficultyName == secondDifficultyName
&& set != null
- && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName));
+ && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName) && s.Beatmaps.All(b => s.Status == BeatmapOnlineStatus.LocallyModified));
});
}
@@ -280,7 +298,7 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4);
AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2);
- AddAssert("status not copied", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.None);
+ AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
AddAssert("online ID not copied", () => EditorBeatmap.BeatmapInfo.OnlineID == -1);
AddStep("save beatmap", () => Editor.Save());
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs
index 6c5cca1874..630d048867 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs
@@ -13,20 +13,12 @@ namespace osu.Game.Tests.Visual.Editing
public override Drawable CreateTestComponent() => Empty();
[Test]
- [FlakyTest]
- /*
- * Fail rate around 0.3%
- *
- * TearDown : osu.Framework.Testing.Drawables.Steps.AssertButton+TracedException : range halved
- * --TearDown
- * at osu.Framework.Threading.ScheduledDelegate.RunTaskInternal()
- * at osu.Framework.Threading.Scheduler.Update()
- * at osu.Framework.Graphics.Drawable.UpdateSubTree()
- */
public void TestVisibleRangeUpdatesOnZoomChange()
{
double initialVisibleRange = 0;
+ AddUntilStep("wait for load", () => MusicController.TrackLoaded);
+
AddStep("reset zoom", () => TimelineArea.Timeline.Zoom = 100);
AddStep("get initial range", () => initialVisibleRange = TimelineArea.Timeline.VisibleRange);
@@ -44,6 +36,8 @@ namespace osu.Game.Tests.Visual.Editing
{
double initialVisibleRange = 0;
+ AddUntilStep("wait for load", () => MusicController.TrackLoaded);
+
AddStep("reset timeline size", () => TimelineArea.Timeline.Width = 1);
AddStep("get initial range", () => initialVisibleRange = TimelineArea.Timeline.VisibleRange);
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs
index 9dc403814b..ce418f33f0 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Editing
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(30)
},
- scrollContainer = new ZoomableScrollContainer
+ scrollContainer = new ZoomableScrollContainer(1, 60, 1)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -80,21 +80,6 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("Inner container width matches scroll container", () => innerBox.DrawWidth == scrollContainer.DrawWidth);
}
- [Test]
- public void TestZoomRangeUpdate()
- {
- AddStep("set zoom to 2", () => scrollContainer.Zoom = 2);
- AddStep("set min zoom to 5", () => scrollContainer.MinZoom = 5);
- AddAssert("zoom = 5", () => scrollContainer.Zoom == 5);
-
- AddStep("set max zoom to 10", () => scrollContainer.MaxZoom = 10);
- AddAssert("zoom = 5", () => scrollContainer.Zoom == 5);
-
- AddStep("set min zoom to 20", () => scrollContainer.MinZoom = 20);
- AddStep("set max zoom to 40", () => scrollContainer.MaxZoom = 40);
- AddAssert("zoom = 20", () => scrollContainer.Zoom == 20);
- }
-
[Test]
public void TestZoom0()
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
index 47c8dc0f8d..f2fe55d719 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
@@ -31,20 +31,20 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override void AddCheckSteps()
{
- // It doesn't matter which ruleset is used - this beatmap is only used for reference.
- var beatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
+ // we only want this beatmap for time reference.
+ var referenceBeatmap = CreateBeatmap(new OsuRuleset().RulesetInfo);
AddUntilStep("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0);
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
- seekTo(beatmap.Beatmap.Breaks[0].StartTime);
+ seekTo(referenceBeatmap.Breaks[0].StartTime);
AddAssert("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
AddAssert("overlay displays 100% accuracy", () => Player.BreakOverlay.ChildrenOfType().Single().AccuracyDisplay.Current.Value == 1);
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
- seekTo(beatmap.Beatmap.HitObjects[^1].GetEndTime());
+ seekTo(referenceBeatmap.HitObjects[^1].GetEndTime());
AddUntilStep("results displayed", () => getResultsScreen()?.IsLoaded == true);
AddAssert("score has combo", () => getResultsScreen().Score.Combo > 100);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
index a79ba0ae5d..334d8f1452 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
@@ -263,27 +263,30 @@ namespace osu.Game.Tests.Visual.Gameplay
return beatmap;
}
- private void createTest(IBeatmap beatmap, Action overrideAction = null) => AddStep("create test", () =>
+ private void createTest(IBeatmap beatmap, Action overrideAction = null)
{
- var ruleset = new TestScrollingRuleset();
-
- drawableRuleset = (TestDrawableScrollingRuleset)ruleset.CreateDrawableRulesetWith(CreateWorkingBeatmap(beatmap).GetPlayableBeatmap(ruleset.RulesetInfo));
- drawableRuleset.FrameStablePlayback = false;
-
- overrideAction?.Invoke(drawableRuleset);
-
- Child = new Container
+ AddStep("create test", () =>
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Y,
- Height = 0.75f,
- Width = 400,
- Masking = true,
- Clock = new FramedClock(testClock),
- Child = drawableRuleset
- };
- });
+ var ruleset = new TestScrollingRuleset();
+
+ drawableRuleset = (TestDrawableScrollingRuleset)ruleset.CreateDrawableRulesetWith(CreateWorkingBeatmap(beatmap).GetPlayableBeatmap(ruleset.RulesetInfo));
+ drawableRuleset.FrameStablePlayback = false;
+
+ overrideAction?.Invoke(drawableRuleset);
+
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Y,
+ Height = 0.75f,
+ Width = 400,
+ Masking = true,
+ Clock = new FramedClock(testClock),
+ Child = drawableRuleset
+ };
+ });
+ }
#region Ruleset
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
index dd0f965914..fb97f94dbb 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
@@ -159,6 +159,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded);
AddUntilStep("wait for components to be hidden", () => hudOverlay.ChildrenOfType().Single().Alpha == 0);
+ AddUntilStep("wait for hud load", () => hudOverlay.ChildrenOfType().All(c => c.ComponentsLoaded));
AddStep("bind on update", () =>
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
index 5bd0a29308..71cc1f7b23 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public TestScenePause()
{
- base.Content.Add(content = new MenuCursorContainer { RelativeSizeAxes = Axes.Both });
+ base.Content.Add(content = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both });
}
[SetUpSteps]
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
index 56588e4d4e..05474e3d39 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
@@ -308,17 +308,18 @@ namespace osu.Game.Tests.Visual.Gameplay
}
}
- [TestCase(false, 1.0, false)] // not charging, above cutoff --> no warning
- [TestCase(true, 0.1, false)] // charging, below cutoff --> no warning
- [TestCase(false, 0.25, true)] // not charging, at cutoff --> warning
- public void TestLowBatteryNotification(bool isCharging, double chargeLevel, bool shouldWarn)
+ [TestCase(true, 1.0, false)] // on battery, above cutoff --> no warning
+ [TestCase(false, 0.1, false)] // not on battery, below cutoff --> no warning
+ [TestCase(true, 0.25, true)] // on battery, at cutoff --> warning
+ [TestCase(true, null, false)] // on battery, level unknown --> no warning
+ public void TestLowBatteryNotification(bool onBattery, double? chargeLevel, bool shouldWarn)
{
AddStep("reset notification lock", () => sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).Value = false);
// set charge status and level
AddStep("load player", () => resetPlayer(false, () =>
{
- batteryInfo.SetCharging(isCharging);
+ batteryInfo.SetOnBattery(onBattery);
batteryInfo.SetChargeLevel(chargeLevel);
}));
AddUntilStep("wait for player", () => player?.LoadState == LoadState.Ready);
@@ -408,19 +409,19 @@ namespace osu.Game.Tests.Visual.Gameplay
///
private class LocalBatteryInfo : BatteryInfo
{
- private bool isCharging = true;
- private double chargeLevel = 1;
+ private bool onBattery;
+ private double? chargeLevel;
- public override bool IsCharging => isCharging;
+ public override bool OnBattery => onBattery;
- public override double ChargeLevel => chargeLevel;
+ public override double? ChargeLevel => chargeLevel;
- public void SetCharging(bool value)
+ public void SetOnBattery(bool value)
{
- isCharging = value;
+ onBattery = value;
}
- public void SetChargeLevel(double value)
+ public void SetChargeLevel(double? value)
{
chargeLevel = value;
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs
index 6491987abe..ddb585a73c 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(new ScoreManager(rulesets, () => beatmaps, LocalStorage, Realm, Scheduler, API));
Dependencies.Cache(Realm);
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
index 96efca6b65..d1bdfb1dfa 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
@@ -239,7 +239,7 @@ namespace osu.Game.Tests.Visual.Gameplay
createPlayerTest(false, r =>
{
var beatmap = createTestBeatmap(r);
- beatmap.BeatmapInfo.OnlineID = -1;
+ beatmap.BeatmapInfo.ResetOnlineInfo();
return beatmap;
});
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs
index 1fa4885b7a..618ffbcb0e 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs
@@ -158,21 +158,24 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("clean up", () => drawableRuleset.NewResult -= onNewResult);
}
- private void createTest(IBeatmap beatmap, int poolSize, Func createClock = null) => AddStep("create test", () =>
+ private void createTest(IBeatmap beatmap, int poolSize, Func createClock = null)
{
- var ruleset = new TestPoolingRuleset();
-
- drawableRuleset = (TestDrawablePoolingRuleset)ruleset.CreateDrawableRulesetWith(CreateWorkingBeatmap(beatmap).GetPlayableBeatmap(ruleset.RulesetInfo));
- drawableRuleset.FrameStablePlayback = true;
- drawableRuleset.PoolSize = poolSize;
-
- Child = new Container
+ AddStep("create test", () =>
{
- RelativeSizeAxes = Axes.Both,
- Clock = createClock?.Invoke() ?? new FramedOffsetClock(Clock, false) { Offset = -Clock.CurrentTime },
- Child = drawableRuleset
- };
- });
+ var ruleset = new TestPoolingRuleset();
+
+ drawableRuleset = (TestDrawablePoolingRuleset)ruleset.CreateDrawableRulesetWith(CreateWorkingBeatmap(beatmap).GetPlayableBeatmap(ruleset.RulesetInfo));
+ drawableRuleset.FrameStablePlayback = true;
+ drawableRuleset.PoolSize = poolSize;
+
+ Child = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Clock = createClock?.Invoke() ?? new FramedOffsetClock(Clock, false) { Offset = -Clock.CurrentTime },
+ Child = drawableRuleset
+ };
+ });
+ }
#region Ruleset
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
index c259d5f0a8..9d70d1ef33 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
@@ -7,7 +7,6 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online;
-using osu.Game.Online.API.Requests.Responses;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
@@ -15,7 +14,6 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
-using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Screens.Ranking;
@@ -30,9 +28,6 @@ namespace osu.Game.Tests.Visual.Gameplay
{
private const long online_score_id = 2553163309;
- [Resolved]
- private RulesetStore rulesets { get; set; }
-
private TestReplayDownloadButton downloadButton;
[Resolved]
@@ -211,21 +206,18 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType().First().Enabled.Value);
}
- private ScoreInfo getScoreInfo(bool replayAvailable, bool hasOnlineId = true)
+ private ScoreInfo getScoreInfo(bool replayAvailable, bool hasOnlineId = true) => new ScoreInfo
{
- return new APIScore
+ OnlineID = hasOnlineId ? online_score_id : 0,
+ Ruleset = new OsuRuleset().RulesetInfo,
+ BeatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First(),
+ Hash = replayAvailable ? "online" : string.Empty,
+ User = new APIUser
{
- OnlineID = hasOnlineId ? online_score_id : 0,
- RulesetID = 0,
- Beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo).Beatmaps.First(),
- HasReplay = replayAvailable,
- User = new APIUser
- {
- Id = 39828,
- Username = @"WubWoofWolf",
- }
- }.CreateScoreInfo(rulesets, beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First());
- }
+ Id = 39828,
+ Username = @"WubWoofWolf",
+ }
+ };
private class TestReplayDownloadButton : ReplayDownloadButton
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
index 54b2e66f2f..b3401c916b 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
@@ -3,10 +3,10 @@
#nullable disable
+using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -40,8 +40,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private TestReplayRecorder recorder;
- [Cached]
- private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset());
+ private GameplayState gameplayState;
[SetUpSteps]
public void SetUpSteps()
@@ -52,81 +51,15 @@ namespace osu.Game.Tests.Visual.Gameplay
{
replay = new Replay();
- Add(new GridContainer
+ gameplayState = TestGameplayState.Create(new OsuRuleset());
+ gameplayState.Score.Replay = replay;
+
+ Child = new DependencyProvidingContainer
{
RelativeSizeAxes = Axes.Both,
- Content = new[]
- {
- new Drawable[]
- {
- recordingManager = new TestRulesetInputManager(TestCustomisableModRuleset.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
- {
- Recorder = recorder = new TestReplayRecorder(new Score
- {
- Replay = replay,
- ScoreInfo =
- {
- BeatmapInfo = gameplayState.Beatmap.BeatmapInfo,
- Ruleset = new OsuRuleset().RulesetInfo,
- }
- })
- {
- ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos),
- },
- Child = new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- new Box
- {
- Colour = Color4.Brown,
- RelativeSizeAxes = Axes.Both,
- },
- new OsuSpriteText
- {
- Text = "Recording",
- Scale = new Vector2(3),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- },
- new TestInputConsumer()
- }
- },
- }
- },
- new Drawable[]
- {
- playbackManager = new TestRulesetInputManager(TestCustomisableModRuleset.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
- {
- ReplayInputHandler = new TestFramedReplayInputHandler(replay)
- {
- GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos),
- },
- Child = new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- new Box
- {
- Colour = Color4.DarkBlue,
- RelativeSizeAxes = Axes.Both,
- },
- new OsuSpriteText
- {
- Text = "Playback",
- Scale = new Vector2(3),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- },
- new TestInputConsumer()
- }
- },
- }
- }
- }
- });
+ CachedDependencies = new (Type, object)[] { (typeof(GameplayState), gameplayState) },
+ Child = createContent(),
+ };
});
}
@@ -203,6 +136,74 @@ namespace osu.Game.Tests.Visual.Gameplay
recorder = null;
}
+ private Drawable createContent() => new GridContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Content = new[]
+ {
+ new Drawable[]
+ {
+ recordingManager = new TestRulesetInputManager(TestCustomisableModRuleset.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
+ {
+ Recorder = recorder = new TestReplayRecorder(gameplayState.Score)
+ {
+ ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos),
+ },
+ Child = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ Colour = Color4.Brown,
+ RelativeSizeAxes = Axes.Both,
+ },
+ new OsuSpriteText
+ {
+ Text = "Recording",
+ Scale = new Vector2(3),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ new TestInputConsumer()
+ }
+ },
+ }
+ },
+ new Drawable[]
+ {
+ playbackManager = new TestRulesetInputManager(TestCustomisableModRuleset.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
+ {
+ ReplayInputHandler = new TestFramedReplayInputHandler(replay)
+ {
+ GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos),
+ },
+ Child = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ Colour = Color4.DarkBlue,
+ RelativeSizeAxes = Axes.Both,
+ },
+ new OsuSpriteText
+ {
+ Text = "Playback",
+ Scale = new Vector2(3),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ new TestInputConsumer()
+ }
+ },
+ }
+ }
+ }
+ };
+
public class TestFramedReplayInputHandler : FramedReplayInputHandler
{
public TestFramedReplayInputHandler(Replay replay)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
index f319290441..bd274dfef5 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
@@ -14,6 +14,7 @@ using osu.Game.Overlays.Settings;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Play.HUD.HitErrorMeters;
+using osu.Game.Skinning;
using osu.Game.Skinning.Editor;
using osuTK.Input;
@@ -33,6 +34,8 @@ namespace osu.Game.Tests.Visual.Gameplay
{
base.SetUpSteps();
+ AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded));
+
AddStep("reload skin editor", () =>
{
skinEditor?.Expire();
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs
index eacab6d34f..ef56f456ea 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs
@@ -10,6 +10,7 @@ using osu.Framework.Testing;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD;
+using osu.Game.Skinning;
namespace osu.Game.Tests.Visual.Gameplay
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs
index e1fc65404d..5c73db15df 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs
@@ -33,7 +33,6 @@ namespace osu.Game.Tests.Visual.Gameplay
increment = skip_time;
var working = CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo));
- working.LoadTrack();
Child = gameplayClockContainer = new MasterGameplayClockContainer(working, 0)
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
index 07efb25b46..9eb71b9cf7 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
@@ -1,161 +1,76 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
-using osu.Framework.Utils;
-using osu.Framework.Timing;
-using osu.Game.Graphics;
using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Play;
+using osu.Game.Screens.Play.HUD;
+using osu.Game.Skinning;
namespace osu.Game.Tests.Visual.Gameplay
{
[TestFixture]
- public class TestSceneSongProgress : OsuTestScene
+ public class TestSceneSongProgress : SkinnableHUDComponentTestScene
{
- private SongProgress progress;
- private TestSongProgressGraph graph;
- private readonly Container progressContainer;
+ private GameplayClockContainer gameplayClockContainer = null!;
- private readonly StopwatchClock clock;
- private readonly FramedClock framedClock;
+ private const double skip_target_time = -2000;
- [Cached]
- private readonly GameplayClock gameplayClock;
-
- public TestSceneSongProgress()
+ [BackgroundDependencyLoader]
+ private void load()
{
- clock = new StopwatchClock();
- gameplayClock = new GameplayClock(framedClock = new FramedClock(clock));
+ Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
- Add(progressContainer = new Container
- {
- RelativeSizeAxes = Axes.X,
- Anchor = Anchor.BottomCentre,
- Origin = Anchor.BottomCentre,
- Height = 100,
- Y = -100,
- Child = new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.Gray(1),
- }
- });
+ Add(gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, skip_target_time));
+
+ Dependencies.CacheAs(gameplayClockContainer.GameplayClock);
}
[SetUpSteps]
public void SetupSteps()
{
- AddStep("add new song progress", () =>
- {
- if (progress != null)
- {
- progress.Expire();
- progress = null;
- }
-
- progressContainer.Add(progress = new SongProgress
- {
- RelativeSizeAxes = Axes.X,
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.BottomLeft,
- });
- });
-
- AddStep("add new big graph", () =>
- {
- if (graph != null)
- {
- graph.Expire();
- graph = null;
- }
-
- Add(graph = new TestSongProgressGraph
- {
- RelativeSizeAxes = Axes.X,
- Height = 200,
- Anchor = Anchor.TopLeft,
- Origin = Anchor.TopLeft,
- });
- });
-
- AddStep("reset clock", clock.Reset);
- }
-
- [Test]
- public void TestGraphRecreation()
- {
- AddAssert("ensure not created", () => graph.CreationCount == 0);
- AddStep("display values", displayRandomValues);
- AddUntilStep("wait for creation count", () => graph.CreationCount == 1);
- AddRepeatStep("new values", displayRandomValues, 5);
- AddWaitStep("wait some", 5);
- AddAssert("ensure recreation debounced", () => graph.CreationCount == 2);
+ AddStep("reset clock", () => gameplayClockContainer.Reset());
+ AddStep("set hit objects", setHitObjects);
}
[Test]
public void TestDisplay()
{
- AddStep("display max values", displayMaxValues);
- AddUntilStep("wait for graph", () => graph.CreationCount == 1);
- AddStep("start", clock.Start);
- AddStep("allow seeking", () => progress.AllowSeeking.Value = true);
- AddStep("hide graph", () => progress.ShowGraph.Value = false);
- AddStep("disallow seeking", () => progress.AllowSeeking.Value = false);
- AddStep("allow seeking", () => progress.AllowSeeking.Value = true);
- AddStep("show graph", () => progress.ShowGraph.Value = true);
- AddStep("stop", clock.Stop);
+ AddStep("seek to intro", () => gameplayClockContainer.Seek(skip_target_time));
+ AddStep("start", gameplayClockContainer.Start);
+ AddStep("stop", gameplayClockContainer.Stop);
}
- private void displayRandomValues()
+ [Test]
+ public void TestToggleSeeking()
{
- var objects = new List();
- for (double i = 0; i < 5000; i += RNG.NextDouble() * 10 + i / 1000)
- objects.Add(new HitObject { StartTime = i });
+ DefaultSongProgress getDefaultProgress() => this.ChildrenOfType().Single();
- replaceObjects(objects);
+ AddStep("allow seeking", () => getDefaultProgress().AllowSeeking.Value = true);
+ AddStep("hide graph", () => getDefaultProgress().ShowGraph.Value = false);
+ AddStep("disallow seeking", () => getDefaultProgress().AllowSeeking.Value = false);
+ AddStep("allow seeking", () => getDefaultProgress().AllowSeeking.Value = true);
+ AddStep("show graph", () => getDefaultProgress().ShowGraph.Value = true);
}
- private void displayMaxValues()
+ private void setHitObjects()
{
var objects = new List();
for (double i = 0; i < 5000; i++)
objects.Add(new HitObject { StartTime = i });
- replaceObjects(objects);
+ this.ChildrenOfType().ForEach(progress => progress.Objects = objects);
}
- private void replaceObjects(List objects)
- {
- progress.Objects = objects;
- graph.Objects = objects;
+ protected override Drawable CreateDefaultImplementation() => new DefaultSongProgress();
- progress.RequestSeek = pos => clock.Seek(pos);
- }
-
- protected override void Update()
- {
- base.Update();
- framedClock.ProcessFrame();
- }
-
- private class TestSongProgressGraph : SongProgressGraph
- {
- public int CreationCount { get; private set; }
-
- protected override void RecreateGraph()
- {
- base.RecreateGraph();
- CreationCount++;
- }
- }
+ protected override Drawable CreateLegacyImplementation() => new LegacySongProgress();
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs
new file mode 100644
index 0000000000..2fa3c0c7ec
--- /dev/null
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs
@@ -0,0 +1,73 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+#nullable disable
+
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Testing;
+using osu.Framework.Utils;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Screens.Play.HUD;
+
+namespace osu.Game.Tests.Visual.Gameplay
+{
+ [TestFixture]
+ public class TestSceneSongProgressGraph : OsuTestScene
+ {
+ private TestSongProgressGraph graph;
+
+ [SetUpSteps]
+ public void SetupSteps()
+ {
+ AddStep("add new big graph", () =>
+ {
+ if (graph != null)
+ {
+ graph.Expire();
+ graph = null;
+ }
+
+ Add(graph = new TestSongProgressGraph
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 200,
+ Anchor = Anchor.TopLeft,
+ Origin = Anchor.TopLeft,
+ });
+ });
+ }
+
+ [Test]
+ public void TestGraphRecreation()
+ {
+ AddAssert("ensure not created", () => graph.CreationCount == 0);
+ AddStep("display values", displayRandomValues);
+ AddUntilStep("wait for creation count", () => graph.CreationCount == 1);
+ AddRepeatStep("new values", displayRandomValues, 5);
+ AddWaitStep("wait some", 5);
+ AddAssert("ensure recreation debounced", () => graph.CreationCount == 2);
+ }
+
+ private void displayRandomValues()
+ {
+ var objects = new List();
+ for (double i = 0; i < 5000; i += RNG.NextDouble() * 10 + i / 1000)
+ objects.Add(new HitObject { StartTime = i });
+
+ graph.Objects = objects;
+ }
+
+ private class TestSongProgressGraph : SongProgressGraph
+ {
+ public int CreationCount { get; private set; }
+
+ protected override void RecreateGraph()
+ {
+ base.RecreateGraph();
+ CreationCount++;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs
index c55e98c1a8..9ad8ac086c 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs
@@ -5,6 +5,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Screens;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Spectator;
@@ -43,6 +44,21 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("spectator client sent correct ruleset", () => spectatorClient.WatchedUserStates[dummy_user_id].RulesetID == Ruleset.Value.OnlineID);
}
+ [Test]
+ public void TestRestart()
+ {
+ AddAssert("spectator client sees playing state", () => spectatorClient.WatchedUserStates[dummy_user_id].State == SpectatedUserState.Playing);
+
+ AddStep("exit player", () => Player.Exit());
+ AddStep("reload player", LoadPlayer);
+ AddUntilStep("wait for player load", () => Player.IsLoaded && Player.Alpha == 1);
+
+ AddAssert("spectator client sees playing state", () => spectatorClient.WatchedUserStates[dummy_user_id].State == SpectatedUserState.Playing);
+
+ AddWaitStep("wait", 5);
+ AddUntilStep("spectator client still sees playing state", () => spectatorClient.WatchedUserStates[dummy_user_id].State == SpectatedUserState.Playing);
+ }
+
public override void TearDownSteps()
{
base.TearDownSteps();
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs
index 5fad661e9b..9c41c70a0e 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs
@@ -27,7 +27,6 @@ using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
-using osu.Game.Screens.Play;
using osu.Game.Tests.Gameplay;
using osu.Game.Tests.Mods;
using osu.Game.Tests.Visual.Spectator;
@@ -41,16 +40,12 @@ namespace osu.Game.Tests.Visual.Gameplay
private TestRulesetInputManager playbackManager;
private TestRulesetInputManager recordingManager;
- private Replay replay;
-
+ private Score recordingScore;
+ private Replay playbackReplay;
private TestSpectatorClient spectatorClient;
-
private ManualClock manualClock;
-
private TestReplayRecorder recorder;
-
private OsuSpriteText latencyDisplay;
-
private TestFramedReplayInputHandler replayHandler;
[SetUpSteps]
@@ -58,7 +53,16 @@ namespace osu.Game.Tests.Visual.Gameplay
{
AddStep("Setup containers", () =>
{
- replay = new Replay();
+ recordingScore = new Score
+ {
+ ScoreInfo =
+ {
+ BeatmapInfo = new BeatmapInfo(),
+ Ruleset = new OsuRuleset().RulesetInfo,
+ }
+ };
+
+ playbackReplay = new Replay();
manualClock = new ManualClock();
Child = new DependencyProvidingContainer
@@ -67,7 +71,6 @@ namespace osu.Game.Tests.Visual.Gameplay
CachedDependencies = new[]
{
(typeof(SpectatorClient), (object)(spectatorClient = new TestSpectatorClient())),
- (typeof(GameplayState), TestGameplayState.Create(new OsuRuleset()))
},
Children = new Drawable[]
{
@@ -81,7 +84,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
recordingManager = new TestRulesetInputManager(TestCustomisableModRuleset.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
{
- Recorder = recorder = new TestReplayRecorder
+ Recorder = recorder = new TestReplayRecorder(recordingScore)
{
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos),
},
@@ -112,7 +115,7 @@ namespace osu.Game.Tests.Visual.Gameplay
playbackManager = new TestRulesetInputManager(TestCustomisableModRuleset.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
{
Clock = new FramedClock(manualClock),
- ReplayInputHandler = replayHandler = new TestFramedReplayInputHandler(replay)
+ ReplayInputHandler = replayHandler = new TestFramedReplayInputHandler(playbackReplay)
{
GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos),
},
@@ -144,6 +147,7 @@ namespace osu.Game.Tests.Visual.Gameplay
}
};
+ spectatorClient.BeginPlaying(TestGameplayState.Create(new OsuRuleset()), recordingScore);
spectatorClient.OnNewFrames += onNewFrames;
});
}
@@ -151,15 +155,15 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test]
public void TestBasic()
{
- AddUntilStep("received frames", () => replay.Frames.Count > 50);
+ AddUntilStep("received frames", () => playbackReplay.Frames.Count > 50);
AddStep("stop sending frames", () => recorder.Expire());
- AddUntilStep("wait for all frames received", () => replay.Frames.Count == recorder.SentFrames.Count);
+ AddUntilStep("wait for all frames received", () => playbackReplay.Frames.Count == recorder.SentFrames.Count);
}
[Test]
public void TestWithSendFailure()
{
- AddUntilStep("received frames", () => replay.Frames.Count > 50);
+ AddUntilStep("received frames", () => playbackReplay.Frames.Count > 50);
int framesReceivedSoFar = 0;
int frameSendAttemptsSoFar = 0;
@@ -172,21 +176,21 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for next send attempt", () =>
{
- framesReceivedSoFar = replay.Frames.Count;
+ framesReceivedSoFar = playbackReplay.Frames.Count;
return spectatorClient.FrameSendAttempts > frameSendAttemptsSoFar + 1;
});
AddUntilStep("wait for more send attempts", () => spectatorClient.FrameSendAttempts > frameSendAttemptsSoFar + 10);
- AddAssert("frames did not increase", () => framesReceivedSoFar == replay.Frames.Count);
+ AddAssert("frames did not increase", () => framesReceivedSoFar == playbackReplay.Frames.Count);
AddStep("stop failing sends", () => spectatorClient.ShouldFailSendingFrames = false);
- AddUntilStep("wait for next frames", () => framesReceivedSoFar < replay.Frames.Count);
+ AddUntilStep("wait for next frames", () => framesReceivedSoFar < playbackReplay.Frames.Count);
AddStep("stop sending frames", () => recorder.Expire());
- AddUntilStep("wait for all frames received", () => replay.Frames.Count == recorder.SentFrames.Count);
- AddAssert("ensure frames were received in the correct sequence", () => replay.Frames.Select(f => f.Time).SequenceEqual(recorder.SentFrames.Select(f => f.Time)));
+ AddUntilStep("wait for all frames received", () => playbackReplay.Frames.Count == recorder.SentFrames.Count);
+ AddAssert("ensure frames were received in the correct sequence", () => playbackReplay.Frames.Select(f => f.Time).SequenceEqual(recorder.SentFrames.Select(f => f.Time)));
}
private void onNewFrames(int userId, FrameDataBundle frames)
@@ -195,10 +199,10 @@ namespace osu.Game.Tests.Visual.Gameplay
{
var frame = new TestReplayFrame();
frame.FromLegacy(legacyFrame, null);
- replay.Frames.Add(frame);
+ playbackReplay.Frames.Add(frame);
}
- Logger.Log($"Received {frames.Frames.Count} new frames (total {replay.Frames.Count} of {recorder.SentFrames.Count})");
+ Logger.Log($"Received {frames.Frames.Count} new frames (total {playbackReplay.Frames.Count} of {recorder.SentFrames.Count})");
}
private double latency = SpectatorClient.TIME_BETWEEN_SENDS;
@@ -219,7 +223,7 @@ namespace osu.Game.Tests.Visual.Gameplay
if (!replayHandler.HasFrames)
return;
- var lastFrame = replay.Frames.LastOrDefault();
+ var lastFrame = playbackReplay.Frames.LastOrDefault();
// this isn't perfect as we basically can't be aware of the rate-of-send here (the streamer is not sending data when not being moved).
// in gameplay playback, the case where NextFrame is null would pause gameplay and handle this correctly; it's strictly a test limitation / best effort implementation.
@@ -360,15 +364,8 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public List SentFrames = new List();
- public TestReplayRecorder()
- : base(new Score
- {
- ScoreInfo =
- {
- BeatmapInfo = new BeatmapInfo(),
- Ruleset = new OsuRuleset().RulesetInfo,
- }
- })
+ public TestReplayRecorder(Score score)
+ : base(score)
{
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
index 2b461cf6f6..ca4d926866 100644
--- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
@@ -35,7 +35,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
protected IScreen CurrentSubScreen => multiplayerComponents.MultiplayerScreen.CurrentSubScreen;
private BeatmapManager beatmaps;
- private RulesetStore rulesets;
private BeatmapSetInfo importedSet;
private TestMultiplayerComponents multiplayerComponents;
@@ -45,8 +44,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs
index 0a59e0e858..b26481387d 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs
@@ -19,29 +19,33 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
private DrawableRoomParticipantsList list;
- [SetUp]
- public new void Setup() => Schedule(() =>
+ public override void SetUpSteps()
{
- SelectedRoom.Value = new Room
- {
- Name = { Value = "test room" },
- Host =
- {
- Value = new APIUser
- {
- Id = 2,
- Username = "peppy",
- }
- }
- };
+ base.SetUpSteps();
- Child = list = new DrawableRoomParticipantsList
+ AddStep("create list", () =>
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- NumberOfCircles = 4
- };
- });
+ SelectedRoom.Value = new Room
+ {
+ Name = { Value = "test room" },
+ Host =
+ {
+ Value = new APIUser
+ {
+ Id = 2,
+ Username = "peppy",
+ }
+ }
+ };
+
+ Child = list = new DrawableRoomParticipantsList
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ NumberOfCircles = 4
+ };
+ });
+ }
[Test]
public void TestCircleCountNearLimit()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
index 1797c82fb9..73d1222156 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
@@ -38,13 +38,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
private TestPlaylist playlist;
private BeatmapManager manager;
- private RulesetStore rulesets;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
index 82e7bf8969..3d6d4f0a90 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
@@ -25,23 +25,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
private RoomsContainer container;
- [SetUp]
- public new void Setup() => Schedule(() =>
+ public override void SetUpSteps()
{
- Child = new PopoverContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Width = 0.5f,
+ base.SetUpSteps();
- Child = container = new RoomsContainer
+ AddStep("create container", () =>
+ {
+ Child = new PopoverContainer
{
- SelectedRoom = { BindTarget = SelectedRoom }
- }
- };
- });
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Width = 0.5f,
+
+ Child = container = new RoomsContainer
+ {
+ SelectedRoom = { BindTarget = SelectedRoom }
+ }
+ };
+ });
+ }
[Test]
public void TestBasicListChanges()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs
index 8cdcdfdfdf..b113352117 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs
@@ -3,7 +3,6 @@
#nullable disable
-using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
@@ -18,19 +17,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMatchBeatmapDetailArea : OnlinePlayTestScene
{
- [SetUp]
- public new void Setup() => Schedule(() =>
+ public override void SetUpSteps()
{
- SelectedRoom.Value = new Room();
+ base.SetUpSteps();
- Child = new MatchBeatmapDetailArea
+ AddStep("create area", () =>
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Size = new Vector2(500),
- CreateNewItem = createNewItem
- };
- });
+ SelectedRoom.Value = new Room();
+
+ Child = new MatchBeatmapDetailArea
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(500),
+ CreateNewItem = createNewItem
+ };
+ });
+ }
private void createNewItem()
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs
index 506d7541a7..d2468ae005 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs
@@ -4,8 +4,6 @@
#nullable disable
using System.Collections.Generic;
-using NUnit.Framework;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
@@ -19,59 +17,62 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMatchLeaderboard : OnlinePlayTestScene
{
- [BackgroundDependencyLoader]
- private void load()
+ public override void SetUpSteps()
{
- ((DummyAPIAccess)API).HandleRequest = r =>
+ base.SetUpSteps();
+
+ AddStep("setup API", () =>
{
- switch (r)
+ ((DummyAPIAccess)API).HandleRequest = r =>
{
- case GetRoomLeaderboardRequest leaderboardRequest:
- leaderboardRequest.TriggerSuccess(new APILeaderboard
- {
- Leaderboard = new List
+ switch (r)
+ {
+ case GetRoomLeaderboardRequest leaderboardRequest:
+ leaderboardRequest.TriggerSuccess(new APILeaderboard
{
- new APIUserScoreAggregate
+ Leaderboard = new List
{
- UserID = 2,
- User = new APIUser { Id = 2, Username = "peppy" },
- TotalScore = 995533,
- RoomID = 3,
- CompletedBeatmaps = 1,
- TotalAttempts = 6,
- Accuracy = 0.9851
- },
- new APIUserScoreAggregate
- {
- UserID = 1040328,
- User = new APIUser { Id = 1040328, Username = "smoogipoo" },
- TotalScore = 981100,
- RoomID = 3,
- CompletedBeatmaps = 1,
- TotalAttempts = 9,
- Accuracy = 0.937
+ new APIUserScoreAggregate
+ {
+ UserID = 2,
+ User = new APIUser { Id = 2, Username = "peppy" },
+ TotalScore = 995533,
+ RoomID = 3,
+ CompletedBeatmaps = 1,
+ TotalAttempts = 6,
+ Accuracy = 0.9851
+ },
+ new APIUserScoreAggregate
+ {
+ UserID = 1040328,
+ User = new APIUser { Id = 1040328, Username = "smoogipoo" },
+ TotalScore = 981100,
+ RoomID = 3,
+ CompletedBeatmaps = 1,
+ TotalAttempts = 9,
+ Accuracy = 0.937
+ }
}
- }
- });
- return true;
- }
+ });
+ return true;
+ }
- return false;
- };
- }
+ return false;
+ };
+ });
- [SetUp]
- public new void Setup() => Schedule(() =>
- {
- SelectedRoom.Value = new Room { RoomID = { Value = 3 } };
-
- Child = new MatchLeaderboard
+ AddStep("create leaderboard", () =>
{
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- Size = new Vector2(550f, 450f),
- Scope = MatchLeaderboardScope.Overall,
- };
- });
+ SelectedRoom.Value = new Room { RoomID = { Value = 3 } };
+
+ Child = new MatchLeaderboard
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Size = new Vector2(550f, 450f),
+ Scope = MatchLeaderboardScope.Overall,
+ };
+ });
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs
index 80c356ec67..9e6941738a 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs
@@ -22,8 +22,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
private MultiSpectatorLeaderboard leaderboard;
[SetUpSteps]
- public new void SetUpSteps()
+ public override void SetUpSteps()
{
+ base.SetUpSteps();
+
AddStep("reset", () =>
{
leaderboard?.RemoveAndDisposeImmediately();
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
index 7df68392cf..d626426e6d 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
@@ -56,8 +56,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
importedBeatmapId = importedBeatmap.OnlineID;
}
- [SetUp]
- public new void Setup() => Schedule(() => playingUsers.Clear());
+ public override void SetUpSteps()
+ {
+ base.SetUpSteps();
+
+ AddStep("clear playing users", () => playingUsers.Clear());
+ }
[Test]
public void TestDelayedStart()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
index bf9b99e3e2..269867be73 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
@@ -49,7 +49,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
public class TestSceneMultiplayer : ScreenTestScene
{
private BeatmapManager beatmaps = null!;
- private RulesetStore rulesets = null!;
private BeatmapSetInfo importedSet = null!;
private TestMultiplayerComponents multiplayerComponents = null!;
@@ -63,8 +62,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs
index a98030e1e3..83e7ef6a81 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs
@@ -3,7 +3,6 @@
#nullable disable
-using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
@@ -13,23 +12,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMultiplayerMatchFooter : MultiplayerTestScene
{
- [SetUp]
- public new void Setup() => Schedule(() =>
+ public override void SetUpSteps()
{
- Child = new PopoverContainer
+ base.SetUpSteps();
+
+ AddStep("create footer", () =>
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Child = new Container
+ Child = new PopoverContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.X,
- Height = 50,
- Child = new MultiplayerMatchFooter()
- }
- };
- });
+ RelativeSizeAxes = Axes.Both,
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.X,
+ Height = 50,
+ Child = new MultiplayerMatchFooter()
+ }
+ };
+ });
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
index ab4f9c37b2..2281235f25 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
@@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
importedBeatmapSet = manager.Import(TestResources.CreateTestBeatmapSetInfo(8, rulesets.AvailableRulesets.ToArray()));
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs
index 5d6a6c8104..9fc42dc68b 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs
@@ -4,6 +4,7 @@
#nullable disable
using System.Linq;
+using JetBrains.Annotations;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@@ -17,6 +18,8 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Dialog;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
@@ -24,6 +27,7 @@ using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Rulesets.UI;
+using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Match;
using osu.Game.Screens.OnlinePlay.Multiplayer;
@@ -40,7 +44,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
private MultiplayerMatchSubScreen screen;
private BeatmapManager beatmaps;
- private RulesetStore rulesets;
private BeatmapSetInfo importedSet;
public TestSceneMultiplayerMatchSubScreen()
@@ -51,8 +54,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
@@ -60,16 +63,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
}
- [SetUp]
- public new void Setup() => Schedule(() =>
- {
- SelectedRoom.Value = new Room { Name = { Value = "Test Room" } };
- });
-
[SetUpSteps]
public void SetupSteps()
{
- AddStep("load match", () => LoadScreen(screen = new MultiplayerMatchSubScreen(SelectedRoom.Value)));
+ AddStep("load match", () =>
+ {
+ SelectedRoom.Value = new Room { Name = { Value = "Test Room" } };
+ LoadScreen(screen = new TestMultiplayerMatchSubScreen(SelectedRoom.Value));
+ });
+
AddUntilStep("wait for load", () => screen.IsCurrentScreen());
}
@@ -283,5 +285,29 @@ namespace osu.Game.Tests.Visual.Multiplayer
return lastItem.IsSelectedItem;
});
}
+
+ private class TestMultiplayerMatchSubScreen : MultiplayerMatchSubScreen
+ {
+ [Resolved(canBeNull: true)]
+ [CanBeNull]
+ private IDialogOverlay dialogOverlay { get; set; }
+
+ public TestMultiplayerMatchSubScreen(Room room)
+ : base(room)
+ {
+ }
+
+ public override bool OnExiting(ScreenExitEvent e)
+ {
+ // For testing purposes allow the screen to exit without confirming on second attempt.
+ if (!ExitConfirmed && dialogOverlay?.CurrentDialog is ConfirmDiscardChangesDialog confirmDialog)
+ {
+ confirmDialog.PerformAction();
+ return true;
+ }
+
+ return base.OnExiting(e);
+ }
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
index 5ee385810b..8dbad4e330 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
@@ -31,33 +31,33 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
private MultiplayerPlaylist list;
private BeatmapManager beatmaps;
- private RulesetStore rulesets;
private BeatmapSetInfo importedSet;
private BeatmapInfo importedBeatmap;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
- [SetUp]
- public new void Setup() => Schedule(() =>
- {
- Child = list = new MultiplayerPlaylist
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Size = new Vector2(0.4f, 0.8f)
- };
- });
-
[SetUpSteps]
- public new void SetUpSteps()
+ public override void SetUpSteps()
{
+ base.SetUpSteps();
+
+ AddStep("create list", () =>
+ {
+ Child = list = new MultiplayerPlaylist
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Size = new Vector2(0.4f, 0.8f)
+ };
+ });
+
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs
index e709a955b3..f31261dc1f 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs
@@ -29,15 +29,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
private MultiplayerQueueList playlist;
private BeatmapManager beatmaps;
- private RulesetStore rulesets;
private BeatmapSetInfo importedSet;
private BeatmapInfo importedBeatmap;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs
index 91c87548c7..9b4cb722f3 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs
@@ -35,55 +35,58 @@ namespace osu.Game.Tests.Visual.Multiplayer
private BeatmapSetInfo importedSet;
private BeatmapManager beatmaps;
- private RulesetStore rulesets;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
}
- [SetUp]
- public new void Setup() => Schedule(() =>
+ public override void SetUpSteps()
{
- AvailabilityTracker.SelectedItem.BindTo(selectedItem);
+ base.SetUpSteps();
- importedSet = beatmaps.GetAllUsableBeatmapSets().First();
- Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
- selectedItem.Value = new PlaylistItem(Beatmap.Value.BeatmapInfo)
+ AddStep("create button", () =>
{
- RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID,
- };
+ AvailabilityTracker.SelectedItem.BindTo(selectedItem);
- Child = new PopoverContainer
- {
- RelativeSizeAxes = Axes.Both,
- Child = new FillFlowContainer
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
+ Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
+ selectedItem.Value = new PlaylistItem(Beatmap.Value.BeatmapInfo)
{
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
+ RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID,
+ };
+
+ Child = new PopoverContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = new FillFlowContainer
{
- spectateButton = new MultiplayerSpectateButton
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Size = new Vector2(200, 50),
- },
- startControl = new MatchStartControl
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Size = new Vector2(200, 50),
+ spectateButton = new MultiplayerSpectateButton
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(200, 50),
+ },
+ startControl = new MatchStartControl
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(200, 50),
+ }
}
}
- }
- };
- });
+ };
+ });
+ }
[TestCase(MultiplayerRoomState.Open)]
[TestCase(MultiplayerRoomState.WaitingForLoad)]
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
index 88afe1ce7c..2eddf1a17e 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
@@ -28,15 +28,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
private BeatmapManager manager;
- private RulesetStore rulesets;
-
private TestPlaylistsSongSelect songSelect;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
var beatmapSet = TestResources.CreateTestBeatmapSetInfo();
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs
index 321e0c2c89..5bccabcf2f 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs
@@ -14,17 +14,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneStarRatingRangeDisplay : OnlinePlayTestScene
{
- [SetUp]
- public new void Setup() => Schedule(() =>
+ public override void SetUpSteps()
{
- SelectedRoom.Value = new Room();
+ base.SetUpSteps();
- Child = new StarRatingRangeDisplay
+ AddStep("create display", () =>
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre
- };
- });
+ SelectedRoom.Value = new Room();
+
+ Child = new StarRatingRangeDisplay
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre
+ };
+ });
+ }
[Test]
public void TestRange([Values(0, 2, 3, 4, 6, 7)] double min, [Values(0, 2, 3, 4, 6, 7)] double max)
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
index d80537a2e5..ef2a431b8f 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
@@ -30,7 +30,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
public class TestSceneTeamVersus : ScreenTestScene
{
private BeatmapManager beatmaps;
- private RulesetStore rulesets;
private BeatmapSetInfo importedSet;
private TestMultiplayerComponents multiplayerComponents;
@@ -40,8 +39,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
index a61352f954..8fce43f9b0 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
@@ -26,6 +26,7 @@ using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay.Lounge;
+using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.Select;
@@ -45,6 +46,57 @@ namespace osu.Game.Tests.Visual.Navigation
private Vector2 optionsButtonPosition => Game.ToScreenSpace(new Vector2(click_padding, click_padding));
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestConfirmationRequiredToDiscardPlaylist(bool withPlaylistItemAdded)
+ {
+ Screens.OnlinePlay.Playlists.Playlists playlistScreen = null;
+
+ AddUntilStep("wait for dialog overlay", () => Game.ChildrenOfType().SingleOrDefault() != null);
+
+ PushAndConfirm(() => playlistScreen = new Screens.OnlinePlay.Playlists.Playlists());
+
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
+
+ AddStep("open create screen", () =>
+ {
+ InputManager.MoveMouseTo(playlistScreen.ChildrenOfType().Single());
+ InputManager.Click(MouseButton.Left);
+ });
+
+ if (withPlaylistItemAdded)
+ {
+ AddUntilStep("wait for settings displayed",
+ () => (playlistScreen.CurrentSubScreen as PlaylistsRoomSubScreen)?.ChildrenOfType().SingleOrDefault()?.State.Value == Visibility.Visible);
+
+ AddStep("edit playlist", () => InputManager.Key(Key.Enter));
+
+ AddUntilStep("wait for song select", () => (playlistScreen.CurrentSubScreen as PlaylistsSongSelect)?.BeatmapSetsLoaded == true);
+
+ AddUntilStep("wait for selection", () => !Game.Beatmap.IsDefault);
+
+ AddStep("add item", () => InputManager.Key(Key.Enter));
+
+ AddUntilStep("wait for return to playlist screen", () => playlistScreen.CurrentSubScreen is PlaylistsRoomSubScreen);
+
+ pushEscape();
+ AddAssert("confirmation dialog shown", () => Game.ChildrenOfType().Single().CurrentDialog is not null);
+
+ AddStep("confirm exit", () => InputManager.Key(Key.Enter));
+
+ AddAssert("dialog dismissed", () => Game.ChildrenOfType().Single().CurrentDialog == null);
+
+ exitViaEscapeAndConfirm();
+ }
+ else
+ {
+ pushEscape();
+ AddAssert("confirmation dialog not shown", () => Game.ChildrenOfType().Single().CurrentDialog == null);
+
+ exitViaEscapeAndConfirm();
+ }
+ }
+
[Test]
public void TestExitSongSelectWithEscape()
{
@@ -74,14 +126,14 @@ namespace osu.Game.Tests.Visual.Navigation
AddStep("set filter again", () => songSelect.ChildrenOfType().Single().Current.Value = "test");
AddStep("open collections dropdown", () =>
{
- InputManager.MoveMouseTo(songSelect.ChildrenOfType().Single());
+ InputManager.MoveMouseTo(songSelect.ChildrenOfType().Single());
InputManager.Click(MouseButton.Left);
});
AddStep("press back once", () => InputManager.Click(MouseButton.Button1));
AddAssert("still at song select", () => Game.ScreenStack.CurrentScreen == songSelect);
AddAssert("collections dropdown closed", () => songSelect
- .ChildrenOfType().Single()
+ .ChildrenOfType().Single()
.ChildrenOfType.DropdownMenu>().Single().State == MenuState.Closed);
AddStep("press back a second time", () => InputManager.Click(MouseButton.Button1));
diff --git a/osu.Game.Tests/Visual/Online/TestSceneExternalLinkButton.cs b/osu.Game.Tests/Visual/Online/TestSceneExternalLinkButton.cs
index fdcde0f2a5..4185d56833 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneExternalLinkButton.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneExternalLinkButton.cs
@@ -3,6 +3,8 @@
#nullable disable
+using osu.Framework.Graphics;
+using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.UserInterface;
using osuTK;
@@ -12,9 +14,15 @@ namespace osu.Game.Tests.Visual.Online
{
public TestSceneExternalLinkButton()
{
- Child = new ExternalLinkButton("https://osu.ppy.sh/home")
+ Child = new OsuContextMenuContainer
{
- Size = new Vector2(50)
+ RelativeSizeAxes = Axes.Both,
+ Child = new ExternalLinkButton("https://osu.ppy.sh/home")
+ {
+ Size = new Vector2(50),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ }
};
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
index 864b2b6878..cfa9f77634 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
@@ -141,6 +141,19 @@ namespace osu.Game.Tests.Visual.Online
AddUntilStep("best score not displayed", () => scoresContainer.ChildrenOfType().Count() == 1);
}
+ [Test]
+ public void TestUnprocessedPP()
+ {
+ AddStep("Load scores with unprocessed PP", () =>
+ {
+ var allScores = createScores();
+ allScores.Scores[0].PP = null;
+ allScores.UserScore = createUserBest();
+ allScores.UserScore.Score.PP = null;
+ scoresContainer.Scores = allScores;
+ });
+ }
+
private int onlineID = 1;
private APIScoresCollection createScores()
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
index 0eb6ec3c04..4bbb72c862 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
@@ -7,6 +7,7 @@ using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
@@ -99,6 +100,23 @@ namespace osu.Game.Tests.Visual.Online
Accuracy = 0.55879
};
+ var unprocessedPPScore = new SoloScoreInfo
+ {
+ Rank = ScoreRank.B,
+ Beatmap = new APIBeatmap
+ {
+ BeatmapSet = new APIBeatmapSet
+ {
+ Title = "C18H27NO3(extend)",
+ Artist = "Team Grimoire",
+ },
+ DifficultyName = "[4K] Cataclysmic Hypernova",
+ Status = BeatmapOnlineStatus.Ranked,
+ },
+ EndedAt = DateTimeOffset.Now,
+ Accuracy = 0.55879
+ };
+
Add(new FillFlowContainer
{
Anchor = Anchor.Centre,
@@ -112,6 +130,7 @@ namespace osu.Game.Tests.Visual.Online
new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(firstScore)),
new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(secondScore)),
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(noPPScore)),
+ new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(unprocessedPPScore)),
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(firstScore, 0.97)),
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(secondScore, 0.85)),
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(thirdScore, 0.66)),
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs
index e6882081dd..c71bdb3a06 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs
@@ -25,17 +25,21 @@ namespace osu.Game.Tests.Visual.Playlists
protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new TestDependencies();
- [SetUp]
- public new void Setup() => Schedule(() =>
+ public override void SetUpSteps()
{
- SelectedRoom.Value = new Room();
+ base.SetUpSteps();
- Child = settings = new TestRoomSettings(SelectedRoom.Value)
+ AddStep("create overlay", () =>
{
- RelativeSizeAxes = Axes.Both,
- State = { Value = Visibility.Visible }
- };
- });
+ SelectedRoom.Value = new Room();
+
+ Child = settings = new TestRoomSettings(SelectedRoom.Value)
+ {
+ RelativeSizeAxes = Axes.Both,
+ State = { Value = Visibility.Visible }
+ };
+ });
+ }
[Test]
public void TestButtonEnabledOnlyWithNameAndBeatmap()
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs
index 5961ed74ad..9a0dda056a 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs
@@ -15,21 +15,25 @@ namespace osu.Game.Tests.Visual.Playlists
{
public class TestScenePlaylistsParticipantsList : OnlinePlayTestScene
{
- [SetUp]
- public new void Setup() => Schedule(() =>
+ public override void SetUpSteps()
{
- SelectedRoom.Value = new Room { RoomID = { Value = 7 } };
+ base.SetUpSteps();
- for (int i = 0; i < 50; i++)
+ AddStep("create list", () =>
{
- SelectedRoom.Value.RecentParticipants.Add(new APIUser
+ SelectedRoom.Value = new Room { RoomID = { Value = 7 } };
+
+ for (int i = 0; i < 50; i++)
{
- Username = "peppy",
- Statistics = new UserStatistics { GlobalRank = 1234 },
- Id = 2
- });
- }
- });
+ SelectedRoom.Value.RecentParticipants.Add(new APIUser
+ {
+ Username = "peppy",
+ Statistics = new UserStatistics { GlobalRank = 1234 },
+ Id = 2
+ });
+ }
+ });
+ }
[Test]
public void TestHorizontalLayout()
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
index c0cd2d9157..b304b34275 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
@@ -6,6 +6,7 @@
using System;
using System.Diagnostics;
using System.Linq;
+using JetBrains.Annotations;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@@ -16,9 +17,12 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.Rooms;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Dialog;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Playlists;
@@ -32,7 +36,6 @@ namespace osu.Game.Tests.Visual.Playlists
public class TestScenePlaylistsRoomCreation : OnlinePlayTestScene
{
private BeatmapManager manager;
- private RulesetStore rulesets;
private TestPlaylistsRoomSubScreen match;
@@ -41,8 +44,8 @@ namespace osu.Game.Tests.Visual.Playlists
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
@@ -222,10 +225,26 @@ namespace osu.Game.Tests.Visual.Playlists
public new Bindable Beatmap => base.Beatmap;
+ [Resolved(canBeNull: true)]
+ [CanBeNull]
+ private IDialogOverlay dialogOverlay { get; set; }
+
public TestPlaylistsRoomSubScreen(Room room)
: base(room)
{
}
+
+ public override bool OnExiting(ScreenExitEvent e)
+ {
+ // For testing purposes allow the screen to exit without confirming on second attempt.
+ if (!ExitConfirmed && dialogOverlay?.CurrentDialog is ConfirmDiscardChangesDialog confirmDialog)
+ {
+ confirmDialog.PerformAction();
+ return true;
+ }
+
+ return base.OnExiting(e);
+ }
}
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
index e574ee30fb..bb9e83a21c 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
@@ -486,9 +486,6 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("Something is selected", () => carousel.SelectedBeatmapInfo != null);
}
- ///
- /// Test sorting
- ///
[Test]
public void TestSorting()
{
@@ -517,18 +514,56 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert($"Check {zzz_string} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Artist == zzz_string);
}
+ ///
+ /// Ensures stability is maintained on different sort modes for items with equal properties.
+ ///
[Test]
public void TestSortingStability()
{
var sets = new List();
- for (int i = 0; i < 20; i++)
+ for (int i = 0; i < 10; i++)
{
var set = TestResources.CreateTestBeatmapSetInfo();
// only need to set the first as they are a shared reference.
var beatmap = set.Beatmaps.First();
+ beatmap.Metadata.Artist = $"artist {i / 2}";
+ beatmap.Metadata.Title = $"title {9 - i}";
+
+ sets.Add(set);
+ }
+
+ int idOffset = sets.First().OnlineID;
+
+ loadBeatmaps(sets);
+
+ AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false));
+ AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b));
+
+ AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false));
+ AddAssert("Items are in reverse order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + sets.Count - index - 1).All(b => b));
+
+ AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false));
+ AddAssert("Items reset to original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b));
+ }
+
+ ///
+ /// Ensures stability is maintained on different sort modes while a new item is added to the carousel.
+ ///
+ [Test]
+ public void TestSortingStabilityWithNewItems()
+ {
+ List sets = new List();
+
+ for (int i = 0; i < 3; i++)
+ {
+ var set = TestResources.CreateTestBeatmapSetInfo(3);
+
+ // only need to set the first as they are a shared reference.
+ var beatmap = set.Beatmaps.First();
+
beatmap.Metadata.Artist = "same artist";
beatmap.Metadata.Title = "same title";
@@ -540,10 +575,25 @@ namespace osu.Game.Tests.Visual.SongSelect
loadBeatmaps(sets);
AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false));
- AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == index + idOffset).All(b => b));
+ AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b));
+
+ AddStep("Add new item", () =>
+ {
+ var set = TestResources.CreateTestBeatmapSetInfo();
+
+ // only need to set the first as they are a shared reference.
+ var beatmap = set.Beatmaps.First();
+
+ beatmap.Metadata.Artist = "same artist";
+ beatmap.Metadata.Title = "same title";
+
+ carousel.UpdateBeatmapSet(set);
+ });
+
+ AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b));
AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false));
- AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == index + idOffset).All(b => b));
+ AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b));
}
[Test]
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index abcb888cd4..aeb30c94e1 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.SongSelect
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.Cache(rulesetStore = new RealmRulesetStore(Realm));
- dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default));
+ dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, Scheduler, API));
Dependencies.Cache(Realm);
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs
index 6807180640..dadcd43db5 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs
@@ -1,8 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
+using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
@@ -21,6 +20,7 @@ using osu.Game.Rulesets;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osuTK.Input;
+using Realms;
namespace osu.Game.Tests.Visual.SongSelect
{
@@ -28,35 +28,28 @@ namespace osu.Game.Tests.Visual.SongSelect
{
protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both };
- private CollectionManager collectionManager;
-
- private RulesetStore rulesets;
- private BeatmapManager beatmapManager;
-
- private FilterControl control;
+ private BeatmapManager beatmapManager = null!;
+ private FilterControl control = null!;
[BackgroundDependencyLoader]
private void load(GameHost host)
{
- Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesets, null, Audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(new RealmRulesetStore(Realm));
+ Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
base.Content.AddRange(new Drawable[]
{
- collectionManager = new CollectionManager(LocalStorage),
Content
});
-
- Dependencies.Cache(collectionManager);
}
[SetUp]
public void SetUp() => Schedule(() =>
{
- collectionManager.Collections.Clear();
+ writeAndRefresh(r => r.RemoveAll());
Child = control = new FilterControl
{
@@ -77,8 +70,8 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestCollectionAddedToDropdown()
{
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "1" } }));
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "2" } }));
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "2"))));
assertCollectionDropdownContains("1");
assertCollectionDropdownContains("2");
}
@@ -86,9 +79,11 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestCollectionRemovedFromDropdown()
{
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "1" } }));
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "2" } }));
- AddStep("remove collection", () => collectionManager.Collections.RemoveAt(0));
+ BeatmapCollection first = null!;
+
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(first = new BeatmapCollection(name: "1"))));
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "2"))));
+ AddStep("remove collection", () => writeAndRefresh(r => r.Remove(first)));
assertCollectionDropdownContains("1", false);
assertCollectionDropdownContains("2");
@@ -97,16 +92,17 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestCollectionRenamed()
{
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "1" } }));
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
+ assertCollectionDropdownContains("1");
AddStep("select collection", () =>
{
- var dropdown = control.ChildrenOfType().Single();
+ var dropdown = control.ChildrenOfType().Single();
dropdown.Current.Value = dropdown.ItemSource.ElementAt(1);
});
addExpandHeaderStep();
- AddStep("change name", () => collectionManager.Collections[0].Name.Value = "First");
+ AddStep("change name", () => writeAndRefresh(_ => getFirstCollection().Name = "First"));
assertCollectionDropdownContains("First");
assertCollectionHeaderDisplays("First");
@@ -124,7 +120,8 @@ namespace osu.Game.Tests.Visual.SongSelect
public void TestCollectionFilterHasAddButton()
{
addExpandHeaderStep();
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "1" } }));
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
+ assertCollectionDropdownContains("1");
AddStep("hover collection", () => InputManager.MoveMouseTo(getAddOrRemoveButton(1)));
AddAssert("collection has add button", () => getAddOrRemoveButton(1).IsPresent);
}
@@ -134,7 +131,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
addExpandHeaderStep();
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "1" } }));
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
+ assertCollectionDropdownContains("1");
AddStep("select available beatmap", () => Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps[0]));
AddAssert("button enabled", () => getAddOrRemoveButton(1).Enabled.Value);
@@ -150,14 +148,16 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("select available beatmap", () => Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps[0]));
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "1" } }));
- AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare));
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
+ assertCollectionDropdownContains("1");
- AddStep("add beatmap to collection", () => collectionManager.Collections[0].BeatmapHashes.Add(Beatmap.Value.BeatmapInfo.MD5Hash));
- AddAssert("button is minus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.MinusSquare));
+ assertFirstButtonIs(FontAwesome.Solid.PlusSquare);
- AddStep("remove beatmap from collection", () => collectionManager.Collections[0].BeatmapHashes.Clear());
- AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare));
+ AddStep("add beatmap to collection", () => writeAndRefresh(r => getFirstCollection().BeatmapMD5Hashes.Add(Beatmap.Value.BeatmapInfo.MD5Hash)));
+ assertFirstButtonIs(FontAwesome.Solid.MinusSquare);
+
+ AddStep("remove beatmap from collection", () => writeAndRefresh(r => getFirstCollection().BeatmapMD5Hashes.Clear()));
+ assertFirstButtonIs(FontAwesome.Solid.PlusSquare);
}
[Test]
@@ -167,24 +167,29 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("select available beatmap", () => Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps[0]));
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "1" } }));
- AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare));
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
+ assertCollectionDropdownContains("1");
+ assertFirstButtonIs(FontAwesome.Solid.PlusSquare);
addClickAddOrRemoveButtonStep(1);
- AddAssert("collection contains beatmap", () => collectionManager.Collections[0].BeatmapHashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash));
- AddAssert("button is minus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.MinusSquare));
+ AddAssert("collection contains beatmap", () => getFirstCollection().BeatmapMD5Hashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash));
+ assertFirstButtonIs(FontAwesome.Solid.MinusSquare);
addClickAddOrRemoveButtonStep(1);
- AddAssert("collection does not contain beatmap", () => !collectionManager.Collections[0].BeatmapHashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash));
- AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare));
+ AddAssert("collection does not contain beatmap", () => !getFirstCollection().BeatmapMD5Hashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash));
+ assertFirstButtonIs(FontAwesome.Solid.PlusSquare);
}
[Test]
public void TestManageCollectionsFilterIsNotSelected()
{
+ bool received = false;
+
addExpandHeaderStep();
- AddStep("add collection", () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "1" } }));
+ AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1", new List { "abc" }))));
+ assertCollectionDropdownContains("1");
+
AddStep("select collection", () =>
{
InputManager.MoveMouseTo(getCollectionDropdownItems().ElementAt(1));
@@ -193,21 +198,39 @@ namespace osu.Game.Tests.Visual.SongSelect
addExpandHeaderStep();
+ AddStep("watch for filter requests", () =>
+ {
+ received = false;
+ control.ChildrenOfType().First().RequestFilter = () => received = true;
+ });
+
AddStep("click manage collections filter", () =>
{
InputManager.MoveMouseTo(getCollectionDropdownItems().Last());
InputManager.Click(MouseButton.Left);
});
- AddAssert("collection filter still selected", () => control.CreateCriteria().Collection?.Name.Value == "1");
+ AddAssert("collection filter still selected", () => control.CreateCriteria().CollectionBeatmapMD5Hashes.Any());
+
+ AddAssert("filter request not fired", () => !received);
}
+ private void writeAndRefresh(Action action) => Realm.Write(r =>
+ {
+ action(r);
+ r.Refresh();
+ });
+
+ private BeatmapCollection getFirstCollection() => Realm.Run(r => r.All().First());
+
private void assertCollectionHeaderDisplays(string collectionName, bool shouldDisplay = true)
- => AddAssert($"collection dropdown header displays '{collectionName}'",
- () => shouldDisplay == (control.ChildrenOfType().Single().ChildrenOfType().First().Text == collectionName));
+ => AddUntilStep($"collection dropdown header displays '{collectionName}'",
+ () => shouldDisplay == (control.ChildrenOfType().Single().ChildrenOfType().First().Text == collectionName));
+
+ private void assertFirstButtonIs(IconUsage icon) => AddUntilStep($"button is {icon.Icon.ToString()}", () => getAddOrRemoveButton(1).Icon.Equals(icon));
private void assertCollectionDropdownContains(string collectionName, bool shouldContain = true) =>
- AddAssert($"collection dropdown {(shouldContain ? "contains" : "does not contain")} '{collectionName}'",
+ AddUntilStep($"collection dropdown {(shouldContain ? "contains" : "does not contain")} '{collectionName}'",
// A bit of a roundabout way of going about this, see: https://github.com/ppy/osu-framework/issues/3871 + https://github.com/ppy/osu-framework/issues/3872
() => shouldContain == (getCollectionDropdownItems().Any(i => i.ChildrenOfType().OfType().First().Text == collectionName)));
@@ -216,7 +239,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private void addExpandHeaderStep() => AddStep("expand header", () =>
{
- InputManager.MoveMouseTo(control.ChildrenOfType().Single());
+ InputManager.MoveMouseTo(control.ChildrenOfType().Single());
InputManager.Click(MouseButton.Left);
});
@@ -227,6 +250,6 @@ namespace osu.Game.Tests.Visual.SongSelect
});
private IEnumerable.DropdownMenu.DrawableDropdownMenuItem> getCollectionDropdownItems()
- => control.ChildrenOfType().Single().ChildrenOfType.DropdownMenu.DrawableDropdownMenuItem>();
+ => control.ChildrenOfType().Single().ChildrenOfType.DropdownMenu.DrawableDropdownMenuItem>();
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 159a3b1923..3d8f496c9a 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -10,6 +10,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
using osu.Framework.Screens;
@@ -54,7 +55,7 @@ namespace osu.Game.Tests.Visual.SongSelect
// At a point we have isolated interactive test runs enough, this can likely be removed.
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(Realm);
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, defaultBeatmap = Beatmap.Default));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, defaultBeatmap = Beatmap.Default));
Dependencies.Cache(music = new MusicController());
@@ -282,6 +283,28 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("filter count is 2", () => songSelect.FilterCount == 2);
}
+ [Test]
+ public void TestCarouselSelectionUpdatesOnResume()
+ {
+ addRulesetImportStep(0);
+
+ createSongSelect();
+
+ AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child")));
+ AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
+
+ AddStep("update beatmap", () =>
+ {
+ var selectedBeatmap = Beatmap.Value.BeatmapInfo;
+ var anotherBeatmap = Beatmap.Value.BeatmapSetInfo.Beatmaps.Except(selectedBeatmap.Yield()).First();
+ Beatmap.Value = manager.GetWorkingBeatmap(anotherBeatmap);
+ });
+
+ AddStep("return", () => songSelect.MakeCurrent());
+ AddUntilStep("wait for current", () => songSelect.IsCurrentScreen());
+ AddAssert("carousel updated", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(Beatmap.Value.BeatmapInfo));
+ }
+
[Test]
public void TestAudioResuming()
{
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs
index 05b5c5c0cd..72d78ededb 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
- Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, Scheduler, API));
Dependencies.Cache(Realm);
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs
index 0fa7c5303c..bcbe146456 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs
@@ -21,12 +21,12 @@ namespace osu.Game.Tests.Visual.UserInterface
[TestFixture]
public class TestSceneCursors : OsuManualInputManagerTestScene
{
- private readonly MenuCursorContainer menuCursorContainer;
+ private readonly GlobalCursorDisplay globalCursorDisplay;
private readonly CustomCursorBox[] cursorBoxes = new CustomCursorBox[6];
public TestSceneCursors()
{
- Child = menuCursorContainer = new MenuCursorContainer
+ Child = globalCursorDisplay = new GlobalCursorDisplay
{
RelativeSizeAxes = Axes.Both,
Children = new[]
@@ -96,11 +96,11 @@ namespace osu.Game.Tests.Visual.UserInterface
private void testUserCursor()
{
AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0]));
- AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor));
- AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].Cursor));
+ AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].MenuCursor));
+ AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].MenuCursor));
AddStep("Move out", moveOut);
- AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
- AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
+ AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor));
+ AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
}
///
@@ -111,13 +111,13 @@ namespace osu.Game.Tests.Visual.UserInterface
private void testLocalCursor()
{
AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3]));
- AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
- AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
- AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
- AddAssert("Check global cursor at mouse", () => checkAtMouse(menuCursorContainer.Cursor));
+ AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
+ AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor));
+ AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
+ AddAssert("Check global cursor at mouse", () => checkAtMouse(globalCursorDisplay.MenuCursor));
AddStep("Move out", moveOut);
- AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
- AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
+ AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
+ AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
}
///
@@ -128,12 +128,12 @@ namespace osu.Game.Tests.Visual.UserInterface
private void testUserCursorOverride()
{
AddStep("Move to blue-green boundary", () => InputManager.MoveMouseTo(cursorBoxes[1].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
- AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor));
- AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
- AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor));
+ AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor));
+ AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor));
+ AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor));
AddStep("Move out", moveOut);
- AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].Cursor));
- AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].Cursor));
+ AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].MenuCursor));
+ AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].MenuCursor));
}
///
@@ -143,13 +143,13 @@ namespace osu.Game.Tests.Visual.UserInterface
private void testMultipleLocalCursors()
{
AddStep("Move to yellow-purple boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
- AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
- AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
- AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
- AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor));
+ AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
+ AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor));
+ AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
+ AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor));
AddStep("Move out", moveOut);
- AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
- AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
+ AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
+ AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
}
///
@@ -159,13 +159,13 @@ namespace osu.Game.Tests.Visual.UserInterface
private void testUserOverrideWithLocal()
{
AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10)));
- AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor));
- AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor));
- AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
- AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor));
+ AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor));
+ AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor));
+ AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
+ AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor));
AddStep("Move out", moveOut);
- AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].Cursor));
- AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
+ AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].MenuCursor));
+ AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
}
///
@@ -191,7 +191,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
public bool SmoothTransition;
- public CursorContainer Cursor { get; }
+ public CursorContainer MenuCursor { get; }
public bool ProvidingUserCursor { get; }
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || (SmoothTransition && !ProvidingUserCursor);
@@ -218,7 +218,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Origin = Anchor.Centre,
Text = providesUserCursor ? "User cursor" : "Local cursor"
},
- Cursor = new TestCursorContainer
+ MenuCursor = new TestCursorContainer
{
State = { Value = providesUserCursor ? Visibility.Hidden : Visibility.Visible },
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
index e59914f69a..3beade9d4f 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -37,7 +37,6 @@ namespace osu.Game.Tests.Visual.UserInterface
private readonly ContextMenuContainer contextMenuContainer;
private readonly BeatmapLeaderboard leaderboard;
- private RulesetStore rulesetStore;
private BeatmapManager beatmapManager;
private ScoreManager scoreManager;
@@ -72,8 +71,8 @@ namespace osu.Game.Tests.Visual.UserInterface
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
- dependencies.Cache(rulesetStore = new RealmRulesetStore(Realm));
- dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default));
+ dependencies.Cache(new RealmRulesetStore(Realm));
+ dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get(), () => beatmapManager, LocalStorage, Realm, Scheduler, API));
Dependencies.Cache(Realm);
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs
new file mode 100644
index 0000000000..05ed03f01d
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs
@@ -0,0 +1,258 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions.ObjectExtensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Testing;
+using osu.Framework.Graphics.Cursor;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Graphics.UserInterfaceV2;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Mods;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Mania.Mods;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu.Mods;
+using osuTK.Input;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneModPresetColumn : OsuManualInputManagerTestScene
+ {
+ protected override bool UseFreshStoragePerRun => true;
+
+ private Container content = null!;
+ protected override Container Content => content;
+
+ private RulesetStore rulesets = null!;
+
+ [Cached]
+ private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
+ Dependencies.Cache(Realm);
+
+ base.Content.Add(content = new PopoverContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding(30),
+ });
+ }
+
+ [SetUpSteps]
+ public void SetUpSteps()
+ {
+ AddStep("clear contents", Clear);
+ AddStep("reset storage", () =>
+ {
+ Realm.Write(realm =>
+ {
+ realm.RemoveAll();
+
+ var testPresets = createTestPresets();
+ foreach (var preset in testPresets)
+ preset.Ruleset = realm.Find(preset.Ruleset.ShortName);
+
+ realm.Add(testPresets);
+ });
+ });
+ }
+
+ [Test]
+ public void TestBasicOperation()
+ {
+ AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
+ AddStep("create content", () => Child = new ModPresetColumn
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+ AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3);
+
+ AddStep("change ruleset to mania", () => Ruleset.Value = rulesets.GetRuleset(3));
+ AddUntilStep("1 panel visible", () => this.ChildrenOfType().Count() == 1);
+
+ AddStep("add another mania preset", () => Realm.Write(r => r.Add(new ModPreset
+ {
+ Name = "and another one",
+ Mods = new Mod[]
+ {
+ new ManiaModMirror(),
+ new ManiaModNightcore(),
+ new ManiaModHardRock()
+ },
+ Ruleset = r.Find("mania")
+ })));
+ AddUntilStep("2 panels visible", () => this.ChildrenOfType().Count() == 2);
+
+ AddStep("add another osu! preset", () => Realm.Write(r => r.Add(new ModPreset
+ {
+ Name = "hdhr",
+ Mods = new Mod[]
+ {
+ new OsuModHidden(),
+ new OsuModHardRock()
+ },
+ Ruleset = r.Find("osu")
+ })));
+ AddUntilStep("2 panels visible", () => this.ChildrenOfType().Count() == 2);
+
+ AddStep("remove mania preset", () => Realm.Write(r =>
+ {
+ var toRemove = r.All().Single(preset => preset.Name == "Different ruleset");
+ r.Remove(toRemove);
+ }));
+ AddUntilStep("1 panel visible", () => this.ChildrenOfType().Count() == 1);
+
+ AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
+ AddUntilStep("4 panels visible", () => this.ChildrenOfType().Count() == 4);
+ }
+
+ [Test]
+ public void TestSoftDeleteSupport()
+ {
+ AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
+ AddStep("create content", () => Child = new ModPresetColumn
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+ AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3);
+
+ AddStep("soft delete preset", () => Realm.Write(r =>
+ {
+ var toSoftDelete = r.All().Single(preset => preset.Name == "AR0");
+ toSoftDelete.DeletePending = true;
+ }));
+ AddUntilStep("2 panels visible", () => this.ChildrenOfType().Count() == 2);
+
+ AddStep("soft delete all presets", () => Realm.Write(r =>
+ {
+ foreach (var preset in r.All())
+ preset.DeletePending = true;
+ }));
+ AddUntilStep("no panels visible", () => this.ChildrenOfType().Count() == 0);
+
+ AddStep("undelete preset", () => Realm.Write(r =>
+ {
+ foreach (var preset in r.All())
+ preset.DeletePending = false;
+ }));
+ AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3);
+ }
+
+ [Test]
+ public void TestAddingFlow()
+ {
+ ModPresetColumn modPresetColumn = null!;
+
+ AddStep("clear mods", () => SelectedMods.Value = Array.Empty());
+ AddStep("create content", () => Child = modPresetColumn = new ModPresetColumn
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+
+ AddUntilStep("items loaded", () => modPresetColumn.IsLoaded && modPresetColumn.ItemsLoaded);
+ AddAssert("add preset button disabled", () => !this.ChildrenOfType().Single().Enabled.Value);
+
+ AddStep("set mods", () => SelectedMods.Value = new Mod[] { new OsuModDaycore(), new OsuModClassic() });
+ AddAssert("add preset button enabled", () => this.ChildrenOfType().Single().Enabled.Value);
+
+ AddStep("click add preset button", () =>
+ {
+ InputManager.MoveMouseTo(this.ChildrenOfType().Single());
+ InputManager.Click(MouseButton.Left);
+ });
+
+ OsuPopover? popover = null;
+ AddUntilStep("wait for popover", () => (popover = this.ChildrenOfType().FirstOrDefault()) != null);
+ AddStep("attempt preset creation", () =>
+ {
+ InputManager.MoveMouseTo(popover.ChildrenOfType