diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index edb8563c65..a3678602d1 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; using Humanizer; using osu.Framework.Logging; @@ -107,7 +108,15 @@ namespace osu.Game.Database notification.State = ProgressNotificationState.Cancelled; if (!(error is OperationCanceledException)) - Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!"); + { + if (error is WebException webException && webException.Message == @"TooManyRequests") + { + notification.Close(); + PostNotification?.Invoke(new TooManyDownloadsNotification()); + } + else + Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!"); + } } } diff --git a/osu.Game/Database/TooManyDownloadsNotification.cs b/osu.Game/Database/TooManyDownloadsNotification.cs new file mode 100644 index 0000000000..aa88fed43c --- /dev/null +++ b/osu.Game/Database/TooManyDownloadsNotification.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Overlays.Notifications; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Database +{ + public class TooManyDownloadsNotification : SimpleNotification + { + public TooManyDownloadsNotification() + { + Text = BeatmapsetsStrings.DownloadLimitExceeded; + Icon = FontAwesome.Solid.ExclamationCircle; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + IconBackground.Colour = colours.RedDark; + } + } +} diff --git a/osu.Game/IO/MigratableStorage.cs b/osu.Game/IO/MigratableStorage.cs index 7cd409c04c..14a3c5a43c 100644 --- a/osu.Game/IO/MigratableStorage.cs +++ b/osu.Game/IO/MigratableStorage.cs @@ -26,6 +26,11 @@ namespace osu.Game.IO /// public virtual string[] IgnoreFiles => Array.Empty(); + /// + /// A list of file/directory suffixes which should not be migrated. + /// + public virtual string[] IgnoreSuffixes => Array.Empty(); + protected MigratableStorage(Storage storage, string subPath = null) : base(storage, subPath) { @@ -73,6 +78,9 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreFiles.Contains(fi.Name)) continue; + if (IgnoreSuffixes.Any(suffix => fi.Name.EndsWith(suffix, StringComparison.Ordinal))) + continue; + allFilesDeleted &= AttemptOperation(() => fi.Delete(), throwOnFailure: false); } @@ -81,6 +89,9 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name)) continue; + if (IgnoreSuffixes.Any(suffix => dir.Name.EndsWith(suffix, StringComparison.Ordinal))) + continue; + allFilesDeleted &= AttemptOperation(() => dir.Delete(true), throwOnFailure: false); } @@ -101,6 +112,9 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreFiles.Contains(fileInfo.Name)) continue; + if (IgnoreSuffixes.Any(suffix => fileInfo.Name.EndsWith(suffix, StringComparison.Ordinal))) + continue; + AttemptOperation(() => { fileInfo.Refresh(); @@ -119,6 +133,9 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name)) continue; + if (IgnoreSuffixes.Any(suffix => dir.Name.EndsWith(suffix, StringComparison.Ordinal))) + continue; + CopyRecursive(dir, destination.CreateSubdirectory(dir.Name), false); } } diff --git a/osu.Game/IO/OsuStorage.cs b/osu.Game/IO/OsuStorage.cs index 368ac56850..f4c55e4b0e 100644 --- a/osu.Game/IO/OsuStorage.cs +++ b/osu.Game/IO/OsuStorage.cs @@ -38,15 +38,20 @@ namespace osu.Game.IO public override string[] IgnoreDirectories => new[] { "cache", - $"{OsuGameBase.CLIENT_DATABASE_FILENAME}.management", }; public override string[] IgnoreFiles => new[] { "framework.ini", "storage.ini", - $"{OsuGameBase.CLIENT_DATABASE_FILENAME}.note", - $"{OsuGameBase.CLIENT_DATABASE_FILENAME}.lock", + }; + + public override string[] IgnoreSuffixes => new[] + { + // Realm pipe files don't play well with copy operations + ".note", + ".lock", + ".management", }; public OsuStorage(GameHost host, Storage defaultStorage) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 1ee562e122..1ffcdc0db2 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using osu.Framework.Localisation; diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 96a6c56860..659984682e 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -40,8 +40,6 @@ namespace osu.Game.Screens.Play.HUD public override bool HandleNonPositionalInput => AllowSeeking.Value; public override bool HandlePositionalInput => AllowSeeking.Value; - protected override bool BlockScrollInput => false; - [Resolved] private Player? player { get; set; } diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 702d2f7c6f..09afd7a9d3 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -14,6 +14,12 @@ namespace osu.Game.Screens.Play.HUD { public abstract class SongProgress : OverlayContainer, ISkinnableDrawable { + // Some implementations of this element allow seeking during gameplay playback. + // Set a sane default of never handling input to override the behaviour provided by OverlayContainer. + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; + protected override bool BlockScrollInput => false; + public bool UsesFixedAnchor { get; set; } [Resolved]