diff --git a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs index 834930a05e..b5ab33b9fc 100644 --- a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs +++ b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs @@ -233,6 +233,48 @@ namespace osu.Game.Tests.NonVisual } } + [Test] + public void TestMigrationFailsOnExistingData() + { + string customPath = prepareCustomPath(); + string customPath2 = prepareCustomPath(); + + using (var host = new CustomTestHeadlessGameHost()) + { + try + { + var osu = LoadOsuIntoHost(host); + + var storage = osu.Dependencies.Get(); + var osuStorage = storage as OsuStorage; + + string originalDirectory = storage.GetFullPath("."); + + const string database_filename = "client.realm"; + + Assert.DoesNotThrow(() => osu.Migrate(customPath)); + Assert.That(File.Exists(Path.Combine(customPath, database_filename))); + + Directory.CreateDirectory(customPath2); + File.Copy(Path.Combine(customPath, database_filename), Path.Combine(customPath2, database_filename)); + + // Fails because file already exists. + Assert.Throws(() => osu.Migrate(customPath2)); + + osuStorage?.ChangeDataPath(customPath2); + + Assert.That(osuStorage?.CustomStoragePath, Is.EqualTo(customPath2)); + Assert.That(new StreamReader(Path.Combine(originalDirectory, "storage.ini")).ReadToEnd().Contains($"FullPath = {customPath2}")); + } + finally + { + host.Exit(); + cleanupPath(customPath); + cleanupPath(customPath2); + } + } + } + [Test] public void TestMigrationToNestedTargetFails() { diff --git a/osu.Game/IO/OsuStorage.cs b/osu.Game/IO/OsuStorage.cs index 6e7cb545e3..a3f7b4bfec 100644 --- a/osu.Game/IO/OsuStorage.cs +++ b/osu.Game/IO/OsuStorage.cs @@ -64,12 +64,22 @@ namespace osu.Game.IO /// public void ResetCustomStoragePath() { - storageConfig.SetValue(StorageConfig.FullPath, string.Empty); - storageConfig.Save(); + ChangeDataPath(string.Empty); ChangeTargetStorage(defaultStorage); } + /// + /// Updates the target data path without immediately switching. + /// This does NOT migrate any data. + /// The game should immediately be restarted after calling this. + /// + public void ChangeDataPath(string newPath) + { + storageConfig.SetValue(StorageConfig.FullPath, newPath); + storageConfig.Save(); + } + /// /// Attempts to change to the user's custom storage path. /// @@ -117,8 +127,7 @@ namespace osu.Game.IO { bool cleanupSucceeded = base.Migrate(newStorage); - storageConfig.SetValue(StorageConfig.FullPath, newStorage.GetFullPath(".")); - storageConfig.Save(); + ChangeDataPath(newStorage.GetFullPath(".")); return cleanupSucceeded; } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs index 1a60ab0638..047587e084 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs @@ -3,11 +3,14 @@ using System; using System.IO; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; +using osu.Game.IO; +using osu.Game.Overlays.Dialog; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -16,6 +19,12 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance [Resolved] private Storage storage { get; set; } + [Resolved] + private OsuGameBase game { get; set; } + + [Resolved(canBeNull: true)] + private DialogOverlay dialogOverlay { get; set; } + protected override DirectoryInfo InitialPath => new DirectoryInfo(storage.GetFullPath(string.Empty)).Parent; public override bool AllowExternalScreenChange => false; @@ -32,8 +41,29 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance try { - if (target.GetDirectories().Length > 0 || target.GetFiles().Length > 0) + var directoryInfos = target.GetDirectories(); + var fileInfos = target.GetFiles(); + + if (directoryInfos.Length > 0 || fileInfos.Length > 0) + { + // Quick test for whether there's already an osu! install at the target path. + if (fileInfos.Any(f => f.Name == @"client.realm")) + { + dialogOverlay.Push(new ConfirmDialog("The target directory already seems to have an osu! install. Use that data instead?", () => + { + dialogOverlay.Push(new ConfirmDialog("To complete this operation, osu! will close. Please open it again to use the new data location.", () => + { + (storage as OsuStorage)?.ChangeDataPath(target.FullName); + game.GracefullyExit(); + }, () => { })); + }, + () => { })); + + return; + } + target = target.CreateSubdirectory("osu-lazer"); + } } catch (Exception e) {