diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 6542866936..5651d07566 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -246,6 +246,12 @@ public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap
if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
return DefaultBeatmap;
+ if (beatmapInfo.BeatmapSet.Files == null)
+ {
+ var info = beatmapInfo;
+ beatmapInfo = QueryBeatmap(b => b.ID == info.ID);
+ }
+
lock (workingCache)
{
var working = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID);
@@ -287,13 +293,34 @@ protected override bool CanUndelete(BeatmapSetInfo existing, BeatmapSetInfo impo
/// Returns a list of all usable s.
///
/// A list of available .
- public List GetAllUsableBeatmapSets() => GetAllUsableBeatmapSetsEnumerable().ToList();
+ public List GetAllUsableBeatmapSets(IncludedDetails includes = IncludedDetails.All) => GetAllUsableBeatmapSetsEnumerable(includes).ToList();
///
- /// Returns a list of all usable s.
+ /// Returns a list of all usable s. Note that files are not populated.
///
+ /// The level of detail to include in the returned objects.
/// A list of available .
- public IQueryable GetAllUsableBeatmapSetsEnumerable() => beatmaps.ConsumableItems.Where(s => !s.DeletePending && !s.Protected);
+ public IQueryable GetAllUsableBeatmapSetsEnumerable(IncludedDetails includes)
+ {
+ IQueryable queryable;
+
+ switch (includes)
+ {
+ case IncludedDetails.Minimal:
+ queryable = beatmaps.BeatmapSetsOverview;
+ break;
+
+ case IncludedDetails.AllButFiles:
+ queryable = beatmaps.BeatmapSetsWithoutFiles;
+ break;
+
+ default:
+ queryable = beatmaps.ConsumableItems;
+ break;
+ }
+
+ return queryable.Where(s => !s.DeletePending && !s.Protected);
+ }
///
/// Perform a lookup query on available s.
@@ -482,4 +509,25 @@ void fail(Exception e)
}
}
}
+
+ ///
+ /// The level of detail to include in database results.
+ ///
+ public enum IncludedDetails
+ {
+ ///
+ /// Only include beatmap difficulties and set level metadata.
+ ///
+ Minimal,
+
+ ///
+ /// Include all difficulties, rulesets, difficulty metadata but no files.
+ ///
+ AllButFiles,
+
+ ///
+ /// Include everything.
+ ///
+ All
+ }
}
diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs
index a2279fdb14..642bafd2ac 100644
--- a/osu.Game/Beatmaps/BeatmapStore.cs
+++ b/osu.Game/Beatmaps/BeatmapStore.cs
@@ -87,6 +87,18 @@ protected override void Purge(List items, OsuDbContext context)
base.Purge(items, context);
}
+ public IQueryable BeatmapSetsOverview => ContextFactory.Get().BeatmapSetInfo
+ .Include(s => s.Metadata)
+ .Include(s => s.Beatmaps)
+ .AsNoTracking();
+
+ public IQueryable BeatmapSetsWithoutFiles => ContextFactory.Get().BeatmapSetInfo
+ .Include(s => s.Metadata)
+ .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset)
+ .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
+ .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
+ .AsNoTracking();
+
public IQueryable Beatmaps =>
ContextFactory.Get().BeatmapInfo
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index 6d269aa944..c872f82b32 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -66,7 +66,7 @@ private void load()
beatmaps.ItemAdded += handleBeatmapAdded;
beatmaps.ItemRemoved += handleBeatmapRemoved;
- beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next()));
+ beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets(IncludedDetails.Minimal).OrderBy(_ => RNG.Next()));
}
protected override void LoadComplete()
diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs
index 26455b1dbd..d2296573a6 100644
--- a/osu.Game/Screens/Menu/IntroScreen.cs
+++ b/osu.Game/Screens/Menu/IntroScreen.cs
@@ -73,7 +73,7 @@ private void load(OsuConfigManager config, SkinManager skinManager, BeatmapManag
if (!MenuMusic.Value)
{
- var sets = beatmaps.GetAllUsableBeatmapSets();
+ var sets = beatmaps.GetAllUsableBeatmapSets(IncludedDetails.Minimal);
if (sets.Count > 0)
setInfo = beatmaps.QueryBeatmapSet(s => s.ID == sets[RNG.Next(0, sets.Count - 1)].ID);
}
diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index f989ab2787..5a4a03662a 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -169,7 +169,7 @@ private void load(OsuConfigManager config)
loadBeatmapSets(GetLoadableBeatmaps());
}
- protected virtual IEnumerable GetLoadableBeatmaps() => beatmaps.GetAllUsableBeatmapSetsEnumerable();
+ protected virtual IEnumerable GetLoadableBeatmaps() => beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.AllButFiles);
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() =>
{
diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs
index 0d07a335cf..c07465ca44 100644
--- a/osu.Game/Screens/Select/SongSelect.cs
+++ b/osu.Game/Screens/Select/SongSelect.cs
@@ -286,7 +286,7 @@ private void load(AudioManager audio, DialogOverlay dialog, OsuColour colours, S
Schedule(() =>
{
// if we have no beatmaps but osu-stable is found, let's prompt the user to import.
- if (!beatmaps.GetAllUsableBeatmapSetsEnumerable().Any() && beatmaps.StableInstallationAvailable)
+ if (!beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.Minimal).Any() && beatmaps.StableInstallationAvailable)
{
dialogOverlay.Push(new ImportFromStablePopup(() =>
{