diff --git a/osu.Android.props b/osu.Android.props
index 1131203a95..563836d29b 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 a9e3575a49..7ec7d53a7e 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -90,7 +90,6 @@ namespace osu.Desktop
Logger.Log("Starting legacy IPC provider...");
legacyIpc = new LegacyTcpIpcProvider();
legacyIpc.Bind();
- legacyIpc.StartAsync();
}
catch (Exception ex)
{
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
index 91f5f93905..a30e09cd29 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
@@ -56,13 +56,13 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
[Test]
public void TestDefaultSkin()
{
- AddStep("set default skin", () => skins.CurrentSkinInfo.Value = DefaultSkin.CreateInfo().ToLive());
+ AddStep("set default skin", () => skins.CurrentSkinInfo.Value = DefaultSkin.CreateInfo().ToLiveUnmanaged());
}
[Test]
public void TestLegacySkin()
{
- AddStep("set legacy skin", () => skins.CurrentSkinInfo.Value = DefaultLegacySkin.CreateInfo().ToLive());
+ AddStep("set legacy skin", () => skins.CurrentSkinInfo.Value = DefaultLegacySkin.CreateInfo().ToLiveUnmanaged());
}
}
}
diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs
index 7314021a14..5c6b907e42 100644
--- a/osu.Game.Rulesets.Osu/OsuInputManager.cs
+++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs
@@ -3,8 +3,10 @@
using System.Collections.Generic;
using System.ComponentModel;
+using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
+using osu.Framework.Input.StateChanges.Events;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Osu
@@ -39,6 +41,19 @@ namespace osu.Game.Rulesets.Osu
return base.Handle(e);
}
+ protected override bool HandleMouseTouchStateChange(TouchStateChangeEvent e)
+ {
+ if (!AllowUserCursorMovement)
+ {
+ // Still allow for forwarding of the "touch" part, but replace the positional data with that of the mouse.
+ // Primarily relied upon by the "autopilot" osu! mod.
+ var touch = new Touch(e.Touch.Source, CurrentState.Mouse.Position);
+ e = new TouchStateChangeEvent(e.State, e.Input, touch, e.IsActive, null);
+ }
+
+ return base.HandleMouseTouchStateChange(e);
+ }
+
private class OsuKeyBindingContainer : RulesetKeyBindingContainer
{
public bool AllowUserPresses = true;
diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs
index 9b6769b788..06cb5a3607 100644
--- a/osu.Game.Tests/Database/RealmLiveTests.cs
+++ b/osu.Game.Tests/Database/RealmLiveTests.cs
@@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
+using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Models;
using Realms;
@@ -21,14 +22,41 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realmFactory, _) =>
{
- ILive beatmap = realmFactory.CreateContext().Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata()))).ToLive();
+ ILive beatmap = realmFactory.CreateContext().Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata()))).ToLive(realmFactory);
- ILive beatmap2 = realmFactory.CreateContext().All().First().ToLive();
+ ILive beatmap2 = realmFactory.CreateContext().All().First().ToLive(realmFactory);
Assert.AreEqual(beatmap, beatmap2);
});
}
+ [Test]
+ public void TestAccessAfterStorageMigrate()
+ {
+ RunTestWithRealm((realmFactory, storage) =>
+ {
+ var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
+
+ ILive liveBeatmap;
+
+ using (var context = realmFactory.CreateContext())
+ {
+ context.Write(r => r.Add(beatmap));
+
+ liveBeatmap = beatmap.ToLive(realmFactory);
+ }
+
+ using (var migratedStorage = new TemporaryNativeStorage("realm-test-migration-target"))
+ {
+ migratedStorage.DeleteDirectory(string.Empty);
+
+ storage.Migrate(migratedStorage);
+
+ Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden));
+ }
+ });
+ }
+
[Test]
public void TestAccessAfterAttach()
{
@@ -36,7 +64,7 @@ namespace osu.Game.Tests.Database
{
var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
- var liveBeatmap = beatmap.ToLive();
+ var liveBeatmap = beatmap.ToLive(realmFactory);
using (var context = realmFactory.CreateContext())
context.Write(r => r.Add(beatmap));
@@ -49,7 +77,7 @@ namespace osu.Game.Tests.Database
public void TestAccessNonManaged()
{
var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
- var liveBeatmap = beatmap.ToLive();
+ var liveBeatmap = beatmap.ToLiveUnmanaged();
Assert.IsFalse(beatmap.Hidden);
Assert.IsFalse(liveBeatmap.Value.Hidden);
@@ -74,7 +102,7 @@ namespace osu.Game.Tests.Database
{
var beatmap = threadContext.Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
- liveBeatmap = beatmap.ToLive();
+ liveBeatmap = beatmap.ToLive(realmFactory);
}
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
@@ -103,7 +131,7 @@ namespace osu.Game.Tests.Database
{
var beatmap = threadContext.Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
- liveBeatmap = beatmap.ToLive();
+ liveBeatmap = beatmap.ToLive(realmFactory);
}
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
@@ -123,7 +151,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealm((realmFactory, _) =>
{
var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
- var liveBeatmap = beatmap.ToLive();
+ var liveBeatmap = beatmap.ToLive(realmFactory);
Assert.DoesNotThrow(() =>
{
@@ -145,7 +173,7 @@ namespace osu.Game.Tests.Database
{
var beatmap = threadContext.Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
- liveBeatmap = beatmap.ToLive();
+ liveBeatmap = beatmap.ToLive(realmFactory);
}
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
@@ -183,7 +211,7 @@ namespace osu.Game.Tests.Database
{
var beatmap = threadContext.Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
- liveBeatmap = beatmap.ToLive();
+ liveBeatmap = beatmap.ToLive(realmFactory);
}
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
@@ -222,7 +250,7 @@ namespace osu.Game.Tests.Database
// not just a refresh from the resolved Live.
threadContext.Write(r => r.Add(new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), new RealmBeatmapMetadata())));
- liveBeatmap = beatmap.ToLive();
+ liveBeatmap = beatmap.ToLive(realmFactory);
}
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
diff --git a/osu.Game.Tests/Database/RealmTest.cs b/osu.Game.Tests/Database/RealmTest.cs
index 04c9f2577a..6904464485 100644
--- a/osu.Game.Tests/Database/RealmTest.cs
+++ b/osu.Game.Tests/Database/RealmTest.cs
@@ -10,6 +10,7 @@ using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Database;
+using osu.Game.IO;
using osu.Game.Models;
#nullable enable
@@ -27,15 +28,16 @@ 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(caller))
{
host.Run(new RealmTestGame(() =>
{
- var testStorage = storage.GetStorageForDirectory(caller);
+ // ReSharper disable once AccessToDisposedClosure
+ var testStorage = new OsuStorage(host, storage.GetStorageForDirectory(caller));
- using (var realmFactory = new RealmContextFactory(testStorage, caller))
+ using (var realmFactory = new RealmContextFactory(testStorage, "client"))
{
Logger.Log($"Running test using realm file {testStorage.GetFullPath(realmFactory.Filename)}");
testAction(realmFactory, testStorage);
@@ -58,7 +60,7 @@ namespace osu.Game.Tests.Database
{
var testStorage = storage.GetStorageForDirectory(caller);
- using (var realmFactory = new RealmContextFactory(testStorage, caller))
+ using (var realmFactory = new RealmContextFactory(testStorage, "client"))
{
Logger.Log($"Running test using realm file {testStorage.GetFullPath(realmFactory.Filename)}");
await testAction(realmFactory, testStorage);
diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
index 88f35976ad..3aab28886e 100644
--- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
@@ -15,6 +15,7 @@ using osu.Framework.IO.Stores;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Audio;
+using osu.Game.Database;
using osu.Game.IO;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
@@ -220,6 +221,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 IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null;
#endregion
diff --git a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs
index 1d3dd35e1d..3211405670 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs
@@ -235,7 +235,7 @@ namespace osu.Game.Tests.Visual.Background
private void setCustomSkin()
{
// feign a skin switch. this doesn't do anything except force CurrentSkin to become a LegacySkin.
- AddStep("set custom skin", () => skins.CurrentSkinInfo.Value = new SkinInfo().ToLive());
+ AddStep("set custom skin", () => skins.CurrentSkinInfo.Value = new SkinInfo().ToLiveUnmanaged());
}
private void setDefaultSkin() => AddStep("set default skin", () => skins.CurrentSkinInfo.SetDefault());
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs
index cccc962a3f..c5f56cae9e 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs
@@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
AddStep("setup skins", () =>
{
- skinManager.CurrentSkinInfo.Value = gameCurrentSkin.ToLive();
+ skinManager.CurrentSkinInfo.Value = gameCurrentSkin.ToLiveUnmanaged();
currentBeatmapSkin = getBeatmapSkin();
});
});
diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
index 559685d3c4..449406eadf 100644
--- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
@@ -15,6 +15,7 @@ using osu.Framework.Platform;
using osu.Framework.Statistics;
using osu.Framework.Testing;
using osu.Game.Beatmaps.Formats;
+using osu.Game.Database;
using osu.Game.IO;
using osu.Game.Skinning;
using osu.Game.Storyboards;
@@ -108,6 +109,7 @@ namespace osu.Game.Beatmaps
TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore;
ITrackStore IBeatmapResourceProvider.Tracks => trackStore;
AudioManager IStorageResourceProvider.AudioManager => audioManager;
+ RealmContextFactory IStorageResourceProvider.RealmContextFactory => null;
IResourceStore IStorageResourceProvider.Files => files;
IResourceStore IStorageResourceProvider.Resources => resources;
IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host?.CreateTextureLoaderStore(underlyingStore);
diff --git a/osu.Game/Database/RealmLive.cs b/osu.Game/Database/RealmLive.cs
index c376d5d503..90b8814c24 100644
--- a/osu.Game/Database/RealmLive.cs
+++ b/osu.Game/Database/RealmLive.cs
@@ -24,13 +24,17 @@ namespace osu.Game.Database
///
private readonly T data;
+ private readonly RealmContextFactory realmFactory;
+
///
/// Construct a new instance of live realm data.
///
/// The realm data.
- public RealmLive(T data)
+ /// The realm factory the data was sourced from. May be null for an unmanaged object.
+ public RealmLive(T data, RealmContextFactory realmFactory)
{
this.data = data;
+ this.realmFactory = realmFactory;
ID = data.ID;
}
@@ -47,7 +51,7 @@ namespace osu.Game.Database
return;
}
- using (var realm = Realm.GetInstance(data.Realm.Config))
+ using (var realm = realmFactory.CreateContext())
perform(realm.Find(ID));
}
@@ -58,12 +62,12 @@ namespace osu.Game.Database
public TReturn PerformRead(Func perform)
{
if (typeof(RealmObjectBase).IsAssignableFrom(typeof(TReturn)))
- throw new InvalidOperationException($"Realm live objects should not exit the scope of {nameof(PerformRead)}.");
+ throw new InvalidOperationException(@$"Realm live objects should not exit the scope of {nameof(PerformRead)}.");
if (!IsManaged)
return perform(data);
- using (var realm = Realm.GetInstance(data.Realm.Config))
+ using (var realm = realmFactory.CreateContext())
return perform(realm.Find(ID));
}
@@ -74,7 +78,7 @@ namespace osu.Game.Database
public void PerformWrite(Action perform)
{
if (!IsManaged)
- throw new InvalidOperationException("Can't perform writes on a non-managed underlying value");
+ throw new InvalidOperationException(@"Can't perform writes on a non-managed underlying value");
PerformRead(t =>
{
@@ -94,11 +98,7 @@ namespace osu.Game.Database
if (!ThreadSafety.IsUpdateThread)
throw new InvalidOperationException($"Can't use {nameof(Value)} on managed objects from non-update threads");
- // When using Value, we rely on garbage collection for the realm instance used to retrieve the instance.
- // As we are sure that this is on the update thread, there should always be an open and constantly refreshing realm instance to ensure file size growth is a non-issue.
- var realm = Realm.GetInstance(data.Realm.Config);
-
- return realm.Find(ID);
+ return realmFactory.Context.Find(ID);
}
}
diff --git a/osu.Game/Database/RealmLiveUnmanaged.cs b/osu.Game/Database/RealmLiveUnmanaged.cs
new file mode 100644
index 0000000000..5a69898206
--- /dev/null
+++ b/osu.Game/Database/RealmLiveUnmanaged.cs
@@ -0,0 +1,44 @@
+// 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 Realms;
+
+#nullable enable
+
+namespace osu.Game.Database
+{
+ ///
+ /// Provides a method of working with unmanaged realm objects.
+ /// Usually used for testing purposes where the instance is never required to be managed.
+ ///
+ /// The underlying object type.
+ public class RealmLiveUnmanaged : ILive where T : RealmObjectBase, IHasGuidPrimaryKey
+ {
+ ///
+ /// Construct a new instance of live realm data.
+ ///
+ /// The realm data.
+ public RealmLiveUnmanaged(T data)
+ {
+ Value = data;
+ }
+
+ public bool Equals(ILive? other) => ID == other?.ID;
+
+ public Guid ID => Value.ID;
+
+ public void PerformRead(Action perform) => perform(Value);
+
+ public TReturn PerformRead(Func perform) => perform(Value);
+
+ public void PerformWrite(Action perform) => throw new InvalidOperationException(@"Can't perform writes on a non-managed underlying value");
+
+ public bool IsManaged => false;
+
+ ///
+ /// The original live data used to create this instance.
+ ///
+ public T Value { get; }
+ }
+}
diff --git a/osu.Game/Database/RealmObjectExtensions.cs b/osu.Game/Database/RealmObjectExtensions.cs
index b38e21453c..e5177823ba 100644
--- a/osu.Game/Database/RealmObjectExtensions.cs
+++ b/osu.Game/Database/RealmObjectExtensions.cs
@@ -53,16 +53,28 @@ namespace osu.Game.Database
return mapper.Map(item);
}
- public static List> ToLive(this IEnumerable realmList)
+ public static List> ToLiveUnmanaged(this IEnumerable realmList)
where T : RealmObject, IHasGuidPrimaryKey
{
- return realmList.Select(l => new RealmLive(l)).Cast>().ToList();
+ return realmList.Select(l => new RealmLiveUnmanaged(l)).Cast>().ToList();
}
- public static ILive ToLive(this T realmObject)
+ public static ILive ToLiveUnmanaged(this T realmObject)
where T : RealmObject, IHasGuidPrimaryKey
{
- return new RealmLive(realmObject);
+ return new RealmLiveUnmanaged(realmObject);
+ }
+
+ public static List> ToLive(this IEnumerable realmList, RealmContextFactory realmContextFactory)
+ where T : RealmObject, IHasGuidPrimaryKey
+ {
+ return realmList.Select(l => new RealmLive(l, realmContextFactory)).Cast>().ToList();
+ }
+
+ public static ILive ToLive(this T realmObject, RealmContextFactory realmContextFactory)
+ where T : RealmObject, IHasGuidPrimaryKey
+ {
+ return new RealmLive(realmObject, realmContextFactory);
}
///
diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs
index 3fa90e2330..8e272f637f 100644
--- a/osu.Game/Graphics/Cursor/MenuCursor.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -72,18 +72,21 @@ namespace osu.Game.Graphics.Cursor
protected override bool OnMouseDown(MouseDownEvent e)
{
- // only trigger animation for main mouse buttons
- activeCursor.Scale = new Vector2(1);
- activeCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
-
- activeCursor.AdditiveLayer.Alpha = 0;
- activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
-
- if (cursorRotate.Value && dragRotationState != DragRotationState.Rotating)
+ if (State.Value == Visibility.Visible)
{
- // if cursor is already rotating don't reset its rotate origin
- dragRotationState = DragRotationState.DragStarted;
- positionMouseDown = e.MousePosition;
+ // only trigger animation for main mouse buttons
+ activeCursor.Scale = new Vector2(1);
+ activeCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
+
+ activeCursor.AdditiveLayer.Alpha = 0;
+ activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
+
+ if (cursorRotate.Value && dragRotationState != DragRotationState.Rotating)
+ {
+ // if cursor is already rotating don't reset its rotate origin
+ dragRotationState = DragRotationState.DragStarted;
+ positionMouseDown = e.MousePosition;
+ }
}
return base.OnMouseDown(e);
diff --git a/osu.Game/Graphics/DateTooltip.cs b/osu.Game/Graphics/DateTooltip.cs
index 3094f9cc2b..d5768b259a 100644
--- a/osu.Game/Graphics/DateTooltip.cs
+++ b/osu.Game/Graphics/DateTooltip.cs
@@ -65,8 +65,10 @@ namespace osu.Game.Graphics
public void SetContent(DateTimeOffset date)
{
- dateText.Text = $"{date:d MMMM yyyy} ";
- timeText.Text = $"{date:HH:mm:ss \"UTC\"z}";
+ DateTimeOffset localDate = date.ToLocalTime();
+
+ dateText.Text = $"{localDate:d MMMM yyyy} ";
+ timeText.Text = $"{localDate:HH:mm:ss \"UTC\"z}";
}
public void Move(Vector2 pos) => Position = pos;
diff --git a/osu.Game/IO/IStorageResourceProvider.cs b/osu.Game/IO/IStorageResourceProvider.cs
index e4c97e18fa..950b5aae09 100644
--- a/osu.Game/IO/IStorageResourceProvider.cs
+++ b/osu.Game/IO/IStorageResourceProvider.cs
@@ -4,6 +4,7 @@
using osu.Framework.Audio;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
+using osu.Game.Database;
namespace osu.Game.IO
{
@@ -24,6 +25,11 @@ namespace osu.Game.IO
///
IResourceStore Resources { get; }
+ ///
+ /// Access realm.
+ ///
+ RealmContextFactory RealmContextFactory { get; }
+
///
/// Create a texture loader store based on an underlying data store.
///
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index a35191613c..a4471b56b9 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -255,10 +255,10 @@ namespace osu.Game
if (skinInfo == null)
{
if (guid == SkinInfo.CLASSIC_SKIN)
- skinInfo = DefaultLegacySkin.CreateInfo().ToLive();
+ skinInfo = DefaultLegacySkin.CreateInfo().ToLiveUnmanaged();
}
- SkinManager.CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.CreateInfo().ToLive();
+ SkinManager.CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.CreateInfo().ToLiveUnmanaged();
};
configSkin.TriggerChange();
@@ -1149,16 +1149,11 @@ namespace osu.Game
}
}
- private void screenPushed(IScreen lastScreen, IScreen newScreen)
- {
- ScreenChanged(lastScreen, newScreen);
- Logger.Log($"Screen changed → {newScreen}");
- }
+ private void screenPushed(IScreen lastScreen, IScreen newScreen) => ScreenChanged(lastScreen, newScreen);
private void screenExited(IScreen lastScreen, IScreen newScreen)
{
ScreenChanged(lastScreen, newScreen);
- Logger.Log($"Screen changed ← {newScreen}");
if (newScreen == null)
Exit();
diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
index b1582d7bee..0fa6d78d4b 100644
--- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
@@ -32,14 +32,14 @@ namespace osu.Game.Overlays.Settings.Sections
Icon = FontAwesome.Solid.PaintBrush
};
- private readonly Bindable> dropdownBindable = new Bindable> { Default = DefaultSkin.CreateInfo().ToLive() };
+ private readonly Bindable> dropdownBindable = new Bindable> { Default = DefaultSkin.CreateInfo().ToLiveUnmanaged() };
private readonly Bindable configBindable = new Bindable();
private static readonly ILive random_skin_info = new SkinInfo
{
ID = SkinInfo.RANDOM_SKIN,
Name = "",
- }.ToLive();
+ }.ToLiveUnmanaged();
private List> skinItems;
@@ -133,7 +133,7 @@ namespace osu.Game.Overlays.Settings.Sections
{
int protectedCount = realmSkins.Count(s => s.Protected);
- skinItems = realmSkins.ToLive();
+ skinItems = realmSkins.ToLive(realmFactory);
skinItems.Insert(protectedCount, random_skin_info);
diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs
index 54fc2340f1..d606d94b97 100644
--- a/osu.Game/Skinning/Skin.cs
+++ b/osu.Game/Skinning/Skin.cs
@@ -43,7 +43,11 @@ namespace osu.Game.Skinning
protected Skin(SkinInfo skin, IStorageResourceProvider resources, [CanBeNull] Stream configurationStream = null)
{
- SkinInfo = skin.ToLive();
+ SkinInfo = resources?.RealmContextFactory != null
+ ? skin.ToLive(resources.RealmContextFactory)
+ // This path should only be used in some tests.
+ : skin.ToLiveUnmanaged();
+
this.resources = resources;
configurationStream ??= getConfigurationStream();
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index 5134632fb1..bb2f0a37b4 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -47,9 +47,9 @@ namespace osu.Game.Skinning
public readonly Bindable CurrentSkin = new Bindable();
- public readonly Bindable> CurrentSkinInfo = new Bindable>(Skinning.DefaultSkin.CreateInfo().ToLive())
+ public readonly Bindable> CurrentSkinInfo = new Bindable>(Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged())
{
- Default = Skinning.DefaultSkin.CreateInfo().ToLive()
+ Default = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged()
};
private readonly SkinModelManager skinModelManager;
@@ -119,13 +119,13 @@ namespace osu.Game.Skinning
if (randomChoices.Length == 0)
{
- CurrentSkinInfo.Value = Skinning.DefaultSkin.CreateInfo().ToLive();
+ CurrentSkinInfo.Value = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged();
return;
}
var chosen = randomChoices.ElementAt(RNG.Next(0, randomChoices.Length));
- CurrentSkinInfo.Value = chosen.ToLive();
+ CurrentSkinInfo.Value = chosen.ToLive(contextFactory);
}
}
@@ -182,7 +182,7 @@ namespace osu.Game.Skinning
public ILive Query(Expression> query)
{
using (var context = contextFactory.CreateContext())
- return context.All().FirstOrDefault(query)?.ToLive();
+ return context.All().FirstOrDefault(query)?.ToLive(contextFactory);
}
public event Action SourceChanged;
@@ -237,6 +237,7 @@ namespace osu.Game.Skinning
AudioManager IStorageResourceProvider.AudioManager => audio;
IResourceStore IStorageResourceProvider.Resources => resources;
IResourceStore IStorageResourceProvider.Files => userFiles;
+ RealmContextFactory IStorageResourceProvider.RealmContextFactory => contextFactory;
IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore);
#endregion
@@ -302,7 +303,7 @@ namespace osu.Game.Skinning
Guid currentUserSkin = CurrentSkinInfo.Value.ID;
if (items.Any(s => s.ID == currentUserSkin))
- scheduler.Add(() => CurrentSkinInfo.Value = Skinning.DefaultSkin.CreateInfo().ToLive());
+ scheduler.Add(() => CurrentSkinInfo.Value = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged());
skinModelManager.Delete(items.ToList(), silent);
}
diff --git a/osu.Game/Stores/RealmArchiveModelImporter.cs b/osu.Game/Stores/RealmArchiveModelImporter.cs
index 1681dad750..4aca079e2e 100644
--- a/osu.Game/Stores/RealmArchiveModelImporter.cs
+++ b/osu.Game/Stores/RealmArchiveModelImporter.cs
@@ -352,7 +352,7 @@ namespace osu.Game.Stores
transaction.Commit();
}
- return existing.ToLive();
+ return existing.ToLive(ContextFactory);
}
LogForModel(item, @"Found existing (optimised) but failed pre-check.");
@@ -387,7 +387,7 @@ namespace osu.Game.Stores
existing.DeletePending = false;
transaction.Commit();
- return existing.ToLive();
+ return existing.ToLive(ContextFactory);
}
LogForModel(item, @"Found existing but failed re-use check.");
@@ -416,7 +416,7 @@ namespace osu.Game.Stores
throw;
}
- return item.ToLive();
+ return item.ToLive(ContextFactory);
}
}
diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs
index 31a2071249..f919edecf7 100644
--- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs
+++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs
@@ -14,6 +14,7 @@ using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
+using osu.Game.Database;
using osu.Game.IO;
using osu.Game.Models;
using osu.Game.Rulesets;
@@ -118,6 +119,7 @@ namespace osu.Game.Tests.Beatmaps
public IResourceStore Files => userSkinResourceStore;
public new IResourceStore Resources => base.Resources;
public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null;
+ RealmContextFactory IStorageResourceProvider.RealmContextFactory => null;
#endregion
diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs
index cdd3e47930..22aac79056 100644
--- a/osu.Game/Tests/Visual/SkinnableTestScene.cs
+++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs
@@ -15,6 +15,7 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
+using osu.Game.Database;
using osu.Game.Graphics.Sprites;
using osu.Game.IO;
using osu.Game.Rulesets;
@@ -158,6 +159,7 @@ namespace osu.Game.Tests.Visual
public IResourceStore Files => null;
public new IResourceStore Resources => base.Resources;
public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore);
+ RealmContextFactory IStorageResourceProvider.RealmContextFactory => null;
#endregion
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index feae990df7..0e8486cabc 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -36,7 +36,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 27ac1bf647..42d8962c14 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -60,7 +60,7 @@
-
+
@@ -83,7 +83,7 @@
-
+