From 6cab7b877dc40883e860ad4e7f10c7e8c5fa68e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 15:36:12 +0900 Subject: [PATCH 01/46] Move stable import handling into its own class --- osu.Game/Beatmaps/BeatmapManager.cs | 5 -- osu.Game/Beatmaps/BeatmapModelManager.cs | 4 -- osu.Game/Database/ArchiveModelManager.cs | 34 ------------ osu.Game/Database/IModelManager.cs | 7 --- osu.Game/Database/StableBeatmapImporter.cs | 18 +++++++ osu.Game/Database/StableImportManager.cs | 10 ++-- osu.Game/Database/StableImporter.cs | 60 ++++++++++++++++++++++ osu.Game/Database/StableScoreImporter.cs | 23 +++++++++ osu.Game/Database/StableSkinImporter.cs | 14 +++++ osu.Game/Scoring/ScoreManager.cs | 6 --- osu.Game/Scoring/ScoreModelManager.cs | 6 --- osu.Game/Skinning/SkinManager.cs | 5 -- osu.Game/Skinning/SkinModelManager.cs | 2 - 13 files changed, 122 insertions(+), 72 deletions(-) create mode 100644 osu.Game/Database/StableBeatmapImporter.cs create mode 100644 osu.Game/Database/StableImporter.cs create mode 100644 osu.Game/Database/StableScoreImporter.cs create mode 100644 osu.Game/Database/StableSkinImporter.cs diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 0594cd1316..2cca3ceaeb 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -225,11 +225,6 @@ namespace osu.Game.Beatmaps remove => beatmapModelManager.ItemRemoved -= value; } - public Task ImportFromStableAsync(StableStorage stableStorage) - { - return beatmapModelManager.ImportFromStableAsync(stableStorage); - } - public void Export(BeatmapSetInfo item) { beatmapModelManager.Export(item); diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index ae395c6da6..63cdd0b852 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -58,10 +58,6 @@ namespace osu.Game.Beatmaps protected override string[] HashableFileTypes => new[] { ".osu" }; - protected override string ImportFromStablePath => "."; - - protected override Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage.GetSongStorage(); - private readonly BeatmapStore beatmaps; private readonly RulesetStore rulesets; diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index adbb71c8da..e5919cb5c4 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -728,17 +728,6 @@ namespace osu.Game.Database #region osu-stable import - /// - /// The relative path from osu-stable's data directory to import items from. - /// - protected virtual string ImportFromStablePath => null; - - /// - /// Select paths to import from stable where all paths should be absolute. Default implementation iterates all directories in . - /// - protected virtual IEnumerable GetStableImportPaths(Storage storage) => storage.GetDirectories(ImportFromStablePath) - .Select(path => storage.GetFullPath(path)); - /// /// Whether this specified path should be removed after successful import. /// @@ -746,29 +735,6 @@ namespace osu.Game.Database /// Whether to perform deletion. protected virtual bool ShouldDeleteArchive(string path) => false; - public Task ImportFromStableAsync(StableStorage stableStorage) - { - var storage = PrepareStableStorage(stableStorage); - - // Handle situations like when the user does not have a Skins folder. - if (!storage.ExistsDirectory(ImportFromStablePath)) - { - string fullPath = storage.GetFullPath(ImportFromStablePath); - - Logger.Log(@$"Folder ""{fullPath}"" not available in the target osu!stable installation to import {HumanisedModelName}s.", LoggingTarget.Information, LogLevel.Error); - return Task.CompletedTask; - } - - return Task.Run(async () => await Import(GetStableImportPaths(storage).ToArray()).ConfigureAwait(false)); - } - - /// - /// 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/Database/IModelManager.cs b/osu.Game/Database/IModelManager.cs index 15ad455f21..6c9cca7c7a 100644 --- a/osu.Game/Database/IModelManager.cs +++ b/osu.Game/Database/IModelManager.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Threading.Tasks; -using osu.Game.IO; namespace osu.Game.Database { @@ -26,11 +24,6 @@ namespace osu.Game.Database /// event Action ItemRemoved; - /// - /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. - /// - Task ImportFromStableAsync(StableStorage stableStorage); - /// /// Exports an item to a legacy (.zip based) package. /// diff --git a/osu.Game/Database/StableBeatmapImporter.cs b/osu.Game/Database/StableBeatmapImporter.cs new file mode 100644 index 0000000000..7aaa8ba013 --- /dev/null +++ b/osu.Game/Database/StableBeatmapImporter.cs @@ -0,0 +1,18 @@ +using osu.Framework.Platform; +using osu.Game.Beatmaps; +using osu.Game.IO; + +namespace osu.Game.Database +{ + public class StableBeatmapImporter : StableImporter + { + protected override string ImportFromStablePath => "."; + + protected override Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage.GetSongStorage(); + + public StableBeatmapImporter(IModelImporter importer) + : base(importer) + { + } + } +} \ No newline at end of file diff --git a/osu.Game/Database/StableImportManager.cs b/osu.Game/Database/StableImportManager.cs index fe8c14c085..0a30fcb2be 100644 --- a/osu.Game/Database/StableImportManager.cs +++ b/osu.Game/Database/StableImportManager.cs @@ -51,18 +51,22 @@ namespace osu.Game.Database var stableStorage = await getStableStorage().ConfigureAwait(false); var importTasks = new List(); + var beatmapImporter = new StableBeatmapImporter(beatmaps); + var skinImporter = new StableSkinImporter(skins); + var scoreImporter = new StableScoreImporter(scores); + Task beatmapImportTask = Task.CompletedTask; if (content.HasFlagFast(StableContent.Beatmaps)) - importTasks.Add(beatmapImportTask = beatmaps.ImportFromStableAsync(stableStorage)); + importTasks.Add(beatmapImportTask = beatmapImporter.ImportFromStableAsync(stableStorage)); if (content.HasFlagFast(StableContent.Skins)) - importTasks.Add(skins.ImportFromStableAsync(stableStorage)); + importTasks.Add(skinImporter.ImportFromStableAsync(stableStorage)); if (content.HasFlagFast(StableContent.Collections)) importTasks.Add(beatmapImportTask.ContinueWith(_ => collections.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion)); if (content.HasFlagFast(StableContent.Scores)) - importTasks.Add(beatmapImportTask.ContinueWith(_ => scores.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion)); + importTasks.Add(beatmapImportTask.ContinueWith(_ => scoreImporter.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion)); await Task.WhenAll(importTasks.ToArray()).ConfigureAwait(false); } diff --git a/osu.Game/Database/StableImporter.cs b/osu.Game/Database/StableImporter.cs new file mode 100644 index 0000000000..e56737959e --- /dev/null +++ b/osu.Game/Database/StableImporter.cs @@ -0,0 +1,60 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using osu.Framework.Logging; +using osu.Framework.Platform; +using osu.Game.IO; + +namespace osu.Game.Database +{ + /// + /// A class which handled importing various user data from osu-stable. + /// + public class StableImporter + where TModel : class + { + /// + /// The relative path from osu-stable's data directory to import items from. + /// + protected virtual string ImportFromStablePath => null; + + /// + /// Select paths to import from stable where all paths should be absolute. Default implementation iterates all directories in . + /// + protected virtual IEnumerable GetStableImportPaths(Storage storage) => storage.GetDirectories(ImportFromStablePath) + .Select(path => storage.GetFullPath(path)); + + protected readonly IModelImporter Importer; + + public StableImporter(IModelImporter importer) + { + Importer = importer; + } + + public Task ImportFromStableAsync(StableStorage stableStorage) + { + var storage = PrepareStableStorage(stableStorage); + + // Handle situations like when the user does not have a Skins folder. + if (!storage.ExistsDirectory(ImportFromStablePath)) + { + string fullPath = storage.GetFullPath(ImportFromStablePath); + + Logger.Log(@$"Folder ""{fullPath}"" not available in the target osu!stable installation to import {Importer.HumanisedModelName}s.", LoggingTarget.Information, LogLevel.Error); + return Task.CompletedTask; + } + + return Task.Run(async () => await Importer.Import(GetStableImportPaths(storage).ToArray()).ConfigureAwait(false)); + } + + /// + /// 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; + } +} diff --git a/osu.Game/Database/StableScoreImporter.cs b/osu.Game/Database/StableScoreImporter.cs new file mode 100644 index 0000000000..fede10c7ea --- /dev/null +++ b/osu.Game/Database/StableScoreImporter.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using osu.Framework.Platform; +using osu.Game.Scoring; + +namespace osu.Game.Database +{ + public class StableScoreImporter : StableImporter + { + protected override string ImportFromStablePath => Path.Combine("Data", "r"); + + protected override IEnumerable GetStableImportPaths(Storage storage) + => storage.GetFiles(ImportFromStablePath).Where(p => Importer.HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false)) + .Select(path => storage.GetFullPath(path)); + + public StableScoreImporter(IModelImporter importer) + : base(importer) + { + } + } +} diff --git a/osu.Game/Database/StableSkinImporter.cs b/osu.Game/Database/StableSkinImporter.cs new file mode 100644 index 0000000000..65601e85b7 --- /dev/null +++ b/osu.Game/Database/StableSkinImporter.cs @@ -0,0 +1,14 @@ +using osu.Game.Skinning; + +namespace osu.Game.Database +{ + public class StableSkinImporter : StableImporter + { + protected override string ImportFromStablePath => "Skins"; + + public StableSkinImporter(IModelImporter importer) + : base(importer) + { + } + } +} \ No newline at end of file diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 29144e7bdc..d25671d77e 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -15,7 +15,6 @@ using osu.Framework.Threading; 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.Overlays.Notifications; @@ -263,11 +262,6 @@ namespace osu.Game.Scoring remove => scoreModelManager.ItemRemoved -= value; } - public Task ImportFromStableAsync(StableStorage stableStorage) - { - return scoreModelManager.ImportFromStableAsync(stableStorage); - } - public void Export(ScoreInfo item) { scoreModelManager.Export(item); diff --git a/osu.Game/Scoring/ScoreModelManager.cs b/osu.Game/Scoring/ScoreModelManager.cs index c194a7166d..9da739237b 100644 --- a/osu.Game/Scoring/ScoreModelManager.cs +++ b/osu.Game/Scoring/ScoreModelManager.cs @@ -26,8 +26,6 @@ namespace osu.Game.Scoring protected override string[] HashableFileTypes => new[] { ".osr" }; - protected override string ImportFromStablePath => Path.Combine("Data", "r"); - private readonly RulesetStore rulesets; private readonly Func beatmaps; @@ -81,9 +79,5 @@ namespace osu.Game.Scoring using (var inputStream = Files.Storage.GetStream(file.FileInfo.GetStoragePath())) inputStream.CopyTo(outputStream); } - - 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)); } } diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index a840e17ed1..679b35799e 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -301,11 +301,6 @@ namespace osu.Game.Skinning remove => skinModelManager.ItemRemoved -= value; } - public Task ImportFromStableAsync(StableStorage stableStorage) - { - return skinModelManager.ImportFromStableAsync(stableStorage); - } - public void Export(SkinInfo item) { skinModelManager.Export(item); diff --git a/osu.Game/Skinning/SkinModelManager.cs b/osu.Game/Skinning/SkinModelManager.cs index f28b0c066b..572ae5cbfc 100644 --- a/osu.Game/Skinning/SkinModelManager.cs +++ b/osu.Game/Skinning/SkinModelManager.cs @@ -34,8 +34,6 @@ namespace osu.Game.Skinning protected override string[] HashableFileTypes => new[] { ".ini", ".json" }; - protected override string ImportFromStablePath => "Skins"; - protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == @".osk"; protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name ?? @"No name" }; From 9dcb20a8217ff9dfe62487c8d578a7e42ab8ab35 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 15:39:05 +0900 Subject: [PATCH 02/46] Rename `Stable` to `Legacy` and add xmldoc --- ...ImportManager.cs => LeagcyImportManager.cs} | 11 +++++++---- ...mapImporter.cs => LegacyBeatmapImporter.cs} | 6 +++--- .../{StableImporter.cs => LegacyImporter.cs} | 6 +++--- ...ScoreImporter.cs => LegacyScoreImporter.cs} | 4 ++-- ...leSkinImporter.cs => LegacySkinImporter.cs} | 4 ++-- osu.Game/OsuGame.cs | 4 ++-- .../Sections/Maintenance/GeneralSettings.cs | 18 +++++++++--------- osu.Game/Screens/Select/SongSelect.cs | 6 +++--- 8 files changed, 31 insertions(+), 28 deletions(-) rename osu.Game/Database/{StableImportManager.cs => LeagcyImportManager.cs} (90%) rename osu.Game/Database/{StableBeatmapImporter.cs => LegacyBeatmapImporter.cs} (74%) rename osu.Game/Database/{StableImporter.cs => LegacyImporter.cs} (92%) rename osu.Game/Database/{StableScoreImporter.cs => LegacyScoreImporter.cs} (83%) rename osu.Game/Database/{StableSkinImporter.cs => LegacySkinImporter.cs} (59%) diff --git a/osu.Game/Database/StableImportManager.cs b/osu.Game/Database/LeagcyImportManager.cs similarity index 90% rename from osu.Game/Database/StableImportManager.cs rename to osu.Game/Database/LeagcyImportManager.cs index 0a30fcb2be..9f3f9d007a 100644 --- a/osu.Game/Database/StableImportManager.cs +++ b/osu.Game/Database/LeagcyImportManager.cs @@ -19,7 +19,10 @@ using osu.Game.Skinning; namespace osu.Game.Database { - public class StableImportManager : Component + /// + /// Handles migration of legacy user data from osu-stable. + /// + public class LeagcyImportManager : Component { [Resolved] private SkinManager skins { get; set; } @@ -51,9 +54,9 @@ namespace osu.Game.Database var stableStorage = await getStableStorage().ConfigureAwait(false); var importTasks = new List(); - var beatmapImporter = new StableBeatmapImporter(beatmaps); - var skinImporter = new StableSkinImporter(skins); - var scoreImporter = new StableScoreImporter(scores); + var beatmapImporter = new LegacyBeatmapImporter(beatmaps); + var skinImporter = new LegacySkinImporter(skins); + var scoreImporter = new LegacyScoreImporter(scores); Task beatmapImportTask = Task.CompletedTask; if (content.HasFlagFast(StableContent.Beatmaps)) diff --git a/osu.Game/Database/StableBeatmapImporter.cs b/osu.Game/Database/LegacyBeatmapImporter.cs similarity index 74% rename from osu.Game/Database/StableBeatmapImporter.cs rename to osu.Game/Database/LegacyBeatmapImporter.cs index 7aaa8ba013..a377c39b90 100644 --- a/osu.Game/Database/StableBeatmapImporter.cs +++ b/osu.Game/Database/LegacyBeatmapImporter.cs @@ -4,15 +4,15 @@ using osu.Game.IO; namespace osu.Game.Database { - public class StableBeatmapImporter : StableImporter + public class LegacyBeatmapImporter : LegacyImporter { protected override string ImportFromStablePath => "."; protected override Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage.GetSongStorage(); - public StableBeatmapImporter(IModelImporter importer) + public LegacyBeatmapImporter(IModelImporter importer) : base(importer) { } } -} \ No newline at end of file +} diff --git a/osu.Game/Database/StableImporter.cs b/osu.Game/Database/LegacyImporter.cs similarity index 92% rename from osu.Game/Database/StableImporter.cs rename to osu.Game/Database/LegacyImporter.cs index e56737959e..4480aa9ee8 100644 --- a/osu.Game/Database/StableImporter.cs +++ b/osu.Game/Database/LegacyImporter.cs @@ -11,9 +11,9 @@ using osu.Game.IO; namespace osu.Game.Database { /// - /// A class which handled importing various user data from osu-stable. + /// A class which handles importing legacy user data of a single type from osu-stable. /// - public class StableImporter + public abstract class LegacyImporter where TModel : class { /// @@ -29,7 +29,7 @@ namespace osu.Game.Database protected readonly IModelImporter Importer; - public StableImporter(IModelImporter importer) + protected LegacyImporter(IModelImporter importer) { Importer = importer; } diff --git a/osu.Game/Database/StableScoreImporter.cs b/osu.Game/Database/LegacyScoreImporter.cs similarity index 83% rename from osu.Game/Database/StableScoreImporter.cs rename to osu.Game/Database/LegacyScoreImporter.cs index fede10c7ea..4cc2be60e6 100644 --- a/osu.Game/Database/StableScoreImporter.cs +++ b/osu.Game/Database/LegacyScoreImporter.cs @@ -7,7 +7,7 @@ using osu.Game.Scoring; namespace osu.Game.Database { - public class StableScoreImporter : StableImporter + public class LegacyScoreImporter : LegacyImporter { protected override string ImportFromStablePath => Path.Combine("Data", "r"); @@ -15,7 +15,7 @@ namespace osu.Game.Database => storage.GetFiles(ImportFromStablePath).Where(p => Importer.HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false)) .Select(path => storage.GetFullPath(path)); - public StableScoreImporter(IModelImporter importer) + public LegacyScoreImporter(IModelImporter importer) : base(importer) { } diff --git a/osu.Game/Database/StableSkinImporter.cs b/osu.Game/Database/LegacySkinImporter.cs similarity index 59% rename from osu.Game/Database/StableSkinImporter.cs rename to osu.Game/Database/LegacySkinImporter.cs index 65601e85b7..357da1b005 100644 --- a/osu.Game/Database/StableSkinImporter.cs +++ b/osu.Game/Database/LegacySkinImporter.cs @@ -2,11 +2,11 @@ using osu.Game.Skinning; namespace osu.Game.Database { - public class StableSkinImporter : StableImporter + public class LegacySkinImporter : LegacyImporter { protected override string ImportFromStablePath => "Skins"; - public StableSkinImporter(IModelImporter importer) + public LegacySkinImporter(IModelImporter importer) : base(importer) { } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 574a5e5393..9b9ec585e8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -116,7 +116,7 @@ namespace osu.Game private readonly DifficultyRecommender difficultyRecommender = new DifficultyRecommender(); [Cached] - private readonly StableImportManager stableImportManager = new StableImportManager(); + private readonly LeagcyImportManager leagcyImportManager = new LeagcyImportManager(); [Cached] private readonly ScreenshotManager screenshotManager = new ScreenshotManager(); @@ -782,7 +782,7 @@ namespace osu.Game PostNotification = n => Notifications.Post(n), }, Add, true); - loadComponentSingleFile(stableImportManager, Add); + loadComponentSingleFile(leagcyImportManager, Add); loadComponentSingleFile(screenshotManager, Add); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 43df58a8b1..9dfd0d8ff4 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -31,9 +31,9 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private SettingsButton undeleteButton; [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] StableImportManager stableImportManager, DialogOverlay dialogOverlay) + private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LeagcyImportManager leagcyImportManager, DialogOverlay dialogOverlay) { - if (stableImportManager?.SupportsImportFromStable == true) + if (leagcyImportManager?.SupportsImportFromStable == true) { Add(importBeatmapsButton = new SettingsButton { @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importBeatmapsButton.Enabled.Value = false; - stableImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); + leagcyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); } }); } @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance } }); - if (stableImportManager?.SupportsImportFromStable == true) + if (leagcyImportManager?.SupportsImportFromStable == true) { Add(importScoresButton = new SettingsButton { @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importScoresButton.Enabled.Value = false; - stableImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); + leagcyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); } }); } @@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance } }); - if (stableImportManager?.SupportsImportFromStable == true) + if (leagcyImportManager?.SupportsImportFromStable == true) { Add(importSkinsButton = new SettingsButton { @@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importSkinsButton.Enabled.Value = false; - stableImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true)); + leagcyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true)); } }); } @@ -113,7 +113,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance if (collectionManager != null) { - if (stableImportManager?.SupportsImportFromStable == true) + if (leagcyImportManager?.SupportsImportFromStable == true) { Add(importCollectionsButton = new SettingsButton { @@ -121,7 +121,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importCollectionsButton.Enabled.Value = false; - stableImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); + leagcyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); } }); } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 2c36bf5fc8..b6933a9830 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Select protected virtual bool ShowFooter => true; - protected virtual bool DisplayStableImportPrompt => stableImportManager?.SupportsImportFromStable == true; + protected virtual bool DisplayStableImportPrompt => leagcyImportManager?.SupportsImportFromStable == true; public override bool? AllowTrackAdjustments => true; @@ -90,7 +90,7 @@ namespace osu.Game.Screens.Select private BeatmapManager beatmaps { get; set; } [Resolved(CanBeNull = true)] - private StableImportManager stableImportManager { get; set; } + private LeagcyImportManager leagcyImportManager { get; set; } protected ModSelectOverlay ModSelect { get; private set; } @@ -297,7 +297,7 @@ namespace osu.Game.Screens.Select { dialogOverlay.Push(new ImportFromStablePopup(() => { - Task.Run(() => stableImportManager.ImportFromStableAsync(StableContent.All)); + Task.Run(() => leagcyImportManager.ImportFromStableAsync(StableContent.All)); })); } }); From 2df793ca228e69032fcb0e8027ebd4bf4a138589 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 15:44:04 +0900 Subject: [PATCH 03/46] Inline individual importers to avoid unnecessary construction for singular import types --- osu.Game/Database/LeagcyImportManager.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Database/LeagcyImportManager.cs b/osu.Game/Database/LeagcyImportManager.cs index 9f3f9d007a..8ee63429e2 100644 --- a/osu.Game/Database/LeagcyImportManager.cs +++ b/osu.Game/Database/LeagcyImportManager.cs @@ -54,22 +54,18 @@ namespace osu.Game.Database var stableStorage = await getStableStorage().ConfigureAwait(false); var importTasks = new List(); - var beatmapImporter = new LegacyBeatmapImporter(beatmaps); - var skinImporter = new LegacySkinImporter(skins); - var scoreImporter = new LegacyScoreImporter(scores); - Task beatmapImportTask = Task.CompletedTask; if (content.HasFlagFast(StableContent.Beatmaps)) - importTasks.Add(beatmapImportTask = beatmapImporter.ImportFromStableAsync(stableStorage)); + importTasks.Add(beatmapImportTask = new LegacyBeatmapImporter(beatmaps).ImportFromStableAsync(stableStorage)); if (content.HasFlagFast(StableContent.Skins)) - importTasks.Add(skinImporter.ImportFromStableAsync(stableStorage)); + importTasks.Add(new LegacySkinImporter(skins).ImportFromStableAsync(stableStorage)); if (content.HasFlagFast(StableContent.Collections)) importTasks.Add(beatmapImportTask.ContinueWith(_ => collections.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion)); if (content.HasFlagFast(StableContent.Scores)) - importTasks.Add(beatmapImportTask.ContinueWith(_ => scoreImporter.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion)); + importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyScoreImporter(scores).ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion)); await Task.WhenAll(importTasks.ToArray()).ConfigureAwait(false); } From a0fa030f55385cb3f85d1a2d4c1d8e99e65cbb07 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 16:33:04 +0900 Subject: [PATCH 04/46] Rename base class to `LegacyModelImporter` --- osu.Game/Database/LegacyBeatmapImporter.cs | 2 +- .../Database/{LegacyImporter.cs => LegacyModelImporter.cs} | 4 ++-- osu.Game/Database/LegacyScoreImporter.cs | 2 +- osu.Game/Database/LegacySkinImporter.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename osu.Game/Database/{LegacyImporter.cs => LegacyModelImporter.cs} (95%) diff --git a/osu.Game/Database/LegacyBeatmapImporter.cs b/osu.Game/Database/LegacyBeatmapImporter.cs index a377c39b90..041a692655 100644 --- a/osu.Game/Database/LegacyBeatmapImporter.cs +++ b/osu.Game/Database/LegacyBeatmapImporter.cs @@ -4,7 +4,7 @@ using osu.Game.IO; namespace osu.Game.Database { - public class LegacyBeatmapImporter : LegacyImporter + public class LegacyBeatmapImporter : LegacyModelImporter { protected override string ImportFromStablePath => "."; diff --git a/osu.Game/Database/LegacyImporter.cs b/osu.Game/Database/LegacyModelImporter.cs similarity index 95% rename from osu.Game/Database/LegacyImporter.cs rename to osu.Game/Database/LegacyModelImporter.cs index 4480aa9ee8..dacb7327ea 100644 --- a/osu.Game/Database/LegacyImporter.cs +++ b/osu.Game/Database/LegacyModelImporter.cs @@ -13,7 +13,7 @@ namespace osu.Game.Database /// /// A class which handles importing legacy user data of a single type from osu-stable. /// - public abstract class LegacyImporter + public abstract class LegacyModelImporter where TModel : class { /// @@ -29,7 +29,7 @@ namespace osu.Game.Database protected readonly IModelImporter Importer; - protected LegacyImporter(IModelImporter importer) + protected LegacyModelImporter(IModelImporter importer) { Importer = importer; } diff --git a/osu.Game/Database/LegacyScoreImporter.cs b/osu.Game/Database/LegacyScoreImporter.cs index 4cc2be60e6..984aa8a1ac 100644 --- a/osu.Game/Database/LegacyScoreImporter.cs +++ b/osu.Game/Database/LegacyScoreImporter.cs @@ -7,7 +7,7 @@ using osu.Game.Scoring; namespace osu.Game.Database { - public class LegacyScoreImporter : LegacyImporter + public class LegacyScoreImporter : LegacyModelImporter { protected override string ImportFromStablePath => Path.Combine("Data", "r"); diff --git a/osu.Game/Database/LegacySkinImporter.cs b/osu.Game/Database/LegacySkinImporter.cs index 357da1b005..b102e26bc6 100644 --- a/osu.Game/Database/LegacySkinImporter.cs +++ b/osu.Game/Database/LegacySkinImporter.cs @@ -2,7 +2,7 @@ using osu.Game.Skinning; namespace osu.Game.Database { - public class LegacySkinImporter : LegacyImporter + public class LegacySkinImporter : LegacyModelImporter { protected override string ImportFromStablePath => "Skins"; From 416ee2447a02f60b29d39b19d65851628b139236 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 16:33:35 +0900 Subject: [PATCH 05/46] Move archive filename helper method to extension method --- osu.Game/Beatmaps/BeatmapModelManager.cs | 2 +- osu.Game/Extensions/ModelExtensions.cs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index 63cdd0b852..c91264c03a 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -212,7 +212,7 @@ namespace osu.Game.Beatmaps var fileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase)) ?? new BeatmapSetFileInfo(); // metadata may have changed; update the path with the standard format. - beatmapInfo.Path = GetValidFilename($"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.DifficultyName}].osu"); + beatmapInfo.Path = $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.DifficultyName}].osu".GetValidArchiveContentFilename(); beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); diff --git a/osu.Game/Extensions/ModelExtensions.cs b/osu.Game/Extensions/ModelExtensions.cs index 9f00d21383..2274da0fd4 100644 --- a/osu.Game/Extensions/ModelExtensions.cs +++ b/osu.Game/Extensions/ModelExtensions.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.IO; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.IO; @@ -124,5 +125,21 @@ namespace osu.Game.Extensions return instance.OnlineID.Equals(other.OnlineID); } + + private static readonly char[] invalid_filename_characters = Path.GetInvalidFileNameChars() + // Backslash is added to avoid issues when exporting to zip. + // See SharpCompress filename normalisation https://github.com/adamhathcock/sharpcompress/blob/a1e7c0068db814c9aa78d86a94ccd1c761af74bd/src/SharpCompress/Writers/Zip/ZipWriter.cs#L143. + .Append('\\') + .ToArray(); + + /// + /// Get a valid filename for use inside a zip file. Avoids backslashes being incorrectly converted to directories. + /// + public static string GetValidArchiveContentFilename(this string filename) + { + foreach (char c in invalid_filename_characters) + filename = filename.Replace(c, '_'); + return filename; + } } } From 7488ccd5fe4830469b9e8e1bc393ea1a0e0c7348 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 16:35:42 +0900 Subject: [PATCH 06/46] Update all models to implement `IHasNamedFiles` --- osu.Game/Beatmaps/BeatmapSetInfo.cs | 2 +- osu.Game/Beatmaps/IBeatmapSetInfo.cs | 7 +------ osu.Game/Database/IHasNamedFiles.cs | 15 +++++++++++++++ osu.Game/Models/RealmBeatmapSet.cs | 3 +-- .../API/Requests/Responses/APIBeatmapSet.cs | 2 +- .../Online/API/Requests/Responses/APIScoreInfo.cs | 2 ++ osu.Game/Scoring/IScoreInfo.cs | 2 +- osu.Game/Scoring/ScoreFileInfo.cs | 4 +++- osu.Game/Scoring/ScoreInfo.cs | 2 ++ osu.Game/Skinning/SkinFileInfo.cs | 4 +++- osu.Game/Skinning/SkinInfo.cs | 4 +++- 11 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 osu.Game/Database/IHasNamedFiles.cs diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index a4d60d7ea0..ac7067edda 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -95,7 +95,7 @@ namespace osu.Game.Beatmaps IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => Metadata ?? Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata(); IEnumerable IBeatmapSetInfo.Beatmaps => Beatmaps; - IEnumerable IBeatmapSetInfo.Files => Files; + IEnumerable IHasNamedFiles.Files => Files; #endregion } diff --git a/osu.Game/Beatmaps/IBeatmapSetInfo.cs b/osu.Game/Beatmaps/IBeatmapSetInfo.cs index aa114c8472..9755120457 100644 --- a/osu.Game/Beatmaps/IBeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/IBeatmapSetInfo.cs @@ -12,7 +12,7 @@ namespace osu.Game.Beatmaps /// /// A representation of a collection of beatmap difficulties, generally packaged as an ".osz" archive. /// - public interface IBeatmapSetInfo : IHasOnlineID, IEquatable + public interface IBeatmapSetInfo : IHasOnlineID, IEquatable, IHasNamedFiles { /// /// The date when this beatmap was imported. @@ -29,11 +29,6 @@ namespace osu.Game.Beatmaps /// IEnumerable Beatmaps { get; } - /// - /// All files used by this set. - /// - IEnumerable Files { get; } - /// /// The maximum star difficulty of all beatmaps in this set. /// diff --git a/osu.Game/Database/IHasNamedFiles.cs b/osu.Game/Database/IHasNamedFiles.cs new file mode 100644 index 0000000000..08906aaa08 --- /dev/null +++ b/osu.Game/Database/IHasNamedFiles.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; + +namespace osu.Game.Database +{ + public interface IHasNamedFiles + { + /// + /// All files used by this model. + /// + IEnumerable Files { get; } + } +} diff --git a/osu.Game/Models/RealmBeatmapSet.cs b/osu.Game/Models/RealmBeatmapSet.cs index fee59633f1..3566ff5321 100644 --- a/osu.Game/Models/RealmBeatmapSet.cs +++ b/osu.Game/Models/RealmBeatmapSet.cs @@ -76,7 +76,6 @@ namespace osu.Game.Models public bool Equals(IBeatmapSetInfo? other) => other is RealmBeatmapSet b && Equals(b); IEnumerable IBeatmapSetInfo.Beatmaps => Beatmaps; - - IEnumerable IBeatmapSetInfo.Files => Files; + IEnumerable IHasNamedFiles.Files => Files; } } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 9005fa8eb7..57c45faed3 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -136,7 +136,7 @@ namespace osu.Game.Online.API.Requests.Responses IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => metadata; DateTimeOffset IBeatmapSetInfo.DateAdded => throw new NotImplementedException(); - IEnumerable IBeatmapSetInfo.Files => throw new NotImplementedException(); + IEnumerable IHasNamedFiles.Files => throw new NotImplementedException(); double IBeatmapSetInfo.MaxStarDifficulty => throw new NotImplementedException(); double IBeatmapSetInfo.MaxLength => throw new NotImplementedException(); double IBeatmapSetInfo.MaxBPM => BPM; diff --git a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs index 0a2d6ca7b0..467d5a9f23 100644 --- a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs @@ -8,6 +8,7 @@ using JetBrains.Annotations; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using osu.Game.Beatmaps; +using osu.Game.Database; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; @@ -147,6 +148,7 @@ namespace osu.Game.Online.API.Requests.Responses } public IRulesetInfo Ruleset => new RulesetInfo { OnlineID = RulesetID }; + IEnumerable IHasNamedFiles.Files => throw new NotImplementedException(); IBeatmapInfo IScoreInfo.Beatmap => Beatmap; } diff --git a/osu.Game/Scoring/IScoreInfo.cs b/osu.Game/Scoring/IScoreInfo.cs index 21a402f8c3..8b5b228632 100644 --- a/osu.Game/Scoring/IScoreInfo.cs +++ b/osu.Game/Scoring/IScoreInfo.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets; namespace osu.Game.Scoring { - public interface IScoreInfo : IHasOnlineID + public interface IScoreInfo : IHasOnlineID, IHasNamedFiles { APIUser User { get; } diff --git a/osu.Game/Scoring/ScoreFileInfo.cs b/osu.Game/Scoring/ScoreFileInfo.cs index 9075fdec5b..b2e81d4b8d 100644 --- a/osu.Game/Scoring/ScoreFileInfo.cs +++ b/osu.Game/Scoring/ScoreFileInfo.cs @@ -7,7 +7,7 @@ using osu.Game.IO; namespace osu.Game.Scoring { - public class ScoreFileInfo : INamedFileInfo, IHasPrimaryKey + public class ScoreFileInfo : INamedFileInfo, IHasPrimaryKey, INamedFileUsage { public int ID { get; set; } @@ -17,5 +17,7 @@ namespace osu.Game.Scoring [Required] public string Filename { get; set; } + + IFileInfo INamedFileUsage.File => FileInfo; } } diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index b4e194cbed..564aa3b98c 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -257,5 +257,7 @@ namespace osu.Game.Scoring bool IScoreInfo.HasReplay => Files.Any(); #endregion + + IEnumerable IHasNamedFiles.Files => Files; } } diff --git a/osu.Game/Skinning/SkinFileInfo.cs b/osu.Game/Skinning/SkinFileInfo.cs index 8a7019e1a3..db7cd953bb 100644 --- a/osu.Game/Skinning/SkinFileInfo.cs +++ b/osu.Game/Skinning/SkinFileInfo.cs @@ -7,7 +7,7 @@ using osu.Game.IO; namespace osu.Game.Skinning { - public class SkinFileInfo : INamedFileInfo, IHasPrimaryKey + public class SkinFileInfo : INamedFileInfo, IHasPrimaryKey, INamedFileUsage { public int ID { get; set; } @@ -19,5 +19,7 @@ namespace osu.Game.Skinning [Required] public string Filename { get; set; } + + IFileInfo INamedFileUsage.File => FileInfo; } } diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 4733e8cdd9..5d2d51a9b0 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -10,7 +10,7 @@ using osu.Game.IO; namespace osu.Game.Skinning { - public class SkinInfo : IHasFiles, IEquatable, IHasPrimaryKey, ISoftDelete + public class SkinInfo : IHasFiles, IEquatable, IHasPrimaryKey, ISoftDelete, IHasNamedFiles { internal const int DEFAULT_SKIN = 0; internal const int CLASSIC_SKIN = -1; @@ -55,5 +55,7 @@ namespace osu.Game.Skinning string author = Creator == null ? string.Empty : $"({Creator})"; return $"{Name} {author}".Trim(); } + + IEnumerable IHasNamedFiles.Files => Files; } } From cc1b91e4bd9aa7730771088da568d841a22eaf72 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 16:36:30 +0900 Subject: [PATCH 07/46] Split out legacy model export logic into `LegacyModelExporter` classes --- osu.Game/Beatmaps/BeatmapManager.cs | 10 --- osu.Game/Database/ArchiveModelManager.cs | 53 --------------- osu.Game/Database/IModelManager.cs | 14 ---- osu.Game/Database/LegacyBeatmapExporter.cs | 18 +++++ osu.Game/Database/LegacyExporter.cs | 66 +++++++++++++++++++ osu.Game/Database/LegacyScoreExporter.cs | 31 +++++++++ osu.Game/Database/LegacySkinExporter.cs | 18 +++++ .../Online/Leaderboards/LeaderboardScore.cs | 7 +- .../Overlays/Settings/Sections/SkinSection.cs | 7 +- osu.Game/Scoring/ScoreManager.cs | 10 --- osu.Game/Scoring/ScoreModelManager.cs | 12 ---- osu.Game/Screens/Edit/Editor.cs | 7 +- osu.Game/Skinning/SkinManager.cs | 10 --- 13 files changed, 151 insertions(+), 112 deletions(-) create mode 100644 osu.Game/Database/LegacyBeatmapExporter.cs create mode 100644 osu.Game/Database/LegacyExporter.cs create mode 100644 osu.Game/Database/LegacyScoreExporter.cs create mode 100644 osu.Game/Database/LegacySkinExporter.cs diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 2cca3ceaeb..1c01f100eb 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -225,16 +225,6 @@ namespace osu.Game.Beatmaps remove => beatmapModelManager.ItemRemoved -= value; } - public void Export(BeatmapSetInfo item) - { - beatmapModelManager.Export(item); - } - - public void ExportModelTo(BeatmapSetInfo model, Stream outputStream) - { - beatmapModelManager.ExportModelTo(model, outputStream); - } - public void Update(BeatmapSetInfo item) { beatmapModelManager.Update(item); diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index e5919cb5c4..e73f4a7f6e 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -20,7 +20,6 @@ using osu.Game.IO; using osu.Game.IO.Archives; using osu.Game.IPC; using osu.Game.Overlays.Notifications; -using SharpCompress.Archives.Zip; namespace osu.Game.Database { @@ -82,8 +81,6 @@ namespace osu.Game.Database // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private ArchiveImportIPCChannel ipc; - private readonly Storage exportStorage; - protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStoreWithFileIncludes modelStore, IIpcHost importHost = null) { ContextFactory = contextFactory; @@ -92,8 +89,6 @@ namespace osu.Game.Database ModelStore.ItemUpdated += item => handleEvent(() => ItemUpdated?.Invoke(item)); ModelStore.ItemRemoved += item => handleEvent(() => ItemRemoved?.Invoke(item)); - exportStorage = storage.GetStorageForDirectory(@"exports"); - Files = new FileStore(contextFactory, storage); if (importHost != null) @@ -452,41 +447,6 @@ namespace osu.Game.Database return item.ToEntityFrameworkLive(); }, cancellationToken, TaskCreationOptions.HideScheduler, lowPriority ? import_scheduler_low_priority : import_scheduler).Unwrap().ConfigureAwait(false); - /// - /// Exports an item to a legacy (.zip based) package. - /// - /// The item to export. - public void Export(TModel item) - { - var retrievedItem = ModelStore.ConsumableItems.FirstOrDefault(s => s.ID == item.ID); - - if (retrievedItem == null) - throw new ArgumentException(@"Specified model could not be found", nameof(item)); - - string filename = $"{GetValidFilename(item.ToString())}{HandledExtensions.First()}"; - - using (var stream = exportStorage.GetStream(filename, FileAccess.Write, FileMode.Create)) - ExportModelTo(retrievedItem, stream); - - exportStorage.PresentFileExternally(filename); - } - - /// - /// Exports an item to the given output stream. - /// - /// The item to export. - /// The output stream to export to. - public virtual void ExportModelTo(TModel model, Stream outputStream) - { - using (var archive = ZipArchive.Create()) - { - foreach (var file in model.Files) - archive.AddEntry(file.Filename, Files.Storage.GetStream(file.FileInfo.GetStoragePath())); - - archive.SaveTo(outputStream); - } - } - /// /// Replace an existing file with a new version. /// @@ -875,18 +835,5 @@ namespace osu.Game.Database // this doesn't follow the SHA2 hashing schema intentionally, so such entries on the data store can be identified. return Guid.NewGuid().ToString(); } - - private readonly char[] invalidFilenameCharacters = Path.GetInvalidFileNameChars() - // Backslash is added to avoid issues when exporting to zip. - // See SharpCompress filename normalisation https://github.com/adamhathcock/sharpcompress/blob/a1e7c0068db814c9aa78d86a94ccd1c761af74bd/src/SharpCompress/Writers/Zip/ZipWriter.cs#L143. - .Append('\\') - .ToArray(); - - protected string GetValidFilename(string filename) - { - foreach (char c in invalidFilenameCharacters) - filename = filename.Replace(c, '_'); - return filename; - } } } diff --git a/osu.Game/Database/IModelManager.cs b/osu.Game/Database/IModelManager.cs index 6c9cca7c7a..779d0522f7 100644 --- a/osu.Game/Database/IModelManager.cs +++ b/osu.Game/Database/IModelManager.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.IO; namespace osu.Game.Database { @@ -24,19 +23,6 @@ namespace osu.Game.Database /// event Action ItemRemoved; - /// - /// Exports an item to a legacy (.zip based) package. - /// - /// The item to export. - void Export(TModel item); - - /// - /// Exports an item to the given output stream. - /// - /// The item to export. - /// The output stream to export to. - void ExportModelTo(TModel model, Stream outputStream); - /// /// Perform an update of the specified item. /// TODO: Support file additions/removals. diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs new file mode 100644 index 0000000000..671ed54326 --- /dev/null +++ b/osu.Game/Database/LegacyBeatmapExporter.cs @@ -0,0 +1,18 @@ +// 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.Platform; +using osu.Game.Beatmaps; + +namespace osu.Game.Database +{ + public class LegacyBeatmapExporter : LegacyExporter + { + protected override string FileExtension => ".osz"; + + public LegacyBeatmapExporter(Storage storage, IModelManager manager) + : base(storage, manager) + { + } + } +} diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs new file mode 100644 index 0000000000..846495b1ed --- /dev/null +++ b/osu.Game/Database/LegacyExporter.cs @@ -0,0 +1,66 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.IO; +using osu.Framework.Platform; +using osu.Game.Extensions; +using SharpCompress.Archives.Zip; + +namespace osu.Game.Database +{ + /// + /// A class which handles exporting legacy user data of a single type from osu-stable. + /// + public abstract class LegacyExporter + where TModel : class, IHasNamedFiles + { + /// + /// The file extension for exports (including the leading '.'). + /// + protected abstract string FileExtension { get; } + + protected readonly IModelManager Manager; + + protected readonly Storage UserFileStorage; + + private readonly Storage exportStorage; + + protected LegacyExporter(Storage storage, IModelManager manager) + { + Manager = manager; + + exportStorage = storage.GetStorageForDirectory(@"exports"); + UserFileStorage = storage.GetStorageForDirectory(@"files"); + } + + /// + /// Exports an item to a legacy (.zip based) package. + /// + /// The item to export. + public void Export(TModel item) + { + string filename = $"{item.ToString().GetValidArchiveContentFilename()}{FileExtension}"; + + using (var stream = exportStorage.GetStream(filename, FileAccess.Write, FileMode.Create)) + ExportModelTo(item, stream); + + exportStorage.PresentFileExternally(filename); + } + + /// + /// Exports an item to the given output stream. + /// + /// The item to export. + /// The output stream to export to. + public virtual void ExportModelTo(TModel model, Stream outputStream) + { + using (var archive = ZipArchive.Create()) + { + foreach (var file in model.Files) + archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath())); + + archive.SaveTo(outputStream); + } + } + } +} diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs new file mode 100644 index 0000000000..e4ddd5982b --- /dev/null +++ b/osu.Game/Database/LegacyScoreExporter.cs @@ -0,0 +1,31 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.IO; +using System.Linq; +using osu.Framework.Platform; +using osu.Game.Extensions; +using osu.Game.Scoring; + +namespace osu.Game.Database +{ + public class LegacyScoreExporter : LegacyExporter + { + protected override string FileExtension => ".osr"; + + public LegacyScoreExporter(Storage storage, IModelManager manager) + : base(storage, manager) + { + } + + public override void ExportModelTo(ScoreInfo model, Stream outputStream) + { + var file = model.Files.SingleOrDefault(); + if (file == null) + return; + + using (var inputStream = UserFileStorage.GetStream(file.FileInfo.GetStoragePath())) + inputStream.CopyTo(outputStream); + } + } +} diff --git a/osu.Game/Database/LegacySkinExporter.cs b/osu.Game/Database/LegacySkinExporter.cs new file mode 100644 index 0000000000..f6d243315c --- /dev/null +++ b/osu.Game/Database/LegacySkinExporter.cs @@ -0,0 +1,18 @@ +// 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.Platform; +using osu.Game.Skinning; + +namespace osu.Game.Database +{ + public class LegacySkinExporter : LegacyExporter + { + protected override string FileExtension => ".osk"; + + public LegacySkinExporter(Storage storage, IModelManager manager) + : base(storage, manager) + { + } + } +} diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index f0c57cb953..06c0636d17 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -14,6 +14,8 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Framework.Platform; +using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -66,6 +68,9 @@ namespace osu.Game.Online.Leaderboards [Resolved] private ScoreManager scoreManager { get; set; } + [Resolved] + private Storage storage { get; set; } + public LeaderboardScore(ScoreInfo score, int? rank, bool allowHighlight = true) { Score = score; @@ -395,7 +400,7 @@ namespace osu.Game.Online.Leaderboards items.Add(new OsuMenuItem("Use these mods", MenuItemType.Highlighted, () => songSelect.Mods.Value = Score.Mods)); if (Score.Files.Count > 0) - items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => scoreManager.Export(Score))); + items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => new LegacyScoreExporter(storage, scoreManager).Export(Score))); if (Score.ID != 0) items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index e7a7abed59..0eec6f5f77 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -11,7 +11,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Logging; +using osu.Framework.Platform; using osu.Game.Configuration; +using osu.Game.Database; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Skinning; @@ -167,6 +169,9 @@ namespace osu.Game.Overlays.Settings.Sections [Resolved] private SkinManager skins { get; set; } + [Resolved] + private Storage storage { get; set; } + private Bindable currentSkin; [BackgroundDependencyLoader] @@ -183,7 +188,7 @@ namespace osu.Game.Overlays.Settings.Sections { try { - skins.Export(currentSkin.Value.SkinInfo); + new LegacySkinExporter(storage, skins).Export(currentSkin.Value.SkinInfo); } catch (Exception e) { diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index d25671d77e..a89444408d 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -262,16 +262,6 @@ namespace osu.Game.Scoring remove => scoreModelManager.ItemRemoved -= value; } - public void Export(ScoreInfo item) - { - scoreModelManager.Export(item); - } - - public void ExportModelTo(ScoreInfo model, Stream outputStream) - { - scoreModelManager.ExportModelTo(model, outputStream); - } - public void Update(ScoreInfo item) { scoreModelManager.Update(item); diff --git a/osu.Game/Scoring/ScoreModelManager.cs b/osu.Game/Scoring/ScoreModelManager.cs index 9da739237b..2cbd3aded7 100644 --- a/osu.Game/Scoring/ScoreModelManager.cs +++ b/osu.Game/Scoring/ScoreModelManager.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Linq.Expressions; using System.Threading; @@ -13,7 +12,6 @@ using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Database; -using osu.Game.Extensions; using osu.Game.IO.Archives; using osu.Game.Rulesets; using osu.Game.Scoring.Legacy; @@ -69,15 +67,5 @@ namespace osu.Game.Scoring protected override bool CheckLocalAvailability(ScoreInfo model, IQueryable items) => base.CheckLocalAvailability(model, items) || (model.OnlineScoreID != null && items.Any(i => i.OnlineScoreID == model.OnlineScoreID)); - - public override void ExportModelTo(ScoreInfo model, Stream outputStream) - { - var file = model.Files.SingleOrDefault(); - if (file == null) - return; - - using (var inputStream = Files.Storage.GetStream(file.FileInfo.GetStoragePath())) - inputStream.CopyTo(outputStream); - } } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 94b6e58b67..46d84fe73d 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -16,9 +16,11 @@ using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Logging; +using osu.Framework.Platform; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; @@ -63,6 +65,9 @@ namespace osu.Game.Screens.Edit [Resolved] private BeatmapManager beatmapManager { get; set; } + [Resolved] + private Storage storage { get; set; } + [Resolved(canBeNull: true)] private DialogOverlay dialogOverlay { get; set; } @@ -753,7 +758,7 @@ namespace osu.Game.Screens.Edit private void exportBeatmap() { Save(); - beatmapManager.Export(Beatmap.Value.BeatmapSetInfo); + new LegacyBeatmapExporter(storage, beatmapManager).Export(Beatmap.Value.BeatmapSetInfo); } private void updateLastSavedHash() diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 679b35799e..8d07dd046a 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -301,16 +301,6 @@ namespace osu.Game.Skinning remove => skinModelManager.ItemRemoved -= value; } - public void Export(SkinInfo item) - { - skinModelManager.Export(item); - } - - public void ExportModelTo(SkinInfo model, Stream outputStream) - { - skinModelManager.ExportModelTo(model, outputStream); - } - public void Update(SkinInfo item) { skinModelManager.Update(item); From ec9a09d5a42a0a2818c369faf22e134802e73917 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 16:56:19 +0900 Subject: [PATCH 08/46] Add missing licence headers --- osu.Game/Database/LegacyBeatmapImporter.cs | 3 +++ osu.Game/Database/LegacyScoreImporter.cs | 3 +++ osu.Game/Database/LegacySkinImporter.cs | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/LegacyBeatmapImporter.cs b/osu.Game/Database/LegacyBeatmapImporter.cs index 041a692655..97f6eba6c2 100644 --- a/osu.Game/Database/LegacyBeatmapImporter.cs +++ b/osu.Game/Database/LegacyBeatmapImporter.cs @@ -1,3 +1,6 @@ +// 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.Platform; using osu.Game.Beatmaps; using osu.Game.IO; diff --git a/osu.Game/Database/LegacyScoreImporter.cs b/osu.Game/Database/LegacyScoreImporter.cs index 984aa8a1ac..48445b7bdb 100644 --- a/osu.Game/Database/LegacyScoreImporter.cs +++ b/osu.Game/Database/LegacyScoreImporter.cs @@ -1,3 +1,6 @@ +// 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.Collections.Generic; using System.IO; diff --git a/osu.Game/Database/LegacySkinImporter.cs b/osu.Game/Database/LegacySkinImporter.cs index b102e26bc6..2f05ccae45 100644 --- a/osu.Game/Database/LegacySkinImporter.cs +++ b/osu.Game/Database/LegacySkinImporter.cs @@ -1,3 +1,6 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + using osu.Game.Skinning; namespace osu.Game.Database @@ -11,4 +14,4 @@ namespace osu.Game.Database { } } -} \ No newline at end of file +} From 79459c1aebc968ac4821161399126075b6301c93 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 17:12:15 +0900 Subject: [PATCH 09/46] Fix typo in class and variable names --- ...ImportManager.cs => LegacyImportManager.cs} | 2 +- osu.Game/OsuGame.cs | 4 ++-- .../Sections/Maintenance/GeneralSettings.cs | 18 +++++++++--------- osu.Game/Screens/Select/SongSelect.cs | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) rename osu.Game/Database/{LeagcyImportManager.cs => LegacyImportManager.cs} (98%) diff --git a/osu.Game/Database/LeagcyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs similarity index 98% rename from osu.Game/Database/LeagcyImportManager.cs rename to osu.Game/Database/LegacyImportManager.cs index 8ee63429e2..4dc26b18bb 100644 --- a/osu.Game/Database/LeagcyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.cs @@ -22,7 +22,7 @@ namespace osu.Game.Database /// /// Handles migration of legacy user data from osu-stable. /// - public class LeagcyImportManager : Component + public class LegacyImportManager : Component { [Resolved] private SkinManager skins { get; set; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9b9ec585e8..0e050304f0 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -116,7 +116,7 @@ namespace osu.Game private readonly DifficultyRecommender difficultyRecommender = new DifficultyRecommender(); [Cached] - private readonly LeagcyImportManager leagcyImportManager = new LeagcyImportManager(); + private readonly LegacyImportManager legacyImportManager = new LegacyImportManager(); [Cached] private readonly ScreenshotManager screenshotManager = new ScreenshotManager(); @@ -782,7 +782,7 @@ namespace osu.Game PostNotification = n => Notifications.Post(n), }, Add, true); - loadComponentSingleFile(leagcyImportManager, Add); + loadComponentSingleFile(legacyImportManager, Add); loadComponentSingleFile(screenshotManager, Add); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 9dfd0d8ff4..5bc89ec77c 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -31,9 +31,9 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private SettingsButton undeleteButton; [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LeagcyImportManager leagcyImportManager, DialogOverlay dialogOverlay) + private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, DialogOverlay dialogOverlay) { - if (leagcyImportManager?.SupportsImportFromStable == true) + if (legacyImportManager?.SupportsImportFromStable == true) { Add(importBeatmapsButton = new SettingsButton { @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importBeatmapsButton.Enabled.Value = false; - leagcyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); + legacyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); } }); } @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance } }); - if (leagcyImportManager?.SupportsImportFromStable == true) + if (legacyImportManager?.SupportsImportFromStable == true) { Add(importScoresButton = new SettingsButton { @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importScoresButton.Enabled.Value = false; - leagcyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); + legacyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); } }); } @@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance } }); - if (leagcyImportManager?.SupportsImportFromStable == true) + if (legacyImportManager?.SupportsImportFromStable == true) { Add(importSkinsButton = new SettingsButton { @@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importSkinsButton.Enabled.Value = false; - leagcyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true)); + legacyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true)); } }); } @@ -113,7 +113,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance if (collectionManager != null) { - if (leagcyImportManager?.SupportsImportFromStable == true) + if (legacyImportManager?.SupportsImportFromStable == true) { Add(importCollectionsButton = new SettingsButton { @@ -121,7 +121,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importCollectionsButton.Enabled.Value = false; - leagcyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); + legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); } }); } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b6933a9830..25efe22892 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Select protected virtual bool ShowFooter => true; - protected virtual bool DisplayStableImportPrompt => leagcyImportManager?.SupportsImportFromStable == true; + protected virtual bool DisplayStableImportPrompt => legacyImportManager?.SupportsImportFromStable == true; public override bool? AllowTrackAdjustments => true; @@ -90,7 +90,7 @@ namespace osu.Game.Screens.Select private BeatmapManager beatmaps { get; set; } [Resolved(CanBeNull = true)] - private LeagcyImportManager leagcyImportManager { get; set; } + private LegacyImportManager legacyImportManager { get; set; } protected ModSelectOverlay ModSelect { get; private set; } @@ -297,7 +297,7 @@ namespace osu.Game.Screens.Select { dialogOverlay.Push(new ImportFromStablePopup(() => { - Task.Run(() => leagcyImportManager.ImportFromStableAsync(StableContent.All)); + Task.Run(() => legacyImportManager.ImportFromStableAsync(StableContent.All)); })); } }); From 716543b5b3ba8bb467da72ae059a153fc449a813 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 17:23:46 +0900 Subject: [PATCH 10/46] Move beatmap download logic out of `BeatmapManager` --- ...ager.cs => TestSceneBeatmapDownloading.cs} | 6 +-- ...eneOnlinePlayBeatmapAvailabilityTracker.cs | 35 ++++++++---------- osu.Game/Beatmaps/BeatmapManager.cs | 37 +------------------ .../Drawables/Cards/Buttons/DownloadButton.cs | 2 +- osu.Game/Online/BeatmapDownloadTracker.cs | 19 +++++++--- osu.Game/OsuGame.cs | 1 + osu.Game/OsuGameBase.cs | 3 ++ .../Panels/BeatmapPanelDownloadButton.cs | 2 +- .../Buttons/HeaderDownloadButton.cs | 2 +- osu.Game/Screens/Play/SoloSpectator.cs | 5 ++- 10 files changed, 45 insertions(+), 67 deletions(-) rename osu.Game.Tests/Online/{TestSceneBeatmapManager.cs => TestSceneBeatmapDownloading.cs} (94%) diff --git a/osu.Game.Tests/Online/TestSceneBeatmapManager.cs b/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs similarity index 94% rename from osu.Game.Tests/Online/TestSceneBeatmapManager.cs rename to osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs index fc1b4f224d..4e77973655 100644 --- a/osu.Game.Tests/Online/TestSceneBeatmapManager.cs +++ b/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs @@ -12,9 +12,9 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Online { [HeadlessTest] - public class TestSceneBeatmapManager : OsuTestScene + public class TestSceneBeatmapDownloading : OsuTestScene { - private BeatmapManager beatmaps; + private BeatmapModelDownloader beatmaps; private ProgressNotification recentNotification; private static readonly BeatmapSetInfo test_db_model = new BeatmapSetInfo @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Online }; [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps) + private void load(BeatmapModelDownloader beatmaps) { this.beatmaps = beatmaps; diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index a4c69075be..f5d57240ca 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -33,6 +33,7 @@ namespace osu.Game.Tests.Online { private RulesetStore rulesets; private TestBeatmapManager beatmaps; + private TestBeatmapModelDownloader beatmapDownloader; private string testBeatmapFile; private BeatmapInfo testBeatmapInfo; @@ -46,6 +47,7 @@ namespace osu.Game.Tests.Online { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.CacheAs(beatmaps = new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default)); + Dependencies.CacheAs(beatmapDownloader = new TestBeatmapModelDownloader(beatmaps, API, host)); } [SetUp] @@ -80,13 +82,13 @@ namespace osu.Game.Tests.Online AddAssert("ensure beatmap unavailable", () => !beatmaps.IsAvailableLocally(testBeatmapSet)); addAvailabilityCheckStep("state not downloaded", BeatmapAvailability.NotDownloaded); - AddStep("start downloading", () => beatmaps.Download(testBeatmapSet)); + AddStep("start downloading", () => beatmapDownloader.Download(testBeatmapSet)); addAvailabilityCheckStep("state downloading 0%", () => BeatmapAvailability.Downloading(0.0f)); - AddStep("set progress 40%", () => ((TestDownloadRequest)beatmaps.GetExistingDownload(testBeatmapSet)).SetProgress(0.4f)); + AddStep("set progress 40%", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet)).SetProgress(0.4f)); addAvailabilityCheckStep("state downloading 40%", () => BeatmapAvailability.Downloading(0.4f)); - AddStep("finish download", () => ((TestDownloadRequest)beatmaps.GetExistingDownload(testBeatmapSet)).TriggerSuccess(testBeatmapFile)); + AddStep("finish download", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet)).TriggerSuccess(testBeatmapFile)); addAvailabilityCheckStep("state importing", BeatmapAvailability.Importing); AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true)); @@ -171,22 +173,6 @@ namespace osu.Game.Tests.Online return new TestBeatmapModelManager(this, storage, contextFactory, rulesets, api, host); } - protected override BeatmapModelDownloader CreateBeatmapModelDownloader(IModelImporter manager, IAPIProvider api, GameHost host) - { - return new TestBeatmapModelDownloader(manager, api, host); - } - - internal class TestBeatmapModelDownloader : BeatmapModelDownloader - { - public TestBeatmapModelDownloader(IModelImporter importer, IAPIProvider apiProvider, GameHost gameHost) - : base(importer, apiProvider, gameHost) - { - } - - protected override ArchiveDownloadRequest CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize) - => new TestDownloadRequest(set); - } - internal class TestBeatmapModelManager : BeatmapModelManager { private readonly TestBeatmapManager testBeatmapManager; @@ -205,6 +191,17 @@ namespace osu.Game.Tests.Online } } + internal class TestBeatmapModelDownloader : BeatmapModelDownloader + { + public TestBeatmapModelDownloader(IModelImporter importer, IAPIProvider apiProvider, GameHost gameHost) + : base(importer, apiProvider, gameHost) + { + } + + protected override ArchiveDownloadRequest CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize) + => new TestDownloadRequest(set); + } + private class TestDownloadRequest : ArchiveDownloadRequest { public new void SetProgress(float progress) => base.SetProgress(progress); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 0594cd1316..179d479b53 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -29,12 +29,11 @@ namespace osu.Game.Beatmaps /// Handles general operations related to global beatmap management. /// [ExcludeFromDynamicCompile] - public class BeatmapManager : IModelDownloader, IModelManager, IModelFileManager, IModelImporter, IWorkingBeatmapCache, IDisposable + public class BeatmapManager : IModelManager, IModelFileManager, IModelImporter, IWorkingBeatmapCache, IDisposable { public ITrackStore BeatmapTrackStore { get; } private readonly BeatmapModelManager beatmapModelManager; - private readonly BeatmapModelDownloader beatmapModelDownloader; private readonly WorkingBeatmapCache workingBeatmapCache; private readonly BeatmapOnlineLookupQueue onlineBeatmapLookupQueue; @@ -46,7 +45,6 @@ namespace osu.Game.Beatmaps BeatmapTrackStore = audioManager.GetTrackStore(userResources); beatmapModelManager = CreateBeatmapModelManager(storage, contextFactory, rulesets, api, host); - beatmapModelDownloader = CreateBeatmapModelDownloader(beatmapModelManager, api, host); workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host); workingBeatmapCache.BeatmapManager = beatmapModelManager; @@ -59,11 +57,6 @@ namespace osu.Game.Beatmaps } } - protected virtual BeatmapModelDownloader CreateBeatmapModelDownloader(IModelImporter modelManager, IAPIProvider api, GameHost host) - { - return new BeatmapModelDownloader(modelManager, api, host); - } - protected virtual WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore resources, IResourceStore storage, WorkingBeatmap defaultBeatmap, GameHost host) { return new WorkingBeatmapCache(BeatmapTrackStore, audioManager, resources, storage, defaultBeatmap, host); @@ -185,11 +178,7 @@ namespace osu.Game.Beatmaps /// public Action PostNotification { - set - { - beatmapModelManager.PostNotification = value; - beatmapModelDownloader.PostNotification = value; - } + set => beatmapModelManager.PostNotification = value; } /// @@ -267,28 +256,6 @@ namespace osu.Game.Beatmaps #endregion - #region Implementation of IModelDownloader - - public event Action> DownloadBegan - { - add => beatmapModelDownloader.DownloadBegan += value; - remove => beatmapModelDownloader.DownloadBegan -= value; - } - - public event Action> DownloadFailed - { - add => beatmapModelDownloader.DownloadFailed += value; - remove => beatmapModelDownloader.DownloadFailed -= value; - } - - public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false) => - beatmapModelDownloader.Download(model, minimiseDownloadSize); - - public ArchiveDownloadRequest GetExistingDownload(IBeatmapSetInfo model) => - beatmapModelDownloader.GetExistingDownload(model); - - #endregion - #region Implementation of ICanAcceptFiles public Task Import(params string[] paths) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs index 7430fce1c8..1a514c8d36 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs @@ -24,7 +24,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons private Bindable preferNoVideo = null!; [Resolved] - private BeatmapManager beatmaps { get; set; } = null!; + private BeatmapModelDownloader beatmaps { get; set; } = null!; public DownloadButton(APIBeatmapSet beatmapSet) { diff --git a/osu.Game/Online/BeatmapDownloadTracker.cs b/osu.Game/Online/BeatmapDownloadTracker.cs index 77a8fca1e4..509d5c1b71 100644 --- a/osu.Game/Online/BeatmapDownloadTracker.cs +++ b/osu.Game/Online/BeatmapDownloadTracker.cs @@ -15,6 +15,9 @@ namespace osu.Game.Online [Resolved(CanBeNull = true)] protected BeatmapManager? Manager { get; private set; } + [Resolved(CanBeNull = true)] + protected BeatmapModelDownloader? Downloader { get; private set; } + private ArchiveDownloadRequest? attachedRequest; public BeatmapDownloadTracker(IBeatmapSetInfo trackedItem) @@ -25,7 +28,7 @@ namespace osu.Game.Online [BackgroundDependencyLoader(true)] private void load() { - if (Manager == null) + if (Manager == null || Downloader == null) return; // Used to interact with manager classes that don't support interface types. Will eventually be replaced. @@ -34,10 +37,10 @@ namespace osu.Game.Online if (Manager.IsAvailableLocally(beatmapSetInfo)) UpdateState(DownloadState.LocallyAvailable); else - attachDownload(Manager.GetExistingDownload(beatmapSetInfo)); + attachDownload(Downloader.GetExistingDownload(beatmapSetInfo)); - Manager.DownloadBegan += downloadBegan; - Manager.DownloadFailed += downloadFailed; + Downloader.DownloadBegan += downloadBegan; + Downloader.DownloadFailed += downloadFailed; Manager.ItemUpdated += itemUpdated; Manager.ItemRemoved += itemRemoved; } @@ -115,10 +118,14 @@ namespace osu.Game.Online base.Dispose(isDisposing); attachDownload(null); + if (Downloader != null) + { + Downloader.DownloadBegan -= downloadBegan; + Downloader.DownloadFailed -= downloadFailed; + } + if (Manager != null) { - Manager.DownloadBegan -= downloadBegan; - Manager.DownloadFailed -= downloadFailed; Manager.ItemUpdated -= itemUpdated; Manager.ItemRemoved -= itemRemoved; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 574a5e5393..1060724680 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -656,6 +656,7 @@ namespace osu.Game BeatmapManager.PostNotification = n => Notifications.Post(n); BeatmapManager.PostImport = items => PresentBeatmap(items.First().Value); + BeatmapDownloader.PostNotification = n => Notifications.Post(n); ScoreManager.PostNotification = n => Notifications.Post(n); ScoreManager.PostImport = items => PresentScore(items.First().Value); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index dd4ae590c7..a64d9ac01a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -96,6 +96,8 @@ namespace osu.Game protected BeatmapManager BeatmapManager { get; private set; } + protected BeatmapModelDownloader BeatmapDownloader { get; private set; } + protected ScoreManager ScoreManager { get; private set; } protected SkinManager SkinManager { get; private set; } @@ -235,6 +237,7 @@ namespace osu.Game dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Scheduler, Host, () => difficultyCache, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, performOnlineLookups: true)); + dependencies.Cache(BeatmapDownloader = new BeatmapModelDownloader(BeatmapManager, API, Host)); // the following realm components are not actively used yet, but initialised and kept up to date for initial testing. realmRulesetStore = new RealmRulesetStore(realmFactory, Storage); diff --git a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs index 1282a14c3d..0a66c3ccb7 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs @@ -65,7 +65,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels } [BackgroundDependencyLoader(true)] - private void load(OsuGame game, BeatmapManager beatmaps, OsuConfigManager osuConfig) + private void load(OsuGame game, BeatmapModelDownloader beatmaps, OsuConfigManager osuConfig) { noVideoSetting = osuConfig.GetBindable(OsuSetting.PreferNoVideo); diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index ee40f114d2..4eed8f28f2 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -51,7 +51,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons } [BackgroundDependencyLoader] - private void load(IAPIProvider api, BeatmapManager beatmaps) + private void load(IAPIProvider api, BeatmapModelDownloader beatmaps) { FillFlowContainer textSprites; diff --git a/osu.Game/Screens/Play/SoloSpectator.cs b/osu.Game/Screens/Play/SoloSpectator.cs index c65d4af2ae..5ecdb91718 100644 --- a/osu.Game/Screens/Play/SoloSpectator.cs +++ b/osu.Game/Screens/Play/SoloSpectator.cs @@ -49,6 +49,9 @@ namespace osu.Game.Screens.Play [Resolved] private BeatmapManager beatmaps { get; set; } + [Resolved] + private BeatmapModelDownloader beatmapDownloader { get; set; } + private Container beatmapPanelContainer; private TriangleButton watchButton; private SettingsCheckbox automaticDownload; @@ -244,7 +247,7 @@ namespace osu.Game.Screens.Play if (beatmaps.IsAvailableLocally(new BeatmapSetInfo { OnlineID = beatmapSet.OnlineID })) return; - beatmaps.Download(beatmapSet); + beatmapDownloader.Download(beatmapSet); } public override bool OnExiting(IScreen next) From a2ab9f457d8c883d8a302befd7a3a78241d89174 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 17:21:05 +0900 Subject: [PATCH 11/46] Move score download logic out of `ScoreManager` --- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 2 +- .../TestSceneDeleteLocalScore.cs | 2 +- osu.Game/Online/ScoreDownloadTracker.cs | 19 +++++++--- osu.Game/OsuGame.cs | 2 + osu.Game/OsuGameBase.cs | 6 ++- osu.Game/Scoring/ScoreManager.cs | 37 ++----------------- .../Screens/Ranking/ReplayDownloadButton.cs | 4 +- 7 files changed, 27 insertions(+), 45 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 2a2df777f7..aa36bde030 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.SongSelect dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); - dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory, Scheduler)); + dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, ContextFactory, Scheduler)); return dependencies; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index 7353e47229..9f0f4a6b8b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual.UserInterface dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); - dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory, Scheduler)); + dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, ContextFactory, Scheduler)); beatmapInfo = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).Result.Value.Beatmaps[0]; diff --git a/osu.Game/Online/ScoreDownloadTracker.cs b/osu.Game/Online/ScoreDownloadTracker.cs index 32307fc50e..e09cc7c9cd 100644 --- a/osu.Game/Online/ScoreDownloadTracker.cs +++ b/osu.Game/Online/ScoreDownloadTracker.cs @@ -15,6 +15,9 @@ namespace osu.Game.Online [Resolved(CanBeNull = true)] protected ScoreManager? Manager { get; private set; } + [Resolved(CanBeNull = true)] + protected ScoreModelDownloader? Downloader { get; private set; } + private ArchiveDownloadRequest? attachedRequest; public ScoreDownloadTracker(ScoreInfo trackedItem) @@ -25,7 +28,7 @@ namespace osu.Game.Online [BackgroundDependencyLoader(true)] private void load() { - if (Manager == null) + if (Manager == null || Downloader == null) return; // Used to interact with manager classes that don't support interface types. Will eventually be replaced. @@ -38,10 +41,10 @@ namespace osu.Game.Online if (Manager.IsAvailableLocally(scoreInfo)) UpdateState(DownloadState.LocallyAvailable); else - attachDownload(Manager.GetExistingDownload(scoreInfo)); + attachDownload(Downloader.GetExistingDownload(scoreInfo)); - Manager.DownloadBegan += downloadBegan; - Manager.DownloadFailed += downloadFailed; + Downloader.DownloadBegan += downloadBegan; + Downloader.DownloadFailed += downloadFailed; Manager.ItemUpdated += itemUpdated; Manager.ItemRemoved += itemRemoved; } @@ -119,10 +122,14 @@ namespace osu.Game.Online base.Dispose(isDisposing); attachDownload(null); + if (Downloader != null) + { + Downloader.DownloadBegan -= downloadBegan; + Downloader.DownloadFailed -= downloadFailed; + } + if (Manager != null) { - Manager.DownloadBegan -= downloadBegan; - Manager.DownloadFailed -= downloadFailed; Manager.ItemUpdated -= itemUpdated; Manager.ItemRemoved -= itemRemoved; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1060724680..aa9bdac756 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -657,6 +657,8 @@ namespace osu.Game BeatmapManager.PostImport = items => PresentBeatmap(items.First().Value); BeatmapDownloader.PostNotification = n => Notifications.Post(n); + ScoreDownloader.PostNotification = n => Notifications.Post(n); + ScoreManager.PostNotification = n => Notifications.Post(n); ScoreManager.PostImport = items => PresentScore(items.First().Value); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index a64d9ac01a..c0594231df 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -100,6 +100,8 @@ namespace osu.Game protected ScoreManager ScoreManager { get; private set; } + protected ScoreModelDownloader ScoreDownloader { get; private set; } + protected SkinManager SkinManager { get; private set; } protected RulesetStore RulesetStore { get; private set; } @@ -234,10 +236,12 @@ namespace osu.Game dependencies.Cache(fileStore = new FileStore(contextFactory, Storage)); // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Scheduler, Host, () => difficultyCache, LocalConfig)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, contextFactory, Scheduler, Host, () => difficultyCache, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, performOnlineLookups: true)); dependencies.Cache(BeatmapDownloader = new BeatmapModelDownloader(BeatmapManager, API, Host)); + dependencies.Cache(ScoreDownloader = new ScoreModelDownloader(ScoreManager, API, Host)); + // the following realm components are not actively used yet, but initialised and kept up to date for initial testing. realmRulesetStore = new RealmRulesetStore(realmFactory, Storage); diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index abc0bfdda7..8d9733669c 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -17,7 +17,6 @@ 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.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Rulesets.Judgements; @@ -25,15 +24,14 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Scoring { - public class ScoreManager : IModelManager, IModelImporter, IModelDownloader + public class ScoreManager : IModelManager, IModelImporter { private readonly Scheduler scheduler; private readonly Func difficulties; private readonly OsuConfigManager configManager; private readonly ScoreModelManager scoreModelManager; - private readonly ScoreModelDownloader scoreModelDownloader; - public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, IAPIProvider api, IDatabaseContextFactory contextFactory, Scheduler scheduler, + public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, IDatabaseContextFactory contextFactory, Scheduler scheduler, IIpcHost importHost = null, Func difficulties = null, OsuConfigManager configManager = null) { this.scheduler = scheduler; @@ -41,7 +39,6 @@ namespace osu.Game.Scoring this.configManager = configManager; scoreModelManager = new ScoreModelManager(rulesets, beatmaps, storage, contextFactory, importHost); - scoreModelDownloader = new ScoreModelDownloader(scoreModelManager, api, importHost); } public Score GetScore(ScoreInfo score) => scoreModelManager.GetScore(score); @@ -240,11 +237,7 @@ namespace osu.Game.Scoring public Action PostNotification { - set - { - scoreModelManager.PostNotification = value; - scoreModelDownloader.PostNotification = value; - } + set => scoreModelManager.PostNotification = value; } #endregion @@ -342,30 +335,6 @@ namespace osu.Game.Scoring #endregion - #region Implementation of IModelDownloader - - public event Action> DownloadBegan - { - add => scoreModelDownloader.DownloadBegan += value; - remove => scoreModelDownloader.DownloadBegan -= value; - } - - public event Action> DownloadFailed - { - add => scoreModelDownloader.DownloadFailed += value; - remove => scoreModelDownloader.DownloadFailed -= value; - } - - public bool Download(IScoreInfo model, bool minimiseDownloadSize) => - scoreModelDownloader.Download(model, minimiseDownloadSize); - - public ArchiveDownloadRequest GetExistingDownload(IScoreInfo model) - { - return scoreModelDownloader.GetExistingDownload(model); - } - - #endregion - #region Implementation of IPresentImports public Action>> PostImport diff --git a/osu.Game/Screens/Ranking/ReplayDownloadButton.cs b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs index 66b3c973f5..6a74fdaf75 100644 --- a/osu.Game/Screens/Ranking/ReplayDownloadButton.cs +++ b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Ranking } [BackgroundDependencyLoader(true)] - private void load(OsuGame game, ScoreManager scores) + private void load(OsuGame game, ScoreModelDownloader scores) { InternalChild = shakeContainer = new ShakeContainer { @@ -65,7 +65,7 @@ namespace osu.Game.Screens.Ranking break; case DownloadState.NotDownloaded: - scores.Download(Score.Value, false); + scores.Download(Score.Value); break; case DownloadState.Importing: From eeccf836ec04d2e3aac1fec93c15b48aa6672352 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 17:42:41 +0900 Subject: [PATCH 12/46] Remove unnecessary `GameHost` parameter --- .../Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs | 2 +- osu.Game/Beatmaps/BeatmapModelDownloader.cs | 5 ++--- osu.Game/Database/ModelDownloader.cs | 3 +-- osu.Game/OsuGameBase.cs | 4 ++-- osu.Game/Scoring/ScoreModelDownloader.cs | 5 ++--- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index f5d57240ca..24824b1e23 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -194,7 +194,7 @@ namespace osu.Game.Tests.Online internal class TestBeatmapModelDownloader : BeatmapModelDownloader { public TestBeatmapModelDownloader(IModelImporter importer, IAPIProvider apiProvider, GameHost gameHost) - : base(importer, apiProvider, gameHost) + : base(importer, apiProvider) { } diff --git a/osu.Game/Beatmaps/BeatmapModelDownloader.cs b/osu.Game/Beatmaps/BeatmapModelDownloader.cs index a170edc9f8..d31730ca15 100644 --- a/osu.Game/Beatmaps/BeatmapModelDownloader.cs +++ b/osu.Game/Beatmaps/BeatmapModelDownloader.cs @@ -1,7 +1,6 @@ // 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.Platform; using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -16,8 +15,8 @@ namespace osu.Game.Beatmaps public override ArchiveDownloadRequest GetExistingDownload(IBeatmapSetInfo model) => CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID); - public BeatmapModelDownloader(IModelImporter beatmapImporter, IAPIProvider api, GameHost host = null) - : base(beatmapImporter, api, host) + public BeatmapModelDownloader(IModelImporter beatmapImporter, IAPIProvider api) + : base(beatmapImporter, api) { } } diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index 43ba62dfe0..362bc68cc1 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading.Tasks; using Humanizer; using osu.Framework.Logging; -using osu.Framework.Platform; using osu.Game.Extensions; using osu.Game.Online.API; using osu.Game.Overlays.Notifications; @@ -29,7 +28,7 @@ namespace osu.Game.Database protected readonly List> CurrentDownloads = new List>(); - protected ModelDownloader(IModelImporter importer, IAPIProvider api, IIpcHost importHost = null) + protected ModelDownloader(IModelImporter importer, IAPIProvider api) { this.importer = importer; this.api = api; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index c0594231df..88c9ab370c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -239,8 +239,8 @@ namespace osu.Game dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, contextFactory, Scheduler, Host, () => difficultyCache, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, performOnlineLookups: true)); - dependencies.Cache(BeatmapDownloader = new BeatmapModelDownloader(BeatmapManager, API, Host)); - dependencies.Cache(ScoreDownloader = new ScoreModelDownloader(ScoreManager, API, Host)); + dependencies.Cache(BeatmapDownloader = new BeatmapModelDownloader(BeatmapManager, API)); + dependencies.Cache(ScoreDownloader = new ScoreModelDownloader(ScoreManager, API)); // the following realm components are not actively used yet, but initialised and kept up to date for initial testing. realmRulesetStore = new RealmRulesetStore(realmFactory, Storage); diff --git a/osu.Game/Scoring/ScoreModelDownloader.cs b/osu.Game/Scoring/ScoreModelDownloader.cs index 6c63e2aa71..038a4bc351 100644 --- a/osu.Game/Scoring/ScoreModelDownloader.cs +++ b/osu.Game/Scoring/ScoreModelDownloader.cs @@ -1,7 +1,6 @@ // 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.Platform; using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -10,8 +9,8 @@ namespace osu.Game.Scoring { public class ScoreModelDownloader : ModelDownloader { - public ScoreModelDownloader(IModelImporter scoreManager, IAPIProvider api, IIpcHost importHost = null) - : base(scoreManager, api, importHost) + public ScoreModelDownloader(IModelImporter scoreManager, IAPIProvider api) + : base(scoreManager, api) { } From a6ee0eec0dcaaed2844adf40fa9d7d54f6633ad1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 18:15:09 +0900 Subject: [PATCH 13/46] Remove pointless interface class for `IBeatmapModelManager` Was originally going to be used but serves no purpose any more. --- osu.Game/Beatmaps/BeatmapModelManager.cs | 2 +- osu.Game/Beatmaps/IBeatmapModelManager.cs | 20 -------------------- 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 osu.Game/Beatmaps/IBeatmapModelManager.cs diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index ae395c6da6..fc25884446 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -32,7 +32,7 @@ namespace osu.Game.Beatmaps /// Handles ef-core storage of beatmaps. /// [ExcludeFromDynamicCompile] - public class BeatmapModelManager : ArchiveModelManager, IBeatmapModelManager + public class BeatmapModelManager : ArchiveModelManager { /// /// Fired when a single difficulty has been hidden. diff --git a/osu.Game/Beatmaps/IBeatmapModelManager.cs b/osu.Game/Beatmaps/IBeatmapModelManager.cs deleted file mode 100644 index 8c243c2b77..0000000000 --- a/osu.Game/Beatmaps/IBeatmapModelManager.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Database; - -namespace osu.Game.Beatmaps -{ - public interface IBeatmapModelManager : IModelManager - { - /// - /// Provide an online lookup queue component to handle populating online beatmap metadata. - /// - BeatmapOnlineLookupQueue OnlineLookupQueue { set; } - - /// - /// Provide a working beatmap cache, used to invalidate entries on changes. - /// - IWorkingBeatmapCache WorkingBeatmapCache { set; } - } -} From e2ebcf7a26f932b5ea0bbd8db285d9c2b46b7971 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Nov 2021 18:36:01 +0900 Subject: [PATCH 14/46] Remove unnecessary manager parameter Confused why I added this in the first place.. --- osu.Game/Database/LegacyBeatmapExporter.cs | 4 ++-- osu.Game/Database/LegacyExporter.cs | 6 +----- osu.Game/Database/LegacyScoreExporter.cs | 4 ++-- osu.Game/Database/LegacySkinExporter.cs | 4 ++-- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 2 +- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 2 +- 7 files changed, 10 insertions(+), 14 deletions(-) diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs index 671ed54326..fb8ee8f5f5 100644 --- a/osu.Game/Database/LegacyBeatmapExporter.cs +++ b/osu.Game/Database/LegacyBeatmapExporter.cs @@ -10,8 +10,8 @@ namespace osu.Game.Database { protected override string FileExtension => ".osz"; - public LegacyBeatmapExporter(Storage storage, IModelManager manager) - : base(storage, manager) + public LegacyBeatmapExporter(Storage storage) + : base(storage) { } } diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 846495b1ed..802ccec6ed 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -19,16 +19,12 @@ namespace osu.Game.Database /// protected abstract string FileExtension { get; } - protected readonly IModelManager Manager; - protected readonly Storage UserFileStorage; private readonly Storage exportStorage; - protected LegacyExporter(Storage storage, IModelManager manager) + protected LegacyExporter(Storage storage) { - Manager = manager; - exportStorage = storage.GetStorageForDirectory(@"exports"); UserFileStorage = storage.GetStorageForDirectory(@"files"); } diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs index e4ddd5982b..41f8516880 100644 --- a/osu.Game/Database/LegacyScoreExporter.cs +++ b/osu.Game/Database/LegacyScoreExporter.cs @@ -13,8 +13,8 @@ namespace osu.Game.Database { protected override string FileExtension => ".osr"; - public LegacyScoreExporter(Storage storage, IModelManager manager) - : base(storage, manager) + public LegacyScoreExporter(Storage storage) + : base(storage) { } diff --git a/osu.Game/Database/LegacySkinExporter.cs b/osu.Game/Database/LegacySkinExporter.cs index f6d243315c..9432a1b5fc 100644 --- a/osu.Game/Database/LegacySkinExporter.cs +++ b/osu.Game/Database/LegacySkinExporter.cs @@ -10,8 +10,8 @@ namespace osu.Game.Database { protected override string FileExtension => ".osk"; - public LegacySkinExporter(Storage storage, IModelManager manager) - : base(storage, manager) + public LegacySkinExporter(Storage storage) + : base(storage) { } } diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 06c0636d17..e01c7c9e49 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -400,7 +400,7 @@ namespace osu.Game.Online.Leaderboards items.Add(new OsuMenuItem("Use these mods", MenuItemType.Highlighted, () => songSelect.Mods.Value = Score.Mods)); if (Score.Files.Count > 0) - items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => new LegacyScoreExporter(storage, scoreManager).Export(Score))); + items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => new LegacyScoreExporter(storage).Export(Score))); if (Score.ID != 0) items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 0eec6f5f77..0eb65b4b0f 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -188,7 +188,7 @@ namespace osu.Game.Overlays.Settings.Sections { try { - new LegacySkinExporter(storage, skins).Export(currentSkin.Value.SkinInfo); + new LegacySkinExporter(storage).Export(currentSkin.Value.SkinInfo); } catch (Exception e) { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 46d84fe73d..ac71298f36 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -758,7 +758,7 @@ namespace osu.Game.Screens.Edit private void exportBeatmap() { Save(); - new LegacyBeatmapExporter(storage, beatmapManager).Export(Beatmap.Value.BeatmapSetInfo); + new LegacyBeatmapExporter(storage).Export(Beatmap.Value.BeatmapSetInfo); } private void updateLastSavedHash() From 8baf00c0231c3276f497257fd810c36cc3f82109 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Nov 2021 19:36:06 +0900 Subject: [PATCH 15/46] Remove unused using --- osu.Game/Scoring/ScoreManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index cb2659442d..1564b3bcc5 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Linq.Expressions; using System.Threading; From 09dd0542836a83bc411b99dfb6f46db01b30fbf8 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Nov 2021 21:11:13 +0900 Subject: [PATCH 16/46] Fix SongSelect-related test failures --- .../Visual/Editing/TestSceneEditorSaving.cs | 5 ++++- .../Multiplayer/TestSceneAllPlayersQueueMode.cs | 2 +- .../Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs | 2 +- .../Visual/Multiplayer/TestSceneMultiplayer.cs | 2 +- .../TestSceneMultiplayerMatchSongSelect.cs | 2 +- .../Multiplayer/TestScenePlaylistsSongSelect.cs | 2 +- .../Visual/Navigation/TestSceneScreenNavigation.cs | 12 +++++++++--- osu.Game/Screens/Select/SongSelect.cs | 2 ++ 8 files changed, 20 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index e1e869cfbf..f89be0adf3 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -69,7 +69,10 @@ namespace osu.Game.Tests.Visual.Editing AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu); - PushAndConfirm(() => new PlaySongSelect()); + Screens.Select.SongSelect songSelect = null; + + PushAndConfirm(() => songSelect = new PlaySongSelect()); + AddUntilStep("wait for carousel load", () => songSelect.BeatmapSetsLoaded); AddUntilStep("Wait for beatmap selected", () => !Game.Beatmap.IsDefault); AddStep("Open options", () => InputManager.Key(Key.F3)); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs index dcb01b83cc..85982682c6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.IsLoaded); + AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded); AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(beatmap())); AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs index efa5c481ed..1de7289446 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.IsLoaded); + AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded); BeatmapInfo otherBeatmap = null; AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(otherBeatmap = beatmap())); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index c4833b5226..027769995a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -204,7 +204,7 @@ namespace osu.Game.Tests.Visual.Multiplayer // edit playlist item AddStep("Press select", () => InputManager.Key(Key.Enter)); - AddUntilStep("wait for song select", () => InputManager.ChildrenOfType().FirstOrDefault() != null); + AddUntilStep("wait for song select", () => InputManager.ChildrenOfType().FirstOrDefault()?.BeatmapSetsLoaded == true); // select beatmap AddStep("Press select", () => InputManager.Key(Key.Enter)); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs index 6b67a979e5..84b24ba3a1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Multiplayer }); AddStep("create song select", () => LoadScreen(songSelect = new TestMultiplayerMatchSongSelect(SelectedRoom.Value))); - AddUntilStep("wait for present", () => songSelect.IsCurrentScreen()); + AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded); } [Test] diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs index 6d761105c1..35c66e8cda 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs @@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Multiplayer }); AddStep("create song select", () => LoadScreen(songSelect = new TestPlaylistsSongSelect(SelectedRoom.Value))); - AddUntilStep("wait for present", () => songSelect.IsCurrentScreen()); + AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded); } [Test] diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 497c68cf2e..664c186cf8 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -66,7 +66,9 @@ namespace osu.Game.Tests.Visual.Navigation { Player player = null; - PushAndConfirm(() => new TestPlaySongSelect()); + Screens.Select.SongSelect songSelect = null; + PushAndConfirm(() => songSelect = new TestPlaySongSelect()); + AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded); AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait()); @@ -98,7 +100,9 @@ namespace osu.Game.Tests.Visual.Navigation IWorkingBeatmap beatmap() => Game.Beatmap.Value; - PushAndConfirm(() => new TestPlaySongSelect()); + Screens.Select.SongSelect songSelect = null; + PushAndConfirm(() => songSelect = new TestPlaySongSelect()); + AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded); AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait()); @@ -130,7 +134,9 @@ namespace osu.Game.Tests.Visual.Navigation IWorkingBeatmap beatmap() => Game.Beatmap.Value; - PushAndConfirm(() => new TestPlaySongSelect()); + Screens.Select.SongSelect songSelect = null; + PushAndConfirm(() => songSelect = new TestPlaySongSelect()); + AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded); AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).Wait()); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 2c36bf5fc8..045a8fbe54 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -76,6 +76,8 @@ namespace osu.Game.Screens.Select /// public virtual bool AllowEditing => true; + public bool BeatmapSetsLoaded => IsLoaded && Carousel?.BeatmapSetsLoaded == true; + [Resolved] private Bindable> selectedMods { get; set; } From 8a941fa42206becffc9a8059c0ce11f9b76d0806 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Nov 2021 21:41:03 +0900 Subject: [PATCH 17/46] Add owner id to PlaylistItem --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 1 + osu.Game/Online/Rooms/PlaylistItem.cs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 5c339c5d55..4c472164d6 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -718,6 +718,7 @@ namespace osu.Game.Online.Multiplayer var playlistItem = new PlaylistItem { ID = item.ID, + OwnerID = item.OwnerID, Beatmap = { Value = beatmap }, Ruleset = { Value = ruleset }, Expired = item.Expired diff --git a/osu.Game/Online/Rooms/PlaylistItem.cs b/osu.Game/Online/Rooms/PlaylistItem.cs index c889dc514b..a1480865b8 100644 --- a/osu.Game/Online/Rooms/PlaylistItem.cs +++ b/osu.Game/Online/Rooms/PlaylistItem.cs @@ -18,6 +18,9 @@ namespace osu.Game.Online.Rooms [JsonProperty("id")] public long ID { get; set; } + [JsonProperty("owner_id")] + public int OwnerID { get; set; } + [JsonProperty("beatmap_id")] public int BeatmapID { get; set; } From d0c0b7ce476971c039bf8ad5d6dd9e325b975ea5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Nov 2021 22:05:39 +0900 Subject: [PATCH 18/46] Fix intermittent beatmap thumbnail test --- .../Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs index 1b4542d946..a5b52f75f6 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs @@ -70,6 +70,11 @@ namespace osu.Game.Tests.Visual.Beatmaps AddWaitStep("wait some", 3); AddAssert("button still visible", () => playButton.IsPresent); + // The track plays in real-time, so we need to check for progress in increments to avoid timeout. + AddUntilStep("progress > 0.25", () => thumbnail.ChildrenOfType().Single().Progress.Value > 0.25); + AddUntilStep("progress > 0.5", () => thumbnail.ChildrenOfType().Single().Progress.Value > 0.5); + AddUntilStep("progress > 0.75", () => thumbnail.ChildrenOfType().Single().Progress.Value > 0.75); + AddUntilStep("wait for track to end", () => !playButton.Playing.Value); AddUntilStep("button hidden", () => !playButton.IsPresent); } From 7c91cd674e2eb01704a512ae6a0facfcea92a028 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Nov 2021 22:17:18 +0900 Subject: [PATCH 19/46] Update test classes to set owner ids --- osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs | 6 +++++- osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index b54e243bde..2d77e17513 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -299,7 +299,7 @@ namespace osu.Game.Tests.Visual.Multiplayer return ((IMultiplayerClient)this).LoadRequested(); } - public override async Task AddPlaylistItem(MultiplayerPlaylistItem item) + public async Task AddUserPlaylistItem(int userId, MultiplayerPlaylistItem item) { Debug.Assert(Room != null); Debug.Assert(APIRoom != null); @@ -313,6 +313,7 @@ namespace osu.Game.Tests.Visual.Multiplayer case QueueMode.HostOnly: // In host-only mode, the current item is re-used. item.ID = currentItem.ID; + item.OwnerID = currentItem.OwnerID; serverSidePlaylist[currentIndex] = item; await ((IMultiplayerClient)this).PlaylistItemChanged(item).ConfigureAwait(false); @@ -323,6 +324,7 @@ namespace osu.Game.Tests.Visual.Multiplayer default: item.ID = serverSidePlaylist.Last().ID + 1; + item.OwnerID = userId; serverSidePlaylist.Add(item); await ((IMultiplayerClient)this).PlaylistItemAdded(item).ConfigureAwait(false); @@ -332,6 +334,8 @@ namespace osu.Game.Tests.Visual.Multiplayer } } + public override Task AddPlaylistItem(MultiplayerPlaylistItem item) => AddUserPlaylistItem(api.LocalUser.Value.OnlineID, item); + protected override Task GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default) { IBeatmapSetInfo? set = roomManager.ServerSideRooms.SelectMany(r => r.Playlist) diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs index dc12e48297..0b7d9af5e7 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -128,8 +128,12 @@ namespace osu.Game.Tests.Visual.OnlinePlay public void AddServerSideRoom(Room room) { room.RoomID.Value ??= currentRoomId++; + for (int i = 0; i < room.Playlist.Count; i++) + { room.Playlist[i].ID = currentPlaylistItemId++; + room.Playlist[i].OwnerID = room.Host.Value.OnlineID; + } serverSideRooms.Add(room); } From 1f5d95666e660557d825f52bb9ef6d0a29c18b6b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Nov 2021 23:15:28 +0900 Subject: [PATCH 20/46] Add owner avatar to multiplayer items --- .../TestSceneDrawableRoomPlaylist.cs | 6 ++ .../OnlinePlay/DrawableRoomPlaylistItem.cs | 57 +++++++++++++++++-- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 1d0401832f..b0174104f7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -13,6 +13,7 @@ using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; +using osu.Game.Database; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; @@ -34,6 +35,9 @@ namespace osu.Game.Tests.Visual.Multiplayer private BeatmapManager manager; private RulesetStore rulesets; + [Cached(typeof(UserLookupCache))] + private readonly TestUserLookupCache userLookupCache = new TestUserLookupCache(); + [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { @@ -343,6 +347,7 @@ namespace osu.Game.Tests.Visual.Multiplayer playlist.Items.Add(new PlaylistItem { ID = i, + OwnerID = 2, Beatmap = { Value = i % 2 == 1 @@ -390,6 +395,7 @@ namespace osu.Game.Tests.Visual.Multiplayer playlist.Items.Add(new PlaylistItem { ID = index++, + OwnerID = 2, Beatmap = { Value = b }, Ruleset = { Value = new OsuRuleset().RulesetInfo }, RequiredMods = diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 5a86161b50..5b90713148 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -4,17 +4,21 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; +using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -26,6 +30,7 @@ using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play.HUD; +using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; @@ -34,6 +39,7 @@ namespace osu.Game.Screens.OnlinePlay public class DrawableRoomPlaylistItem : OsuRearrangeableListItem { public const float HEIGHT = 50; + public const float ICON_HEIGHT = 34; public Action RequestDeletion; @@ -45,6 +51,7 @@ namespace osu.Game.Screens.OnlinePlay private LinkFlowContainer authorText; private ExplicitContentBeatmapPill explicitContentPill; private ModDisplay modDisplay; + private UpdateableAvatar ownerAvatar; private readonly IBindable valid = new Bindable(); @@ -54,6 +61,12 @@ namespace osu.Game.Screens.OnlinePlay public readonly PlaylistItem Item; + [Resolved] + private OsuColour colours { get; set; } + + [Resolved] + private UserLookupCache userLookupCache { get; set; } + private readonly bool allowEdit; private readonly bool allowSelection; @@ -79,9 +92,6 @@ namespace osu.Game.Screens.OnlinePlay Colour = OsuColour.Gray(0.5f); } - [Resolved] - private OsuColour colours { get; set; } - [BackgroundDependencyLoader] private void load() { @@ -132,7 +142,8 @@ namespace osu.Game.Screens.OnlinePlay maskingContainer.BorderColour = colours.Red; } - difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) }; + userLookupCache.GetUserAsync(Item.OwnerID).ContinueWith(u => Schedule(() => ownerAvatar.User = u.Result), TaskContinuationOptions.OnlyOnRanToCompletion); + difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(ICON_HEIGHT) }; panelBackground.Beatmap.Value = Item.Beatmap.Value; @@ -183,6 +194,7 @@ namespace osu.Game.Screens.OnlinePlay RelativeSizeAxes = Axes.Both, ColumnDimensions = new[] { + new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.AutoSize), new Dimension(), new Dimension(GridSizeMode.AutoSize), @@ -191,12 +203,21 @@ namespace osu.Game.Screens.OnlinePlay { new Drawable[] { + ownerAvatar = new OwnerAvatar + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(ICON_HEIGHT), + Margin = new MarginPadding { Left = 8, Right = 8, }, + Masking = true, + CornerRadius = 4, + }, difficultyIconContainer = new Container { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Left = 8, Right = 8, }, + Margin = new MarginPadding { Right = 8 }, }, new FillFlowContainer { @@ -417,5 +438,31 @@ namespace osu.Game.Screens.OnlinePlay Beatmap.BindValueChanged(beatmap => backgroundSprite.Beatmap.Value = beatmap.NewValue); } } + + private class OwnerAvatar : UpdateableAvatar, IHasTooltip + { + public OwnerAvatar() + { + AddInternal(new TooltipArea(this) + { + RelativeSizeAxes = Axes.Both, + Depth = -1 + }); + } + + public LocalisableString TooltipText => User == null ? "loading user..." : $"queued by {User.Username}"; + + private class TooltipArea : Component, IHasTooltip + { + private readonly OwnerAvatar avatar; + + public TooltipArea(OwnerAvatar avatar) + { + this.avatar = avatar; + } + + public LocalisableString TooltipText => avatar.TooltipText; + } + } } } From 84a36ab4a9c6af5c2a310b4e5233e940fc65f546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Oct 2021 16:48:54 +0200 Subject: [PATCH 21/46] Add integration with beatmap set overlay --- .../Beatmaps/Drawables/Cards/BeatmapCard.cs | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs index 4ffad0f065..76b1166626 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable enable + using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -41,27 +43,23 @@ namespace osu.Game.Beatmaps.Drawables.Cards private readonly BeatmapDownloadTracker downloadTracker; - private BeatmapCardThumbnail thumbnail; - private FillFlowContainer leftIconArea; + private BeatmapCardThumbnail thumbnail = null!; - private Container rightAreaBackground; - private Container rightAreaButtons; + private Container rightAreaBackground = null!; + private Container rightAreaButtons = null!; - private Container mainContent; - private BeatmapCardContentBackground mainContentBackground; + private Container mainContent = null!; + private BeatmapCardContentBackground mainContentBackground = null!; + private FillFlowContainer statisticsContainer = null!; - private GridContainer titleContainer; - private GridContainer artistContainer; - private FillFlowContainer statisticsContainer; - - private FillFlowContainer idleBottomContent; - private BeatmapCardDownloadProgressBar downloadProgressBar; + private FillFlowContainer idleBottomContent = null!; + private BeatmapCardDownloadProgressBar downloadProgressBar = null!; [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; [Resolved] - private OverlayColourProvider colourProvider { get; set; } + private OverlayColourProvider colourProvider { get; set; } = null!; public BeatmapCard(APIBeatmapSet beatmapSet) : base(HoverSampleSet.Submit) @@ -71,14 +69,18 @@ namespace osu.Game.Beatmaps.Drawables.Cards downloadTracker = new BeatmapDownloadTracker(beatmapSet); } - [BackgroundDependencyLoader] - private void load() + [BackgroundDependencyLoader(true)] + private void load(BeatmapSetOverlay? beatmapSetOverlay) { Width = width; Height = height; CornerRadius = corner_radius; Masking = true; + FillFlowContainer leftIconArea; + GridContainer titleContainer; + GridContainer artistContainer; + InternalChildren = new Drawable[] { downloadTracker, @@ -335,6 +337,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards Margin = new MarginPadding { Left = 5 } }; } + + Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmapSet.OnlineID); } protected override void LoadComplete() From 0f9ebe3d5d9b0c9a4e213b5c9ea12fbb4ae9e817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Oct 2021 16:55:05 +0200 Subject: [PATCH 22/46] Use beatmap cards in beatmap listing overlay --- .../BeatmapListing/BeatmapListingFilterControl.cs | 2 +- osu.Game/Overlays/BeatmapListingOverlay.cs | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index fa57191ef3..38f2bdb34f 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -119,7 +119,7 @@ namespace osu.Game.Overlays.BeatmapListing [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - sortControlBackground.Colour = colourProvider.Background5; + sortControlBackground.Colour = colourProvider.Background4; } public void Search(string query) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index e08af52a72..49f2f5c211 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -15,12 +15,11 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Events; using osu.Game.Audio; +using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Containers; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapListing; -using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; @@ -34,7 +33,7 @@ namespace osu.Game.Overlays private Drawable currentContent; private Container panelTarget; - private FillFlowContainer foundContent; + private FillFlowContainer foundContent; private NotFoundDrawable notFoundContent; private SupporterRequiredDrawable supporterRequiredContent; private BeatmapListingFilterControl filterControl; @@ -69,7 +68,7 @@ namespace osu.Game.Overlays new Box { RelativeSizeAxes = Axes.Both, - Colour = ColourProvider.Background4, + Colour = ColourProvider.Background5, }, panelTarget = new Container { @@ -79,7 +78,7 @@ namespace osu.Game.Overlays Padding = new MarginPadding { Horizontal = 20 }, Children = new Drawable[] { - foundContent = new FillFlowContainer(), + foundContent = new FillFlowContainer(), notFoundContent = new NotFoundDrawable(), supporterRequiredContent = new SupporterRequiredDrawable(), } @@ -136,7 +135,7 @@ namespace osu.Game.Overlays return; } - var newPanels = searchResult.Results.Select(b => new GridBeatmapPanel(b) + var newPanels = searchResult.Results.Select(b => new BeatmapCard(b) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -152,7 +151,7 @@ namespace osu.Game.Overlays } // spawn new children with the contained so we only clear old content at the last moment. - var content = new FillFlowContainer + var content = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, From 42b09fd1ece244ba589df58ec8fccbdd16cf5795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 24 Oct 2021 19:20:57 +0200 Subject: [PATCH 23/46] Use beatmap cards in user profile overlay --- .../Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 36b94283e5..e46e503dfa 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -6,10 +6,10 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Localisation; +using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays.BeatmapListing.Panels; using osuTK; using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; @@ -61,7 +61,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0 - ? new GridBeatmapPanel(model) + ? new BeatmapCard(model) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, From ec2265d5bbddc2690fcb028be0dc44d96ec7f051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 24 Oct 2021 19:21:46 +0200 Subject: [PATCH 24/46] Use beatmap cards in spotlights layout --- osu.Game/Overlays/Rankings/SpotlightsLayout.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs index b95b0a1afc..cc553ad361 100644 --- a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs +++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs @@ -13,9 +13,9 @@ using osu.Game.Online.API.Requests; using osu.Game.Overlays.Rankings.Tables; using System.Linq; using System.Threading; +using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Overlays.BeatmapListing.Panels; namespace osu.Game.Overlays.Rankings { @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.Rankings AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, Spacing = new Vector2(10), - Children = response.BeatmapSets.Select(b => new GridBeatmapPanel(b) + Children = response.BeatmapSets.Select(b => new BeatmapCard(b) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, From a188d6662fa72452f82b94815be841b5be558f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 24 Oct 2021 19:44:32 +0200 Subject: [PATCH 25/46] Use beatmap card in solo spectator screen --- osu.Game/Screens/Play/SoloSpectator.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/SoloSpectator.cs b/osu.Game/Screens/Play/SoloSpectator.cs index 5ecdb91718..45601999a0 100644 --- a/osu.Game/Screens/Play/SoloSpectator.cs +++ b/osu.Game/Screens/Play/SoloSpectator.cs @@ -12,6 +12,7 @@ using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Audio; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -20,7 +21,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Spectator; -using osu.Game.Overlays.BeatmapListing.Panels; +using osu.Game.Overlays; using osu.Game.Overlays.Settings; using osu.Game.Rulesets; using osu.Game.Screens.OnlinePlay.Match.Components; @@ -52,6 +53,9 @@ namespace osu.Game.Screens.Play [Resolved] private BeatmapModelDownloader beatmapDownloader { get; set; } + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + private Container beatmapPanelContainer; private TriangleButton watchButton; private SettingsCheckbox automaticDownload; @@ -73,7 +77,7 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader] - private void load(OsuColour colours, OsuConfigManager config) + private void load(OsuConfigManager config) { InternalChild = new Container { @@ -88,7 +92,7 @@ namespace osu.Game.Screens.Play { new Box { - Colour = colours.GreySeafoamDark, + Colour = colourProvider.Background5, RelativeSizeAxes = Axes.Both, }, new FillFlowContainer @@ -229,7 +233,7 @@ namespace osu.Game.Screens.Play onlineBeatmapRequest.Success += beatmapSet => Schedule(() => { this.beatmapSet = beatmapSet; - beatmapPanelContainer.Child = new GridBeatmapPanel(this.beatmapSet); + beatmapPanelContainer.Child = new BeatmapCard(this.beatmapSet); checkForAutomaticDownload(); }); From 1d96542a2ac430d75e3d6177d3f503775e13577d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 12:19:24 +0900 Subject: [PATCH 26/46] Fix incorrect `ConfigureAwait` specification causing stalled test This only occurs on upcoming changes I have (occurred when switching existing skin import tests across to realm). Unsure why it was set to `true`, seems like a weird oversight. --- osu.Game/Stores/RealmArchiveModelImporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Stores/RealmArchiveModelImporter.cs b/osu.Game/Stores/RealmArchiveModelImporter.cs index 6370d4ebe4..b74670e722 100644 --- a/osu.Game/Stores/RealmArchiveModelImporter.cs +++ b/osu.Game/Stores/RealmArchiveModelImporter.cs @@ -253,7 +253,7 @@ namespace osu.Game.Stores var scheduledImport = Task.Factory.StartNew(async () => await Import(model, archive, lowPriority, cancellationToken).ConfigureAwait(false), cancellationToken, TaskCreationOptions.HideScheduler, lowPriority ? import_scheduler_low_priority : import_scheduler).Unwrap(); - return await scheduledImport.ConfigureAwait(true); + return await scheduledImport.ConfigureAwait(false); } /// From 13612c0d02b0b1d94d3b8b293c025757a452cf01 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 14:38:39 +0900 Subject: [PATCH 27/46] Add equality support to `ILive` types --- osu.Game.Tests/Database/RealmLiveTests.cs | 9 ++++----- osu.Game/Database/EntityFrameworkLive.cs | 4 ++++ osu.Game/Database/ILive.cs | 3 ++- osu.Game/Database/IPostImports.cs | 2 +- osu.Game/Database/RealmLive.cs | 2 ++ 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs index 33aa1afb89..41a81382f8 100644 --- a/osu.Game.Tests/Database/RealmLiveTests.cs +++ b/osu.Game.Tests/Database/RealmLiveTests.cs @@ -6,7 +6,6 @@ using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using NUnit.Framework; -using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Models; using Realms; @@ -18,15 +17,15 @@ namespace osu.Game.Tests.Database public class RealmLiveTests : RealmTest { [Test] - public void TestLiveCastability() + public void TestLiveEquality() { RunTestWithRealm((realmFactory, _) => { - RealmLive beatmap = realmFactory.CreateContext().Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata()))).ToLive(); + ILive beatmap = realmFactory.CreateContext().Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata()))).ToLive(); - ILive iBeatmap = beatmap; + ILive beatmap2 = realmFactory.CreateContext().All().First().ToLive(); - Assert.AreEqual(0, iBeatmap.Value.Length); + Assert.AreEqual(beatmap, beatmap2); }); } diff --git a/osu.Game/Database/EntityFrameworkLive.cs b/osu.Game/Database/EntityFrameworkLive.cs index 1d7b53911a..0fe8fea1ff 100644 --- a/osu.Game/Database/EntityFrameworkLive.cs +++ b/osu.Game/Database/EntityFrameworkLive.cs @@ -3,6 +3,8 @@ using System; +#nullable enable + namespace osu.Game.Database { public class EntityFrameworkLive : ILive where T : class @@ -30,5 +32,7 @@ namespace osu.Game.Database } public T Value { get; } + + public bool Equals(ILive? other) => ID == other?.ID; } } diff --git a/osu.Game/Database/ILive.cs b/osu.Game/Database/ILive.cs index 9359b09eaf..ed2b926782 100644 --- a/osu.Game/Database/ILive.cs +++ b/osu.Game/Database/ILive.cs @@ -9,7 +9,8 @@ namespace osu.Game.Database /// A wrapper to provide access to database backed classes in a thread-safe manner. /// /// The databased type. - public interface ILive where T : class // TODO: Add IHasGuidPrimaryKey once we don't need EF support any more. + public interface ILive : IEquatable> + where T : class // TODO: Add IHasGuidPrimaryKey once we don't need EF support any more. { Guid ID { get; } diff --git a/osu.Game/Database/IPostImports.cs b/osu.Game/Database/IPostImports.cs index b3b83f23ef..adb3a7108d 100644 --- a/osu.Game/Database/IPostImports.cs +++ b/osu.Game/Database/IPostImports.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; namespace osu.Game.Database { - public interface IPostImports + public interface IPostImports where TModel : class { /// diff --git a/osu.Game/Database/RealmLive.cs b/osu.Game/Database/RealmLive.cs index abb69644d6..d988a81739 100644 --- a/osu.Game/Database/RealmLive.cs +++ b/osu.Game/Database/RealmLive.cs @@ -107,5 +107,7 @@ namespace osu.Game.Database // this matches realm's internal thread validation (see https://github.com/realm/realm-dotnet/blob/903b4d0b304f887e37e2d905384fb572a6496e70/Realm/Realm/Native/SynchronizationContextScheduler.cs#L72) private bool isCorrectThread => (fetchedContext != null && SynchronizationContext.Current == fetchedContext) || fetchedThreadId == Thread.CurrentThread.ManagedThreadId; + + public bool Equals(ILive? other) => ID == other?.ID; } } From 40d1b97af10fa5d5a6f8a70f4d65886da78181cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 14:39:35 +0900 Subject: [PATCH 28/46] Avoid attempting to fetch a non-managed `RealmLive` instance from the realm backing For compatibility reasons, we quite often convert completely unmanaged instances to `ILive`s so they fit the required parameters of a property or method call. This ensures such cases will not cause any issues when trying to interact with the underlying data. Originally I had this allowing write operations, but that seems a bit unsafe (when performing a write one would assume that the underlying data is being persisted, whereas in this case it is not). We can change this if the requirements change in the future, but I think throwing is the safest bet for now. --- osu.Game.Tests/Database/RealmLiveTests.cs | 17 +++++++++++++++++ osu.Game/Database/EntityFrameworkLive.cs | 3 +++ osu.Game/Database/ILive.cs | 5 +++++ osu.Game/Database/RealmLive.cs | 20 ++++++++++++++++---- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs index 33aa1afb89..4f7681e3ae 100644 --- a/osu.Game.Tests/Database/RealmLiveTests.cs +++ b/osu.Game.Tests/Database/RealmLiveTests.cs @@ -30,6 +30,23 @@ namespace osu.Game.Tests.Database }); } + [Test] + public void TestAccessNonManaged() + { + var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata()); + var liveBeatmap = beatmap.ToLive(); + + Assert.IsFalse(beatmap.Hidden); + Assert.IsFalse(liveBeatmap.Value.Hidden); + Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden)); + + Assert.Throws(() => liveBeatmap.PerformWrite(l => l.Hidden = true)); + + Assert.IsFalse(beatmap.Hidden); + Assert.IsFalse(liveBeatmap.Value.Hidden); + Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden)); + } + [Test] public void TestValueAccessWithOpenContext() { diff --git a/osu.Game/Database/EntityFrameworkLive.cs b/osu.Game/Database/EntityFrameworkLive.cs index 1d7b53911a..e4507b8d3b 100644 --- a/osu.Game/Database/EntityFrameworkLive.cs +++ b/osu.Game/Database/EntityFrameworkLive.cs @@ -9,6 +9,7 @@ namespace osu.Game.Database { public EntityFrameworkLive(T item) { + IsManaged = true; // no way to really know. Value = item; } @@ -29,6 +30,8 @@ namespace osu.Game.Database perform(Value); } + public bool IsManaged { get; } + public T Value { get; } } } diff --git a/osu.Game/Database/ILive.cs b/osu.Game/Database/ILive.cs index 9359b09eaf..ae287f1f6f 100644 --- a/osu.Game/Database/ILive.cs +++ b/osu.Game/Database/ILive.cs @@ -31,6 +31,11 @@ namespace osu.Game.Database /// The action to perform. void PerformWrite(Action perform); + /// + /// Whether this instance is tracking data which is managed by the database backing. + /// + bool IsManaged { get; } + /// /// Resolve the value of this instance on the current thread's context. /// diff --git a/osu.Game/Database/RealmLive.cs b/osu.Game/Database/RealmLive.cs index abb69644d6..fe631a9964 100644 --- a/osu.Game/Database/RealmLive.cs +++ b/osu.Game/Database/RealmLive.cs @@ -17,6 +17,8 @@ namespace osu.Game.Database { public Guid ID { get; } + public bool IsManaged { get; } + private readonly SynchronizationContext? fetchedContext; private readonly int fetchedThreadId; @@ -33,8 +35,13 @@ namespace osu.Game.Database { this.data = data; - fetchedContext = SynchronizationContext.Current; - fetchedThreadId = Thread.CurrentThread.ManagedThreadId; + if (data.IsManaged) + { + IsManaged = true; + + fetchedContext = SynchronizationContext.Current; + fetchedThreadId = Thread.CurrentThread.ManagedThreadId; + } ID = data.ID; } @@ -75,13 +82,18 @@ namespace osu.Game.Database /// Perform a write operation on this live object. /// /// The action to perform. - public void PerformWrite(Action perform) => + public void PerformWrite(Action perform) + { + if (!IsManaged) + throw new InvalidOperationException("Can't perform writes on a non-managed underlying value"); + PerformRead(t => { var transaction = t.Realm.BeginWrite(); perform(t); transaction.Commit(); }); + } public T Value { @@ -102,7 +114,7 @@ namespace osu.Game.Database } } - private bool originalDataValid => isCorrectThread && data.IsValid; + private bool originalDataValid => !IsManaged || (isCorrectThread && data.IsValid); // this matches realm's internal thread validation (see https://github.com/realm/realm-dotnet/blob/903b4d0b304f887e37e2d905384fb572a6496e70/Realm/Realm/Native/SynchronizationContextScheduler.cs#L72) private bool isCorrectThread From 5de2f6211d72a7d1820e223faa6d076ad7349f8f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 15:32:33 +0900 Subject: [PATCH 29/46] Show a spinner instead of the download button on the new card during beatmap download --- .../Cards/Buttons/BeatmapCardIconButton.cs | 6 +- .../Drawables/Cards/Buttons/DownloadButton.cs | 56 ++++++++++++++----- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index ad9caf7e34..e362e3abeb 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -54,6 +54,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons protected readonly SpriteIcon Icon; + protected override Container Content => content; + private readonly Container content; protected BeatmapCardIconButton() @@ -61,7 +63,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons Origin = Anchor.Centre; Anchor = Anchor.Centre; - Child = content = new Container + base.Content.Add(content = new Container { RelativeSizeAxes = Axes.Both, Masking = true, @@ -75,7 +77,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons Anchor = Anchor.Centre } } - }; + }); Size = new Vector2(24); IconSize = 12; diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs index 1a514c8d36..150a5b1d15 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs @@ -3,14 +3,17 @@ #nullable enable +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Resources.Localisation.Web; +using osuTK; namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { @@ -23,6 +26,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons private Bindable preferNoVideo = null!; + private readonly LoadingSpinner spinner; + [Resolved] private BeatmapModelDownloader beatmaps { get; set; } = null!; @@ -30,6 +35,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { Icon.Icon = FontAwesome.Solid.Download; + Content.Add(spinner = new LoadingSpinner { Size = new Vector2(IconSize) }); + this.beatmapSet = beatmapSet; } @@ -49,21 +56,44 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons private void updateState() { - this.FadeTo(state.Value != DownloadState.LocallyAvailable ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); - - if (beatmapSet.Availability.DownloadDisabled) + switch (state.Value) { - Enabled.Value = false; - TooltipText = BeatmapsetsStrings.AvailabilityDisabled; - return; + case DownloadState.Downloading: + case DownloadState.Importing: + Action = null; + TooltipText = string.Empty; + spinner.Show(); + Icon.Hide(); + return; + + case DownloadState.LocallyAvailable: + Action = null; + TooltipText = string.Empty; + this.FadeOut(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + break; + + case DownloadState.NotDownloaded: + if (beatmapSet.Availability.DownloadDisabled) + { + Enabled.Value = false; + TooltipText = BeatmapsetsStrings.AvailabilityDisabled; + return; + } + + Action = () => beatmaps.Download(beatmapSet, preferNoVideo.Value); + this.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + spinner.Hide(); + Icon.Show(); + + if (!beatmapSet.HasVideo) + TooltipText = BeatmapsetsStrings.PanelDownloadAll; + else + TooltipText = preferNoVideo.Value ? BeatmapsetsStrings.PanelDownloadNoVideo : BeatmapsetsStrings.PanelDownloadVideo; + break; + + default: + throw new InvalidOperationException($"Unknown {nameof(DownloadState)} specified."); } - - if (!beatmapSet.HasVideo) - TooltipText = BeatmapsetsStrings.PanelDownloadAll; - else - TooltipText = preferNoVideo.Value ? BeatmapsetsStrings.PanelDownloadNoVideo : BeatmapsetsStrings.PanelDownloadVideo; - - Action = () => beatmaps.Download(beatmapSet, preferNoVideo.Value); } } } From bf443a5a7a447b05c2cbed666022ae78d688568c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 15:36:16 +0900 Subject: [PATCH 30/46] Switch unnecessary `return` to `break` instead --- osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs index 150a5b1d15..c94e335e8f 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs @@ -64,7 +64,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons TooltipText = string.Empty; spinner.Show(); Icon.Hide(); - return; + break; case DownloadState.LocallyAvailable: Action = null; From 8be2defd09d018bfe4df29373005b6badda0844a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 26 Nov 2021 17:17:06 +0900 Subject: [PATCH 31/46] Right-align avatar --- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 5b90713148..6c518616e2 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -194,30 +194,21 @@ namespace osu.Game.Screens.OnlinePlay RelativeSizeAxes = Axes.Both, ColumnDimensions = new[] { - new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.AutoSize), new Dimension(), new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize) }, Content = new[] { new Drawable[] { - ownerAvatar = new OwnerAvatar - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(ICON_HEIGHT), - Margin = new MarginPadding { Left = 8, Right = 8, }, - Masking = true, - CornerRadius = 4, - }, difficultyIconContainer = new Container { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Right = 8 }, + Margin = new MarginPadding { Left = 8, Right = 8 }, }, new FillFlowContainer { @@ -280,7 +271,7 @@ namespace osu.Game.Screens.OnlinePlay Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Direction = FillDirection.Horizontal, - Margin = new MarginPadding { Left = 8, Right = 10, }, + Margin = new MarginPadding { Left = 8 }, AutoSizeAxes = Axes.Both, Spacing = new Vector2(5), ChildrenEnumerable = CreateButtons().Select(button => button.With(b => @@ -288,7 +279,16 @@ namespace osu.Game.Screens.OnlinePlay b.Anchor = Anchor.Centre; b.Origin = Anchor.Centre; })) - } + }, + ownerAvatar = new OwnerAvatar + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(ICON_HEIGHT), + Margin = new MarginPadding { Left = 8, Right = 8, }, + Masking = true, + CornerRadius = 4, + }, } } }, From e9a19aacd7c1551dbcfb57573ec86cda82109c28 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 26 Nov 2021 17:23:50 +0900 Subject: [PATCH 32/46] Fix tests by requiring host --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs | 8 ++++---- .../Visual/Multiplayer/TestMultiplayerRoomManager.cs | 4 +++- .../Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs | 6 ++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 027769995a..4521a7fa0f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -253,7 +253,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Ruleset = { Value = new OsuRuleset().RulesetInfo }, } } - }); + }, API.LocalUser.Value); }); AddStep("refresh rooms", () => this.ChildrenOfType().Single().UpdateFilter()); @@ -283,7 +283,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Ruleset = { Value = new OsuRuleset().RulesetInfo }, } } - }); + }, API.LocalUser.Value); }); AddStep("refresh rooms", () => this.ChildrenOfType().Single().UpdateFilter()); @@ -336,7 +336,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Ruleset = { Value = new OsuRuleset().RulesetInfo }, } } - }); + }, API.LocalUser.Value); }); AddStep("refresh rooms", () => this.ChildrenOfType().Single().UpdateFilter()); @@ -597,7 +597,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Ruleset = { Value = new OsuRuleset().RulesetInfo }, } } - }); + }, API.LocalUser.Value); }); AddStep("refresh rooms", () => this.ChildrenOfType().Single().UpdateFilter()); diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs index f8419b4164..a1f010f082 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Multiplayer; @@ -55,6 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer /// Adds a room to a local "server-side" list that's returned when a is fired. /// /// The room. - public void AddServerSideRoom(Room room) => requestsHandler.AddServerSideRoom(room); + /// The host. + public void AddServerSideRoom(Room room, APIUser host) => requestsHandler.AddServerSideRoom(room, host); } } diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs index 0b7d9af5e7..abcf31c007 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay apiRoom.HasPassword.Value = !string.IsNullOrEmpty(createRoomRequest.Room.Password.Value); apiRoom.Password.Value = createRoomRequest.Room.Password.Value; - AddServerSideRoom(apiRoom); + AddServerSideRoom(apiRoom, localUser); var responseRoom = new APICreatedRoom(); responseRoom.CopyFrom(createResponseRoom(apiRoom, false)); @@ -125,9 +125,11 @@ namespace osu.Game.Tests.Visual.OnlinePlay /// Adds a room to a local "server-side" list that's returned when a is fired. /// /// The room. - public void AddServerSideRoom(Room room) + /// The room host. + public void AddServerSideRoom(Room room, APIUser host) { room.RoomID.Value ??= currentRoomId++; + room.Host.Value = host; for (int i = 0; i < room.Playlist.Count; i++) { From e1445dcb058495d909efab2800f84d51e0f81aaf Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 26 Nov 2021 17:40:45 +0900 Subject: [PATCH 33/46] Only show owner in match subscreen --- .../TestSceneDrawableRoomPlaylist.cs | 18 ++++++++++++++---- .../Screens/OnlinePlay/DrawableRoomPlaylist.cs | 6 ++++-- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 16 ++++++++++++---- .../DrawableRoomPlaylistWithResults.cs | 13 ++++++++----- .../Multiplayer/MultiplayerMatchSubScreen.cs | 2 +- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index b0174104f7..13d98145a1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -23,6 +23,7 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.OnlinePlay; using osu.Game.Tests.Beatmaps; +using osu.Game.Users.Drawables; using osuTK; using osuTK.Input; @@ -308,6 +309,15 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded)); } + [TestCase(false)] + [TestCase(true)] + public void TestWithOwner(bool withOwner) + { + createPlaylist(false, false, withOwner); + + AddAssert("owner visible", () => playlist.ChildrenOfType().All(a => a.IsPresent == withOwner)); + } + private void moveToItem(int index, Vector2? offset = null) => AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType().ElementAt(index), offset)); @@ -331,11 +341,11 @@ namespace osu.Game.Tests.Visual.Multiplayer => AddAssert($"delete button {index} {(visible ? "is" : "is not")} visible", () => (playlist.ChildrenOfType().ElementAt(2 + index * 2).Alpha > 0) == visible); - private void createPlaylist(bool allowEdit, bool allowSelection) + private void createPlaylist(bool allowEdit, bool allowSelection, bool showItemOwner = false) { AddStep("create playlist", () => { - Child = playlist = new TestPlaylist(allowEdit, allowSelection) + Child = playlist = new TestPlaylist(allowEdit, allowSelection, showItemOwner) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -415,8 +425,8 @@ namespace osu.Game.Tests.Visual.Multiplayer { public new IReadOnlyDictionary> ItemMap => base.ItemMap; - public TestPlaylist(bool allowEdit, bool allowSelection) - : base(allowEdit, allowSelection) + public TestPlaylist(bool allowEdit, bool allowSelection, bool showItemOwner = false) + : base(allowEdit, allowSelection, showItemOwner: showItemOwner) { } } diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs index f5522cd25d..6deca0482a 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs @@ -20,11 +20,13 @@ namespace osu.Game.Screens.OnlinePlay private readonly bool allowEdit; private readonly bool allowSelection; + private readonly bool showItemOwner; - public DrawableRoomPlaylist(bool allowEdit, bool allowSelection, bool reverse = false) + public DrawableRoomPlaylist(bool allowEdit, bool allowSelection, bool reverse = false, bool showItemOwner = false) { this.allowEdit = allowEdit; this.allowSelection = allowSelection; + this.showItemOwner = showItemOwner; ((ReversibleFillFlowContainer)ListContainer).Reverse = reverse; } @@ -56,7 +58,7 @@ namespace osu.Game.Screens.OnlinePlay Spacing = new Vector2(0, 2) }; - protected override OsuRearrangeableListItem CreateOsuDrawable(PlaylistItem item) => new DrawableRoomPlaylistItem(item, allowEdit, allowSelection) + protected override OsuRearrangeableListItem CreateOsuDrawable(PlaylistItem item) => new DrawableRoomPlaylistItem(item, allowEdit, allowSelection, showItemOwner) { SelectedItem = { BindTarget = SelectedItem }, RequestDeletion = requestDeletion diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 6c518616e2..6cbdc80d60 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -69,10 +69,11 @@ namespace osu.Game.Screens.OnlinePlay private readonly bool allowEdit; private readonly bool allowSelection; + private readonly bool showItemOwner; protected override bool ShouldBeConsideredForInput(Drawable child) => allowEdit || !allowSelection || SelectedItem.Value == Model; - public DrawableRoomPlaylistItem(PlaylistItem item, bool allowEdit, bool allowSelection) + public DrawableRoomPlaylistItem(PlaylistItem item, bool allowEdit, bool allowSelection, bool showItemOwner) : base(item) { Item = item; @@ -80,6 +81,7 @@ namespace osu.Game.Screens.OnlinePlay // TODO: edit support should be moved out into a derived class this.allowEdit = allowEdit; this.allowSelection = allowSelection; + this.showItemOwner = showItemOwner; beatmap.BindTo(item.Beatmap); valid.BindTo(item.Valid); @@ -142,7 +144,12 @@ namespace osu.Game.Screens.OnlinePlay maskingContainer.BorderColour = colours.Red; } - userLookupCache.GetUserAsync(Item.OwnerID).ContinueWith(u => Schedule(() => ownerAvatar.User = u.Result), TaskContinuationOptions.OnlyOnRanToCompletion); + if (showItemOwner) + { + ownerAvatar.Show(); + userLookupCache.GetUserAsync(Item.OwnerID).ContinueWith(u => Schedule(() => ownerAvatar.User = u.Result), TaskContinuationOptions.OnlyOnRanToCompletion); + } + difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(ICON_HEIGHT) }; panelBackground.Beatmap.Value = Item.Beatmap.Value; @@ -271,7 +278,7 @@ namespace osu.Game.Screens.OnlinePlay Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Direction = FillDirection.Horizontal, - Margin = new MarginPadding { Left = 8 }, + Margin = new MarginPadding { Horizontal = 8 }, AutoSizeAxes = Axes.Both, Spacing = new Vector2(5), ChildrenEnumerable = CreateButtons().Select(button => button.With(b => @@ -285,9 +292,10 @@ namespace osu.Game.Screens.OnlinePlay Anchor = Anchor.Centre, Origin = Anchor.Centre, Size = new Vector2(ICON_HEIGHT), - Margin = new MarginPadding { Left = 8, Right = 8, }, + Margin = new MarginPadding { Right = 8 }, Masking = true, CornerRadius = 4, + Alpha = showItemOwner ? 1 : 0 }, } } diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs index 575f336e58..8b1bb7abc1 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs @@ -19,13 +19,16 @@ namespace osu.Game.Screens.OnlinePlay { public Action RequestShowResults; - public DrawableRoomPlaylistWithResults() - : base(false, true) + private readonly bool showItemOwner; + + public DrawableRoomPlaylistWithResults(bool showItemOwner = false) + : base(false, true, showItemOwner: showItemOwner) { + this.showItemOwner = showItemOwner; } protected override OsuRearrangeableListItem CreateOsuDrawable(PlaylistItem item) => - new DrawableRoomPlaylistItemWithResults(item, false, true) + new DrawableRoomPlaylistItemWithResults(item, false, true, showItemOwner) { RequestShowResults = () => RequestShowResults(item), SelectedItem = { BindTarget = SelectedItem }, @@ -35,8 +38,8 @@ namespace osu.Game.Screens.OnlinePlay { public Action RequestShowResults; - public DrawableRoomPlaylistItemWithResults(PlaylistItem item, bool allowEdit, bool allowSelection) - : base(item, allowEdit, allowSelection) + public DrawableRoomPlaylistItemWithResults(PlaylistItem item, bool allowEdit, bool allowSelection, bool showItemOwner) + : base(item, allowEdit, allowSelection, showItemOwner) { } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 1e3cfdbcbb..077e9cef93 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -153,7 +153,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer null, new Drawable[] { - playlist = new DrawableRoomPlaylist(false, false, true) + playlist = new DrawableRoomPlaylist(false, false, true, true) { RelativeSizeAxes = Axes.Both, }, From 89b4e5cffbfa5df0815e46e3b8f816baee4228a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 18:18:45 +0900 Subject: [PATCH 34/46] Rename mass deletion confirmation dialog --- .../Settings/Sections/Maintenance/GeneralSettings.cs | 8 ++++---- ...lBeatmapsDialog.cs => MassDeleteConfirmationDialog.cs} | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) rename osu.Game/Overlays/Settings/Sections/Maintenance/{DeleteAllBeatmapsDialog.cs => MassDeleteConfirmationDialog.cs} (87%) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 5bc89ec77c..acdf9cdea6 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Text = MaintenanceSettingsStrings.DeleteAllBeatmaps, Action = () => { - dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => + dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => { deleteBeatmapsButton.Enabled.Value = false; Task.Run(() => beatmaps.Delete(beatmaps.GetAllUsableBeatmapSets())).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); @@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Text = MaintenanceSettingsStrings.DeleteAllScores, Action = () => { - dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => + dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => { deleteScoresButton.Enabled.Value = false; Task.Run(() => scores.Delete(scores.GetAllUsableScores())).ContinueWith(t => Schedule(() => deleteScoresButton.Enabled.Value = true)); @@ -103,7 +103,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Text = MaintenanceSettingsStrings.DeleteAllSkins, Action = () => { - dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => + dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => { deleteSkinsButton.Enabled.Value = false; Task.Run(() => skins.Delete(skins.GetAllUserSkins())).ContinueWith(t => Schedule(() => deleteSkinsButton.Enabled.Value = true)); @@ -131,7 +131,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Text = MaintenanceSettingsStrings.DeleteAllCollections, Action = () => { - dialogOverlay?.Push(new DeleteAllBeatmapsDialog(collectionManager.DeleteAll)); + dialogOverlay?.Push(new MassDeleteConfirmationDialog(collectionManager.DeleteAll)); } }); } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DeleteAllBeatmapsDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs similarity index 87% rename from osu.Game/Overlays/Settings/Sections/Maintenance/DeleteAllBeatmapsDialog.cs rename to osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs index a124501454..6380232bbb 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/DeleteAllBeatmapsDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs @@ -7,9 +7,9 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class DeleteAllBeatmapsDialog : PopupDialog + public class MassDeleteConfirmationDialog : PopupDialog { - public DeleteAllBeatmapsDialog(Action deleteAction) + public MassDeleteConfirmationDialog(Action deleteAction) { BodyText = "Everything?"; From 7f9cc4d5ff9195d9b9de05b8479342574b5b2b4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 21:37:43 +0900 Subject: [PATCH 35/46] Fix incorrect logging of preview tracks without track owner --- osu.Game/Audio/PreviewTrackManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index fd9d5a97c6..e631d35180 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -105,7 +105,9 @@ namespace osu.Game.Audio protected override void LoadComplete() { base.LoadComplete(); - Logger.Log($"A {nameof(PreviewTrack)} was created without a containing {nameof(IPreviewTrackOwner)}. An owner should be added for correct behaviour."); + + if (Owner == null) + Logger.Log($"A {nameof(PreviewTrack)} was created without a containing {nameof(IPreviewTrackOwner)}. An owner should be added for correct behaviour."); } protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineID}.mp3"); From f16ef1ee69fafc74caeb3c3a0964fca3fe58fbfd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 22:34:05 +0900 Subject: [PATCH 36/46] Reapply schedule workaround for `PreviewTrack` --- .../Drawables/Cards/Buttons/PlayButton.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs index 4574d37da0..f7bab26666 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs @@ -97,6 +97,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons if (previewTrack == null) { toggleLoading(true); + LoadComponentAsync(previewTrack = previewTrackManager.Get(beatmapSetInfo), onPreviewLoaded); } else @@ -112,18 +113,23 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons private void onPreviewLoaded(PreviewTrack loadedPreview) { - // another async load might have completed before this one. - // if so, do not make any changes. - if (loadedPreview != previewTrack) - return; + // Make sure that we schedule to after the next audio frame to fix crashes in single-threaded execution. + // See: https://github.com/ppy/osu-framework/issues/4692 + Schedule(() => + { + // another async load might have completed before this one. + // if so, do not make any changes. + if (loadedPreview != previewTrack) + return; - AddInternal(loadedPreview); - toggleLoading(false); + AddInternal(loadedPreview); + toggleLoading(false); - loadedPreview.Stopped += () => Schedule(() => Playing.Value = false); + loadedPreview.Stopped += () => Schedule(() => Playing.Value = false); - if (Playing.Value) - tryStartPreview(); + if (Playing.Value) + tryStartPreview(); + }); } private void tryStartPreview() From b8a47755faa7bc3c28a556ecbe6d66023209526c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 22:54:10 +0900 Subject: [PATCH 37/46] Don't show loading tooltip for now Should probably be replaced with a loading spinner in the future, don't really like "loading" tooltips. --- osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 6cbdc80d60..8d9ea91b47 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -147,7 +147,8 @@ namespace osu.Game.Screens.OnlinePlay if (showItemOwner) { ownerAvatar.Show(); - userLookupCache.GetUserAsync(Item.OwnerID).ContinueWith(u => Schedule(() => ownerAvatar.User = u.Result), TaskContinuationOptions.OnlyOnRanToCompletion); + userLookupCache.GetUserAsync(Item.OwnerID) + .ContinueWith(u => Schedule(() => ownerAvatar.User = u.Result), TaskContinuationOptions.OnlyOnRanToCompletion); } difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(ICON_HEIGHT) }; @@ -458,7 +459,7 @@ namespace osu.Game.Screens.OnlinePlay }); } - public LocalisableString TooltipText => User == null ? "loading user..." : $"queued by {User.Username}"; + public LocalisableString TooltipText => User == null ? string.Empty : $"queued by {User.Username}"; private class TooltipArea : Component, IHasTooltip { From 0a75067ee55e880ef108ef5299f590ab56949679 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 27 Nov 2021 12:13:39 +0900 Subject: [PATCH 38/46] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index d893792285..eff0eed278 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f9c8d9743d..7cc8893d8d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 47f8fbb43a..9c21f76617 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -60,7 +60,7 @@ - + @@ -83,7 +83,7 @@ - + From f4b7db5a7bfb89e18b5ac83bbd89ca339e07a6eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 27 Nov 2021 14:36:34 +0100 Subject: [PATCH 39/46] Ensure correct disabled beatmap callback scheduling in now playing overlay --- osu.Game/Overlays/NowPlayingOverlay.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index f37e6bedf7..4dd23c0008 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -214,7 +214,8 @@ namespace osu.Game.Overlays { base.LoadComplete(); - beatmap.BindDisabledChanged(beatmapDisabledChanged, true); + beatmap.BindDisabledChanged(_ => Scheduler.AddOnce(beatmapDisabledChanged)); + beatmapDisabledChanged(); musicController.TrackChanged += trackChanged; trackChanged(beatmap.Value); @@ -318,8 +319,10 @@ namespace osu.Game.Overlays }; } - private void beatmapDisabledChanged(bool disabled) + private void beatmapDisabledChanged() { + bool disabled = beatmap.Disabled; + if (disabled) playlist?.Hide(); From 567c985da0faf08c088c42276a6e6a4cb9218048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 27 Nov 2021 14:56:27 +0100 Subject: [PATCH 40/46] Remove beatmap panel test scene --- .../Visual/Online/TestSceneDirectPanel.cs | 137 ------------------ 1 file changed, 137 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs deleted file mode 100644 index 510b9e8483..0000000000 --- a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Audio; -using osu.Game.Beatmaps; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays.BeatmapListing.Panels; -using osu.Game.Rulesets; -using osuTK; -using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; - -namespace osu.Game.Tests.Visual.Online -{ - [Cached(typeof(IPreviewTrackOwner))] - public class TestSceneDirectPanel : OsuTestScene, IPreviewTrackOwner - { - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) - { - var normal = getBeatmapSet(); - normal.HasVideo = true; - normal.HasStoryboard = true; - - var undownloadable = getUndownloadableBeatmapSet(); - var manyDifficulties = getManyDifficultiesBeatmapSet(); - - var explicitMap = getBeatmapSet(); - explicitMap.HasExplicitContent = true; - - var featuredMap = getBeatmapSet(); - featuredMap.TrackId = 1; - - var explicitFeaturedMap = getBeatmapSet(); - explicitFeaturedMap.HasExplicitContent = true; - explicitFeaturedMap.TrackId = 2; - - Child = new BasicScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Full, - Padding = new MarginPadding(20), - Spacing = new Vector2(5, 20), - Children = new Drawable[] - { - new GridBeatmapPanel(normal), - new GridBeatmapPanel(undownloadable), - new GridBeatmapPanel(manyDifficulties), - new GridBeatmapPanel(explicitMap), - new GridBeatmapPanel(featuredMap), - new GridBeatmapPanel(explicitFeaturedMap), - new ListBeatmapPanel(normal), - new ListBeatmapPanel(undownloadable), - new ListBeatmapPanel(manyDifficulties), - new ListBeatmapPanel(explicitMap), - new ListBeatmapPanel(featuredMap), - new ListBeatmapPanel(explicitFeaturedMap) - }, - }, - }; - - APIBeatmapSet getBeatmapSet() => CreateAPIBeatmapSet(Ruleset.Value); - - APIBeatmapSet getUndownloadableBeatmapSet() => new APIBeatmapSet - { - OnlineID = 123, - Title = "undownloadable beatmap", - Artist = "test", - Source = "more tests", - Author = new APIUser - { - Username = "BanchoBot", - Id = 3, - }, - Availability = new BeatmapSetOnlineAvailability - { - DownloadDisabled = true, - }, - Preview = @"https://b.ppy.sh/preview/12345.mp3", - PlayCount = 123, - FavouriteCount = 456, - BPM = 111, - HasVideo = true, - HasStoryboard = true, - Covers = new BeatmapSetOnlineCovers(), - Beatmaps = new[] - { - new APIBeatmap - { - RulesetID = Ruleset.Value.OnlineID, - DifficultyName = "Test", - StarRating = 6.42, - } - } - }; - - APIBeatmapSet getManyDifficultiesBeatmapSet() - { - var beatmaps = new List(); - - for (int i = 0; i < 100; i++) - { - beatmaps.Add(new APIBeatmap - { - RulesetID = i % 4, - StarRating = 2 + i % 4 * 2, - OverallDifficulty = 3.5f, - }); - } - - return new APIBeatmapSet - { - OnlineID = 1, - Title = "undownloadable beatmap", - Artist = "test", - Source = "more tests", - Author = new APIUser - { - Username = "BanchoBot", - Id = 3, - }, - HasVideo = true, - HasStoryboard = true, - Covers = new BeatmapSetOnlineCovers(), - Beatmaps = beatmaps.ToArray(), - }; - } - } - } -} From 6773877a40c532732d92fbbb1b655fd87ce92ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 27 Nov 2021 15:00:06 +0100 Subject: [PATCH 41/46] Remove no-longer-used beatmap panels --- .../BeatmapListing/Panels/BeatmapPanel.cs | 216 -------------- .../BeatmapListing/Panels/GridBeatmapPanel.cs | 269 ------------------ .../BeatmapListing/Panels/ListBeatmapPanel.cs | 267 ----------------- 3 files changed, 752 deletions(-) delete mode 100644 osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs delete mode 100644 osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs delete mode 100644 osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs diff --git a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs deleted file mode 100644 index 34086c214f..0000000000 --- a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs +++ /dev/null @@ -1,216 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osu.Game.Audio; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API.Requests.Responses; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Overlays.BeatmapListing.Panels -{ - public abstract class BeatmapPanel : OsuClickableContainer, IHasContextMenu - { - public readonly APIBeatmapSet SetInfo; - - private const double hover_transition_time = 400; - private const int maximum_difficulty_icons = 10; - - private Container content; - - public PreviewTrack Preview => PlayButton.Preview; - public IBindable PreviewPlaying => PlayButton?.Playing; - - protected abstract PlayButton PlayButton { get; } - protected abstract Box PreviewBar { get; } - - protected virtual bool FadePlayButton => true; - - protected override Container Content => content; - - protected Action ViewBeatmap; - - protected BeatmapPanel(APIBeatmapSet setInfo) - : base(HoverSampleSet.Submit) - { - Debug.Assert(setInfo.OnlineID > 0); - - SetInfo = setInfo; - } - - private readonly EdgeEffectParameters edgeEffectNormal = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0f, 1f), - Radius = 2f, - Colour = Color4.Black.Opacity(0.25f), - }; - - private readonly EdgeEffectParameters edgeEffectHovered = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0f, 5f), - Radius = 10f, - Colour = Color4.Black.Opacity(0.3f), - }; - - [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay) - { - AddInternal(content = new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - EdgeEffect = edgeEffectNormal, - Children = new[] - { - CreateBackground(), - new DownloadProgressBar(SetInfo) - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Depth = -1, - }, - } - }); - - Action = ViewBeatmap = () => - { - Debug.Assert(SetInfo.OnlineID > 0); - beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineID); - }; - } - - protected override void Update() - { - base.Update(); - - if (PreviewPlaying.Value && Preview != null && Preview.TrackLoaded) - { - PreviewBar.Width = (float)(Preview.CurrentTime / Preview.Length); - } - } - - protected override bool OnHover(HoverEvent e) - { - content.TweenEdgeEffectTo(edgeEffectHovered, hover_transition_time, Easing.OutQuint); - content.MoveToY(-4, hover_transition_time, Easing.OutQuint); - if (FadePlayButton) - PlayButton.FadeIn(120, Easing.InOutQuint); - - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - content.TweenEdgeEffectTo(edgeEffectNormal, hover_transition_time, Easing.OutQuint); - content.MoveToY(0, hover_transition_time, Easing.OutQuint); - if (FadePlayButton && !PreviewPlaying.Value) - PlayButton.FadeOut(120, Easing.InOutQuint); - - base.OnHoverLost(e); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - this.FadeInFromZero(200, Easing.Out); - - PreviewPlaying.ValueChanged += playing => - { - PlayButton.FadeTo(playing.NewValue || IsHovered || !FadePlayButton ? 1 : 0, 120, Easing.InOutQuint); - PreviewBar.FadeTo(playing.NewValue ? 1 : 0, 120, Easing.InOutQuint); - }; - } - - protected List GetDifficultyIcons(OsuColour colours) - { - var icons = new List(); - - if (SetInfo.Beatmaps.Length > maximum_difficulty_icons) - { - foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct()) - icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.Where(b => b.RulesetID == ruleset.OnlineID).ToList(), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5)); - } - else - { - foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.RulesetID).ThenBy(beatmap => beatmap.StarRating)) - icons.Add(new DifficultyIcon(b)); - } - - return icons; - } - - protected Drawable CreateBackground() => new UpdateableOnlineBeatmapSetCover - { - RelativeSizeAxes = Axes.Both, - OnlineInfo = SetInfo, - }; - - public class Statistic : FillFlowContainer - { - private readonly SpriteText text; - - private int value; - - public int Value - { - get => value; - set - { - this.value = value; - text.Text = Value.ToString(@"N0"); - } - } - - public Statistic(IconUsage icon, int value = 0) - { - Anchor = Anchor.TopRight; - Origin = Anchor.TopRight; - AutoSizeAxes = Axes.Both; - Direction = FillDirection.Horizontal; - Spacing = new Vector2(5f, 0f); - - Children = new Drawable[] - { - text = new OsuSpriteText { Font = OsuFont.GetFont(weight: FontWeight.SemiBold, italics: true) }, - new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Icon = icon, - Shadow = true, - Size = new Vector2(14), - }, - }; - - Value = value; - } - } - - public MenuItem[] ContextMenuItems => new MenuItem[] - { - new OsuMenuItem("View Beatmap", MenuItemType.Highlighted, ViewBeatmap), - }; - } -} diff --git a/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs deleted file mode 100644 index 770e5af7bd..0000000000 --- a/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs +++ /dev/null @@ -1,269 +0,0 @@ -// 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.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays.BeatmapSet; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Overlays.BeatmapListing.Panels -{ - public class GridBeatmapPanel : BeatmapPanel - { - private const float horizontal_padding = 10; - private const float vertical_padding = 5; - - private FillFlowContainer bottomPanel, statusContainer, titleContainer, artistContainer; - private PlayButton playButton; - private Box progressBar; - - protected override PlayButton PlayButton => playButton; - protected override Box PreviewBar => progressBar; - - public GridBeatmapPanel(APIBeatmapSet beatmap) - : base(beatmap) - { - Width = 380; - Height = 140 + vertical_padding; // full height of all the elements plus vertical padding (autosize uses the image) - } - - protected override void LoadComplete() - { - base.LoadComplete(); - bottomPanel.LayoutDuration = 200; - bottomPanel.LayoutEasing = Easing.Out; - bottomPanel.Origin = Anchor.BottomLeft; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Content.CornerRadius = 4; - - AddRange(new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.5f), - }, - bottomPanel = new FillFlowContainer - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.TopLeft, - Direction = FillDirection.Vertical, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0f, vertical_padding), - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = horizontal_padding, Right = horizontal_padding }, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - titleContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = new RomanisableString(SetInfo.TitleUnicode, SetInfo.Title), - Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold, italics: true) - }, - } - }, - artistContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = new RomanisableString(SetInfo.ArtistUnicode, SetInfo.Artist), - Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true) - } - } - } - }, - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - }, - progressBar = new Box - { - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - BypassAutoSizeAxes = Axes.Both, - Size = new Vector2(0, 3), - Alpha = 0, - Colour = colours.Yellow, - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Padding = new MarginPadding - { - Top = vertical_padding, - Bottom = vertical_padding, - Left = horizontal_padding, - Right = horizontal_padding, - }, - Children = new Drawable[] - { - new LinkFlowContainer(s => - { - s.Shadow = false; - s.Font = OsuFont.GetFont(size: 14); - }).With(d => - { - d.AutoSizeAxes = Axes.Both; - d.AddText("mapped by ", t => t.Colour = colours.Gray5); - d.AddUserLink(SetInfo.Author); - }), - new Container - { - AutoSizeAxes = Axes.X, - Height = 14, - Children = new[] - { - new OsuSpriteText - { - Text = SetInfo.Source, - Font = OsuFont.GetFont(size: 14), - Shadow = false, - Colour = colours.Gray5, - Alpha = string.IsNullOrEmpty(SetInfo.Source) ? 0f : 1f, - }, - }, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.X, - Height = 20, - Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, - Spacing = new Vector2(3), - Children = GetDifficultyIcons(colours), - }, - }, - }, - new BeatmapPanelDownloadButton(SetInfo) - { - Size = new Vector2(50, 30), - Margin = new MarginPadding(horizontal_padding), - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - }, - }, - }, - }, - }, - new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Margin = new MarginPadding { Top = vertical_padding, Right = vertical_padding }, - Children = new[] - { - new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.PlayCount), - new Statistic(FontAwesome.Solid.Heart, SetInfo.FavouriteCount), - }, - }, - statusContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = 5, Left = 5 }, - Spacing = new Vector2(5), - }, - playButton = new PlayButton(SetInfo) - { - Margin = new MarginPadding { Top = 5, Left = 10 }, - Size = new Vector2(30), - Alpha = 0, - }, - }); - - if (SetInfo.HasExplicitContent) - { - titleContainer.Add(new ExplicitContentBeatmapPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Left = 10f, Top = 2f }, - }); - } - - if (SetInfo.TrackId != null) - { - artistContainer.Add(new FeaturedArtistBeatmapPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Left = 10f, Top = 2f }, - }); - } - - if (SetInfo.HasVideo) - { - statusContainer.Add(new IconPill(FontAwesome.Solid.Film)); - } - - if (SetInfo.HasStoryboard) - { - statusContainer.Add(new IconPill(FontAwesome.Solid.Image)); - } - - statusContainer.Add(new BeatmapSetOnlineStatusPill - { - AutoSizeAxes = Axes.Both, - TextSize = 12, - TextPadding = new MarginPadding { Horizontal = 10, Vertical = 5 }, - Status = SetInfo.Status, - }); - - PreviewPlaying.ValueChanged += _ => updateStatusContainer(); - } - - protected override bool OnHover(HoverEvent e) - { - updateStatusContainer(); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - base.OnHoverLost(e); - updateStatusContainer(); - } - - private void updateStatusContainer() => statusContainer.FadeTo(IsHovered || PreviewPlaying.Value ? 0 : 1, 120, Easing.InOutQuint); - } -} diff --git a/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs deleted file mode 100644 index dcd676724a..0000000000 --- a/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs +++ /dev/null @@ -1,267 +0,0 @@ -// 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.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Localisation; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays.BeatmapSet; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Overlays.BeatmapListing.Panels -{ - public class ListBeatmapPanel : BeatmapPanel - { - private const float transition_duration = 120; - private const float horizontal_padding = 10; - private const float vertical_padding = 5; - private const float height = 70; - - private FillFlowContainer statusContainer, titleContainer, artistContainer; - protected BeatmapPanelDownloadButton DownloadButton; - private PlayButton playButton; - private Box progressBar; - - protected override bool FadePlayButton => false; - - protected override PlayButton PlayButton => playButton; - protected override Box PreviewBar => progressBar; - - public ListBeatmapPanel(APIBeatmapSet beatmap) - : base(beatmap) - { - RelativeSizeAxes = Axes.X; - Height = height; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Content.CornerRadius = 5; - - AddRange(new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.25f), Color4.Black.Opacity(0.75f)), - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding, Left = horizontal_padding, Right = vertical_padding }, - Children = new Drawable[] - { - new FillFlowContainer - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - LayoutEasing = Easing.OutQuint, - LayoutDuration = transition_duration, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - playButton = new PlayButton(SetInfo) - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Size = new Vector2(height / 3), - FillMode = FillMode.Fit, - Margin = new MarginPadding { Right = 10 }, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - titleContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new[] - { - new OsuSpriteText - { - Text = new RomanisableString(SetInfo.TitleUnicode, SetInfo.Title), - Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold, italics: true) - }, - } - }, - artistContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new[] - { - new OsuSpriteText - { - Text = new RomanisableString(SetInfo.ArtistUnicode, SetInfo.Artist), - Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true) - }, - }, - }, - } - }, - } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - statusContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Vertical = vertical_padding, Horizontal = 5 }, - Spacing = new Vector2(5), - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.X, - Height = 20, - Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, - Spacing = new Vector2(3), - Children = GetDifficultyIcons(colours), - }, - }, - }, - }, - }, - } - }, - new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new Container - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AutoSizeAxes = Axes.Both, - Child = DownloadButton = new BeatmapPanelDownloadButton(SetInfo) - { - Size = new Vector2(height - vertical_padding * 3), - Margin = new MarginPadding { Left = vertical_padding * 2, Right = vertical_padding }, - }, - }, - new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.PlayCount), - new Statistic(FontAwesome.Solid.Heart, SetInfo.FavouriteCount), - new LinkFlowContainer(s => - { - s.Shadow = false; - s.Font = OsuFont.GetFont(size: 14); - }) - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - }.With(d => - { - d.AutoSizeAxes = Axes.Both; - d.AddText("mapped by "); - d.AddUserLink(SetInfo.Author); - }), - new OsuSpriteText - { - Text = SetInfo.Source, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Font = OsuFont.GetFont(size: 14), - Alpha = string.IsNullOrEmpty(SetInfo.Source) ? 0f : 1f, - }, - }, - }, - }, - }, - }, - }, - progressBar = new Box - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - BypassAutoSizeAxes = Axes.Y, - Size = new Vector2(0, 3), - Alpha = 0, - Colour = colours.Yellow, - }, - }); - - if (SetInfo.HasExplicitContent) - { - titleContainer.Add(new ExplicitContentBeatmapPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Left = 10f, Top = 2f }, - }); - } - - if (SetInfo.TrackId != null) - { - artistContainer.Add(new FeaturedArtistBeatmapPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Left = 10f, Top = 2f }, - }); - } - - if (SetInfo.HasVideo) - { - statusContainer.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) }); - } - - if (SetInfo.HasStoryboard) - { - statusContainer.Add(new IconPill(FontAwesome.Solid.Image) { IconSize = new Vector2(20) }); - } - - statusContainer.Add(new BeatmapSetOnlineStatusPill - { - AutoSizeAxes = Axes.Both, - TextSize = 12, - TextPadding = new MarginPadding { Horizontal = 10, Vertical = 4 }, - Status = SetInfo.Status, - }); - } - } -} From 74196823348350b2ec5ad1d871ca57fe4cb65e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 27 Nov 2021 15:01:48 +0100 Subject: [PATCH 42/46] Move icon pill to beatmap card-specific namespace --- osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs | 1 - .../Panels => Beatmaps/Drawables/Cards}/IconPill.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) rename osu.Game/{Overlays/BeatmapListing/Panels => Beatmaps/Drawables/Cards}/IconPill.cs (96%) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs index 76b1166626..37c1bacda4 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs @@ -23,7 +23,6 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; using osuTK; -using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Resources.Localisation.Web; using DownloadButton = osu.Game.Beatmaps.Drawables.Cards.Buttons.DownloadButton; diff --git a/osu.Game/Overlays/BeatmapListing/Panels/IconPill.cs b/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs similarity index 96% rename from osu.Game/Overlays/BeatmapListing/Panels/IconPill.cs rename to osu.Game/Beatmaps/Drawables/Cards/IconPill.cs index 1cb6c84f13..c55e9c0a28 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/IconPill.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; using osuTK; using osuTK.Graphics; -namespace osu.Game.Overlays.BeatmapListing.Panels +namespace osu.Game.Beatmaps.Drawables.Cards { public class IconPill : CircularContainer { From 251ab183a08627d3b309e1dab89e4c238674f83d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 27 Nov 2021 15:04:05 +0100 Subject: [PATCH 43/46] Move beatmap play button nearer its only remaining usage --- .../{BeatmapListing/Panels => BeatmapSet/Buttons}/PlayButton.cs | 2 +- osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) rename osu.Game/Overlays/{BeatmapListing/Panels => BeatmapSet/Buttons}/PlayButton.cs (99%) diff --git a/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs similarity index 99% rename from osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs rename to osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs index c352fe0223..63b7a0a062 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs @@ -14,7 +14,7 @@ using osu.Game.Online.API.Requests.Responses; using osuTK; using osuTK.Graphics; -namespace osu.Game.Overlays.BeatmapListing.Panels +namespace osu.Game.Overlays.BeatmapSet.Buttons { public class PlayButton : Container { diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 6bcdb7bdc5..751299161d 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -11,7 +11,6 @@ using osu.Game.Audio; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays.BeatmapListing.Panels; using osuTK; namespace osu.Game.Overlays.BeatmapSet.Buttons From a043d1e4273804350eace4c6d658c5afe24fe36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 27 Nov 2021 15:06:57 +0100 Subject: [PATCH 44/46] Move old beatmap download button to more general namespace --- .../Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs | 1 - osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs | 2 +- .../Drawables}/BeatmapPanelDownloadButton.cs | 3 +-- .../Panels => Beatmaps/Drawables}/DownloadProgressBar.cs | 3 +-- osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs | 1 - osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs | 2 +- osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs | 1 - 7 files changed, 4 insertions(+), 9 deletions(-) rename osu.Game/{Overlays/BeatmapListing/Panels => Beatmaps/Drawables}/BeatmapPanelDownloadButton.cs (98%) rename osu.Game/{Overlays/BeatmapListing/Panels => Beatmaps/Drawables}/DownloadProgressBar.cs (97%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 13d98145a1..0b3ecb41cd 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -17,7 +17,6 @@ using osu.Game.Database; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; -using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs index 22a91fa9a3..d1af8dd685 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs @@ -6,9 +6,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Tests.Resources; using osuTK; diff --git a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanelDownloadButton.cs similarity index 98% rename from osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs rename to osu.Game/Beatmaps/Drawables/BeatmapPanelDownloadButton.cs index 0a66c3ccb7..1a47182d22 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanelDownloadButton.cs @@ -6,7 +6,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Extensions; using osu.Game.Graphics.Containers; @@ -14,7 +13,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; -namespace osu.Game.Overlays.BeatmapListing.Panels +namespace osu.Game.Beatmaps.Drawables { public class BeatmapPanelDownloadButton : CompositeDrawable { diff --git a/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs b/osu.Game/Beatmaps/Drawables/DownloadProgressBar.cs similarity index 97% rename from osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs rename to osu.Game/Beatmaps/Drawables/DownloadProgressBar.cs index 93eaf775e0..54dcdc55e3 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs +++ b/osu.Game/Beatmaps/Drawables/DownloadProgressBar.cs @@ -5,13 +5,12 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osuTK.Graphics; -namespace osu.Game.Overlays.BeatmapListing.Panels +namespace osu.Game.Beatmaps.Drawables { public class DownloadProgressBar : CompositeDrawable { diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs index 547b8a6ec3..b46919ef18 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs @@ -17,7 +17,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Overlays.BeatmapSet.Buttons; using osuTK; diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index 4eed8f28f2..74417b0ac6 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -9,13 +9,13 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 8d9ea91b47..58c63010fd 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -25,7 +25,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Online.Chat; using osu.Game.Online.Rooms; -using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; From 05f7ea6b6d27ea5378b10c1e4f0965e162a5ce96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 27 Nov 2021 15:08:03 +0100 Subject: [PATCH 45/46] Remove mentions of "panel" and "direct" from names of old download buttons --- .../Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs | 4 ++-- ...ectDownloadButton.cs => TestSceneBeatmapDownloadButton.cs} | 4 ++-- ...BeatmapPanelDownloadButton.cs => BeatmapDownloadButton.cs} | 4 ++-- osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs | 2 +- osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) rename osu.Game.Tests/Visual/Online/{TestSceneDirectDownloadButton.cs => TestSceneBeatmapDownloadButton.cs} (97%) rename osu.Game/Beatmaps/Drawables/{BeatmapPanelDownloadButton.cs => BeatmapDownloadButton.cs} (96%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 0b3ecb41cd..55aa665ff1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -235,7 +235,7 @@ namespace osu.Game.Tests.Visual.Multiplayer assertDownloadButtonVisible(false); void assertDownloadButtonVisible(bool visible) => AddUntilStep($"download button {(visible ? "shown" : "hidden")}", - () => playlist.ChildrenOfType().Single().Alpha == (visible ? 1 : 0)); + () => playlist.ChildrenOfType().Single().Alpha == (visible ? 1 : 0)); } [Test] @@ -249,7 +249,7 @@ namespace osu.Game.Tests.Visual.Multiplayer createPlaylist(byOnlineId, byChecksum); - AddAssert("download buttons shown", () => playlist.ChildrenOfType().All(d => d.IsPresent)); + AddAssert("download buttons shown", () => playlist.ChildrenOfType().All(d => d.IsPresent)); } [Test] diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs similarity index 97% rename from osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs rename to osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs index d1af8dd685..21bf8d1c5a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { - public class TestSceneDirectDownloadButton : OsuTestScene + public class TestSceneBeatmapDownloadButton : OsuTestScene { private TestDownloadButton downloadButton; @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual.Online return apiBeatmapSet; } - private class TestDownloadButton : BeatmapPanelDownloadButton + private class TestDownloadButton : BeatmapDownloadButton { public new bool DownloadEnabled => base.DownloadEnabled; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanelDownloadButton.cs b/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs similarity index 96% rename from osu.Game/Beatmaps/Drawables/BeatmapPanelDownloadButton.cs rename to osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs index 1a47182d22..e2485e7a77 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanelDownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs @@ -15,7 +15,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Beatmaps.Drawables { - public class BeatmapPanelDownloadButton : CompositeDrawable + public class BeatmapDownloadButton : CompositeDrawable { protected bool DownloadEnabled => button.Enabled.Value; @@ -34,7 +34,7 @@ namespace osu.Game.Beatmaps.Drawables private readonly IBeatmapSetInfo beatmapSet; - public BeatmapPanelDownloadButton(IBeatmapSetInfo beatmapSet) + public BeatmapDownloadButton(IBeatmapSetInfo beatmapSet) { this.beatmapSet = beatmapSet; diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs index b46919ef18..8f4089c707 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs @@ -285,7 +285,7 @@ namespace osu.Game.Overlays.BeatmapSet { case DownloadState.LocallyAvailable: // temporary for UX until new design is implemented. - downloadButtonsContainer.Child = new BeatmapPanelDownloadButton(BeatmapSet.Value) + downloadButtonsContainer.Child = new BeatmapDownloadButton(BeatmapSet.Value) { Width = 50, RelativeSizeAxes = Axes.Y, diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 58c63010fd..2dbe2df82c 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -338,7 +338,7 @@ namespace osu.Game.Screens.OnlinePlay return true; } - private sealed class PlaylistDownloadButton : BeatmapPanelDownloadButton + private sealed class PlaylistDownloadButton : BeatmapDownloadButton { private readonly PlaylistItem playlistItem; From db49d99cc0e86901357538c515da4a3f58a26361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 27 Nov 2021 14:39:12 +0100 Subject: [PATCH 46/46] Ensure correct disabled ruleset callback scheduling in ruleset selector --- osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs index 9ca105ee7f..6e5fbf6efb 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs @@ -68,13 +68,19 @@ namespace osu.Game.Overlays.Toolbar { base.LoadComplete(); - Current.BindDisabledChanged(disabled => this.FadeColour(disabled ? Color4.Gray : Color4.White, 300), true); - Current.BindValueChanged(_ => moveLineToCurrent()); + Current.BindDisabledChanged(_ => Scheduler.AddOnce(currentDisabledChanged)); + currentDisabledChanged(); + Current.BindValueChanged(_ => moveLineToCurrent()); // Scheduled to allow the button flow layout to be computed before the line position is updated ScheduleAfterChildren(moveLineToCurrent); } + private void currentDisabledChanged() + { + this.FadeColour(Current.Disabled ? Color4.Gray : Color4.White, 300); + } + private bool hasInitialPosition; private void moveLineToCurrent()