diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/VisualTestRunner.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/VisualTestRunner.cs
index 4f810ce17f..03ee7c9204 100644
--- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/VisualTestRunner.cs
+++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/VisualTestRunner.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.EmptyFreeform.Tests
[STAThread]
public static int Main(string[] args)
{
- using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+ using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
{
host.Run(new OsuTestBrowser());
return 0;
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/VisualTestRunner.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/VisualTestRunner.cs
index fd6bd9b714..55c0cf6a3b 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/VisualTestRunner.cs
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/VisualTestRunner.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
[STAThread]
public static int Main(string[] args)
{
- using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+ using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
{
host.Run(new OsuTestBrowser());
return 0;
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/VisualTestRunner.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/VisualTestRunner.cs
index 65cfb2bff4..b45505678c 100644
--- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/VisualTestRunner.cs
+++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/VisualTestRunner.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.EmptyScrolling.Tests
[STAThread]
public static int Main(string[] args)
{
- using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+ using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
{
host.Run(new OsuTestBrowser());
return 0;
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/VisualTestRunner.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/VisualTestRunner.cs
index fd6bd9b714..55c0cf6a3b 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/VisualTestRunner.cs
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/VisualTestRunner.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
[STAThread]
public static int Main(string[] args)
{
- using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+ using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
{
host.Run(new OsuTestBrowser());
return 0;
diff --git a/osu.Android.props b/osu.Android.props
index b296c114e9..4e5b9fdbb1 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index 7ec7d53a7e..b944068e78 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -55,7 +55,7 @@ namespace osu.Desktop
}
}
- using (DesktopGameHost host = Host.GetSuitableHost(gameName, true))
+ using (DesktopGameHost host = Host.GetSuitableDesktopHost(gameName, new HostOptions { BindIPC = true }))
{
host.ExceptionThrown += handleException;
diff --git a/osu.Game.Benchmarks/BenchmarkRealmReads.cs b/osu.Game.Benchmarks/BenchmarkRealmReads.cs
new file mode 100644
index 0000000000..bf9467700c
--- /dev/null
+++ b/osu.Game.Benchmarks/BenchmarkRealmReads.cs
@@ -0,0 +1,141 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using System.Threading;
+using BenchmarkDotNet.Attributes;
+using osu.Framework.Testing;
+using osu.Framework.Threading;
+using osu.Game.Beatmaps;
+using osu.Game.Database;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Tests.Resources;
+
+namespace osu.Game.Benchmarks
+{
+ public class BenchmarkRealmReads : BenchmarkTest
+ {
+ private TemporaryNativeStorage storage;
+ private RealmAccess realm;
+ private UpdateThread updateThread;
+
+ [Params(1, 100, 1000)]
+ public int ReadsPerFetch { get; set; }
+
+ public override void SetUp()
+ {
+ storage = new TemporaryNativeStorage("realm-benchmark");
+ storage.DeleteDirectory(string.Empty);
+
+ realm = new RealmAccess(storage, "client");
+
+ realm.Run(r =>
+ {
+ realm.Write(c => c.Add(TestResources.CreateTestBeatmapSetInfo(rulesets: new[] { new OsuRuleset().RulesetInfo })));
+ });
+
+ updateThread = new UpdateThread(() => { }, null);
+ updateThread.Start();
+ }
+
+ [Benchmark]
+ public void BenchmarkDirectPropertyRead()
+ {
+ realm.Run(r =>
+ {
+ var beatmapSet = r.All().First();
+
+ for (int i = 0; i < ReadsPerFetch; i++)
+ {
+ string _ = beatmapSet.Beatmaps.First().Hash;
+ }
+ });
+ }
+
+ [Benchmark]
+ public void BenchmarkDirectPropertyReadUpdateThread()
+ {
+ var done = new ManualResetEventSlim();
+
+ updateThread.Scheduler.Add(() =>
+ {
+ try
+ {
+ var beatmapSet = realm.Realm.All().First();
+
+ for (int i = 0; i < ReadsPerFetch; i++)
+ {
+ string _ = beatmapSet.Beatmaps.First().Hash;
+ }
+ }
+ finally
+ {
+ done.Set();
+ }
+ });
+
+ done.Wait();
+ }
+
+ [Benchmark]
+ public void BenchmarkRealmLivePropertyRead()
+ {
+ realm.Run(r =>
+ {
+ var beatmapSet = r.All().First().ToLive(realm);
+
+ for (int i = 0; i < ReadsPerFetch; i++)
+ {
+ string _ = beatmapSet.PerformRead(b => b.Beatmaps.First().Hash);
+ }
+ });
+ }
+
+ [Benchmark]
+ public void BenchmarkRealmLivePropertyReadUpdateThread()
+ {
+ var done = new ManualResetEventSlim();
+
+ updateThread.Scheduler.Add(() =>
+ {
+ try
+ {
+ var beatmapSet = realm.Realm.All().First().ToLive(realm);
+
+ for (int i = 0; i < ReadsPerFetch; i++)
+ {
+ string _ = beatmapSet.PerformRead(b => b.Beatmaps.First().Hash);
+ }
+ }
+ finally
+ {
+ done.Set();
+ }
+ });
+
+ done.Wait();
+ }
+
+ [Benchmark]
+ public void BenchmarkDetachedPropertyRead()
+ {
+ realm.Run(r =>
+ {
+ var beatmapSet = r.All().First().Detach();
+
+ for (int i = 0; i < ReadsPerFetch; i++)
+ {
+ string _ = beatmapSet.Beatmaps.First().Hash;
+ }
+ });
+ }
+
+ [GlobalCleanup]
+ public void Cleanup()
+ {
+ realm?.Dispose();
+ storage?.Dispose();
+ updateThread?.Exit();
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
index f399f48ebd..2d92c925d7 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
@@ -3,6 +3,7 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Game.Configuration;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods;
@@ -15,9 +16,26 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public override double ScoreMultiplier => 1.12;
- private const float default_flashlight_size = 350;
+ [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
+ public override BindableNumber SizeMultiplier { get; } = new BindableNumber
+ {
+ MinValue = 0.5f,
+ MaxValue = 1.5f,
+ Default = 1f,
+ Value = 1f,
+ Precision = 0.1f
+ };
- public override Flashlight CreateFlashlight() => new CatchFlashlight(playfield);
+ [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
+ public override BindableBool ComboBasedSize { get; } = new BindableBool
+ {
+ Default = true,
+ Value = true
+ };
+
+ public override float DefaultFlashlightSize => 350;
+
+ protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield);
private CatchPlayfield playfield;
@@ -31,10 +49,11 @@ namespace osu.Game.Rulesets.Catch.Mods
{
private readonly CatchPlayfield playfield;
- public CatchFlashlight(CatchPlayfield playfield)
+ public CatchFlashlight(CatchModFlashlight modFlashlight, CatchPlayfield playfield)
+ : base(modFlashlight)
{
this.playfield = playfield;
- FlashlightSize = new Vector2(0, getSizeFor(0));
+ FlashlightSize = new Vector2(0, GetSizeFor(0));
}
protected override void Update()
@@ -44,19 +63,9 @@ namespace osu.Game.Rulesets.Catch.Mods
FlashlightPosition = playfield.CatcherArea.ToSpaceOfOtherDrawable(playfield.Catcher.DrawPosition, this);
}
- private float getSizeFor(int combo)
- {
- if (combo > 200)
- return default_flashlight_size * 0.8f;
- else if (combo > 100)
- return default_flashlight_size * 0.9f;
- else
- return default_flashlight_size;
- }
-
protected override void OnComboChange(ValueChangedEvent e)
{
- this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
+ this.TransformTo(nameof(FlashlightSize), new Vector2(0, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
}
protected override string FragmentShader => "CircularFlashlight";
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
index 86a00271e9..1ee4ea12e3 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
@@ -5,6 +5,7 @@ using System;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Layout;
+using osu.Game.Configuration;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
using osuTK;
@@ -16,17 +17,35 @@ namespace osu.Game.Rulesets.Mania.Mods
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
- private const float default_flashlight_size = 180;
+ [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
+ public override BindableNumber SizeMultiplier { get; } = new BindableNumber
+ {
+ MinValue = 0.5f,
+ MaxValue = 3f,
+ Default = 1f,
+ Value = 1f,
+ Precision = 0.1f
+ };
- public override Flashlight CreateFlashlight() => new ManiaFlashlight();
+ [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
+ public override BindableBool ComboBasedSize { get; } = new BindableBool
+ {
+ Default = false,
+ Value = false
+ };
+
+ public override float DefaultFlashlightSize => 50;
+
+ protected override Flashlight CreateFlashlight() => new ManiaFlashlight(this);
private class ManiaFlashlight : Flashlight
{
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
- public ManiaFlashlight()
+ public ManiaFlashlight(ManiaModFlashlight modFlashlight)
+ : base(modFlashlight)
{
- FlashlightSize = new Vector2(0, default_flashlight_size);
+ FlashlightSize = new Vector2(DrawWidth, GetSizeFor(0));
AddLayout(flashlightProperties);
}
@@ -46,6 +65,7 @@ namespace osu.Game.Rulesets.Mania.Mods
protected override void OnComboChange(ValueChangedEvent e)
{
+ this.TransformTo(nameof(FlashlightSize), new Vector2(DrawWidth, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
}
protected override string FragmentShader => "RectangularFlashlight";
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs
new file mode 100644
index 0000000000..4750c97566
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs
@@ -0,0 +1,98 @@
+// 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.Linq;
+using NUnit.Framework;
+using osu.Framework.Input;
+using osu.Framework.Testing;
+using osu.Framework.Utils;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.UI;
+using osu.Game.Screens.Edit;
+using osu.Game.Screens.Edit.Compose.Components.Timeline;
+using osu.Game.Screens.Edit.Timing;
+using osu.Game.Tests.Beatmaps;
+using osu.Game.Tests.Visual;
+using osuTK;
+using osuTK.Input;
+
+namespace osu.Game.Rulesets.Osu.Tests.Editor
+{
+ public class TestSceneSliderVelocityAdjust : OsuGameTestScene
+ {
+ private Screens.Edit.Editor editor => Game.ScreenStack.CurrentScreen as Screens.Edit.Editor;
+
+ private EditorBeatmap editorBeatmap => editor.ChildrenOfType().FirstOrDefault();
+
+ private EditorClock editorClock => editor.ChildrenOfType().FirstOrDefault();
+
+ private Slider slider => editorBeatmap.HitObjects.OfType().FirstOrDefault();
+
+ private TimelineHitObjectBlueprint blueprint => editor.ChildrenOfType().FirstOrDefault();
+
+ private DifficultyPointPiece difficultyPointPiece => blueprint.ChildrenOfType().First();
+
+ private IndeterminateSliderWithTextBoxInput velocityTextBox => Game.ChildrenOfType().First().ChildrenOfType>().First();
+
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
+
+ private bool editorComponentsReady => editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true
+ && editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true
+ && editor?.ChildrenOfType().FirstOrDefault()?.IsLoaded == true;
+
+ [TestCase(true)]
+ [TestCase(false)]
+ public void TestVelocityChangeSavesCorrectly(bool adjustVelocity)
+ {
+ double? velocity = null;
+
+ AddStep("enter editor", () => Game.ScreenStack.Push(new EditorLoader()));
+ AddUntilStep("wait for editor load", () => editorComponentsReady);
+
+ AddStep("seek to first control point", () => editorClock.Seek(editorBeatmap.ControlPointInfo.TimingPoints.First().Time));
+ AddStep("enter slider placement mode", () => InputManager.Key(Key.Number3));
+
+ AddStep("move mouse to centre", () => InputManager.MoveMouseTo(editor.ChildrenOfType().First().ScreenSpaceDrawQuad.Centre));
+ AddStep("start placement", () => InputManager.Click(MouseButton.Left));
+
+ AddStep("move mouse to bottom right", () => InputManager.MoveMouseTo(editor.ChildrenOfType().First().ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
+ AddStep("end placement", () => InputManager.Click(MouseButton.Right));
+
+ AddStep("exit placement mode", () => InputManager.Key(Key.Number1));
+
+ AddAssert("slider placed", () => slider != null);
+
+ AddStep("select slider", () => editorBeatmap.SelectedHitObjects.Add(slider));
+
+ AddAssert("ensure one slider placed", () => slider != null);
+
+ AddStep("store velocity", () => velocity = slider.Velocity);
+
+ if (adjustVelocity)
+ {
+ AddStep("open velocity adjust panel", () => difficultyPointPiece.TriggerClick());
+ AddStep("change velocity", () => velocityTextBox.Current.Value = 2);
+
+ AddAssert("velocity adjusted", () =>
+ {
+ Debug.Assert(velocity != null);
+ return Precision.AlmostEquals(velocity.Value * 2, slider.Velocity);
+ });
+
+ AddStep("store velocity", () => velocity = slider.Velocity);
+ }
+
+ AddStep("save", () => InputManager.Keys(PlatformAction.Save));
+ AddStep("exit", () => InputManager.Key(Key.Escape));
+
+ AddStep("enter editor (again)", () => Game.ScreenStack.Push(new EditorLoader()));
+ AddUntilStep("wait for editor load", () => editorComponentsReady);
+
+ AddStep("seek to slider", () => editorClock.Seek(slider.StartTime));
+ AddAssert("slider has correct velocity", () => slider.Velocity == velocity);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
index 300a9d48aa..b4eff57c55 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
@@ -12,7 +12,6 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
-using osu.Game.Rulesets.UI;
using osuTK;
namespace osu.Game.Rulesets.Osu.Mods
@@ -21,27 +20,8 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override double ScoreMultiplier => 1.12;
- private const float default_flashlight_size = 180;
-
private const double default_follow_delay = 120;
- private OsuFlashlight flashlight;
-
- public override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight();
-
- public void ApplyToDrawableHitObject(DrawableHitObject drawable)
- {
- if (drawable is DrawableSlider s)
- s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange;
- }
-
- public override void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
- {
- base.ApplyToDrawableRuleset(drawableRuleset);
-
- flashlight.FollowDelay = FollowDelay.Value;
- }
-
[SettingSource("Follow delay", "Milliseconds until the flashlight reaches the cursor")]
public BindableNumber FollowDelay { get; } = new BindableDouble(default_follow_delay)
{
@@ -50,13 +30,45 @@ namespace osu.Game.Rulesets.Osu.Mods
Precision = default_follow_delay,
};
+ [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
+ public override BindableNumber SizeMultiplier { get; } = new BindableNumber
+ {
+ MinValue = 0.5f,
+ MaxValue = 2f,
+ Default = 1f,
+ Value = 1f,
+ Precision = 0.1f
+ };
+
+ [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
+ public override BindableBool ComboBasedSize { get; } = new BindableBool
+ {
+ Default = true,
+ Value = true
+ };
+
+ public override float DefaultFlashlightSize => 180;
+
+ private OsuFlashlight flashlight;
+
+ protected override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight(this);
+
+ public void ApplyToDrawableHitObject(DrawableHitObject drawable)
+ {
+ if (drawable is DrawableSlider s)
+ s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange;
+ }
+
private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition
{
- public double FollowDelay { private get; set; }
+ private readonly double followDelay;
- public OsuFlashlight()
+ public OsuFlashlight(OsuModFlashlight modFlashlight)
+ : base(modFlashlight)
{
- FlashlightSize = new Vector2(0, getSizeFor(0));
+ followDelay = modFlashlight.FollowDelay.Value;
+
+ FlashlightSize = new Vector2(0, GetSizeFor(0));
}
public void OnSliderTrackingChange(ValueChangedEvent e)
@@ -71,24 +83,14 @@ namespace osu.Game.Rulesets.Osu.Mods
var destination = e.MousePosition;
FlashlightPosition = Interpolation.ValueAt(
- Math.Min(Math.Abs(Clock.ElapsedFrameTime), FollowDelay), position, destination, 0, FollowDelay, Easing.Out);
+ Math.Min(Math.Abs(Clock.ElapsedFrameTime), followDelay), position, destination, 0, followDelay, Easing.Out);
return base.OnMouseMove(e);
}
- private float getSizeFor(int combo)
- {
- if (combo > 200)
- return default_flashlight_size * 0.8f;
- else if (combo > 100)
- return default_flashlight_size * 0.9f;
- else
- return default_flashlight_size;
- }
-
protected override void OnComboChange(ValueChangedEvent e)
{
- this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
+ this.TransformTo(nameof(FlashlightSize), new Vector2(0, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
}
protected override string FragmentShader => "CircularFlashlight";
diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs
deleted file mode 100644
index 42ab84714a..0000000000
--- a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs
+++ /dev/null
@@ -1,91 +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.Linq;
-using NUnit.Framework;
-using osu.Framework.Input;
-using osu.Framework.Testing;
-using osu.Framework.Utils;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Edit;
-using osu.Game.Rulesets.Taiko.Beatmaps;
-using osu.Game.Screens.Edit;
-using osu.Game.Screens.Edit.Setup;
-using osu.Game.Screens.Menu;
-using osu.Game.Screens.Select;
-using osu.Game.Tests.Visual;
-using osuTK.Input;
-
-namespace osu.Game.Rulesets.Taiko.Tests.Editor
-{
- public class TestSceneEditorSaving : OsuGameTestScene
- {
- private Screens.Edit.Editor editor => Game.ChildrenOfType().FirstOrDefault();
-
- private EditorBeatmap editorBeatmap => (EditorBeatmap)editor.Dependencies.Get(typeof(EditorBeatmap));
-
- ///
- /// Tests the general expected flow of creating a new beatmap, saving it, then loading it back from song select.
- /// Emphasis is placed on , since taiko has special handling for it to keep compatibility with stable.
- ///
- [Test]
- public void TestNewBeatmapSaveThenLoad()
- {
- AddStep("set default beatmap", () => Game.Beatmap.SetDefault());
- AddStep("set taiko ruleset", () => Ruleset.Value = new TaikoRuleset().RulesetInfo);
-
- PushAndConfirm(() => new EditorLoader());
-
- AddUntilStep("wait for editor load", () => editor?.IsLoaded == true);
-
- AddUntilStep("wait for metadata screen load", () => editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true);
-
- // We intentionally switch away from the metadata screen, else there is a feedback loop with the textbox handling which causes metadata changes below to get overwritten.
-
- AddStep("Enter compose mode", () => InputManager.Key(Key.F1));
- AddUntilStep("Wait for compose mode load", () => editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true);
-
- AddStep("Set slider multiplier", () => editorBeatmap.Difficulty.SliderMultiplier = 2);
- AddStep("Set artist and title", () =>
- {
- editorBeatmap.BeatmapInfo.Metadata.Artist = "artist";
- editorBeatmap.BeatmapInfo.Metadata.Title = "title";
- });
- AddStep("Set difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName = "difficulty");
-
- checkMutations();
-
- AddStep("Save", () => InputManager.Keys(PlatformAction.Save));
-
- checkMutations();
-
- AddStep("Exit", () => InputManager.Key(Key.Escape));
-
- AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
-
- PushAndConfirm(() => new PlaySongSelect());
-
- AddUntilStep("Wait for beatmap selected", () => !Game.Beatmap.IsDefault);
- AddStep("Open options", () => InputManager.Key(Key.F3));
- AddStep("Enter editor", () => InputManager.Key(Key.Number5));
-
- AddUntilStep("Wait for editor load", () => editor != null);
-
- checkMutations();
- }
-
- private void checkMutations()
- {
- AddAssert("Beatmap has correct slider multiplier", () =>
- {
- // we can only assert value correctness on TaikoMultiplierAppliedDifficulty, because that is the final difficulty converted taiko beatmaps use.
- // therefore, ensure that we have that difficulty type by calling .CopyFrom(), which is a no-op if the type is already correct.
- var taikoDifficulty = new TaikoBeatmapConverter.TaikoMultiplierAppliedDifficulty();
- taikoDifficulty.CopyFrom(editorBeatmap.Difficulty);
- return Precision.AlmostEquals(taikoDifficulty.SliderMultiplier, 2);
- });
- AddAssert("Beatmap has correct metadata", () => editorBeatmap.BeatmapInfo.Metadata.Artist == "artist" && editorBeatmap.BeatmapInfo.Metadata.Title == "title");
- AddAssert("Beatmap has correct difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName == "difficulty");
- }
- }
-}
diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs
new file mode 100644
index 0000000000..33c2ba532e
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs
@@ -0,0 +1,38 @@
+// 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.Utils;
+using osu.Game.Rulesets.Taiko.Beatmaps;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Taiko.Tests.Editor
+{
+ public class TestSceneTaikoEditorSaving : EditorSavingTestScene
+ {
+ protected override Ruleset CreateRuleset() => new TaikoRuleset();
+
+ [Test]
+ public void TestTaikoSliderMultiplier()
+ {
+ AddStep("Set slider multiplier", () => EditorBeatmap.Difficulty.SliderMultiplier = 2);
+
+ SaveEditor();
+
+ AddAssert("Beatmap has correct slider multiplier", assertTaikoSliderMulitplier);
+
+ ReloadEditorToSameBeatmap();
+
+ AddAssert("Beatmap still has correct slider multiplier", assertTaikoSliderMulitplier);
+
+ bool assertTaikoSliderMulitplier()
+ {
+ // we can only assert value correctness on TaikoMultiplierAppliedDifficulty, because that is the final difficulty converted taiko beatmaps use.
+ // therefore, ensure that we have that difficulty type by calling .CopyFrom(), which is a no-op if the type is already correct.
+ var taikoDifficulty = new TaikoBeatmapConverter.TaikoMultiplierAppliedDifficulty();
+ taikoDifficulty.CopyFrom(EditorBeatmap.Difficulty);
+ return Precision.AlmostEquals(taikoDifficulty.SliderMultiplier, 2);
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
index 0a325f174e..fb07c687bb 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
@@ -4,6 +4,7 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Layout;
+using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.UI;
@@ -16,9 +17,26 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public override double ScoreMultiplier => 1.12;
- private const float default_flashlight_size = 250;
+ [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
+ public override BindableNumber SizeMultiplier { get; } = new BindableNumber
+ {
+ MinValue = 0.5f,
+ MaxValue = 1.5f,
+ Default = 1f,
+ Value = 1f,
+ Precision = 0.1f
+ };
- public override Flashlight CreateFlashlight() => new TaikoFlashlight(playfield);
+ [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
+ public override BindableBool ComboBasedSize { get; } = new BindableBool
+ {
+ Default = true,
+ Value = true
+ };
+
+ public override float DefaultFlashlightSize => 250;
+
+ protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, playfield);
private TaikoPlayfield playfield;
@@ -33,7 +51,8 @@ namespace osu.Game.Rulesets.Taiko.Mods
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
private readonly TaikoPlayfield taikoPlayfield;
- public TaikoFlashlight(TaikoPlayfield taikoPlayfield)
+ public TaikoFlashlight(TaikoModFlashlight modFlashlight, TaikoPlayfield taikoPlayfield)
+ : base(modFlashlight)
{
this.taikoPlayfield = taikoPlayfield;
FlashlightSize = getSizeFor(0);
@@ -43,15 +62,8 @@ namespace osu.Game.Rulesets.Taiko.Mods
private Vector2 getSizeFor(int combo)
{
- float size = default_flashlight_size;
-
- if (combo > 200)
- size *= 0.8f;
- else if (combo > 100)
- size *= 0.9f;
-
// Preserve flashlight size through the playfield's aspect adjustment.
- return new Vector2(0, size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT);
+ return new Vector2(0, GetSizeFor(combo) * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT);
}
protected override void OnComboChange(ValueChangedEvent e)
diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs
index 8ca996159b..a106c4f629 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs
@@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
if (!effectPoint.KiaiMode)
return;
- if (beatIndex % (int)timingPoint.TimeSignature != 0)
+ if (beatIndex % timingPoint.TimeSignature.Numerator != 0)
return;
double duration = timingPoint.BeatLength * 2;
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
index 6ec14e6351..0459753b28 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
@@ -178,17 +178,17 @@ namespace osu.Game.Tests.Beatmaps.Formats
var timingPoint = controlPoints.TimingPointAt(0);
Assert.AreEqual(956, timingPoint.Time);
Assert.AreEqual(329.67032967033, timingPoint.BeatLength);
- Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
+ Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
timingPoint = controlPoints.TimingPointAt(48428);
Assert.AreEqual(956, timingPoint.Time);
Assert.AreEqual(329.67032967033d, timingPoint.BeatLength);
- Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
+ Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
timingPoint = controlPoints.TimingPointAt(119637);
Assert.AreEqual(119637, timingPoint.Time);
Assert.AreEqual(659.340659340659, timingPoint.BeatLength);
- Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
+ Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
var difficultyPoint = controlPoints.DifficultyPointAt(0);
Assert.AreEqual(0, difficultyPoint.Time);
diff --git a/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs b/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs
index 44f6943871..9e440c6bce 100644
--- a/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs
+++ b/osu.Game.Tests/Beatmaps/IO/BeatmapImportHelper.cs
@@ -53,10 +53,9 @@ namespace osu.Game.Tests.Beatmaps.IO
private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)
{
- var realmContextFactory = osu.Dependencies.Get();
+ var realm = osu.Dependencies.Get();
- using (var realm = realmContextFactory.CreateContext())
- BeatmapImporterTests.EnsureLoaded(realm, timeout);
+ realm.Run(r => BeatmapImporterTests.EnsureLoaded(r, timeout));
// TODO: add back some extra checks outside of the realm ones?
// var set = queryBeatmapSets().First();
diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs
index 53e4ef07e7..5cbede54f5 100644
--- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs
+++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs
@@ -155,7 +155,7 @@ namespace osu.Game.Tests.Collections.IO
}
// Name matches the automatically chosen name from `CleanRunHeadlessGameHost` above, so we end up using the same storage location.
- using (HeadlessGameHost host = new TestRunHeadlessGameHost(firstRunName))
+ using (HeadlessGameHost host = new TestRunHeadlessGameHost(firstRunName, null))
{
try
{
diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs
index 227314cffd..2c7d0211a0 100644
--- a/osu.Game.Tests/Database/BeatmapImporterTests.cs
+++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs
@@ -38,12 +38,12 @@ namespace osu.Game.Tests.Database
[Test]
public void TestDetachBeatmapSet()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using (var importer = new BeatmapModelManager(realmFactory, storage))
- using (new RulesetStore(realmFactory, storage))
+ using (var importer = new BeatmapModelManager(realm, storage))
+ using (new RulesetStore(realm, storage))
{
- ILive? beatmapSet;
+ Live? beatmapSet;
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
beatmapSet = await importer.Import(reader);
@@ -82,12 +82,12 @@ namespace osu.Game.Tests.Database
[Test]
public void TestUpdateDetachedBeatmapSet()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using (var importer = new BeatmapModelManager(realmFactory, storage))
- using (new RulesetStore(realmFactory, storage))
+ using (var importer = new BeatmapModelManager(realm, storage))
+ using (new RulesetStore(realm, storage))
{
- ILive? beatmapSet;
+ Live? beatmapSet;
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
beatmapSet = await importer.Import(reader);
@@ -139,53 +139,53 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportBeatmapThenCleanup()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using (var importer = new BeatmapModelManager(realmFactory, storage))
- using (new RulesetStore(realmFactory, storage))
+ using (var importer = new BeatmapModelManager(realm, storage))
+ using (new RulesetStore(realm, storage))
{
- ILive? imported;
+ Live? imported;
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
imported = await importer.Import(reader);
- Assert.AreEqual(1, realmFactory.Context.All().Count());
+ Assert.AreEqual(1, realm.Realm.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, realm.Realm.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((realm, _) => { Assert.AreEqual(0, realm.Realm.All().Count()); });
}
[Test]
public void TestImportWhenClosed()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
- await LoadOszIntoStore(importer, realmFactory.Context);
+ await LoadOszIntoStore(importer, realm.Realm);
});
}
[Test]
public void TestAccessFileAfterImport()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
var beatmap = imported.Beatmaps.First();
var file = beatmap.File;
@@ -198,33 +198,33 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportThenDelete()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
- deleteBeatmapSet(imported, realmFactory.Context);
+ deleteBeatmapSet(imported, realm.Realm);
});
}
[Test]
public void TestImportThenDeleteFromStream()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? tempPath = TestResources.GetTestBeatmapForImport();
- ILive? importedSet;
+ Live? importedSet;
using (var stream = File.OpenRead(tempPath))
{
importedSet = await importer.Import(new ImportTask(stream, Path.GetFileName(tempPath)));
- EnsureLoaded(realmFactory.Context);
+ EnsureLoaded(realm.Realm);
}
Assert.NotNull(importedSet);
@@ -233,39 +233,39 @@ 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 = realm.Realm.All().First(beatmapSet => beatmapSet.ID == importedSet.ID);
- deleteBeatmapSet(imported, realmFactory.Context);
+ deleteBeatmapSet(imported, realm.Realm);
});
}
[Test]
public void TestImportThenImport()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
- var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
+ var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
// 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(realmFactory.Context, 1);
- checkSingleReferencedFileCount(realmFactory.Context, 18);
+ checkBeatmapSetCount(realm.Realm, 1);
+ checkSingleReferencedFileCount(realm.Realm, 18);
});
}
[Test]
public void TestImportThenImportWithReZip()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -274,7 +274,7 @@ namespace osu.Game.Tests.Database
try
{
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
string hashBefore = hashFile(temp);
@@ -292,7 +292,7 @@ namespace osu.Game.Tests.Database
var importedSecondTime = await importer.Import(new ImportTask(temp));
- EnsureLoaded(realmFactory.Context);
+ EnsureLoaded(realm.Realm);
Assert.NotNull(importedSecondTime);
Debug.Assert(importedSecondTime != null);
@@ -311,10 +311,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportThenImportWithChangedHashedFile()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -323,9 +323,9 @@ namespace osu.Game.Tests.Database
try
{
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
- await createScoreForBeatmap(realmFactory.Context, imported.Beatmaps.First());
+ await createScoreForBeatmap(realm.Realm, imported.Beatmaps.First());
using (var zip = ZipArchive.Open(temp))
zip.WriteToDirectory(extractedFolder);
@@ -343,7 +343,7 @@ namespace osu.Game.Tests.Database
var importedSecondTime = await importer.Import(new ImportTask(temp));
- EnsureLoaded(realmFactory.Context);
+ EnsureLoaded(realm.Realm);
// check the newly "imported" beatmap is not the original.
Assert.NotNull(importedSecondTime);
@@ -363,10 +363,10 @@ namespace osu.Game.Tests.Database
[Ignore("intentionally broken by import optimisations")]
public void TestImportThenImportWithChangedFile()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -375,7 +375,7 @@ namespace osu.Game.Tests.Database
try
{
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
using (var zip = ZipArchive.Open(temp))
zip.WriteToDirectory(extractedFolder);
@@ -392,7 +392,7 @@ namespace osu.Game.Tests.Database
var importedSecondTime = await importer.Import(new ImportTask(temp));
- EnsureLoaded(realmFactory.Context);
+ EnsureLoaded(realm.Realm);
Assert.NotNull(importedSecondTime);
Debug.Assert(importedSecondTime != null);
@@ -411,10 +411,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportThenImportWithDifferentFilename()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -423,7 +423,7 @@ namespace osu.Game.Tests.Database
try
{
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
using (var zip = ZipArchive.Open(temp))
zip.WriteToDirectory(extractedFolder);
@@ -440,7 +440,7 @@ namespace osu.Game.Tests.Database
var importedSecondTime = await importer.Import(new ImportTask(temp));
- EnsureLoaded(realmFactory.Context);
+ EnsureLoaded(realm.Realm);
Assert.NotNull(importedSecondTime);
Debug.Assert(importedSecondTime != null);
@@ -460,12 +460,12 @@ namespace osu.Game.Tests.Database
[Ignore("intentionally broken by import optimisations")]
public void TestImportCorruptThenImport()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
var firstFile = imported.Files.First();
@@ -476,7 +476,7 @@ namespace osu.Game.Tests.Database
using (var stream = storage.GetStream(firstFile.File.GetStoragePath(), FileAccess.Write, FileMode.Create))
stream.WriteByte(0);
- var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
+ var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
using (var stream = storage.GetStream(firstFile.File.GetStoragePath()))
Assert.AreEqual(stream.Length, originalLength, "Corruption was not fixed on second import");
@@ -485,18 +485,18 @@ namespace osu.Game.Tests.Database
Assert.IsTrue(imported.ID == importedSecondTime.ID);
Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
- checkBeatmapSetCount(realmFactory.Context, 1);
- checkSingleReferencedFileCount(realmFactory.Context, 18);
+ checkBeatmapSetCount(realm.Realm, 1);
+ checkSingleReferencedFileCount(realm.Realm, 18);
});
}
[Test]
public void TestModelCreationFailureDoesntReturn()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
var progressNotification = new ImportProgressNotification();
@@ -510,8 +510,8 @@ namespace osu.Game.Tests.Database
new ImportTask(zipStream, string.Empty)
);
- checkBeatmapSetCount(realmFactory.Context, 0);
- checkBeatmapCount(realmFactory.Context, 0);
+ checkBeatmapSetCount(realm.Realm, 0);
+ checkBeatmapCount(realm.Realm, 0);
Assert.IsEmpty(imported);
Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State);
@@ -521,7 +521,7 @@ namespace osu.Game.Tests.Database
[Test]
public void TestRollbackOnFailure()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
int loggedExceptionCount = 0;
@@ -531,16 +531,16 @@ namespace osu.Game.Tests.Database
Interlocked.Increment(ref loggedExceptionCount);
};
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
- realmFactory.Context.Write(() => imported.Hash += "-changed");
+ realm.Realm.Write(() => imported.Hash += "-changed");
- checkBeatmapSetCount(realmFactory.Context, 1);
- checkBeatmapCount(realmFactory.Context, 12);
- checkSingleReferencedFileCount(realmFactory.Context, 18);
+ checkBeatmapSetCount(realm.Realm, 1);
+ checkBeatmapCount(realm.Realm, 12);
+ checkSingleReferencedFileCount(realm.Realm, 18);
string? brokenTempFilename = TestResources.GetTestBeatmapForImport();
@@ -565,10 +565,10 @@ namespace osu.Game.Tests.Database
{
}
- checkBeatmapSetCount(realmFactory.Context, 1);
- checkBeatmapCount(realmFactory.Context, 12);
+ checkBeatmapSetCount(realm.Realm, 1);
+ checkBeatmapCount(realm.Realm, 12);
- checkSingleReferencedFileCount(realmFactory.Context, 18);
+ checkSingleReferencedFileCount(realm.Realm, 18);
Assert.AreEqual(1, loggedExceptionCount);
@@ -579,18 +579,18 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportThenDeleteThenImportOptimisedPath()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
- deleteBeatmapSet(imported, realmFactory.Context);
+ deleteBeatmapSet(imported, realm.Realm);
Assert.IsTrue(imported.DeletePending);
- var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
+ var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
Assert.IsTrue(imported.ID == importedSecondTime.ID);
@@ -601,20 +601,52 @@ namespace osu.Game.Tests.Database
}
[Test]
- public void TestImportThenDeleteThenImportNonOptimisedPath()
+ public void TestImportThenReimportAfterMissingFiles()
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
- using var importer = new NonOptimisedBeatmapImporter(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realmFactory.Realm);
- deleteBeatmapSet(imported, realmFactory.Context);
+ deleteBeatmapSet(imported, realmFactory.Realm);
Assert.IsTrue(imported.DeletePending);
- var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
+ // intentionally nuke all files
+ storage.DeleteDirectory("files");
+
+ Assert.That(imported.Files.All(f => !storage.GetStorageForDirectory("files").Exists(f.File.GetStoragePath())));
+
+ var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Realm);
+
+ // 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);
+ Assert.IsFalse(imported.DeletePending);
+ Assert.IsFalse(importedSecondTime.DeletePending);
+
+ // check that the files now exist, even though they were deleted above.
+ Assert.That(importedSecondTime.Files.All(f => storage.GetStorageForDirectory("files").Exists(f.File.GetStoragePath())));
+ });
+ }
+
+ [Test]
+ public void TestImportThenDeleteThenImportNonOptimisedPath()
+ {
+ RunTestWithRealmAsync(async (realm, storage) =>
+ {
+ using var importer = new NonOptimisedBeatmapImporter(realm, storage);
+ using var store = new RulesetStore(realm, storage);
+
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
+
+ deleteBeatmapSet(imported, realm.Realm);
+
+ Assert.IsTrue(imported.DeletePending);
+
+ var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
Assert.IsTrue(imported.ID == importedSecondTime.ID);
@@ -627,22 +659,22 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportThenDeleteThenImportWithOnlineIDsMissing()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
- var imported = await LoadOszIntoStore(importer, realmFactory.Context);
+ var imported = await LoadOszIntoStore(importer, realm.Realm);
- realmFactory.Context.Write(() =>
+ realm.Realm.Write(() =>
{
foreach (var b in imported.Beatmaps)
b.OnlineID = -1;
});
- deleteBeatmapSet(imported, realmFactory.Context);
+ deleteBeatmapSet(imported, realm.Realm);
- var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
+ var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
// check the newly "imported" beatmap has been reimported due to mismatch (even though hashes matched)
Assert.IsTrue(imported.ID != importedSecondTime.ID);
@@ -653,10 +685,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportWithDuplicateBeatmapIDs()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealm((realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
var metadata = new BeatmapMetadata
{
@@ -667,7 +699,7 @@ namespace osu.Game.Tests.Database
}
};
- var ruleset = realmFactory.Context.All().First();
+ var ruleset = realm.Realm.All().First();
var toImport = new BeatmapSetInfo
{
@@ -686,7 +718,7 @@ namespace osu.Game.Tests.Database
}
};
- var imported = await importer.Import(toImport);
+ var imported = importer.Import(toImport);
Assert.NotNull(imported);
Debug.Assert(imported != null);
@@ -699,15 +731,15 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportWhenFileOpen()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
using (File.OpenRead(temp))
await importer.Import(temp);
- EnsureLoaded(realmFactory.Context);
+ EnsureLoaded(realm.Realm);
File.Delete(temp);
Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't");
});
@@ -716,10 +748,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportWithDuplicateHashes()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -740,7 +772,7 @@ namespace osu.Game.Tests.Database
await importer.Import(temp);
- EnsureLoaded(realmFactory.Context);
+ EnsureLoaded(realm.Realm);
}
finally
{
@@ -752,10 +784,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportNestedStructure()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -780,7 +812,7 @@ namespace osu.Game.Tests.Database
Assert.NotNull(imported);
Debug.Assert(imported != null);
- EnsureLoaded(realmFactory.Context);
+ EnsureLoaded(realm.Realm);
Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("subfolder"))), "Files contain common subfolder");
}
@@ -794,10 +826,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportWithIgnoredDirectoryInArchive()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@@ -830,7 +862,7 @@ namespace osu.Game.Tests.Database
Assert.NotNull(imported);
Debug.Assert(imported != null);
- EnsureLoaded(realmFactory.Context);
+ EnsureLoaded(realm.Realm);
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");
@@ -845,22 +877,22 @@ namespace osu.Game.Tests.Database
[Test]
public void TestUpdateBeatmapInfo()
{
- RunTestWithRealmAsync(async (realmFactory, storage) =>
+ RunTestWithRealmAsync(async (realm, storage) =>
{
- using var importer = new BeatmapModelManager(realmFactory, storage);
- using var store = new RulesetStore(realmFactory, storage);
+ using var importer = new BeatmapModelManager(realm, storage);
+ using var store = new RulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
await importer.Import(temp);
// Update via the beatmap, not the beatmap info, to ensure correct linking
- BeatmapSetInfo setToUpdate = realmFactory.Context.All().First();
+ BeatmapSetInfo setToUpdate = realm.Realm.All().First();
var beatmapToUpdate = setToUpdate.Beatmaps.First();
- realmFactory.Context.Write(() => beatmapToUpdate.DifficultyName = "updated");
+ realm.Realm.Write(() => beatmapToUpdate.DifficultyName = "updated");
- BeatmapInfo updatedInfo = realmFactory.Context.All().First(b => b.ID == beatmapToUpdate.ID);
+ BeatmapInfo updatedInfo = realm.Realm.All().First(b => b.ID == beatmapToUpdate.ID);
Assert.That(updatedInfo.DifficultyName, Is.EqualTo("updated"));
});
}
@@ -1004,8 +1036,8 @@ namespace osu.Game.Tests.Database
public class NonOptimisedBeatmapImporter : BeatmapImporter
{
- public NonOptimisedBeatmapImporter(RealmContextFactory realmFactory, Storage storage)
- : base(realmFactory, storage)
+ public NonOptimisedBeatmapImporter(RealmAccess realm, Storage storage)
+ : base(realm, storage)
{
}
diff --git a/osu.Game.Tests/Database/FileStoreTests.cs b/osu.Game.Tests/Database/FileStoreTests.cs
index 3cb4705381..98b0ed99b5 100644
--- a/osu.Game.Tests/Database/FileStoreTests.cs
+++ b/osu.Game.Tests/Database/FileStoreTests.cs
@@ -19,10 +19,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportFile()
{
- RunTestWithRealm((realmFactory, storage) =>
+ RunTestWithRealm((realmAccess, storage) =>
{
- var realm = realmFactory.Context;
- var files = new RealmFileStore(realmFactory, storage);
+ var realm = realmAccess.Realm;
+ var files = new RealmFileStore(realmAccess, storage);
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
@@ -36,10 +36,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestImportSameFileTwice()
{
- RunTestWithRealm((realmFactory, storage) =>
+ RunTestWithRealm((realmAccess, storage) =>
{
- var realm = realmFactory.Context;
- var files = new RealmFileStore(realmFactory, storage);
+ var realm = realmAccess.Realm;
+ var files = new RealmFileStore(realmAccess, storage);
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
@@ -53,10 +53,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestDontPurgeReferenced()
{
- RunTestWithRealm((realmFactory, storage) =>
+ RunTestWithRealm((realmAccess, storage) =>
{
- var realm = realmFactory.Context;
- var files = new RealmFileStore(realmFactory, storage);
+ var realm = realmAccess.Realm;
+ var files = new RealmFileStore(realmAccess, storage);
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
@@ -92,10 +92,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestPurgeUnreferenced()
{
- RunTestWithRealm((realmFactory, storage) =>
+ RunTestWithRealm((realmAccess, storage) =>
{
- var realm = realmFactory.Context;
- var files = new RealmFileStore(realmFactory, storage);
+ var realm = realmAccess.Realm;
+ var files = new RealmFileStore(realmAccess, storage);
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
diff --git a/osu.Game.Tests/Database/GeneralUsageTests.cs b/osu.Game.Tests/Database/GeneralUsageTests.cs
index 0961ad71e4..dc0d42595b 100644
--- a/osu.Game.Tests/Database/GeneralUsageTests.cs
+++ b/osu.Game.Tests/Database/GeneralUsageTests.cs
@@ -21,15 +21,15 @@ namespace osu.Game.Tests.Database
[Test]
public void TestConstructRealm()
{
- RunTestWithRealm((realmFactory, _) => { realmFactory.CreateContext().Refresh(); });
+ RunTestWithRealm((realm, _) => { realm.Run(r => r.Refresh()); });
}
[Test]
public void TestBlockOperations()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
- using (realmFactory.BlockAllOperations())
+ using (realm.BlockAllOperations())
{
}
});
@@ -42,27 +42,26 @@ namespace osu.Game.Tests.Database
[Test]
public void TestNestedContextCreationWithSubscription()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
bool callbackRan = false;
- using (var context = realmFactory.CreateContext())
+ realm.RegisterCustomSubscription(r =>
{
- var subscription = context.All().QueryAsyncWithNotifications((sender, changes, error) =>
+ var subscription = r.All().QueryAsyncWithNotifications((sender, changes, error) =>
{
- using (realmFactory.CreateContext())
+ realm.Run(_ =>
{
callbackRan = true;
- }
+ });
});
// Force the callback above to run.
- using (realmFactory.CreateContext())
- {
- }
+ realm.Run(rr => rr.Refresh());
subscription?.Dispose();
- }
+ return null;
+ });
Assert.IsTrue(callbackRan);
});
@@ -71,32 +70,47 @@ namespace osu.Game.Tests.Database
[Test]
public void TestBlockOperationsWithContention()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
ManualResetEventSlim stopThreadedUsage = new ManualResetEventSlim();
ManualResetEventSlim hasThreadedUsage = new ManualResetEventSlim();
Task.Factory.StartNew(() =>
{
- using (realmFactory.CreateContext())
+ realm.Run(_ =>
{
hasThreadedUsage.Set();
stopThreadedUsage.Wait();
- }
+ });
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler);
hasThreadedUsage.Wait();
+ // Usually the host would run the synchronization context work per frame.
+ // For the sake of keeping this test simple (there's only one update invocation),
+ // let's replace it so we can ensure work is run immediately.
+ SynchronizationContext.SetSynchronizationContext(new ImmediateExecuteSynchronizationContext());
+
Assert.Throws(() =>
{
- using (realmFactory.BlockAllOperations())
+ using (realm.BlockAllOperations())
{
}
});
stopThreadedUsage.Set();
+
+ // Ensure we can block a second time after the usage has ended.
+ using (realm.BlockAllOperations())
+ {
+ }
});
}
+
+ private class ImmediateExecuteSynchronizationContext : SynchronizationContext
+ {
+ public override void Post(SendOrPostCallback d, object? state) => d(state);
+ }
}
}
diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs
index 187fcd3ca7..3f81b36378 100644
--- a/osu.Game.Tests/Database/RealmLiveTests.cs
+++ b/osu.Game.Tests/Database/RealmLiveTests.cs
@@ -21,11 +21,11 @@ namespace osu.Game.Tests.Database
[Test]
public void TestLiveEquality()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
- ILive beatmap = realmFactory.CreateContext().Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata()))).ToLive(realmFactory);
+ Live beatmap = realm.Run(r => r.Write(_ => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata()))).ToLive(realm));
- ILive beatmap2 = realmFactory.CreateContext().All().First().ToLive(realmFactory);
+ Live beatmap2 = realm.Run(r => r.All().First().ToLive(realm));
Assert.AreEqual(beatmap, beatmap2);
});
@@ -34,17 +34,22 @@ namespace osu.Game.Tests.Database
[Test]
public void TestAccessAfterStorageMigrate()
{
- RunTestWithRealm((realmFactory, storage) =>
+ RunTestWithRealm((realm, storage) =>
{
var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
- ILive liveBeatmap;
+ Live? liveBeatmap = null;
- using (var context = realmFactory.CreateContext())
+ realm.Run(r =>
{
- context.Write(r => r.Add(beatmap));
+ r.Write(_ => r.Add(beatmap));
- liveBeatmap = beatmap.ToLive(realmFactory);
+ liveBeatmap = beatmap.ToLive(realm);
+ });
+
+ using (realm.BlockAllOperations())
+ {
+ // recycle realm before migrating
}
using (var migratedStorage = new TemporaryNativeStorage("realm-test-migration-target"))
@@ -53,7 +58,7 @@ namespace osu.Game.Tests.Database
storage.Migrate(migratedStorage);
- Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden));
+ Assert.IsFalse(liveBeatmap?.PerformRead(l => l.Hidden));
}
});
}
@@ -61,14 +66,13 @@ namespace osu.Game.Tests.Database
[Test]
public void TestAccessAfterAttach()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
- var liveBeatmap = beatmap.ToLive(realmFactory);
+ var liveBeatmap = beatmap.ToLive(realm);
- using (var context = realmFactory.CreateContext())
- context.Write(r => r.Add(beatmap));
+ realm.Run(r => r.Write(_ => r.Add(beatmap)));
Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden));
});
@@ -94,17 +98,17 @@ namespace osu.Game.Tests.Database
[Test]
public void TestScopedReadWithoutContext()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
- ILive? liveBeatmap = null;
+ Live? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
- using (var threadContext = realmFactory.CreateContext())
+ realm.Run(threadContext =>
{
var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata())));
- liveBeatmap = beatmap.ToLive(realmFactory);
- }
+ liveBeatmap = beatmap.ToLive(realm);
+ });
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
Debug.Assert(liveBeatmap != null);
@@ -123,17 +127,17 @@ namespace osu.Game.Tests.Database
[Test]
public void TestScopedWriteWithoutContext()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
- ILive? liveBeatmap = null;
+ Live? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
- using (var threadContext = realmFactory.CreateContext())
+ realm.Run(threadContext =>
{
var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata())));
- liveBeatmap = beatmap.ToLive(realmFactory);
- }
+ liveBeatmap = beatmap.ToLive(realm);
+ });
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
Debug.Assert(liveBeatmap != null);
@@ -149,10 +153,10 @@ namespace osu.Game.Tests.Database
[Test]
public void TestValueAccessNonManaged()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
- var liveBeatmap = beatmap.ToLive(realmFactory);
+ var liveBeatmap = beatmap.ToLive(realm);
Assert.DoesNotThrow(() =>
{
@@ -164,18 +168,18 @@ namespace osu.Game.Tests.Database
[Test]
public void TestValueAccessWithOpenContextFails()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
- ILive? liveBeatmap = null;
+ Live? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
- using (var threadContext = realmFactory.CreateContext())
+ realm.Run(threadContext =>
{
var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata())));
- liveBeatmap = beatmap.ToLive(realmFactory);
- }
+ liveBeatmap = beatmap.ToLive(realm);
+ });
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
Debug.Assert(liveBeatmap != null);
@@ -189,13 +193,13 @@ namespace osu.Game.Tests.Database
});
// Can't be used, even from within a valid context.
- using (realmFactory.CreateContext())
+ realm.Run(threadContext =>
{
Assert.Throws(() =>
{
var __ = liveBeatmap.Value;
});
- }
+ });
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
});
}
@@ -203,17 +207,17 @@ namespace osu.Game.Tests.Database
[Test]
public void TestValueAccessWithoutOpenContextFails()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
- ILive? liveBeatmap = null;
+ Live? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
- using (var threadContext = realmFactory.CreateContext())
+ realm.Run(threadContext =>
{
var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata())));
- liveBeatmap = beatmap.ToLive(realmFactory);
- }
+ liveBeatmap = beatmap.ToLive(realm);
+ });
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
Debug.Assert(liveBeatmap != null);
@@ -231,54 +235,56 @@ namespace osu.Game.Tests.Database
[Test]
public void TestLiveAssumptions()
{
- RunTestWithRealm((realmFactory, _) =>
+ RunTestWithRealm((realm, _) =>
{
int changesTriggered = 0;
- using (var updateThreadContext = realmFactory.CreateContext())
+ realm.RegisterCustomSubscription(outerRealm =>
{
- updateThreadContext.All().QueryAsyncWithNotifications(gotChange);
- ILive? liveBeatmap = null;
+ outerRealm.All().QueryAsyncWithNotifications(gotChange);
+ Live? liveBeatmap = null;
Task.Factory.StartNew(() =>
{
- using (var threadContext = realmFactory.CreateContext())
+ realm.Run(innerRealm =>
{
var ruleset = CreateRuleset();
- var beatmap = threadContext.Write(r => r.Add(new BeatmapInfo(ruleset, new BeatmapDifficulty(), new BeatmapMetadata())));
+ var beatmap = innerRealm.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 BeatmapInfo(ruleset, new BeatmapDifficulty(), new BeatmapMetadata())));
+ innerRealm.Write(r => r.Add(new BeatmapInfo(ruleset, new BeatmapDifficulty(), new BeatmapMetadata())));
- liveBeatmap = beatmap.ToLive(realmFactory);
- }
+ liveBeatmap = beatmap.ToLive(realm);
+ });
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
Debug.Assert(liveBeatmap != null);
// not yet seen by main context
- Assert.AreEqual(0, updateThreadContext.All().Count());
+ Assert.AreEqual(0, outerRealm.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, outerRealm.All().Count());
Assert.AreEqual(1, changesTriggered);
// can access properties without a crash.
Assert.IsFalse(resolved.Hidden);
// ReSharper disable once AccessToDisposedClosure
- updateThreadContext.Write(r =>
+ outerRealm.Write(r =>
{
// can use with the main context.
r.Remove(resolved);
});
});
- }
+
+ return null;
+ });
void gotChange(IRealmCollection sender, ChangeSet changes, Exception error)
{
diff --git a/osu.Game.Tests/Database/RealmSubscriptionRegistrationTests.cs b/osu.Game.Tests/Database/RealmSubscriptionRegistrationTests.cs
new file mode 100644
index 0000000000..d62ce3b585
--- /dev/null
+++ b/osu.Game.Tests/Database/RealmSubscriptionRegistrationTests.cs
@@ -0,0 +1,138 @@
+// 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.Allocation;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets;
+using osu.Game.Tests.Resources;
+using Realms;
+
+#nullable enable
+
+namespace osu.Game.Tests.Database
+{
+ [TestFixture]
+ public class RealmSubscriptionRegistrationTests : RealmTest
+ {
+ [Test]
+ public void TestSubscriptionWithContextLoss()
+ {
+ IEnumerable? resolvedItems = null;
+ ChangeSet? lastChanges = null;
+
+ RunTestWithRealm((realm, _) =>
+ {
+ realm.Write(r => r.Add(TestResources.CreateTestBeatmapSetInfo()));
+
+ var registration = realm.RegisterForNotifications(r => r.All(), onChanged);
+
+ testEventsArriving(true);
+
+ // All normal until here.
+ // Now let's yank the main realm context.
+ resolvedItems = null;
+ lastChanges = null;
+
+ using (realm.BlockAllOperations())
+ Assert.That(resolvedItems, Is.Empty);
+
+ realm.Write(r => r.Add(TestResources.CreateTestBeatmapSetInfo()));
+
+ testEventsArriving(true);
+
+ // Now let's try unsubscribing.
+ resolvedItems = null;
+ lastChanges = null;
+
+ registration.Dispose();
+
+ realm.Write(r => r.Add(TestResources.CreateTestBeatmapSetInfo()));
+
+ testEventsArriving(false);
+
+ // And make sure even after another context loss we don't get firings.
+ using (realm.BlockAllOperations())
+ Assert.That(resolvedItems, Is.Null);
+
+ realm.Write(r => r.Add(TestResources.CreateTestBeatmapSetInfo()));
+
+ testEventsArriving(false);
+
+ void testEventsArriving(bool shouldArrive)
+ {
+ realm.Run(r => r.Refresh());
+
+ if (shouldArrive)
+ Assert.That(resolvedItems, Has.One.Items);
+ else
+ Assert.That(resolvedItems, Is.Null);
+
+ realm.Write(r =>
+ {
+ r.RemoveAll();
+ r.RemoveAll();
+ });
+
+ realm.Run(r => r.Refresh());
+
+ if (shouldArrive)
+ Assert.That(lastChanges?.DeletedIndices, Has.One.Items);
+ else
+ Assert.That(lastChanges, Is.Null);
+ }
+ });
+
+ void onChanged(IRealmCollection sender, ChangeSet? changes, Exception error)
+ {
+ if (changes == null)
+ resolvedItems = sender;
+
+ lastChanges = changes;
+ }
+ }
+
+ [Test]
+ public void TestCustomRegisterWithContextLoss()
+ {
+ RunTestWithRealm((realm, _) =>
+ {
+ BeatmapSetInfo? beatmapSetInfo = null;
+
+ realm.Write(r => r.Add(TestResources.CreateTestBeatmapSetInfo()));
+
+ var subscription = realm.RegisterCustomSubscription(r =>
+ {
+ beatmapSetInfo = r.All().First();
+
+ return new InvokeOnDisposal(() => beatmapSetInfo = null);
+ });
+
+ Assert.That(beatmapSetInfo, Is.Not.Null);
+
+ using (realm.BlockAllOperations())
+ {
+ // custom disposal action fired when context lost.
+ Assert.That(beatmapSetInfo, Is.Null);
+ }
+
+ // re-registration after context restore.
+ realm.Run(r => r.Refresh());
+ Assert.That(beatmapSetInfo, Is.Not.Null);
+
+ subscription.Dispose();
+
+ Assert.That(beatmapSetInfo, Is.Null);
+
+ using (realm.BlockAllOperations())
+ Assert.That(beatmapSetInfo, Is.Null);
+
+ realm.Run(r => r.Refresh());
+ Assert.That(beatmapSetInfo, Is.Null);
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Database/RealmTest.cs b/osu.Game.Tests/Database/RealmTest.cs
index 0cee165f75..c2339dd9ad 100644
--- a/osu.Game.Tests/Database/RealmTest.cs
+++ b/osu.Game.Tests/Database/RealmTest.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Tests.Database
storage.DeleteDirectory(string.Empty);
}
- protected void RunTestWithRealm(Action testAction, [CallerMemberName] string caller = "")
+ protected void RunTestWithRealm(Action testAction, [CallerMemberName] string caller = "")
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(callingMethodName: caller))
{
@@ -39,22 +39,22 @@ namespace osu.Game.Tests.Database
// ReSharper disable once AccessToDisposedClosure
var testStorage = new OsuStorage(host, storage.GetStorageForDirectory(caller));
- using (var realmFactory = new RealmContextFactory(testStorage, "client"))
+ using (var realm = new RealmAccess(testStorage, "client"))
{
- Logger.Log($"Running test using realm file {testStorage.GetFullPath(realmFactory.Filename)}");
- testAction(realmFactory, testStorage);
+ Logger.Log($"Running test using realm file {testStorage.GetFullPath(realm.Filename)}");
+ testAction(realm, testStorage);
- realmFactory.Dispose();
+ realm.Dispose();
- Logger.Log($"Final database size: {getFileSize(testStorage, realmFactory)}");
- realmFactory.Compact();
- Logger.Log($"Final database size after compact: {getFileSize(testStorage, realmFactory)}");
+ Logger.Log($"Final database size: {getFileSize(testStorage, realm)}");
+ realm.Compact();
+ Logger.Log($"Final database size after compact: {getFileSize(testStorage, realm)}");
}
}));
}
}
- protected void RunTestWithRealmAsync(Func testAction, [CallerMemberName] string caller = "")
+ protected void RunTestWithRealmAsync(Func testAction, [CallerMemberName] string caller = "")
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(callingMethodName: caller))
{
@@ -62,15 +62,15 @@ namespace osu.Game.Tests.Database
{
var testStorage = storage.GetStorageForDirectory(caller);
- using (var realmFactory = new RealmContextFactory(testStorage, "client"))
+ using (var realm = new RealmAccess(testStorage, "client"))
{
- Logger.Log($"Running test using realm file {testStorage.GetFullPath(realmFactory.Filename)}");
- await testAction(realmFactory, testStorage);
+ Logger.Log($"Running test using realm file {testStorage.GetFullPath(realm.Filename)}");
+ await testAction(realm, testStorage);
- realmFactory.Dispose();
+ realm.Dispose();
- Logger.Log($"Final database size: {getFileSize(testStorage, realmFactory)}");
- realmFactory.Compact();
+ Logger.Log($"Final database size: {getFileSize(testStorage, realm)}");
+ realm.Compact();
}
}));
}
@@ -138,11 +138,11 @@ namespace osu.Game.Tests.Database
}
}
- private static long getFileSize(Storage testStorage, RealmContextFactory realmFactory)
+ private static long getFileSize(Storage testStorage, RealmAccess realm)
{
try
{
- using (var stream = testStorage.GetStream(realmFactory.Filename))
+ using (var stream = testStorage.GetStream(realm.Filename))
return stream?.Length ?? 0;
}
catch
diff --git a/osu.Game.Tests/Database/RulesetStoreTests.cs b/osu.Game.Tests/Database/RulesetStoreTests.cs
index 4416da6f92..7544142b70 100644
--- a/osu.Game.Tests/Database/RulesetStoreTests.cs
+++ b/osu.Game.Tests/Database/RulesetStoreTests.cs
@@ -12,37 +12,37 @@ namespace osu.Game.Tests.Database
[Test]
public void TestCreateStore()
{
- RunTestWithRealm((realmFactory, storage) =>
+ RunTestWithRealm((realm, storage) =>
{
- var rulesets = new RulesetStore(realmFactory, storage);
+ var rulesets = new RulesetStore(realm, storage);
Assert.AreEqual(4, rulesets.AvailableRulesets.Count());
- Assert.AreEqual(4, realmFactory.Context.All().Count());
+ Assert.AreEqual(4, realm.Realm.All().Count());
});
}
[Test]
public void TestCreateStoreTwiceDoesntAddRulesetsAgain()
{
- RunTestWithRealm((realmFactory, storage) =>
+ RunTestWithRealm((realm, storage) =>
{
- var rulesets = new RulesetStore(realmFactory, storage);
- var rulesets2 = new RulesetStore(realmFactory, storage);
+ var rulesets = new RulesetStore(realm, storage);
+ var rulesets2 = new RulesetStore(realm, 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, realm.Realm.All().Count());
});
}
[Test]
public void TestRetrievedRulesetsAreDetached()
{
- RunTestWithRealm((realmFactory, storage) =>
+ RunTestWithRealm((realm, storage) =>
{
- var rulesets = new RulesetStore(realmFactory, storage);
+ var rulesets = new RulesetStore(realm, storage);
Assert.IsFalse(rulesets.AvailableRulesets.First().IsManaged);
Assert.IsFalse(rulesets.GetRuleset(0)?.IsManaged);
diff --git a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs
index e3c1d42667..891801865f 100644
--- a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs
+++ b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Tests.Database
private RealmKeyBindingStore keyBindingStore;
- private RealmContextFactory realmContextFactory;
+ private RealmAccess realm;
[SetUp]
public void SetUp()
@@ -33,8 +33,8 @@ namespace osu.Game.Tests.Database
storage = new NativeStorage(directory.FullName);
- realmContextFactory = new RealmContextFactory(storage, "test");
- keyBindingStore = new RealmKeyBindingStore(realmContextFactory, new ReadableKeyCombinationProvider());
+ realm = new RealmAccess(storage, "test");
+ keyBindingStore = new RealmKeyBindingStore(realm, new ReadableKeyCombinationProvider());
}
[Test]
@@ -60,15 +60,12 @@ namespace osu.Game.Tests.Database
KeyBindingContainer testContainer = new TestKeyBindingContainer();
// Add some excess bindings for an action which only supports 1.
- using (var realm = realmContextFactory.CreateContext())
- using (var transaction = realm.BeginWrite())
+ realm.Write(r =>
{
- realm.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.A)));
- realm.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.S)));
- realm.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.D)));
-
- transaction.Commit();
- }
+ r.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.A)));
+ r.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.S)));
+ r.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.D)));
+ });
Assert.That(queryCount(GlobalAction.Back), Is.EqualTo(3));
@@ -79,13 +76,13 @@ namespace osu.Game.Tests.Database
private int queryCount(GlobalAction? match = null)
{
- using (var realm = realmContextFactory.CreateContext())
+ return realm.Run(r =>
{
- var results = realm.All();
+ var results = r.All();
if (match.HasValue)
results = results.Where(k => k.ActionInt == (int)match.Value);
return results.Count();
- }
+ });
}
[Test]
@@ -95,32 +92,32 @@ namespace osu.Game.Tests.Database
keyBindingStore.Register(testContainer, Enumerable.Empty());
- using (var primaryRealm = realmContextFactory.CreateContext())
+ realm.Run(outerRealm =>
{
- var backBinding = primaryRealm.All().Single(k => k.ActionInt == (int)GlobalAction.Back);
+ var backBinding = outerRealm.All().Single(k => k.ActionInt == (int)GlobalAction.Back);
Assert.That(backBinding.KeyCombination.Keys, Is.EquivalentTo(new[] { InputKey.Escape }));
var tsr = ThreadSafeReference.Create(backBinding);
- using (var threadedContext = realmContextFactory.CreateContext())
+ realm.Run(innerRealm =>
{
- var binding = threadedContext.ResolveReference(tsr);
- threadedContext.Write(() => binding.KeyCombination = new KeyCombination(InputKey.BackSpace));
- }
+ var binding = innerRealm.ResolveReference(tsr);
+ innerRealm.Write(() => binding.KeyCombination = new KeyCombination(InputKey.BackSpace));
+ });
Assert.That(backBinding.KeyCombination.Keys, Is.EquivalentTo(new[] { InputKey.BackSpace }));
// check still correct after re-query.
- backBinding = primaryRealm.All().Single(k => k.ActionInt == (int)GlobalAction.Back);
+ backBinding = outerRealm.All().Single(k => k.ActionInt == (int)GlobalAction.Back);
Assert.That(backBinding.KeyCombination.Keys, Is.EquivalentTo(new[] { InputKey.BackSpace }));
- }
+ });
}
[TearDown]
public void TearDown()
{
- realmContextFactory.Dispose();
+ realm.Dispose();
storage.DeleteDirectory(string.Empty);
}
diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
index f0ebd7a8cc..88862ea28b 100644
--- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
@@ -261,7 +261,7 @@ namespace osu.Game.Tests.Gameplay
public AudioManager AudioManager => Audio;
public IResourceStore Files => null;
public new IResourceStore Resources => base.Resources;
- public RealmContextFactory RealmContextFactory => null;
+ public RealmAccess RealmAccess => null;
public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null;
#endregion
diff --git a/osu.Game.Tests/NonVisual/BarLineGeneratorTest.cs b/osu.Game.Tests/NonVisual/BarLineGeneratorTest.cs
index 834c05fd08..6ae8231deb 100644
--- a/osu.Game.Tests/NonVisual/BarLineGeneratorTest.cs
+++ b/osu.Game.Tests/NonVisual/BarLineGeneratorTest.cs
@@ -26,7 +26,7 @@ namespace osu.Game.Tests.NonVisual
const int beat_length_numerator = 2000;
const int beat_length_denominator = 7;
- const TimeSignatures signature = TimeSignatures.SimpleQuadruple;
+ TimeSignature signature = TimeSignature.SimpleQuadruple;
var beatmap = new Beatmap
{
@@ -49,7 +49,7 @@ namespace osu.Game.Tests.NonVisual
for (int i = 0; i * beat_length_denominator < barLines.Count; i++)
{
var barLine = barLines[i * beat_length_denominator];
- int expectedTime = beat_length_numerator * (int)signature * i;
+ int expectedTime = beat_length_numerator * signature.Numerator * i;
// every seventh bar's start time should be at least greater than the whole number we expect.
// It cannot be less, as that can affect overlapping scroll algorithms
@@ -60,7 +60,7 @@ namespace osu.Game.Tests.NonVisual
Assert.IsTrue(Precision.AlmostEquals(barLine.StartTime, expectedTime));
// check major/minor lines for good measure too
- Assert.AreEqual(i % (int)signature == 0, barLine.Major);
+ Assert.AreEqual(i % signature.Numerator == 0, barLine.Major);
}
}
diff --git a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
index 61ef31e07e..834930a05e 100644
--- a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
+++ b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
@@ -142,19 +142,28 @@ namespace osu.Game.Tests.NonVisual
Assert.That(osuStorage, Is.Not.Null);
+ // In the following tests, realm files are ignored as
+ // - in the case of checking the source, interacting with the pipe files (client.realm.note) may
+ // lead to unexpected behaviour.
+ // - in the case of checking the destination, the files may have already been recreated by the game
+ // as part of the standard migration flow.
+
foreach (string file in osuStorage.IgnoreFiles)
{
- // avoid touching realm files which may be a pipe and break everything.
- // this is also done locally inside OsuStorage via the IgnoreFiles list.
- if (file.EndsWith(".ini", StringComparison.Ordinal))
+ if (!file.Contains("realm", StringComparison.Ordinal))
+ {
Assert.That(File.Exists(Path.Combine(originalDirectory, file)));
- Assert.That(storage.Exists(file), Is.False);
+ Assert.That(storage.Exists(file), Is.False, () => $"{file} exists in destination when it was expected to be ignored");
+ }
}
foreach (string dir in osuStorage.IgnoreDirectories)
{
- Assert.That(Directory.Exists(Path.Combine(originalDirectory, dir)));
- Assert.That(storage.ExistsDirectory(dir), Is.False);
+ if (!dir.Contains("realm", StringComparison.Ordinal))
+ {
+ Assert.That(Directory.Exists(Path.Combine(originalDirectory, dir)));
+ Assert.That(storage.Exists(dir), Is.False, () => $"{dir} exists in destination when it was expected to be ignored");
+ }
}
Assert.That(new StreamReader(Path.Combine(originalDirectory, "storage.ini")).ReadToEnd().Contains($"FullPath = {customPath}"));
diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
index 8c24b2eef8..f9161816e7 100644
--- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
+++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs
@@ -45,8 +45,8 @@ namespace osu.Game.Tests.Online
[BackgroundDependencyLoader]
private void load(AudioManager audio, GameHost host)
{
- Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.CacheAs(beatmaps = new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.CacheAs(beatmaps = new TestBeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
Dependencies.CacheAs(beatmapDownloader = new TestBeatmapModelDownloader(beatmaps, API, host));
}
@@ -60,8 +60,8 @@ namespace osu.Game.Tests.Online
testBeatmapInfo = getTestBeatmapInfo(testBeatmapFile);
testBeatmapSet = testBeatmapInfo.BeatmapSet;
- ContextFactory.Context.Write(r => r.RemoveAll());
- ContextFactory.Context.Write(r => r.RemoveAll());
+ Realm.Write(r => r.RemoveAll());
+ Realm.Write(r => r.RemoveAll());
selectedItem.Value = new PlaylistItem
{
@@ -91,7 +91,7 @@ namespace osu.Game.Tests.Online
addAvailabilityCheckStep("state importing", BeatmapAvailability.Importing);
AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
- AddUntilStep("wait for import", () => beatmaps.CurrentImportTask?.IsCompleted == true);
+ AddUntilStep("wait for import", () => beatmaps.CurrentImport != null);
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
}
@@ -164,32 +164,32 @@ namespace osu.Game.Tests.Online
{
public TaskCompletionSource AllowImport = new TaskCompletionSource();
- public Task> CurrentImportTask { get; private set; }
+ public Live CurrentImport { get; private set; }
- 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)
+ public TestBeatmapManager(Storage storage, RealmAccess realm, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore resources, GameHost host = null, WorkingBeatmap defaultBeatmap = null)
+ : base(storage, realm, rulesets, api, audioManager, resources, host, defaultBeatmap)
{
}
- protected override BeatmapModelManager CreateBeatmapModelManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, BeatmapOnlineLookupQueue onlineLookupQueue)
+ protected override BeatmapModelManager CreateBeatmapModelManager(Storage storage, RealmAccess realm, RulesetStore rulesets, BeatmapOnlineLookupQueue onlineLookupQueue)
{
- return new TestBeatmapModelManager(this, storage, contextFactory, rulesets, onlineLookupQueue);
+ return new TestBeatmapModelManager(this, storage, realm, rulesets, onlineLookupQueue);
}
internal class TestBeatmapModelManager : BeatmapModelManager
{
private readonly TestBeatmapManager testBeatmapManager;
- public TestBeatmapModelManager(TestBeatmapManager testBeatmapManager, Storage storage, RealmContextFactory databaseContextFactory, RulesetStore rulesetStore, BeatmapOnlineLookupQueue beatmapOnlineLookupQueue)
- : base(databaseContextFactory, storage, beatmapOnlineLookupQueue)
+ public TestBeatmapModelManager(TestBeatmapManager testBeatmapManager, Storage storage, RealmAccess databaseAccess, RulesetStore rulesetStore, BeatmapOnlineLookupQueue beatmapOnlineLookupQueue)
+ : base(databaseAccess, storage, beatmapOnlineLookupQueue)
{
this.testBeatmapManager = testBeatmapManager;
}
- public override async Task> Import(BeatmapSetInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
+ public override Live Import(BeatmapSetInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
{
- await testBeatmapManager.AllowImport.Task.ConfigureAwait(false);
- return await (testBeatmapManager.CurrentImportTask = base.Import(item, archive, lowPriority, cancellationToken)).ConfigureAwait(false);
+ testBeatmapManager.AllowImport.Task.WaitSafely();
+ return (testBeatmapManager.CurrentImport = base.Import(item, archive, lowPriority, cancellationToken));
}
}
}
diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs
index d2cab09ac9..81b624f908 100644
--- a/osu.Game.Tests/Resources/TestResources.cs
+++ b/osu.Game.Tests/Resources/TestResources.cs
@@ -80,7 +80,10 @@ namespace osu.Game.Tests.Resources
public static BeatmapSetInfo CreateTestBeatmapSetInfo(int? difficultyCount = null, RulesetInfo[] rulesets = null)
{
int j = 0;
- RulesetInfo getRuleset() => rulesets?[j++ % rulesets.Length] ?? new OsuRuleset().RulesetInfo;
+
+ rulesets ??= new[] { new OsuRuleset().RulesetInfo };
+
+ RulesetInfo getRuleset() => rulesets?[j++ % rulesets.Length];
int setId = Interlocked.Increment(ref importId);
diff --git a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
index dd12c94855..8de9f0a292 100644
--- a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
+++ b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
@@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
@@ -25,7 +24,7 @@ namespace osu.Game.Tests.Scores.IO
public class ImportScoreTest : ImportTest
{
[Test]
- public async Task TestBasicImport()
+ public void TestBasicImport()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
{
@@ -49,7 +48,7 @@ namespace osu.Game.Tests.Scores.IO
BeatmapInfo = beatmap.Beatmaps.First()
};
- var imported = await LoadScoreIntoOsu(osu, toImport);
+ var imported = LoadScoreIntoOsu(osu, toImport);
Assert.AreEqual(toImport.Rank, imported.Rank);
Assert.AreEqual(toImport.TotalScore, imported.TotalScore);
@@ -67,7 +66,7 @@ namespace osu.Game.Tests.Scores.IO
}
[Test]
- public async Task TestImportMods()
+ public void TestImportMods()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
{
@@ -85,7 +84,7 @@ namespace osu.Game.Tests.Scores.IO
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
};
- var imported = await LoadScoreIntoOsu(osu, toImport);
+ var imported = LoadScoreIntoOsu(osu, toImport);
Assert.IsTrue(imported.Mods.Any(m => m is OsuModHardRock));
Assert.IsTrue(imported.Mods.Any(m => m is OsuModDoubleTime));
@@ -98,7 +97,7 @@ namespace osu.Game.Tests.Scores.IO
}
[Test]
- public async Task TestImportStatistics()
+ public void TestImportStatistics()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
{
@@ -120,7 +119,7 @@ namespace osu.Game.Tests.Scores.IO
}
};
- var imported = await LoadScoreIntoOsu(osu, toImport);
+ var imported = LoadScoreIntoOsu(osu, toImport);
Assert.AreEqual(toImport.Statistics[HitResult.Perfect], imported.Statistics[HitResult.Perfect]);
Assert.AreEqual(toImport.Statistics[HitResult.Miss], imported.Statistics[HitResult.Miss]);
@@ -133,7 +132,7 @@ namespace osu.Game.Tests.Scores.IO
}
[Test]
- public async Task TestOnlineScoreIsAvailableLocally()
+ public void TestOnlineScoreIsAvailableLocally()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
{
@@ -143,7 +142,7 @@ namespace osu.Game.Tests.Scores.IO
var beatmap = BeatmapImportHelper.LoadOszIntoOsu(osu, TestResources.GetQuickTestBeatmapForImport()).GetResultSafely();
- await LoadScoreIntoOsu(osu, new ScoreInfo
+ LoadScoreIntoOsu(osu, new ScoreInfo
{
User = new APIUser { Username = "Test user" },
BeatmapInfo = beatmap.Beatmaps.First(),
@@ -168,13 +167,14 @@ namespace osu.Game.Tests.Scores.IO
}
}
- public static async Task LoadScoreIntoOsu(OsuGameBase osu, ScoreInfo score, ArchiveReader archive = null)
+ public static ScoreInfo LoadScoreIntoOsu(OsuGameBase osu, ScoreInfo score, ArchiveReader archive = null)
{
// clone to avoid attaching the input score to realm.
score = score.DeepClone();
var scoreManager = osu.Dependencies.Get();
- await scoreManager.Import(score, archive);
+
+ scoreManager.Import(score, archive);
return scoreManager.Query(_ => true);
}
diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
index 3f063264e0..9b0facd625 100644
--- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
+++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
@@ -235,7 +235,7 @@ namespace osu.Game.Tests.Skins.IO
#endregion
- private void assertCorrectMetadata(ILive import1, string name, string creator, OsuGameBase osu)
+ private void assertCorrectMetadata(Live import1, string name, string creator, OsuGameBase osu)
{
import1.PerformRead(i =>
{
@@ -250,7 +250,7 @@ namespace osu.Game.Tests.Skins.IO
});
}
- private void assertImportedBoth(ILive import1, ILive import2)
+ private void assertImportedBoth(Live import1, Live import2)
{
import1.PerformRead(i1 => import2.PerformRead(i2 =>
{
@@ -260,7 +260,7 @@ namespace osu.Game.Tests.Skins.IO
}));
}
- private void assertImportedOnce(ILive import1, ILive import2)
+ private void assertImportedOnce(Live import1, Live import2)
{
import1.PerformRead(i1 => import2.PerformRead(i2 =>
{
@@ -334,7 +334,7 @@ namespace osu.Game.Tests.Skins.IO
}
}
- private async Task> loadSkinIntoOsu(OsuGameBase osu, ArchiveReader archive = null)
+ private async Task> loadSkinIntoOsu(OsuGameBase osu, ArchiveReader archive = null)
{
var skinManager = osu.Dependencies.Get();
return await skinManager.Import(archive);
diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
index 4ab4c08353..40e7c0a844 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
@@ -47,10 +47,10 @@ namespace osu.Game.Tests.Visual.Background
[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(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(new OsuConfigManager(LocalStorage));
- Dependencies.Cache(ContextFactory);
+ Dependencies.Cache(Realm);
manager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
diff --git a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs
index 18572ac211..d4c13059da 100644
--- a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs
+++ b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs
@@ -36,9 +36,9 @@ namespace osu.Game.Tests.Visual.Collections
[BackgroundDependencyLoader]
private void load(GameHost host)
{
- Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, Resources, host, Beatmap.Default));
- Dependencies.Cache(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesets, null, Audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs
index 243bb71e26..cf6488f721 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs
@@ -13,6 +13,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Edit;
+using osu.Game.Storyboards;
using osu.Game.Tests.Beatmaps.IO;
namespace osu.Game.Tests.Visual.Editing
@@ -37,11 +38,8 @@ namespace osu.Game.Tests.Visual.Editing
base.SetUpSteps();
}
- protected override void LoadEditor()
- {
- Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First());
- base.LoadEditor();
- }
+ protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
+ => beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First());
[Test]
public void TestBasicSwitch()
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs
index 2386446e96..e3fb44534b 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs
@@ -13,6 +13,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Setup;
+using osu.Game.Storyboards;
using osu.Game.Tests.Resources;
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
@@ -39,11 +40,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("make new beatmap unique", () => EditorBeatmap.Metadata.Title = Guid.NewGuid().ToString());
}
- protected override void LoadEditor()
- {
- Beatmap.Value = new DummyWorkingBeatmap(Audio, null);
- base.LoadEditor();
- }
+ protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) => new DummyWorkingBeatmap(Audio, null);
[Test]
public void TestCreateNewBeatmap()
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs
index f89be0adf3..58daab1ce2 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs
@@ -3,92 +3,118 @@
using System.Linq;
using NUnit.Framework;
-using osu.Framework.Input;
+using osu.Framework.Allocation;
using osu.Framework.Testing;
+using osu.Framework.Utils;
using osu.Game.Beatmaps.ControlPoints;
-using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit;
-using osu.Game.Screens.Edit.Setup;
-using osu.Game.Screens.Menu;
-using osu.Game.Screens.Select;
+using osu.Game.Screens.Edit.Compose.Components.Timeline;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Editing
{
- public class TestSceneEditorSaving : OsuGameTestScene
+ public class TestSceneEditorSaving : EditorSavingTestScene
{
- private Editor editor => Game.ChildrenOfType().FirstOrDefault();
-
- private EditorBeatmap editorBeatmap => (EditorBeatmap)editor.Dependencies.Get(typeof(EditorBeatmap));
-
- ///
- /// Tests the general expected flow of creating a new beatmap, saving it, then loading it back from song select.
- ///
[Test]
- public void TestNewBeatmapSaveThenLoad()
+ public void TestMetadata()
{
- AddStep("set default beatmap", () => Game.Beatmap.SetDefault());
-
- PushAndConfirm(() => new EditorLoader());
-
- AddUntilStep("wait for editor load", () => editor?.IsLoaded == true);
-
- AddUntilStep("wait for metadata screen load", () => editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true);
-
- // We intentionally switch away from the metadata screen, else there is a feedback loop with the textbox handling which causes metadata changes below to get overwritten.
-
- AddStep("Enter compose mode", () => InputManager.Key(Key.F1));
- AddUntilStep("Wait for compose mode load", () => editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true);
-
- AddStep("Set overall difficulty", () => editorBeatmap.Difficulty.OverallDifficulty = 7);
AddStep("Set artist and title", () =>
{
- editorBeatmap.BeatmapInfo.Metadata.Artist = "artist";
- editorBeatmap.BeatmapInfo.Metadata.Title = "title";
+ EditorBeatmap.BeatmapInfo.Metadata.Artist = "artist";
+ EditorBeatmap.BeatmapInfo.Metadata.Title = "title";
});
- AddStep("Set difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName = "difficulty");
+ AddStep("Set author", () => EditorBeatmap.BeatmapInfo.Metadata.Author.Username = "author");
+ AddStep("Set difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = "difficulty");
- AddStep("Add timing point", () => editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint()));
+ SaveEditor();
+ AddAssert("Beatmap has correct metadata", () => EditorBeatmap.BeatmapInfo.Metadata.Artist == "artist" && EditorBeatmap.BeatmapInfo.Metadata.Title == "title");
+ AddAssert("Beatmap has correct author", () => EditorBeatmap.BeatmapInfo.Metadata.Author.Username == "author");
+ AddAssert("Beatmap has correct difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName == "difficulty");
+ AddAssert("Beatmap has correct .osu file path", () => EditorBeatmap.BeatmapInfo.Path == "artist - title (author) [difficulty].osu");
+
+ ReloadEditorToSameBeatmap();
+
+ AddAssert("Beatmap still has correct metadata", () => EditorBeatmap.BeatmapInfo.Metadata.Artist == "artist" && EditorBeatmap.BeatmapInfo.Metadata.Title == "title");
+ AddAssert("Beatmap still has correct author", () => EditorBeatmap.BeatmapInfo.Metadata.Author.Username == "author");
+ AddAssert("Beatmap still has correct difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName == "difficulty");
+ AddAssert("Beatmap still has correct .osu file path", () => EditorBeatmap.BeatmapInfo.Path == "artist - title (author) [difficulty].osu");
+ }
+
+ [Test]
+ public void TestConfiguration()
+ {
+ double originalTimelineZoom = 0;
+ double changedTimelineZoom = 0;
+
+ AddStep("Set beat divisor", () => Editor.Dependencies.Get().Value = 16);
+ AddStep("Set timeline zoom", () =>
+ {
+ originalTimelineZoom = EditorBeatmap.BeatmapInfo.TimelineZoom;
+
+ var timeline = Editor.ChildrenOfType().Single();
+ InputManager.MoveMouseTo(timeline);
+ InputManager.PressKey(Key.AltLeft);
+ InputManager.ScrollVerticalBy(15f);
+ InputManager.ReleaseKey(Key.AltLeft);
+ });
+
+ AddAssert("Ensure timeline zoom changed", () =>
+ {
+ changedTimelineZoom = EditorBeatmap.BeatmapInfo.TimelineZoom;
+ return !Precision.AlmostEquals(changedTimelineZoom, originalTimelineZoom);
+ });
+
+ SaveEditor();
+
+ AddAssert("Beatmap has correct beat divisor", () => EditorBeatmap.BeatmapInfo.BeatDivisor == 16);
+ AddAssert("Beatmap has correct timeline zoom", () => EditorBeatmap.BeatmapInfo.TimelineZoom == changedTimelineZoom);
+
+ ReloadEditorToSameBeatmap();
+
+ AddAssert("Beatmap still has correct beat divisor", () => EditorBeatmap.BeatmapInfo.BeatDivisor == 16);
+ AddAssert("Beatmap still has correct timeline zoom", () => EditorBeatmap.BeatmapInfo.TimelineZoom == changedTimelineZoom);
+ }
+
+ [Test]
+ public void TestDifficulty()
+ {
+ AddStep("Set overall difficulty", () => EditorBeatmap.Difficulty.OverallDifficulty = 7);
+
+ SaveEditor();
+
+ AddAssert("Beatmap has correct overall difficulty", () => EditorBeatmap.Difficulty.OverallDifficulty == 7);
+
+ ReloadEditorToSameBeatmap();
+
+ AddAssert("Beatmap still has correct overall difficulty", () => EditorBeatmap.Difficulty.OverallDifficulty == 7);
+ }
+
+ [Test]
+ public void TestHitObjectPlacement()
+ {
+ AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(500, new TimingControlPoint()));
AddStep("Change to placement mode", () => InputManager.Key(Key.Number2));
AddStep("Move to playfield", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre));
AddStep("Place single hitcircle", () => InputManager.Click(MouseButton.Left));
- checkMutations();
+ SaveEditor();
+
+ AddAssert("Beatmap has correct timing point", () => EditorBeatmap.ControlPointInfo.TimingPoints.Single().Time == 500);
// After placement these must be non-default as defaults are read-only.
AddAssert("Placed object has non-default control points", () =>
- editorBeatmap.HitObjects[0].SampleControlPoint != SampleControlPoint.DEFAULT &&
- editorBeatmap.HitObjects[0].DifficultyControlPoint != DifficultyControlPoint.DEFAULT);
+ EditorBeatmap.HitObjects[0].SampleControlPoint != SampleControlPoint.DEFAULT &&
+ EditorBeatmap.HitObjects[0].DifficultyControlPoint != DifficultyControlPoint.DEFAULT);
- AddStep("Save", () => InputManager.Keys(PlatformAction.Save));
+ ReloadEditorToSameBeatmap();
- checkMutations();
+ AddAssert("Beatmap still has correct timing point", () => EditorBeatmap.ControlPointInfo.TimingPoints.Single().Time == 500);
- AddStep("Exit", () => InputManager.Key(Key.Escape));
-
- AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
-
- Screens.Select.SongSelect songSelect = null;
-
- PushAndConfirm(() => songSelect = new PlaySongSelect());
- AddUntilStep("wait for carousel load", () => songSelect.BeatmapSetsLoaded);
-
- AddUntilStep("Wait for beatmap selected", () => !Game.Beatmap.IsDefault);
- AddStep("Open options", () => InputManager.Key(Key.F3));
- AddStep("Enter editor", () => InputManager.Key(Key.Number5));
-
- AddUntilStep("Wait for editor load", () => editor != null);
-
- checkMutations();
- }
-
- private void checkMutations()
- {
- AddAssert("Beatmap contains single hitcircle", () => editorBeatmap.HitObjects.Count == 1);
- AddAssert("Beatmap has correct overall difficulty", () => editorBeatmap.Difficulty.OverallDifficulty == 7);
- AddAssert("Beatmap has correct metadata", () => editorBeatmap.BeatmapInfo.Metadata.Artist == "artist" && editorBeatmap.BeatmapInfo.Metadata.Title == "title");
- AddAssert("Beatmap has correct difficulty name", () => editorBeatmap.BeatmapInfo.DifficultyName == "difficulty");
+ // After placement these must be non-default as defaults are read-only.
+ AddAssert("Placed object still has non-default control points", () =>
+ EditorBeatmap.HitObjects[0].SampleControlPoint != SampleControlPoint.DEFAULT &&
+ EditorBeatmap.HitObjects[0].DifficultyControlPoint != DifficultyControlPoint.DEFAULT);
}
}
}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
index bb630e5d5c..79afc8cf27 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
@@ -17,6 +17,7 @@ using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Components.Timelines.Summary;
using osu.Game.Screens.Edit.GameplayTest;
using osu.Game.Screens.Play;
+using osu.Game.Storyboards;
using osu.Game.Tests.Beatmaps.IO;
using osuTK.Graphics;
using osuTK.Input;
@@ -43,9 +44,11 @@ namespace osu.Game.Tests.Visual.Editing
base.SetUpSteps();
}
+ protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
+ => beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(b => b.RulesetID == 0));
+
protected override void LoadEditor()
{
- Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(b => b.RulesetID == 0));
SelectedMods.Value = new[] { new ModCinema() };
base.LoadEditor();
}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneLabelledTimeSignature.cs b/osu.Game.Tests/Visual/Editing/TestSceneLabelledTimeSignature.cs
new file mode 100644
index 0000000000..b34974dfc7
--- /dev/null
+++ b/osu.Game.Tests/Visual/Editing/TestSceneLabelledTimeSignature.cs
@@ -0,0 +1,88 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Testing;
+using osu.Game.Beatmaps.Timing;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Screens.Edit.Timing;
+
+namespace osu.Game.Tests.Visual.Editing
+{
+ public class TestSceneLabelledTimeSignature : OsuManualInputManagerTestScene
+ {
+ private LabelledTimeSignature timeSignature;
+
+ private void createLabelledTimeSignature(TimeSignature initial) => AddStep("create labelled time signature", () =>
+ {
+ Child = timeSignature = new LabelledTimeSignature
+ {
+ Label = "Time Signature",
+ RelativeSizeAxes = Axes.None,
+ Width = 400,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Current = { Value = initial }
+ };
+ });
+
+ private OsuTextBox numeratorTextBox => timeSignature.ChildrenOfType().Single();
+
+ [Test]
+ public void TestInitialValue()
+ {
+ createLabelledTimeSignature(TimeSignature.SimpleTriple);
+ AddAssert("current is 3/4", () => timeSignature.Current.Value.Equals(TimeSignature.SimpleTriple));
+ }
+
+ [Test]
+ public void TestChangeViaCurrent()
+ {
+ createLabelledTimeSignature(TimeSignature.SimpleQuadruple);
+ AddAssert("current is 4/4", () => timeSignature.Current.Value.Equals(TimeSignature.SimpleQuadruple));
+
+ AddStep("set current to 5/4", () => timeSignature.Current.Value = new TimeSignature(5));
+
+ AddAssert("current is 5/4", () => timeSignature.Current.Value.Equals(new TimeSignature(5)));
+ AddAssert("numerator is 5", () => numeratorTextBox.Current.Value == "5");
+
+ AddStep("set current to 3/4", () => timeSignature.Current.Value = TimeSignature.SimpleTriple);
+
+ AddAssert("current is 3/4", () => timeSignature.Current.Value.Equals(TimeSignature.SimpleTriple));
+ AddAssert("numerator is 3", () => numeratorTextBox.Current.Value == "3");
+ }
+
+ [Test]
+ public void TestChangeNumerator()
+ {
+ createLabelledTimeSignature(TimeSignature.SimpleQuadruple);
+ AddAssert("current is 4/4", () => timeSignature.Current.Value.Equals(TimeSignature.SimpleQuadruple));
+
+ AddStep("focus text box", () => InputManager.ChangeFocus(numeratorTextBox));
+
+ AddStep("set numerator to 7", () => numeratorTextBox.Current.Value = "7");
+ AddAssert("current is 4/4", () => timeSignature.Current.Value.Equals(TimeSignature.SimpleQuadruple));
+
+ AddStep("drop focus", () => InputManager.ChangeFocus(null));
+ AddAssert("current is 7/4", () => timeSignature.Current.Value.Equals(new TimeSignature(7)));
+ }
+
+ [Test]
+ public void TestInvalidChangeRollbackOnCommit()
+ {
+ createLabelledTimeSignature(TimeSignature.SimpleQuadruple);
+ AddAssert("current is 4/4", () => timeSignature.Current.Value.Equals(TimeSignature.SimpleQuadruple));
+
+ AddStep("focus text box", () => InputManager.ChangeFocus(numeratorTextBox));
+
+ AddStep("set numerator to 0", () => numeratorTextBox.Current.Value = "0");
+ AddAssert("current is 4/4", () => timeSignature.Current.Value.Equals(TimeSignature.SimpleQuadruple));
+
+ AddStep("drop focus", () => InputManager.ChangeFocus(null));
+ AddAssert("current is 4/4", () => timeSignature.Current.Value.Equals(TimeSignature.SimpleQuadruple));
+ AddAssert("numerator is 4", () => numeratorTextBox.Current.Value == "4");
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs
index 2544b6c2a1..81ab4712ab 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs
@@ -47,25 +47,25 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
{
- new HitCircle { StartTime = 100 },
- new HitCircle { StartTime = 200, Position = new Vector2(100) },
- new HitCircle { StartTime = 300, Position = new Vector2(200) },
- new HitCircle { StartTime = 400, Position = new Vector2(300) },
+ new HitCircle { StartTime = 500 },
+ new HitCircle { StartTime = 1000, Position = new Vector2(100) },
+ new HitCircle { StartTime = 1500, Position = new Vector2(200) },
+ new HitCircle { StartTime = 2000, Position = new Vector2(300) },
}));
AddStep("select objects", () => EditorBeatmap.SelectedHitObjects.AddRange(addedObjects));
AddStep("nudge forwards", () => InputManager.Key(Key.K));
- AddAssert("objects moved forwards in time", () => addedObjects[0].StartTime > 100);
+ AddAssert("objects moved forwards in time", () => addedObjects[0].StartTime > 500);
AddStep("nudge backwards", () => InputManager.Key(Key.J));
- AddAssert("objects reverted to original position", () => addedObjects[0].StartTime == 100);
+ AddAssert("objects reverted to original position", () => addedObjects[0].StartTime == 500);
}
[Test]
public void TestBasicSelect()
{
- var addedObject = new HitCircle { StartTime = 100 };
+ var addedObject = new HitCircle { StartTime = 500 };
AddStep("add hitobject", () => EditorBeatmap.Add(addedObject));
moveMouseToObject(() => addedObject);
@@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual.Editing
var addedObject2 = new HitCircle
{
- StartTime = 200,
+ StartTime = 1000,
Position = new Vector2(100),
};
@@ -92,10 +92,10 @@ namespace osu.Game.Tests.Visual.Editing
{
var addedObjects = new[]
{
- new HitCircle { StartTime = 100 },
- new HitCircle { StartTime = 200, Position = new Vector2(100) },
- new HitCircle { StartTime = 300, Position = new Vector2(200) },
- new HitCircle { StartTime = 400, Position = new Vector2(300) },
+ new HitCircle { StartTime = 500 },
+ new HitCircle { StartTime = 1000, Position = new Vector2(100) },
+ new HitCircle { StartTime = 1500, Position = new Vector2(200) },
+ new HitCircle { StartTime = 2000, Position = new Vector2(300) },
};
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects));
@@ -125,7 +125,7 @@ namespace osu.Game.Tests.Visual.Editing
[Test]
public void TestBasicDeselect()
{
- var addedObject = new HitCircle { StartTime = 100 };
+ var addedObject = new HitCircle { StartTime = 500 };
AddStep("add hitobject", () => EditorBeatmap.Add(addedObject));
moveMouseToObject(() => addedObject);
@@ -166,11 +166,11 @@ namespace osu.Game.Tests.Visual.Editing
{
var addedObjects = new[]
{
- new HitCircle { StartTime = 100 },
- new HitCircle { StartTime = 200, Position = new Vector2(100) },
- new HitCircle { StartTime = 300, Position = new Vector2(200) },
- new HitCircle { StartTime = 400, Position = new Vector2(300) },
- new HitCircle { StartTime = 500, Position = new Vector2(400) },
+ new HitCircle { StartTime = 500 },
+ new HitCircle { StartTime = 1000, Position = new Vector2(100) },
+ new HitCircle { StartTime = 1500, Position = new Vector2(200) },
+ new HitCircle { StartTime = 2000, Position = new Vector2(300) },
+ new HitCircle { StartTime = 2500, Position = new Vector2(400) },
};
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects));
@@ -236,10 +236,10 @@ namespace osu.Game.Tests.Visual.Editing
{
var addedObjects = new[]
{
- new HitCircle { StartTime = 100 },
- new HitCircle { StartTime = 200, Position = new Vector2(100) },
- new HitCircle { StartTime = 300, Position = new Vector2(200) },
- new HitCircle { StartTime = 400, Position = new Vector2(300) },
+ new HitCircle { StartTime = 500 },
+ new HitCircle { StartTime = 1000, Position = new Vector2(100) },
+ new HitCircle { StartTime = 1500, Position = new Vector2(200) },
+ new HitCircle { StartTime = 2000, Position = new Vector2(300) },
};
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects));
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneNightcoreBeatContainer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneNightcoreBeatContainer.cs
index 951ee1489d..759e4fa4ec 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneNightcoreBeatContainer.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneNightcoreBeatContainer.cs
@@ -24,8 +24,8 @@ namespace osu.Game.Tests.Visual.Gameplay
Add(new ModNightcore.NightcoreBeatContainer());
- AddStep("change signature to quadruple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignatures.SimpleQuadruple));
- AddStep("change signature to triple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignatures.SimpleTriple));
+ AddStep("change signature to quadruple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignature.SimpleQuadruple));
+ AddStep("change signature to triple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignature.SimpleTriple));
}
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
index 8199389b36..8b7e1c4e58 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
@@ -132,7 +132,7 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test]
public void TestScoreImportThenDelete()
{
- ILive imported = null;
+ Live imported = null;
AddStep("create button without replay", () =>
{
@@ -147,7 +147,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded);
- AddStep("import score", () => imported = scoreManager.Import(getScoreInfo(true)).GetResultSafely());
+ AddStep("import score", () => imported = scoreManager.Import(getScoreInfo(true)));
AddUntilStep("state is available", () => downloadButton.State.Value == DownloadState.LocallyAvailable);
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs
index 4754a73f83..642cc68de5 100644
--- a/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs
+++ b/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs
@@ -8,6 +8,8 @@ using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Overlays.Login;
+using osu.Game.Users.Drawables;
+using osuTK.Input;
namespace osu.Game.Tests.Visual.Menus
{
@@ -15,6 +17,7 @@ namespace osu.Game.Tests.Visual.Menus
public class TestSceneLoginPanel : OsuManualInputManagerTestScene
{
private LoginPanel loginPanel;
+ private int hideCount;
[SetUpSteps]
public void SetUpSteps()
@@ -26,6 +29,7 @@ namespace osu.Game.Tests.Visual.Menus
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 0.5f,
+ RequestHide = () => hideCount++,
});
});
}
@@ -51,5 +55,22 @@ namespace osu.Game.Tests.Visual.Menus
AddStep("enter password", () => loginPanel.ChildrenOfType().First().Text = "password");
AddStep("submit", () => loginPanel.ChildrenOfType().First(b => b.Text.ToString() == "Sign in").TriggerClick());
}
+
+ [Test]
+ public void TestClickingOnFlagClosesPanel()
+ {
+ AddStep("reset hide count", () => hideCount = 0);
+
+ AddStep("logout", () => API.Logout());
+ AddStep("enter password", () => loginPanel.ChildrenOfType().First().Text = "password");
+ AddStep("submit", () => loginPanel.ChildrenOfType().First(b => b.Text.ToString() == "Sign in").TriggerClick());
+
+ AddStep("click on flag", () =>
+ {
+ InputManager.MoveMouseTo(loginPanel.ChildrenOfType().First());
+ InputManager.Click(MouseButton.Left);
+ });
+ AddAssert("hide requested", () => hideCount == 1);
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
index 3ebc64cd0b..10a82089b3 100644
--- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
+++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs
@@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual.Menus
Queue<(IWorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null;
// ensure we have at least two beatmaps available to identify the direction the music controller navigated to.
- AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(TestResources.CreateTestBeatmapSetInfo()).WaitSafely(), 5);
+ AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(TestResources.CreateTestBeatmapSetInfo()), 5);
AddStep("import beatmap with track", () =>
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
index d4282ff21e..4cd19b53a4 100644
--- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
@@ -47,9 +47,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
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(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
}
public override void SetUpSteps()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
index 99c867b014..5c8c90e166 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs
@@ -8,7 +8,6 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
-using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
@@ -43,9 +42,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[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(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
}
[Test]
@@ -154,11 +153,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
public void TestDownloadButtonHiddenWhenBeatmapExists()
{
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
- ILive imported = null;
+ Live imported = null;
Debug.Assert(beatmap.BeatmapSet != null);
- AddStep("import beatmap", () => imported = manager.Import(beatmap.BeatmapSet).GetResultSafely());
+ AddStep("import beatmap", () => imported = manager.Import(beatmap.BeatmapSet));
createPlaylistWithBeatmaps(() => imported.PerformRead(s => s.Beatmaps.Detach()));
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
index 373b165acc..3f151a0ae8 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
@@ -61,9 +61,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default));
- Dependencies.Cache(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
}
public override void SetUpSteps()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
index 15ebe0ee00..5465061891 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs
@@ -42,9 +42,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[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(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
beatmaps = new List();
@@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
beatmapSetInfo.Beatmaps.Add(beatmap);
}
- manager.Import(beatmapSetInfo).WaitSafely();
+ manager.Import(beatmapSetInfo);
}
public override void SetUpSteps()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs
index 012a2fd960..9d14d80d07 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs
@@ -38,9 +38,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
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(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
index d547b42891..d970ab6c34 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
@@ -33,9 +33,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
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(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
}
[SetUp]
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs
index 965b142ed7..d83421ee3a 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs
@@ -38,9 +38,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default));
- Dependencies.Cache(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
}
public override void SetUpSteps()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs
index 1c346e09d5..9867e5225e 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs
@@ -40,9 +40,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
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(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs
index 221732910b..42ae279667 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs
@@ -41,9 +41,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
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(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
index 0b0006e437..d933491ab6 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs
@@ -6,7 +6,6 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
-using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Utils;
@@ -34,13 +33,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
[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(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
var beatmapSet = TestResources.CreateTestBeatmapSetInfo();
- manager.Import(beatmapSet).WaitSafely();
+ manager.Import(beatmapSet);
}
public override void SetUpSteps()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
index 39cde0ad87..73c67d26d9 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs
@@ -42,9 +42,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
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(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
}
public override void SetUpSteps()
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
index 0f314242b4..347b4b6c54 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
@@ -50,10 +50,20 @@ namespace osu.Game.Tests.Visual.Navigation
AddStep("close settings", () => Game.Settings.Hide());
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
+
PushAndConfirm(() => new PlaySongSelect());
+ AddUntilStep("wait for selection", () => !Game.Beatmap.IsDefault);
+
AddStep("enter gameplay", () => InputManager.Key(Key.Enter));
+ AddUntilStep("wait for player", () =>
+ {
+ // dismiss any notifications that may appear (ie. muted notification).
+ clickMouseInCentre();
+ return player != null;
+ });
+
AddUntilStep("wait for gameplay", () => player?.IsBreakTime.Value == false);
AddStep("press 'z'", () => InputManager.Key(Key.Z));
@@ -63,6 +73,12 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("key counter did increase", () => keyCounter.CountPresses == 1);
}
+ private void clickMouseInCentre()
+ {
+ InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre);
+ InputManager.Click(MouseButton.Left);
+ }
+
private KeyBindingsSubsection osuBindingSubsection => keyBindingPanel
.ChildrenOfType()
.FirstOrDefault(s => s.Ruleset.ShortName == "osu");
@@ -76,7 +92,7 @@ namespace osu.Game.Tests.Visual.Navigation
.ChildrenOfType().SingleOrDefault();
private RealmKeyBinding firstOsuRulesetKeyBindings => Game.Dependencies
- .Get().Context
+ .Get().Realm
.All()
.AsEnumerable()
.First(k => k.RulesetName == "osu" && k.ActionInt == 0);
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
index f6c53e76c4..63226de750 100644
--- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
@@ -4,7 +4,6 @@
using System;
using System.Linq;
using NUnit.Framework;
-using osu.Framework.Extensions;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Extensions;
@@ -125,7 +124,7 @@ namespace osu.Game.Tests.Visual.Navigation
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
},
}
- }).GetResultSafely()?.Value;
+ })?.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 7bd8110374..7656bf79dc 100644
--- a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs
@@ -4,7 +4,6 @@
using System;
using System.Linq;
using NUnit.Framework;
-using osu.Framework.Extensions;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
@@ -60,7 +59,7 @@ namespace osu.Game.Tests.Visual.Navigation
Ruleset = new OsuRuleset().RulesetInfo
},
}
- }).GetResultSafely()?.Value;
+ })?.Value;
});
}
@@ -135,7 +134,7 @@ namespace osu.Game.Tests.Visual.Navigation
BeatmapInfo = beatmap.Beatmaps.First(),
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo,
User = new GuestUser(),
- }).GetResultSafely().Value;
+ }).Value;
});
AddAssert($"import {i} succeeded", () => imported != null);
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
index bc9f759bdd..68225f6d64 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
@@ -8,7 +8,6 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
-using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
@@ -40,9 +39,9 @@ namespace osu.Game.Tests.Visual.Playlists
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default));
- Dependencies.Cache(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
}
[SetUpSteps]
@@ -151,7 +150,7 @@ namespace osu.Game.Tests.Visual.Playlists
Debug.Assert(modifiedBeatmap.BeatmapInfo.BeatmapSet != null);
- manager.Import(modifiedBeatmap.BeatmapInfo.BeatmapSet).WaitSafely();
+ manager.Import(modifiedBeatmap.BeatmapInfo.BeatmapSet);
});
// Create the room using the real beatmap values.
@@ -196,7 +195,7 @@ namespace osu.Game.Tests.Visual.Playlists
Debug.Assert(originalBeatmap.BeatmapInfo.BeatmapSet != null);
- manager.Import(originalBeatmap.BeatmapInfo.BeatmapSet).WaitSafely();
+ manager.Import(originalBeatmap.BeatmapInfo.BeatmapSet);
});
AddUntilStep("match has correct beatmap", () => realHash == match.Beatmap.Value.BeatmapInfo.MD5Hash);
@@ -219,7 +218,7 @@ namespace osu.Game.Tests.Visual.Playlists
Debug.Assert(beatmap.BeatmapInfo.BeatmapSet != null);
- importedBeatmap = manager.Import(beatmap.BeatmapInfo.BeatmapSet).GetResultSafely()?.Value.Detach();
+ importedBeatmap = manager.Import(beatmap.BeatmapInfo.BeatmapSet)?.Value.Detach();
});
private class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen
diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
index 62500babc1..988f429ff5 100644
--- a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
+++ b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
@@ -36,21 +36,21 @@ namespace osu.Game.Tests.Visual.Ranking
private BeatmapManager beatmaps { get; set; }
[Resolved]
- private RealmContextFactory realmContextFactory { get; set; }
+ private RealmAccess realm { get; set; }
protected override void LoadComplete()
{
base.LoadComplete();
- using (var realm = realmContextFactory.CreateContext())
+ realm.Run(r =>
{
- var beatmapInfo = realm.All()
- .Filter($"{nameof(BeatmapInfo.Ruleset)}.{nameof(RulesetInfo.OnlineID)} = $0", 0)
- .FirstOrDefault();
+ var beatmapInfo = r.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/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 2e1a66be5f..e31be1d51a 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -42,10 +42,10 @@ namespace osu.Game.Tests.Visual.SongSelect
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
- 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);
+ dependencies.Cache(rulesetStore = new RulesetStore(Realm));
+ dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default));
+ dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, Scheduler));
+ Dependencies.Cache(Realm);
return dependencies;
}
@@ -180,7 +180,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"Load new scores via manager", () =>
{
foreach (var score in generateSampleScores(beatmapInfo()))
- scoreManager.Import(score).WaitSafely();
+ scoreManager.Import(score);
});
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs
index b7bc0c37e1..940d001c5b 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs
@@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
-using osu.Framework.Extensions;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Extensions;
@@ -184,7 +183,7 @@ namespace osu.Game.Tests.Visual.SongSelect
beatmap.DifficultyName = $"SR{i + 1}";
}
- return Game.BeatmapManager.Import(beatmapSet).GetResultSafely()?.Value;
+ return Game.BeatmapManager.Import(beatmapSet)?.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 ca8e9d2eff..b384061531 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs
@@ -36,9 +36,9 @@ namespace osu.Game.Tests.Visual.SongSelect
[BackgroundDependencyLoader]
private void load(GameHost host)
{
- Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, Resources, host, Beatmap.Default));
- Dependencies.Cache(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesets, null, Audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(Realm);
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 6295a52bdd..458c6130c7 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -8,7 +8,6 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
-using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
@@ -47,9 +46,9 @@ namespace osu.Game.Tests.Visual.SongSelect
{
// 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(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(Realm);
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, defaultBeatmap = Beatmap.Default));
Dependencies.Cache(music = new MusicController());
@@ -65,13 +64,13 @@ namespace osu.Game.Tests.Visual.SongSelect
{
base.SetUpSteps();
- AddStep("delete all beatmaps", () =>
+ AddStep("reset defaults", () =>
{
Ruleset.Value = new OsuRuleset().RulesetInfo;
- manager?.Delete(manager.GetAllUsableBeatmapSets());
-
Beatmap.SetDefault();
});
+
+ AddStep("delete all beatmaps", () => manager?.Delete());
}
[Test]
@@ -260,7 +259,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("import multi-ruleset map", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
- manager.Import(TestResources.CreateTestBeatmapSetInfo(rulesets: usableRulesets)).WaitSafely();
+ manager.Import(TestResources.CreateTestBeatmapSetInfo(rulesets: usableRulesets));
});
}
else
@@ -675,7 +674,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("import multi-ruleset map", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
- manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets)).WaitSafely();
+ manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets));
});
int previousSetID = 0;
@@ -715,7 +714,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("import multi-ruleset map", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
- manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets)).WaitSafely();
+ manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets));
});
DrawableCarouselBeatmapSet set = null;
@@ -764,7 +763,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))?.Value;
});
AddStep("select the first beatmap of import", () => Beatmap.Value = manager.GetWorkingBeatmap(imported.Beatmaps.First()));
@@ -873,7 +872,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private void addRulesetImportStep(int id) => AddStep($"import test map for ruleset {id}", () => importForRuleset(id));
- private void importForRuleset(int id) => manager.Import(TestResources.CreateTestBeatmapSetInfo(3, rulesets.AvailableRulesets.Where(r => r.OnlineID == id).ToArray())).WaitSafely();
+ private void importForRuleset(int id) => manager.Import(TestResources.CreateTestBeatmapSetInfo(3, rulesets.AvailableRulesets.Where(r => r.OnlineID == id).ToArray()));
private void checkMusicPlaying(bool playing) =>
AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing);
@@ -903,7 +902,7 @@ namespace osu.Game.Tests.Visual.SongSelect
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
for (int i = 0; i < 10; i++)
- manager.Import(TestResources.CreateTestBeatmapSetInfo(difficultyCountPerSet, usableRulesets)).WaitSafely();
+ manager.Import(TestResources.CreateTestBeatmapSetInfo(difficultyCountPerSet, usableRulesets));
});
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs
index 3aa5a759e6..8e5f76a2eb 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs
@@ -28,10 +28,10 @@ namespace osu.Game.Tests.Visual.SongSelect
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
- Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
- Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
- Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, ContextFactory, Scheduler));
- Dependencies.Cache(ContextFactory);
+ Dependencies.Cache(rulesets = new RulesetStore(Realm));
+ Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
+ Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, Scheduler));
+ Dependencies.Cache(Realm);
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
index 1e14e4b3e5..4826d2fb33 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.UserInterface
private BeatmapInfo beatmapInfo;
[Resolved]
- private RealmContextFactory realmFactory { get; set; }
+ private RealmAccess realm { get; set; }
[Cached]
private readonly DialogOverlay dialogOverlay;
@@ -87,10 +87,10 @@ namespace osu.Game.Tests.Visual.UserInterface
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
- 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(dependencies.Get(), () => beatmapManager, LocalStorage, ContextFactory, Scheduler));
- Dependencies.Cache(ContextFactory);
+ dependencies.Cache(rulesetStore = new RulesetStore(Realm));
+ dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default));
+ dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get(), () => beatmapManager, LocalStorage, Realm, Scheduler));
+ Dependencies.Cache(Realm);
var imported = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).GetResultSafely();
@@ -112,7 +112,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Ruleset = new OsuRuleset().RulesetInfo,
};
- importedScores.Add(scoreManager.Import(score).GetResultSafely().Value);
+ importedScores.Add(scoreManager.Import(score).Value);
}
});
@@ -122,11 +122,11 @@ namespace osu.Game.Tests.Visual.UserInterface
[SetUp]
public void Setup() => Schedule(() =>
{
- using (var realm = realmFactory.CreateContext())
+ realm.Run(r =>
{
// Due to soft deletions, we can re-use deleted scores between test runs
- scoreManager.Undelete(realm.All().Where(s => s.DeletePending).ToList());
- }
+ scoreManager.Undelete(r.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.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs
index fc5d3b652f..26fb03bed4 100644
--- a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs
+++ b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
[Test]
public void TestCustomDirectory()
{
- using (HeadlessGameHost host = new TestRunHeadlessGameHost(nameof(TestCustomDirectory))) // don't use clean run as we are writing a config file.
+ using (HeadlessGameHost host = new TestRunHeadlessGameHost(nameof(TestCustomDirectory), null)) // don't use clean run as we are writing a config file.
{
string osuDesktopStorage = Path.Combine(host.UserStoragePaths.First(), nameof(TestCustomDirectory));
const string custom_tournament = "custom";
@@ -68,7 +68,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
[Test]
public void TestMigration()
{
- using (HeadlessGameHost host = new TestRunHeadlessGameHost(nameof(TestMigration))) // don't use clean run as we are writing test files for migration.
+ using (HeadlessGameHost host = new TestRunHeadlessGameHost(nameof(TestMigration), null)) // don't use clean run as we are writing test files for migration.
{
string osuRoot = Path.Combine(host.UserStoragePaths.First(), nameof(TestMigration));
string configFile = Path.Combine(osuRoot, "tournament.ini");
diff --git a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs
index 03252e3be6..80cc9be5c1 100644
--- a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs
+++ b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs
@@ -19,7 +19,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
public void CheckIPCLocation()
{
// don't use clean run because files are being written before osu! launches.
- using (var host = new TestRunHeadlessGameHost(nameof(CheckIPCLocation)))
+ using (var host = new TestRunHeadlessGameHost(nameof(CheckIPCLocation), null))
{
string basePath = Path.Combine(host.UserStoragePaths.First(), nameof(CheckIPCLocation));
diff --git a/osu.Game.Tournament.Tests/TournamentTestRunner.cs b/osu.Game.Tournament.Tests/TournamentTestRunner.cs
index 1f63f7c545..229ab41a1e 100644
--- a/osu.Game.Tournament.Tests/TournamentTestRunner.cs
+++ b/osu.Game.Tournament.Tests/TournamentTestRunner.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Tournament.Tests
[STAThread]
public static int Main(string[] args)
{
- using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+ using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
{
host.Run(new TournamentTestBrowser());
return 0;
diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs
index fe22d1e76d..a5ead6c2f0 100644
--- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs
+++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs
@@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Components
if (manager == null)
{
- AddInternal(manager = new ChannelManager());
+ AddInternal(manager = new ChannelManager { HighPollRate = { Value = true } });
Channel.BindTo(manager.CurrentChannel);
}
diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs
index 96254295a6..4e1a34ddbf 100644
--- a/osu.Game/Beatmaps/BeatmapInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapInfo.cs
@@ -111,7 +111,7 @@ namespace osu.Game.Beatmaps
public int GridSize { get; set; }
- public double TimelineZoom { get; set; }
+ public double TimelineZoom { get; set; } = 1.0;
[Ignored]
public CountdownType Countdown { get; set; } = CountdownType.Normal;
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index ee649ad960..414b7cd12b 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -10,7 +10,6 @@ using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
-using osu.Framework.Extensions;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Framework.Testing;
@@ -41,11 +40,11 @@ namespace osu.Game.Beatmaps
private readonly WorkingBeatmapCache workingBeatmapCache;
private readonly BeatmapOnlineLookupQueue? onlineBeatmapLookupQueue;
- private readonly RealmContextFactory contextFactory;
+ private readonly RealmAccess realm;
- public BeatmapManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, IAPIProvider? api, AudioManager audioManager, IResourceStore gameResources, GameHost? host = null, WorkingBeatmap? defaultBeatmap = null, bool performOnlineLookups = false)
+ public BeatmapManager(Storage storage, RealmAccess realm, RulesetStore rulesets, IAPIProvider? api, AudioManager audioManager, IResourceStore gameResources, GameHost? host = null, WorkingBeatmap? defaultBeatmap = null, bool performOnlineLookups = false)
{
- this.contextFactory = contextFactory;
+ this.realm = realm;
if (performOnlineLookups)
{
@@ -55,11 +54,11 @@ namespace osu.Game.Beatmaps
onlineBeatmapLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
}
- var userResources = new RealmFileStore(contextFactory, storage).Store;
+ var userResources = new RealmFileStore(realm, storage).Store;
BeatmapTrackStore = audioManager.GetTrackStore(userResources);
- beatmapModelManager = CreateBeatmapModelManager(storage, contextFactory, rulesets, onlineBeatmapLookupQueue);
+ beatmapModelManager = CreateBeatmapModelManager(storage, realm, rulesets, onlineBeatmapLookupQueue);
workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host);
beatmapModelManager.WorkingBeatmapCache = workingBeatmapCache;
@@ -70,8 +69,8 @@ namespace osu.Game.Beatmaps
return new WorkingBeatmapCache(BeatmapTrackStore, audioManager, resources, storage, defaultBeatmap, host);
}
- protected virtual BeatmapModelManager CreateBeatmapModelManager(Storage storage, RealmContextFactory contextFactory, RulesetStore rulesets, BeatmapOnlineLookupQueue? onlineLookupQueue) =>
- new BeatmapModelManager(contextFactory, storage, onlineLookupQueue);
+ protected virtual BeatmapModelManager CreateBeatmapModelManager(Storage storage, RealmAccess realm, RulesetStore rulesets, BeatmapOnlineLookupQueue? onlineLookupQueue) =>
+ new BeatmapModelManager(realm, storage, onlineLookupQueue);
///
/// Create a new .
@@ -105,7 +104,7 @@ namespace osu.Game.Beatmaps
foreach (BeatmapInfo b in beatmapSet.Beatmaps)
b.BeatmapSet = beatmapSet;
- var imported = beatmapModelManager.Import(beatmapSet).GetResultSafely();
+ var imported = beatmapModelManager.Import(beatmapSet);
if (imported == null)
throw new InvalidOperationException("Failed to import new beatmap");
@@ -119,15 +118,17 @@ namespace osu.Game.Beatmaps
/// The beatmap difficulty to hide.
public void Hide(BeatmapInfo beatmapInfo)
{
- using (var realm = contextFactory.CreateContext())
- using (var transaction = realm.BeginWrite())
+ realm.Run(r =>
{
- if (!beatmapInfo.IsManaged)
- beatmapInfo = realm.Find(beatmapInfo.ID);
+ using (var transaction = r.BeginWrite())
+ {
+ if (!beatmapInfo.IsManaged)
+ beatmapInfo = r.Find(beatmapInfo.ID);
- beatmapInfo.Hidden = true;
- transaction.Commit();
- }
+ beatmapInfo.Hidden = true;
+ transaction.Commit();
+ }
+ });
}
///
@@ -136,27 +137,31 @@ namespace osu.Game.Beatmaps
/// The beatmap difficulty to restore.
public void Restore(BeatmapInfo beatmapInfo)
{
- using (var realm = contextFactory.CreateContext())
- using (var transaction = realm.BeginWrite())
+ realm.Run(r =>
{
- if (!beatmapInfo.IsManaged)
- beatmapInfo = realm.Find(beatmapInfo.ID);
+ using (var transaction = r.BeginWrite())
+ {
+ if (!beatmapInfo.IsManaged)
+ beatmapInfo = r.Find(beatmapInfo.ID);
- beatmapInfo.Hidden = false;
- transaction.Commit();
- }
+ beatmapInfo.Hidden = false;
+ transaction.Commit();
+ }
+ });
}
public void RestoreAll()
{
- using (var realm = contextFactory.CreateContext())
- using (var transaction = realm.BeginWrite())
+ realm.Run(r =>
{
- foreach (var beatmap in realm.All().Where(b => b.Hidden))
- beatmap.Hidden = false;
+ using (var transaction = r.BeginWrite())
+ {
+ foreach (var beatmap in r.All().Where(b => b.Hidden))
+ beatmap.Hidden = false;
- transaction.Commit();
- }
+ transaction.Commit();
+ }
+ });
}
///
@@ -165,8 +170,11 @@ namespace osu.Game.Beatmaps
/// A list of available .
public List GetAllUsableBeatmapSets()
{
- using (var context = contextFactory.CreateContext())
- return context.All().Where(b => !b.DeletePending).Detach();
+ return realm.Run(r =>
+ {
+ r.Refresh();
+ return r.All().Where(b => !b.DeletePending).Detach();
+ });
}
///
@@ -174,10 +182,9 @@ namespace osu.Game.Beatmaps
///
/// The query.
/// The first result for the provided query, or null if no results were found.
- public ILive? QueryBeatmapSet(Expression> query)
+ public Live? QueryBeatmapSet(Expression> query)
{
- using (var context = contextFactory.CreateContext())
- return context.All().FirstOrDefault(query)?.ToLive(contextFactory);
+ return realm.Run(r => r.All().FirstOrDefault(query)?.ToLive(realm));
}
#region Delegation to BeatmapModelManager (methods which previously existed locally).
@@ -232,21 +239,20 @@ namespace osu.Game.Beatmaps
public void Delete(Expression>? filter = null, bool silent = false)
{
- using (var context = contextFactory.CreateContext())
+ realm.Run(r =>
{
- var items = context.All().Where(s => !s.DeletePending && !s.Protected);
+ var items = r.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());
+ realm.Run(r => beatmapModelManager.Undelete(r.All().Where(s => s.DeletePending).ToList()));
}
public void Undelete(List items, bool silent = false)
@@ -273,22 +279,22 @@ namespace osu.Game.Beatmaps
return beatmapModelManager.Import(tasks);
}
- public Task>> Import(ProgressNotification notification, params ImportTask[] tasks)
+ public Task>> Import(ProgressNotification notification, params ImportTask[] tasks)
{
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 Live? Import(BeatmapSetInfo item, ArchiveReader? archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
{
return beatmapModelManager.Import(item, archive, lowPriority, cancellationToken);
}
@@ -305,19 +311,19 @@ namespace osu.Game.Beatmaps
// If we seem to be missing files, now is a good time to re-fetch.
if (importedBeatmap?.BeatmapSet?.Files.Count == 0)
{
- using (var realm = contextFactory.CreateContext())
+ realm.Run(r =>
{
- var refetch = realm.Find(importedBeatmap.ID)?.Detach();
+ var refetch = r.Find(importedBeatmap.ID)?.Detach();
if (refetch != null)
importedBeatmap = refetch;
- }
+ });
}
return workingBeatmapCache.GetWorkingBeatmap(importedBeatmap);
}
- public WorkingBeatmap GetWorkingBeatmap(ILive? importedBeatmap)
+ public WorkingBeatmap GetWorkingBeatmap(Live? importedBeatmap)
{
WorkingBeatmap working = workingBeatmapCache.GetWorkingBeatmap(null);
@@ -361,7 +367,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/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs
index 3822c6e121..e8104f2ecb 100644
--- a/osu.Game/Beatmaps/BeatmapModelManager.cs
+++ b/osu.Game/Beatmaps/BeatmapModelManager.cs
@@ -33,8 +33,8 @@ namespace osu.Game.Beatmaps
protected override string[] HashableFileTypes => new[] { ".osu" };
- public BeatmapModelManager(RealmContextFactory contextFactory, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null)
- : base(contextFactory, storage, onlineLookupQueue)
+ public BeatmapModelManager(RealmAccess realm, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null)
+ : base(realm, storage, onlineLookupQueue)
{
}
@@ -88,7 +88,7 @@ namespace osu.Game.Beatmaps
private static string getFilename(BeatmapInfo beatmapInfo)
{
var metadata = beatmapInfo.Metadata;
- return $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.DifficultyName}].osu".GetValidArchiveContentFilename();
+ return $"{metadata.Artist} - {metadata.Title} ({metadata.Author.Username}) [{beatmapInfo.DifficultyName}].osu".GetValidArchiveContentFilename();
}
///
@@ -98,17 +98,16 @@ namespace osu.Game.Beatmaps
/// The first result for the provided query, or null if no results were found.
public BeatmapInfo? QueryBeatmap(Expression> query)
{
- using (var context = ContextFactory.CreateContext())
- return context.All().FirstOrDefault(query)?.Detach();
+ return Realm.Run(realm => realm.All().FirstOrDefault(query)?.Detach());
}
public void Update(BeatmapSetInfo item)
{
- using (var realm = ContextFactory.CreateContext())
+ Realm.Write(realm =>
{
var existing = realm.Find(item.ID);
- realm.Write(r => item.CopyChangesToRealm(existing));
- }
+ item.CopyChangesToRealm(existing);
+ });
}
}
}
diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
index ec20328fab..922439fcb8 100644
--- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Beatmaps.ControlPoints
///
/// The time signature at this control point.
///
- public readonly Bindable TimeSignatureBindable = new Bindable(TimeSignatures.SimpleQuadruple) { Default = TimeSignatures.SimpleQuadruple };
+ public readonly Bindable TimeSignatureBindable = new Bindable(TimeSignature.SimpleQuadruple);
///
/// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing.
@@ -35,7 +35,7 @@ namespace osu.Game.Beatmaps.ControlPoints
///
/// The time signature at this control point.
///
- public TimeSignatures TimeSignature
+ public TimeSignature TimeSignature
{
get => TimeSignatureBindable.Value;
set => TimeSignatureBindable.Value = value;
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
index 893eb8ab78..8f3f05aa9f 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
@@ -340,9 +340,9 @@ namespace osu.Game.Beatmaps.Formats
double beatLength = Parsing.ParseDouble(split[1].Trim());
double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
- TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
+ TimeSignature timeSignature = TimeSignature.SimpleQuadruple;
if (split.Length >= 3)
- timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)Parsing.ParseInt(split[2]);
+ timeSignature = split[2][0] == '0' ? TimeSignature.SimpleQuadruple : new TimeSignature(Parsing.ParseInt(split[2]));
LegacySampleBank sampleSet = defaultSampleBank;
if (split.Length >= 4)
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
index ebdc882d2f..9d848fd8a4 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
@@ -227,7 +227,7 @@ namespace osu.Game.Beatmaps.Formats
if (effectPoint.OmitFirstBarLine)
effectFlags |= LegacyEffectFlags.OmitFirstBarLine;
- writer.Write(FormattableString.Invariant($"{(int)legacyControlPoints.TimingPointAt(time).TimeSignature},"));
+ writer.Write(FormattableString.Invariant($"{legacyControlPoints.TimingPointAt(time).TimeSignature.Numerator},"));
writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},"));
writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},"));
writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},"));
@@ -242,12 +242,7 @@ namespace osu.Game.Beatmaps.Formats
yield break;
foreach (var hitObject in hitObjects)
- {
yield return hitObject.DifficultyControlPoint;
-
- foreach (var nested in collectDifficultyControlPoints(hitObject.NestedHitObjects))
- yield return nested;
- }
}
void extractDifficultyControlPoints(IEnumerable hitObjects)
diff --git a/osu.Game/Beatmaps/Timing/TimeSignature.cs b/osu.Game/Beatmaps/Timing/TimeSignature.cs
new file mode 100644
index 0000000000..eebbcc34cd
--- /dev/null
+++ b/osu.Game/Beatmaps/Timing/TimeSignature.cs
@@ -0,0 +1,45 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+
+namespace osu.Game.Beatmaps.Timing
+{
+ ///
+ /// Stores the time signature of a track.
+ /// For now, the lower numeral can only be 4; support for other denominators can be considered at a later date.
+ ///
+ public class TimeSignature : IEquatable
+ {
+ ///
+ /// The numerator of a signature.
+ ///
+ public int Numerator { get; }
+
+ // TODO: support time signatures with a denominator other than 4
+ // this in particular requires a new beatmap format.
+
+ public TimeSignature(int numerator)
+ {
+ if (numerator < 1)
+ throw new ArgumentOutOfRangeException(nameof(numerator), numerator, "The numerator of a time signature must be positive.");
+
+ Numerator = numerator;
+ }
+
+ public static TimeSignature SimpleTriple { get; } = new TimeSignature(3);
+ public static TimeSignature SimpleQuadruple { get; } = new TimeSignature(4);
+
+ public override string ToString() => $"{Numerator}/4";
+
+ public bool Equals(TimeSignature other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+
+ return Numerator == other.Numerator;
+ }
+
+ public override int GetHashCode() => Numerator;
+ }
+}
diff --git a/osu.Game/Beatmaps/Timing/TimeSignatures.cs b/osu.Game/Beatmaps/Timing/TimeSignatures.cs
index 33e6342ae6..d783d3f9ec 100644
--- a/osu.Game/Beatmaps/Timing/TimeSignatures.cs
+++ b/osu.Game/Beatmaps/Timing/TimeSignatures.cs
@@ -1,11 +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 System;
using System.ComponentModel;
namespace osu.Game.Beatmaps.Timing
{
- public enum TimeSignatures
+ [Obsolete("Use osu.Game.Beatmaps.Timing.TimeSignature instead.")]
+ public enum TimeSignatures // can be removed 20220722
{
[Description("4/4")]
SimpleQuadruple = 4,
diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
index 6947752c47..d3f356bb24 100644
--- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
@@ -100,7 +100,7 @@ namespace osu.Game.Beatmaps
TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore;
ITrackStore IBeatmapResourceProvider.Tracks => trackStore;
AudioManager IStorageResourceProvider.AudioManager => audioManager;
- RealmContextFactory IStorageResourceProvider.RealmContextFactory => null;
+ RealmAccess IStorageResourceProvider.RealmAccess => null;
IResourceStore IStorageResourceProvider.Files => files;
IResourceStore IStorageResourceProvider.Resources => resources;
IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host?.CreateTextureLoaderStore(underlyingStore);
diff --git a/osu.Game/Configuration/SettingsStore.cs b/osu.Game/Configuration/SettingsStore.cs
index 2bba20fb09..e5d2d572c8 100644
--- a/osu.Game/Configuration/SettingsStore.cs
+++ b/osu.Game/Configuration/SettingsStore.cs
@@ -10,11 +10,11 @@ namespace osu.Game.Configuration
// this class mostly exists as a wrapper to avoid breaking the ruleset API (see usage in RulesetConfigManager).
// it may cease to exist going forward, depending on how the structure of the config data layer changes.
- public readonly RealmContextFactory Realm;
+ public readonly RealmAccess Realm;
- public SettingsStore(RealmContextFactory realmFactory)
+ public SettingsStore(RealmAccess realm)
{
- Realm = realmFactory;
+ Realm = realm;
}
}
}
diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs
index 635c4373cd..c84edbfb81 100644
--- a/osu.Game/Database/DatabaseContextFactory.cs
+++ b/osu.Game/Database/DatabaseContextFactory.cs
@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using Microsoft.EntityFrameworkCore.Storage;
-using osu.Framework.Development;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Statistics;
@@ -151,9 +150,6 @@ namespace osu.Game.Database
{
Logger.Log($"Creating full EF database backup at {backupFilename}", LoggingTarget.Database);
- if (DebugUtils.IsDebugBuild)
- Logger.Log("Your development database has been fully migrated to realm. If you switch back to a pre-realm branch and need your previous database, rename the backup file back to \"client.db\".\n\nNote that doing this can potentially leave your file store in a bad state.", level: LogLevel.Important);
-
using (var source = storage.GetStream(DATABASE_NAME))
using (var destination = storage.GetStream(backupFilename, FileAccess.Write, FileMode.CreateNew))
source.CopyTo(destination);
diff --git a/osu.Game/Database/EFToRealmMigrator.cs b/osu.Game/Database/EFToRealmMigrator.cs
index 727815cc4d..adf91e4a41 100644
--- a/osu.Game/Database/EFToRealmMigrator.cs
+++ b/osu.Game/Database/EFToRealmMigrator.cs
@@ -1,55 +1,140 @@
// 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.Linq;
+using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
+using osu.Framework.Allocation;
+using osu.Framework.Development;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
-using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Models;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Skinning;
+using osuTK;
using Realms;
#nullable enable
namespace osu.Game.Database
{
- internal class EFToRealmMigrator
+ internal class EFToRealmMigrator : CompositeDrawable
{
- private readonly DatabaseContextFactory efContextFactory;
- private readonly RealmContextFactory realmContextFactory;
- private readonly OsuConfigManager config;
- private readonly Storage storage;
+ public Task MigrationCompleted => migrationCompleted.Task;
- public EFToRealmMigrator(DatabaseContextFactory efContextFactory, RealmContextFactory realmContextFactory, OsuConfigManager config, Storage storage)
+ private readonly TaskCompletionSource migrationCompleted = new TaskCompletionSource();
+
+ [Resolved]
+ private DatabaseContextFactory efContextFactory { get; set; } = null!;
+
+ [Resolved]
+ private RealmAccess realm { get; set; } = null!;
+
+ [Resolved]
+ private OsuConfigManager config { get; set; } = null!;
+
+ private readonly OsuSpriteText currentOperationText;
+
+ public EFToRealmMigrator()
{
- this.efContextFactory = efContextFactory;
- this.realmContextFactory = realmContextFactory;
- this.config = config;
- this.storage = storage;
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChildren = new Drawable[]
+ {
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Spacing = new Vector2(10),
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Text = "Database migration in progress",
+ Font = OsuFont.Default.With(size: 40)
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Text = "This could take a few minutes depending on the speed of your disk(s).",
+ Font = OsuFont.Default.With(size: 30)
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Text = "Please keep the window open until this completes!",
+ Font = OsuFont.Default.With(size: 30)
+ },
+ new LoadingSpinner(true)
+ {
+ State = { Value = Visibility.Visible }
+ },
+ currentOperationText = new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Font = OsuFont.Default.With(size: 30)
+ },
+ }
+ },
+ };
}
- public void Run()
+ protected override void LoadComplete()
{
- createBackup();
+ base.LoadComplete();
- using (var ef = efContextFactory.Get())
+ Task.Factory.StartNew(() =>
{
- migrateSettings(ef);
- migrateSkins(ef);
- migrateBeatmaps(ef);
- migrateScores(ef);
- }
+ using (var ef = efContextFactory.Get())
+ {
+ realm.Write(r =>
+ {
+ // Before beginning, ensure realm is in an empty state.
+ // Migrations which are half-completed could lead to issues if the user tries a second time.
+ // Note that we only do this for beatmaps and scores since the other migrations are yonks old.
+ r.RemoveAll();
+ r.RemoveAll();
+ r.RemoveAll();
+ r.RemoveAll