From f3984d98e654fdf93d011d795672270b9f7692b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Jun 2022 18:53:13 +0900 Subject: [PATCH 1/6] Remove `RealmArchiveModelManager` from hierarchy --- .../Database/BeatmapImporterTests.cs | 56 ++++++++++--------- ...eneOnlinePlayBeatmapAvailabilityTracker.cs | 2 +- osu.Game/Beatmaps/BeatmapImporter.cs | 9 +-- osu.Game/Beatmaps/BeatmapManager.cs | 51 ++--------------- osu.Game/Database/ImportTask.cs | 2 +- osu.Game/Database/RealmArchiveModelManager.cs | 22 ++++---- osu.Game/Scoring/ScoreImporter.cs | 7 +-- osu.Game/Scoring/ScoreManager.cs | 33 ++--------- osu.Game/Skinning/SkinImporter.cs | 20 ++++--- osu.Game/Skinning/SkinManager.cs | 32 +---------- 10 files changed, 69 insertions(+), 165 deletions(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index 03e388c821..53d13f0d4e 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using (var importer = new BeatmapImporter(realm, storage)) + using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { Live? beatmapSet; @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using (var importer = new BeatmapImporter(realm, storage)) + using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { Live? beatmapSet; @@ -141,7 +141,9 @@ namespace osu.Game.Tests.Database { BeatmapSetInfo? detachedSet = null; - using (var importer = new BeatmapImporter(realm, storage)) + var manager = new ModelManager(storage, realm); + + using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { Task.Run(async () => @@ -160,7 +162,7 @@ namespace osu.Game.Tests.Database }).WaitSafely(); Debug.Assert(detachedSet != null); - importer.AddFile(detachedSet, new MemoryStream(), "test"); + manager.AddFile(detachedSet, new MemoryStream(), "test"); } }); } @@ -170,7 +172,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using (var importer = new BeatmapImporter(realm, storage)) + using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { Live? imported; @@ -202,7 +204,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); await LoadOszIntoStore(importer, realm.Realm); @@ -214,7 +216,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var imported = await LoadOszIntoStore(importer, realm.Realm); @@ -232,7 +234,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var imported = await LoadOszIntoStore(importer, realm.Realm); @@ -246,7 +248,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? tempPath = TestResources.GetTestBeatmapForImport(); @@ -276,7 +278,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var imported = await LoadOszIntoStore(importer, realm.Realm); @@ -296,7 +298,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? temp = TestResources.GetTestBeatmapForImport(); @@ -345,7 +347,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? temp = TestResources.GetTestBeatmapForImport(); @@ -396,7 +398,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? temp = TestResources.GetTestBeatmapForImport(); @@ -444,7 +446,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? temp = TestResources.GetTestBeatmapForImport(); @@ -492,7 +494,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var imported = await LoadOszIntoStore(importer, realm.Realm); @@ -527,7 +529,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var progressNotification = new ImportProgressNotification(); @@ -565,7 +567,7 @@ namespace osu.Game.Tests.Database Interlocked.Increment(ref loggedExceptionCount); }; - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var imported = await LoadOszIntoStore(importer, realm.Realm); @@ -617,7 +619,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var imported = await LoadOszIntoStore(importer, realm.Realm, batchImport: true); @@ -644,7 +646,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realmFactory, storage) => { - using var importer = new BeatmapImporter(realmFactory, storage); + using var importer = new BeatmapImporter(storage, realmFactory); using var store = new RealmRulesetStore(realmFactory, storage); var imported = await LoadOszIntoStore(importer, realmFactory.Realm); @@ -676,7 +678,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var imported = await LoadOszIntoStore(importer, realm.Realm); @@ -703,7 +705,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var imported = await LoadOszIntoStore(importer, realm.Realm); @@ -729,7 +731,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealm((realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var metadata = new BeatmapMetadata @@ -777,7 +779,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? temp = TestResources.GetTestBeatmapForImport(); @@ -794,7 +796,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? temp = TestResources.GetTestBeatmapForImport(); @@ -830,7 +832,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? temp = TestResources.GetTestBeatmapForImport(); @@ -872,7 +874,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? temp = TestResources.GetTestBeatmapForImport(); @@ -923,7 +925,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealmAsync(async (realm, storage) => { - using var importer = new BeatmapImporter(realm, storage); + using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string? temp = TestResources.GetTestBeatmapForImport(); diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index 915ad50d2b..c26d7937ad 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -220,7 +220,7 @@ namespace osu.Game.Tests.Online private readonly TestBeatmapManager testBeatmapManager; public TestBeatmapImporter(TestBeatmapManager testBeatmapManager, Storage storage, RealmAccess databaseAccess, BeatmapOnlineLookupQueue beatmapOnlineLookupQueue) - : base(databaseAccess, storage, beatmapOnlineLookupQueue) + : base(storage, databaseAccess, beatmapOnlineLookupQueue) { this.testBeatmapManager = testBeatmapManager; } diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index eded4cf9d1..5e3aa434b8 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -32,7 +32,7 @@ namespace osu.Game.Beatmaps /// Handles the storage and retrieval of Beatmaps/WorkingBeatmaps. /// [ExcludeFromDynamicCompile] - public class BeatmapImporter : RealmArchiveModelManager, IDisposable + public class BeatmapImporter : RealmArchiveModelImporter, IDisposable { public override IEnumerable HandledExtensions => new[] { ".osz" }; @@ -40,7 +40,7 @@ namespace osu.Game.Beatmaps private readonly BeatmapOnlineLookupQueue? onlineLookupQueue; - public BeatmapImporter(RealmAccess realm, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null) + public BeatmapImporter(Storage storage, RealmAccess realm, BeatmapOnlineLookupQueue? onlineLookupQueue = null) : base(storage, realm) { this.onlineLookupQueue = onlineLookupQueue; @@ -165,11 +165,6 @@ namespace osu.Game.Beatmaps existing.DateAdded = DateTimeOffset.UtcNow; } - public override bool IsAvailableLocally(BeatmapSetInfo model) - { - return Realm.Run(realm => realm.All().Any(s => s.OnlineID == model.OnlineID)); - } - public override string HumanisedModelName => "beatmap"; protected override BeatmapSetInfo? CreateModel(ArchiveReader reader) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index a4ac161223..662931cd17 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -36,7 +36,7 @@ namespace osu.Game.Beatmaps /// Handles general operations related to global beatmap management. /// [ExcludeFromDynamicCompile] - public class BeatmapManager : IModelManager, IModelFileManager, IModelImporter, IWorkingBeatmapCache, IDisposable + public class BeatmapManager : ModelManager, IModelImporter, IWorkingBeatmapCache, IDisposable { public ITrackStore BeatmapTrackStore { get; } @@ -49,6 +49,7 @@ namespace osu.Game.Beatmaps public BeatmapManager(Storage storage, RealmAccess realm, RulesetStore rulesets, IAPIProvider? api, AudioManager audioManager, IResourceStore gameResources, GameHost? host = null, WorkingBeatmap? defaultBeatmap = null, bool performOnlineLookups = false) + : base(storage, realm) { this.realm = realm; @@ -75,7 +76,7 @@ namespace osu.Game.Beatmaps } protected virtual BeatmapImporter CreateBeatmapImporter(Storage storage, RealmAccess realm, RulesetStore rulesets, BeatmapOnlineLookupQueue? onlineLookupQueue) => - new BeatmapImporter(realm, storage, onlineLookupQueue); + new BeatmapImporter(storage, realm, onlineLookupQueue); /// /// Create a new beatmap set, backed by a model, @@ -272,15 +273,6 @@ namespace osu.Game.Beatmaps /// public IWorkingBeatmap DefaultBeatmap => workingBeatmapCache.DefaultBeatmap; - /// - /// Fired when a notification should be presented to the user. - /// - public Action? PostNotification - { - get => beatmapImporter.PostNotification; - set => beatmapImporter.PostNotification = value; - } - /// /// Saves an file against a given . /// @@ -356,7 +348,7 @@ namespace osu.Game.Beatmaps if (filter != null) items = items.Where(filter); - beatmapImporter.Delete(items.ToList(), silent); + Delete(items.ToList(), silent); }); } @@ -407,23 +399,9 @@ namespace osu.Game.Beatmaps public void UndeleteAll() { - realm.Run(r => beatmapImporter.Undelete(r.All().Where(s => s.DeletePending).ToList())); + realm.Run(r => Undelete(r.All().Where(s => s.DeletePending).ToList())); } - #region Implementation of IModelManager - - public bool IsAvailableLocally(BeatmapSetInfo model) => beatmapImporter.IsAvailableLocally(model); - - public bool Delete(BeatmapSetInfo item) => beatmapImporter.Delete(item); - - public void Delete(List items, bool silent = false) => beatmapImporter.Delete(items, silent); - - public void Undelete(List items, bool silent = false) => beatmapImporter.Undelete(items, silent); - - public void Undelete(BeatmapSetInfo item) => beatmapImporter.Undelete(item); - - #endregion - #region Implementation of ICanAcceptFiles public Task Import(params string[] paths) => beatmapImporter.Import(paths); @@ -479,25 +457,6 @@ namespace osu.Game.Beatmaps #endregion - #region Implementation of IModelFileManager - - public void ReplaceFile(BeatmapSetInfo model, RealmNamedFileUsage file, Stream contents) - { - beatmapImporter.ReplaceFile(model, file, contents); - } - - public void DeleteFile(BeatmapSetInfo model, RealmNamedFileUsage file) - { - beatmapImporter.DeleteFile(model, file); - } - - public void AddFile(BeatmapSetInfo model, Stream contents, string filename) - { - beatmapImporter.AddFile(model, contents, filename); - } - - #endregion - #region Implementation of IDisposable public void Dispose() diff --git a/osu.Game/Database/ImportTask.cs b/osu.Game/Database/ImportTask.cs index 41ce0339a1..e34b4c76a9 100644 --- a/osu.Game/Database/ImportTask.cs +++ b/osu.Game/Database/ImportTask.cs @@ -12,7 +12,7 @@ using SharpCompress.Common; namespace osu.Game.Database { /// - /// An encapsulated import task to be imported to an . + /// An encapsulated import task to be imported to an . /// public class ImportTask { diff --git a/osu.Game/Database/RealmArchiveModelManager.cs b/osu.Game/Database/RealmArchiveModelManager.cs index 371b9be575..5056b0d49f 100644 --- a/osu.Game/Database/RealmArchiveModelManager.cs +++ b/osu.Game/Database/RealmArchiveModelManager.cs @@ -15,18 +15,17 @@ using Realms; namespace osu.Game.Database { - /// - /// Class which adds all the missing pieces bridging the gap between and (legacy) ArchiveModelManager. - /// - public abstract class RealmArchiveModelManager : RealmArchiveModelImporter, IModelManager, IModelFileManager + public class ModelManager : IModelManager, IModelFileManager where TModel : RealmObject, IHasRealmFiles, IHasGuidPrimaryKey, ISoftDelete { + protected RealmAccess Realm; + private readonly RealmFileStore realmFileStore; - protected RealmArchiveModelManager(Storage storage, RealmAccess realm) - : base(storage, realm) + public ModelManager(Storage storage, RealmAccess realm) { realmFileStore = new RealmFileStore(realm, storage); + Realm = realm; } public void DeleteFile(TModel item, RealmNamedFileUsage file) => @@ -62,7 +61,7 @@ namespace osu.Game.Database /// /// Delete a file from within an ongoing realm transaction. /// - protected void DeleteFile(TModel item, RealmNamedFileUsage file, Realm realm) + public void DeleteFile(TModel item, RealmNamedFileUsage file, Realm realm) { item.Files.Remove(file); } @@ -70,7 +69,7 @@ namespace osu.Game.Database /// /// Replace a file from within an ongoing realm transaction. /// - protected void ReplaceFile(RealmNamedFileUsage file, Stream contents, Realm realm) + public void ReplaceFile(RealmNamedFileUsage file, Stream contents, Realm realm) { file.File = realmFileStore.Add(contents, realm); } @@ -78,7 +77,7 @@ namespace osu.Game.Database /// /// Add a file from within an ongoing realm transaction. If the file already exists, it is overwritten. /// - protected void AddFile(TModel item, Stream contents, string filename, Realm realm) + public void AddFile(TModel item, Stream contents, string filename, Realm realm) { var existing = item.Files.FirstOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase)); @@ -200,6 +199,9 @@ namespace osu.Game.Database }); } - public abstract bool IsAvailableLocally(TModel model); + // TODO: implement + public virtual bool IsAvailableLocally(TModel model) => true; + public Action? PostNotification { get; set; } + public string HumanisedModelName { get; set; } = "wang"; } } diff --git a/osu.Game/Scoring/ScoreImporter.cs b/osu.Game/Scoring/ScoreImporter.cs index 76c43ba2e2..7d1aa4b01d 100644 --- a/osu.Game/Scoring/ScoreImporter.cs +++ b/osu.Game/Scoring/ScoreImporter.cs @@ -19,7 +19,7 @@ using Realms; namespace osu.Game.Scoring { - public class ScoreImporter : RealmArchiveModelManager + public class ScoreImporter : RealmArchiveModelImporter { public override IEnumerable HandledExtensions => new[] { ".osr" }; @@ -70,10 +70,5 @@ namespace osu.Game.Scoring if (string.IsNullOrEmpty(model.StatisticsJson)) model.StatisticsJson = JsonConvert.SerializeObject(model.Statistics); } - - public override bool IsAvailableLocally(ScoreInfo model) - { - return Realm.Run(realm => realm.All().Any(s => s.OnlineID == model.OnlineID)); - } } } diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 125746d5dd..da77b0bc6c 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -22,7 +22,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Scoring { - public class ScoreManager : IModelManager, IModelImporter + public class ScoreManager : ModelManager, IModelImporter { private readonly RealmAccess realm; private readonly Scheduler scheduler; @@ -32,6 +32,7 @@ namespace osu.Game.Scoring public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, Scheduler scheduler, Func difficulties = null, OsuConfigManager configManager = null) + : base(storage, realm) { this.realm = realm; this.scheduler = scheduler; @@ -227,22 +228,6 @@ namespace osu.Game.Scoring } } - #region Implementation of IPostNotifications - - public Action PostNotification - { - set => scoreImporter.PostNotification = value; - } - - #endregion - - #region Implementation of IModelManager - - public bool Delete(ScoreInfo item) - { - return scoreImporter.Delete(item); - } - public void Delete([CanBeNull] Expression> filter = null, bool silent = false) { realm.Run(r => @@ -253,7 +238,7 @@ namespace osu.Game.Scoring if (filter != null) items = items.Where(filter); - scoreImporter.Delete(items.ToList(), silent); + Delete(items.ToList(), silent); }); } @@ -262,16 +247,10 @@ namespace osu.Game.Scoring realm.Run(r => { var beatmapScores = r.Find(beatmap.ID).Scores.ToList(); - scoreImporter.Delete(beatmapScores, silent); + Delete(beatmapScores, silent); }); } - public void Delete(List items, bool silent = false) => scoreImporter.Delete(items, silent); - - public void Undelete(List items, bool silent = false) => scoreImporter.Undelete(items, silent); - - public void Undelete(ScoreInfo item) => scoreImporter.Undelete(item); - public Task Import(params string[] paths) => scoreImporter.Import(paths); public Task Import(params ImportTask[] tasks) => scoreImporter.Import(tasks); @@ -282,10 +261,6 @@ namespace osu.Game.Scoring public Live Import(ScoreInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) => scoreImporter.Import(item, archive, batchImport, cancellationToken); - public bool IsAvailableLocally(ScoreInfo model) => scoreImporter.IsAvailableLocally(model); - - #endregion - #region Implementation of IPresentImports public Action>> PostImport diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index 67626a45a8..7b82655dca 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -20,17 +20,21 @@ using Realms; namespace osu.Game.Skinning { - public class SkinImporter : RealmArchiveModelManager + public class SkinImporter : RealmArchiveModelImporter { private const string skin_info_file = "skininfo.json"; private readonly IStorageResourceProvider skinResources; + private readonly ModelManager modelManager; + public SkinImporter(Storage storage, RealmAccess realm, IStorageResourceProvider skinResources) : base(storage, realm) { this.skinResources = skinResources; + modelManager = new ModelManager(storage, realm); + // can be removed 20220420. populateMissingHashes(); } @@ -154,7 +158,7 @@ namespace osu.Game.Skinning sw.WriteLine(line); } - ReplaceFile(existingFile, stream, realm); + modelManager.ReplaceFile(existingFile, stream, realm); // can be removed 20220502. if (!ensureIniWasUpdated(item)) @@ -184,7 +188,7 @@ namespace osu.Game.Skinning sw.WriteLine(line); } - AddFile(item, stream, @"skin.ini", realm); + modelManager.AddFile(item, stream, @"skin.ini", realm); } item.Hash = ComputeHash(item); @@ -216,7 +220,7 @@ namespace osu.Game.Skinning } catch (Exception e) { - Delete(skin); + modelManager.Delete(skin); Logger.Error(e, $"Existing skin {skin} has been deleted during hash recomputation due to being invalid"); } } @@ -234,7 +238,7 @@ namespace osu.Game.Skinning using (var streamContent = new MemoryStream(Encoding.UTF8.GetBytes(skinInfoJson))) { - AddFile(s, streamContent, skin_info_file, s.Realm); + modelManager.AddFile(s, streamContent, skin_info_file, s.Realm); } // Then serialise each of the drawable component groups into respective files. @@ -249,16 +253,14 @@ namespace osu.Game.Skinning var oldFile = s.Files.FirstOrDefault(f => f.Filename == filename); if (oldFile != null) - ReplaceFile(oldFile, streamContent, s.Realm); + modelManager.ReplaceFile(oldFile, streamContent, s.Realm); else - AddFile(s, streamContent, filename, s.Realm); + modelManager.AddFile(s, streamContent, filename, s.Realm); } } s.Hash = ComputeHash(s); }); } - - public override bool IsAvailableLocally(SkinInfo model) => true; // skins do not have online download support yet. } } diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index f244657ea3..491de0c152 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Linq.Expressions; using System.Threading; @@ -24,7 +23,6 @@ using osu.Game.Audio; using osu.Game.Database; using osu.Game.IO; using osu.Game.IO.Archives; -using osu.Game.Models; using osu.Game.Overlays.Notifications; using osu.Game.Utils; @@ -38,7 +36,7 @@ namespace osu.Game.Skinning /// For gameplay components, see which adds extra legacy and toggle logic that may affect the lookup process. /// [ExcludeFromDynamicCompile] - public class SkinManager : ISkinSource, IStorageResourceProvider, IModelImporter, IModelManager, IModelFileManager + public class SkinManager : ModelManager, ISkinSource, IStorageResourceProvider, IModelImporter { private readonly AudioManager audio; @@ -71,6 +69,7 @@ namespace osu.Game.Skinning public Skin DefaultLegacySkin { get; } public SkinManager(Storage storage, RealmAccess realm, GameHost host, IResourceStore resources, AudioManager audio, Scheduler scheduler) + : base(storage, realm) { this.realm = realm; this.audio = audio; @@ -258,11 +257,6 @@ namespace osu.Game.Skinning #region Implementation of IModelImporter - public Action PostNotification - { - set => skinImporter.PostNotification = value; - } - public Action>> PostImport { set => skinImporter.PostImport = value; @@ -283,8 +277,6 @@ namespace osu.Game.Skinning #endregion - #region Implementation of IModelManager - public void Delete([CanBeNull] Expression> filter = null, bool silent = false) { realm.Run(r => @@ -300,26 +292,8 @@ namespace osu.Game.Skinning if (items.Any(s => s.ID == currentUserSkin)) scheduler.Add(() => CurrentSkinInfo.Value = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged()); - skinImporter.Delete(items.ToList(), silent); + Delete(items.ToList(), silent); }); } - - public bool Delete(SkinInfo item) => skinImporter.Delete(item); - - public void Delete(List items, bool silent = false) => skinImporter.Delete(items, silent); - - public void Undelete(List items, bool silent = false) => skinImporter.Undelete(items, silent); - - public void Undelete(SkinInfo item) => skinImporter.Undelete(item); - - public bool IsAvailableLocally(SkinInfo model) => skinImporter.IsAvailableLocally(model); - - public void ReplaceFile(SkinInfo model, RealmNamedFileUsage file, Stream contents) => skinImporter.ReplaceFile(model, file, contents); - - public void DeleteFile(SkinInfo model, RealmNamedFileUsage file) => skinImporter.DeleteFile(model, file); - - public void AddFile(SkinInfo model, Stream contents, string filename) => skinImporter.AddFile(model, contents, filename); - - #endregion } } From 72c5b9009d6743a4aab0666a5ef919d21e91ccaa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Jun 2022 18:56:53 +0900 Subject: [PATCH 2/6] Remove local `realm` fields in manager classes --- osu.Game/Beatmaps/BeatmapManager.cs | 26 ++++++++----------- osu.Game/Database/RealmArchiveModelManager.cs | 2 +- osu.Game/Scoring/ScoreManager.cs | 8 +++--- osu.Game/Skinning/SkinManager.cs | 14 +++++----- 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 662931cd17..33e8cea380 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -45,14 +45,10 @@ namespace osu.Game.Beatmaps private readonly WorkingBeatmapCache workingBeatmapCache; private readonly BeatmapOnlineLookupQueue? onlineBeatmapLookupQueue; - private readonly RealmAccess realm; - public BeatmapManager(Storage storage, RealmAccess realm, RulesetStore rulesets, IAPIProvider? api, AudioManager audioManager, IResourceStore gameResources, GameHost? host = null, WorkingBeatmap? defaultBeatmap = null, bool performOnlineLookups = false) : base(storage, realm) { - this.realm = realm; - if (performOnlineLookups) { if (api == null) @@ -192,7 +188,7 @@ namespace osu.Game.Beatmaps /// The beatmap difficulty to hide. public void Hide(BeatmapInfo beatmapInfo) { - realm.Run(r => + Realm.Run(r => { using (var transaction = r.BeginWrite()) { @@ -211,7 +207,7 @@ namespace osu.Game.Beatmaps /// The beatmap difficulty to restore. public void Restore(BeatmapInfo beatmapInfo) { - realm.Run(r => + Realm.Run(r => { using (var transaction = r.BeginWrite()) { @@ -226,7 +222,7 @@ namespace osu.Game.Beatmaps public void RestoreAll() { - realm.Run(r => + Realm.Run(r => { using (var transaction = r.BeginWrite()) { @@ -244,7 +240,7 @@ namespace osu.Game.Beatmaps /// A list of available . public List GetAllUsableBeatmapSets() { - return realm.Run(r => + return Realm.Run(r => { r.Refresh(); return r.All().Where(b => !b.DeletePending).Detach(); @@ -258,7 +254,7 @@ namespace osu.Game.Beatmaps /// The first result for the provided query, or null if no results were found. public Live? QueryBeatmapSet(Expression> query) { - return realm.Run(r => r.All().FirstOrDefault(query)?.ToLive(realm)); + return Realm.Run(r => r.All().FirstOrDefault(query)?.ToLive(Realm)); } /// @@ -266,7 +262,7 @@ namespace osu.Game.Beatmaps /// /// The query. /// The first result for the provided query, or null if no results were found. - public BeatmapInfo? QueryBeatmap(Expression> query) => realm.Run(r => r.All().FirstOrDefault(query)?.Detach()); + public BeatmapInfo? QueryBeatmap(Expression> query) => Realm.Run(r => r.All().FirstOrDefault(query)?.Detach()); /// /// A default representation of a WorkingBeatmap to use when no beatmap is available. @@ -318,7 +314,7 @@ namespace osu.Game.Beatmaps AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo)); - realm.Write(r => setInfo.CopyChangesToRealm(r.Find(setInfo.ID))); + Realm.Write(r => setInfo.CopyChangesToRealm(r.Find(setInfo.ID))); } workingBeatmapCache.Invalidate(beatmapInfo); @@ -332,7 +328,7 @@ namespace osu.Game.Beatmaps public void DeleteAllVideos() { - realm.Write(r => + Realm.Write(r => { var items = r.All().Where(s => !s.DeletePending && !s.Protected); DeleteVideos(items.ToList()); @@ -341,7 +337,7 @@ namespace osu.Game.Beatmaps public void Delete(Expression>? filter = null, bool silent = false) { - realm.Run(r => + Realm.Run(r => { var items = r.All().Where(s => !s.DeletePending && !s.Protected); @@ -399,7 +395,7 @@ namespace osu.Game.Beatmaps public void UndeleteAll() { - realm.Run(r => Undelete(r.All().Where(s => s.DeletePending).ToList())); + Realm.Run(r => Undelete(r.All().Where(s => s.DeletePending).ToList())); } #region Implementation of ICanAcceptFiles @@ -431,7 +427,7 @@ 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) { - realm.Run(r => + Realm.Run(r => { var refetch = r.Find(importedBeatmap.ID)?.Detach(); diff --git a/osu.Game/Database/RealmArchiveModelManager.cs b/osu.Game/Database/RealmArchiveModelManager.cs index 5056b0d49f..bf4a8ca969 100644 --- a/osu.Game/Database/RealmArchiveModelManager.cs +++ b/osu.Game/Database/RealmArchiveModelManager.cs @@ -18,7 +18,7 @@ namespace osu.Game.Database public class ModelManager : IModelManager, IModelFileManager where TModel : RealmObject, IHasRealmFiles, IHasGuidPrimaryKey, ISoftDelete { - protected RealmAccess Realm; + protected RealmAccess Realm { get; } private readonly RealmFileStore realmFileStore; diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index da77b0bc6c..2b13b5cf4e 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -24,7 +24,6 @@ namespace osu.Game.Scoring { public class ScoreManager : ModelManager, IModelImporter { - private readonly RealmAccess realm; private readonly Scheduler scheduler; private readonly Func difficulties; private readonly OsuConfigManager configManager; @@ -34,7 +33,6 @@ namespace osu.Game.Scoring Func difficulties = null, OsuConfigManager configManager = null) : base(storage, realm) { - this.realm = realm; this.scheduler = scheduler; this.difficulties = difficulties; this.configManager = configManager; @@ -51,7 +49,7 @@ namespace osu.Game.Scoring /// The first result for the provided query, or null if no results were found. public ScoreInfo Query(Expression> query) { - return realm.Run(r => r.All().FirstOrDefault(query)?.Detach()); + return Realm.Run(r => r.All().FirstOrDefault(query)?.Detach()); } /// @@ -230,7 +228,7 @@ namespace osu.Game.Scoring public void Delete([CanBeNull] Expression> filter = null, bool silent = false) { - realm.Run(r => + Realm.Run(r => { var items = r.All() .Where(s => !s.DeletePending); @@ -244,7 +242,7 @@ namespace osu.Game.Scoring public void Delete(BeatmapInfo beatmap, bool silent = false) { - realm.Run(r => + Realm.Run(r => { var beatmapScores = r.Find(beatmap.ID).Scores.ToList(); Delete(beatmapScores, silent); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 491de0c152..33af46bc1c 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -54,7 +54,6 @@ namespace osu.Game.Skinning }; private readonly SkinImporter skinImporter; - private readonly RealmAccess realm; private readonly IResourceStore userFiles; @@ -71,7 +70,6 @@ namespace osu.Game.Skinning public SkinManager(Storage storage, RealmAccess realm, GameHost host, IResourceStore resources, AudioManager audio, Scheduler scheduler) : base(storage, realm) { - this.realm = realm; this.audio = audio; this.scheduler = scheduler; this.host = host; @@ -114,7 +112,7 @@ namespace osu.Game.Skinning public void SelectRandomSkin() { - realm.Run(r => + Realm.Run(r => { // choose from only user skins, removing the current selection to ensure a new one is chosen. var randomChoices = r.All().Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID).ToArray(); @@ -127,7 +125,7 @@ namespace osu.Game.Skinning var chosen = randomChoices.ElementAt(RNG.Next(0, randomChoices.Length)); - CurrentSkinInfo.Value = chosen.ToLive(realm); + CurrentSkinInfo.Value = chosen.ToLive(Realm); }); } @@ -152,7 +150,7 @@ namespace osu.Game.Skinning if (!s.Protected) return false; - string[] existingSkinNames = realm.Run(r => r.All() + string[] existingSkinNames = Realm.Run(r => r.All() .Where(skin => !skin.DeletePending) .AsEnumerable() .Select(skin => skin.Name).ToArray()); @@ -195,7 +193,7 @@ namespace osu.Game.Skinning /// The first result for the provided query, or null if no results were found. public Live Query(Expression> query) { - return realm.Run(r => r.All().FirstOrDefault(query)?.ToLive(realm)); + return Realm.Run(r => r.All().FirstOrDefault(query)?.ToLive(Realm)); } public event Action SourceChanged; @@ -250,7 +248,7 @@ namespace osu.Game.Skinning AudioManager IStorageResourceProvider.AudioManager => audio; IResourceStore IStorageResourceProvider.Resources => resources; IResourceStore IStorageResourceProvider.Files => userFiles; - RealmAccess IStorageResourceProvider.RealmAccess => realm; + RealmAccess IStorageResourceProvider.RealmAccess => Realm; IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); #endregion @@ -279,7 +277,7 @@ namespace osu.Game.Skinning public void Delete([CanBeNull] Expression> filter = null, bool silent = false) { - realm.Run(r => + Realm.Run(r => { var items = r.All() .Where(s => !s.Protected && !s.DeletePending); From ce3d3a967c6e5a13e34578c8c122a7a81ef5a357 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Jun 2022 19:05:25 +0900 Subject: [PATCH 3/6] Reimplement missing methods --- osu.Game/Beatmaps/BeatmapManager.cs | 10 +++++++--- osu.Game/Database/RealmArchiveModelManager.cs | 5 +++-- osu.Game/Scoring/ScoreManager.cs | 5 ++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 33e8cea380..778829cba8 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -359,7 +359,7 @@ namespace osu.Game.Beatmaps var notification = new ProgressNotification { Progress = 0, - Text = $"Preparing to delete all {beatmapImporter.HumanisedModelName} videos...", + Text = $"Preparing to delete all {HumanisedModelName} videos...", CompletionText = "No videos found to delete!", State = ProgressNotificationState.Active, }; @@ -382,10 +382,10 @@ namespace osu.Game.Beatmaps { DeleteFile(b, video); deleted++; - notification.CompletionText = $"Deleted {deleted} {beatmapImporter.HumanisedModelName} video(s)!"; + notification.CompletionText = $"Deleted {deleted} {HumanisedModelName} video(s)!"; } - notification.Text = $"Deleting videos from {beatmapImporter.HumanisedModelName}s ({deleted} deleted)"; + notification.Text = $"Deleting videos from {HumanisedModelName}s ({deleted} deleted)"; notification.Progress = (float)++i / items.Count; } @@ -451,6 +451,8 @@ namespace osu.Game.Beatmaps void IWorkingBeatmapCache.Invalidate(BeatmapSetInfo beatmapSetInfo) => workingBeatmapCache.Invalidate(beatmapSetInfo); void IWorkingBeatmapCache.Invalidate(BeatmapInfo beatmapInfo) => workingBeatmapCache.Invalidate(beatmapInfo); + public override bool IsAvailableLocally(BeatmapSetInfo model) => Realm.Run(realm => realm.All().Any(s => s.OnlineID == model.OnlineID)); + #endregion #region Implementation of IDisposable @@ -470,5 +472,7 @@ namespace osu.Game.Beatmaps } #endregion + + public override string HumanisedModelName => "beatmap"; } } diff --git a/osu.Game/Database/RealmArchiveModelManager.cs b/osu.Game/Database/RealmArchiveModelManager.cs index bf4a8ca969..795647e94c 100644 --- a/osu.Game/Database/RealmArchiveModelManager.cs +++ b/osu.Game/Database/RealmArchiveModelManager.cs @@ -199,9 +199,10 @@ namespace osu.Game.Database }); } - // TODO: implement public virtual bool IsAvailableLocally(TModel model) => true; + public Action? PostNotification { get; set; } - public string HumanisedModelName { get; set; } = "wang"; + + public virtual string HumanisedModelName => $"{typeof(TModel).Name.Replace(@"Info", "").ToLower()}"; } } diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 2b13b5cf4e..9b5eab96e8 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -253,11 +253,14 @@ namespace osu.Game.Scoring public Task Import(params ImportTask[] tasks) => scoreImporter.Import(tasks); + public override bool IsAvailableLocally(ScoreInfo model) => Realm.Run(realm => realm.All().Any(s => s.OnlineID == model.OnlineID)); + public IEnumerable HandledExtensions => scoreImporter.HandledExtensions; public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => scoreImporter.Import(notification, tasks); - public Live Import(ScoreInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) => scoreImporter.Import(item, archive, batchImport, cancellationToken); + public Live Import(ScoreInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) => + scoreImporter.Import(item, archive, batchImport, cancellationToken); #region Implementation of IPresentImports From 3860f0b3e5b8e3105501cd89dfddaa6da874334b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Jun 2022 19:08:59 +0900 Subject: [PATCH 4/6] Remove unused `GetWorkingBetamap` method --- osu.Game/Beatmaps/BeatmapManager.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 778829cba8..583594b152 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -439,15 +439,6 @@ namespace osu.Game.Beatmaps return workingBeatmapCache.GetWorkingBeatmap(importedBeatmap); } - public WorkingBeatmap GetWorkingBeatmap(Live? importedBeatmap) - { - WorkingBeatmap working = workingBeatmapCache.GetWorkingBeatmap(null); - - importedBeatmap?.PerformRead(b => working = workingBeatmapCache.GetWorkingBeatmap(b)); - - return working; - } - void IWorkingBeatmapCache.Invalidate(BeatmapSetInfo beatmapSetInfo) => workingBeatmapCache.Invalidate(beatmapSetInfo); void IWorkingBeatmapCache.Invalidate(BeatmapInfo beatmapInfo) => workingBeatmapCache.Invalidate(beatmapInfo); From 448eee051ad5e727c4c2436c116e3fa61eb62860 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Jun 2022 19:41:14 +0900 Subject: [PATCH 5/6] Update filename to match new class name --- .../Database/{RealmArchiveModelManager.cs => ModelManager.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game/Database/{RealmArchiveModelManager.cs => ModelManager.cs} (100%) diff --git a/osu.Game/Database/RealmArchiveModelManager.cs b/osu.Game/Database/ModelManager.cs similarity index 100% rename from osu.Game/Database/RealmArchiveModelManager.cs rename to osu.Game/Database/ModelManager.cs From e66ccfd980e55027a3cd8ae40cd9689babddf401 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Jun 2022 19:48:18 +0900 Subject: [PATCH 6/6] Add back missing notification flow --- osu.Game/Beatmaps/BeatmapManager.cs | 2 ++ osu.Game/Scoring/ScoreManager.cs | 5 ++++- osu.Game/Skinning/SkinManager.cs | 5 ++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 583594b152..fcc78bc34d 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -62,6 +62,8 @@ namespace osu.Game.Beatmaps BeatmapTrackStore = audioManager.GetTrackStore(userResources); beatmapImporter = CreateBeatmapImporter(storage, realm, rulesets, onlineBeatmapLookupQueue); + beatmapImporter.PostNotification = obj => PostNotification?.Invoke(obj); + workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host); } diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 9b5eab96e8..4627ca414a 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -37,7 +37,10 @@ namespace osu.Game.Scoring this.difficulties = difficulties; this.configManager = configManager; - scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm); + scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm) + { + PostNotification = obj => PostNotification?.Invoke(obj) + }; } public Score GetScore(ScoreInfo score) => scoreImporter.GetScore(score); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 33af46bc1c..813ed3e066 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -77,7 +77,10 @@ namespace osu.Game.Skinning userFiles = new StorageBackedResourceStore(storage.GetStorageForDirectory("files")); - skinImporter = new SkinImporter(storage, realm, this); + skinImporter = new SkinImporter(storage, realm, this) + { + PostNotification = obj => PostNotification?.Invoke(obj), + }; var defaultSkins = new[] {