diff --git a/osu.Game/Beatmaps/IWorkingBeatmap.cs b/osu.Game/Beatmaps/IWorkingBeatmap.cs
index 3bfbbad714..5a8ae45226 100644
--- a/osu.Game/Beatmaps/IWorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/IWorkingBeatmap.cs
@@ -37,12 +37,12 @@ namespace osu.Game.Beatmaps
///
/// Retrieves the which this represents.
///
- IBeatmap Beatmap { get; }
+ IBeatmap? Beatmap { get; }
///
/// Retrieves the background for this .
///
- Texture Background { get; }
+ Texture? Background { get; }
///
/// Retrieves the for the of this .
@@ -57,12 +57,12 @@ namespace osu.Game.Beatmaps
///
/// Retrieves the which this provides.
///
- ISkin Skin { get; }
+ ISkin? Skin { get; }
///
/// Retrieves the which this has loaded.
///
- Track Track { get; }
+ Track? Track { get; }
///
/// Constructs a playable from using the applicable converters for a specific .
@@ -114,7 +114,7 @@ namespace osu.Game.Beatmaps
/// Returns the stream of the file from the given storage path.
///
/// The storage path to the file.
- Stream GetStream(string storagePath);
+ Stream? GetStream(string storagePath);
///
/// Beings loading the contents of this asynchronously.
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index 451b4ccac8..6d39a294c8 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -8,7 +8,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using JetBrains.Annotations;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
@@ -21,6 +20,8 @@ using osu.Game.Rulesets.UI;
using osu.Game.Skinning;
using osu.Game.Storyboards;
+#nullable enable
+
namespace osu.Game.Beatmaps
{
[ExcludeFromDynamicCompile]
@@ -30,28 +31,28 @@ namespace osu.Game.Beatmaps
public readonly BeatmapSetInfo BeatmapSetInfo;
// TODO: remove once the fallback lookup is not required (and access via `working.BeatmapInfo.Metadata` directly).
- public BeatmapMetadata Metadata => BeatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
+ public BeatmapMetadata Metadata => BeatmapInfo.Metadata ?? BeatmapSetInfo.Metadata;
public Waveform Waveform => waveform.Value;
public Storyboard Storyboard => storyboard.Value;
- public Texture Background => GetBackground(); // Texture uses ref counting, so we want to return a new instance every usage.
+ public Texture? Background => GetBackground(); // Texture uses ref counting, so we want to return a new instance every usage.
- public ISkin Skin => skin.Value;
+ public ISkin? Skin => skin.Value;
- private AudioManager audioManager { get; }
+ private AudioManager? audioManager { get; }
- private CancellationTokenSource loadCancellationSource = new CancellationTokenSource();
+ private CancellationTokenSource? loadCancellationSource;
private readonly object beatmapFetchLock = new object();
private readonly Lazy waveform;
private readonly Lazy storyboard;
- private readonly Lazy skin;
- private Track track; // track is not Lazy as we allow transferring and loading multiple times.
+ private readonly Lazy skin;
+ private Track? track; // track is not Lazy as we allow transferring and loading multiple times.
- protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager audioManager)
+ protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager? audioManager)
{
this.audioManager = audioManager;
@@ -60,7 +61,7 @@ namespace osu.Game.Beatmaps
waveform = new Lazy(GetWaveform);
storyboard = new Lazy(GetStoryboard);
- skin = new Lazy(GetSkin);
+ skin = new Lazy(GetSkin);
}
#region Resource getters
@@ -68,9 +69,9 @@ namespace osu.Game.Beatmaps
protected virtual Waveform GetWaveform() => new Waveform(null);
protected virtual Storyboard GetStoryboard() => new Storyboard { BeatmapInfo = BeatmapInfo };
- protected abstract IBeatmap GetBeatmap();
- protected abstract Texture GetBackground();
- protected abstract Track GetBeatmapTrack();
+ protected abstract IBeatmap? GetBeatmap();
+ protected abstract Texture? GetBackground();
+ protected abstract Track? GetBeatmapTrack();
///
/// Creates a new skin instance for this beatmap.
@@ -80,7 +81,7 @@ namespace osu.Game.Beatmaps
/// (e.g. for editing purposes, to avoid state pollution).
/// For standard reading purposes, should always be used directly.
///
- protected internal abstract ISkin GetSkin();
+ protected internal abstract ISkin? GetSkin();
#endregion
@@ -93,7 +94,6 @@ namespace osu.Game.Beatmaps
lock (beatmapFetchLock)
{
loadCancellationSource?.Cancel();
- loadCancellationSource = new CancellationTokenSource();
if (beatmapLoadTask?.IsCompleted != true)
beatmapLoadTask = null;
@@ -130,7 +130,7 @@ namespace osu.Game.Beatmaps
/// across difficulties in the same beatmap set.
///
/// The track to transfer.
- public void TransferTrack([NotNull] Track track) => this.track = track ?? throw new ArgumentNullException(nameof(track));
+ public void TransferTrack(Track track) => this.track = track ?? throw new ArgumentNullException(nameof(track));
///
/// Get the loaded audio track instance. must have first been called.
@@ -143,6 +143,9 @@ namespace osu.Game.Beatmaps
if (!TrackLoaded)
throw new InvalidOperationException($"Cannot access {nameof(Track)} without first calling {nameof(LoadTrack)}.");
+ // Covered by TrackLoaded call above.
+ Debug.Assert(track != null);
+
return track;
}
}
@@ -170,7 +173,7 @@ namespace osu.Game.Beatmaps
break;
}
- return audioManager.Tracks.GetVirtual(length);
+ return audioManager?.Tracks.GetVirtual(length) ?? throw new InvalidOperationException($"Attempted to get virtual track without providing an {nameof(AudioManager)}");
}
#endregion
@@ -179,7 +182,7 @@ namespace osu.Game.Beatmaps
public virtual bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false;
- public IBeatmap Beatmap
+ public IBeatmap? Beatmap
{
get
{
@@ -204,7 +207,7 @@ namespace osu.Game.Beatmaps
}
}
- private Task beatmapLoadTask;
+ private Task? beatmapLoadTask;
private Task loadBeatmapAsync()
{
@@ -222,7 +225,7 @@ namespace osu.Game.Beatmaps
b.BeatmapInfo = BeatmapInfo;
return b;
- }, loadCancellationSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ }, (loadCancellationSource = new CancellationTokenSource()).Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
}
@@ -230,7 +233,7 @@ namespace osu.Game.Beatmaps
#region Playable beatmap
- public IBeatmap GetPlayableBeatmap(IRulesetInfo ruleset, IReadOnlyList mods = null)
+ public IBeatmap GetPlayableBeatmap(IRulesetInfo ruleset, IReadOnlyList? mods = null)
{
try
{
@@ -253,6 +256,9 @@ namespace osu.Game.Beatmaps
if (rulesetInstance == null)
throw new RulesetLoadException("Creating ruleset instance failed when attempting to create playable beatmap.");
+ if (Beatmap == null)
+ throw new InvalidOperationException("Beatmap could not be loaded.");
+
IBeatmapConverter converter = CreateBeatmapConverter(Beatmap, rulesetInstance);
// Check if the beatmap can be converted
@@ -332,7 +338,7 @@ namespace osu.Game.Beatmaps
public override string ToString() => BeatmapInfo.ToString();
- public abstract Stream GetStream(string storagePath);
+ public abstract Stream? GetStream(string storagePath);
IBeatmapInfo IWorkingBeatmap.BeatmapInfo => BeatmapInfo;
diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
index 514551e184..3174754b76 100644
--- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
@@ -180,17 +180,17 @@ namespace osu.Game.Beatmaps
protected override Waveform GetWaveform()
{
if (string.IsNullOrEmpty(Metadata?.AudioFile))
- return null;
+ return base.GetWaveform();
try
{
var trackData = GetStream(BeatmapSetInfo.GetPathForFile(Metadata.AudioFile));
- return trackData == null ? null : new Waveform(trackData);
+ return trackData == null ? base.GetWaveform() : new Waveform(trackData);
}
catch (Exception e)
{
Logger.Error(e, "Waveform failed to load");
- return null;
+ return base.GetWaveform();
}
}
diff --git a/osu.Game/Stores/BeatmapImporter.cs b/osu.Game/Stores/BeatmapImporter.cs
index 8ab6941885..ec0db772de 100644
--- a/osu.Game/Stores/BeatmapImporter.cs
+++ b/osu.Game/Stores/BeatmapImporter.cs
@@ -324,7 +324,7 @@ namespace osu.Game.Stores
protected override IBeatmap GetBeatmap() => beatmap;
protected override Texture? GetBackground() => null;
- protected override Track? GetBeatmapTrack() => null;
+ protected override Track GetBeatmapTrack() => null!;
protected internal override ISkin? GetSkin() => null;
public override Stream? GetStream(string storagePath) => null;
}