From 9a5790cd31dbd9a60932fb16790fea3390db7ca8 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 24 Jan 2021 19:18:16 +0100 Subject: [PATCH 01/13] Implement StableStorage class. --- osu.Desktop/OsuGameDesktop.cs | 3 +- osu.Game/IO/StableStorage.cs | 64 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 osu.Game/IO/StableStorage.cs diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index d1515acafa..0dc659b120 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -18,6 +18,7 @@ using osu.Framework.Screens; using osu.Game.Screens.Menu; using osu.Game.Updater; using osu.Desktop.Windows; +using osu.Game.IO; namespace osu.Desktop { @@ -40,7 +41,7 @@ namespace osu.Desktop { string stablePath = getStableInstallPath(); if (!string.IsNullOrEmpty(stablePath)) - return new DesktopStorage(stablePath, desktopHost); + return new StableStorage(stablePath, desktopHost); } } catch (Exception) diff --git a/osu.Game/IO/StableStorage.cs b/osu.Game/IO/StableStorage.cs new file mode 100644 index 0000000000..a8665b5267 --- /dev/null +++ b/osu.Game/IO/StableStorage.cs @@ -0,0 +1,64 @@ +// 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 osu.Framework.Platform; + +namespace osu.Game.IO +{ + /// + /// A storage pointing to an osu-stable installation. + /// Provides methods for handling installations with a custom Song folder location. + /// + public class StableStorage : DesktopStorage + { + private const string stable_songs_path = "Songs"; + + private readonly DesktopGameHost host; + private string songs_path; + + public StableStorage(string path, DesktopGameHost host) + : base(path, host) + { + this.host = host; + songs_path = locateSongsDirectory(); + } + + /// + /// Returns a pointing to the osu-stable Songs directory. + /// + public Storage GetSongStorage() + { + if (songs_path.Equals(stable_songs_path, StringComparison.OrdinalIgnoreCase)) + return GetStorageForDirectory(stable_songs_path); + else + return new DesktopStorage(songs_path, host); + } + + private string locateSongsDirectory() + { + var configFile = GetStream(GetFiles(".", "osu!.*.cfg").First()); + var textReader = new StreamReader(configFile); + + var songs_directory_path = stable_songs_path; + + while (!textReader.EndOfStream) + { + var line = textReader.ReadLine(); + + if (line?.StartsWith("BeatmapDirectory", StringComparison.OrdinalIgnoreCase) == true) + { + var directory = line.Split('=')[1].TrimStart(); + if (Path.IsPathFullyQualified(directory) && !directory.Equals(stable_songs_path, StringComparison.OrdinalIgnoreCase)) + songs_directory_path = directory; + + break; + } + } + + return songs_directory_path; + } + } +} From d71ac834280c0873422a974dbc78bf73baa5ce71 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 24 Jan 2021 19:46:10 +0100 Subject: [PATCH 02/13] Use StableStorage in ArchiveModelManager. --- osu.Desktop/OsuGameDesktop.cs | 2 +- osu.Game/Database/ArchiveModelManager.cs | 4 ++-- osu.Game/OsuGame.cs | 3 ++- osu.Game/Scoring/ScoreManager.cs | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 0dc659b120..5909b82c8f 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -33,7 +33,7 @@ namespace osu.Desktop noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false; } - public override Storage GetStorageForStableInstall() + public override StableStorage GetStorageForStableInstall() { try { diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 9f69ad035f..7d22c51d0f 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -625,7 +625,7 @@ namespace osu.Game.Database /// /// Set a storage with access to an osu-stable install for import purposes. /// - public Func GetStableStorage { private get; set; } + public Func GetStableStorage { private get; set; } /// /// Denotes whether an osu-stable installation is present to perform automated imports from. @@ -640,7 +640,7 @@ namespace osu.Game.Database /// /// Select paths to import from stable. Default implementation iterates all directories in . /// - protected virtual IEnumerable GetStableImportPaths(Storage stableStoage) => stableStoage.GetDirectories(ImportFromStablePath); + protected virtual IEnumerable GetStableImportPaths(StableStorage stableStoage) => stableStoage.GetDirectories(ImportFromStablePath); /// /// Whether this specified path should be removed after successful import. diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 5acd6bc73d..399bdda491 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -52,6 +52,7 @@ using osu.Game.Updater; using osu.Game.Utils; using LogLevel = osu.Framework.Logging.LogLevel; using osu.Game.Database; +using osu.Game.IO; namespace osu.Game { @@ -88,7 +89,7 @@ namespace osu.Game protected SentryLogger SentryLogger; - public virtual Storage GetStorageForStableInstall() => null; + public virtual StableStorage GetStorageForStableInstall() => null; public float ToolbarOffset => (Toolbar?.Position.Y ?? 0) + (Toolbar?.DrawHeight ?? 0); diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index cf1d123c06..11f31f7d59 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -16,6 +16,7 @@ using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; +using osu.Game.IO; using osu.Game.IO.Archives; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -71,7 +72,7 @@ namespace osu.Game.Scoring } } - protected override IEnumerable GetStableImportPaths(Storage stableStorage) + protected override IEnumerable GetStableImportPaths(StableStorage stableStorage) => stableStorage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false)); public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store); From f0fdad2f838ec4ab18a82841f4483cba66f715f0 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 24 Jan 2021 22:04:46 +0100 Subject: [PATCH 03/13] Construct a DesktopStorage pointing to the absolute path of the song directory. --- osu.Game/IO/StableStorage.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game/IO/StableStorage.cs b/osu.Game/IO/StableStorage.cs index a8665b5267..c7ca37a163 100644 --- a/osu.Game/IO/StableStorage.cs +++ b/osu.Game/IO/StableStorage.cs @@ -29,20 +29,14 @@ namespace osu.Game.IO /// /// Returns a pointing to the osu-stable Songs directory. /// - public Storage GetSongStorage() - { - if (songs_path.Equals(stable_songs_path, StringComparison.OrdinalIgnoreCase)) - return GetStorageForDirectory(stable_songs_path); - else - return new DesktopStorage(songs_path, host); - } + public Storage GetSongStorage() => new DesktopStorage(songs_path, host); private string locateSongsDirectory() { var configFile = GetStream(GetFiles(".", "osu!.*.cfg").First()); var textReader = new StreamReader(configFile); - var songs_directory_path = stable_songs_path; + var songs_directory_path = Path.Combine(BasePath, stable_songs_path); while (!textReader.EndOfStream) { @@ -51,7 +45,7 @@ namespace osu.Game.IO if (line?.StartsWith("BeatmapDirectory", StringComparison.OrdinalIgnoreCase) == true) { var directory = line.Split('=')[1].TrimStart(); - if (Path.IsPathFullyQualified(directory) && !directory.Equals(stable_songs_path, StringComparison.OrdinalIgnoreCase)) + if (Path.IsPathFullyQualified(directory)) songs_directory_path = directory; break; From 51d4da565c87192549f62fa94cf624818809a3d8 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 24 Jan 2021 22:25:49 +0100 Subject: [PATCH 04/13] Fix ArchiveModelManagers lookup paths. --- osu.Game/Beatmaps/BeatmapManager.cs | 8 +++++++- osu.Game/Database/ArchiveModelManager.cs | 12 +++++++++--- osu.Game/Scoring/ScoreManager.cs | 3 ++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 42418e532b..a455f676b3 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -64,7 +64,13 @@ namespace osu.Game.Beatmaps protected override string[] HashableFileTypes => new[] { ".osu" }; - protected override string ImportFromStablePath => "Songs"; + protected override bool CheckStableDirectoryExists(StableStorage stableStorage) => stableStorage.GetSongStorage().ExistsDirectory("."); + + protected override IEnumerable GetStableImportPaths(StableStorage stableStoage) + { + var songStorage = stableStoage.GetSongStorage(); + return songStorage.GetDirectories(".").Select(path => songStorage.GetFullPath(path)); + } private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 7d22c51d0f..516f70c700 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -637,10 +637,16 @@ namespace osu.Game.Database /// protected virtual string ImportFromStablePath => null; + /// + /// Checks for the existence of an osu-stable directory. + /// + protected virtual bool CheckStableDirectoryExists(StableStorage stableStorage) => stableStorage.ExistsDirectory(ImportFromStablePath); + /// /// Select paths to import from stable. Default implementation iterates all directories in . /// - protected virtual IEnumerable GetStableImportPaths(StableStorage stableStoage) => stableStoage.GetDirectories(ImportFromStablePath); + protected virtual IEnumerable GetStableImportPaths(StableStorage stableStoage) => stableStoage.GetDirectories(ImportFromStablePath) + .Select(path => stableStoage.GetFullPath(path)); /// /// Whether this specified path should be removed after successful import. @@ -662,14 +668,14 @@ namespace osu.Game.Database return Task.CompletedTask; } - if (!stable.ExistsDirectory(ImportFromStablePath)) + if (!CheckStableDirectoryExists(stable)) { // This handles situations like when the user does not have a Skins folder Logger.Log($"No {ImportFromStablePath} folder available in osu!stable installation", LoggingTarget.Information, LogLevel.Error); return Task.CompletedTask; } - return Task.Run(async () => await Import(GetStableImportPaths(GetStableStorage()).Select(f => stable.GetFullPath(f)).ToArray())); + return Task.Run(async () => await Import(GetStableImportPaths(stable).ToArray())); } #endregion diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 11f31f7d59..6aa0a30a75 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -73,7 +73,8 @@ namespace osu.Game.Scoring } protected override IEnumerable GetStableImportPaths(StableStorage stableStorage) - => stableStorage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false)); + => stableStorage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false)) + .Select(path => stableStorage.GetFullPath(path)); public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store); From a4a7f0c5787a1fd0a5470a8af72c1ac5211e7d1b Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 25 Jan 2021 19:05:16 +0100 Subject: [PATCH 05/13] Address CI inspections. --- osu.Game/IO/StableStorage.cs | 12 ++++++------ osu.Game/OsuGame.cs | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/osu.Game/IO/StableStorage.cs b/osu.Game/IO/StableStorage.cs index c7ca37a163..85af92621b 100644 --- a/osu.Game/IO/StableStorage.cs +++ b/osu.Game/IO/StableStorage.cs @@ -17,26 +17,26 @@ namespace osu.Game.IO private const string stable_songs_path = "Songs"; private readonly DesktopGameHost host; - private string songs_path; + private readonly string songsPath; public StableStorage(string path, DesktopGameHost host) : base(path, host) { this.host = host; - songs_path = locateSongsDirectory(); + songsPath = locateSongsDirectory(); } /// /// Returns a pointing to the osu-stable Songs directory. /// - public Storage GetSongStorage() => new DesktopStorage(songs_path, host); + public Storage GetSongStorage() => new DesktopStorage(songsPath, host); private string locateSongsDirectory() { var configFile = GetStream(GetFiles(".", "osu!.*.cfg").First()); var textReader = new StreamReader(configFile); - var songs_directory_path = Path.Combine(BasePath, stable_songs_path); + var songsDirectoryPath = Path.Combine(BasePath, stable_songs_path); while (!textReader.EndOfStream) { @@ -46,13 +46,13 @@ namespace osu.Game.IO { var directory = line.Split('=')[1].TrimStart(); if (Path.IsPathFullyQualified(directory)) - songs_directory_path = directory; + songsDirectoryPath = directory; break; } } - return songs_directory_path; + return songsDirectoryPath; } } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 399bdda491..78c4d4ccad 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -28,7 +28,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Collections; From 9f9206726a0cd9cbae347ed26264434f37a86738 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Tue, 26 Jan 2021 18:11:54 +0100 Subject: [PATCH 06/13] Fix typos. --- osu.Game/Beatmaps/BeatmapManager.cs | 4 ++-- osu.Game/Database/ArchiveModelManager.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index a455f676b3..43b2486ac5 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -66,9 +66,9 @@ namespace osu.Game.Beatmaps protected override bool CheckStableDirectoryExists(StableStorage stableStorage) => stableStorage.GetSongStorage().ExistsDirectory("."); - protected override IEnumerable GetStableImportPaths(StableStorage stableStoage) + protected override IEnumerable GetStableImportPaths(StableStorage stableStorage) { - var songStorage = stableStoage.GetSongStorage(); + var songStorage = stableStorage.GetSongStorage(); return songStorage.GetDirectories(".").Select(path => songStorage.GetFullPath(path)); } diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 516f70c700..99301b6c68 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -645,8 +645,8 @@ namespace osu.Game.Database /// /// Select paths to import from stable. Default implementation iterates all directories in . /// - protected virtual IEnumerable GetStableImportPaths(StableStorage stableStoage) => stableStoage.GetDirectories(ImportFromStablePath) - .Select(path => stableStoage.GetFullPath(path)); + protected virtual IEnumerable GetStableImportPaths(StableStorage stableStorage) => stableStorage.GetDirectories(ImportFromStablePath) + .Select(path => stableStorage.GetFullPath(path)); /// /// Whether this specified path should be removed after successful import. From 043385f91928204cba2a292469eecfd65fd086a9 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Tue, 26 Jan 2021 18:26:01 +0100 Subject: [PATCH 07/13] Rename const and fix unintended tabbing. --- osu.Game/Database/ArchiveModelManager.cs | 2 +- osu.Game/IO/StableStorage.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 99301b6c68..ae1608d801 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -646,7 +646,7 @@ namespace osu.Game.Database /// Select paths to import from stable. Default implementation iterates all directories in . /// protected virtual IEnumerable GetStableImportPaths(StableStorage stableStorage) => stableStorage.GetDirectories(ImportFromStablePath) - .Select(path => stableStorage.GetFullPath(path)); + .Select(path => stableStorage.GetFullPath(path)); /// /// Whether this specified path should be removed after successful import. diff --git a/osu.Game/IO/StableStorage.cs b/osu.Game/IO/StableStorage.cs index 85af92621b..88a087087e 100644 --- a/osu.Game/IO/StableStorage.cs +++ b/osu.Game/IO/StableStorage.cs @@ -14,7 +14,7 @@ namespace osu.Game.IO /// public class StableStorage : DesktopStorage { - private const string stable_songs_path = "Songs"; + private const string stable_default_songs_path = "Songs"; private readonly DesktopGameHost host; private readonly string songsPath; @@ -36,7 +36,7 @@ namespace osu.Game.IO var configFile = GetStream(GetFiles(".", "osu!.*.cfg").First()); var textReader = new StreamReader(configFile); - var songsDirectoryPath = Path.Combine(BasePath, stable_songs_path); + var songsDirectoryPath = Path.Combine(BasePath, stable_default_songs_path); while (!textReader.EndOfStream) { From 2a2b6f347e7e8af533e3a9053497fe7ee77898eb Mon Sep 17 00:00:00 2001 From: Lucas A Date: Tue, 26 Jan 2021 19:07:05 +0100 Subject: [PATCH 08/13] Use a lazy for delegating Songs directory locating until it is actually used. --- osu.Game/IO/StableStorage.cs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/osu.Game/IO/StableStorage.cs b/osu.Game/IO/StableStorage.cs index 88a087087e..ebceba6ce0 100644 --- a/osu.Game/IO/StableStorage.cs +++ b/osu.Game/IO/StableStorage.cs @@ -17,38 +17,43 @@ namespace osu.Game.IO private const string stable_default_songs_path = "Songs"; private readonly DesktopGameHost host; - private readonly string songsPath; + private readonly Lazy songsPath; public StableStorage(string path, DesktopGameHost host) : base(path, host) { this.host = host; - songsPath = locateSongsDirectory(); + songsPath = new Lazy(locateSongsDirectory); } /// /// Returns a pointing to the osu-stable Songs directory. /// - public Storage GetSongStorage() => new DesktopStorage(songsPath, host); + public Storage GetSongStorage() => new DesktopStorage(songsPath.Value, host); private string locateSongsDirectory() { - var configFile = GetStream(GetFiles(".", "osu!.*.cfg").First()); - var textReader = new StreamReader(configFile); - var songsDirectoryPath = Path.Combine(BasePath, stable_default_songs_path); - while (!textReader.EndOfStream) + var configFile = GetFiles(".", "osu!.*.cfg").FirstOrDefault(); + + if (configFile == null) + return songsDirectoryPath; + + using (var textReader = new StreamReader(GetStream(configFile))) { - var line = textReader.ReadLine(); + string line; - if (line?.StartsWith("BeatmapDirectory", StringComparison.OrdinalIgnoreCase) == true) + while ((line = textReader.ReadLine()) != null) { - var directory = line.Split('=')[1].TrimStart(); - if (Path.IsPathFullyQualified(directory)) - songsDirectoryPath = directory; + if (line.StartsWith("BeatmapDirectory", StringComparison.OrdinalIgnoreCase)) + { + var directory = line.Split('=')[1].TrimStart(); + if (Path.IsPathFullyQualified(directory)) + songsDirectoryPath = directory; - break; + break; + } } } From 383c40b99268b350e35d955b638781c75e09e682 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Tue, 26 Jan 2021 20:35:42 +0100 Subject: [PATCH 09/13] Address remaining reviews suggestions. --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Database/ArchiveModelManager.cs | 6 +++--- osu.Game/IO/StableStorage.cs | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 43b2486ac5..4825569ee4 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -64,7 +64,7 @@ namespace osu.Game.Beatmaps protected override string[] HashableFileTypes => new[] { ".osu" }; - protected override bool CheckStableDirectoryExists(StableStorage stableStorage) => stableStorage.GetSongStorage().ExistsDirectory("."); + protected override bool StableDirectoryExists(StableStorage stableStorage) => stableStorage.GetSongStorage().ExistsDirectory("."); protected override IEnumerable GetStableImportPaths(StableStorage stableStorage) { diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index ae1608d801..fd94660a4b 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -640,10 +640,10 @@ namespace osu.Game.Database /// /// Checks for the existence of an osu-stable directory. /// - protected virtual bool CheckStableDirectoryExists(StableStorage stableStorage) => stableStorage.ExistsDirectory(ImportFromStablePath); + protected virtual bool StableDirectoryExists(StableStorage stableStorage) => stableStorage.ExistsDirectory(ImportFromStablePath); /// - /// Select paths to import from stable. Default implementation iterates all directories in . + /// Select paths to import from stable where all paths should be absolute. Default implementation iterates all directories in . /// protected virtual IEnumerable GetStableImportPaths(StableStorage stableStorage) => stableStorage.GetDirectories(ImportFromStablePath) .Select(path => stableStorage.GetFullPath(path)); @@ -668,7 +668,7 @@ namespace osu.Game.Database return Task.CompletedTask; } - if (!CheckStableDirectoryExists(stable)) + if (!StableDirectoryExists(stable)) { // This handles situations like when the user does not have a Skins folder Logger.Log($"No {ImportFromStablePath} folder available in osu!stable installation", LoggingTarget.Information, LogLevel.Error); diff --git a/osu.Game/IO/StableStorage.cs b/osu.Game/IO/StableStorage.cs index ebceba6ce0..f86b18c724 100644 --- a/osu.Game/IO/StableStorage.cs +++ b/osu.Game/IO/StableStorage.cs @@ -35,12 +35,13 @@ namespace osu.Game.IO { var songsDirectoryPath = Path.Combine(BasePath, stable_default_songs_path); - var configFile = GetFiles(".", "osu!.*.cfg").FirstOrDefault(); + var configFile = GetFiles(".", "osu!.*.cfg").SingleOrDefault(); if (configFile == null) return songsDirectoryPath; - using (var textReader = new StreamReader(GetStream(configFile))) + using (var stream = GetStream(configFile)) + using (var textReader = new StreamReader(stream)) { string line; From f6d08f54e6e950f4784087012fe27cd3e566a22c Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 5 Feb 2021 21:19:13 +0100 Subject: [PATCH 10/13] Use the oldest user config file available when there happens to be multiple config files available. --- osu.Game/IO/StableStorage.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/IO/StableStorage.cs b/osu.Game/IO/StableStorage.cs index f86b18c724..614e548d93 100644 --- a/osu.Game/IO/StableStorage.cs +++ b/osu.Game/IO/StableStorage.cs @@ -35,7 +35,11 @@ namespace osu.Game.IO { var songsDirectoryPath = Path.Combine(BasePath, stable_default_songs_path); - var configFile = GetFiles(".", "osu!.*.cfg").SingleOrDefault(); + // enumerate the user config files available in case the user migrated their files from another pc / operating system. + var foundConfigFiles = GetFiles(".", "osu!.*.cfg"); + + // if more than one config file is found, let's use the oldest one (where the username in the filename doesn't match the local username). + var configFile = foundConfigFiles.Count() > 1 ? foundConfigFiles.FirstOrDefault(filename => !filename[5..^4].Contains(Environment.UserName, StringComparison.Ordinal)) : foundConfigFiles.FirstOrDefault(); if (configFile == null) return songsDirectoryPath; From f0dfa9f8f397269571b96d1165f03f36a555bc8e Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 8 Feb 2021 11:12:25 +0100 Subject: [PATCH 11/13] Use the newest config file available (where the local username matches the filename) --- osu.Game/IO/StableStorage.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/IO/StableStorage.cs b/osu.Game/IO/StableStorage.cs index 614e548d93..ccc6f9c311 100644 --- a/osu.Game/IO/StableStorage.cs +++ b/osu.Game/IO/StableStorage.cs @@ -35,11 +35,7 @@ namespace osu.Game.IO { var songsDirectoryPath = Path.Combine(BasePath, stable_default_songs_path); - // enumerate the user config files available in case the user migrated their files from another pc / operating system. - var foundConfigFiles = GetFiles(".", "osu!.*.cfg"); - - // if more than one config file is found, let's use the oldest one (where the username in the filename doesn't match the local username). - var configFile = foundConfigFiles.Count() > 1 ? foundConfigFiles.FirstOrDefault(filename => !filename[5..^4].Contains(Environment.UserName, StringComparison.Ordinal)) : foundConfigFiles.FirstOrDefault(); + var configFile = GetFiles(".", $"osu!.{Environment.UserName}.cfg").SingleOrDefault(); if (configFile == null) return songsDirectoryPath; From 5f23bd725941a94304481d7aa37409162426e8ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Feb 2021 12:48:32 +0900 Subject: [PATCH 12/13] Revert most of the changes to ArchiveModeManager by using better code --- osu.Game/Beatmaps/BeatmapManager.cs | 8 ++------ osu.Game/Database/ArchiveModelManager.cs | 26 ++++++++++++++---------- osu.Game/Scoring/ScoreManager.cs | 7 +++---- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 4825569ee4..f23e135c68 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -64,13 +64,9 @@ namespace osu.Game.Beatmaps protected override string[] HashableFileTypes => new[] { ".osu" }; - protected override bool StableDirectoryExists(StableStorage stableStorage) => stableStorage.GetSongStorage().ExistsDirectory("."); + protected override string ImportFromStablePath => "."; - protected override IEnumerable GetStableImportPaths(StableStorage stableStorage) - { - var songStorage = stableStorage.GetSongStorage(); - return songStorage.GetDirectories(".").Select(path => songStorage.GetFullPath(path)); - } + protected override Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage.GetSongStorage(); private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index fd94660a4b..b55020c437 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -637,16 +637,11 @@ namespace osu.Game.Database /// protected virtual string ImportFromStablePath => null; - /// - /// Checks for the existence of an osu-stable directory. - /// - protected virtual bool StableDirectoryExists(StableStorage stableStorage) => stableStorage.ExistsDirectory(ImportFromStablePath); - /// /// Select paths to import from stable where all paths should be absolute. Default implementation iterates all directories in . /// - protected virtual IEnumerable GetStableImportPaths(StableStorage stableStorage) => stableStorage.GetDirectories(ImportFromStablePath) - .Select(path => stableStorage.GetFullPath(path)); + protected virtual IEnumerable GetStableImportPaths(Storage storage) => storage.GetDirectories(ImportFromStablePath) + .Select(path => storage.GetFullPath(path)); /// /// Whether this specified path should be removed after successful import. @@ -660,24 +655,33 @@ namespace osu.Game.Database /// public Task ImportFromStableAsync() { - var stable = GetStableStorage?.Invoke(); + var stableStorage = GetStableStorage?.Invoke(); - if (stable == null) + if (stableStorage == null) { Logger.Log("No osu!stable installation available!", LoggingTarget.Information, LogLevel.Error); return Task.CompletedTask; } - if (!StableDirectoryExists(stable)) + var storage = PrepareStableStorage(stableStorage); + + if (!storage.ExistsDirectory(ImportFromStablePath)) { // This handles situations like when the user does not have a Skins folder Logger.Log($"No {ImportFromStablePath} folder available in osu!stable installation", LoggingTarget.Information, LogLevel.Error); return Task.CompletedTask; } - return Task.Run(async () => await Import(GetStableImportPaths(stable).ToArray())); + return Task.Run(async () => await Import(GetStableImportPaths(storage).ToArray())); } + /// + /// Run any required traversal operations on the stable storage location before performing operations. + /// + /// The stable storage. + /// The usable storage. Return the unchanged if no traversal is required. + protected virtual Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage; + #endregion /// diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 6aa0a30a75..a6beb19876 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -16,7 +16,6 @@ using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; -using osu.Game.IO; using osu.Game.IO.Archives; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -72,9 +71,9 @@ namespace osu.Game.Scoring } } - protected override IEnumerable GetStableImportPaths(StableStorage stableStorage) - => stableStorage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false)) - .Select(path => stableStorage.GetFullPath(path)); + protected override IEnumerable GetStableImportPaths(Storage storage) + => storage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false)) + .Select(path => storage.GetFullPath(path)); public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store); From 8ab7d07eab83befc7332496d20250fe54bf5ddc3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Feb 2021 12:57:57 +0900 Subject: [PATCH 13/13] Tidy up config parsing logic --- osu.Game/IO/StableStorage.cs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/osu.Game/IO/StableStorage.cs b/osu.Game/IO/StableStorage.cs index ccc6f9c311..d4b0d300ff 100644 --- a/osu.Game/IO/StableStorage.cs +++ b/osu.Game/IO/StableStorage.cs @@ -23,6 +23,7 @@ namespace osu.Game.IO : base(path, host) { this.host = host; + songsPath = new Lazy(locateSongsDirectory); } @@ -33,32 +34,29 @@ namespace osu.Game.IO private string locateSongsDirectory() { - var songsDirectoryPath = Path.Combine(BasePath, stable_default_songs_path); - var configFile = GetFiles(".", $"osu!.{Environment.UserName}.cfg").SingleOrDefault(); - if (configFile == null) - return songsDirectoryPath; - - using (var stream = GetStream(configFile)) - using (var textReader = new StreamReader(stream)) + if (configFile != null) { - string line; - - while ((line = textReader.ReadLine()) != null) + using (var stream = GetStream(configFile)) + using (var textReader = new StreamReader(stream)) { - if (line.StartsWith("BeatmapDirectory", StringComparison.OrdinalIgnoreCase)) + string line; + + while ((line = textReader.ReadLine()) != null) { - var directory = line.Split('=')[1].TrimStart(); - if (Path.IsPathFullyQualified(directory)) - songsDirectoryPath = directory; + if (!line.StartsWith("BeatmapDirectory", StringComparison.OrdinalIgnoreCase)) continue; + + var customDirectory = line.Split('=').LastOrDefault()?.Trim(); + if (customDirectory != null && Path.IsPathFullyQualified(customDirectory)) + return customDirectory; break; } } } - return songsDirectoryPath; + return GetFullPath(stable_default_songs_path); } } }