Load beatmap content asynchronously in the background (#5133)

Load beatmap content asynchronously in the background

Co-authored-by: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com>
This commit is contained in:
Dean Herbert 2019-07-02 23:37:18 +09:00 committed by GitHub
commit 6bddee5169
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 6 deletions

View File

@ -13,6 +13,7 @@
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Audio;
using osu.Framework.Statistics;
using osu.Game.IO.Serialization;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
@ -32,6 +33,8 @@ public abstract class WorkingBeatmap : IDisposable
protected AudioManager AudioManager { get; }
private static readonly GlobalStatistic<int> total_count = GlobalStatistics.Get<int>(nameof(Beatmaps), $"Total {nameof(WorkingBeatmap)}s");
protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager audioManager)
{
AudioManager = audioManager;
@ -44,11 +47,8 @@ protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager audioManager)
waveform = new RecyclableLazy<Waveform>(GetWaveform);
storyboard = new RecyclableLazy<Storyboard>(GetStoryboard);
skin = new RecyclableLazy<Skin>(GetSkin);
}
~WorkingBeatmap()
{
Dispose(false);
total_count.Value++;
}
protected virtual Track GetVirtualTrack()
@ -150,6 +150,7 @@ public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList<Mod> mods)
public Task<IBeatmap> LoadBeatmapAsync() => (beatmapLoadTask ?? (beatmapLoadTask = Task.Factory.StartNew(() =>
{
// Todo: Handle cancellation during beatmap parsing
var b = GetBeatmap() ?? new Beatmap();
// The original beatmap version needs to be preserved as the database doesn't contain it
@ -161,7 +162,20 @@ public Task<IBeatmap> LoadBeatmapAsync() => (beatmapLoadTask ?? (beatmapLoadTask
return b;
}, beatmapCancellation.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)));
public IBeatmap Beatmap => LoadBeatmapAsync().Result;
public IBeatmap Beatmap
{
get
{
try
{
return LoadBeatmapAsync().Result;
}
catch (TaskCanceledException)
{
return null;
}
}
}
private readonly CancellationTokenSource beatmapCancellation = new CancellationTokenSource();
protected abstract IBeatmap GetBeatmap();
@ -218,15 +232,28 @@ public void Dispose()
GC.SuppressFinalize(this);
}
private bool isDisposed;
protected virtual void Dispose(bool isDisposing)
{
if (isDisposed)
return;
isDisposed = true;
// recycling logic is not here for the time being, as components which use
// retrieved objects from WorkingBeatmap may not hold a reference to the WorkingBeatmap itself.
// this should be fine as each retrieved comopnent do have their own finalizers.
// this should be fine as each retrieved component do have their own finalizers.
// cancelling the beatmap load is safe for now since the retrieval is a synchronous
// operation. if we add an async retrieval method this may need to be reconsidered.
beatmapCancellation.Cancel();
total_count.Value--;
}
~WorkingBeatmap()
{
Dispose(false);
}
#endregion

View File

@ -296,6 +296,8 @@ private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> beatmap)
if (nextBeatmap?.Track != null)
nextBeatmap.Track.Completed += currentTrackCompleted;
beatmap.OldValue?.Dispose();
nextBeatmap?.LoadBeatmapAsync();
}