From 5e0763ae33c65105ef38a38cddc833abc921854d Mon Sep 17 00:00:00 2001 From: MK56 <74463310+mk56-spn@users.noreply.github.com> Date: Thu, 25 Nov 2021 10:24:00 +0100 Subject: [PATCH 01/38] Expand the functionality of Approach different --- osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index d832411104..d3a01e5def 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods public BindableFloat Scale { get; } = new BindableFloat(4) { Precision = 0.1f, - MinValue = 2, + MinValue = 1.5f, MaxValue = 10, }; @@ -58,6 +58,9 @@ namespace osu.Game.Rulesets.Osu.Mods case AnimationStyle.Accelerate1: return Easing.In; + case AnimationStyle.Linear: + return Easing.None; + case AnimationStyle.Accelerate2: return Easing.InCubic; @@ -86,6 +89,7 @@ namespace osu.Game.Rulesets.Osu.Mods public enum AnimationStyle { + Linear, Gravity, InOut1, InOut2, From 5e56122d650f78c1a69e9890b608aa4d9021c446 Mon Sep 17 00:00:00 2001 From: MK-56 Date: Fri, 26 Nov 2021 09:48:38 +0100 Subject: [PATCH 02/38] Linear approach type moved per peppys request --- osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index d3a01e5def..ae5ca0d679 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs @@ -89,7 +89,6 @@ namespace osu.Game.Rulesets.Osu.Mods public enum AnimationStyle { - Linear, Gravity, InOut1, InOut2, @@ -99,6 +98,7 @@ namespace osu.Game.Rulesets.Osu.Mods Decelerate1, Decelerate2, Decelerate3, + Linear, } } } From 89b4e5cffbfa5df0815e46e3b8f816baee4228a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 18:18:45 +0900 Subject: [PATCH 03/38] 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 04/38] 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 05/38] 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 06/38] 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 07/38] 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 0df97744ad8425e7b62dd8ea305a07310d921066 Mon Sep 17 00:00:00 2001 From: mk-56 Date: Sat, 27 Nov 2021 13:34:09 +0100 Subject: [PATCH 08/38] Moved linear to a better place. i decided to go with leaving it under gravity, its plenty visible and fine there, since the public enum list self orders I wasn't sure about how i could set a default that wasn't the topmost option --- osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index ae5ca0d679..6aeb378c69 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -90,6 +90,7 @@ namespace osu.Game.Rulesets.Osu.Mods public enum AnimationStyle { Gravity, + Linear, InOut1, InOut2, Accelerate1, @@ -98,7 +99,6 @@ namespace osu.Game.Rulesets.Osu.Mods Decelerate1, Decelerate2, Decelerate3, - Linear, } } } 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 09/38] 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 10/38] 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 11/38] 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 12/38] 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 13/38] 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 14/38] 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 15/38] 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 16/38] 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() From 1ae41118cd611d4965272a3272035f2c307acc7a Mon Sep 17 00:00:00 2001 From: mk-56 Date: Sat, 27 Nov 2021 22:59:09 +0100 Subject: [PATCH 17/38] Added gravity as a default. --- osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index 6aeb378c69..db74790221 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Mods }; [SettingSource("Style", "Change the animation style of the approach circles.", 1)] - public Bindable Style { get; } = new Bindable(); + public Bindable Style { get; } = new Bindable(AnimationStyle.Gravity); public void ApplyToDrawableHitObject(DrawableHitObject drawable) { @@ -89,8 +89,8 @@ namespace osu.Game.Rulesets.Osu.Mods public enum AnimationStyle { - Gravity, Linear, + Gravity, InOut1, InOut2, Accelerate1, From 93b5aec23ec00b85b75a4aebcc22dfc40d68750d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 28 Nov 2021 15:00:40 +0100 Subject: [PATCH 18/38] Fix realm migration failures when upgrading from old versions * `RealmRulesetSetting` was added in 2021.916.0. * `RealmKeyBinding` was added in 2021.703.0. Attempting to upgrade from older releases than the above would cause migrations up to schema versions 10 and 11 to fail. --- osu.Game/Database/RealmContextFactory.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Database/RealmContextFactory.cs b/osu.Game/Database/RealmContextFactory.cs index 3c5dfeafe8..2bc77934a8 100644 --- a/osu.Game/Database/RealmContextFactory.cs +++ b/osu.Game/Database/RealmContextFactory.cs @@ -307,6 +307,9 @@ namespace osu.Game.Database case 10: string rulesetSettingClassName = getMappedOrOriginalName(typeof(RealmRulesetSetting)); + if (!migration.OldRealm.Schema.TryFindObjectSchema(rulesetSettingClassName, out _)) + return; + var oldSettings = migration.OldRealm.DynamicApi.All(rulesetSettingClassName); var newSettings = migration.NewRealm.All().ToList(); @@ -329,6 +332,9 @@ namespace osu.Game.Database case 11: string keyBindingClassName = getMappedOrOriginalName(typeof(RealmKeyBinding)); + if (!migration.OldRealm.Schema.TryFindObjectSchema(keyBindingClassName, out _)) + return; + var oldKeyBindings = migration.OldRealm.DynamicApi.All(keyBindingClassName); var newKeyBindings = migration.NewRealm.All().ToList(); From aba9ed624a408d7b0b28e45796d6dd1e096b977f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 28 Nov 2021 15:16:33 +0100 Subject: [PATCH 19/38] Remove unnecessary whitespace --- osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index db74790221..d784320d22 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Mods public enum AnimationStyle { Linear, - Gravity, + Gravity, InOut1, InOut2, Accelerate1, From 5001412a0dada04c25400ebeb8676e5d927f1f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 28 Nov 2021 15:19:12 +0100 Subject: [PATCH 20/38] Reorder easing mapping to match enum order and throw on unknown animation style --- .../Mods/OsuModApproachDifferent.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index d784320d22..8b323eefa6 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs @@ -52,24 +52,27 @@ namespace osu.Game.Rulesets.Osu.Mods { switch (style) { - default: + case AnimationStyle.Linear: return Easing.None; + case AnimationStyle.Gravity: + return Easing.InBack; + + case AnimationStyle.InOut1: + return Easing.InOutCubic; + + case AnimationStyle.InOut2: + return Easing.InOutQuint; + case AnimationStyle.Accelerate1: return Easing.In; - case AnimationStyle.Linear: - return Easing.None; - case AnimationStyle.Accelerate2: return Easing.InCubic; case AnimationStyle.Accelerate3: return Easing.InQuint; - case AnimationStyle.Gravity: - return Easing.InBack; - case AnimationStyle.Decelerate1: return Easing.Out; @@ -79,11 +82,8 @@ namespace osu.Game.Rulesets.Osu.Mods case AnimationStyle.Decelerate3: return Easing.OutQuint; - case AnimationStyle.InOut1: - return Easing.InOutCubic; - - case AnimationStyle.InOut2: - return Easing.InOutQuint; + default: + throw new ArgumentOutOfRangeException(nameof(style), style, @"Unsupported animation style"); } } From 87d6a743dd9cd153d347a6257cb7086b69449b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 28 Nov 2021 16:14:12 +0100 Subject: [PATCH 21/38] Migrate custom tournament client assets to uppercased directories It has transpired that on filename-case-sensitive filesystems, the tournament client does not consistently handle custom asset paths. Videos and mods could only be looked up from `videos` and `mods` directories (lowercase), while flags could only be looked up from the `Flags` directory (uppercase). A complicating circumstance is that default country flags, coming from osu-resources, also depend on the flag lookup being uppercased. To attempt to clean up the handling as much as it appears to be possible, automatically move user-supplied lowercase directories to uppercase. --- .../NonVisual/CustomTourneyDirectoryTest.cs | 12 ++++++------ .../Components/TournamentModIcon.cs | 2 +- osu.Game.Tournament/IO/TournamentStorage.cs | 17 +++++++++++++++++ .../IO/TournamentVideoResourceStore.cs | 2 +- .../Screens/TeamIntro/SeedingScreen.cs | 2 +- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs index 94472a8bc7..d149ec145b 100644 --- a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs +++ b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs @@ -87,9 +87,9 @@ namespace osu.Game.Tournament.Tests.NonVisual // Recreate the old setup that uses "tournament" as the base path. string oldPath = Path.Combine(osuRoot, "tournament"); - string videosPath = Path.Combine(oldPath, "videos"); - string modsPath = Path.Combine(oldPath, "mods"); - string flagsPath = Path.Combine(oldPath, "flags"); + string videosPath = Path.Combine(oldPath, "Videos"); + string modsPath = Path.Combine(oldPath, "Mods"); + string flagsPath = Path.Combine(oldPath, "Flags"); Directory.CreateDirectory(videosPath); Directory.CreateDirectory(modsPath); @@ -123,9 +123,9 @@ namespace osu.Game.Tournament.Tests.NonVisual string migratedPath = Path.Combine(host.Storage.GetFullPath("."), "tournaments", "default"); - videosPath = Path.Combine(migratedPath, "videos"); - modsPath = Path.Combine(migratedPath, "mods"); - flagsPath = Path.Combine(migratedPath, "flags"); + videosPath = Path.Combine(migratedPath, "Videos"); + modsPath = Path.Combine(migratedPath, "Mods"); + flagsPath = Path.Combine(migratedPath, "Flags"); videoFile = Path.Combine(videosPath, "video.mp4"); modFile = Path.Combine(modsPath, "mod.png"); diff --git a/osu.Game.Tournament/Components/TournamentModIcon.cs b/osu.Game.Tournament/Components/TournamentModIcon.cs index 7c4e9c69a2..0fde263bc8 100644 --- a/osu.Game.Tournament/Components/TournamentModIcon.cs +++ b/osu.Game.Tournament/Components/TournamentModIcon.cs @@ -31,7 +31,7 @@ namespace osu.Game.Tournament.Components [BackgroundDependencyLoader] private void load(TextureStore textures, LadderInfo ladderInfo) { - var customTexture = textures.Get($"mods/{modAcronym}"); + var customTexture = textures.Get($"Mods/{modAcronym}"); if (customTexture != null) { diff --git a/osu.Game.Tournament/IO/TournamentStorage.cs b/osu.Game.Tournament/IO/TournamentStorage.cs index 044b60bbd5..02cf567837 100644 --- a/osu.Game.Tournament/IO/TournamentStorage.cs +++ b/osu.Game.Tournament/IO/TournamentStorage.cs @@ -51,6 +51,23 @@ namespace osu.Game.Tournament.IO Logger.Log("Changing tournament storage: " + GetFullPath(string.Empty)); } + protected override void ChangeTargetStorage(Storage newStorage) + { + // due to an unfortunate oversight, on OSes that are sensitive to pathname casing + // the custom flags directory needed to be named `Flags` (uppercase), + // while custom mods and videos directories needed to be named `mods` and `videos` respectively (lowercase). + // to unify handling to uppercase, move any non-compliant directories automatically for the user to migrate. + // can be removed 20220528 + if (newStorage.ExistsDirectory("flags")) + AttemptOperation(() => Directory.Move(newStorage.GetFullPath("flags"), newStorage.GetFullPath("Flags"))); + if (newStorage.ExistsDirectory("mods")) + AttemptOperation(() => Directory.Move(newStorage.GetFullPath("mods"), newStorage.GetFullPath("Mods"))); + if (newStorage.ExistsDirectory("videos")) + AttemptOperation(() => Directory.Move(newStorage.GetFullPath("videos"), newStorage.GetFullPath("Videos"))); + + base.ChangeTargetStorage(newStorage); + } + public IEnumerable ListTournaments() => AllTournaments.GetDirectories(string.Empty); public override void Migrate(Storage newStorage) diff --git a/osu.Game.Tournament/IO/TournamentVideoResourceStore.cs b/osu.Game.Tournament/IO/TournamentVideoResourceStore.cs index 4b26840b79..964d03220d 100644 --- a/osu.Game.Tournament/IO/TournamentVideoResourceStore.cs +++ b/osu.Game.Tournament/IO/TournamentVideoResourceStore.cs @@ -9,7 +9,7 @@ namespace osu.Game.Tournament.IO public class TournamentVideoResourceStore : NamespacedResourceStore { public TournamentVideoResourceStore(Storage storage) - : base(new StorageBackedResourceStore(storage), "videos") + : base(new StorageBackedResourceStore(storage), "Videos") { AddExtension("m4v"); AddExtension("avi"); diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs index d34a8583b9..cd74a75b10 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs @@ -197,7 +197,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro { row.Add(new Sprite { - Texture = textures.Get($"mods/{mods.ToLower()}"), + Texture = textures.Get($"Mods/{mods.ToLower()}"), Scale = new Vector2(0.5f) }); } From 21e8ab835769c5be5c66f16b241bdf6cb774b848 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 14:40:09 +0900 Subject: [PATCH 22/38] Return `ILive` from `ToLive` calls instead of realm-typed instance --- osu.Game/Database/RealmObjectExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/RealmObjectExtensions.cs b/osu.Game/Database/RealmObjectExtensions.cs index 18a926fa8c..ac4ca436ad 100644 --- a/osu.Game/Database/RealmObjectExtensions.cs +++ b/osu.Game/Database/RealmObjectExtensions.cs @@ -49,13 +49,13 @@ namespace osu.Game.Database return mapper.Map(item); } - public static List> ToLive(this IEnumerable realmList) + public static List> ToLive(this IEnumerable realmList) where T : RealmObject, IHasGuidPrimaryKey { - return realmList.Select(l => new RealmLive(l)).ToList(); + return realmList.Select(l => new RealmLive(l)).Cast>().ToList(); } - public static RealmLive ToLive(this T realmObject) + public static ILive ToLive(this T realmObject) where T : RealmObject, IHasGuidPrimaryKey { return new RealmLive(realmObject); From 3bd4872520ca02a1ec1af4de5ad4fdf548731e9d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 16:36:05 +0900 Subject: [PATCH 23/38] Add note about indexing support for `RealmNamedFileUsage.Filename` --- osu.Game/Models/RealmNamedFileUsage.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Models/RealmNamedFileUsage.cs b/osu.Game/Models/RealmNamedFileUsage.cs index ba12d51d0b..17e32510a8 100644 --- a/osu.Game/Models/RealmNamedFileUsage.cs +++ b/osu.Game/Models/RealmNamedFileUsage.cs @@ -16,6 +16,7 @@ namespace osu.Game.Models { public RealmFile File { get; set; } = null!; + // [Indexed] cannot be used on `EmbeddedObject`s as it only applies to top-level queries. May need to reconsider this if performance becomes a concern. public string Filename { get; set; } = null!; public RealmNamedFileUsage(RealmFile file, string filename) From d73e81ee63f1bc385b76a2e52c4663d04776df44 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Nov 2021 14:48:28 +0900 Subject: [PATCH 24/38] Add test coverage of non-optimised existing model check --- .../Database/BeatmapImporterTests.cs | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index 9ee237cfd9..d2193350ad 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -12,6 +12,7 @@ using NUnit.Framework; using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Logging; +using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Extensions; @@ -474,7 +475,7 @@ namespace osu.Game.Tests.Database } [Test] - public void TestImportThenDeleteThenImport() + public void TestImportThenDeleteThenImportOptimisedPath() { RunTestWithRealmAsync(async (realmFactory, storage) => { @@ -485,11 +486,39 @@ namespace osu.Game.Tests.Database deleteBeatmapSet(imported, realmFactory.Context); + Assert.IsTrue(imported.DeletePending); + var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. Assert.IsTrue(imported.ID == importedSecondTime.ID); Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); + Assert.IsFalse(imported.DeletePending); + Assert.IsFalse(importedSecondTime.DeletePending); + }); + } + + [Test] + public void TestImportThenDeleteThenImportNonOptimisedPath() + { + RunTestWithRealmAsync(async (realmFactory, storage) => + { + using var importer = new NonOptimisedBeatmapImporter(realmFactory, storage); + using var store = new RealmRulesetStore(realmFactory, storage); + + var imported = await LoadOszIntoStore(importer, realmFactory.Context); + + deleteBeatmapSet(imported, realmFactory.Context); + + Assert.IsTrue(imported.DeletePending); + + var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context); + + // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. + Assert.IsTrue(imported.ID == importedSecondTime.ID); + Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); + Assert.IsFalse(imported.DeletePending); + Assert.IsFalse(importedSecondTime.DeletePending); }); } @@ -867,5 +896,15 @@ namespace osu.Game.Tests.Database Assert.Fail(failureMessage); } + + public class NonOptimisedBeatmapImporter : BeatmapImporter + { + public NonOptimisedBeatmapImporter(RealmContextFactory realmFactory, Storage storage) + : base(realmFactory, storage) + { + } + + protected override bool HasCustomHashFunction => true; + } } } From 2ee08b5f4cb35e832dedbda3fc1c8b9876d629d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Nov 2021 19:05:34 +0900 Subject: [PATCH 25/38] Fix undelete on existing not committing transaction --- osu.Game/Stores/RealmArchiveModelImporter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Stores/RealmArchiveModelImporter.cs b/osu.Game/Stores/RealmArchiveModelImporter.cs index b74670e722..56469184a9 100644 --- a/osu.Game/Stores/RealmArchiveModelImporter.cs +++ b/osu.Game/Stores/RealmArchiveModelImporter.cs @@ -387,7 +387,9 @@ namespace osu.Game.Stores if (CanReuseExisting(existing, item)) { LogForModel(item, @$"Found existing {HumanisedModelName} for {item} (ID {existing.ID}) – skipping import."); + existing.DeletePending = false; + transaction.Commit(); return existing.ToLive(); } From 071a8c670942c04a2566e493f278acc4778352b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Nov 2021 17:34:56 +0900 Subject: [PATCH 26/38] Add test coverage showing `RealmLive` failure after an attach --- osu.Game.Tests/Database/RealmLiveTests.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs index f86761fdc8..a4b82fb8b1 100644 --- a/osu.Game.Tests/Database/RealmLiveTests.cs +++ b/osu.Game.Tests/Database/RealmLiveTests.cs @@ -29,6 +29,22 @@ namespace osu.Game.Tests.Database }); } + [Test] + public void TestAccessAfterAttach() + { + RunTestWithRealm((realmFactory, _) => + { + var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata()); + + var liveBeatmap = beatmap.ToLive(); + + using (var context = realmFactory.CreateContext()) + context.Write(r => r.Add(beatmap)); + + Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden)); + }); + } + [Test] public void TestAccessNonManaged() { From 6dcc244e2185ae77622c261b1a4c19c3cc901c8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Nov 2021 17:21:51 +0900 Subject: [PATCH 27/38] Fix `RealmLive` not working is data is attached to realm post-`ToLive` call --- osu.Game/Database/RealmLive.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Database/RealmLive.cs b/osu.Game/Database/RealmLive.cs index 73e6715aaa..5ee40f5b4d 100644 --- a/osu.Game/Database/RealmLive.cs +++ b/osu.Game/Database/RealmLive.cs @@ -17,7 +17,7 @@ namespace osu.Game.Database { public Guid ID { get; } - public bool IsManaged { get; } + public bool IsManaged => data.IsManaged; private readonly SynchronizationContext? fetchedContext; private readonly int fetchedThreadId; @@ -37,8 +37,6 @@ namespace osu.Game.Database if (data.IsManaged) { - IsManaged = true; - fetchedContext = SynchronizationContext.Current; fetchedThreadId = Thread.CurrentThread.ManagedThreadId; } From a7e4e7be3adad487acf9e190ea0a6291396ca4e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Nov 2021 18:08:02 +0900 Subject: [PATCH 28/38] Remove the ability to specify a filename in `ReplaceFile` --- osu.Game/Beatmaps/BeatmapManager.cs | 4 ++-- osu.Game/Database/ArchiveModelManager.cs | 5 ++--- osu.Game/Database/IModelFileManager.cs | 3 +-- osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 11 +++++------ 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d920b194b5..8502b91096 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -288,9 +288,9 @@ namespace osu.Game.Beatmaps #region Implementation of IModelFileManager - public void ReplaceFile(BeatmapSetInfo model, BeatmapSetFileInfo file, Stream contents, string filename = null) + public void ReplaceFile(BeatmapSetInfo model, BeatmapSetFileInfo file, Stream contents) { - beatmapModelManager.ReplaceFile(model, file, contents, filename); + beatmapModelManager.ReplaceFile(model, file, contents); } public void DeleteFile(BeatmapSetInfo model, BeatmapSetFileInfo file) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index e73f4a7f6e..8cabb55cc3 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -453,13 +453,12 @@ namespace osu.Game.Database /// The item to operate on. /// The existing file to be replaced. /// The new file contents. - /// An optional filename for the new file. Will use the previous filename if not specified. - public void ReplaceFile(TModel model, TFileModel file, Stream contents, string filename = null) + public void ReplaceFile(TModel model, TFileModel file, Stream contents) { using (ContextFactory.GetForWrite()) { DeleteFile(model, file); - AddFile(model, contents, filename ?? file.Filename); + AddFile(model, contents, file.Filename); } } diff --git a/osu.Game/Database/IModelFileManager.cs b/osu.Game/Database/IModelFileManager.cs index c74b945eb7..4bc1e2d29b 100644 --- a/osu.Game/Database/IModelFileManager.cs +++ b/osu.Game/Database/IModelFileManager.cs @@ -15,8 +15,7 @@ namespace osu.Game.Database /// The item to operate on. /// The existing file to be replaced. /// The new file contents. - /// An optional filename for the new file. Will use the previous filename if not specified. - void ReplaceFile(TModel model, TFileModel file, Stream contents, string filename = null); + void ReplaceFile(TModel model, TFileModel file, Stream contents); /// /// Delete an existing file. diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 8e739a786f..1e97218074 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -78,9 +78,9 @@ namespace osu.Game.Screens.Edit.Setup using (var stream = info.OpenRead()) { if (oldFile != null) - beatmaps.ReplaceFile(set, oldFile, stream, info.Name); - else - beatmaps.AddFile(set, stream, info.Name); + beatmaps.DeleteFile(set, oldFile); + + beatmaps.AddFile(set, stream, info.Name); } working.Value.Metadata.BackgroundFile = info.Name; @@ -105,9 +105,8 @@ namespace osu.Game.Screens.Edit.Setup using (var stream = info.OpenRead()) { if (oldFile != null) - beatmaps.ReplaceFile(set, oldFile, stream, info.Name); - else - beatmaps.AddFile(set, stream, info.Name); + beatmaps.DeleteFile(set, oldFile); + beatmaps.AddFile(set, stream, info.Name); } working.Value.Metadata.AudioFile = info.Name; From 6aad90674eeccdc505cc8b431ac0b39a27b5ab55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Nov 2021 18:06:21 +0900 Subject: [PATCH 29/38] Remove `computeHashFast` usage in `RealmArchiveModelImporter.ComputeHash` --- osu.Game/Stores/RealmArchiveModelImporter.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Stores/RealmArchiveModelImporter.cs b/osu.Game/Stores/RealmArchiveModelImporter.cs index 56469184a9..1681dad750 100644 --- a/osu.Game/Stores/RealmArchiveModelImporter.cs +++ b/osu.Game/Stores/RealmArchiveModelImporter.cs @@ -294,12 +294,8 @@ namespace osu.Game.Stores /// /// In the case of no matching files, a hash will be generated from the passed archive's . /// - protected virtual string ComputeHash(TModel item, ArchiveReader? reader = null) + protected virtual string ComputeHash(TModel item) { - if (reader != null) - // fast hashing for cases where the item's files may not be populated. - return computeHashFast(reader); - // for now, concatenate all hashable files in the set to create a unique hash. MemoryStream hashable = new MemoryStream(); @@ -374,7 +370,7 @@ namespace osu.Game.Stores // TODO: look into rollback of file additions (or delayed commit). item.Files.AddRange(createFileInfos(archive, Files, realm)); - item.Hash = ComputeHash(item, archive); + item.Hash = ComputeHash(item); // TODO: we may want to run this outside of the transaction. await Populate(item, archive, realm, cancellationToken).ConfigureAwait(false); From bac79663371dfdd4efa40c5f73192ce38efa782a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Nov 2021 18:00:28 +0900 Subject: [PATCH 30/38] Update `RealmLiveTests` to use interface type --- osu.Game.Tests/Database/RealmLiveTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs index f86761fdc8..d6eca80274 100644 --- a/osu.Game.Tests/Database/RealmLiveTests.cs +++ b/osu.Game.Tests/Database/RealmLiveTests.cs @@ -51,7 +51,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealm((realmFactory, _) => { - RealmLive? liveBeatmap = null; + ILive? liveBeatmap = null; Task.Factory.StartNew(() => { using (var threadContext = realmFactory.CreateContext()) @@ -88,7 +88,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealm((realmFactory, _) => { - RealmLive? liveBeatmap = null; + ILive? liveBeatmap = null; Task.Factory.StartNew(() => { using (var threadContext = realmFactory.CreateContext()) @@ -117,7 +117,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealm((realmFactory, _) => { - RealmLive? liveBeatmap = null; + ILive? liveBeatmap = null; Task.Factory.StartNew(() => { using (var threadContext = realmFactory.CreateContext()) @@ -143,7 +143,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealm((realmFactory, _) => { - RealmLive? liveBeatmap = null; + ILive? liveBeatmap = null; Task.Factory.StartNew(() => { using (var threadContext = realmFactory.CreateContext()) @@ -176,7 +176,7 @@ namespace osu.Game.Tests.Database using (var updateThreadContext = realmFactory.CreateContext()) { updateThreadContext.All().SubscribeForNotifications(gotChange); - RealmLive? liveBeatmap = null; + ILive? liveBeatmap = null; Task.Factory.StartNew(() => { From 94b10492be658d028bec1fc8768400c303357f51 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Nov 2021 18:20:07 +0900 Subject: [PATCH 31/38] Update legacy `SkinManager` to match new interface --- osu.Game/Skinning/SkinManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 8d07dd046a..26ff4457af 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -171,7 +171,7 @@ namespace osu.Game.Skinning var oldFile = skin.SkinInfo.Files.FirstOrDefault(f => f.Filename == filename); if (oldFile != null) - skinModelManager.ReplaceFile(skin.SkinInfo, oldFile, streamContent, oldFile.Filename); + skinModelManager.ReplaceFile(skin.SkinInfo, oldFile, streamContent); else skinModelManager.AddFile(skin.SkinInfo, streamContent, filename); } From 0fc4d6dc2a85636d8390a144dcb13ee5ecab9eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 28 Nov 2021 21:43:56 +0100 Subject: [PATCH 32/38] Implement beatmap card difficulty list --- .../TestSceneBeatmapCardDifficultyList.cs | 71 ++++++++++++ .../Cards/BeatmapCardDifficultyList.cs | 103 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDifficultyList.cs create mode 100644 osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDifficultyList.cs diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDifficultyList.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDifficultyList.cs new file mode 100644 index 0000000000..aec75884d6 --- /dev/null +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDifficultyList.cs @@ -0,0 +1,71 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps.Drawables.Cards; +using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; + +namespace osu.Game.Tests.Visual.Beatmaps +{ + public class TestSceneBeatmapCardDifficultyList : OsuTestScene + { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + var beatmapSet = new APIBeatmapSet + { + Beatmaps = new[] + { + new APIBeatmap { RulesetID = 1, StarRating = 5.76, DifficultyName = "Oni" }, + new APIBeatmap { RulesetID = 1, StarRating = 3.20, DifficultyName = "Muzukashii" }, + new APIBeatmap { RulesetID = 1, StarRating = 2.45, DifficultyName = "Futsuu" }, + + new APIBeatmap { RulesetID = 0, StarRating = 2.04, DifficultyName = "Normal" }, + new APIBeatmap { RulesetID = 0, StarRating = 3.51, DifficultyName = "Hard" }, + new APIBeatmap { RulesetID = 0, StarRating = 5.25, DifficultyName = "Insane" }, + + new APIBeatmap { RulesetID = 2, StarRating = 2.64, DifficultyName = "Salad" }, + new APIBeatmap { RulesetID = 2, StarRating = 3.56, DifficultyName = "Platter" }, + new APIBeatmap { RulesetID = 2, StarRating = 4.65, DifficultyName = "Rain" }, + + new APIBeatmap { RulesetID = 3, StarRating = 1.93, DifficultyName = "[7K] Normal" }, + new APIBeatmap { RulesetID = 3, StarRating = 3.18, DifficultyName = "[7K] Hyper" }, + new APIBeatmap { RulesetID = 3, StarRating = 4.82, DifficultyName = "[7K] Another" }, + + new APIBeatmap { RulesetID = 4, StarRating = 9.99, DifficultyName = "Unknown?!" }, + } + }; + + Child = new Container + { + Width = 300, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background2 + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(10), + Child = new BeatmapCardDifficultyList(beatmapSet) + } + } + }; + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDifficultyList.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDifficultyList.cs new file mode 100644 index 0000000000..7753d8480a --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDifficultyList.cs @@ -0,0 +1,103 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Online.Chat; +using osu.Game.Rulesets; +using osuTK; + +namespace osu.Game.Beatmaps.Drawables.Cards +{ + public class BeatmapCardDifficultyList : CompositeDrawable + { + public BeatmapCardDifficultyList(IBeatmapSetInfo beatmapSetInfo) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + FillFlowContainer flow; + + InternalChild = flow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 3) + }; + + bool firstGroup = true; + + foreach (var group in beatmapSetInfo.Beatmaps.GroupBy(beatmap => beatmap.Ruleset.OnlineID).OrderBy(group => group.Key)) + { + if (!firstGroup) + { + flow.Add(Empty().With(s => + { + s.RelativeSizeAxes = Axes.X; + s.Height = 4; + })); + } + + foreach (var difficulty in group.OrderBy(b => b.StarRating)) + flow.Add(new BeatmapCardDifficultyRow(difficulty)); + + firstGroup = false; + } + } + + private class BeatmapCardDifficultyRow : CompositeDrawable + { + private readonly IBeatmapInfo beatmapInfo; + + public BeatmapCardDifficultyRow(IBeatmapInfo beatmapInfo) + { + this.beatmapInfo = beatmapInfo; + } + + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4, 0), + Children = new[] + { + (rulesets.GetRuleset(beatmapInfo.Ruleset.OnlineID)?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle }).With(icon => + { + icon.Anchor = icon.Origin = Anchor.CentreLeft; + icon.Size = new Vector2(16); + }), + new StarRatingDisplay(new StarDifficulty(beatmapInfo.StarRating, 0), StarRatingDisplaySize.Small) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + new LinkFlowContainer(s => + { + s.Font = OsuFont.Default.With(size: 14, weight: FontWeight.SemiBold); + }).With(d => + { + d.AutoSizeAxes = Axes.Both; + d.Anchor = Anchor.CentreLeft; + d.Origin = Anchor.CentreLeft; + d.Padding = new MarginPadding { Bottom = 2 }; + d.AddLink(beatmapInfo.DifficultyName, LinkAction.OpenBeatmap, beatmapInfo.OnlineID.ToString()); + }) + } + }; + } + } + } +} From 45656c359936b935e17b8ef0ec4b6ada043cc85f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 29 Nov 2021 22:06:11 +0100 Subject: [PATCH 33/38] Fix difficulty spectrum display not ordering ruleset groups by ID --- osu.Game/Beatmaps/Drawables/DifficultySpectrumDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultySpectrumDisplay.cs b/osu.Game/Beatmaps/Drawables/DifficultySpectrumDisplay.cs index f4501f0633..5b211084ab 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultySpectrumDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultySpectrumDisplay.cs @@ -62,7 +62,7 @@ namespace osu.Game.Beatmaps.Drawables // matching web: https://github.com/ppy/osu-web/blob/d06d8c5e735eb1f48799b1654b528e9a7afb0a35/resources/assets/lib/beatmapset-panel.tsx#L127 bool collapsed = beatmapSet.Beatmaps.Count() > 12; - foreach (var rulesetGrouping in beatmapSet.Beatmaps.GroupBy(beatmap => beatmap.Ruleset.OnlineID)) + foreach (var rulesetGrouping in beatmapSet.Beatmaps.GroupBy(beatmap => beatmap.Ruleset.OnlineID).OrderBy(group => group.Key)) { flow.Add(new RulesetDifficultyGroup(rulesetGrouping.Key, rulesetGrouping, collapsed)); } From a73919917c3f829bee58a827c9071a8e145ddb51 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Nov 2021 12:32:08 +0900 Subject: [PATCH 34/38] Fix intermittent test failures in `TestScenBeatmapInfoWedge` due to async load https://github.com/ppy/osu/runs/4358685294?check_suite_focus=true Occurs due to the wedge content also reloading on ruleset change, which wasn't being accounted for. In a fail case, the content would change during the "select beatmap" step's async load wait, causing incorrect results. https://github.com/ppy/osu/blob/51a353e12db189f9958228d30fe045b8460c6b92/osu.Game/Screens/Select/BeatmapInfoWedge.cs#L70 --- .../SongSelect/TestSceneBeatmapInfoWedge.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs index e7c54efa8c..9ad5242df4 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.SongSelect beatmaps.Add(testBeatmap); - AddStep("set ruleset", () => Ruleset.Value = rulesetInfo); + setRuleset(rulesetInfo); selectBeatmap(testBeatmap); @@ -167,6 +167,22 @@ namespace osu.Game.Tests.Visual.SongSelect label => label.Statistic.Name == "BPM" && label.Statistic.Content == target.ToString(CultureInfo.InvariantCulture))); } + private void setRuleset(RulesetInfo rulesetInfo) + { + Container containerBefore = null; + + AddStep("set ruleset", () => + { + // wedge content is only refreshed if the ruleset changes, so only wait for load in that case. + if (!rulesetInfo.Equals(Ruleset.Value)) + containerBefore = infoWedge.DisplayedContent; + + Ruleset.Value = rulesetInfo; + }); + + AddUntilStep("wait for async load", () => infoWedge.DisplayedContent != containerBefore); + } + private void selectBeatmap([CanBeNull] IBeatmap b) { Container containerBefore = null; From f921acc681fbef678c39a15cc3502b58d286148c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Nov 2021 13:01:40 +0900 Subject: [PATCH 35/38] Fix chat tab dropdown not being reachable at default sizing Would have liked to fix this in a more local way, but the structure of the dropdowns is just a pain in the ass to work with, so this will do for now. --- osu.Game/Graphics/UserInterface/OsuTabDropdown.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTabDropdown.cs b/osu.Game/Graphics/UserInterface/OsuTabDropdown.cs index 68ffc6bf4e..b7e25ae4e7 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabDropdown.cs @@ -66,7 +66,7 @@ namespace osu.Game.Graphics.UserInterface Origin = Anchor.TopRight; BackgroundColour = Color4.Black.Opacity(0.7f); - MaxHeight = 400; + MaxHeight = 200; } protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableOsuTabDropdownMenuItem(item); From 384a0664c27101c9f32712942e817913a12cb73e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Nov 2021 14:05:44 +0900 Subject: [PATCH 36/38] Remove unused migration method --- osu.Game/OsuGameBase.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 88c9ab370c..bfc0da468b 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -442,10 +442,6 @@ namespace osu.Game protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); - private void migrateDataToRealm() - { - } - private void onRulesetChanged(ValueChangedEvent r) { if (r.NewValue?.Available != true) From 6e4cd91b7bb782572e2e7abbd5b6dc9926dca95e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Nov 2021 14:12:36 +0900 Subject: [PATCH 37/38] Fix update thread realm context never being `Refresh()`ed --- osu.Game/OsuGameBase.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index bfc0da468b..6eb67b34e8 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -377,6 +377,13 @@ namespace osu.Game FrameStatistics.ValueChanged += e => fpsDisplayVisible.Value = e.NewValue != FrameStatisticsMode.None; } + protected override void Update() + { + base.Update(); + + realmFactory.Refresh(); + } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); From 0feec0996665a0009479d4667a4500d3edd8b8b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Nov 2021 14:12:49 +0900 Subject: [PATCH 38/38] Refactor beatmap importer tests to ensure realm is refreshed when waiting on state --- .../Database/BeatmapImporterTests.cs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index d2193350ad..a6edd6cb5f 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -852,7 +852,11 @@ namespace osu.Game.Tests.Database { IQueryable? resultSets = null; - waitForOrAssert(() => (resultSets = realm.All().Where(s => !s.DeletePending && s.OnlineID == 241526)).Any(), + waitForOrAssert(() => + { + realm.Refresh(); + return (resultSets = realm.All().Where(s => !s.DeletePending && s.OnlineID == 241526)).Any(); + }, @"BeatmapSet did not import to the database in allocated time.", timeout); // ensure we were stored to beatmap database backing... @@ -865,16 +869,16 @@ namespace osu.Game.Tests.Database // ReSharper disable once PossibleUnintendedReferenceComparison IEnumerable queryBeatmaps() => realm.All().Where(s => s.BeatmapSet != null && s.BeatmapSet == set); - waitForOrAssert(() => queryBeatmaps().Count() == 12, @"Beatmaps did not import to the database in allocated time", timeout); - waitForOrAssert(() => queryBeatmapSets().Count() == 1, @"BeatmapSet did not import to the database in allocated time", timeout); + Assert.AreEqual(12, queryBeatmaps().Count(), @"Beatmap count was not correct"); + Assert.AreEqual(1, queryBeatmapSets().Count(), @"Beatmapset count was not correct"); - int countBeatmapSetBeatmaps = 0; - int countBeatmaps = 0; + int countBeatmapSetBeatmaps; + int countBeatmaps; - waitForOrAssert(() => - (countBeatmapSetBeatmaps = queryBeatmapSets().First().Beatmaps.Count) == - (countBeatmaps = queryBeatmaps().Count()), - $@"Incorrect database beatmap count post-import ({countBeatmaps} but should be {countBeatmapSetBeatmaps}).", timeout); + Assert.AreEqual( + countBeatmapSetBeatmaps = queryBeatmapSets().First().Beatmaps.Count, + countBeatmaps = queryBeatmaps().Count(), + $@"Incorrect database beatmap count post-import ({countBeatmaps} but should be {countBeatmapSetBeatmaps})."); foreach (RealmBeatmap b in set.Beatmaps) Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineID == b.OnlineID));