1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-13 08:32:57 +08:00

Update model manager and many related classes to get things compiling again

This commit is contained in:
Dean Herbert 2021-12-14 19:47:11 +09:00
parent a3da8dc49d
commit 00e3af3366
34 changed files with 165 additions and 431 deletions

View File

@ -40,7 +40,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using (var importer = new BeatmapImporter(realmFactory, storage))
using (var importer = new BeatmapModelManager(realmFactory, storage))
using (new RulesetStore(realmFactory, storage))
{
ILive<BeatmapSetInfo>? imported;
@ -69,7 +69,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
await LoadOszIntoStore(importer, realmFactory.Context);
@ -81,7 +81,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@ -113,7 +113,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? tempPath = TestResources.GetTestBeatmapForImport();
@ -143,7 +143,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@ -163,7 +163,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -212,7 +212,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -264,7 +264,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -312,7 +312,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -361,7 +361,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@ -394,7 +394,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
var progressNotification = new ImportProgressNotification();
@ -430,7 +430,7 @@ namespace osu.Game.Tests.Database
Interlocked.Increment(ref loggedExceptionCount);
};
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@ -480,7 +480,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@ -528,7 +528,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@ -554,7 +554,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
var metadata = new BeatmapMetadata
@ -600,7 +600,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -617,7 +617,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -653,7 +653,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -695,7 +695,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -746,7 +746,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();

View File

@ -172,17 +172,17 @@ namespace osu.Game.Tests.Online
{
}
protected override BeatmapModelManager CreateBeatmapModelManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, GameHost host)
protected override BeatmapModelManager CreateBeatmapModelManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, BeatmapOnlineLookupQueue onlineLookupQueue)
{
return new TestBeatmapModelManager(this, storage, contextFactory, rulesets, api, host);
return new TestBeatmapModelManager(this, storage, contextFactory, rulesets, onlineLookupQueue);
}
internal class TestBeatmapModelManager : BeatmapModelManager
{
private readonly TestBeatmapManager testBeatmapManager;
public TestBeatmapModelManager(TestBeatmapManager testBeatmapManager, Storage storage, IDatabaseContextFactory databaseContextFactory, RulesetStore rulesetStore, IAPIProvider apiProvider, GameHost gameHost)
: base(storage, databaseContextFactory, rulesetStore, gameHost)
public TestBeatmapModelManager(TestBeatmapManager testBeatmapManager, Storage storage, RealmContextFactory databaseContextFactory, RulesetStore rulesetStore, BeatmapOnlineLookupQueue beatmapOnlineLookupQueue)
: base(databaseContextFactory, storage, beatmapOnlineLookupQueue)
{
this.testBeatmapManager = testBeatmapManager;
}

View File

@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable().First();
InitialBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
OtherBeatmap = importedSet.Beatmaps.Last(b => b.RulesetID == 0);
});

View File

@ -72,7 +72,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable().First();
});
AddStep("load multiplayer", () => LoadScreen(multiplayerComponents = new TestMultiplayerComponents()));
@ -588,7 +588,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("restore beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable().First();
});
AddUntilStep("play started", () => multiplayerComponents.CurrentScreen is SpectatorScreen);

View File

@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable().First();
}
[SetUp]

View File

@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable().First();
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
});
@ -169,7 +169,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void addItemStep(bool expired = false) => AddStep("add item", () => Client.AddPlaylistItem(new MultiplayerPlaylistItem(new PlaylistItem
{
Beatmap = { Value = importedBeatmap },
BeatmapID = importedBeatmap.OnlineID ?? -1,
BeatmapID = importedBeatmap.OnlineID,
Expired = expired,
PlayedAt = DateTimeOffset.Now
})));

View File

@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable().First();
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
});
@ -126,7 +126,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
MultiplayerPlaylistItem item = new MultiplayerPlaylistItem(new PlaylistItem
{
Beatmap = { Value = importedBeatmap },
BeatmapID = importedBeatmap.OnlineID ?? -1,
BeatmapID = importedBeatmap.OnlineID,
});
Client.AddUserPlaylistItem(userId(), item);

View File

@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AvailabilityTracker.SelectedItem.BindTo(selectedItem);
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable().First();
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
selectedItem.Value = new PlaylistItem
{

View File

@ -51,7 +51,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AvailabilityTracker.SelectedItem.BindTo(selectedItem);
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable().First();
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
selectedItem.Value = new PlaylistItem
{

View File

@ -12,7 +12,7 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Models;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
@ -155,7 +155,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Metadata = new BeatmapMetadata
{
Artist = "Artist",
Author = new APIUser { Username = "Creator name here" },
Author = new RealmUser { Username = "Creator name here" },
Title = "Long title used to check background colour",
},
BeatmapSet = new BeatmapSetInfo()

View File

@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable().First();
});
AddStep("load multiplayer", () => LoadScreen(multiplayerComponents = new TestMultiplayerComponents()));

View File

@ -20,7 +20,6 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Stores;
using osu.Game.Tests.Resources;
using osu.Game.Users;
using osuTK;
@ -45,7 +44,7 @@ namespace osu.Game.Tests.Visual.SongSelect
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get<RealmRulesetStore>(), () => beatmapManager, LocalStorage, dependencies.Get<RealmContextFactory>(), Scheduler));
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get<RulesetStore>(), () => beatmapManager, LocalStorage, dependencies.Get<RealmContextFactory>(), Scheduler));
return dependencies;
}

View File

@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{
showMetadataForBeatmap(() =>
{
var allBeatmapSets = manager.GetAllUsableBeatmapSets(IncludedDetails.Minimal);
var allBeatmapSets = manager.GetAllUsableBeatmapSets();
if (allBeatmapSets.Count == 0)
return manager.DefaultBeatmap;

View File

@ -5,10 +5,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Platform;
using osu.Framework.Testing;
@ -24,7 +24,6 @@ using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Stores;
using osu.Game.Tests.Resources;
using osuTK;
using osuTK.Input;
@ -89,7 +88,7 @@ namespace osu.Game.Tests.Visual.UserInterface
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get<RealmRulesetStore>(), () => beatmapManager, LocalStorage, dependencies.Get<RealmContextFactory>(), Scheduler));
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get<RulesetStore>(), () => beatmapManager, LocalStorage, dependencies.Get<RealmContextFactory>(), Scheduler));
beatmapInfo = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).GetResultSafely().Value.Beatmaps[0];

View File

@ -16,7 +16,6 @@ using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.IO;
using osu.Game.IO.Archives;
using osu.Game.Models;
using osu.Game.Online.API;
@ -43,21 +42,18 @@ namespace osu.Game.Beatmaps
public BeatmapManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore<byte[]> gameResources, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false)
{
if (performOnlineLookups)
onlineBeatmapLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
var userResources = new RealmFileStore(contextFactory, storage).Store;
BeatmapTrackStore = audioManager.GetTrackStore(userResources);
beatmapModelManager = CreateBeatmapModelManager(storage, contextFactory, rulesets, api, host);
beatmapModelManager = CreateBeatmapModelManager(storage, contextFactory, rulesets, onlineBeatmapLookupQueue);
workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host);
workingBeatmapCache.BeatmapManager = beatmapModelManager;
beatmapModelManager.WorkingBeatmapCache = workingBeatmapCache;
if (performOnlineLookups)
{
onlineBeatmapLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
beatmapModelManager.OnlineLookupQueue = onlineBeatmapLookupQueue;
}
}
protected virtual WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore<byte[]> resources, IResourceStore<byte[]> storage, WorkingBeatmap defaultBeatmap, GameHost host)
@ -65,8 +61,8 @@ namespace osu.Game.Beatmaps
return new WorkingBeatmapCache(BeatmapTrackStore, audioManager, resources, storage, defaultBeatmap, host);
}
protected virtual BeatmapModelManager CreateBeatmapModelManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, GameHost host) =>
new BeatmapModelManager(storage, contextFactory, rulesets, host);
protected virtual BeatmapModelManager CreateBeatmapModelManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, [CanBeNull] BeatmapOnlineLookupQueue onlineLookupQueue) =>
new BeatmapModelManager(contextFactory, storage, onlineLookupQueue);
/// <summary>
/// Create a new <see cref="WorkingBeatmap"/>.
@ -97,9 +93,9 @@ namespace osu.Game.Beatmaps
}
};
var imported = beatmapModelManager.Import(set).GetResultSafely().Value;
var imported = beatmapModelManager.Import(set).GetResultSafely()?.Value;
return GetWorkingBeatmap(imported.Beatmaps.First());
return GetWorkingBeatmap(imported?.Beatmaps.First());
}
#region Delegation to BeatmapModelManager (methods which previously existed locally).
@ -135,23 +131,21 @@ namespace osu.Game.Beatmaps
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
/// </summary>
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
public List<BeatmapSetInfo> GetAllUsableBeatmapSets(IncludedDetails includes = IncludedDetails.All, bool includeProtected = false) => beatmapModelManager.GetAllUsableBeatmapSets(includes, includeProtected);
public List<BeatmapSetInfo> GetAllUsableBeatmapSets(bool includeProtected = false) => beatmapModelManager.GetAllUsableBeatmapSets(includeProtected);
/// <summary>
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s. Note that files are not populated.
/// </summary>
/// <param name="includes">The level of detail to include in the returned objects.</param>
/// <param name="includeProtected">Whether to include protected (system) beatmaps. These should not be included for gameplay playable use cases.</param>
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
public IEnumerable<BeatmapSetInfo> GetAllUsableBeatmapSetsEnumerable(IncludedDetails includes, bool includeProtected = false) => beatmapModelManager.GetAllUsableBeatmapSetsEnumerable(includes, includeProtected);
public IEnumerable<BeatmapSetInfo> GetAllUsableBeatmapSetsEnumerable(bool includeProtected = false) => beatmapModelManager.GetAllUsableBeatmapSetsEnumerable(includeProtected);
/// <summary>
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="includes">The level of detail to include in the returned objects.</param>
/// <returns>Results from the provided query.</returns>
public IEnumerable<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query, IncludedDetails includes = IncludedDetails.All) => beatmapModelManager.QueryBeatmapSets(query, includes);
public IEnumerable<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query) => beatmapModelManager.QueryBeatmapSets(query);
/// <summary>
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.

View File

@ -3,30 +3,21 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions;
using osu.Framework.Graphics.Textures;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Beatmaps.Formats;
using osu.Game.Database;
using osu.Game.Extensions;
using osu.Game.IO;
using osu.Game.IO.Archives;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
using osu.Game.Skinning;
using osu.Game.Stores;
using Realms;
using Decoder = osu.Game.Beatmaps.Formats.Decoder;
#nullable enable
namespace osu.Game.Beatmaps
{
@ -34,145 +25,65 @@ namespace osu.Game.Beatmaps
/// Handles ef-core storage of beatmaps.
/// </summary>
[ExcludeFromDynamicCompile]
public class BeatmapModelManager : RealmArchiveModelManager<BeatmapSetInfo>
public class BeatmapModelManager : BeatmapImporter
{
/// <summary>
/// Fired when a single difficulty has been hidden.
/// </summary>
public event Action<BeatmapInfo> BeatmapHidden;
public event Action<BeatmapInfo>? BeatmapHidden;
/// <summary>
/// Fired when a single difficulty has been restored.
/// </summary>
public event Action<BeatmapInfo> BeatmapRestored;
/// <summary>
/// An online lookup queue component which handles populating online beatmap metadata.
/// </summary>
public BeatmapOnlineLookupQueue OnlineLookupQueue { private get; set; }
public event Action<BeatmapInfo>? BeatmapRestored;
/// <summary>
/// The game working beatmap cache, used to invalidate entries on changes.
/// </summary>
public IWorkingBeatmapCache WorkingBeatmapCache { private get; set; }
public IWorkingBeatmapCache? WorkingBeatmapCache { private get; set; }
public override IEnumerable<string> HandledExtensions => new[] { ".osz" };
protected override string[] HashableFileTypes => new[] { ".osu" };
private readonly RulesetStore rulesets;
public BeatmapModelManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, GameHost host = null)
: base(storage, contextFactory)
public BeatmapModelManager(RealmContextFactory contextFactory, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null)
: base(contextFactory, storage, onlineLookupQueue)
{
this.rulesets = rulesets;
// beatmaps.BeatmapHidden += b => BeatmapHidden?.Invoke(b);
// beatmaps.BeatmapRestored += b => BeatmapRestored?.Invoke(b);
// beatmaps.ItemRemoved += b => WorkingBeatmapCache?.Invalidate(b);
// beatmaps.ItemUpdated += obj => WorkingBeatmapCache?.Invalidate(obj);
}
protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osz";
protected override async Task Populate(BeatmapSetInfo beatmapSet, ArchiveReader? archive, Realm realm, CancellationToken cancellationToken)
{
if (archive != null)
beatmapSet.Beatmaps.AddRange(createBeatmapDifficulties(beatmapSet.Files));
foreach (BeatmapInfo b in beatmapSet.Beatmaps)
{
// remove metadata from difficulties where it matches the set
if (beatmapSet.Metadata.Equals(b.Metadata))
b.Metadata = null;
b.BeatmapSet = beatmapSet;
}
validateOnlineIds(beatmapSet);
bool hadOnlineIDs = beatmapSet.Beatmaps.Any(b => b.OnlineID > 0);
if (OnlineLookupQueue != null)
await OnlineLookupQueue.UpdateAsync(beatmapSet, cancellationToken).ConfigureAwait(false);
// ensure at least one beatmap was able to retrieve or keep an online ID, else drop the set ID.
if (hadOnlineIDs && !beatmapSet.Beatmaps.Any(b => b.OnlineID > 0))
{
if (beatmapSet.OnlineID != null)
{
beatmapSet.OnlineID = -1;
LogForModel(beatmapSet, "Disassociating beatmap set ID due to loss of all beatmap IDs");
}
}
}
protected override void PreImport(BeatmapSetInfo beatmapSet)
{
if (beatmapSet.Beatmaps.Any(b => b.BaseDifficulty == null))
throw new InvalidOperationException($"Cannot import {nameof(BeatmapInfo)} with null {nameof(BeatmapInfo.BaseDifficulty)}.");
// check if a set already exists with the same online id, delete if it does.
if (beatmapSet.OnlineID != null)
{
var existingSetWithSameOnlineID = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineID == beatmapSet.OnlineID);
if (existingSetWithSameOnlineID != null)
{
Delete(existingSetWithSameOnlineID);
// in order to avoid a unique key constraint, immediately remove the online ID from the previous set.
existingSetWithSameOnlineID.OnlineID = -1;
foreach (var b in existingSetWithSameOnlineID.Beatmaps)
b.OnlineID = -1;
LogForModel(beatmapSet, $"Found existing beatmap set with same OnlineBeatmapSetID ({beatmapSet.OnlineID}). It has been deleted.");
}
}
}
private void validateOnlineIds(BeatmapSetInfo beatmapSet)
{
var beatmapIds = beatmapSet.Beatmaps.Where(b => b.OnlineID.HasValue).Select(b => b.OnlineID).ToList();
// ensure all IDs are unique
if (beatmapIds.GroupBy(b => b).Any(g => g.Count() > 1))
{
LogForModel(beatmapSet, "Found non-unique IDs, resetting...");
resetIds();
return;
}
// find any existing beatmaps in the database that have matching online ids
var existingBeatmaps = QueryBeatmaps(b => beatmapIds.Contains(b.OnlineID)).ToList();
if (existingBeatmaps.Count > 0)
{
// reset the import ids (to force a re-fetch) *unless* they match the candidate CheckForExisting set.
// we can ignore the case where the new ids are contained by the CheckForExisting set as it will either be used (import skipped) or deleted.
var existing = CheckForExisting(beatmapSet);
if (existing == null || existingBeatmaps.Any(b => !existing.Beatmaps.Contains(b)))
{
LogForModel(beatmapSet, "Found existing import with IDs already, resetting...");
resetIds();
}
}
void resetIds() => beatmapSet.Beatmaps.ForEach(b => b.OnlineID = -1);
}
/// <summary>
/// Delete a beatmap difficulty.
/// </summary>
/// <param name="beatmapInfo">The beatmap difficulty to hide.</param>
public void Hide(BeatmapInfo beatmapInfo) => beatmaps.Hide(beatmapInfo);
public void Hide(BeatmapInfo beatmapInfo)
{
using (var realm = ContextFactory.CreateContext())
using (var transaction = realm.BeginWrite())
{
beatmapInfo.Hidden = true;
transaction.Commit();
BeatmapHidden?.Invoke(beatmapInfo);
}
}
/// <summary>
/// Restore a beatmap difficulty.
/// </summary>
/// <param name="beatmapInfo">The beatmap difficulty to restore.</param>
public void Restore(BeatmapInfo beatmapInfo) => beatmaps.Restore(beatmapInfo);
public void Restore(BeatmapInfo beatmapInfo)
{
using (var realm = ContextFactory.CreateContext())
using (var transaction = realm.BeginWrite())
{
beatmapInfo.Hidden = false;
transaction.Commit();
BeatmapRestored?.Invoke(beatmapInfo);
}
}
/// <summary>
/// Saves an <see cref="IBeatmap"/> file against a given <see cref="BeatmapInfo"/>.
@ -180,10 +91,12 @@ namespace osu.Game.Beatmaps
/// <param name="beatmapInfo">The <see cref="BeatmapInfo"/> to save the content against. The file referenced by <see cref="BeatmapInfo.Path"/> will be replaced.</param>
/// <param name="beatmapContent">The <see cref="IBeatmap"/> content to write.</param>
/// <param name="beatmapSkin">The beatmap <see cref="ISkin"/> content to write, null if to be omitted.</param>
public virtual void Save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin beatmapSkin = null)
public virtual void Save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null)
{
var setInfo = beatmapInfo.BeatmapSet;
Debug.Assert(setInfo != null);
// Difficulty settings must be copied first due to the clone in `Beatmap<>.BeatmapInfo_Set`.
// This should hopefully be temporary, assuming said clone is eventually removed.
@ -202,25 +115,29 @@ namespace osu.Game.Beatmaps
stream.Seek(0, SeekOrigin.Begin);
using (ContextFactory.GetForWrite())
using (var realm = ContextFactory.CreateContext())
using (var transaction = realm.BeginWrite())
{
beatmapInfo = setInfo.Beatmaps.Single(b => b.Equals(beatmapInfo));
var metadata = beatmapInfo.Metadata ?? setInfo.Metadata;
// grab the original file (or create a new one if not found).
var fileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase)) ?? new BeatmapSetFileInfo();
var existingFileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase));
if (existingFileInfo != null)
{
DeleteFile(setInfo, existingFileInfo);
}
// metadata may have changed; update the path with the standard format.
beatmapInfo.Path = $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.DifficultyName}].osu".GetValidArchiveContentFilename();
var metadata = beatmapInfo.Metadata;
string filename = $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.DifficultyName}].osu".GetValidArchiveContentFilename();
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
// update existing or populate new file's filename.
fileInfo.Filename = beatmapInfo.Path;
stream.Seek(0, SeekOrigin.Begin);
ReplaceFile(setInfo, fileInfo, stream);
AddFile(setInfo, stream, filename, realm);
transaction.Commit();
}
}
@ -232,100 +149,43 @@ namespace osu.Game.Beatmaps
/// </summary>
/// <param name="query">The query.</param>
/// <returns>The first result for the provided query, or null if no results were found.</returns>
public BeatmapSetInfo QueryBeatmapSet(Expression<Func<BeatmapSetInfo, bool>> query) => beatmaps.ConsumableItems.AsNoTracking().FirstOrDefault(query);
protected override bool CanSkipImport(BeatmapSetInfo existing, BeatmapSetInfo import)
public BeatmapSetInfo? QueryBeatmapSet(Expression<Func<BeatmapSetInfo, bool>> query)
{
if (!base.CanSkipImport(existing, import))
return false;
return existing.Beatmaps.Any(b => b.OnlineID != null);
}
protected override bool CanReuseExisting(BeatmapSetInfo existing, BeatmapSetInfo import)
{
if (!base.CanReuseExisting(existing, import))
return false;
var existingIds = existing.Beatmaps.Select(b => b.OnlineID).OrderBy(i => i);
var importIds = import.Beatmaps.Select(b => b.OnlineID).OrderBy(i => i);
// force re-import if we are not in a sane state.
return existing.OnlineID == import.OnlineID && existingIds.SequenceEqual(importIds);
using (var context = ContextFactory.CreateContext())
return context.All<BeatmapSetInfo>().FirstOrDefault(query); // TODO: ?.ToLive();
}
/// <summary>
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
/// </summary>
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
public List<BeatmapSetInfo> GetAllUsableBeatmapSets(IncludedDetails includes = IncludedDetails.All, bool includeProtected = false) =>
GetAllUsableBeatmapSetsEnumerable(includes, includeProtected).ToList();
public List<BeatmapSetInfo> GetAllUsableBeatmapSets(bool includeProtected = false) =>
GetAllUsableBeatmapSetsEnumerable(includeProtected).ToList();
/// <summary>
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s. Note that files are not populated.
/// </summary>
/// <param name="includes">The level of detail to include in the returned objects.</param>
/// <param name="includeProtected">Whether to include protected (system) beatmaps. These should not be included for gameplay playable use cases.</param>
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
public IEnumerable<BeatmapSetInfo> GetAllUsableBeatmapSetsEnumerable(IncludedDetails includes, bool includeProtected = false)
public IEnumerable<BeatmapSetInfo> GetAllUsableBeatmapSetsEnumerable(bool includeProtected = false)
{
IQueryable<BeatmapSetInfo> queryable;
switch (includes)
{
case IncludedDetails.Minimal:
queryable = beatmaps.BeatmapSetsOverview;
break;
case IncludedDetails.AllButRuleset:
queryable = beatmaps.BeatmapSetsWithoutRuleset;
break;
case IncludedDetails.AllButFiles:
queryable = beatmaps.BeatmapSetsWithoutFiles;
break;
default:
queryable = beatmaps.ConsumableItems;
break;
}
// AsEnumerable used here to avoid applying the WHERE in sql. When done so, ef core 2.x uses an incorrect ORDER BY
// clause which causes queries to take 5-10x longer.
// TODO: remove if upgrading to EF core 3.x.
return queryable.AsEnumerable().Where(s => !s.DeletePending && (includeProtected || !s.Protected));
using (var context = ContextFactory.CreateContext())
return context.All<BeatmapSetInfo>().Where(b => !b.DeletePending && (includeProtected || !b.Protected));
}
/// <summary>
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="includes">The level of detail to include in the returned objects.</param>
/// <returns>Results from the provided query.</returns>
public IEnumerable<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query, IncludedDetails includes = IncludedDetails.All)
public IEnumerable<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query)
{
IQueryable<BeatmapSetInfo> queryable;
switch (includes)
using (var context = ContextFactory.CreateContext())
{
case IncludedDetails.Minimal:
queryable = beatmaps.BeatmapSetsOverview;
break;
case IncludedDetails.AllButRuleset:
queryable = beatmaps.BeatmapSetsWithoutRuleset;
break;
case IncludedDetails.AllButFiles:
queryable = beatmaps.BeatmapSetsWithoutFiles;
break;
default:
queryable = beatmaps.ConsumableItems;
break;
return context.All<BeatmapSetInfo>()
.Where(b => !b.DeletePending)
.Where(query);
}
return queryable.AsNoTracking().Where(query);
}
/// <summary>
@ -333,145 +193,24 @@ namespace osu.Game.Beatmaps
/// </summary>
/// <param name="query">The query.</param>
/// <returns>The first result for the provided query, or null if no results were found.</returns>
public BeatmapInfo QueryBeatmap(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.Beatmaps.AsNoTracking().FirstOrDefault(query);
public BeatmapInfo? QueryBeatmap(Expression<Func<BeatmapInfo, bool>> query)
{
using (var context = ContextFactory.CreateContext())
return context.All<BeatmapInfo>().FirstOrDefault(query); // TODO: ?.ToLive();
}
/// <summary>
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>Results from the provided query.</returns>
public IQueryable<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.Beatmaps.AsNoTracking().Where(query);
public override string HumanisedModelName => "beatmap";
protected override bool CheckLocalAvailability(BeatmapSetInfo model, IQueryable<BeatmapSetInfo> items)
=> base.CheckLocalAvailability(model, items)
|| (model.OnlineID != null && items.Any(b => b.OnlineID == model.OnlineID));
protected override BeatmapSetInfo CreateModel(ArchiveReader reader)
public IQueryable<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query)
{
// let's make sure there are actually .osu files to import.
string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu", StringComparison.OrdinalIgnoreCase));
if (string.IsNullOrEmpty(mapName))
using (var context = ContextFactory.CreateContext())
{
Logger.Log($"No beatmap files found in the beatmap archive ({reader.Name}).", LoggingTarget.Database);
return null;
return context.All<BeatmapInfo>()
.Where(query);
}
Beatmap beatmap;
using (var stream = new LineBufferedReader(reader.GetStream(mapName)))
beatmap = Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
return new BeatmapSetInfo
{
OnlineID = beatmap.BeatmapInfo.BeatmapSet?.OnlineID,
Metadata = beatmap.Metadata,
DateAdded = DateTimeOffset.UtcNow
};
}
/// <summary>
/// Create all required <see cref="BeatmapInfo"/>s for the provided archive.
/// </summary>
private List<BeatmapInfo> createBeatmapDifficulties(List<BeatmapSetFileInfo> files)
{
var beatmapInfos = new List<BeatmapInfo>();
foreach (var file in files.Where(f => f.Filename.EndsWith(".osu", StringComparison.OrdinalIgnoreCase)))
{
using (var raw = Files.Store.GetStream(file.FileInfo.GetStoragePath()))
using (var ms = new MemoryStream()) // we need a memory stream so we can seek
using (var sr = new LineBufferedReader(ms))
{
raw.CopyTo(ms);
ms.Position = 0;
var decoder = Decoder.GetDecoder<Beatmap>(sr);
IBeatmap beatmap = decoder.Decode(sr);
string hash = ms.ComputeSHA2Hash();
if (beatmapInfos.Any(b => b.Hash == hash))
continue;
beatmap.BeatmapInfo.Path = file.Filename;
beatmap.BeatmapInfo.Hash = hash;
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
var ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
beatmap.BeatmapInfo.Ruleset = ruleset;
// TODO: this should be done in a better place once we actually need to dynamically update it.
beatmap.BeatmapInfo.StarRating = ruleset?.CreateInstance().CreateDifficultyCalculator(new DummyConversionBeatmap(beatmap)).Calculate().StarRating ?? 0;
beatmap.BeatmapInfo.Length = calculateLength(beatmap);
beatmap.BeatmapInfo.BPM = 60000 / beatmap.GetMostCommonBeatLength();
beatmapInfos.Add(beatmap.BeatmapInfo);
}
}
return beatmapInfos;
}
private double calculateLength(IBeatmap b)
{
if (!b.HitObjects.Any())
return 0;
var lastObject = b.HitObjects.Last();
//TODO: this isn't always correct (consider mania where a non-last object may last for longer than the last in the list).
double endTime = lastObject.GetEndTime();
double startTime = b.HitObjects.First().StartTime;
return endTime - startTime;
}
/// <summary>
/// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation.
/// </summary>
private class DummyConversionBeatmap : WorkingBeatmap
{
private readonly IBeatmap beatmap;
public DummyConversionBeatmap(IBeatmap beatmap)
: base(beatmap.BeatmapInfo, null)
{
this.beatmap = beatmap;
}
protected override IBeatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null;
protected override Track GetBeatmapTrack() => null;
protected internal override ISkin GetSkin() => null;
public override Stream GetStream(string storagePath) => null;
}
}
/// <summary>
/// The level of detail to include in database results.
/// </summary>
public enum IncludedDetails
{
/// <summary>
/// Only include beatmap difficulties and set level metadata.
/// </summary>
Minimal,
/// <summary>
/// Include all difficulties, rulesets, difficulty metadata but no files.
/// </summary>
AllButFiles,
/// <summary>
/// Include everything except ruleset. Used for cases where we aren't sure the ruleset is present but still want to consume the beatmap.
/// </summary>
AllButRuleset,
/// <summary>
/// Include everything.
/// </summary>
All
}
}

View File

@ -34,7 +34,7 @@ namespace osu.Game.Beatmaps
public EFBeatmapMetadata Metadata { get; set; }
[NotNull]
public List<BeatmapInfo> Beatmaps { get; } = new List<BeatmapInfo>();
public List<EFBeatmapInfo> Beatmaps { get; } = new List<EFBeatmapInfo>();
public BeatmapOnlineStatus Status { get; set; } = BeatmapOnlineStatus.None;
@ -95,7 +95,7 @@ namespace osu.Game.Beatmaps
#region Implementation of IBeatmapSetInfo
IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => Metadata ?? Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata();
IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => Metadata ?? Beatmaps.FirstOrDefault()?.Metadata ?? new EFBeatmapMetadata();
IEnumerable<IBeatmapInfo> IBeatmapSetInfo.Beatmaps => Beatmaps;
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => Files;

View File

@ -33,7 +33,7 @@ namespace osu.Game.Beatmaps
beatmap.BeatmapInfo.Ruleset = rulesetProvider(beatmap.BeatmapInfo.RulesetID).RulesetInfo;
if (beatmapId.HasValue)
beatmap.BeatmapInfo.OnlineID = beatmapId;
beatmap.BeatmapInfo.OnlineID = beatmapId.Value;
}
private static Beatmap readFromFile(string filename)

View File

@ -11,6 +11,7 @@ using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Beatmaps.Timing;
using osu.Game.IO;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects.Legacy;
namespace osu.Game.Beatmaps.Formats
@ -141,7 +142,8 @@ namespace osu.Game.Beatmaps.Formats
break;
case @"Mode":
beatmap.BeatmapInfo.RulesetID = Parsing.ParseInt(pair.Value);
// TODO: ha ha ha.
beatmap.BeatmapInfo.Ruleset = new RulesetInfo(Parsing.ParseInt(pair.Value), "some ruleset", "wangs", true /* probably not */);
switch (beatmap.BeatmapInfo.RulesetID)
{

View File

@ -5,13 +5,14 @@
using System.IO;
using osu.Game.IO.Archives;
using osu.Game.Stores;
using osu.Game.Utils;
using SharpCompress.Common;
namespace osu.Game.Database
{
/// <summary>
/// An encapsulated import task to be imported to an <see cref="ArchiveModelManager{TModel,TFileModel}"/>.
/// An encapsulated import task to be imported to an <see cref="RealmArchiveModelManager{TModel}"/>.
/// </summary>
public class ImportTask
{

View File

@ -71,7 +71,7 @@ namespace osu.Game.Overlays
beatmaps.ItemUpdated += beatmapUpdated;
beatmaps.ItemRemoved += beatmapRemoved;
beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets(IncludedDetails.Minimal, true).OrderBy(_ => RNG.Next()));
beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets(true).OrderBy(_ => RNG.Next()));
// Todo: These binds really shouldn't be here, but are unlikely to cause any issues for now.
// They are placed here for now since some tests rely on setting the beatmap _and_ their hierarchies inside their load(), which runs before the MusicController's load().

View File

@ -6,14 +6,14 @@ using System.Linq;
using osu.Framework.IO.Stores;
using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.Rulesets;
using osu.Game.Scoring.Legacy;
using osu.Game.Stores;
namespace osu.Game.Scoring
{
public class LegacyDatabasedScore : Score
{
public LegacyDatabasedScore(ScoreInfo score, RealmRulesetStore rulesets, BeatmapManager beatmaps, IResourceStore<byte[]> store)
public LegacyDatabasedScore(ScoreInfo score, RulesetStore rulesets, BeatmapManager beatmaps, IResourceStore<byte[]> store)
{
ScoreInfo = score;

View File

@ -80,17 +80,9 @@ namespace osu.Game.Scoring
public double? PP { get; set; }
public RealmBeatmap Beatmap { get; set; } = null!;
public BeatmapInfo Beatmap { get; set; } = null!;
public BeatmapInfo BeatmapInfo
{
get => new BeatmapInfo();
// .. todo
// ReSharper disable once ValueParameterNotUsed
set => Beatmap = new RealmBeatmap(new RealmRuleset("osu", "osu!", "wangs", 0), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
}
public RealmRuleset Ruleset { get; set; } = null!;
public RulesetInfo Ruleset { get; set; } = null!;
[Ignored]
public Dictionary<HitResult, int> Statistics
@ -132,7 +124,13 @@ namespace osu.Game.Scoring
private Mod[]? mods;
public int BeatmapInfoID => BeatmapInfo.ID;
public Guid BeatmapInfoID => Beatmap.ID;
public BeatmapInfo BeatmapInfo
{
get => Beatmap;
set => Beatmap = value;
}
public int UserID => RealmUser.OnlineID;

View File

@ -20,7 +20,6 @@ using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Stores;
namespace osu.Game.Scoring
{

View File

@ -11,6 +11,7 @@ using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.IO.Archives;
using osu.Game.Rulesets;
using osu.Game.Scoring.Legacy;
using osu.Game.Stores;
using Realms;
@ -25,10 +26,10 @@ namespace osu.Game.Scoring
protected override string[] HashableFileTypes => new[] { ".osr" };
private readonly RealmRulesetStore rulesets;
private readonly RulesetStore rulesets;
private readonly Func<BeatmapManager> beatmaps;
public ScoreModelManager(RealmRulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, RealmContextFactory contextFactory)
public ScoreModelManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, RealmContextFactory contextFactory)
: base(storage, contextFactory)
{
this.rulesets = rulesets;

View File

@ -95,7 +95,7 @@ namespace osu.Game.Screens.Menu
// if the user has requested not to play theme music, we should attempt to find a random beatmap from their collection.
if (!MenuMusic.Value)
{
var sets = beatmaps.GetAllUsableBeatmapSets(IncludedDetails.Minimal);
var sets = beatmaps.GetAllUsableBeatmapSets();
if (sets.Count > 0)
{
@ -125,7 +125,7 @@ namespace osu.Game.Screens.Menu
bool loadThemedIntro()
{
setInfo = beatmaps.QueryBeatmapSets(b => b.Hash == BeatmapHash, IncludedDetails.AllButRuleset).FirstOrDefault();
setInfo = beatmaps.QueryBeatmapSets(b => b.Hash == BeatmapHash).FirstOrDefault();
if (setInfo == null)
return false;

View File

@ -27,7 +27,7 @@ namespace osu.Game.Screens.Ranking
protected override APIRequest FetchScores(Action<IEnumerable<ScoreInfo>> scoresCallback)
{
if (Score.BeatmapInfo.OnlineID == null || Score.BeatmapInfo.Status <= BeatmapOnlineStatus.Pending)
if (Score.BeatmapInfo.OnlineID <= 0 || Score.BeatmapInfo.Status <= BeatmapOnlineStatus.Pending)
return null;
getScoreRequest = new GetScoresRequest(Score.BeatmapInfo, Score.Ruleset);

View File

@ -182,7 +182,7 @@ namespace osu.Game.Screens.Select
loadBeatmapSets(GetLoadableBeatmaps());
}
protected virtual IEnumerable<BeatmapSetInfo> GetLoadableBeatmaps() => beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.AllButFiles);
protected virtual IEnumerable<BeatmapSetInfo> GetLoadableBeatmaps() => beatmaps.GetAllUsableBeatmapSetsEnumerable();
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() =>
{

View File

@ -61,7 +61,11 @@ namespace osu.Game.Screens.Select.Carousel
[BackgroundDependencyLoader(true)]
private void load(BeatmapSetOverlay beatmapOverlay)
{
restoreHiddenRequested = s => s.Beatmaps.ForEach(manager.Restore);
restoreHiddenRequested = s =>
{
foreach (var b in s.Beatmaps)
manager.Restore(b);
};
if (beatmapOverlay != null)
viewDetails = beatmapOverlay.FetchAndShowBeatmapSet;
@ -214,8 +218,8 @@ namespace osu.Game.Screens.Select.Carousel
if (Item.State.Value == CarouselItemState.NotSelected)
items.Add(new OsuMenuItem("Expand", MenuItemType.Highlighted, () => Item.State.Value = CarouselItemState.Selected));
if (beatmapSet.OnlineID != null && viewDetails != null)
items.Add(new OsuMenuItem("Details...", MenuItemType.Standard, () => viewDetails(beatmapSet.OnlineID.Value)));
if (beatmapSet.OnlineID > 0 && viewDetails != null)
items.Add(new OsuMenuItem("Details...", MenuItemType.Standard, () => viewDetails(beatmapSet.OnlineID)));
if (collectionManager != null)
{

View File

@ -295,7 +295,7 @@ namespace osu.Game.Screens.Select
Schedule(() =>
{
// if we have no beatmaps, let's prompt the user to import from over a stable install if he has one.
if (!beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.Minimal).Any() && DisplayStableImportPrompt)
if (!beatmaps.GetAllUsableBeatmapSetsEnumerable().Any() && DisplayStableImportPrompt)
{
dialogOverlay.Push(new ImportFromStablePopup(() =>
{

View File

@ -34,7 +34,7 @@ namespace osu.Game.Stores
/// Handles the storage and retrieval of Beatmaps/WorkingBeatmaps.
/// </summary>
[ExcludeFromDynamicCompile]
public class BeatmapImporter : RealmArchiveModelImporter<BeatmapSetInfo>, IDisposable
public abstract class BeatmapImporter : RealmArchiveModelManager<BeatmapSetInfo>, IDisposable
{
public override IEnumerable<string> HandledExtensions => new[] { ".osz" };
@ -45,7 +45,7 @@ namespace osu.Game.Stores
private readonly BeatmapOnlineLookupQueue? onlineLookupQueue;
public BeatmapImporter(RealmContextFactory contextFactory, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null)
protected BeatmapImporter(RealmContextFactory contextFactory, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null)
: base(storage, contextFactory)
{
this.onlineLookupQueue = onlineLookupQueue;

View File

@ -10,8 +10,8 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.Platform;
using osu.Game.IO;
using osu.Game.Screens.Play;
using osu.Game.Stores;
namespace osu.Game.Storyboards.Drawables
{
@ -76,7 +76,7 @@ namespace osu.Game.Storyboards.Drawables
}
[BackgroundDependencyLoader(true)]
private void load(FileStore fileStore, GameplayClock clock, CancellationToken? cancellationToken, GameHost host)
private void load(RealmFileStore fileStore, GameplayClock clock, CancellationToken? cancellationToken, GameHost host)
{
if (clock != null)
Clock = clock;

View File

@ -32,14 +32,12 @@ namespace osu.Game.Tests.Beatmaps
HitObjects = baseBeatmap.HitObjects;
BeatmapInfo.Ruleset = ruleset;
BeatmapInfo.RulesetID = ruleset.ID ?? 0;
BeatmapInfo.Length = 75000;
BeatmapInfo.OnlineInfo = new APIBeatmap();
BeatmapInfo.OnlineID = Interlocked.Increment(ref onlineBeatmapID);
Debug.Assert(BeatmapInfo.BeatmapSet != null);
BeatmapInfo.BeatmapSet.Metadata = BeatmapInfo.Metadata;
BeatmapInfo.BeatmapSet.Beatmaps.Add(BeatmapInfo);
BeatmapInfo.BeatmapSet.OnlineID = Interlocked.Increment(ref onlineSetID);
}

View File

@ -122,9 +122,9 @@ namespace osu.Game.Tests.Visual
this.testBeatmap = testBeatmap;
}
protected override BeatmapModelManager CreateBeatmapModelManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, GameHost host)
protected override BeatmapModelManager CreateBeatmapModelManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, BeatmapOnlineLookupQueue onlineLookupQueue)
{
return new TestBeatmapModelManager(storage, contextFactory, rulesets, api, host);
return new TestBeatmapModelManager(storage, contextFactory, rulesets, onlineLookupQueue);
}
protected override WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore<byte[]> resources, IResourceStore<byte[]> storage, WorkingBeatmap defaultBeatmap, GameHost host)
@ -148,8 +148,8 @@ namespace osu.Game.Tests.Visual
internal class TestBeatmapModelManager : BeatmapModelManager
{
public TestBeatmapModelManager(Storage storage, IDatabaseContextFactory databaseContextFactory, RulesetStore rulesetStore, IAPIProvider apiProvider, GameHost gameHost)
: base(storage, databaseContextFactory, rulesetStore, gameHost)
public TestBeatmapModelManager(Storage storage, RealmContextFactory databaseContextFactory, RulesetStore rulesetStore, BeatmapOnlineLookupQueue beatmapOnlineLookupQueue)
: base(databaseContextFactory, storage, beatmapOnlineLookupQueue)
{
}