diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f0533f27be..623a657cd0 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -62,6 +62,7 @@ namespace osu.Game.Beatmaps BeatmapTrackStore = audioManager.GetTrackStore(userResources); beatmapImporter = CreateBeatmapImporter(storage, realm); + beatmapImporter.PauseImports.BindTo(PauseImports); beatmapImporter.ProcessBeatmap = args => ProcessBeatmap?.Invoke(args); beatmapImporter.PostNotification = obj => PostNotification?.Invoke(obj); @@ -458,7 +459,8 @@ namespace osu.Game.Beatmaps public Task Import(ImportTask[] tasks, ImportParameters parameters = default) => beatmapImporter.Import(tasks, parameters); - public Task>> Import(ProgressNotification notification, ImportTask[] tasks, ImportParameters parameters = default) => beatmapImporter.Import(notification, tasks, parameters); + public Task>> Import(ProgressNotification notification, ImportTask[] tasks, ImportParameters parameters = default) => + beatmapImporter.Import(notification, tasks, parameters); public Task?> Import(ImportTask task, ImportParameters parameters = default, CancellationToken cancellationToken = default) => beatmapImporter.Import(task, parameters, cancellationToken); diff --git a/osu.Game/Database/ModelManager.cs b/osu.Game/Database/ModelManager.cs index 5c106aa493..9a88bd5646 100644 --- a/osu.Game/Database/ModelManager.cs +++ b/osu.Game/Database/ModelManager.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using osu.Framework.Bindables; using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Extensions; @@ -18,6 +19,11 @@ namespace osu.Game.Database public class ModelManager : IModelManager, IModelFileManager where TModel : RealmObject, IHasRealmFiles, IHasGuidPrimaryKey, ISoftDelete { + /// + /// Temporarily pause imports to avoid performance overheads affecting gameplay scenarios. + /// + public readonly BindableBool PauseImports = new BindableBool(); + protected RealmAccess Realm { get; } private readonly RealmFileStore realmFileStore; diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index 4e8b27e0b4..cd86a5a94c 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Humanizer; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Logging; @@ -56,6 +57,11 @@ namespace osu.Game.Database /// private static readonly ThreadedTaskScheduler import_scheduler_batch = new ThreadedTaskScheduler(import_queue_request_concurrency, nameof(RealmArchiveModelImporter)); + /// + /// Temporarily pause imports to avoid performance overheads affecting gameplay scenarios. + /// + public readonly BindableBool PauseImports = new BindableBool(); + public abstract IEnumerable HandledExtensions { get; } protected readonly RealmFileStore Files; @@ -253,7 +259,7 @@ namespace osu.Game.Database /// An optional cancellation token. public virtual Live? ImportModel(TModel item, ArchiveReader? archive = null, ImportParameters parameters = default, CancellationToken cancellationToken = default) => Realm.Run(realm => { - cancellationToken.ThrowIfCancellationRequested(); + pauseIfNecessary(cancellationToken); TModel? existing; @@ -551,6 +557,22 @@ namespace osu.Game.Database /// Whether to perform deletion. protected virtual bool ShouldDeleteArchive(string path) => false; + private void pauseIfNecessary(CancellationToken cancellationToken) + { + if (!PauseImports.Value) + return; + + Logger.Log(@"Import is being paused."); + + while (PauseImports.Value) + { + cancellationToken.ThrowIfCancellationRequested(); + Thread.Sleep(500); + } + + Logger.Log(@"Import is being resumed."); + } + private IEnumerable getIDs(IEnumerable files) { foreach (var f in files.OrderBy(f => f.Filename)) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 6efa3c4172..27152743f8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -307,6 +307,10 @@ namespace osu.Game // Transfer any runtime changes back to configuration file. SkinManager.CurrentSkinInfo.ValueChanged += skin => configSkin.Value = skin.NewValue.ID.ToString(); + BeatmapManager.PauseImports.BindTo(LocalUserPlaying); + SkinManager.PauseImports.BindTo(LocalUserPlaying); + ScoreManager.PauseImports.BindTo(LocalUserPlaying); + IsActive.BindValueChanged(active => updateActiveState(active.NewValue), true); Audio.AddAdjustment(AdjustableProperty.Volume, inactiveVolumeFade); diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 5ec96a951b..0852ab43f4 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -38,6 +38,8 @@ namespace osu.Game.Scoring { PostNotification = obj => PostNotification?.Invoke(obj) }; + + scoreImporter.PauseImports.BindTo(PauseImports); } public Score GetScore(ScoreInfo score) => scoreImporter.GetScore(score); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index f750bfad8a..a0e7037d6d 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -79,6 +79,8 @@ namespace osu.Game.Skinning PostNotification = obj => PostNotification?.Invoke(obj), }; + skinImporter.PauseImports.BindTo(PauseImports); + var defaultSkins = new[] { DefaultClassicSkin = new DefaultLegacySkin(this),