From a56f9d6770e0ea9f3392a59dd2a2e99706c2654e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Sep 2020 00:08:33 +0900 Subject: [PATCH] Implement collection import --- osu.Game/Collections/CollectionManager.cs | 88 +++++++++++++------ osu.Game/OsuGame.cs | 2 + osu.Game/OsuGameBase.cs | 5 +- .../Sections/Maintenance/GeneralSettings.cs | 45 +++++++--- 4 files changed, 99 insertions(+), 41 deletions(-) diff --git a/osu.Game/Collections/CollectionManager.cs b/osu.Game/Collections/CollectionManager.cs index e6eed40dfc..20bf96da9d 100644 --- a/osu.Game/Collections/CollectionManager.cs +++ b/osu.Game/Collections/CollectionManager.cs @@ -4,8 +4,10 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; @@ -25,12 +27,13 @@ namespace osu.Game.Collections private const string database_name = "collection.db"; + public readonly BindableList Collections = new BindableList(); + + public bool SupportsImportFromStable => RuntimeInfo.IsDesktop; + [Resolved] private GameHost host { get; set; } - public IBindableList Collections => collections; - private readonly BindableList collections = new BindableList(); - [Resolved] private BeatmapManager beatmaps { get; set; } @@ -40,12 +43,12 @@ namespace osu.Game.Collections if (host.Storage.Exists(database_name)) { using (var stream = host.Storage.GetStream(database_name)) - collections.AddRange(readCollection(stream)); + importCollections(readCollections(stream)); } - foreach (var c in collections) + foreach (var c in Collections) c.Changed += backgroundSave; - collections.CollectionChanged += (_, __) => backgroundSave(); + Collections.CollectionChanged += (_, __) => backgroundSave(); } /// @@ -56,26 +59,55 @@ namespace osu.Game.Collections /// /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. /// - // public Task ImportFromStableAsync() - // { - // var stable = GetStableStorage?.Invoke(); - // - // if (stable == null) - // { - // Logger.Log("No osu!stable installation available!", LoggingTarget.Information, LogLevel.Error); - // return Task.CompletedTask; - // } - // - // if (!stable.ExistsDirectory(database_name)) - // { - // // This handles situations like when the user does not have a Skins folder - // Logger.Log($"No {database_name} 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())); - // } - private List readCollection(Stream stream) + public Task ImportFromStableAsync() + { + var stable = GetStableStorage?.Invoke(); + + if (stable == null) + { + Logger.Log("No osu!stable installation available!", LoggingTarget.Information, LogLevel.Error); + return Task.CompletedTask; + } + + if (!stable.Exists(database_name)) + { + // This handles situations like when the user does not have a collections.db file + Logger.Log($"No {database_name} available in osu!stable installation", LoggingTarget.Information, LogLevel.Error); + return Task.CompletedTask; + } + + return Task.Run(() => + { + var storage = GetStableStorage(); + + if (storage.Exists(database_name)) + { + using (var stream = storage.GetStream(database_name)) + { + var collection = readCollections(stream); + Schedule(() => importCollections(collection)); + } + } + }); + } + + private void importCollections(List newCollections) + { + foreach (var newCol in newCollections) + { + var existing = Collections.FirstOrDefault(c => c.Name == newCol.Name); + if (existing == null) + Collections.Add(existing = new BeatmapCollection { Name = newCol.Name }); + + foreach (var newBeatmap in newCol.Beatmaps) + { + if (!existing.Beatmaps.Contains(newBeatmap)) + existing.Beatmaps.Add(newBeatmap); + } + } + } + + private List readCollections(Stream stream) { var result = new List(); @@ -147,9 +179,9 @@ namespace osu.Game.Collections using (var sw = new SerializationWriter(host.Storage.GetStream(database_name, FileAccess.Write))) { sw.Write(database_version); - sw.Write(collections.Count); + sw.Write(Collections.Count); - foreach (var c in collections) + foreach (var c in Collections) { sw.Write(c.Name); sw.Write(c.Beatmaps.Count); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 053eb01dcd..5008a3cf3b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -549,6 +549,8 @@ namespace osu.Game ScoreManager.GetStableStorage = GetStorageForStableInstall; ScoreManager.PresentImport = items => PresentScore(items.First()); + CollectionManager.GetStableStorage = GetStorageForStableInstall; + Container logoContainer; BackButton.Receptor receptor; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 3ba164e87f..d512f57ca5 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -225,9 +225,8 @@ namespace osu.Game dependencies.Cache(difficultyManager); AddInternal(difficultyManager); - var collectionManager = new CollectionManager(); - dependencies.Cache(collectionManager); - AddInternal(collectionManager); + dependencies.Cache(CollectionManager = new CollectionManager()); + AddInternal(CollectionManager); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 832673703b..21a5ed6b31 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; +using osu.Game.Collections; using osu.Game.Graphics.UserInterface; using osu.Game.Scoring; using osu.Game.Skinning; @@ -19,6 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private TriangleButton importBeatmapsButton; private TriangleButton importScoresButton; private TriangleButton importSkinsButton; + private TriangleButton importCollectionsButton; private TriangleButton deleteBeatmapsButton; private TriangleButton deleteScoresButton; private TriangleButton deleteSkinsButton; @@ -26,7 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private TriangleButton undeleteButton; [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, DialogOverlay dialogOverlay) + private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, CollectionManager collections, DialogOverlay dialogOverlay) { if (beatmaps.SupportsImportFromStable) { @@ -93,20 +95,43 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance }); } - AddRange(new Drawable[] + Add(deleteSkinsButton = new DangerousSettingsButton { - deleteSkinsButton = new DangerousSettingsButton + Text = "Delete ALL skins", + Action = () => { - Text = "Delete ALL skins", + dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => + { + deleteSkinsButton.Enabled.Value = false; + Task.Run(() => skins.Delete(skins.GetAllUserSkins())).ContinueWith(t => Schedule(() => deleteSkinsButton.Enabled.Value = true)); + })); + } + }); + + if (collections.SupportsImportFromStable) + { + Add(importCollectionsButton = new SettingsButton + { + Text = "Import collections from stable", Action = () => { - dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => - { - deleteSkinsButton.Enabled.Value = false; - Task.Run(() => skins.Delete(skins.GetAllUserSkins())).ContinueWith(t => Schedule(() => deleteSkinsButton.Enabled.Value = true)); - })); + importCollectionsButton.Enabled.Value = false; + collections.ImportFromStableAsync().ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); } - }, + }); + } + + Add(new DangerousSettingsButton + { + Text = "Delete ALL collections", + Action = () => + { + dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => collections.Collections.Clear())); + } + }); + + AddRange(new Drawable[] + { restoreButton = new SettingsButton { Text = "Restore all hidden difficulties",