diff --git a/osu.Android.props b/osu.Android.props
index b2e3b32916..b296c114e9 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,10 +52,10 @@
-
+
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs
index d4c2c0f0af..e345e03c96 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs
@@ -29,7 +29,13 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor
protected CatchSelectionBlueprintTestScene()
{
- EditorBeatmap = new EditorBeatmap(new CatchBeatmap()) { Difficulty = { CircleSize = 0 } };
+ EditorBeatmap = new EditorBeatmap(new CatchBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new CatchRuleset().RulesetInfo,
+ }
+ }) { Difficulty = { CircleSize = 0 } };
EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint
{
BeatLength = 100
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs
index 5ccb191a9b..50be13c4e0 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs
@@ -29,7 +29,13 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo();
[Cached(typeof(EditorBeatmap))]
- private EditorBeatmap editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition()));
+ private EditorBeatmap editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition())
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new ManiaRuleset().RulesetInfo
+ }
+ });
private readonly ManiaBeatSnapGrid beatSnapGrid;
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
index a30e09cd29..5dd7c23ab6 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
@@ -31,10 +31,10 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
{
AddStep("setup compose screen", () =>
{
- var editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }))
+ var editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })
{
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
- };
+ });
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs
index 01d80881fa..9788dfe844 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs
@@ -203,10 +203,10 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
{
InternalChildren = new Drawable[]
{
- EditorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }))
+ EditorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })
{
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo }
- },
+ }),
Composer = new ManiaHitObjectComposer(new ManiaRuleset())
};
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs
index ef43c3a696..c770e2d96f 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs
@@ -40,7 +40,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
public TestSceneOsuDistanceSnapGrid()
{
- editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo
+ }
+ });
}
[SetUp]
diff --git a/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs b/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs
index db4a6eb50b..6c76da7925 100644
--- a/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs
+++ b/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs
@@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Osu.Statistics
pointGrid.Content = points;
- if (score.HitEvents == null || score.HitEvents.Count == 0)
+ if (score.HitEvents.Count == 0)
return;
// Todo: This should probably not be done like this.
diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs
index 626537053a..55eb2fa66b 100644
--- a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs
@@ -40,10 +40,10 @@ namespace osu.Game.Rulesets.Taiko.Tests.Editor
{
InternalChildren = new Drawable[]
{
- EditorBeatmap = new EditorBeatmap(new TaikoBeatmap())
+ EditorBeatmap = new EditorBeatmap(new TaikoBeatmap
{
BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo }
- },
+ }),
new TaikoHitObjectComposer(new TaikoRuleset())
};
diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs
index 9b2e9fedc5..613874b7d6 100644
--- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs
@@ -191,6 +191,9 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
protected override Beatmap CreateBeatmap() => new TaikoBeatmap();
+ // Important to note that this is subclassing a realm object.
+ // Realm doesn't allow this, but for now this can work since we aren't (in theory?) persisting this to the database.
+ // It is only used during beatmap conversion and processing.
internal class TaikoMultiplierAppliedDifficulty : BeatmapDifficulty
{
public TaikoMultiplierAppliedDifficulty(IBeatmapDifficultyInfo difficulty)
@@ -205,6 +208,8 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
#region Overrides of BeatmapDifficulty
+ public override BeatmapDifficulty Clone() => new TaikoMultiplierAppliedDifficulty(this);
+
public override void CopyTo(BeatmapDifficulty other)
{
base.CopyTo(other);
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
index 677aaf6f78..6ec14e6351 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
@@ -117,7 +117,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(string.Empty, metadata.Source);
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags);
Assert.AreEqual(557821, beatmapInfo.OnlineID);
- Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineID);
+ Assert.AreEqual(241526, beatmapInfo.BeatmapSet?.OnlineID);
}
}
diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
index bfd6ff0314..06ed638e0a 100644
--- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
{
var beatmap = decodeAsJson(normal);
var meta = beatmap.BeatmapInfo.Metadata;
- Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineID);
+ Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet?.OnlineID);
Assert.AreEqual("Soleily", meta.Artist);
Assert.AreEqual("Soleily", meta.ArtistUnicode);
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
diff --git a/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs b/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs
new file mode 100644
index 0000000000..44f6943871
--- /dev/null
+++ b/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs
@@ -0,0 +1,86 @@
+// 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.Threading;
+using System.Threading.Tasks;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Game.Beatmaps;
+using osu.Game.Database;
+using osu.Game.Tests.Database;
+using osu.Game.Tests.Resources;
+
+namespace osu.Game.Tests.Beatmaps.IO
+{
+ public static class BeatmapImportHelper
+ {
+ public static async Task LoadQuickOszIntoOsu(OsuGameBase osu)
+ {
+ string temp = TestResources.GetQuickTestBeatmapForImport();
+
+ var manager = osu.Dependencies.Get();
+
+ var importedSet = await manager.Import(new ImportTask(temp)).ConfigureAwait(false);
+
+ Debug.Assert(importedSet != null);
+
+ ensureLoaded(osu);
+
+ waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
+
+ return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.ID);
+ }
+
+ public static async Task LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
+ {
+ string temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
+
+ var manager = osu.Dependencies.Get();
+
+ var importedSet = await manager.Import(new ImportTask(temp)).ConfigureAwait(false);
+
+ Debug.Assert(importedSet != null);
+
+ ensureLoaded(osu);
+
+ waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
+
+ return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.ID);
+ }
+
+ private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)
+ {
+ var realmContextFactory = osu.Dependencies.Get();
+
+ using (var realm = realmContextFactory.CreateContext())
+ BeatmapImporterTests.EnsureLoaded(realm, timeout);
+
+ // TODO: add back some extra checks outside of the realm ones?
+ // var set = queryBeatmapSets().First();
+ // foreach (BeatmapInfo b in set.Beatmaps)
+ // Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID));
+ // Assert.IsTrue(set.Beatmaps.Count > 0);
+ // var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
+ // Assert.IsTrue(beatmap?.HitObjects.Any() == true);
+ // beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap;
+ // Assert.IsTrue(beatmap?.HitObjects.Any() == true);
+ // beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap;
+ // Assert.IsTrue(beatmap?.HitObjects.Any() == true);
+ // beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap;
+ // Assert.IsTrue(beatmap?.HitObjects.Any() == true);
+ }
+
+ private static void waitForOrAssert(Func result, string failureMessage, int timeout = 60000)
+ {
+ Task task = Task.Run(() =>
+ {
+ while (!result()) Thread.Sleep(200);
+ });
+
+ Assert.IsTrue(task.Wait(timeout), failureMessage);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
deleted file mode 100644
index c02141bf9f..0000000000
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ /dev/null
@@ -1,1106 +0,0 @@
-// 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.IO;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using NUnit.Framework;
-using osu.Framework.Platform;
-using osu.Game.IPC;
-using osu.Framework.Allocation;
-using osu.Framework.Extensions;
-using osu.Framework.Extensions.ObjectExtensions;
-using osu.Framework.Logging;
-using osu.Game.Beatmaps;
-using osu.Game.Database;
-using osu.Game.Extensions;
-using osu.Game.IO;
-using osu.Game.Online.API.Requests.Responses;
-using osu.Game.Overlays.Notifications;
-using osu.Game.Rulesets.Osu;
-using osu.Game.Rulesets.Osu.Objects;
-using osu.Game.Scoring;
-using osu.Game.Tests.Resources;
-using osu.Game.Tests.Scores.IO;
-using SharpCompress.Archives;
-using SharpCompress.Archives.Zip;
-using SharpCompress.Common;
-using SharpCompress.Writers.Zip;
-using FileInfo = System.IO.FileInfo;
-
-namespace osu.Game.Tests.Beatmaps.IO
-{
- [TestFixture]
- public class ImportBeatmapTest : ImportTest
- {
- [Test]
- public async Task TestImportWhenClosed()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- await LoadOszIntoOsu(LoadOsuIntoHost(host));
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportThenDelete()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- var imported = await LoadOszIntoOsu(osu);
-
- deleteBeatmapSet(imported, osu);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportThenDeleteFromStream()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- string tempPath = TestResources.GetTestBeatmapForImport();
-
- var manager = osu.Dependencies.Get();
-
- ILive importedSet;
-
- using (var stream = File.OpenRead(tempPath))
- {
- importedSet = await manager.Import(new ImportTask(stream, Path.GetFileName(tempPath)));
- await ensureLoaded(osu);
- }
-
- Assert.IsTrue(File.Exists(tempPath), "Stream source file somehow went missing");
- File.Delete(tempPath);
-
- var imported = manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.Value.ID);
-
- deleteBeatmapSet(imported, osu);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportThenImport()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- var imported = await LoadOszIntoOsu(osu);
- var importedSecondTime = await LoadOszIntoOsu(osu);
-
- // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
- Assert.IsTrue(imported.ID == importedSecondTime.ID);
- Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
-
- checkBeatmapSetCount(osu, 1);
- checkSingleReferencedFileCount(osu, 18);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportThenImportWithReZip()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- string extractedFolder = $"{temp}_extracted";
- Directory.CreateDirectory(extractedFolder);
-
- try
- {
- var imported = await LoadOszIntoOsu(osu);
-
- string hashBefore = hashFile(temp);
-
- using (var zip = ZipArchive.Open(temp))
- zip.WriteToDirectory(extractedFolder);
-
- using (var zip = ZipArchive.Create())
- {
- zip.AddAllFromDirectory(extractedFolder);
- zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
- }
-
- // zip files differ because different compression or encoder.
- Assert.AreNotEqual(hashBefore, hashFile(temp));
-
- var importedSecondTime = await osu.Dependencies.Get().Import(new ImportTask(temp));
-
- await ensureLoaded(osu);
-
- // but contents doesn't, so existing should still be used.
- Assert.IsTrue(imported.ID == importedSecondTime.Value.ID);
- Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Value.Beatmaps.First().ID);
- }
- finally
- {
- Directory.Delete(extractedFolder, true);
- }
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportThenImportWithChangedHashedFile()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- string extractedFolder = $"{temp}_extracted";
- Directory.CreateDirectory(extractedFolder);
-
- try
- {
- var imported = await LoadOszIntoOsu(osu);
-
- await createScoreForBeatmap(osu, imported.Beatmaps.First());
-
- using (var zip = ZipArchive.Open(temp))
- zip.WriteToDirectory(extractedFolder);
-
- // arbitrary write to hashed file
- // this triggers the special BeatmapManager.PreImport deletion/replacement flow.
- using (var sw = new FileInfo(Directory.GetFiles(extractedFolder, "*.osu").First()).AppendText())
- await sw.WriteLineAsync("// changed");
-
- using (var zip = ZipArchive.Create())
- {
- zip.AddAllFromDirectory(extractedFolder);
- zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
- }
-
- var importedSecondTime = await osu.Dependencies.Get().Import(new ImportTask(temp));
-
- await ensureLoaded(osu);
-
- // check the newly "imported" beatmap is not the original.
- Assert.IsTrue(imported.ID != importedSecondTime.Value.ID);
- Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.Value.Beatmaps.First().ID);
- }
- finally
- {
- Directory.Delete(extractedFolder, true);
- }
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- [Ignore("intentionally broken by import optimisations")]
- public async Task TestImportThenImportWithChangedFile()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- string extractedFolder = $"{temp}_extracted";
- Directory.CreateDirectory(extractedFolder);
-
- try
- {
- var imported = await LoadOszIntoOsu(osu);
-
- using (var zip = ZipArchive.Open(temp))
- zip.WriteToDirectory(extractedFolder);
-
- // arbitrary write to non-hashed file
- using (var sw = new FileInfo(Directory.GetFiles(extractedFolder, "*.mp3").First()).AppendText())
- await sw.WriteLineAsync("text");
-
- using (var zip = ZipArchive.Create())
- {
- zip.AddAllFromDirectory(extractedFolder);
- zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
- }
-
- var importedSecondTime = await osu.Dependencies.Get().Import(new ImportTask(temp));
-
- await ensureLoaded(osu);
-
- // check the newly "imported" beatmap is not the original.
- Assert.IsTrue(imported.ID != importedSecondTime.Value.ID);
- Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.Value.Beatmaps.First().ID);
- }
- finally
- {
- Directory.Delete(extractedFolder, true);
- }
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportThenImportWithDifferentFilename()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- string extractedFolder = $"{temp}_extracted";
- Directory.CreateDirectory(extractedFolder);
-
- try
- {
- var imported = await LoadOszIntoOsu(osu);
-
- using (var zip = ZipArchive.Open(temp))
- zip.WriteToDirectory(extractedFolder);
-
- // change filename
- var firstFile = new FileInfo(Directory.GetFiles(extractedFolder).First());
- firstFile.MoveTo(Path.Combine(firstFile.DirectoryName.AsNonNull(), $"{firstFile.Name}-changed{firstFile.Extension}"));
-
- using (var zip = ZipArchive.Create())
- {
- zip.AddAllFromDirectory(extractedFolder);
- zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
- }
-
- var importedSecondTime = await osu.Dependencies.Get().Import(new ImportTask(temp));
-
- await ensureLoaded(osu);
-
- // check the newly "imported" beatmap is not the original.
- Assert.IsTrue(imported.ID != importedSecondTime.Value.ID);
- Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.Value.Beatmaps.First().ID);
- }
- finally
- {
- Directory.Delete(extractedFolder, true);
- }
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- [Ignore("intentionally broken by import optimisations")]
- public async Task TestImportCorruptThenImport()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- var imported = await LoadOszIntoOsu(osu);
-
- var firstFile = imported.Files.First();
-
- var files = osu.Dependencies.Get();
-
- long originalLength;
- using (var stream = files.Storage.GetStream(firstFile.FileInfo.GetStoragePath()))
- originalLength = stream.Length;
-
- using (var stream = files.Storage.GetStream(firstFile.FileInfo.GetStoragePath(), FileAccess.Write, FileMode.Create))
- stream.WriteByte(0);
-
- var importedSecondTime = await LoadOszIntoOsu(osu);
-
- using (var stream = files.Storage.GetStream(firstFile.FileInfo.GetStoragePath()))
- Assert.AreEqual(stream.Length, originalLength, "Corruption was not fixed on second import");
-
- // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
- Assert.IsTrue(imported.ID == importedSecondTime.ID);
- Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
-
- checkBeatmapSetCount(osu, 1);
- checkSingleReferencedFileCount(osu, 18);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestModelCreationFailureDoesntReturn()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
- var importer = osu.Dependencies.Get();
-
- var progressNotification = new ImportProgressNotification();
-
- var zipStream = new MemoryStream();
-
- using (var zip = ZipArchive.Create())
- zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate));
-
- var imported = await importer.Import(
- progressNotification,
- new ImportTask(zipStream, string.Empty)
- );
-
- checkBeatmapSetCount(osu, 0);
- checkBeatmapCount(osu, 0);
-
- Assert.IsEmpty(imported);
- Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestRollbackOnFailure()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- int itemAddRemoveFireCount = 0;
- int loggedExceptionCount = 0;
-
- Logger.NewEntry += l =>
- {
- if (l.Target == LoggingTarget.Database && l.Exception != null)
- Interlocked.Increment(ref loggedExceptionCount);
- };
-
- var osu = LoadOsuIntoHost(host);
- var manager = osu.Dependencies.Get();
-
- // ReSharper disable once AccessToModifiedClosure
- manager.ItemUpdated += _ => Interlocked.Increment(ref itemAddRemoveFireCount);
- manager.ItemRemoved += _ => Interlocked.Increment(ref itemAddRemoveFireCount);
-
- var imported = await LoadOszIntoOsu(osu);
-
- Assert.AreEqual(0, itemAddRemoveFireCount -= 1);
-
- imported.Hash += "-changed";
- manager.Update(imported);
-
- Assert.AreEqual(0, itemAddRemoveFireCount -= 1);
-
- checkBeatmapSetCount(osu, 1);
- checkBeatmapCount(osu, 12);
- checkSingleReferencedFileCount(osu, 18);
-
- string brokenTempFilename = TestResources.GetTestBeatmapForImport();
-
- MemoryStream brokenOsu = new MemoryStream();
- MemoryStream brokenOsz = new MemoryStream(await File.ReadAllBytesAsync(brokenTempFilename));
-
- File.Delete(brokenTempFilename);
-
- using (var outStream = File.Open(brokenTempFilename, FileMode.CreateNew))
- using (var zip = ZipArchive.Open(brokenOsz))
- {
- zip.AddEntry("broken.osu", brokenOsu, false);
- zip.SaveTo(outStream, CompressionType.Deflate);
- }
-
- // this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu.
- try
- {
- await manager.Import(new ImportTask(brokenTempFilename));
- }
- catch
- {
- }
-
- // no events should be fired in the case of a rollback.
- Assert.AreEqual(0, itemAddRemoveFireCount);
-
- checkBeatmapSetCount(osu, 1);
- checkBeatmapCount(osu, 12);
-
- checkSingleReferencedFileCount(osu, 18);
-
- Assert.AreEqual(1, loggedExceptionCount);
-
- File.Delete(brokenTempFilename);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportThenDeleteThenImport()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- var imported = await LoadOszIntoOsu(osu);
-
- deleteBeatmapSet(imported, osu);
-
- var importedSecondTime = await LoadOszIntoOsu(osu);
-
- // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
- Assert.IsTrue(imported.ID == importedSecondTime.ID);
- Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportThenDeleteThenImportWithOnlineIDsMissing()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- var imported = await LoadOszIntoOsu(osu);
-
- foreach (var b in imported.Beatmaps)
- b.OnlineID = null;
-
- osu.Dependencies.Get().Update(imported);
-
- deleteBeatmapSet(imported, osu);
-
- var importedSecondTime = await LoadOszIntoOsu(osu);
-
- // check the newly "imported" beatmap has been reimported due to mismatch (even though hashes matched)
- Assert.IsTrue(imported.ID != importedSecondTime.ID);
- Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.Beatmaps.First().ID);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportWithDuplicateBeatmapIDs()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- var metadata = new BeatmapMetadata
- {
- Artist = "SomeArtist",
- AuthorString = "SomeAuthor"
- };
-
- var difficulty = new BeatmapDifficulty();
-
- var toImport = new BeatmapSetInfo
- {
- OnlineID = 1,
- Metadata = metadata,
- Beatmaps =
- {
- new BeatmapInfo
- {
- OnlineID = 2,
- Metadata = metadata,
- BaseDifficulty = difficulty
- },
- new BeatmapInfo
- {
- OnlineID = 2,
- Metadata = metadata,
- Status = BeatmapOnlineStatus.Loved,
- BaseDifficulty = difficulty
- }
- }
- };
-
- var manager = osu.Dependencies.Get();
-
- var imported = await manager.Import(toImport);
-
- Assert.NotNull(imported);
- Assert.AreEqual(null, imported.Value.Beatmaps[0].OnlineID);
- Assert.AreEqual(null, imported.Value.Beatmaps[1].OnlineID);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- [NonParallelizable]
- public void TestImportOverIPC()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost(true))
- using (HeadlessGameHost client = new CleanRunHeadlessGameHost(true))
- {
- try
- {
- Assert.IsTrue(host.IsPrimaryInstance);
- Assert.IsFalse(client.IsPrimaryInstance);
-
- var osu = LoadOsuIntoHost(host);
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- var importer = new ArchiveImportIPCChannel(client);
- if (!importer.ImportAsync(temp).Wait(10000))
- Assert.Fail(@"IPC took too long to send");
-
- ensureLoaded(osu).WaitSafely();
-
- waitForOrAssert(() => !File.Exists(temp), "Temporary still exists after IPC import", 5000);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportWhenFileOpen()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
- string temp = TestResources.GetTestBeatmapForImport();
- using (File.OpenRead(temp))
- await osu.Dependencies.Get().Import(temp);
- await ensureLoaded(osu);
- File.Delete(temp);
- Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't");
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportWithDuplicateHashes()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- string extractedFolder = $"{temp}_extracted";
- Directory.CreateDirectory(extractedFolder);
-
- try
- {
- using (var zip = ZipArchive.Open(temp))
- zip.WriteToDirectory(extractedFolder);
-
- using (var zip = ZipArchive.Create())
- {
- zip.AddAllFromDirectory(extractedFolder);
- zip.AddEntry("duplicate.osu", Directory.GetFiles(extractedFolder, "*.osu").First());
- zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
- }
-
- await osu.Dependencies.Get().Import(temp);
-
- await ensureLoaded(osu);
- }
- finally
- {
- Directory.Delete(extractedFolder, true);
- }
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportNestedStructure()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- string extractedFolder = $"{temp}_extracted";
- string subfolder = Path.Combine(extractedFolder, "subfolder");
-
- Directory.CreateDirectory(subfolder);
-
- try
- {
- using (var zip = ZipArchive.Open(temp))
- zip.WriteToDirectory(subfolder);
-
- using (var zip = ZipArchive.Create())
- {
- zip.AddAllFromDirectory(extractedFolder);
- zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
- }
-
- var imported = await osu.Dependencies.Get().Import(new ImportTask(temp));
-
- await ensureLoaded(osu);
-
- Assert.IsFalse(imported.Value.Files.Any(f => f.Filename.Contains("subfolder")), "Files contain common subfolder");
- }
- finally
- {
- Directory.Delete(extractedFolder, true);
- }
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public async Task TestImportWithIgnoredDirectoryInArchive()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- string extractedFolder = $"{temp}_extracted";
- string dataFolder = Path.Combine(extractedFolder, "actual_data");
- string resourceForkFolder = Path.Combine(extractedFolder, "__MACOSX");
- string resourceForkFilePath = Path.Combine(resourceForkFolder, ".extracted");
-
- Directory.CreateDirectory(dataFolder);
- Directory.CreateDirectory(resourceForkFolder);
-
- using (var resourceForkFile = File.CreateText(resourceForkFilePath))
- {
- await resourceForkFile.WriteLineAsync("adding content so that it's not empty");
- }
-
- try
- {
- using (var zip = ZipArchive.Open(temp))
- zip.WriteToDirectory(dataFolder);
-
- using (var zip = ZipArchive.Create())
- {
- zip.AddAllFromDirectory(extractedFolder);
- zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate));
- }
-
- var imported = await osu.Dependencies.Get().Import(new ImportTask(temp));
-
- await ensureLoaded(osu);
-
- Assert.IsFalse(imported.Value.Files.Any(f => f.Filename.Contains("__MACOSX")), "Files contain resource fork folder, which should be ignored");
- Assert.IsFalse(imported.Value.Files.Any(f => f.Filename.Contains("actual_data")), "Files contain common subfolder");
- }
- finally
- {
- Directory.Delete(extractedFolder, true);
- }
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public void TestUpdateBeatmapInfo()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
- var manager = osu.Dependencies.Get();
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- osu.Dependencies.Get().Import(temp).WaitSafely();
-
- // Update via the beatmap, not the beatmap info, to ensure correct linking
- BeatmapSetInfo setToUpdate = manager.GetAllUsableBeatmapSets()[0];
- Beatmap beatmapToUpdate = (Beatmap)manager.GetWorkingBeatmap(setToUpdate.Beatmaps.First(b => b.RulesetID == 0)).Beatmap;
- beatmapToUpdate.BeatmapInfo.DifficultyName = "updated";
-
- manager.Update(setToUpdate);
-
- BeatmapInfo updatedInfo = manager.QueryBeatmap(b => b.ID == beatmapToUpdate.BeatmapInfo.ID);
- Assert.That(updatedInfo.DifficultyName, Is.EqualTo("updated"));
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public void TestUpdateBeatmapFile()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
- var manager = osu.Dependencies.Get();
-
- string temp = TestResources.GetTestBeatmapForImport();
-
- osu.Dependencies.Get().Import(temp).WaitSafely();
-
- BeatmapSetInfo setToUpdate = manager.GetAllUsableBeatmapSets()[0];
-
- var beatmapInfo = setToUpdate.Beatmaps.First(b => b.RulesetID == 0);
- Beatmap beatmapToUpdate = (Beatmap)manager.GetWorkingBeatmap(setToUpdate.Beatmaps.First(b => b.RulesetID == 0)).Beatmap;
- BeatmapSetFileInfo fileToUpdate = setToUpdate.Files.First(f => beatmapToUpdate.BeatmapInfo.Path.Contains(f.Filename));
-
- string oldMd5Hash = beatmapToUpdate.BeatmapInfo.MD5Hash;
-
- beatmapToUpdate.HitObjects.Clear();
- beatmapToUpdate.HitObjects.Add(new HitCircle { StartTime = 5000 });
-
- manager.Save(beatmapInfo, beatmapToUpdate);
-
- // Check that the old file reference has been removed
- Assert.That(manager.QueryBeatmapSet(s => s.ID == setToUpdate.ID).Files.All(f => f.ID != fileToUpdate.ID));
-
- // Check that the new file is referenced correctly by attempting a retrieval
- Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(manager.QueryBeatmap(b => b.ID == beatmapToUpdate.BeatmapInfo.ID)).Beatmap;
- Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(1));
- Assert.That(updatedBeatmap.HitObjects[0].StartTime, Is.EqualTo(5000));
- Assert.That(updatedBeatmap.BeatmapInfo.MD5Hash, Is.Not.EqualTo(oldMd5Hash));
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- // TODO: needs to be pulled across to realm implementation when this file is nuked.
- [Test]
- public void TestSaveRemovesInvalidCharactersFromPath()
- {
- // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
-
- var manager = osu.Dependencies.Get();
-
- var working = manager.CreateNew(new OsuRuleset().RulesetInfo, APIUser.SYSTEM_USER);
-
- var beatmap = working.Beatmap;
-
- beatmap.BeatmapInfo.DifficultyName = "difficulty";
- beatmap.BeatmapInfo.Metadata = new BeatmapMetadata
- {
- Artist = "Artist/With\\Slashes",
- Title = "Title",
- AuthorString = "mapper",
- };
-
- manager.Save(beatmap.BeatmapInfo, working.Beatmap);
-
- Assert.AreEqual("Artist_With_Slashes - Title (mapper) [difficulty].osu", beatmap.BeatmapInfo.Path);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public void TestCreateNewEmptyBeatmap()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
- var manager = osu.Dependencies.Get();
-
- var working = manager.CreateNew(new OsuRuleset().RulesetInfo, APIUser.SYSTEM_USER);
-
- manager.Save(working.BeatmapInfo, working.Beatmap);
-
- var retrievedSet = manager.GetAllUsableBeatmapSets()[0];
-
- // Check that the new file is referenced correctly by attempting a retrieval
- Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(retrievedSet.Beatmaps[0]).Beatmap;
- Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(0));
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- [Test]
- public void TestCreateNewBeatmapWithObject()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host);
- var manager = osu.Dependencies.Get();
-
- var working = manager.CreateNew(new OsuRuleset().RulesetInfo, APIUser.SYSTEM_USER);
-
- ((Beatmap)working.Beatmap).HitObjects.Add(new HitCircle { StartTime = 5000 });
-
- manager.Save(working.BeatmapInfo, working.Beatmap);
-
- var retrievedSet = manager.GetAllUsableBeatmapSets()[0];
-
- // Check that the new file is referenced correctly by attempting a retrieval
- Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(retrievedSet.Beatmaps[0]).Beatmap;
- Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(1));
- Assert.That(updatedBeatmap.HitObjects[0].StartTime, Is.EqualTo(5000));
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
- public static Task LoadQuickOszIntoOsu(OsuGameBase osu) => Task.Factory.StartNew(() =>
- {
- string temp = TestResources.GetQuickTestBeatmapForImport();
-
- var manager = osu.Dependencies.Get();
-
- var importedSet = manager.Import(new ImportTask(temp)).GetResultSafely();
-
- ensureLoaded(osu).WaitSafely();
-
- waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
-
- return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.Value.ID);
- }, TaskCreationOptions.LongRunning);
-
- public static Task LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false) => Task.Factory.StartNew(() =>
- {
- string temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
-
- var manager = osu.Dependencies.Get();
-
- var importedSet = manager.Import(new ImportTask(temp)).GetResultSafely();
-
- ensureLoaded(osu).WaitSafely();
-
- waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
-
- return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.Value.ID);
- }, TaskCreationOptions.LongRunning);
-
- private void deleteBeatmapSet(BeatmapSetInfo imported, OsuGameBase osu)
- {
- var manager = osu.Dependencies.Get();
- manager.Delete(imported);
-
- checkBeatmapSetCount(osu, 0);
- checkBeatmapSetCount(osu, 1, true);
- checkSingleReferencedFileCount(osu, 0);
-
- Assert.IsTrue(manager.QueryBeatmapSets(_ => true).First().DeletePending);
- }
-
- private static Task createScoreForBeatmap(OsuGameBase osu, BeatmapInfo beatmapInfo)
- {
- return ImportScoreTest.LoadScoreIntoOsu(osu, new ScoreInfo
- {
- OnlineID = 2,
- BeatmapInfo = beatmapInfo,
- BeatmapInfoID = beatmapInfo.ID
- }, new ImportScoreTest.TestArchiveReader());
- }
-
- private static void checkBeatmapSetCount(OsuGameBase osu, int expected, bool includeDeletePending = false)
- {
- var manager = osu.Dependencies.Get();
-
- Assert.AreEqual(expected, includeDeletePending
- ? manager.QueryBeatmapSets(_ => true).ToList().Count
- : manager.GetAllUsableBeatmapSets().Count);
- }
-
- private static string hashFile(string filename)
- {
- using (var s = File.OpenRead(filename))
- return s.ComputeMD5Hash();
- }
-
- private static void checkBeatmapCount(OsuGameBase osu, int expected)
- {
- Assert.AreEqual(expected, osu.Dependencies.Get().QueryBeatmaps(_ => true).ToList().Count);
- }
-
- private static void checkSingleReferencedFileCount(OsuGameBase osu, int expected)
- {
- Assert.AreEqual(expected, osu.Dependencies.Get().Get().FileInfo.Count(f => f.ReferenceCount == 1));
- }
-
- private static Task ensureLoaded(OsuGameBase osu, int timeout = 60000) => Task.Factory.StartNew(() =>
- {
- IEnumerable resultSets = null;
- var store = osu.Dependencies.Get();
- waitForOrAssert(() => (resultSets = store.QueryBeatmapSets(s => s.OnlineID == 241526)).Any(),
- @"BeatmapSet did not import to the database in allocated time.", timeout);
-
- // ensure we were stored to beatmap database backing...
- Assert.IsTrue(resultSets.Count() == 1, $@"Incorrect result count found ({resultSets.Count()} but should be 1).");
- IEnumerable queryBeatmaps() => store.QueryBeatmaps(s => s.BeatmapSet.OnlineID == 241526 && s.BaseDifficultyID > 0);
- IEnumerable queryBeatmapSets() => store.QueryBeatmapSets(s => s.OnlineID == 241526);
-
- // if we don't re-check here, the set will be inserted but the beatmaps won't be present yet.
- waitForOrAssert(() => queryBeatmaps().Count() == 12,
- @"Beatmaps did not import to the database in allocated time", timeout);
- waitForOrAssert(() => queryBeatmapSets().Count() == 1,
- @"BeatmapSet did not import to the database in allocated time", timeout);
- int countBeatmapSetBeatmaps = 0;
- int countBeatmaps = 0;
- waitForOrAssert(() =>
- (countBeatmapSetBeatmaps = queryBeatmapSets().First().Beatmaps.Count) ==
- (countBeatmaps = queryBeatmaps().Count()),
- $@"Incorrect database beatmap count post-import ({countBeatmaps} but should be {countBeatmapSetBeatmaps}).", timeout);
-
- var set = queryBeatmapSets().First();
- foreach (BeatmapInfo b in set.Beatmaps)
- Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID));
- Assert.IsTrue(set.Beatmaps.Count > 0);
- var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
- Assert.IsTrue(beatmap?.HitObjects.Any() == true);
- beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap;
- Assert.IsTrue(beatmap?.HitObjects.Any() == true);
- beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap;
- Assert.IsTrue(beatmap?.HitObjects.Any() == true);
- beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap;
- Assert.IsTrue(beatmap?.HitObjects.Any() == true);
- }, TaskCreationOptions.LongRunning);
-
- private static void waitForOrAssert(Func result, string failureMessage, int timeout = 60000)
- {
- Task task = Task.Factory.StartNew(() =>
- {
- while (!result()) Thread.Sleep(200);
- }, TaskCreationOptions.LongRunning);
-
- Assert.IsTrue(task.Wait(timeout), failureMessage);
- }
- }
-}
diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
index b2ab1eeaa6..810ea5dbd0 100644
--- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var meta = beatmap.Metadata;
- Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineID);
+ Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet?.OnlineID);
Assert.AreEqual("Soleily", meta.Artist);
Assert.AreEqual("Soleily", meta.ArtistUnicode);
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs
index 26ab8808b9..f3456cf8e4 100644
--- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs
+++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs
@@ -24,6 +24,8 @@ namespace osu.Game.Tests.Beatmaps
{
public const double BASE_STARS = 5.55;
+ private static readonly Guid guid = Guid.NewGuid();
+
private BeatmapSetInfo importedSet;
private TestBeatmapDifficultyCache difficultyCache;
@@ -33,7 +35,7 @@ namespace osu.Game.Tests.Beatmaps
[BackgroundDependencyLoader]
private void load(OsuGameBase osu)
{
- importedSet = ImportBeatmapTest.LoadQuickOszIntoOsu(osu).GetResultSafely();
+ importedSet = BeatmapImportHelper.LoadQuickOszIntoOsu(osu).GetResultSafely();
}
[SetUpSteps]
@@ -98,8 +100,8 @@ namespace osu.Game.Tests.Beatmaps
[Test]
public void TestKeyEqualsWithDifferentModInstances()
{
- var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
- var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
+ var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
+ var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
Assert.That(key1, Is.EqualTo(key2));
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
@@ -108,8 +110,8 @@ namespace osu.Game.Tests.Beatmaps
[Test]
public void TestKeyEqualsWithDifferentModOrder()
{
- var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
- var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
+ var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
+ var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
Assert.That(key1, Is.EqualTo(key2));
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
@@ -118,8 +120,8 @@ namespace osu.Game.Tests.Beatmaps
[Test]
public void TestKeyDoesntEqualWithDifferentModSettings()
{
- var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } });
- var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } });
+ var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } });
+ var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } });
Assert.That(key1, Is.Not.EqualTo(key2));
Assert.That(key1.GetHashCode(), Is.Not.EqualTo(key2.GetHashCode()));
@@ -128,8 +130,8 @@ namespace osu.Game.Tests.Beatmaps
[Test]
public void TestKeyEqualWithMatchingModSettings()
{
- var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
- var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
+ var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
+ var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = guid }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
Assert.That(key1, Is.EqualTo(key2));
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
diff --git a/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs b/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs
index bf5b517603..153788c2cf 100644
--- a/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs
+++ b/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs
@@ -7,6 +7,7 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit;
@@ -30,7 +31,13 @@ namespace osu.Game.Tests.Beatmaps
AddStep("add beatmap", () =>
{
- Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
+ });
editorBeatmap.HitObjectAdded += h => addedObject = h;
});
@@ -49,7 +56,14 @@ namespace osu.Game.Tests.Beatmaps
EditorBeatmap editorBeatmap = null;
AddStep("add beatmap", () =>
{
- Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } });
+ Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
+ HitObjects = { hitCircle }
+ });
editorBeatmap.HitObjectRemoved += h => removedObject = h;
});
AddStep("remove hitobject", () => editorBeatmap.Remove(editorBeatmap.HitObjects.First()));
@@ -71,7 +85,14 @@ namespace osu.Game.Tests.Beatmaps
{
EditorBeatmap editorBeatmap;
- Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } });
+ Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
+ HitObjects = { hitCircle }
+ });
editorBeatmap.HitObjectUpdated += h => changedObject = h;
});
@@ -91,7 +112,13 @@ namespace osu.Game.Tests.Beatmaps
AddStep("add beatmap", () =>
{
- Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
+ });
editorBeatmap.HitObjectUpdated += h => changedObject = h;
});
@@ -111,7 +138,14 @@ namespace osu.Game.Tests.Beatmaps
public void TestRemovedHitObjectStartTimeChangeEvent()
{
var hitCircle = new HitCircle();
- var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } });
+ var editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
+ HitObjects = { hitCircle }
+ });
HitObject changedObject = null;
editorBeatmap.HitObjectUpdated += h => changedObject = h;
@@ -131,6 +165,10 @@ namespace osu.Game.Tests.Beatmaps
{
var editorBeatmap = new EditorBeatmap(new OsuBeatmap
{
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
HitObjects =
{
new HitCircle(),
@@ -156,6 +194,10 @@ namespace osu.Game.Tests.Beatmaps
var editorBeatmap = new EditorBeatmap(new OsuBeatmap
{
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
HitObjects =
{
new HitCircle(),
@@ -185,7 +227,13 @@ namespace osu.Game.Tests.Beatmaps
{
updatedObjects.Clear();
- Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
+ });
for (int i = 0; i < 10; i++)
{
@@ -220,7 +268,13 @@ namespace osu.Game.Tests.Beatmaps
{
updatedObjects.Clear();
- Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ Child = editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
+ });
editorBeatmap.Add(new HitCircle());
});
diff --git a/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs b/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs
index 4a7d7505ad..10cac4ed9d 100644
--- a/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs
+++ b/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs
@@ -3,7 +3,7 @@
using NUnit.Framework;
using osu.Game.Beatmaps;
-using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Models;
namespace osu.Game.Tests.Beatmaps
{
@@ -34,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps
{
Artist = "artist",
Title = "title",
- Author = new APIUser { Username = "creator" }
+ Author = new RealmUser { Username = "creator" }
}
};
@@ -50,7 +50,7 @@ namespace osu.Game.Tests.Beatmaps
{
Artist = "artist",
Title = "title",
- Author = new APIUser { Username = "creator" }
+ Author = new RealmUser { Username = "creator" }
},
DifficultyName = "difficulty"
};
diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs
index e47e24021f..1bba73bea0 100644
--- a/osu.Game.Tests/Database/BeatmapImporterTests.cs
+++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs
@@ -19,6 +19,7 @@ using osu.Game.Extensions;
using osu.Game.IO.Archives;
using osu.Game.Models;
using osu.Game.Overlays.Notifications;
+using osu.Game.Rulesets;
using osu.Game.Stores;
using osu.Game.Tests.Resources;
using Realms;
@@ -34,33 +35,132 @@ namespace osu.Game.Tests.Database
[TestFixture]
public class BeatmapImporterTests : RealmTest
{
+ [Test]
+ public void TestDetachBeatmapSet()
+ {
+ RunTestWithRealmAsync(async (realmFactory, storage) =>
+ {
+ using (var importer = new BeatmapModelManager(realmFactory, storage))
+ using (new RulesetStore(realmFactory, storage))
+ {
+ ILive? beatmapSet;
+
+ using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
+ beatmapSet = await importer.Import(reader);
+
+ Assert.NotNull(beatmapSet);
+ Debug.Assert(beatmapSet != null);
+
+ BeatmapSetInfo? detachedBeatmapSet = null;
+
+ beatmapSet.PerformRead(live =>
+ {
+ detachedBeatmapSet = live.Detach();
+
+ Assert.AreEqual(live.Files.Count, detachedBeatmapSet.Files.Count);
+ Assert.AreEqual(live.Files.Select(f => f.File).Count(), detachedBeatmapSet.Files.Select(f => f.File).Count());
+ Assert.AreEqual(live.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count);
+ Assert.AreEqual(live.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count());
+ Assert.AreEqual(live.Metadata, detachedBeatmapSet.Metadata);
+ });
+
+ Debug.Assert(detachedBeatmapSet != null);
+
+ // Check detached instances can all be accessed without throwing.
+ Assert.NotNull(detachedBeatmapSet.Files.Count);
+ Assert.NotZero(detachedBeatmapSet.Files.Select(f => f.File).Count());
+ Assert.NotNull(detachedBeatmapSet.Beatmaps.Count);
+ Assert.NotZero(detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count());
+ Assert.NotNull(detachedBeatmapSet.Beatmaps.First().Path);
+ Assert.NotNull(detachedBeatmapSet.Metadata);
+
+ // Check cyclic reference to beatmap set
+ Assert.AreEqual(detachedBeatmapSet, detachedBeatmapSet.Beatmaps.First().BeatmapSet);
+ }
+ });
+ }
+
+ [Test]
+ public void TestUpdateDetachedBeatmapSet()
+ {
+ RunTestWithRealmAsync(async (realmFactory, storage) =>
+ {
+ using (var importer = new BeatmapModelManager(realmFactory, storage))
+ using (new RulesetStore(realmFactory, storage))
+ {
+ ILive? beatmapSet;
+
+ using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
+ beatmapSet = await importer.Import(reader);
+
+ Assert.NotNull(beatmapSet);
+ Debug.Assert(beatmapSet != null);
+
+ BeatmapSetInfo? detachedBeatmapSet = null;
+
+ beatmapSet.PerformRead(s => detachedBeatmapSet = s.Detach());
+
+ Debug.Assert(detachedBeatmapSet != null);
+
+ var newUser = new RealmUser { Username = "peppy", OnlineID = 2 };
+
+ detachedBeatmapSet.Beatmaps.First().Metadata.Artist = "New Artist";
+ detachedBeatmapSet.Beatmaps.First().Metadata.Author = newUser;
+
+ Assert.AreNotEqual(detachedBeatmapSet.Status, BeatmapOnlineStatus.Ranked);
+ detachedBeatmapSet.Status = BeatmapOnlineStatus.Ranked;
+
+ beatmapSet.PerformWrite(s =>
+ {
+ detachedBeatmapSet.CopyChangesToRealm(s);
+ });
+
+ beatmapSet.PerformRead(s =>
+ {
+ // Check above changes explicitly.
+ Assert.AreEqual(BeatmapOnlineStatus.Ranked, s.Status);
+ Assert.AreEqual("New Artist", s.Beatmaps.First().Metadata.Artist);
+ Assert.AreEqual(newUser, s.Beatmaps.First().Metadata.Author);
+ Assert.NotZero(s.Files.Count);
+
+ // Check nothing was lost in the copy operation.
+ Assert.AreEqual(s.Files.Count, detachedBeatmapSet.Files.Count);
+ Assert.AreEqual(s.Files.Select(f => f.File).Count(), detachedBeatmapSet.Files.Select(f => f.File).Count());
+ Assert.AreEqual(s.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count);
+ Assert.AreEqual(s.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count());
+ Assert.AreEqual(s.Metadata, detachedBeatmapSet.Metadata);
+ });
+ }
+ });
+ }
+
[Test]
public void TestImportBeatmapThenCleanup()
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using (var importer = new BeatmapImporter(realmFactory, storage))
- using (new RealmRulesetStore(realmFactory, storage))
+ using (var importer = new BeatmapModelManager(realmFactory, storage))
+ using (new RulesetStore(realmFactory, storage))
{
- ILive? imported;
+ ILive? imported;
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
imported = await importer.Import(reader);
- Assert.AreEqual(1, realmFactory.Context.All().Count());
+ Assert.AreEqual(1, realmFactory.Context.All().Count());
Assert.NotNull(imported);
Debug.Assert(imported != null);
imported.PerformWrite(s => s.DeletePending = true);
- Assert.AreEqual(1, realmFactory.Context.All().Count(s => s.DeletePending));
+ Assert.AreEqual(1, realmFactory.Context.All().Count(s => s.DeletePending));
}
});
Logger.Log("Running with no work to purge pending deletions");
- RunTestWithRealm((realmFactory, _) => { Assert.AreEqual(0, realmFactory.Context.All().Count()); });
+ RunTestWithRealm((realmFactory, _) => { Assert.AreEqual(0, realmFactory.Context.All().Count()); });
}
[Test]
@@ -68,8 +168,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
await LoadOszIntoStore(importer, realmFactory.Context);
});
@@ -80,8 +180,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@@ -98,8 +198,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@@ -112,17 +212,17 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? tempPath = TestResources.GetTestBeatmapForImport();
- ILive? importedSet;
+ ILive? importedSet;
using (var stream = File.OpenRead(tempPath))
{
importedSet = await importer.Import(new ImportTask(stream, Path.GetFileName(tempPath)));
- ensureLoaded(realmFactory.Context);
+ EnsureLoaded(realmFactory.Context);
}
Assert.NotNull(importedSet);
@@ -131,7 +231,7 @@ namespace osu.Game.Tests.Database
Assert.IsTrue(File.Exists(tempPath), "Stream source file somehow went missing");
File.Delete(tempPath);
- var imported = realmFactory.Context.All().First(beatmapSet => beatmapSet.ID == importedSet.ID);
+ var imported = realmFactory.Context.All().First(beatmapSet => beatmapSet.ID == importedSet.ID);
deleteBeatmapSet(imported, realmFactory.Context);
});
@@ -142,8 +242,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
@@ -162,8 +262,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -190,7 +290,7 @@ namespace osu.Game.Tests.Database
var importedSecondTime = await importer.Import(new ImportTask(temp));
- ensureLoaded(realmFactory.Context);
+ EnsureLoaded(realmFactory.Context);
Assert.NotNull(importedSecondTime);
Debug.Assert(importedSecondTime != null);
@@ -211,8 +311,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -241,7 +341,7 @@ namespace osu.Game.Tests.Database
var importedSecondTime = await importer.Import(new ImportTask(temp));
- ensureLoaded(realmFactory.Context);
+ EnsureLoaded(realmFactory.Context);
// check the newly "imported" beatmap is not the original.
Assert.NotNull(importedSecondTime);
@@ -263,8 +363,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -290,7 +390,7 @@ namespace osu.Game.Tests.Database
var importedSecondTime = await importer.Import(new ImportTask(temp));
- ensureLoaded(realmFactory.Context);
+ EnsureLoaded(realmFactory.Context);
Assert.NotNull(importedSecondTime);
Debug.Assert(importedSecondTime != null);
@@ -311,8 +411,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -338,7 +438,7 @@ namespace osu.Game.Tests.Database
var importedSecondTime = await importer.Import(new ImportTask(temp));
- ensureLoaded(realmFactory.Context);
+ EnsureLoaded(realmFactory.Context);
Assert.NotNull(importedSecondTime);
Debug.Assert(importedSecondTime != null);
@@ -360,8 +460,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@@ -393,8 +493,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
var progressNotification = new ImportProgressNotification();
@@ -429,8 +529,8 @@ namespace osu.Game.Tests.Database
Interlocked.Increment(ref loggedExceptionCount);
};
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@@ -479,8 +579,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@@ -504,7 +604,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new NonOptimisedBeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@@ -527,8 +627,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
@@ -553,10 +653,10 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
- var metadata = new RealmBeatmapMetadata
+ var metadata = new BeatmapMetadata
{
Artist = "SomeArtist",
Author =
@@ -565,18 +665,18 @@ namespace osu.Game.Tests.Database
}
};
- var ruleset = realmFactory.Context.All().First();
+ var ruleset = realmFactory.Context.All().First();
- var toImport = new RealmBeatmapSet
+ var toImport = new BeatmapSetInfo
{
OnlineID = 1,
Beatmaps =
{
- new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata)
+ new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata)
{
OnlineID = 2,
},
- new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata)
+ new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata)
{
OnlineID = 2,
Status = BeatmapOnlineStatus.Loved,
@@ -599,13 +699,13 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
using (File.OpenRead(temp))
await importer.Import(temp);
- ensureLoaded(realmFactory.Context);
+ EnsureLoaded(realmFactory.Context);
File.Delete(temp);
Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't");
});
@@ -616,8 +716,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -638,7 +738,7 @@ namespace osu.Game.Tests.Database
await importer.Import(temp);
- ensureLoaded(realmFactory.Context);
+ EnsureLoaded(realmFactory.Context);
}
finally
{
@@ -652,8 +752,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -678,7 +778,7 @@ namespace osu.Game.Tests.Database
Assert.NotNull(imported);
Debug.Assert(imported != null);
- ensureLoaded(realmFactory.Context);
+ EnsureLoaded(realmFactory.Context);
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("subfolder"))), "Files contain common subfolder");
}
@@ -694,8 +794,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -728,7 +828,7 @@ namespace osu.Game.Tests.Database
Assert.NotNull(imported);
Debug.Assert(imported != null);
- ensureLoaded(realmFactory.Context);
+ EnsureLoaded(realmFactory.Context);
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("__MACOSX"))), "Files contain resource fork folder, which should be ignored");
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("actual_data"))), "Files contain common subfolder");
@@ -745,25 +845,25 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new BeatmapImporter(realmFactory, storage);
- using var store = new RealmRulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
+ using var store = new RulesetStore(realmFactory, storage);
string? temp = TestResources.GetTestBeatmapForImport();
await importer.Import(temp);
// Update via the beatmap, not the beatmap info, to ensure correct linking
- RealmBeatmapSet setToUpdate = realmFactory.Context.All().First();
+ BeatmapSetInfo setToUpdate = realmFactory.Context.All().First();
var beatmapToUpdate = setToUpdate.Beatmaps.First();
realmFactory.Context.Write(() => beatmapToUpdate.DifficultyName = "updated");
- RealmBeatmap updatedInfo = realmFactory.Context.All().First(b => b.ID == beatmapToUpdate.ID);
+ BeatmapInfo updatedInfo = realmFactory.Context.All().First(b => b.ID == beatmapToUpdate.ID);
Assert.That(updatedInfo.DifficultyName, Is.EqualTo("updated"));
});
}
- public static async Task LoadQuickOszIntoOsu(BeatmapImporter importer, Realm realm)
+ public static async Task LoadQuickOszIntoOsu(BeatmapImporter importer, Realm realm)
{
string? temp = TestResources.GetQuickTestBeatmapForImport();
@@ -771,14 +871,14 @@ namespace osu.Game.Tests.Database
Assert.NotNull(importedSet);
- ensureLoaded(realm);
+ EnsureLoaded(realm);
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
- return realm.All().FirstOrDefault(beatmapSet => beatmapSet.ID == importedSet!.ID);
+ return realm.All().FirstOrDefault(beatmapSet => beatmapSet.ID == importedSet!.ID);
}
- public static async Task LoadOszIntoStore(BeatmapImporter importer, Realm realm, string? path = null, bool virtualTrack = false)
+ public static async Task LoadOszIntoStore(BeatmapImporter importer, Realm realm, string? path = null, bool virtualTrack = false)
{
string? temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
@@ -787,24 +887,24 @@ namespace osu.Game.Tests.Database
Assert.NotNull(importedSet);
Debug.Assert(importedSet != null);
- ensureLoaded(realm);
+ EnsureLoaded(realm);
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
- return realm.All().First(beatmapSet => beatmapSet.ID == importedSet.ID);
+ return realm.All().First(beatmapSet => beatmapSet.ID == importedSet.ID);
}
- private void deleteBeatmapSet(RealmBeatmapSet imported, Realm realm)
+ private void deleteBeatmapSet(BeatmapSetInfo imported, Realm realm)
{
realm.Write(() => imported.DeletePending = true);
checkBeatmapSetCount(realm, 0);
checkBeatmapSetCount(realm, 1, true);
- Assert.IsTrue(realm.All().First(_ => true).DeletePending);
+ Assert.IsTrue(realm.All().First(_ => true).DeletePending);
}
- private static Task createScoreForBeatmap(Realm realm, RealmBeatmap beatmap)
+ private static Task createScoreForBeatmap(Realm realm, BeatmapInfo beatmap)
{
// TODO: reimplement when we have score support in realm.
// return ImportScoreTest.LoadScoreIntoOsu(osu, new ScoreInfo
@@ -820,8 +920,8 @@ namespace osu.Game.Tests.Database
private static void checkBeatmapSetCount(Realm realm, int expected, bool includeDeletePending = false)
{
Assert.AreEqual(expected, includeDeletePending
- ? realm.All().Count()
- : realm.All().Count(s => !s.DeletePending));
+ ? realm.All().Count()
+ : realm.All().Count(s => !s.DeletePending));
}
private static string hashFile(string filename)
@@ -832,7 +932,7 @@ namespace osu.Game.Tests.Database
private static void checkBeatmapCount(Realm realm, int expected)
{
- Assert.AreEqual(expected, realm.All().Where(_ => true).ToList().Count);
+ Assert.AreEqual(expected, realm.All().Where(_ => true).ToList().Count);
}
private static void checkSingleReferencedFileCount(Realm realm, int expected)
@@ -848,26 +948,25 @@ namespace osu.Game.Tests.Database
Assert.AreEqual(expected, singleReferencedCount);
}
- private static void ensureLoaded(Realm realm, int timeout = 60000)
+ internal static void EnsureLoaded(Realm realm, int timeout = 60000)
{
- IQueryable? resultSets = null;
+ IQueryable? resultSets = null;
waitForOrAssert(() =>
- {
- realm.Refresh();
- return (resultSets = realm.All().Where(s => !s.DeletePending && s.OnlineID == 241526)).Any();
- },
- @"BeatmapSet did not import to the database in allocated time.", timeout);
+ {
+ realm.Refresh();
+ return (resultSets = realm.All().Where(s => !s.DeletePending && s.OnlineID == 241526)).Any();
+ }, @"BeatmapSet did not import to the database in allocated time.", timeout);
// ensure we were stored to beatmap database backing...
Assert.IsTrue(resultSets?.Count() == 1, $@"Incorrect result count found ({resultSets?.Count()} but should be 1).");
- IEnumerable queryBeatmapSets() => realm.All().Where(s => !s.DeletePending && s.OnlineID == 241526);
+ IEnumerable queryBeatmapSets() => realm.All().Where(s => !s.DeletePending && s.OnlineID == 241526);
var set = queryBeatmapSets().First();
// ReSharper disable once PossibleUnintendedReferenceComparison
- IEnumerable queryBeatmaps() => realm.All().Where(s => s.BeatmapSet != null && s.BeatmapSet == set);
+ IEnumerable queryBeatmaps() => realm.All().Where(s => s.BeatmapSet != null && s.BeatmapSet == set);
Assert.AreEqual(12, queryBeatmaps().Count(), @"Beatmap count was not correct");
Assert.AreEqual(1, queryBeatmapSets().Count(), @"Beatmapset count was not correct");
@@ -880,7 +979,7 @@ namespace osu.Game.Tests.Database
countBeatmaps = queryBeatmaps().Count(),
$@"Incorrect database beatmap count post-import ({countBeatmaps} but should be {countBeatmapSetBeatmaps}).");
- foreach (RealmBeatmap b in set.Beatmaps)
+ foreach (BeatmapInfo b in set.Beatmaps)
Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID));
Assert.IsTrue(set.Beatmaps.Count > 0);
}
diff --git a/osu.Game.Tests/Database/GeneralUsageTests.cs b/osu.Game.Tests/Database/GeneralUsageTests.cs
index 2285b22a3a..0961ad71e4 100644
--- a/osu.Game.Tests/Database/GeneralUsageTests.cs
+++ b/osu.Game.Tests/Database/GeneralUsageTests.cs
@@ -5,8 +5,8 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
+using osu.Game.Beatmaps;
using osu.Game.Database;
-using osu.Game.Models;
#nullable enable
@@ -48,7 +48,7 @@ namespace osu.Game.Tests.Database
using (var context = realmFactory.CreateContext())
{
- var subscription = context.All().QueryAsyncWithNotifications((sender, changes, error) =>
+ var subscription = context.All().QueryAsyncWithNotifications((sender, changes, error) =>
{
using (realmFactory.CreateContext())
{
diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs
index 9432a56741..187fcd3ca7 100644
--- a/osu.Game.Tests/Database/RealmLiveTests.cs
+++ b/osu.Game.Tests/Database/RealmLiveTests.cs
@@ -8,8 +8,8 @@ using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Framework.Testing;
+using osu.Game.Beatmaps;
using osu.Game.Database;
-using osu.Game.Models;
using Realms;
#nullable enable
@@ -23,9 +23,9 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, _) =>
{
- ILive beatmap = realmFactory.CreateContext().Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata()))).ToLive(realmFactory);
+ ILive beatmap = realmFactory.CreateContext().Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata()))).ToLive(realmFactory);
- ILive beatmap2 = realmFactory.CreateContext().All().First().ToLive(realmFactory);
+ ILive beatmap2 = realmFactory.CreateContext().All().First().ToLive(realmFactory);
Assert.AreEqual(beatmap, beatmap2);
});
@@ -36,9 +36,9 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, storage) =>
{
- var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
+ var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
- ILive liveBeatmap;
+ ILive liveBeatmap;
using (var context = realmFactory.CreateContext())
{
@@ -63,7 +63,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, _) =>
{
- var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
+ var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
var liveBeatmap = beatmap.ToLive(realmFactory);
@@ -77,7 +77,7 @@ namespace osu.Game.Tests.Database
[Test]
public void TestAccessNonManaged()
{
- var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
+ var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
var liveBeatmap = beatmap.ToLiveUnmanaged();
Assert.IsFalse(beatmap.Hidden);
@@ -96,12 +96,12 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, _) =>
{
- ILive? liveBeatmap = null;
+ ILive? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
using (var threadContext = realmFactory.CreateContext())
{
- var beatmap = threadContext.Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
+ var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata())));
liveBeatmap = beatmap.ToLive(realmFactory);
}
@@ -125,12 +125,12 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, _) =>
{
- ILive? liveBeatmap = null;
+ ILive? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
using (var threadContext = realmFactory.CreateContext())
{
- var beatmap = threadContext.Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
+ var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata())));
liveBeatmap = beatmap.ToLive(realmFactory);
}
@@ -151,7 +151,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, _) =>
{
- var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
+ var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
var liveBeatmap = beatmap.ToLive(realmFactory);
Assert.DoesNotThrow(() =>
@@ -166,13 +166,13 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, _) =>
{
- ILive? liveBeatmap = null;
+ ILive? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
using (var threadContext = realmFactory.CreateContext())
{
- var beatmap = threadContext.Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
+ var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata())));
liveBeatmap = beatmap.ToLive(realmFactory);
}
@@ -205,12 +205,12 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, _) =>
{
- ILive? liveBeatmap = null;
+ ILive? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
using (var threadContext = realmFactory.CreateContext())
{
- var beatmap = threadContext.Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
+ var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata())));
liveBeatmap = beatmap.ToLive(realmFactory);
}
@@ -237,19 +237,19 @@ namespace osu.Game.Tests.Database
using (var updateThreadContext = realmFactory.CreateContext())
{
- updateThreadContext.All().QueryAsyncWithNotifications(gotChange);
- ILive? liveBeatmap = null;
+ updateThreadContext.All().QueryAsyncWithNotifications(gotChange);
+ ILive? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
using (var threadContext = realmFactory.CreateContext())
{
var ruleset = CreateRuleset();
- var beatmap = threadContext.Write(r => r.Add(new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
+ var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(ruleset, new BeatmapDifficulty(), new BeatmapMetadata())));
// add a second beatmap to ensure that a full refresh occurs below.
// not just a refresh from the resolved Live.
- threadContext.Write(r => r.Add(new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
+ threadContext.Write(r => r.Add(new BeatmapInfo(ruleset, new BeatmapDifficulty(), new BeatmapMetadata())));
liveBeatmap = beatmap.ToLive(realmFactory);
}
@@ -258,14 +258,14 @@ namespace osu.Game.Tests.Database
Debug.Assert(liveBeatmap != null);
// not yet seen by main context
- Assert.AreEqual(0, updateThreadContext.All().Count());
+ Assert.AreEqual(0, updateThreadContext.All().Count());
Assert.AreEqual(0, changesTriggered);
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, updateThreadContext.All().Count());
+ Assert.AreEqual(2, updateThreadContext.All().Count());
Assert.AreEqual(1, changesTriggered);
// can access properties without a crash.
@@ -280,7 +280,7 @@ namespace osu.Game.Tests.Database
});
}
- void gotChange(IRealmCollection sender, ChangeSet changes, Exception error)
+ void gotChange(IRealmCollection sender, ChangeSet changes, Exception error)
{
changesTriggered++;
}
diff --git a/osu.Game.Tests/Database/RealmTest.cs b/osu.Game.Tests/Database/RealmTest.cs
index 4e67f09dca..0cee165f75 100644
--- a/osu.Game.Tests/Database/RealmTest.cs
+++ b/osu.Game.Tests/Database/RealmTest.cs
@@ -9,9 +9,11 @@ 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;
using osu.Game.Models;
+using osu.Game.Rulesets;
#nullable enable
@@ -74,24 +76,24 @@ namespace osu.Game.Tests.Database
}
}
- protected static RealmBeatmapSet CreateBeatmapSet(RealmRuleset ruleset)
+ protected static BeatmapSetInfo CreateBeatmapSet(RulesetInfo ruleset)
{
RealmFile createRealmFile() => new RealmFile { Hash = Guid.NewGuid().ToString().ComputeSHA2Hash() };
- var metadata = new RealmBeatmapMetadata
+ var metadata = new BeatmapMetadata
{
Title = "My Love",
Artist = "Kuba Oms"
};
- var beatmapSet = new RealmBeatmapSet
+ var beatmapSet = new BeatmapSetInfo
{
Beatmaps =
{
- new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata) { DifficultyName = "Easy", },
- new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata) { DifficultyName = "Normal", },
- new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata) { DifficultyName = "Hard", },
- new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata) { DifficultyName = "Insane", }
+ new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata) { DifficultyName = "Easy", },
+ new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata) { DifficultyName = "Normal", },
+ new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata) { DifficultyName = "Hard", },
+ new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata) { DifficultyName = "Insane", }
},
Files =
{
@@ -111,8 +113,8 @@ namespace osu.Game.Tests.Database
return beatmapSet;
}
- protected static RealmRuleset CreateRuleset() =>
- new RealmRuleset(0, "osu!", "osu", true);
+ protected static RulesetInfo CreateRuleset() =>
+ new RulesetInfo(0, "osu!", "osu", true);
private class RealmTestGame : Framework.Game
{
diff --git a/osu.Game.Tests/Database/RulesetStoreTests.cs b/osu.Game.Tests/Database/RulesetStoreTests.cs
index cc7e8a0c97..4416da6f92 100644
--- a/osu.Game.Tests/Database/RulesetStoreTests.cs
+++ b/osu.Game.Tests/Database/RulesetStoreTests.cs
@@ -3,8 +3,7 @@
using System.Linq;
using NUnit.Framework;
-using osu.Game.Models;
-using osu.Game.Stores;
+using osu.Game.Rulesets;
namespace osu.Game.Tests.Database
{
@@ -15,10 +14,10 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, storage) =>
{
- var rulesets = new RealmRulesetStore(realmFactory, storage);
+ var rulesets = new RulesetStore(realmFactory, storage);
Assert.AreEqual(4, rulesets.AvailableRulesets.Count());
- Assert.AreEqual(4, realmFactory.Context.All().Count());
+ Assert.AreEqual(4, realmFactory.Context.All().Count());
});
}
@@ -27,14 +26,14 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, storage) =>
{
- var rulesets = new RealmRulesetStore(realmFactory, storage);
- var rulesets2 = new RealmRulesetStore(realmFactory, storage);
+ var rulesets = new RulesetStore(realmFactory, storage);
+ var rulesets2 = new RulesetStore(realmFactory, storage);
Assert.AreEqual(4, rulesets.AvailableRulesets.Count());
Assert.AreEqual(4, rulesets2.AvailableRulesets.Count());
Assert.AreEqual(rulesets.AvailableRulesets.First(), rulesets2.AvailableRulesets.First());
- Assert.AreEqual(4, realmFactory.Context.All().Count());
+ Assert.AreEqual(4, realmFactory.Context.All().Count());
});
}
@@ -43,7 +42,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, storage) =>
{
- var rulesets = new RealmRulesetStore(realmFactory, storage);
+ var rulesets = new RulesetStore(realmFactory, storage);
Assert.IsFalse(rulesets.AvailableRulesets.First().IsManaged);
Assert.IsFalse(rulesets.GetRuleset(0)?.IsManaged);
diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs
index f9b7bfa586..614b9b4ac1 100644
--- a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs
@@ -74,7 +74,7 @@ namespace osu.Game.Tests.Editing.Checks
[Test]
public void TestMissingFile()
{
- beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
+ beatmap.BeatmapInfo.BeatmapSet?.Files.Clear();
var issues = check.Run(getContext(null)).ToList();
diff --git a/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs b/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs
index f36454aa71..01baaadc7d 100644
--- a/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Editing.Checks
[Test]
public void TestBackgroundSetAndNotInFiles()
{
- beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
+ beatmap.BeatmapInfo.BeatmapSet?.Files.Clear();
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
var issues = check.Run(context).ToList();
diff --git a/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs b/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs
index f702921986..9067714ff9 100644
--- a/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs
@@ -1,18 +1,13 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Game.Beatmaps;
-using osu.Game.IO;
+using osu.Game.Models;
namespace osu.Game.Tests.Editing.Checks
{
public static class CheckTestHelpers
{
- public static BeatmapSetFileInfo CreateMockFile(string extension) =>
- new BeatmapSetFileInfo
- {
- Filename = $"abc123.{extension}",
- FileInfo = new FileInfo { Hash = "abcdef" }
- };
+ public static RealmNamedFileUsage CreateMockFile(string extension) =>
+ new RealmNamedFileUsage(new RealmFile { Hash = "abcdef" }, $"abc123.{extension}");
}
}
diff --git a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs
index 8adf0d3764..242fec2f68 100644
--- a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs
+++ b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs
@@ -1,6 +1,7 @@
// 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 System.IO;
using System.Linq;
using ManagedBass;
@@ -45,6 +46,8 @@ namespace osu.Game.Tests.Editing.Checks
[Test]
public void TestDifferentExtension()
{
+ Debug.Assert(beatmap.BeatmapInfo.BeatmapSet != null);
+
beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
beatmap.BeatmapInfo.BeatmapSet.Files.Add(CheckTestHelpers.CreateMockFile("jpg"));
diff --git a/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs b/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs
index 481cb3230e..2d61948a2a 100644
--- a/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs
+++ b/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs
@@ -2,7 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
-using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit;
@@ -158,7 +159,13 @@ namespace osu.Game.Tests.Editing
private (EditorChangeHandler, EditorBeatmap) createChangeHandler()
{
- var beatmap = new EditorBeatmap(new Beatmap());
+ var beatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
+ });
var changeHandler = new EditorChangeHandler(beatmap);
diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs
index 8eb9452736..43f22e4e90 100644
--- a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs
+++ b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs
@@ -35,7 +35,13 @@ namespace osu.Game.Tests.Editing
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
- editorBeatmap = new EditorBeatmap(new OsuBeatmap()),
+ editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo,
+ },
+ }),
Content = new Container
{
RelativeSizeAxes = Axes.Both,
diff --git a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
index 534983f869..1b6049fcb7 100644
--- a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
+++ b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
@@ -1,6 +1,7 @@
// 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 NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Extensions;
@@ -23,8 +24,10 @@ namespace osu.Game.Tests.NonVisual
[Test]
public void TestDatabasedWithDatabased()
{
- var ourInfo = new BeatmapSetInfo { ID = 123 };
- var otherInfo = new BeatmapSetInfo { ID = 123 };
+ var guid = Guid.NewGuid();
+
+ var ourInfo = new BeatmapSetInfo { ID = guid };
+ var otherInfo = new BeatmapSetInfo { ID = guid };
Assert.AreEqual(ourInfo, otherInfo);
}
@@ -32,7 +35,7 @@ namespace osu.Game.Tests.NonVisual
[Test]
public void TestDatabasedWithOnline()
{
- var ourInfo = new BeatmapSetInfo { ID = 123, OnlineID = 12 };
+ var ourInfo = new BeatmapSetInfo { ID = Guid.NewGuid(), OnlineID = 12 };
var otherInfo = new BeatmapSetInfo { OnlineID = 12 };
Assert.AreNotEqual(ourInfo, otherInfo);
diff --git a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
index 4bb54f1625..61ef31e07e 100644
--- a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
+++ b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
@@ -179,7 +179,7 @@ namespace osu.Game.Tests.NonVisual
{
var osu = LoadOsuIntoHost(host);
- const string database_filename = "client.db";
+ const string database_filename = "client.realm";
Assert.DoesNotThrow(() => osu.Migrate(customPath));
Assert.That(File.Exists(Path.Combine(customPath, database_filename)));
diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
index 8ba3d1a6c7..3d78043c73 100644
--- a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
+++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs
@@ -17,7 +17,6 @@ namespace osu.Game.Tests.NonVisual.Filtering
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
{
Ruleset = new RulesetInfo { OnlineID = 0 },
- RulesetID = 0,
StarRating = 4.0d,
BaseDifficulty = new BeatmapDifficulty
{
diff --git a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
index 4b160e1d67..1b7a7656b5 100644
--- a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
+++ b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
@@ -9,10 +9,12 @@ using osu.Framework.Bindables;
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;
+using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
@@ -93,7 +95,11 @@ namespace osu.Game.Tests.Online
[Test]
public void TestDeserialiseSubmittableScoreWithEmptyMods()
{
- var score = new SubmittableScore(new ScoreInfo());
+ var score = new SubmittableScore(new ScoreInfo
+ {
+ User = new APIUser(),
+ Ruleset = new OsuRuleset().RulesetInfo,
+ });
var deserialised = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(score));
@@ -105,7 +111,9 @@ namespace osu.Game.Tests.Online
{
var score = new SubmittableScore(new ScoreInfo
{
- Mods = new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 2 } } }
+ Mods = new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 2 } } },
+ User = new APIUser(),
+ Ruleset = new OsuRuleset().RulesetInfo,
});
var deserialised = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(score));
diff --git a/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs b/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs
index 4e77973655..ad9ea79646 100644
--- a/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs
+++ b/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs
@@ -5,6 +5,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
+using osu.Game.Models;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Notifications;
using osu.Game.Tests.Visual;
@@ -20,13 +21,19 @@ namespace osu.Game.Tests.Online
private static readonly BeatmapSetInfo test_db_model = new BeatmapSetInfo
{
OnlineID = 1,
- Metadata = new BeatmapMetadata
+ Beatmaps =
{
- Artist = "test author",
- Title = "test title",
- Author = new APIUser
+ new BeatmapInfo
{
- Username = "mapper"
+ Metadata = new BeatmapMetadata
+ {
+ Artist = "test author",
+ Title = "test title",
+ Author = new RealmUser
+ {
+ Username = "mapper"
+ }
+ }
}
}
};
diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
index a7b431fb6e..8c24b2eef8 100644
--- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
+++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
@@ -60,9 +60,8 @@ namespace osu.Game.Tests.Online
testBeatmapInfo = getTestBeatmapInfo(testBeatmapFile);
testBeatmapSet = testBeatmapInfo.BeatmapSet;
- var existing = beatmaps.QueryBeatmapSet(s => s.OnlineID == testBeatmapSet.OnlineID);
- if (existing != null)
- beatmaps.Delete(existing);
+ ContextFactory.Context.Write(r => r.RemoveAll());
+ ContextFactory.Context.Write(r => r.RemoveAll());
selectedItem.Value = new PlaylistItem
{
@@ -103,10 +102,10 @@ namespace osu.Game.Tests.Online
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely());
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
- AddStep("delete beatmap", () => beatmaps.Delete(beatmaps.QueryBeatmapSet(b => b.OnlineID == testBeatmapSet.OnlineID)));
+ AddStep("delete beatmap", () => beatmaps.Delete(beatmaps.QueryBeatmapSet(b => b.OnlineID == testBeatmapSet.OnlineID)!.Value));
addAvailabilityCheckStep("state not downloaded", BeatmapAvailability.NotDownloaded);
- AddStep("undelete beatmap", () => beatmaps.Undelete(beatmaps.QueryBeatmapSet(b => b.OnlineID == testBeatmapSet.OnlineID)));
+ AddStep("undelete beatmap", () => beatmaps.Undelete(beatmaps.QueryBeatmapSet(b => b.OnlineID == testBeatmapSet.OnlineID)!.Value));
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
}
@@ -154,7 +153,6 @@ namespace osu.Game.Tests.Online
Debug.Assert(info.BeatmapSet != null);
info.BeatmapSet.Beatmaps.Add(info);
- info.BeatmapSet.Metadata = info.Metadata;
info.MD5Hash = stream.ComputeMD5Hash();
info.Hash = stream.ComputeSHA2Hash();
}
@@ -168,22 +166,22 @@ namespace osu.Game.Tests.Online
public Task> CurrentImportTask { get; private set; }
- public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore resources, GameHost host = null, WorkingBeatmap defaultBeatmap = null)
+ public TestBeatmapManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore resources, GameHost host = null, WorkingBeatmap defaultBeatmap = null)
: base(storage, contextFactory, rulesets, api, audioManager, resources, host, defaultBeatmap)
{
}
- 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;
}
diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs
index 445394fc77..1d99a5c20d 100644
--- a/osu.Game.Tests/Resources/TestResources.cs
+++ b/osu.Game.Tests/Resources/TestResources.cs
@@ -97,7 +97,6 @@ namespace osu.Game.Tests.Resources
OnlineID = setId,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
DateAdded = DateTimeOffset.UtcNow,
- Metadata = metadata
};
foreach (var b in getBeatmaps(difficultyCount ?? RNG.Next(1, 20)))
@@ -131,8 +130,8 @@ namespace osu.Game.Tests.Resources
StarRating = diff,
Length = length,
BPM = bpm,
+ Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
Ruleset = rulesetInfo,
- RulesetID = rulesetInfo.ID ?? -1,
Metadata = metadata,
BaseDifficulty = new BeatmapDifficulty
{
@@ -166,7 +165,6 @@ namespace osu.Game.Tests.Resources
},
BeatmapInfo = beatmap,
Ruleset = beatmap.Ruleset,
- RulesetID = beatmap.Ruleset.ID ?? 0,
Mods = new Mod[] { new TestModHardRock(), new TestModDoubleTime() },
TotalScore = 2845370,
Accuracy = 0.95,
diff --git a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
index bbc92b7817..dd12c94855 100644
--- a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
+++ b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
@@ -8,8 +8,8 @@ using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Extensions;
using osu.Framework.Platform;
-using osu.Game.Beatmaps;
using osu.Game.IO.Archives;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Mods;
@@ -17,6 +17,8 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
+using osu.Game.Tests.Beatmaps.IO;
+using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Scores.IO
{
@@ -31,6 +33,8 @@ namespace osu.Game.Tests.Scores.IO
{
var osu = LoadOsuIntoHost(host, true);
+ var beatmap = BeatmapImportHelper.LoadOszIntoOsu(osu, TestResources.GetQuickTestBeatmapForImport()).GetResultSafely();
+
var toImport = new ScoreInfo
{
Rank = ScoreRank.B,
@@ -41,6 +45,8 @@ namespace osu.Game.Tests.Scores.IO
User = new APIUser { Username = "Test user" },
Date = DateTimeOffset.Now,
OnlineID = 12345,
+ Ruleset = new OsuRuleset().RulesetInfo,
+ BeatmapInfo = beatmap.Beatmaps.First()
};
var imported = await LoadScoreIntoOsu(osu, toImport);
@@ -49,7 +55,6 @@ namespace osu.Game.Tests.Scores.IO
Assert.AreEqual(toImport.TotalScore, imported.TotalScore);
Assert.AreEqual(toImport.Accuracy, imported.Accuracy);
Assert.AreEqual(toImport.MaxCombo, imported.MaxCombo);
- Assert.AreEqual(toImport.Combo, imported.Combo);
Assert.AreEqual(toImport.User.Username, imported.User.Username);
Assert.AreEqual(toImport.Date, imported.Date);
Assert.AreEqual(toImport.OnlineID, imported.OnlineID);
@@ -70,8 +75,13 @@ namespace osu.Game.Tests.Scores.IO
{
var osu = LoadOsuIntoHost(host, true);
+ var beatmap = BeatmapImportHelper.LoadOszIntoOsu(osu, TestResources.GetQuickTestBeatmapForImport()).GetResultSafely();
+
var toImport = new ScoreInfo
{
+ User = new APIUser { Username = "Test user" },
+ BeatmapInfo = beatmap.Beatmaps.First(),
+ Ruleset = new OsuRuleset().RulesetInfo,
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
};
@@ -96,8 +106,13 @@ namespace osu.Game.Tests.Scores.IO
{
var osu = LoadOsuIntoHost(host, true);
+ var beatmap = BeatmapImportHelper.LoadOszIntoOsu(osu, TestResources.GetQuickTestBeatmapForImport()).GetResultSafely();
+
var toImport = new ScoreInfo
{
+ User = new APIUser { Username = "Test user" },
+ BeatmapInfo = beatmap.Beatmaps.First(),
+ Ruleset = new OsuRuleset().RulesetInfo,
Statistics = new Dictionary
{
{ HitResult.Perfect, 100 },
@@ -117,43 +132,6 @@ namespace osu.Game.Tests.Scores.IO
}
}
- [Test]
- public async Task TestImportWithDeletedBeatmapSet()
- {
- using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
- {
- try
- {
- var osu = LoadOsuIntoHost(host, true);
-
- var toImport = new ScoreInfo
- {
- Hash = Guid.NewGuid().ToString(),
- Statistics = new Dictionary
- {
- { HitResult.Perfect, 100 },
- { HitResult.Miss, 50 }
- }
- };
-
- var imported = await LoadScoreIntoOsu(osu, toImport);
-
- var beatmapManager = osu.Dependencies.Get();
- var scoreManager = osu.Dependencies.Get();
-
- beatmapManager.Delete(beatmapManager.QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == imported.BeatmapInfo.ID)));
- Assert.That(scoreManager.Query(s => s.Equals(imported)).DeletePending, Is.EqualTo(true));
-
- var secondImport = await LoadScoreIntoOsu(osu, imported);
- Assert.That(secondImport, Is.Null);
- }
- finally
- {
- host.Exit();
- }
- }
- }
-
[Test]
public async Task TestOnlineScoreIsAvailableLocally()
{
@@ -163,12 +141,25 @@ namespace osu.Game.Tests.Scores.IO
{
var osu = LoadOsuIntoHost(host, true);
- await LoadScoreIntoOsu(osu, new ScoreInfo { OnlineID = 2 }, new TestArchiveReader());
+ var beatmap = BeatmapImportHelper.LoadOszIntoOsu(osu, TestResources.GetQuickTestBeatmapForImport()).GetResultSafely();
+
+ await LoadScoreIntoOsu(osu, new ScoreInfo
+ {
+ User = new APIUser { Username = "Test user" },
+ BeatmapInfo = beatmap.Beatmaps.First(),
+ Ruleset = new OsuRuleset().RulesetInfo,
+ OnlineID = 2
+ }, new TestArchiveReader());
var scoreManager = osu.Dependencies.Get();
// Note: A new score reference is used here since the import process mutates the original object to set an ID
- Assert.That(scoreManager.IsAvailableLocally(new ScoreInfo { OnlineID = 2 }));
+ Assert.That(scoreManager.IsAvailableLocally(new ScoreInfo
+ {
+ User = new APIUser { Username = "Test user" },
+ BeatmapInfo = beatmap.Beatmaps.First(),
+ OnlineID = 2
+ }));
}
finally
{
@@ -179,15 +170,13 @@ namespace osu.Game.Tests.Scores.IO
public static async Task LoadScoreIntoOsu(OsuGameBase osu, ScoreInfo score, ArchiveReader archive = null)
{
- var beatmapManager = osu.Dependencies.Get();
-
- score.BeatmapInfo ??= beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
- score.Ruleset ??= new OsuRuleset().RulesetInfo;
+ // clone to avoid attaching the input score to realm.
+ score = score.DeepClone();
var scoreManager = osu.Dependencies.Get();
await scoreManager.Import(score, archive);
- return scoreManager.GetAllUsableScores().FirstOrDefault();
+ return scoreManager.Query(_ => true);
}
internal class TestArchiveReader : ArchiveReader
diff --git a/osu.Game.Tests/Scores/IO/TestScoreEquality.cs b/osu.Game.Tests/Scores/IO/TestScoreEquality.cs
index 42fcb3acab..f898774ce6 100644
--- a/osu.Game.Tests/Scores/IO/TestScoreEquality.cs
+++ b/osu.Game.Tests/Scores/IO/TestScoreEquality.cs
@@ -1,6 +1,7 @@
// 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 NUnit.Framework;
using osu.Game.Scoring;
@@ -29,8 +30,8 @@ namespace osu.Game.Tests.Scores.IO
[Test]
public void TestNonMatchingByPrimaryKey()
{
- ScoreInfo score1 = new ScoreInfo { ID = 1 };
- ScoreInfo score2 = new ScoreInfo { ID = 2 };
+ ScoreInfo score1 = new ScoreInfo { ID = Guid.NewGuid() };
+ ScoreInfo score2 = new ScoreInfo { ID = Guid.NewGuid() };
Assert.That(score1, Is.Not.EqualTo(score2));
}
@@ -38,8 +39,10 @@ namespace osu.Game.Tests.Scores.IO
[Test]
public void TestMatchingByPrimaryKey()
{
- ScoreInfo score1 = new ScoreInfo { ID = 1 };
- ScoreInfo score2 = new ScoreInfo { ID = 1 };
+ Guid id = Guid.NewGuid();
+
+ ScoreInfo score1 = new ScoreInfo { ID = id };
+ ScoreInfo score2 = new ScoreInfo { ID = id };
Assert.That(score1, Is.EqualTo(score2));
}
diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs
index c20ab84a68..fe0423dcfc 100644
--- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs
+++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs
@@ -26,8 +26,12 @@ namespace osu.Game.Tests.Skins
private void load()
{
var imported = beatmaps.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-beatmap.osz"))).GetResultSafely();
- beatmap = beatmaps.GetWorkingBeatmap(imported.Value.Beatmaps[0]);
- beatmap.LoadTrack();
+
+ imported?.PerformRead(s =>
+ {
+ beatmap = beatmaps.GetWorkingBeatmap(s.Beatmaps[0]);
+ beatmap.LoadTrack();
+ });
}
[Test]
diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
index 5b2cf877ba..4ab4c08353 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
@@ -50,6 +50,7 @@ namespace osu.Game.Tests.Visual.Background
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(new OsuConfigManager(LocalStorage));
+ Dependencies.Cache(ContextFactory);
manager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
@@ -387,6 +388,9 @@ namespace osu.Game.Tests.Visual.Background
while (BlockLoad && !token.IsCancellationRequested)
Thread.Sleep(1);
+ if (!LoadedBeatmapSuccessfully)
+ return;
+
StoryboardEnabled = config.GetBindable(OsuSetting.ShowStoryboard);
DrawableRuleset.IsPaused.BindTo(IsPaused);
}
diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
index 7b5e1f4ec7..94b693363a 100644
--- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
+++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
@@ -204,7 +204,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
{
var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineID == online_id);
- if (beatmap != null) beatmaps.Delete(beatmap);
+ if (beatmap != null) beatmaps.Delete(beatmap.Value);
});
}
diff --git a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs
index d2b0f7324b..18572ac211 100644
--- a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs
+++ b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs
@@ -38,6 +38,7 @@ namespace osu.Game.Tests.Visual.Collections
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs b/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs
index 00f2979691..10917df075 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs
@@ -11,6 +11,7 @@ using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterfaceV2;
+using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Setup;
using osuTK.Input;
@@ -25,7 +26,13 @@ namespace osu.Game.Tests.Visual.Editing
[SetUpSteps]
public void SetUp()
{
- AddStep("create blank beatmap", () => editorBeatmap = new EditorBeatmap(new Beatmap()));
+ AddStep("create blank beatmap", () => editorBeatmap = new EditorBeatmap(new Beatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo
+ }
+ }));
AddStep("create section", () => Child = new DependencyProvidingContainer
{
RelativeSizeAxes = Axes.Both,
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs
index 516305079b..243bb71e26 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs
@@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.Editing
public override void SetUpSteps()
{
- AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely());
+ AddStep("import test beatmap", () => importedBeatmapSet = BeatmapImportHelper.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely());
base.SetUpSteps();
}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs b/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs
index d1efd22d6f..0d9e06e471 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose.Components;
@@ -29,7 +30,13 @@ namespace osu.Game.Tests.Visual.Editing
public TestSceneDistanceSnapGrid()
{
- editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo
+ }
+ });
editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length });
}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs
index db20d3c7ba..2386446e96 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs
@@ -49,8 +49,7 @@ namespace osu.Game.Tests.Visual.Editing
public void TestCreateNewBeatmap()
{
AddStep("save beatmap", () => Editor.Save());
- AddAssert("new beatmap persisted", () => EditorBeatmap.BeatmapInfo.IsManaged);
- AddAssert("new beatmap in database", () => beatmapManager.QueryBeatmapSet(s => s.ID == EditorBeatmap.BeatmapInfo.BeatmapSet.ID)?.DeletePending == false);
+ AddAssert("new beatmap in database", () => beatmapManager.QueryBeatmapSet(s => s.ID == EditorBeatmap.BeatmapInfo.BeatmapSet.ID)?.Value.DeletePending == false);
}
[Test]
@@ -66,7 +65,7 @@ namespace osu.Game.Tests.Visual.Editing
});
AddUntilStep("wait for exit", () => !Editor.IsCurrentScreen());
- AddAssert("new beatmap not persisted", () => beatmapManager.QueryBeatmapSet(s => s.ID == editorBeatmap.BeatmapInfo.BeatmapSet.ID)?.DeletePending == true);
+ AddAssert("new beatmap not persisted", () => beatmapManager.QueryBeatmapSet(s => s.ID == editorBeatmap.BeatmapInfo.BeatmapSet.ID)?.Value.DeletePending == true);
}
[Test]
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
index 6d48ef3ba7..bb630e5d5c 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Editing
public override void SetUpSteps()
{
- AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game).GetResultSafely());
+ AddStep("import test beatmap", () => importedBeatmapSet = BeatmapImportHelper.LoadOszIntoOsu(game).GetResultSafely());
base.SetUpSteps();
}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs
index eee0d6672c..145d738f60 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs
@@ -39,9 +39,16 @@ namespace osu.Game.Tests.Visual.Editing
{
Beatmap.Value = CreateWorkingBeatmap(new Beatmap
{
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo
+ },
HitObjects = new List
{
- new HitCircle { Position = new Vector2(256, 192), Scale = 0.5f },
+ new HitCircle
+ {
+ Position = new Vector2(256, 192), Scale = 0.5f
+ },
new HitCircle { Position = new Vector2(344, 148), Scale = 0.5f },
new Slider
{
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs b/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs
index 4621436cc6..4ecfb0975b 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs
@@ -5,6 +5,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterfaceV2;
+using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Setup;
@@ -13,7 +14,13 @@ namespace osu.Game.Tests.Visual.Editing
public class TestSceneMetadataSection : OsuTestScene
{
[Cached]
- private EditorBeatmap editorBeatmap = new EditorBeatmap(new Beatmap());
+ private EditorBeatmap editorBeatmap = new EditorBeatmap(new Beatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo
+ },
+ });
private TestMetadataSection metadataSection;
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs
index 03e78ce854..2f6cf46b21 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs
@@ -29,7 +29,13 @@ namespace osu.Game.Tests.Visual.Editing
public TestSceneSetupScreen()
{
- editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ editorBeatmap = new EditorBeatmap(new OsuBeatmap
+ {
+ BeatmapInfo =
+ {
+ Ruleset = new OsuRuleset().RulesetInfo
+ }
+ });
}
[Test]
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
index cf5aadde6d..a4a4f351ec 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
@@ -237,7 +237,7 @@ namespace osu.Game.Tests.Visual.Gameplay
createPlayerTest(false, r =>
{
var beatmap = createTestBeatmap(r);
- beatmap.BeatmapInfo.OnlineID = null;
+ beatmap.BeatmapInfo.OnlineID = -1;
return beatmap;
});
@@ -255,7 +255,15 @@ namespace osu.Game.Tests.Visual.Gameplay
{
prepareTestAPI(true);
- createPlayerTest(false, createRuleset: () => new OsuRuleset { RulesetInfo = { OnlineID = rulesetId ?? -1 } });
+ createPlayerTest(false, createRuleset: () => new OsuRuleset
+ {
+ RulesetInfo =
+ {
+ Name = "custom",
+ ShortName = $"custom{rulesetId}",
+ OnlineID = rulesetId ?? -1
+ }
+ });
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
index 3168c4b94e..8199389b36 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
@@ -6,16 +6,18 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses;
-using osu.Game.Scoring;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
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;
+using osu.Game.Tests.Resources;
using osuTK.Input;
using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
@@ -29,6 +31,18 @@ namespace osu.Game.Tests.Visual.Gameplay
private TestReplayDownloadButton downloadButton;
+ [Resolved]
+ private BeatmapManager beatmapManager { get; set; }
+
+ [Resolved]
+ private ScoreManager scoreManager { get; set; }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
+ }
+
[Test]
public void TestDisplayStates()
{
@@ -115,9 +129,6 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType().First().Enabled.Value);
}
- [Resolved]
- private ScoreManager scoreManager { get; set; }
-
[Test]
public void TestScoreImportThenDelete()
{
@@ -176,7 +187,7 @@ namespace osu.Game.Tests.Visual.Gameplay
Id = 39828,
Username = @"WubWoofWolf",
}
- }.CreateScoreInfo(rulesets, CreateBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo);
+ }.CreateScoreInfo(rulesets, beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First());
}
private class TestReplayDownloadButton : ReplayDownloadButton
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
index e6361a15d7..4eab1a21da 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
@@ -64,7 +64,11 @@ namespace osu.Game.Tests.Visual.Gameplay
Recorder = recorder = new TestReplayRecorder(new Score
{
Replay = replay,
- ScoreInfo = { BeatmapInfo = gameplayState.Beatmap.BeatmapInfo }
+ ScoreInfo =
+ {
+ BeatmapInfo = gameplayState.Beatmap.BeatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
+ }
})
{
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos),
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs
index 242eca0bbc..8b7e1a1d85 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs
@@ -61,8 +61,8 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("import beatmap", () =>
{
- importedBeatmap = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
- importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.RulesetID == 0).OnlineID ?? -1;
+ importedBeatmap = BeatmapImportHelper.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
+ importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.RulesetID == 0).OnlineID;
});
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs
index f7e9a1fe16..4790bd44db 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs
@@ -372,7 +372,14 @@ namespace osu.Game.Tests.Visual.Gameplay
internal class TestReplayRecorder : ReplayRecorder
{
public TestReplayRecorder()
- : base(new Score { ScoreInfo = { BeatmapInfo = new BeatmapInfo() } })
+ : base(new Score
+ {
+ ScoreInfo =
+ {
+ BeatmapInfo = new BeatmapInfo(),
+ Ruleset = new OsuRuleset().RulesetInfo,
+ }
+ })
{
}
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
index ee9363fa12..3ebc64cd0b 100644
--- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
+++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
@@ -39,7 +39,10 @@ namespace osu.Game.Tests.Visual.Menus
AddStep("import beatmap with track", () =>
{
var setWithTrack = Game.BeatmapManager.Import(new ImportTask(TestResources.GetTestBeatmapForImport())).GetResultSafely();
- Beatmap.Value = Game.BeatmapManager.GetWorkingBeatmap(setWithTrack.Value.Beatmaps.First());
+ setWithTrack?.PerformRead(s =>
+ {
+ Beatmap.Value = Game.BeatmapManager.GetWorkingBeatmap(s.Beatmaps.First());
+ });
});
AddStep("bind to track change", () =>
diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
index c4d7bd7e6a..d4282ff21e 100644
--- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
@@ -49,6 +49,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
}
public override void SetUpSteps()
@@ -58,7 +59,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
- importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
InitialBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
OtherBeatmap = importedSet.Beatmaps.Last(b => b.RulesetID == 0);
});
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
index 147bbf2626..99c867b014 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
@@ -17,7 +17,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;
using osu.Game.Rulesets.Osu;
@@ -45,6 +45,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
}
[Test]
@@ -153,17 +154,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
public void TestDownloadButtonHiddenWhenBeatmapExists()
{
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
+ ILive imported = null;
- AddStep("import beatmap", () => manager.Import(beatmap.BeatmapSet).WaitSafely());
+ Debug.Assert(beatmap.BeatmapSet != null);
- createPlaylistWithBeatmaps(beatmap);
+ AddStep("import beatmap", () => imported = manager.Import(beatmap.BeatmapSet).GetResultSafely());
+
+ createPlaylistWithBeatmaps(() => imported.PerformRead(s => s.Beatmaps.Detach()));
assertDownloadButtonVisible(false);
- AddStep("delete beatmap set", () => manager.Delete(manager.QueryBeatmapSets(_ => true).Single()));
+ AddStep("delete beatmap set", () => imported.PerformWrite(s => s.DeletePending = true));
assertDownloadButtonVisible(true);
- AddStep("undelete beatmap set", () => manager.Undelete(manager.QueryBeatmapSets(_ => true).Single()));
+ AddStep("undelete beatmap set", () => imported.PerformWrite(s => s.DeletePending = false));
assertDownloadButtonVisible(false);
void assertDownloadButtonVisible(bool visible) => AddUntilStep($"download button {(visible ? "shown" : "hidden")}",
@@ -179,7 +183,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
var byChecksum = CreateAPIBeatmap();
byChecksum.Checksum = "1337"; // Some random checksum that does not exist locally.
- createPlaylistWithBeatmaps(byOnlineId, byChecksum);
+ createPlaylistWithBeatmaps(() => new[] { byOnlineId, byChecksum });
AddAssert("download buttons shown", () => playlist.ChildrenOfType().All(d => d.IsPresent));
}
@@ -193,7 +197,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
beatmap.BeatmapSet.HasExplicitContent = true;
- createPlaylistWithBeatmaps(beatmap);
+ createPlaylistWithBeatmaps(() => new[] { beatmap });
}
[Test]
@@ -305,7 +309,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()
@@ -325,7 +329,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
}
- private void createPlaylistWithBeatmaps(params IBeatmapInfo[] beatmaps)
+ private void createPlaylistWithBeatmaps(Func> beatmaps)
{
AddStep("create playlist", () =>
{
@@ -338,7 +342,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
int index = 0;
- foreach (var b in beatmaps)
+ foreach (var b in beatmaps())
{
playlist.Items.Add(new PlaylistItem
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
index 61058bc87a..9d67742e4d 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
@@ -47,9 +47,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load()
{
- importedSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
+ importedSet = BeatmapImportHelper.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
- importedBeatmapId = importedBeatmap.OnlineID ?? -1;
+ importedBeatmapId = importedBeatmap.OnlineID;
}
[SetUp]
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
index 3d8c5298dc..373b165acc 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
@@ -62,7 +62,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
}
public override void SetUpSteps()
@@ -72,7 +73,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
- importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
});
AddStep("load multiplayer", () => LoadScreen(multiplayerComponents = new TestMultiplayerComponents()));
@@ -588,7 +589,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("restore beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
- importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
});
AddUntilStep("play started", () => multiplayerComponents.CurrentScreen is SpectatorScreen);
@@ -827,7 +828,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
AddStep("add item as other user", () => client.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(new PlaylistItem
{
- BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo.OnlineID ?? -1
+ BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo.OnlineID
})));
AddUntilStep("item arrived in playlist", () => client.Room?.Playlist.Count == 2);
@@ -858,7 +859,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
AddStep("add item as other user", () => client.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(new PlaylistItem
{
- BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo.OnlineID ?? -1
+ BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo.OnlineID
})));
AddUntilStep("item arrived in playlist", () => client.Room?.Playlist.Count == 2);
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs
index 07a8ef66e1..9b8e67b07a 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
foreach (int user in users)
{
- SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID ?? 0);
+ SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID);
multiplayerUsers.Add(OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true));
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs
index 1237a21e94..8a78c12042 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs
@@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
foreach (int user in users)
{
- SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID ?? 0);
+ SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID);
var roomUser = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true);
roomUser.MatchState = new TeamVersusUserState
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
index bd4b38b9c0..181b0c71f2 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
@@ -44,6 +44,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
beatmaps = new List();
@@ -58,7 +59,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
OnlineID = 10,
Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
- Metadata = metadata,
DateAdded = DateTimeOffset.UtcNow
};
@@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
var beatmap = new BeatmapInfo
{
- Ruleset = rulesets.GetRuleset(i % 4),
+ Ruleset = rulesets.GetRuleset(i % 4) ?? throw new InvalidOperationException(),
OnlineID = beatmapId,
Length = length,
BPM = bpm,
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs
index 52e46ef5af..012a2fd960 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs
@@ -40,9 +40,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
+
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
- importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
}
[SetUp]
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
index 464c0ea5b6..d547b42891 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
@@ -35,6 +35,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
}
[SetUp]
@@ -55,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
- importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
});
@@ -169,7 +170,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
})));
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs
index 29daff546d..965b142ed7 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs
@@ -39,7 +39,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
}
public override void SetUpSteps()
@@ -60,7 +61,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
- importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
});
@@ -126,7 +127,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);
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs
index 8f51b1e381..1c346e09d5 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs
@@ -42,6 +42,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
+
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
}
@@ -50,7 +52,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AvailabilityTracker.SelectedItem.BindTo(selectedItem);
- importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
selectedItem.Value = new PlaylistItem
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs
index 4674601f28..44a1745eee 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
PlaylistItem playlistItem = new PlaylistItem
{
- BeatmapID = beatmapInfo.OnlineID ?? -1,
+ BeatmapID = beatmapInfo.OnlineID,
};
Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem));
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs
index d4ff9f8c41..221732910b 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs
@@ -43,6 +43,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
+
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
}
@@ -51,7 +53,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AvailabilityTracker.SelectedItem.BindTo(selectedItem);
- importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
selectedItem.Value = new PlaylistItem
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs
index f5df8d7507..dfc16c44f2 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
PlaylistItem playlistItem = new PlaylistItem
{
- BeatmapID = beatmapInfo.OnlineID ?? -1,
+ BeatmapID = beatmapInfo.OnlineID,
};
SortedDictionary teamScores = new SortedDictionary
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs
index 93ccd5f1e1..e63e58824f 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs
@@ -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()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
index 08fcac125d..0b0006e437 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
@@ -36,6 +36,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
var beatmapSet = TestResources.CreateTestBeatmapSetInfo();
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
index d20fbd3539..39cde0ad87 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
@@ -44,6 +44,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
}
public override void SetUpSteps()
@@ -53,7 +54,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("import beatmap", () =>
{
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
- importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
+ importedSet = beatmaps.GetAllUsableBeatmapSets().First();
});
AddStep("load multiplayer", () => LoadScreen(multiplayerComponents = new TestMultiplayerComponents()));
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
index 7a44a7643d..0f314242b4 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
@@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Navigation
AddStep("close settings", () => Game.Settings.Hide());
- AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
PushAndConfirm(() => new PlaySongSelect());
AddStep("enter gameplay", () => InputManager.Key(Key.Enter));
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs b/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs
index 701ab480f6..22a00a3e5a 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs
@@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual.Navigation
PushAndConfirm(() => songSelect = new TestSceneScreenNavigation.TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
- AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).WaitSafely());
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadOszIntoOsu(Game, virtualTrack: true).WaitSafely());
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
AddStep("press enter", () => InputManager.Key(Key.Enter));
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs
index 28ff776d5f..b8d1636ea0 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs
@@ -12,11 +12,9 @@ using osu.Framework.Platform;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
-using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Input;
using osu.Game.Input.Bindings;
-using osu.Game.IO;
using osu.Game.Online.API;
using osu.Game.Online.Chat;
using osu.Game.Overlays;
@@ -58,7 +56,6 @@ namespace osu.Game.Tests.Visual.Navigation
private IReadOnlyList requiredGameBaseDependencies => new[]
{
typeof(OsuGameBase),
- typeof(DatabaseContextFactory),
typeof(Bindable),
typeof(IBindable),
typeof(Bindable>),
@@ -69,7 +66,6 @@ namespace osu.Game.Tests.Visual.Navigation
typeof(ISkinSource),
typeof(IAPIProvider),
typeof(RulesetStore),
- typeof(FileStore),
typeof(ScoreManager),
typeof(BeatmapManager),
typeof(IRulesetConfigCache),
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs
index 24f5808961..1ebceed15d 100644
--- a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs
@@ -173,7 +173,7 @@ namespace osu.Game.Tests.Visual.Navigation
private void importAndWaitForSongSelect()
{
- AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
PushAndConfirm(() => new TestPlaySongSelect());
AddUntilStep("beatmap updated", () => Game.Beatmap.Value.BeatmapSetInfo.OnlineID == 241526);
}
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
index 6420e7b849..69b30ec6a0 100644
--- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
@@ -97,7 +97,6 @@ namespace osu.Game.Tests.Visual.Navigation
BeatmapSetInfo imported = null;
AddStep($"import beatmap {i}", () =>
{
- var difficulty = new BeatmapDifficulty();
var metadata = new BeatmapMetadata
{
Artist = "SomeArtist",
@@ -109,25 +108,24 @@ namespace osu.Game.Tests.Visual.Navigation
{
Hash = Guid.NewGuid().ToString(),
OnlineID = i,
- Metadata = metadata,
Beatmaps =
{
new BeatmapInfo
{
OnlineID = i * 1024,
Metadata = metadata,
- BaseDifficulty = difficulty,
+ BaseDifficulty = new BeatmapDifficulty(),
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
},
new BeatmapInfo
{
OnlineID = i * 2048,
Metadata = metadata,
- BaseDifficulty = difficulty,
+ BaseDifficulty = new BeatmapDifficulty(),
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
},
}
- }).GetResultSafely().Value;
+ }).GetResultSafely()?.Value;
});
AddAssert($"import {i} succeeded", () => imported != null);
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
index 5dc1808c12..f9649db135 100644
--- a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
@@ -8,6 +8,7 @@ using osu.Framework.Extensions;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
+using osu.Game.Online.API;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
@@ -28,37 +29,38 @@ namespace osu.Game.Tests.Visual.Navigation
{
AddStep("import beatmap", () =>
{
- var difficulty = new BeatmapDifficulty();
- var metadata = new BeatmapMetadata
- {
- Artist = "SomeArtist",
- AuthorString = "SomeAuthor",
- Title = "import"
- };
-
beatmap = Game.BeatmapManager.Import(new BeatmapSetInfo
{
Hash = Guid.NewGuid().ToString(),
OnlineID = 1,
- Metadata = metadata,
Beatmaps =
{
new BeatmapInfo
{
OnlineID = 1 * 1024,
- Metadata = metadata,
- BaseDifficulty = difficulty,
+ Metadata = new BeatmapMetadata
+ {
+ Artist = "SomeArtist",
+ AuthorString = "SomeAuthor",
+ Title = "import"
+ },
+ BaseDifficulty = new BeatmapDifficulty(),
Ruleset = new OsuRuleset().RulesetInfo
},
new BeatmapInfo
{
OnlineID = 1 * 2048,
- Metadata = metadata,
- BaseDifficulty = difficulty,
+ Metadata = new BeatmapMetadata
+ {
+ Artist = "SomeArtist",
+ AuthorString = "SomeAuthor",
+ Title = "import"
+ },
+ BaseDifficulty = new BeatmapDifficulty(),
Ruleset = new OsuRuleset().RulesetInfo
},
}
- }).GetResultSafely().Value;
+ }).GetResultSafely()?.Value;
});
}
@@ -131,7 +133,8 @@ namespace osu.Game.Tests.Visual.Navigation
Hash = Guid.NewGuid().ToString(),
OnlineID = i,
BeatmapInfo = beatmap.Beatmaps.First(),
- Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
+ Ruleset = ruleset ?? new OsuRuleset().RulesetInfo,
+ User = new GuestUser(),
}).GetResultSafely().Value;
});
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
index 60aabf5639..89dca77af4 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
@@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Navigation
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
- AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
@@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual.Navigation
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
- AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
@@ -139,7 +139,7 @@ namespace osu.Game.Tests.Visual.Navigation
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
- AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).WaitSafely());
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadOszIntoOsu(Game, virtualTrack: true).WaitSafely());
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneStartupRuleset.cs b/osu.Game.Tests/Visual/Navigation/TestSceneStartupRuleset.cs
new file mode 100644
index 0000000000..85dd501fd3
--- /dev/null
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneStartupRuleset.cs
@@ -0,0 +1,32 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Development;
+using osu.Game.Configuration;
+
+namespace osu.Game.Tests.Visual.Navigation
+{
+ [TestFixture]
+ public class TestSceneStartupRuleset : OsuGameTestScene
+ {
+ protected override TestOsuGame CreateTestGame()
+ {
+ // Must be done in this function due to the RecycleLocalStorage call just before.
+ var config = DebugUtils.IsDebugBuild
+ ? new DevelopmentOsuConfigManager(LocalStorage)
+ : new OsuConfigManager(LocalStorage);
+
+ config.SetValue(OsuSetting.Ruleset, "mania");
+ config.Save();
+
+ return base.CreateTestGame();
+ }
+
+ [Test]
+ public void TestRulesetConsumed()
+ {
+ AddUntilStep("ruleset correct", () => Game.Ruleset.Value.ShortName == "mania");
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs
index 21bf8d1c5a..d9f01622da 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs
@@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Online
{
var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineID == 241526);
- if (beatmap != null) beatmaps.Delete(beatmap);
+ if (beatmap != null) beatmaps.Delete(beatmap.Value);
});
}
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs
index e9210496ca..11df115b1a 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs
@@ -44,6 +44,10 @@ namespace osu.Game.Tests.Visual.Playlists
requestComplete = false;
totalCount = 0;
bindHandler();
+
+ // beatmap is required to be an actual beatmap so the scores can get their scores correctly calculated for standardised scoring.
+ // else the tests that rely on ordering will fall over.
+ Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
});
[Test]
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
index e59884f4f4..bc9f759bdd 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@@ -18,6 +19,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.OnlinePlay.Components;
+using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
@@ -33,13 +35,14 @@ namespace osu.Game.Tests.Visual.Playlists
private TestPlaylistsRoomSubScreen match;
- private ILive importedBeatmap;
+ private BeatmapSetInfo importedBeatmap;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
}
[SetUpSteps]
@@ -64,13 +67,15 @@ namespace osu.Game.Tests.Visual.Playlists
room.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
room.Playlist.Add(new PlaylistItem
{
- Beatmap = { Value = importedBeatmap.Value.Beatmaps.First() },
+ Beatmap = { Value = importedBeatmap.Beatmaps.First() },
Ruleset = { Value = new OsuRuleset().RulesetInfo }
});
});
AddUntilStep("Progress details are hidden", () => match.ChildrenOfType().FirstOrDefault()?.Parent.Alpha == 0);
+ AddUntilStep("Leaderboard shows two aggregate scores", () => match.ChildrenOfType().Count(s => s.ScoreText.Text != "0") == 2);
+
AddStep("start match", () => match.ChildrenOfType().First().TriggerClick());
AddUntilStep("player loader loaded", () => Stack.CurrentScreen is PlayerLoader);
}
@@ -87,7 +92,7 @@ namespace osu.Game.Tests.Visual.Playlists
room.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
room.Playlist.Add(new PlaylistItem
{
- Beatmap = { Value = importedBeatmap.Value.Beatmaps.First() },
+ Beatmap = { Value = importedBeatmap.Beatmaps.First() },
Ruleset = { Value = new OsuRuleset().RulesetInfo }
});
});
@@ -104,7 +109,7 @@ namespace osu.Game.Tests.Visual.Playlists
room.Host.Value = API.LocalUser.Value;
room.Playlist.Add(new PlaylistItem
{
- Beatmap = { Value = importedBeatmap.Value.Beatmaps.First() },
+ Beatmap = { Value = importedBeatmap.Beatmaps.First() },
Ruleset = { Value = new OsuRuleset().RulesetInfo }
});
});
@@ -121,9 +126,9 @@ namespace osu.Game.Tests.Visual.Playlists
AddStep("store real beatmap values", () =>
{
- realHash = importedBeatmap.Value.Beatmaps[0].MD5Hash;
- realOnlineId = importedBeatmap.Value.Beatmaps[0].OnlineID ?? -1;
- realOnlineSetId = importedBeatmap.Value.OnlineID ?? -1;
+ realHash = importedBeatmap.Beatmaps[0].MD5Hash;
+ realOnlineId = importedBeatmap.Beatmaps[0].OnlineID;
+ realOnlineSetId = importedBeatmap.OnlineID;
});
AddStep("import modified beatmap", () =>
@@ -133,6 +138,7 @@ namespace osu.Game.Tests.Visual.Playlists
BeatmapInfo =
{
OnlineID = realOnlineId,
+ Metadata = new BeatmapMetadata(),
BeatmapSet =
{
OnlineID = realOnlineSetId
@@ -143,6 +149,8 @@ namespace osu.Game.Tests.Visual.Playlists
modifiedBeatmap.HitObjects.Clear();
modifiedBeatmap.HitObjects.Add(new HitCircle { StartTime = 5000 });
+ Debug.Assert(modifiedBeatmap.BeatmapInfo.BeatmapSet != null);
+
manager.Import(modifiedBeatmap.BeatmapInfo.BeatmapSet).WaitSafely();
});
@@ -159,6 +167,7 @@ namespace osu.Game.Tests.Visual.Playlists
{
MD5Hash = realHash,
OnlineID = realOnlineId,
+ Metadata = new BeatmapMetadata(),
BeatmapSet = new BeatmapSetInfo
{
OnlineID = realOnlineSetId,
@@ -185,6 +194,8 @@ namespace osu.Game.Tests.Visual.Playlists
},
};
+ Debug.Assert(originalBeatmap.BeatmapInfo.BeatmapSet != null);
+
manager.Import(originalBeatmap.BeatmapInfo.BeatmapSet).WaitSafely();
});
@@ -202,7 +213,14 @@ namespace osu.Game.Tests.Visual.Playlists
});
}
- private void importBeatmap() => AddStep("import beatmap", () => importedBeatmap = manager.Import(CreateBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).GetResultSafely());
+ private void importBeatmap() => AddStep("import beatmap", () =>
+ {
+ var beatmap = CreateBeatmap(new OsuRuleset().RulesetInfo);
+
+ Debug.Assert(beatmap.BeatmapInfo.BeatmapSet != null);
+
+ importedBeatmap = manager.Import(beatmap.BeatmapInfo.BeatmapSet).GetResultSafely()?.Value.Detach();
+ });
private class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen
{
diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs
index 944941723e..ac736086fd 100644
--- a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs
+++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs
@@ -72,6 +72,7 @@ namespace osu.Game.Tests.Visual.Ranking
Username = "peppy",
},
BeatmapInfo = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
TotalScore = 2845370,
Accuracy = accuracy,
diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs
index 2cb4fb6b6b..8b646df362 100644
--- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs
+++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs
@@ -12,7 +12,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
-using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Models;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
@@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.Ranking
[Test]
public void TestMapWithKnownMapper()
{
- var author = new APIUser { Username = "mapper_name" };
+ var author = new RealmUser { Username = "mapper_name" };
AddStep("show example score", () => showPanel(TestResources.CreateTestScoreInfo(createTestBeatmap(author))));
}
@@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Ranking
{
AddStep("show excess mods score", () =>
{
- var author = new APIUser { Username = "mapper_name" };
+ var author = new RealmUser { Username = "mapper_name" };
var score = TestResources.CreateTestScoreInfo(createTestBeatmap(author));
score.Mods = score.BeatmapInfo.Ruleset.CreateInstance().CreateAllMods().ToArray();
@@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Ranking
[Test]
public void TestMapWithUnknownMapper()
{
- AddStep("show example score", () => showPanel(TestResources.CreateTestScoreInfo(createTestBeatmap(new APIUser()))));
+ AddStep("show example score", () => showPanel(TestResources.CreateTestScoreInfo(createTestBeatmap(new RealmUser()))));
AddAssert("mapped by text not present", () =>
this.ChildrenOfType().All(spriteText => !containsAny(spriteText.Text.ToString(), "mapped", "by")));
@@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Ranking
var ruleset = new OsuRuleset();
var mods = new Mod[] { ruleset.GetAutoplayMod() };
- var beatmap = createTestBeatmap(new APIUser());
+ var beatmap = createTestBeatmap(new RealmUser());
var score = TestResources.CreateTestScoreInfo(beatmap);
@@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.Ranking
private void showPanel(ScoreInfo score) =>
Child = new ExpandedPanelMiddleContentContainer(score);
- private BeatmapInfo createTestBeatmap([NotNull] APIUser author)
+ private BeatmapInfo createTestBeatmap([NotNull] RealmUser author)
{
var beatmap = new TestBeatmap(rulesetStore.GetRuleset(0)).BeatmapInfo;
diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
index 8a0ed2e108..62500babc1 100644
--- a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
+++ b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
@@ -13,8 +13,10 @@ using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
+using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
+using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Screens;
using osu.Game.Screens.Play;
@@ -23,6 +25,7 @@ using osu.Game.Screens.Ranking.Statistics;
using osu.Game.Tests.Resources;
using osuTK;
using osuTK.Input;
+using Realms;
namespace osu.Game.Tests.Visual.Ranking
{
@@ -32,13 +35,22 @@ namespace osu.Game.Tests.Visual.Ranking
[Resolved]
private BeatmapManager beatmaps { get; set; }
+ [Resolved]
+ private RealmContextFactory realmContextFactory { get; set; }
+
protected override void LoadComplete()
{
base.LoadComplete();
- var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0);
- if (beatmapInfo != null)
- Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
+ using (var realm = realmContextFactory.CreateContext())
+ {
+ var beatmapInfo = realm.All()
+ .Filter($"{nameof(BeatmapInfo.Ruleset)}.{nameof(RulesetInfo.OnlineID)} = $0", 0)
+ .FirstOrDefault();
+
+ if (beatmapInfo != null)
+ Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
+ }
}
[Test]
diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs
index f5ad352b9c..e786b85f78 100644
--- a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs
+++ b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs
@@ -7,6 +7,7 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Framework.Utils;
+using osu.Game.Models;
using osu.Game.Scoring;
using osu.Game.Screens.Ranking;
using osu.Game.Tests.Resources;
@@ -157,10 +158,10 @@ namespace osu.Game.Tests.Visual.Ranking
public void TestSelectMultipleScores()
{
var firstScore = TestResources.CreateTestScoreInfo();
- var secondScore = TestResources.CreateTestScoreInfo();
+ firstScore.RealmUser = new RealmUser { Username = "A" };
- firstScore.UserString = "A";
- secondScore.UserString = "B";
+ var secondScore = TestResources.CreateTestScoreInfo();
+ secondScore.RealmUser = new RealmUser { Username = "B" };
createListStep(() => new ScorePanelList());
@@ -178,7 +179,7 @@ namespace osu.Game.Tests.Visual.Ranking
AddStep("select second score", () =>
{
- InputManager.MoveMouseTo(list.ChildrenOfType().Single(p => p.Score == secondScore));
+ InputManager.MoveMouseTo(list.ChildrenOfType().Single(p => p.Score.Equals(secondScore)));
InputManager.Click(MouseButton.Left);
});
@@ -303,6 +304,6 @@ namespace osu.Game.Tests.Visual.Ranking
=> AddUntilStep("first panel centred", () => Precision.AlmostEquals(list.ChildrenOfType().First().ScreenSpaceDrawQuad.Centre.X, list.ScreenSpaceDrawQuad.Centre.X, 1));
private void assertScoreState(ScoreInfo score, bool expanded)
- => AddUntilStep($"score expanded = {expanded}", () => (list.ChildrenOfType().Single(p => p.Score == score).State == PanelState.Expanded) == expanded);
+ => AddUntilStep($"score expanded = {expanded}", () => (list.ChildrenOfType().Single(p => p.Score.Equals(score)).State == PanelState.Expanded) == expanded);
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
index d57b3dec5d..bc3e8553f7 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
@@ -37,7 +37,6 @@ namespace osu.Game.Tests.Visual.SongSelect
private BeatmapInfo exampleBeatmapInfo => new BeatmapInfo
{
- RulesetID = 0,
Ruleset = rulesets.AvailableRulesets.First(),
BaseDifficulty = new BeatmapDifficulty
{
@@ -68,7 +67,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{
AddStep("set beatmap", () => advancedStats.BeatmapInfo = new BeatmapInfo
{
- Ruleset = rulesets.GetRuleset(3),
+ Ruleset = rulesets.GetRuleset(3) ?? throw new InvalidOperationException(),
BaseDifficulty = new BeatmapDifficulty
{
CircleSize = 5,
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
index f637c715a1..0f5bea10e8 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
@@ -6,6 +6,7 @@ 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.Game.Beatmaps;
@@ -27,7 +28,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private RulesetStore rulesets;
private readonly Stack selectedSets = new Stack();
- private readonly HashSet eagerSelectedIDs = new HashSet();
+ private readonly HashSet eagerSelectedIDs = new HashSet();
private BeatmapInfo currentSelection => carousel.SelectedBeatmapInfo;
@@ -75,7 +76,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{
AddStep("store selection", () => selection = carousel.SelectedBeatmapInfo);
if (isIterating)
- AddUntilStep("selection changed", () => !carousel.SelectedBeatmapInfo.Equals(selection));
+ AddUntilStep("selection changed", () => !carousel.SelectedBeatmapInfo?.Equals(selection) == true);
else
AddUntilStep("selection not changed", () => carousel.SelectedBeatmapInfo.Equals(selection));
}
@@ -377,11 +378,7 @@ namespace osu.Game.Tests.Visual.SongSelect
var rulesetBeatmapSet = TestResources.CreateTestBeatmapSetInfo(1);
var taikoRuleset = rulesets.AvailableRulesets.ElementAt(1);
- rulesetBeatmapSet.Beatmaps.ForEach(b =>
- {
- b.Ruleset = taikoRuleset;
- b.RulesetID = 1;
- });
+ rulesetBeatmapSet.Beatmaps.ForEach(b => b.Ruleset = taikoRuleset);
sets.Add(rulesetBeatmapSet);
});
@@ -409,10 +406,10 @@ namespace osu.Game.Tests.Visual.SongSelect
var set = TestResources.CreateTestBeatmapSetInfo();
if (i == 4)
- set.Metadata.Artist = zzz_string;
+ set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string);
if (i == 16)
- set.Metadata.AuthorString = zzz_string;
+ set.Beatmaps.ForEach(b => b.Metadata.AuthorString = zzz_string);
sets.Add(set);
}
@@ -433,12 +430,17 @@ namespace osu.Game.Tests.Visual.SongSelect
for (int i = 0; i < 20; i++)
{
var set = TestResources.CreateTestBeatmapSetInfo();
- set.Metadata.Artist = "same artist";
- set.Metadata.Title = "same title";
+
+ // 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";
+
sets.Add(set);
}
- int idOffset = sets.First().OnlineID ?? 0;
+ int idOffset = sets.First().OnlineID;
loadBeatmaps(sets);
@@ -577,7 +579,6 @@ namespace osu.Game.Tests.Visual.SongSelect
for (int i = 0; i <= 2; i++)
{
testMixed.Beatmaps[i].Ruleset = rulesets.AvailableRulesets.ElementAt(i);
- testMixed.Beatmaps[i].RulesetID = i;
}
carousel.UpdateBeatmapSet(testMixed);
@@ -599,7 +600,6 @@ namespace osu.Game.Tests.Visual.SongSelect
testSingle.Beatmaps.ForEach(b =>
{
b.Ruleset = rulesets.AvailableRulesets.ElementAt(1);
- b.RulesetID = b.Ruleset.ID ?? 1;
});
carousel.UpdateBeatmapSet(testSingle);
@@ -674,7 +674,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("Restore different ruleset filter", () =>
{
carousel.Filter(new FilterCriteria { Ruleset = rulesets.GetRuleset(1) }, false);
- eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.OnlineID ?? -1);
+ eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID);
});
AddAssert("selection changed", () => !carousel.SelectedBeatmapInfo.Equals(manySets.First().Beatmaps.First()));
@@ -697,10 +697,9 @@ namespace osu.Game.Tests.Visual.SongSelect
for (int i = 1; i <= 15; i++)
{
- set.Beatmaps.Add(new BeatmapInfo
+ set.Beatmaps.Add(new BeatmapInfo(new OsuRuleset().RulesetInfo, new BeatmapDifficulty(), new BeatmapMetadata())
{
DifficultyName = $"Stars: {i}",
- Ruleset = new OsuRuleset().RulesetInfo,
StarRating = i,
});
}
@@ -872,8 +871,6 @@ namespace osu.Game.Tests.Visual.SongSelect
}
}
}
-
- protected override IEnumerable GetLoadableBeatmaps() => Enumerable.Empty();
}
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 605e03564d..2e1a66be5f 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -16,6 +16,7 @@ using osu.Game.Online.Leaderboards;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
@@ -44,6 +45,7 @@ namespace osu.Game.Tests.Visual.SongSelect
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, ContextFactory, Scheduler));
+ Dependencies.Cache(ContextFactory);
return dependencies;
}
@@ -135,6 +137,7 @@ namespace osu.Game.Tests.Visual.SongSelect
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock() },
+ Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
{
Id = 6602580,
@@ -157,6 +160,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
+ Ruleset = new OsuRuleset().RulesetInfo,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new APIUser
{
@@ -182,7 +186,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private void clearScores()
{
- AddStep("Clear all scores", () => scoreManager.Delete(scoreManager.GetAllUsableScores()));
+ AddStep("Clear all scores", () => scoreManager.Delete());
}
private void checkCount(int expected) =>
@@ -199,6 +203,7 @@ namespace osu.Game.Tests.Visual.SongSelect
MaxCombo = 244,
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
+ Ruleset = new OsuRuleset().RulesetInfo,
BeatmapInfo = beatmapInfo,
User = new APIUser
{
@@ -219,6 +224,7 @@ namespace osu.Game.Tests.Visual.SongSelect
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
{
Id = 4608074,
@@ -238,6 +244,8 @@ namespace osu.Game.Tests.Visual.SongSelect
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
+
User = new APIUser
{
Id = 1014222,
@@ -257,6 +265,8 @@ namespace osu.Game.Tests.Visual.SongSelect
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
+
User = new APIUser
{
Id = 1541390,
@@ -276,6 +286,8 @@ namespace osu.Game.Tests.Visual.SongSelect
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
+
User = new APIUser
{
Id = 2243452,
@@ -295,6 +307,8 @@ namespace osu.Game.Tests.Visual.SongSelect
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
+
User = new APIUser
{
Id = 2705430,
@@ -314,6 +328,8 @@ namespace osu.Game.Tests.Visual.SongSelect
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
+
User = new APIUser
{
Id = 7151382,
@@ -333,6 +349,8 @@ namespace osu.Game.Tests.Visual.SongSelect
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
+
User = new APIUser
{
Id = 2051389,
@@ -352,6 +370,8 @@ namespace osu.Game.Tests.Visual.SongSelect
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
+
User = new APIUser
{
Id = 6169483,
@@ -371,6 +391,8 @@ namespace osu.Game.Tests.Visual.SongSelect
TotalScore = 1707827,
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ Ruleset = new OsuRuleset().RulesetInfo,
+
User = new APIUser
{
Id = 6702666,
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs
index e573c96ce9..fb6d9a0b4b 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs
@@ -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;
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs
index 08b5802713..b7bc0c37e1 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs
@@ -113,6 +113,8 @@ namespace osu.Game.Tests.Visual.SongSelect
// Switch to catch
presentAndConfirm(() => catchSet, 1);
+ AddAssert("game-wide ruleset changed", () => Game.Ruleset.Value.Equals(catchSet.Beatmaps.First().Ruleset));
+
// Present mixed difficulty set, expect current ruleset to be selected
presentAndConfirm(() => mixedSet, 2);
}
@@ -182,7 +184,7 @@ namespace osu.Game.Tests.Visual.SongSelect
beatmap.DifficultyName = $"SR{i + 1}";
}
- return Game.BeatmapManager.Import(beatmapSet).GetResultSafely().Value;
+ return Game.BeatmapManager.Import(beatmapSet).GetResultSafely()?.Value;
}
private bool ensureAllBeatmapSetsImported(IEnumerable beatmapSets) => beatmapSets.All(set => set != null);
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs
index 1ee59eccc7..ca8e9d2eff 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs
@@ -38,6 +38,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(ContextFactory);
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 37f110e727..6295a52bdd 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -45,7 +45,10 @@ namespace osu.Game.Tests.Visual.SongSelect
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
+ // These DI caches are required to ensure for interactive runs this test scene doesn't nuke all user beatmaps in the local install.
+ // At a point we have isolated interactive test runs enough, this can likely be removed.
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
+ Dependencies.Cache(ContextFactory);
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, defaultBeatmap = Beatmap.Default));
Dependencies.Cache(music = new MusicController());
@@ -585,7 +588,7 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestHideSetSelectsCorrectBeatmap()
{
- int? previousID = null;
+ Guid? previousID = null;
createSongSelect();
addRulesetImportStep(0);
AddStep("Move to last difficulty", () => songSelect.Carousel.SelectBeatmap(songSelect.Carousel.BeatmapSets.First().Beatmaps.Last()));
@@ -637,8 +640,9 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("Get filtered icon", () =>
{
- filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.First(b => b.BPM < maxBPM);
- int filteredBeatmapIndex = getBeatmapIndex(filteredBeatmap.BeatmapSet, filteredBeatmap);
+ var selectedSet = songSelect.Carousel.SelectedBeatmapSet;
+ filteredBeatmap = selectedSet.Beatmaps.First(b => b.BPM < maxBPM);
+ int filteredBeatmapIndex = getBeatmapIndex(selectedSet, filteredBeatmap);
filteredIcon = set.ChildrenOfType().ElementAt(filteredBeatmapIndex);
});
@@ -744,7 +748,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.OnlineID == 3);
- AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet.OnlineID == previousSetID);
+ AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet?.OnlineID == previousSetID);
AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3);
}
@@ -760,7 +764,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("import huge difficulty count map", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
- imported = manager.Import(TestResources.CreateTestBeatmapSetInfo(50, usableRulesets)).GetResultSafely().Value;
+ imported = manager.Import(TestResources.CreateTestBeatmapSetInfo(50, usableRulesets)).GetResultSafely()?.Value;
});
AddStep("select the first beatmap of import", () => Beatmap.Value = manager.GetWorkingBeatmap(imported.Beatmaps.First()));
@@ -796,8 +800,8 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestChangeRulesetWhilePresentingScore()
{
- BeatmapInfo getPresentBeatmap() => manager.QueryBeatmap(b => !b.BeatmapSet.DeletePending && b.RulesetID == 0);
- BeatmapInfo getSwitchBeatmap() => manager.QueryBeatmap(b => !b.BeatmapSet.DeletePending && b.RulesetID == 1);
+ BeatmapInfo getPresentBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.RulesetID == 0);
+ BeatmapInfo getSwitchBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.RulesetID == 1);
changeRuleset(0);
@@ -828,8 +832,8 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestChangeBeatmapWhilePresentingScore()
{
- BeatmapInfo getPresentBeatmap() => manager.QueryBeatmap(b => !b.BeatmapSet.DeletePending && b.RulesetID == 0);
- BeatmapInfo getSwitchBeatmap() => manager.QueryBeatmap(b => !b.BeatmapSet.DeletePending && b.RulesetID == 1);
+ BeatmapInfo getPresentBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.RulesetID == 0);
+ BeatmapInfo getSwitchBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.RulesetID == 1);
changeRuleset(0);
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs
index 7af9e9eb40..dd7f9951bf 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs
@@ -10,6 +10,7 @@ using osuTK.Graphics;
using osu.Game.Online.Leaderboards;
using osu.Game.Overlays;
using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Users;
@@ -61,6 +62,7 @@ namespace osu.Game.Tests.Visual.SongSelect
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
+ Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
{
Id = 6602580,
@@ -79,6 +81,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
+ Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
{
Id = 4608074,
@@ -97,6 +100,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
+ Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
{
Id = 1541390,
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
index a436fc0bfa..1e14e4b3e5 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -1,13 +1,14 @@
// 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.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;
@@ -16,10 +17,12 @@ using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Models;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards;
using osu.Game.Overlays;
using osu.Game.Rulesets;
+using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Tests.Resources;
@@ -41,6 +44,9 @@ namespace osu.Game.Tests.Visual.UserInterface
private BeatmapInfo beatmapInfo;
+ [Resolved]
+ private RealmContextFactory realmFactory { get; set; }
+
[Cached]
private readonly DialogOverlay dialogOverlay;
@@ -59,13 +65,12 @@ namespace osu.Game.Tests.Visual.UserInterface
Scope = BeatmapLeaderboardScope.Local,
BeatmapInfo = new BeatmapInfo
{
- ID = 1,
+ ID = Guid.NewGuid(),
Metadata = new BeatmapMetadata
{
- ID = 1,
Title = "TestSong",
Artist = "TestArtist",
- Author = new APIUser
+ Author = new RealmUser
{
Username = "TestAuthor"
},
@@ -84,26 +89,32 @@ namespace osu.Game.Tests.Visual.UserInterface
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default));
- dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, ContextFactory, Scheduler));
+ dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get(), () => beatmapManager, LocalStorage, ContextFactory, Scheduler));
+ Dependencies.Cache(ContextFactory);
- beatmapInfo = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).GetResultSafely().Value.Beatmaps[0];
+ var imported = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).GetResultSafely();
- for (int i = 0; i < 50; i++)
+ imported?.PerformRead(s =>
{
- var score = new ScoreInfo
- {
- OnlineID = i,
- BeatmapInfo = beatmapInfo,
- BeatmapInfoID = beatmapInfo.ID,
- Accuracy = RNG.NextDouble(),
- TotalScore = RNG.Next(1, 1000000),
- MaxCombo = RNG.Next(1, 1000),
- Rank = ScoreRank.XH,
- User = new APIUser { Username = "TestUser" },
- };
+ beatmapInfo = s.Beatmaps[0];
- importedScores.Add(scoreManager.Import(score).GetResultSafely().Value);
- }
+ for (int i = 0; i < 50; i++)
+ {
+ var score = new ScoreInfo
+ {
+ OnlineID = i,
+ BeatmapInfo = beatmapInfo,
+ Accuracy = RNG.NextDouble(),
+ TotalScore = RNG.Next(1, 1000000),
+ MaxCombo = RNG.Next(1, 1000),
+ Rank = ScoreRank.XH,
+ User = new APIUser { Username = "TestUser" },
+ Ruleset = new OsuRuleset().RulesetInfo,
+ };
+
+ importedScores.Add(scoreManager.Import(score).GetResultSafely().Value);
+ }
+ });
return dependencies;
}
@@ -111,8 +122,11 @@ namespace osu.Game.Tests.Visual.UserInterface
[SetUp]
public void Setup() => Schedule(() =>
{
- // Due to soft deletions, we can re-use deleted scores between test runs
- scoreManager.Undelete(scoreManager.QueryScores(s => s.DeletePending).ToList());
+ using (var realm = realmFactory.CreateContext())
+ {
+ // Due to soft deletions, we can re-use deleted scores between test runs
+ scoreManager.Undelete(realm.All().Where(s => s.DeletePending).ToList());
+ }
leaderboard.Scores = null;
leaderboard.FinishTransforms(true); // After setting scores, we may be waiting for transforms to expire drawables
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
index f196bbd76e..b429619044 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
@@ -459,6 +459,8 @@ namespace osu.Game.Tests.Visual.UserInterface
private class TestUnimplementedModOsuRuleset : OsuRuleset
{
+ public override string ShortName => "unimplemented";
+
public override IEnumerable GetModsFor(ModType type)
{
if (type == ModType.Conversion) return base.GetModsFor(type).Concat(new[] { new TestUnimplementedMod() });
diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs
index 39146d584c..62f3b63780 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs
@@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.UserInterface
InputManager.MoveMouseTo(item.ScreenSpaceDrawQuad.Centre);
});
- AddAssert("song 1 is 5th", () => beatmapSets[4] == first);
+ AddAssert("song 1 is 5th", () => beatmapSets[4].Equals(first));
AddStep("release handle", () => InputManager.ReleaseButton(MouseButton.Left));
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs
index 736df7dec1..7109a55e7e 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
this.api = api;
- testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu).GetResultSafely();
+ testBeatmap = BeatmapImportHelper.LoadOszIntoOsu(osu).GetResultSafely();
}
[Test]
diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs
index d08322a3e8..f318c8bd85 100644
--- a/osu.Game.Tournament/TournamentGameBase.cs
+++ b/osu.Game.Tournament/TournamentGameBase.cs
@@ -81,8 +81,9 @@ namespace osu.Game.Tournament
ladder ??= new LadderInfo();
- ladder.Ruleset.Value = RulesetStore.GetRuleset(ladder.Ruleset.Value?.ShortName)
- ?? RulesetStore.AvailableRulesets.First();
+ ladder.Ruleset.Value = ladder.Ruleset.Value != null
+ ? RulesetStore.GetRuleset(ladder.Ruleset.Value.ShortName)
+ : RulesetStore.AvailableRulesets.First();
bool addedInfo = false;
diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs
index 435183fe92..ccecd69d21 100644
--- a/osu.Game/Beatmaps/Beatmap.cs
+++ b/osu.Game/Beatmaps/Beatmap.cs
@@ -62,7 +62,7 @@ namespace osu.Game.Beatmaps
}
[JsonIgnore]
- public BeatmapMetadata Metadata => BeatmapInfo?.Metadata ?? BeatmapInfo?.BeatmapSet?.Metadata;
+ public BeatmapMetadata Metadata => BeatmapInfo.Metadata;
public ControlPointInfo ControlPointInfo { get; set; } = new ControlPointInfo();
diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs
index 65d1fb8286..7e0462f1e8 100644
--- a/osu.Game/Beatmaps/BeatmapDifficulty.cs
+++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs
@@ -1,27 +1,29 @@
// 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 osu.Game.Database;
+using osu.Framework.Testing;
+using Realms;
+
+#nullable enable
namespace osu.Game.Beatmaps
{
- public class BeatmapDifficulty : IHasPrimaryKey, IBeatmapDifficultyInfo
+ [ExcludeFromDynamicCompile]
+ [MapTo("BeatmapDifficulty")]
+ public class BeatmapDifficulty : EmbeddedObject, IBeatmapDifficultyInfo
{
///
/// The default value used for all difficulty settings except and .
///
public const float DEFAULT_DIFFICULTY = 5;
- public int ID { get; set; }
+ public float DrainRate { get; set; } = IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY;
+ public float CircleSize { get; set; } = IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY;
+ public float OverallDifficulty { get; set; } = IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY;
+ public float ApproachRate { get; set; } = IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY;
- public bool IsManaged => ID > 0;
-
- public float DrainRate { get; set; } = DEFAULT_DIFFICULTY;
- public float CircleSize { get; set; } = DEFAULT_DIFFICULTY;
- public float OverallDifficulty { get; set; } = DEFAULT_DIFFICULTY;
-
- private float? approachRate;
+ public double SliderMultiplier { get; set; } = 1;
+ public double SliderTickRate { get; set; } = 1;
public BeatmapDifficulty()
{
@@ -32,23 +34,20 @@ namespace osu.Game.Beatmaps
CopyFrom(source);
}
- public float ApproachRate
- {
- get => approachRate ?? OverallDifficulty;
- set => approachRate = value;
- }
-
- public double SliderMultiplier { get; set; } = 1;
- public double SliderTickRate { get; set; } = 1;
-
///
/// Returns a shallow-clone of this .
///
- public BeatmapDifficulty Clone()
+ public virtual BeatmapDifficulty Clone() => new BeatmapDifficulty(this);
+
+ public virtual void CopyTo(BeatmapDifficulty difficulty)
{
- var diff = (BeatmapDifficulty)Activator.CreateInstance(GetType());
- CopyTo(diff);
- return diff;
+ difficulty.ApproachRate = ApproachRate;
+ difficulty.DrainRate = DrainRate;
+ difficulty.CircleSize = CircleSize;
+ difficulty.OverallDifficulty = OverallDifficulty;
+
+ difficulty.SliderMultiplier = SliderMultiplier;
+ difficulty.SliderTickRate = SliderTickRate;
}
public virtual void CopyFrom(IBeatmapDifficultyInfo other)
@@ -61,16 +60,5 @@ namespace osu.Game.Beatmaps
SliderMultiplier = other.SliderMultiplier;
SliderTickRate = other.SliderTickRate;
}
-
- public virtual void CopyTo(BeatmapDifficulty other)
- {
- other.ApproachRate = ApproachRate;
- other.DrainRate = DrainRate;
- other.CircleSize = CircleSize;
- other.OverallDifficulty = OverallDifficulty;
-
- other.SliderMultiplier = SliderMultiplier;
- other.SliderTickRate = SliderTickRate;
- }
}
}
diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs
index f760c25170..f102daeef5 100644
--- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs
+++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs
@@ -136,7 +136,7 @@ namespace osu.Game.Beatmaps
var localRulesetInfo = rulesetInfo as RulesetInfo;
// Difficulty can only be computed if the beatmap and ruleset are locally available.
- if (localBeatmapInfo?.IsManaged != true || localRulesetInfo == null)
+ if (localBeatmapInfo == null || localRulesetInfo == null)
{
// If not, fall back to the existing star difficulty (e.g. from an online source).
return Task.FromResult(new StarDifficulty(beatmapInfo.StarRating, (beatmapInfo as IBeatmapOnlineInfo)?.MaxCombo ?? 0));
diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs
index 4175d7ff6b..b0e10c2c38 100644
--- a/osu.Game/Beatmaps/BeatmapInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapInfo.cs
@@ -2,102 +2,118 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Framework.Testing;
using osu.Game.Database;
+using osu.Game.Models;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Scoring;
+using Realms;
+
+#nullable enable
namespace osu.Game.Beatmaps
{
+ ///
+ /// A single beatmap difficulty.
+ ///
[ExcludeFromDynamicCompile]
[Serializable]
- public class BeatmapInfo : IEquatable, IHasPrimaryKey, IBeatmapInfo
+ [MapTo("Beatmap")]
+ public class BeatmapInfo : RealmObject, IHasGuidPrimaryKey, IBeatmapInfo, IEquatable
{
- public int ID { get; set; }
+ [PrimaryKey]
+ public Guid ID { get; set; } = Guid.NewGuid();
- public bool IsManaged => ID > 0;
+ public string DifficultyName { get; set; } = string.Empty;
- public int BeatmapVersion;
+ public RulesetInfo Ruleset { get; set; }
- private int? onlineID;
-
- [JsonProperty("id")]
- [Column("OnlineBeatmapID")]
- public int? OnlineID
- {
- get => onlineID;
- set => onlineID = value > 0 ? value : null;
- }
-
- [JsonIgnore]
- public int BeatmapSetInfoID { get; set; }
-
- public BeatmapOnlineStatus Status { get; set; } = BeatmapOnlineStatus.None;
-
- [Required]
- public BeatmapSetInfo BeatmapSet { get; set; }
+ public BeatmapDifficulty Difficulty { get; set; }
public BeatmapMetadata Metadata { get; set; }
- [JsonIgnore]
- public int BaseDifficultyID { get; set; }
+ [Backlink(nameof(ScoreInfo.BeatmapInfo))]
+ public IQueryable Scores { get; } = null!;
- public BeatmapDifficulty BaseDifficulty { get; set; }
+ public BeatmapInfo(RulesetInfo ruleset, BeatmapDifficulty difficulty, BeatmapMetadata metadata)
+ {
+ Ruleset = ruleset;
+ Difficulty = difficulty;
+ Metadata = metadata;
+ }
- [NotMapped]
- public APIBeatmap OnlineInfo { get; set; }
+ [UsedImplicitly]
+ public BeatmapInfo() // TODO: consider removing this and migrating all usages to ctor with parameters.
+ {
+ Ruleset = new RulesetInfo
+ {
+ OnlineID = 0,
+ ShortName = @"osu",
+ Name = @"null placeholder ruleset"
+ };
+ Difficulty = new BeatmapDifficulty();
+ Metadata = new BeatmapMetadata();
+ }
- [NotMapped]
- public int? MaxCombo { get; set; }
+ public BeatmapSetInfo? BeatmapSet { get; set; }
+
+ [Ignored]
+ public RealmNamedFileUsage? File => BeatmapSet?.Files.FirstOrDefault(f => f.File.Hash == Hash);
+
+ public BeatmapOnlineStatus Status
+ {
+ get => (BeatmapOnlineStatus)StatusInt;
+ set => StatusInt = (int)value;
+ }
+
+ [MapTo(nameof(Status))]
+ public int StatusInt { get; set; } = (int)BeatmapOnlineStatus.None;
+
+ [Indexed]
+ public int OnlineID { get; set; } = -1;
- ///
- /// The playable length in milliseconds of this beatmap.
- ///
public double Length { get; set; }
- ///
- /// The most common BPM of this beatmap.
- ///
public double BPM { get; set; }
- public string Path { get; set; }
+ public string Hash { get; set; } = string.Empty;
- [JsonProperty("file_sha2")]
- public string Hash { get; set; }
+ public double StarRating { get; set; }
+
+ public string MD5Hash { get; set; } = string.Empty;
[JsonIgnore]
public bool Hidden { get; set; }
- ///
- /// MD5 is kept for legacy support (matching against replays, osu-web-10 etc.).
- ///
- [JsonProperty("file_md5")]
- public string MD5Hash { get; set; }
+ #region Properties we may not want persisted (but also maybe no harm?)
- // General
public double AudioLeadIn { get; set; }
+
public float StackLeniency { get; set; } = 0.7f;
+
public bool SpecialStyle { get; set; }
- public int RulesetID { get; set; }
-
- public RulesetInfo Ruleset { get; set; }
-
public bool LetterboxInBreaks { get; set; }
+
public bool WidescreenStoryboard { get; set; }
+
public bool EpilepsyWarning { get; set; }
- ///
- /// Whether or not sound samples should change rate when playing with speed-changing mods.
- /// TODO: only read/write supported for now, requires implementation in gameplay.
- ///
public bool SamplesMatchPlaybackRate { get; set; }
+ public double DistanceSpacing { get; set; }
+
+ public int BeatDivisor { get; set; }
+
+ public int GridSize { get; set; }
+
+ public double TimelineZoom { get; set; }
+
+ [Ignored]
public CountdownType Countdown { get; set; } = CountdownType.Normal;
///
@@ -105,77 +121,74 @@ namespace osu.Game.Beatmaps
///
public int CountdownOffset { get; set; }
- [NotMapped]
- public int[] Bookmarks { get; set; } = Array.Empty();
+ #endregion
- public double DistanceSpacing { get; set; }
- public int BeatDivisor { get; set; }
- public int GridSize { get; set; }
- public double TimelineZoom { get; set; }
-
- // Metadata
- [Column("Version")]
- public string DifficultyName { get; set; }
-
- [JsonProperty("difficulty_rating")]
- [Column("StarDifficulty")]
- public double StarRating { get; set; }
-
- ///
- /// Currently only populated for beatmap deletion. Use to query scores.
- ///
- public List Scores { get; set; }
-
- [JsonIgnore]
- public DifficultyRating DifficultyRating => BeatmapDifficultyCache.GetDifficultyRating(StarRating);
-
- public override string ToString() => this.GetDisplayTitle();
-
- public bool Equals(BeatmapInfo other)
+ public bool Equals(BeatmapInfo? other)
{
if (ReferenceEquals(this, other)) return true;
if (other == null) return false;
- if (ID != 0 && other.ID != 0)
- return ID == other.ID;
-
- return false;
+ return ID == other.ID;
}
- public bool Equals(IBeatmapInfo other) => other is BeatmapInfo b && Equals(b);
+ public bool Equals(IBeatmapInfo? other) => other is BeatmapInfo b && Equals(b);
- public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
- BeatmapSet.Hash == other.BeatmapSet.Hash &&
- (Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
+ public bool AudioEquals(BeatmapInfo? other) => other != null
+ && BeatmapSet != null
+ && other.BeatmapSet != null
+ && BeatmapSet.Hash == other.BeatmapSet.Hash
+ && Metadata.AudioFile == other.Metadata.AudioFile;
- public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
- BeatmapSet.Hash == other.BeatmapSet.Hash &&
- (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile;
+ public bool BackgroundEquals(BeatmapInfo? other) => other != null
+ && BeatmapSet != null
+ && other.BeatmapSet != null
+ && BeatmapSet.Hash == other.BeatmapSet.Hash
+ && Metadata.BackgroundFile == other.Metadata.BackgroundFile;
- ///
- /// Returns a shallow-clone of this .
- ///
- public BeatmapInfo Clone() => (BeatmapInfo)MemberwiseClone();
-
- #region Implementation of IHasOnlineID
-
- int IHasOnlineID.OnlineID => OnlineID ?? -1;
-
- #endregion
-
- #region Implementation of IBeatmapInfo
-
- [JsonIgnore]
- IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata ?? BeatmapSet?.Metadata ?? new BeatmapMetadata();
-
- [JsonIgnore]
- IBeatmapDifficultyInfo IBeatmapInfo.Difficulty => BaseDifficulty;
-
- [JsonIgnore]
- IBeatmapSetInfo IBeatmapInfo.BeatmapSet => BeatmapSet;
-
- [JsonIgnore]
+ IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata;
+ IBeatmapSetInfo? IBeatmapInfo.BeatmapSet => BeatmapSet;
IRulesetInfo IBeatmapInfo.Ruleset => Ruleset;
+ IBeatmapDifficultyInfo IBeatmapInfo.Difficulty => Difficulty;
+
+ #region Compatibility properties
+
+ [Ignored]
+ public int RulesetID
+ {
+ get => Ruleset.OnlineID;
+ set
+ {
+ if (!string.IsNullOrEmpty(Ruleset.InstantiationInfo))
+ throw new InvalidOperationException($"Cannot set a {nameof(RulesetID)} when {nameof(Ruleset)} is already set to an actual ruleset.");
+
+ Ruleset.OnlineID = value;
+ }
+ }
+
+ [Ignored]
+ public BeatmapDifficulty BaseDifficulty
+ {
+ get => Difficulty;
+ set => Difficulty = value;
+ }
+
+ [Ignored]
+ public string? Path => File?.Filename;
+
+ [Ignored]
+ public APIBeatmap? OnlineInfo { get; set; }
+
+ [Ignored]
+ public int? MaxCombo { get; set; }
+
+ [Ignored]
+ public int[] Bookmarks { get; set; } = Array.Empty();
+
+ public int BeatmapVersion;
+
+ public BeatmapInfo Clone() => (BeatmapInfo)this.Detach().MemberwiseClone();
+
+ public override string ToString() => this.GetDisplayTitle();
#endregion
}
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index ed7fe0bc91..f901b0fbc1 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -8,7 +8,6 @@ using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
-using JetBrains.Annotations;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions;
@@ -16,13 +15,16 @@ 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;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
using osu.Game.Skinning;
+using osu.Game.Stores;
+
+#nullable enable
namespace osu.Game.Beatmaps
{
@@ -30,41 +32,46 @@ namespace osu.Game.Beatmaps
/// Handles general operations related to global beatmap management.
///
[ExcludeFromDynamicCompile]
- public class BeatmapManager : IModelManager, IModelFileManager, IModelImporter, IWorkingBeatmapCache, IDisposable
+ public class BeatmapManager : IModelManager, IModelFileManager, IModelImporter, IWorkingBeatmapCache, IDisposable
{
public ITrackStore BeatmapTrackStore { get; }
private readonly BeatmapModelManager beatmapModelManager;
private readonly WorkingBeatmapCache workingBeatmapCache;
- private readonly BeatmapOnlineLookupQueue onlineBeatmapLookupQueue;
+ private readonly BeatmapOnlineLookupQueue? onlineBeatmapLookupQueue;
- public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore gameResources, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false)
+ private readonly RealmContextFactory contextFactory;
+
+ public BeatmapManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, IAPIProvider? api, AudioManager audioManager, IResourceStore gameResources, GameHost? host = null, WorkingBeatmap? defaultBeatmap = null, bool performOnlineLookups = false)
{
- var userResources = new FileStore(contextFactory, storage).Store;
-
- BeatmapTrackStore = audioManager.GetTrackStore(userResources);
-
- beatmapModelManager = CreateBeatmapModelManager(storage, contextFactory, rulesets, api, host);
- workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host);
-
- workingBeatmapCache.BeatmapManager = beatmapModelManager;
- beatmapModelManager.WorkingBeatmapCache = workingBeatmapCache;
+ this.contextFactory = contextFactory;
if (performOnlineLookups)
{
+ if (api == null)
+ throw new ArgumentNullException(nameof(api), "API must be provided if online lookups are required.");
+
onlineBeatmapLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
- beatmapModelManager.OnlineLookupQueue = onlineBeatmapLookupQueue;
}
+
+ var userResources = new RealmFileStore(contextFactory, storage).Store;
+
+ BeatmapTrackStore = audioManager.GetTrackStore(userResources);
+
+ beatmapModelManager = CreateBeatmapModelManager(storage, contextFactory, rulesets, onlineBeatmapLookupQueue);
+ workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host);
+
+ beatmapModelManager.WorkingBeatmapCache = workingBeatmapCache;
}
- protected virtual WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore resources, IResourceStore storage, WorkingBeatmap defaultBeatmap, GameHost host)
+ protected virtual WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore resources, IResourceStore storage, WorkingBeatmap? defaultBeatmap, GameHost? host)
{
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, BeatmapOnlineLookupQueue? onlineLookupQueue) =>
+ new BeatmapModelManager(contextFactory, storage, onlineLookupQueue);
///
/// Create a new .
@@ -73,12 +80,15 @@ namespace osu.Game.Beatmaps
{
var metadata = new BeatmapMetadata
{
- Author = user,
+ Author = new RealmUser
+ {
+ OnlineID = user.OnlineID,
+ Username = user.Username,
+ }
};
- var set = new BeatmapSetInfo
+ var beatmapSet = new BeatmapSetInfo
{
- Metadata = metadata,
Beatmaps =
{
new BeatmapInfo
@@ -92,30 +102,92 @@ namespace osu.Game.Beatmaps
}
};
- var imported = beatmapModelManager.Import(set).GetResultSafely().Value;
+ foreach (BeatmapInfo b in beatmapSet.Beatmaps)
+ b.BeatmapSet = beatmapSet;
- return GetWorkingBeatmap(imported.Beatmaps.First());
+ var imported = beatmapModelManager.Import(beatmapSet).GetResultSafely();
+
+ if (imported == null)
+ throw new InvalidOperationException("Failed to import new beatmap");
+
+ return imported.PerformRead(s => GetWorkingBeatmap(s.Beatmaps.First()));
+ }
+
+ ///
+ /// Delete a beatmap difficulty.
+ ///
+ /// The beatmap difficulty to hide.
+ public void Hide(BeatmapInfo beatmapInfo)
+ {
+ using (var realm = contextFactory.CreateContext())
+ using (var transaction = realm.BeginWrite())
+ {
+ if (!beatmapInfo.IsManaged)
+ beatmapInfo = realm.Find(beatmapInfo.ID);
+
+ beatmapInfo.Hidden = true;
+ transaction.Commit();
+ }
+ }
+
+ ///
+ /// Restore a beatmap difficulty.
+ ///
+ /// The beatmap difficulty to restore.
+ public void Restore(BeatmapInfo beatmapInfo)
+ {
+ using (var realm = contextFactory.CreateContext())
+ using (var transaction = realm.BeginWrite())
+ {
+ if (!beatmapInfo.IsManaged)
+ beatmapInfo = realm.Find(beatmapInfo.ID);
+
+ beatmapInfo.Hidden = false;
+ transaction.Commit();
+ }
+ }
+
+ public void RestoreAll()
+ {
+ using (var realm = contextFactory.CreateContext())
+ using (var transaction = realm.BeginWrite())
+ {
+ foreach (var beatmap in realm.All().Where(b => b.Hidden))
+ beatmap.Hidden = false;
+
+ transaction.Commit();
+ }
+ }
+
+ ///
+ /// Returns a list of all usable s.
+ ///
+ /// A list of available .
+ public List GetAllUsableBeatmapSets()
+ {
+ using (var context = contextFactory.CreateContext())
+ return context.All().Where(b => !b.DeletePending).Detach();
+ }
+
+ ///
+ /// Perform a lookup query on available s.
+ ///
+ /// The query.
+ /// The first result for the provided query, or null if no results were found.
+ public ILive? QueryBeatmapSet(Expression> query)
+ {
+ using (var context = contextFactory.CreateContext())
+ return context.All().FirstOrDefault(query)?.ToLive(contextFactory);
}
#region Delegation to BeatmapModelManager (methods which previously existed locally).
///
- /// Fired when a single difficulty has been hidden.
+ /// Perform a lookup query on available s.
///
- public event Action BeatmapHidden
- {
- add => beatmapModelManager.BeatmapHidden += value;
- remove => beatmapModelManager.BeatmapHidden -= value;
- }
-
- ///
- /// Fired when a single difficulty has been restored.
- ///
- public event Action BeatmapRestored
- {
- add => beatmapModelManager.BeatmapRestored += value;
- remove => beatmapModelManager.BeatmapRestored -= value;
- }
+ /// The query.
+ /// The first result for the provided query, or null if no results were found.
+ public BeatmapInfo? QueryBeatmap(Expression> query) => beatmapModelManager.QueryBeatmap(query)?.Detach();
///
/// Saves an file against a given .
@@ -123,52 +195,9 @@ namespace osu.Game.Beatmaps
/// The to save the content against. The file referenced by will be replaced.
/// The content to write.
/// The beatmap content to write, null if to be omitted.
- public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) =>
+ public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin? beatmapSkin = null) =>
beatmapModelManager.Save(info, beatmapContent, beatmapSkin);
- ///
- /// Returns a list of all usable s.
- ///
- /// A list of available .
- public List GetAllUsableBeatmapSets(IncludedDetails includes = IncludedDetails.All, bool includeProtected = false) => beatmapModelManager.GetAllUsableBeatmapSets(includes, includeProtected);
-
- ///
- /// Returns a list of all usable s. Note that files are not populated.
- ///
- /// The level of detail to include in the returned objects.
- /// Whether to include protected (system) beatmaps. These should not be included for gameplay playable use cases.
- /// A list of available .
- public IEnumerable GetAllUsableBeatmapSetsEnumerable(IncludedDetails includes, bool includeProtected = false) => beatmapModelManager.GetAllUsableBeatmapSetsEnumerable(includes, includeProtected);
-
- ///
- /// Perform a lookup query on available s.
- ///
- /// The query.
- /// The level of detail to include in the returned objects.
- /// Results from the provided query.
- public IEnumerable QueryBeatmapSets(Expression> query, IncludedDetails includes = IncludedDetails.All) => beatmapModelManager.QueryBeatmapSets(query, includes);
-
- ///
- /// Perform a lookup query on available s.
- ///
- /// The query.
- /// The first result for the provided query, or null if no results were found.
- public BeatmapSetInfo QueryBeatmapSet(Expression> query) => beatmapModelManager.QueryBeatmapSet(query);
-
- ///
- /// Perform a lookup query on available s.
- ///
- /// The query.
- /// Results from the provided query.
- public IQueryable QueryBeatmaps(Expression> query) => beatmapModelManager.QueryBeatmaps(query);
-
- ///
- /// Perform a lookup query on available s.
- ///
- /// The query.
- /// The first result for the provided query, or null if no results were found.
- public BeatmapInfo QueryBeatmap(Expression> query) => beatmapModelManager.QueryBeatmap(query);
-
///
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
///
@@ -182,18 +211,6 @@ namespace osu.Game.Beatmaps
set => beatmapModelManager.PostNotification = value;
}
- ///
- /// Delete a beatmap difficulty.
- ///
- /// The beatmap difficulty to hide.
- public void Hide(BeatmapInfo beatmapInfo) => beatmapModelManager.Hide(beatmapInfo);
-
- ///
- /// Restore a beatmap difficulty.
- ///
- /// The beatmap difficulty to restore.
- public void Restore(BeatmapInfo beatmapInfo) => beatmapModelManager.Restore(beatmapInfo);
-
#endregion
#region Implementation of IModelManager
@@ -203,23 +220,6 @@ namespace osu.Game.Beatmaps
return beatmapModelManager.IsAvailableLocally(model);
}
- public event Action ItemUpdated
- {
- add => beatmapModelManager.ItemUpdated += value;
- remove => beatmapModelManager.ItemUpdated -= value;
- }
-
- public event Action ItemRemoved
- {
- add => beatmapModelManager.ItemRemoved += value;
- remove => beatmapModelManager.ItemRemoved -= value;
- }
-
- public void Update(BeatmapSetInfo item)
- {
- beatmapModelManager.Update(item);
- }
-
public bool Delete(BeatmapSetInfo item)
{
return beatmapModelManager.Delete(item);
@@ -230,6 +230,25 @@ namespace osu.Game.Beatmaps
beatmapModelManager.Delete(items, silent);
}
+ public void Delete(Expression>? filter = null, bool silent = false)
+ {
+ using (var context = contextFactory.CreateContext())
+ {
+ var items = context.All().Where(s => !s.DeletePending && !s.Protected);
+
+ if (filter != null)
+ items = items.Where(filter);
+
+ beatmapModelManager.Delete(items.ToList(), silent);
+ }
+ }
+
+ public void UndeleteAll()
+ {
+ using (var context = contextFactory.CreateContext())
+ beatmapModelManager.Undelete(context.All().Where(s => s.DeletePending).ToList());
+ }
+
public void Undelete(List items, bool silent = false)
{
beatmapModelManager.Undelete(items, silent);
@@ -259,17 +278,17 @@ namespace osu.Game.Beatmaps
return beatmapModelManager.Import(notification, tasks);
}
- public Task> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default)
+ public Task?> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default)
{
return beatmapModelManager.Import(task, lowPriority, cancellationToken);
}
- public Task> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default)
+ public Task?> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default)
{
return beatmapModelManager.Import(archive, lowPriority, cancellationToken);
}
- public Task> Import(BeatmapSetInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
+ public Task?> Import(BeatmapSetInfo item, ArchiveReader? archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
{
return beatmapModelManager.Import(item, archive, lowPriority, cancellationToken);
}
@@ -280,7 +299,16 @@ namespace osu.Game.Beatmaps
#region Implementation of IWorkingBeatmapCache
- public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo importedBeatmap) => workingBeatmapCache.GetWorkingBeatmap(importedBeatmap);
+ public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo? importedBeatmap) => workingBeatmapCache.GetWorkingBeatmap(importedBeatmap);
+
+ public WorkingBeatmap GetWorkingBeatmap(ILive? importedBeatmap)
+ {
+ WorkingBeatmap working = workingBeatmapCache.GetWorkingBeatmap(null);
+
+ importedBeatmap?.PerformRead(b => working = workingBeatmapCache.GetWorkingBeatmap(b));
+
+ return working;
+ }
void IWorkingBeatmapCache.Invalidate(BeatmapSetInfo beatmapSetInfo) => workingBeatmapCache.Invalidate(beatmapSetInfo);
void IWorkingBeatmapCache.Invalidate(BeatmapInfo beatmapInfo) => workingBeatmapCache.Invalidate(beatmapInfo);
@@ -289,12 +317,12 @@ namespace osu.Game.Beatmaps
#region Implementation of IModelFileManager
- public void ReplaceFile(BeatmapSetInfo model, BeatmapSetFileInfo file, Stream contents)
+ public void ReplaceFile(BeatmapSetInfo model, RealmNamedFileUsage file, Stream contents)
{
beatmapModelManager.ReplaceFile(model, file, contents);
}
- public void DeleteFile(BeatmapSetInfo model, BeatmapSetFileInfo file)
+ public void DeleteFile(BeatmapSetInfo model, RealmNamedFileUsage file)
{
beatmapModelManager.DeleteFile(model, file);
}
@@ -317,7 +345,7 @@ namespace osu.Game.Beatmaps
#region Implementation of IPostImports
- public Action>> PostImport
+ public Action>>? PostImport
{
set => beatmapModelManager.PostImport = value;
}
diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs
index 5da0264893..6349476550 100644
--- a/osu.Game/Beatmaps/BeatmapMetadata.cs
+++ b/osu.Game/Beatmaps/BeatmapMetadata.cs
@@ -2,13 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
using osu.Framework.Testing;
-using osu.Game.Database;
-using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Models;
using osu.Game.Users;
+using Realms;
#nullable enable
@@ -16,12 +14,9 @@ namespace osu.Game.Beatmaps
{
[ExcludeFromDynamicCompile]
[Serializable]
- public class BeatmapMetadata : IEquatable, IHasPrimaryKey, IBeatmapMetadataInfo
+ [MapTo("BeatmapMetadata")]
+ public class BeatmapMetadata : RealmObject, IBeatmapMetadataInfo
{
- public int ID { get; set; }
-
- public bool IsManaged => ID > 0;
-
public string Title { get; set; } = string.Empty;
[JsonProperty("title_unicode")]
@@ -32,39 +27,7 @@ namespace osu.Game.Beatmaps
[JsonProperty("artist_unicode")]
public string ArtistUnicode { get; set; } = string.Empty;
- [JsonIgnore]
- public List Beatmaps { get; set; } = new List();
-
- [JsonIgnore]
- public List BeatmapSets { get; set; } = new List();
-
- ///
- /// The author of the beatmaps in this set.
- ///
- [JsonIgnore]
- public APIUser Author = new APIUser();
-
- ///
- /// Helper property to deserialize a username to .
- ///
- [JsonProperty(@"user_id")]
- [Column("AuthorID")]
- public int AuthorID
- {
- get => Author.Id; // This should not be used, but is required to make EF work correctly.
- set => Author.Id = value;
- }
-
- ///
- /// Helper property to deserialize a username to .
- ///
- [JsonProperty(@"creator")]
- [Column("Author")]
- public string AuthorString
- {
- get => Author.Username; // This should not be used, but is required to make EF work correctly.
- set => Author.Username = value;
- }
+ public RealmUser Author { get; set; } = new RealmUser(); // TODO: not sure we want to initialise this only to have it overwritten by retrieval.
public string Source { get; set; } = string.Empty;
@@ -75,16 +38,23 @@ namespace osu.Game.Beatmaps
/// The time in milliseconds to begin playing the track for preview purposes.
/// If -1, the track should begin playing at 40% of its length.
///
- public int PreviewTime { get; set; } = -1;
+ public int PreviewTime { get; set; }
public string AudioFile { get; set; } = string.Empty;
-
public string BackgroundFile { get; set; } = string.Empty;
- public bool Equals(BeatmapMetadata other) => ((IBeatmapMetadataInfo)this).Equals(other);
+ IUser IBeatmapMetadataInfo.Author => Author;
+
+ #region Compatibility properties
+
+ public string AuthorString
+ {
+ get => Author.Username;
+ set => Author.Username = value;
+ }
+
+ #endregion
public override string ToString() => this.GetDisplayTitle();
-
- IUser IBeatmapMetadataInfo.Author => Author;
}
}
diff --git a/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs
index 7aab6a7a9b..7e7d1babf0 100644
--- a/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs
+++ b/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs
@@ -40,7 +40,7 @@ namespace osu.Game.Beatmaps
///
public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapMetadataInfo metadataInfo, bool includeCreator = true)
{
- string author = !includeCreator || string.IsNullOrEmpty(metadataInfo.Author.Username) ? string.Empty : $"({metadataInfo.Author})";
+ string author = !includeCreator || string.IsNullOrEmpty(metadataInfo.Author.Username) ? string.Empty : $"({metadataInfo.Author.Username})";
string artistUnicode = string.IsNullOrEmpty(metadataInfo.ArtistUnicode) ? metadataInfo.Artist : metadataInfo.ArtistUnicode;
string titleUnicode = string.IsNullOrEmpty(metadataInfo.TitleUnicode) ? metadataInfo.Title : metadataInfo.TitleUnicode;
diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs
index d0c41e0fb8..73ada09ef6 100644
--- a/osu.Game/Beatmaps/BeatmapModelManager.cs
+++ b/osu.Game/Beatmaps/BeatmapModelManager.cs
@@ -3,187 +3,55 @@
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 Decoder = osu.Game.Beatmaps.Formats.Decoder;
+using osu.Game.Stores;
+
+#nullable enable
namespace osu.Game.Beatmaps
{
- ///
- /// Handles ef-core storage of beatmaps.
- ///
[ExcludeFromDynamicCompile]
- public class BeatmapModelManager : ArchiveModelManager
+ public class BeatmapModelManager : BeatmapImporter
{
- ///
- /// Fired when a single difficulty has been hidden.
- ///
- public event Action BeatmapHidden;
-
- ///
- /// Fired when a single difficulty has been restored.
- ///
- public event Action BeatmapRestored;
-
- ///
- /// An online lookup queue component which handles populating online beatmap metadata.
- ///
- public BeatmapOnlineLookupQueue OnlineLookupQueue { private get; set; }
-
///
/// The game working beatmap cache, used to invalidate entries on changes.
///
- public IWorkingBeatmapCache WorkingBeatmapCache { private get; set; }
+ public IWorkingBeatmapCache? WorkingBeatmapCache { private get; set; }
public override IEnumerable HandledExtensions => new[] { ".osz" };
protected override string[] HashableFileTypes => new[] { ".osu" };
- private readonly BeatmapStore beatmaps;
- private readonly RulesetStore rulesets;
-
- public BeatmapModelManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, GameHost host = null)
- : base(storage, contextFactory, new BeatmapStore(contextFactory), host)
+ public BeatmapModelManager(RealmContextFactory contextFactory, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null)
+ : base(contextFactory, storage, onlineLookupQueue)
{
- this.rulesets = rulesets;
-
- beatmaps = (BeatmapStore)ModelStore;
- 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, CancellationToken cancellationToken = default)
- {
- 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 = null;
- 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 = null;
- foreach (var b in existingSetWithSameOnlineID.Beatmaps)
- b.OnlineID = null;
-
- 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 = null);
- }
-
- ///
- /// Delete a beatmap difficulty.
- ///
- /// The beatmap difficulty to hide.
- public void Hide(BeatmapInfo beatmapInfo) => beatmaps.Hide(beatmapInfo);
-
- ///
- /// Restore a beatmap difficulty.
- ///
- /// The beatmap difficulty to restore.
- public void Restore(BeatmapInfo beatmapInfo) => beatmaps.Restore(beatmapInfo);
-
///
/// Saves an file against a given .
///
/// The to save the content against. The file referenced by will be replaced.
/// The content to write.
/// The beatmap content to write, null if to be omitted.
- 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,130 +70,25 @@ namespace osu.Game.Beatmaps
stream.Seek(0, SeekOrigin.Begin);
- using (ContextFactory.GetForWrite())
- {
- beatmapInfo = setInfo.Beatmaps.Single(b => b.Equals(beatmapInfo));
+ // AddFile generally handles updating/replacing files, but this is a case where the filename may have also changed so let's delete for simplicity.
+ var existingFileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase));
+ if (existingFileInfo != null)
+ DeleteFile(setInfo, existingFileInfo);
- var metadata = beatmapInfo.Metadata ?? setInfo.Metadata;
+ beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
+ beatmapInfo.Hash = stream.ComputeSHA2Hash();
- // 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();
-
- // metadata may have changed; update the path with the standard format.
- beatmapInfo.Path = $"{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, getFilename(beatmapInfo));
+ Update(setInfo);
}
WorkingBeatmapCache?.Invalidate(beatmapInfo);
}
- ///
- /// Perform a lookup query on available s.
- ///
- /// The query.
- /// The first result for the provided query, or null if no results were found.
- public BeatmapSetInfo QueryBeatmapSet(Expression> query) => beatmaps.ConsumableItems.AsNoTracking().FirstOrDefault(query);
-
- protected override bool CanSkipImport(BeatmapSetInfo existing, BeatmapSetInfo import)
+ private static string getFilename(BeatmapInfo beatmapInfo)
{
- 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);
- }
-
- ///
- /// Returns a list of all usable s.
- ///
- /// A list of available .
- public List GetAllUsableBeatmapSets(IncludedDetails includes = IncludedDetails.All, bool includeProtected = false) =>
- GetAllUsableBeatmapSetsEnumerable(includes, includeProtected).ToList();
-
- ///
- /// Returns a list of all usable s. Note that files are not populated.
- ///
- /// The level of detail to include in the returned objects.
- /// Whether to include protected (system) beatmaps. These should not be included for gameplay playable use cases.
- /// A list of available .
- public IEnumerable GetAllUsableBeatmapSetsEnumerable(IncludedDetails includes, bool includeProtected = false)
- {
- IQueryable 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));
- }
-
- ///
- /// Perform a lookup query on available s.
- ///
- /// The query.
- /// The level of detail to include in the returned objects.
- /// Results from the provided query.
- public IEnumerable QueryBeatmapSets(Expression> query, IncludedDetails includes = IncludedDetails.All)
- {
- IQueryable 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;
- }
-
- return queryable.AsNoTracking().Where(query);
+ var metadata = beatmapInfo.Metadata;
+ return $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.DifficultyName}].osu".GetValidArchiveContentFilename();
}
///
@@ -333,145 +96,19 @@ namespace osu.Game.Beatmaps
///
/// The query.
/// The first result for the provided query, or null if no results were found.
- public BeatmapInfo QueryBeatmap(Expression> query) => beatmaps.Beatmaps.AsNoTracking().FirstOrDefault(query);
-
- ///
- /// Perform a lookup query on available s.
- ///
- /// The query.
- /// Results from the provided query.
- public IQueryable QueryBeatmaps(Expression> query) => beatmaps.Beatmaps.AsNoTracking().Where(query);
-
- public override string HumanisedModelName => "beatmap";
-
- protected override bool CheckLocalAvailability(BeatmapSetInfo model, IQueryable items)
- => base.CheckLocalAvailability(model, items)
- || (model.OnlineID != null && items.Any(b => b.OnlineID == model.OnlineID));
-
- protected override BeatmapSetInfo CreateModel(ArchiveReader reader)
+ public BeatmapInfo? QueryBeatmap(Expression> query)
{
- // let's make sure there are actually .osu files to import.
- string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu", StringComparison.OrdinalIgnoreCase));
+ using (var context = ContextFactory.CreateContext())
+ return context.All().FirstOrDefault(query)?.Detach();
+ }
- if (string.IsNullOrEmpty(mapName))
+ public void Update(BeatmapSetInfo item)
+ {
+ using (var realm = ContextFactory.CreateContext())
{
- Logger.Log($"No beatmap files found in the beatmap archive ({reader.Name}).", LoggingTarget.Database);
- return null;
+ var existing = realm.Find(item.ID);
+ realm.Write(r => item.CopyChangesToRealm(existing));
}
-
- Beatmap beatmap;
- using (var stream = new LineBufferedReader(reader.GetStream(mapName)))
- beatmap = Decoder.GetDecoder(stream).Decode(stream);
-
- return new BeatmapSetInfo
- {
- OnlineID = beatmap.BeatmapInfo.BeatmapSet?.OnlineID,
- Metadata = beatmap.Metadata,
- DateAdded = DateTimeOffset.UtcNow
- };
}
-
- ///
- /// Create all required s for the provided archive.
- ///
- private List createBeatmapDifficulties(List files)
- {
- var beatmapInfos = new List();
-
- 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(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;
- }
-
- ///
- /// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation.
- ///
- 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;
- }
- }
-
- ///
- /// 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 except ruleset. Used for cases where we aren't sure the ruleset is present but still want to consume the beatmap.
- ///
- AllButRuleset,
-
- ///
- /// Include everything.
- ///
- All
}
}
diff --git a/osu.Game/Beatmaps/BeatmapOnlineLookupQueue.cs b/osu.Game/Beatmaps/BeatmapOnlineLookupQueue.cs
index 76232c2932..a24b6b315a 100644
--- a/osu.Game/Beatmaps/BeatmapOnlineLookupQueue.cs
+++ b/osu.Game/Beatmaps/BeatmapOnlineLookupQueue.cs
@@ -2,6 +2,7 @@
// 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.Threading;
@@ -16,6 +17,7 @@ using osu.Framework.Threading;
using osu.Game.Database;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
+using osu.Game.Stores;
using SharpCompress.Compressors;
using SharpCompress.Compressors.BZip2;
@@ -52,6 +54,12 @@ namespace osu.Game.Beatmaps
prepareLocalCache();
}
+ public void Update(BeatmapSetInfo beatmapSet)
+ {
+ foreach (var b in beatmapSet.Beatmaps)
+ lookup(beatmapSet, b);
+ }
+
public Task UpdateAsync(BeatmapSetInfo beatmapSet, CancellationToken cancellationToken)
{
return Task.WhenAll(beatmapSet.Beatmaps.Select(b => UpdateAsync(beatmapSet, b, cancellationToken)).ToArray());
@@ -71,40 +79,39 @@ namespace osu.Game.Beatmaps
var req = new GetBeatmapRequest(beatmapInfo);
- req.Failure += fail;
-
try
{
// intentionally blocking to limit web request concurrency
api.Perform(req);
+ if (req.CompletionState == APIRequestCompletionState.Failed)
+ {
+ logForModel(set, $"Online retrieval failed for {beatmapInfo}");
+ beatmapInfo.OnlineID = -1;
+ return;
+ }
+
var res = req.Response;
if (res != null)
{
beatmapInfo.Status = res.Status;
+
+ Debug.Assert(beatmapInfo.BeatmapSet != null);
+
beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None;
beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID;
beatmapInfo.OnlineID = res.OnlineID;
- if (beatmapInfo.Metadata != null)
- beatmapInfo.Metadata.AuthorID = res.AuthorID;
-
- if (beatmapInfo.BeatmapSet.Metadata != null)
- beatmapInfo.BeatmapSet.Metadata.AuthorID = res.AuthorID;
+ beatmapInfo.Metadata.Author.OnlineID = res.AuthorID;
logForModel(set, $"Online retrieval mapped {beatmapInfo} to {res.OnlineBeatmapSetID} / {res.OnlineID}.");
}
}
catch (Exception e)
{
- fail(e);
- }
-
- void fail(Exception e)
- {
- beatmapInfo.OnlineID = null;
logForModel(set, $"Online retrieval failed for {beatmapInfo} ({e.Message})");
+ beatmapInfo.OnlineID = -1;
}
}
@@ -161,7 +168,7 @@ namespace osu.Game.Beatmaps
if (string.IsNullOrEmpty(beatmapInfo.MD5Hash)
&& string.IsNullOrEmpty(beatmapInfo.Path)
- && beatmapInfo.OnlineID == null)
+ && beatmapInfo.OnlineID <= 0)
return false;
try
@@ -175,7 +182,7 @@ namespace osu.Game.Beatmaps
cmd.CommandText = "SELECT beatmapset_id, beatmap_id, approved, user_id FROM osu_beatmaps WHERE checksum = @MD5Hash OR beatmap_id = @OnlineID OR filename = @Path";
cmd.Parameters.Add(new SqliteParameter("@MD5Hash", beatmapInfo.MD5Hash));
- cmd.Parameters.Add(new SqliteParameter("@OnlineID", beatmapInfo.OnlineID ?? (object)DBNull.Value));
+ cmd.Parameters.Add(new SqliteParameter("@OnlineID", beatmapInfo.OnlineID));
cmd.Parameters.Add(new SqliteParameter("@Path", beatmapInfo.Path));
using (var reader = cmd.ExecuteReader())
@@ -185,15 +192,14 @@ namespace osu.Game.Beatmaps
var status = (BeatmapOnlineStatus)reader.GetByte(2);
beatmapInfo.Status = status;
+
+ Debug.Assert(beatmapInfo.BeatmapSet != null);
+
beatmapInfo.BeatmapSet.Status = status;
beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0);
beatmapInfo.OnlineID = reader.GetInt32(1);
- if (beatmapInfo.Metadata != null)
- beatmapInfo.Metadata.AuthorID = reader.GetInt32(3);
-
- if (beatmapInfo.BeatmapSet.Metadata != null)
- beatmapInfo.BeatmapSet.Metadata.AuthorID = reader.GetInt32(3);
+ beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3);
logForModel(set, $"Cached local retrieval for {beatmapInfo}.");
return true;
@@ -211,7 +217,7 @@ namespace osu.Game.Beatmaps
}
private void logForModel(BeatmapSetInfo set, string message) =>
- ArchiveModelManager.LogForModel(set, $"[{nameof(BeatmapOnlineLookupQueue)}] {message}");
+ RealmArchiveModelImporter.LogForModel(set, $"[{nameof(BeatmapOnlineLookupQueue)}] {message}");
public void Dispose()
{
diff --git a/osu.Game/Beatmaps/BeatmapSetFileInfo.cs b/osu.Game/Beatmaps/BeatmapSetFileInfo.cs
index 29dcf4d6aa..3d41f59b3d 100644
--- a/osu.Game/Beatmaps/BeatmapSetFileInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetFileInfo.cs
@@ -15,6 +15,8 @@ namespace osu.Game.Beatmaps
public int BeatmapSetInfoID { get; set; }
+ public EFBeatmapSetInfo BeatmapSetInfo { get; set; }
+
public int FileInfoID { get; set; }
public FileInfo FileInfo { get; set; }
@@ -22,6 +24,6 @@ namespace osu.Game.Beatmaps
[Required]
public string Filename { get; set; }
- public IFileInfo File => FileInfo;
+ IFileInfo INamedFileUsage.File => FileInfo;
}
}
diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs
index a3a8f8555f..f6ca184ea3 100644
--- a/osu.Game/Beatmaps/BeatmapSetInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs
@@ -3,102 +3,80 @@
using System;
using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
-using JetBrains.Annotations;
-using Newtonsoft.Json;
using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Extensions;
+using osu.Game.Models;
+using Realms;
+
+#nullable enable
namespace osu.Game.Beatmaps
{
[ExcludeFromDynamicCompile]
- public class BeatmapSetInfo : IHasPrimaryKey, IHasFiles, ISoftDelete, IEquatable, IBeatmapSetInfo
+ [MapTo("BeatmapSet")]
+ public class BeatmapSetInfo : RealmObject, IHasGuidPrimaryKey, IHasRealmFiles, ISoftDelete, IEquatable, IBeatmapSetInfo
{
- public int ID { get; set; }
+ [PrimaryKey]
+ public Guid ID { get; set; } = Guid.NewGuid();
- public bool IsManaged => ID > 0;
-
- private int? onlineID;
-
- [Column("OnlineBeatmapSetID")]
- public int? OnlineID
- {
- get => onlineID;
- set => onlineID = value > 0 ? value : null;
- }
+ [Indexed]
+ public int OnlineID { get; set; } = -1;
public DateTimeOffset DateAdded { get; set; }
- public BeatmapMetadata Metadata { get; set; }
+ public IBeatmapMetadataInfo Metadata => Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata();
- [NotNull]
- public List Beatmaps { get; } = new List();
+ public IList Beatmaps { get; } = null!;
- public BeatmapOnlineStatus Status { get; set; } = BeatmapOnlineStatus.None;
+ public IList Files { get; } = null!;
- public List Files { get; } = new List();
+ public BeatmapOnlineStatus Status
+ {
+ get => (BeatmapOnlineStatus)StatusInt;
+ set => StatusInt = (int)value;
+ }
- ///
- /// The maximum star difficulty of all beatmaps in this set.
- ///
- [JsonIgnore]
- public double MaxStarDifficulty => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.StarRating);
+ [MapTo(nameof(Status))]
+ public int StatusInt { get; set; } = (int)BeatmapOnlineStatus.None;
- ///
- /// The maximum playable length in milliseconds of all beatmaps in this set.
- ///
- [JsonIgnore]
- public double MaxLength => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.Length);
-
- ///
- /// The maximum BPM of all beatmaps in this set.
- ///
- [JsonIgnore]
- public double MaxBPM => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.BPM);
-
- [NotMapped]
public bool DeletePending { get; set; }
- public string Hash { get; set; }
+ public string Hash { get; set; } = string.Empty;
+
+ ///
+ /// Whether deleting this beatmap set should be prohibited (due to it being a system requirement to be present).
+ ///
+ public bool Protected { get; set; }
+
+ public double MaxStarDifficulty => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.StarRating);
+
+ public double MaxLength => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.Length);
+
+ public double MaxBPM => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.BPM);
///
/// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null.
/// The path returned is relative to the user file storage.
///
/// The name of the file to get the storage path of.
- public string GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.GetStoragePath();
+ public string? GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.File.GetStoragePath();
- public override string ToString() => Metadata?.ToString() ?? base.ToString();
-
- public bool Protected { get; set; }
-
- public bool Equals(BeatmapSetInfo other)
+ public bool Equals(BeatmapSetInfo? other)
{
if (ReferenceEquals(this, other)) return true;
if (other == null) return false;
- if (ID != 0 && other.ID != 0)
- return ID == other.ID;
-
- return false;
+ return ID == other.ID;
}
- public bool Equals(IBeatmapSetInfo other) => other is BeatmapSetInfo b && Equals(b);
+ public override string ToString() => Metadata.GetDisplayString();
- #region Implementation of IHasOnlineID
+ public bool Equals(IBeatmapSetInfo? other) => other is BeatmapSetInfo b && Equals(b);
- int IHasOnlineID.OnlineID => OnlineID ?? -1;
-
- #endregion
-
- #region Implementation of IBeatmapSetInfo
-
- IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => Metadata ?? Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata();
IEnumerable IBeatmapSetInfo.Beatmaps => Beatmaps;
- IEnumerable IHasNamedFiles.Files => Files;
- #endregion
+ IEnumerable IHasNamedFiles.Files => Files;
}
}
diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs
deleted file mode 100644
index 197581db88..0000000000
--- a/osu.Game/Beatmaps/BeatmapStore.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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 Microsoft.EntityFrameworkCore;
-using osu.Game.Database;
-
-namespace osu.Game.Beatmaps
-{
- ///
- /// Handles the storage and retrieval of Beatmaps/BeatmapSets to the database backing
- ///
- public class BeatmapStore : MutableDatabaseBackedStoreWithFileIncludes
- {
- public event Action BeatmapHidden;
- public event Action BeatmapRestored;
-
- public BeatmapStore(IDatabaseContextFactory factory)
- : base(factory)
- {
- }
-
- ///
- /// Hide a in the database.
- ///
- /// The beatmap to hide.
- /// Whether the beatmap's was changed.
- public bool Hide(BeatmapInfo beatmapInfo)
- {
- using (ContextFactory.GetForWrite())
- {
- Refresh(ref beatmapInfo, Beatmaps);
-
- if (beatmapInfo.Hidden) return false;
-
- beatmapInfo.Hidden = true;
- }
-
- BeatmapHidden?.Invoke(beatmapInfo);
- return true;
- }
-
- ///
- /// Restore a previously hidden .
- ///
- /// The beatmap to restore.
- /// Whether the beatmap's was changed.
- public bool Restore(BeatmapInfo beatmapInfo)
- {
- using (ContextFactory.GetForWrite())
- {
- Refresh(ref beatmapInfo, Beatmaps);
-
- if (!beatmapInfo.Hidden) return false;
-
- beatmapInfo.Hidden = false;
- }
-
- BeatmapRestored?.Invoke(beatmapInfo);
- return true;
- }
-
- protected override IQueryable AddIncludesForDeletion(IQueryable query) =>
- base.AddIncludesForDeletion(query)
- .Include(s => s.Metadata)
- .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
- .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata);
-
- protected override IQueryable AddIncludesForConsumption(IQueryable query) =>
- base.AddIncludesForConsumption(query)
- .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);
-
- protected override void Purge(List