From 5ca93758dc40e50094897877749391ec9dea0d5b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 17 Feb 2020 16:59:35 +0900 Subject: [PATCH 01/36] Fix music playlist being enumerated asynchronously --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 8 ++++-- osu.Game/Overlays/MusicController.cs | 30 +++++++++++++++++----- osu.Game/Overlays/NowPlayingOverlay.cs | 11 +++++--- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 8f753fd3aa..b878aba489 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -75,8 +75,6 @@ namespace osu.Game.Overlays.Music }, }; - list.Items.BindTo(beatmapSets); - filter.Search.OnCommit = (sender, newText) => { BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault(); @@ -87,7 +85,13 @@ namespace osu.Game.Overlays.Music beatmap.Value.Track.Restart(); } }; + } + protected override void LoadComplete() + { + base.LoadComplete(); + + list.Items.BindTo(beatmapSets); beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo, true); } diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 7c7daf6eb9..d788929739 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -25,7 +25,16 @@ namespace osu.Game.Overlays [Resolved] private BeatmapManager beatmaps { get; set; } - public IBindableList BeatmapSets => beatmapSets; + public IBindableList BeatmapSets + { + get + { + if (LoadState < LoadState.Ready) + throw new InvalidOperationException($"{nameof(BeatmapSets)} should not be accessed before the music controller is loaded."); + + return beatmapSets; + } + } /// /// Point in time after which the current track will be restarted on triggering a "previous track" action. @@ -54,16 +63,18 @@ namespace osu.Game.Overlays [BackgroundDependencyLoader] private void load() { - beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next())); beatmaps.ItemAdded += handleBeatmapAdded; beatmaps.ItemRemoved += handleBeatmapRemoved; + + beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next())); } protected override void LoadComplete() { + base.LoadComplete(); + beatmap.BindValueChanged(beatmapChanged, true); mods.BindValueChanged(_ => ResetTrackAdjustments(), true); - base.LoadComplete(); } /// @@ -82,11 +93,16 @@ namespace osu.Game.Overlays /// public bool IsPlaying => current?.Track.IsRunning ?? false; - private void handleBeatmapAdded(BeatmapSetInfo set) => - Schedule(() => beatmapSets.Add(set)); + private void handleBeatmapAdded(BeatmapSetInfo set) => Schedule(() => + { + if (!beatmapSets.Contains(set)) + beatmapSets.Add(set); + }); - private void handleBeatmapRemoved(BeatmapSetInfo set) => - Schedule(() => beatmapSets.RemoveAll(s => s.ID == set.ID)); + private void handleBeatmapRemoved(BeatmapSetInfo set) => Schedule(() => + { + beatmapSets.RemoveAll(s => s.ID == set.ID); + }); private ScheduledDelegate seekDelegate; diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index dfcf99d30c..118cb037cb 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -58,6 +58,9 @@ namespace osu.Game.Overlays [Resolved] private Bindable beatmap { get; set; } + [Resolved] + private OsuColour colours { get; set; } + public NowPlayingOverlay() { Width = 400; @@ -65,7 +68,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { Children = new Drawable[] { @@ -182,15 +185,15 @@ namespace osu.Game.Overlays } } }; - - playlist.BeatmapSets.BindTo(musicController.BeatmapSets); - playlist.State.ValueChanged += s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint); } protected override void LoadComplete() { base.LoadComplete(); + playlist.BeatmapSets.BindTo(musicController.BeatmapSets); + playlist.State.BindValueChanged(s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint), true); + beatmap.BindDisabledChanged(beatmapDisabledChanged, true); musicController.TrackChanged += trackChanged; From 5340d1de59d5d332b55ce1790fceda94c515f79f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Feb 2020 15:05:04 +0900 Subject: [PATCH 02/36] Move combo colour update logic to osu! ruleset --- .../Objects/Drawables/DrawableOsuHitObject.cs | 4 ++++ .../Objects/Drawables/DrawableHitObject.cs | 17 +++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index a677cb6a72..1bb72a3176 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -1,11 +1,13 @@ // 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.Game.Rulesets.Objects.Drawables; using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Graphics.Containers; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -54,6 +56,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } + protected override void UpdateComboColour(Color4 proposedColour, IReadOnlyList comboColours) => AccentColour.Value = proposedColour; + protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(HitObject, judgement); } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 6f20bcf595..c5ce490845 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Objects.Drawables if (HitObject is IHasComboInformation combo) { comboIndexBindable = combo.ComboIndexBindable.GetBoundCopy(); - comboIndexBindable.BindValueChanged(_ => updateAccentColour(), true); + comboIndexBindable.BindValueChanged(_ => updateComboColour(), true); } samplesBindable = HitObject.SamplesBindable.GetBoundCopy(); @@ -336,7 +336,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { base.SkinChanged(skin, allowFallback); - updateAccentColour(); + updateComboColour(); ApplySkin(skin, allowFallback); @@ -344,15 +344,24 @@ namespace osu.Game.Rulesets.Objects.Drawables updateState(State.Value, true); } - private void updateAccentColour() + private void updateComboColour() { if (HitObject is IHasComboInformation combo) { var comboColours = CurrentSkin.GetConfig>(GlobalSkinColours.ComboColours)?.Value; - AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; + UpdateComboColour(comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White, comboColours); } } + /// + /// Called when a combo colour change is proposed. + /// + /// The proposed combo colour, based off the combo index. + /// A list of combo colours provided by the beatmap or skin. Can be null if not available. + protected virtual void UpdateComboColour(Color4 proposedColour, IReadOnlyList comboColours) + { + } + /// /// Called when a change is made to the skin. /// From 345eaff76ddadab913eba031eba6c744ac06f694 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Feb 2020 15:57:15 +0900 Subject: [PATCH 03/36] Fix regressing tests --- osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs index 17dc27543d..7469771e0b 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -76,6 +76,8 @@ namespace osu.Game.Tests.Gameplay : base(new TestHitObjectWithCombo()) { } + + protected override void UpdateComboColour(Color4 proposedColour, IReadOnlyList comboColours) => AccentColour.Value = proposedColour; } private class TestHitObjectWithCombo : HitObject, IHasComboInformation From 1938dd04cf320b556663c1c1f904eaa30fa759cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Feb 2020 15:37:12 +0900 Subject: [PATCH 04/36] Fix indices in beatmap not being transferred to children (and being off by one) --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index db52fbac1b..1a5d0f983b 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -34,9 +34,14 @@ namespace osu.Game.Rulesets.Catch.Beatmaps foreach (var obj in Beatmap.HitObjects.OfType()) { - obj.IndexInBeatmap = index++; + obj.IndexInBeatmap = index; + foreach (var nested in obj.NestedHitObjects.OfType()) + nested.IndexInBeatmap = index; + if (obj.LastInCombo && obj.NestedHitObjects.LastOrDefault() is IHasComboInformation lastNested) lastNested.LastInCombo = true; + + index++; } } From dff218afd1f9c5b28ae9375fec288b529a5d4759 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Feb 2020 14:31:43 +0900 Subject: [PATCH 05/36] Fix ordering of fruits to match stable --- osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index e4ad49ea50..e287797137 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -100,8 +100,8 @@ namespace osu.Game.Rulesets.Catch.Objects { Pear, Grape, - Raspberry, Pineapple, + Raspberry, Banana // banananananannaanana } } From d3844f912abd7b88b3391c1190422851b04dbb5c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Feb 2020 14:41:25 +0900 Subject: [PATCH 06/36] Fix fruit representation not cycling as often as it should --- osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index e287797137..5243091625 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.Objects public int IndexInBeatmap { get; set; } - public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(ComboIndex % 4); + public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(IndexInBeatmap % 4); public virtual bool NewCombo { get; set; } From 7b0c3281c29938ef01ff40949a954884bea87357 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 16:49:39 +0300 Subject: [PATCH 07/36] Make country names clickable --- .../Rankings/Tables/CountriesTable.cs | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs index 32ac1404bc..0b9a48ce0e 100644 --- a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs @@ -9,6 +9,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics; using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Rankings.Tables { @@ -61,18 +62,35 @@ namespace osu.Game.Overlays.Rankings.Tables } }; - private class CountryName : OsuSpriteText + private class CountryName : OsuHoverContainer { + protected override IEnumerable EffectTargets => new[] { text }; + + [Resolved(canBeNull: true)] + private RankingsOverlay rankings { get; set; } + + private readonly OsuSpriteText text; + private readonly Country country; + public CountryName(Country country) { - Font = OsuFont.GetFont(size: 12); - Text = country.FullName ?? string.Empty; + this.country = country; + + AutoSizeAxes = Axes.Both; + Add(text = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 12), + Text = country.FullName ?? string.Empty, + }); } [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - Colour = colourProvider.Light2; + IdleColour = colourProvider.Light2; + HoverColour = colourProvider.Content2; + + Action = () => rankings?.ShowCountry(country); } } } From a79398ddbd698d165ee7b0e35242c7c4bd3f4641 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 17:09:22 +0300 Subject: [PATCH 08/36] Fix incorrect caching in TestSceneRankingsOverlay --- osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs index a769ebe4a9..47582e5486 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs @@ -29,8 +29,9 @@ namespace osu.Game.Tests.Visual.Online typeof(RankingsOverlayHeader) }; - [Cached] - private RankingsOverlay rankingsOverlay; + [Cached(typeof(RankingsOverlay))] + + private readonly RankingsOverlay rankingsOverlay; private readonly Bindable countryBindable = new Bindable(); private readonly Bindable scope = new Bindable(); From 1417c901738a5be99f56629d02f055f91598e996 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 17:24:44 +0300 Subject: [PATCH 09/36] Remove redundant blank line --- osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs index 47582e5486..83e5cd0fe7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs @@ -30,7 +30,6 @@ namespace osu.Game.Tests.Visual.Online }; [Cached(typeof(RankingsOverlay))] - private readonly RankingsOverlay rankingsOverlay; private readonly Bindable countryBindable = new Bindable(); From 98654586de78a3d4ace7cd3ef4d60d7af26580b4 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 17:28:14 +0300 Subject: [PATCH 10/36] Implement BeatmapListingHeader component --- .../BeatmapListing/BeatmapListingHeader.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs new file mode 100644 index 0000000000..5af92914de --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs @@ -0,0 +1,24 @@ +// 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.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.BeatmapListing +{ + public class BeatmapListingHeader : OverlayHeader + { + protected override ScreenTitle CreateTitle() => new BeatmapListingTitle(); + + private class BeatmapListingTitle : ScreenTitle + { + public BeatmapListingTitle() + { + Title = @"beatmap"; + Section = @"listing"; + } + + protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/changelog"); + } + } +} From 1442f5e0db37185c88fae5744d30e2c130904249 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 17:30:26 +0300 Subject: [PATCH 11/36] Use DirectSortCriteria for BeatmapListingSortTabControl --- .../BeatmapListingSortTabControl.cs | 24 ++++++------------- osu.Game/Overlays/Direct/FilterControl.cs | 3 +-- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs index cb41b33bc4..27c43b092a 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs @@ -8,16 +8,17 @@ using osu.Framework.Graphics; using osuTK.Graphics; using osuTK; using osu.Framework.Input.Events; +using osu.Game.Overlays.Direct; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapListingSortTabControl : OverlaySortTabControl + public class BeatmapListingSortTabControl : OverlaySortTabControl { public readonly Bindable SortDirection = new Bindable(Overlays.SortDirection.Descending); public BeatmapListingSortTabControl() { - Current.Value = BeatmapSortCriteria.Ranked; + Current.Value = DirectSortCriteria.Ranked; } protected override SortTabControl CreateControl() => new BeatmapSortTabControl @@ -29,7 +30,7 @@ namespace osu.Game.Overlays.BeatmapListing { public readonly Bindable SortDirection = new Bindable(); - protected override TabItem CreateTabItem(BeatmapSortCriteria value) => new BeatmapSortTabItem(value) + protected override TabItem CreateTabItem(DirectSortCriteria value) => new BeatmapSortTabItem(value) { SortDirection = { BindTarget = SortDirection } }; @@ -39,12 +40,12 @@ namespace osu.Game.Overlays.BeatmapListing { public readonly Bindable SortDirection = new Bindable(); - public BeatmapSortTabItem(BeatmapSortCriteria value) + public BeatmapSortTabItem(DirectSortCriteria value) : base(value) { } - protected override TabButton CreateTabButton(BeatmapSortCriteria value) => new BeatmapTabButton(value) + protected override TabButton CreateTabButton(DirectSortCriteria value) => new BeatmapTabButton(value) { Active = { BindTarget = Active }, SortDirection = { BindTarget = SortDirection } @@ -66,7 +67,7 @@ namespace osu.Game.Overlays.BeatmapListing private readonly SpriteIcon icon; - public BeatmapTabButton(BeatmapSortCriteria value) + public BeatmapTabButton(DirectSortCriteria value) : base(value) { Add(icon = new SpriteIcon @@ -104,15 +105,4 @@ namespace osu.Game.Overlays.BeatmapListing } } } - - public enum BeatmapSortCriteria - { - Title, - Artist, - Difficulty, - Ranked, - Rating, - Plays, - Favourites, - } } diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs index 8b04bf0387..70a3ab54fb 100644 --- a/osu.Game/Overlays/Direct/FilterControl.cs +++ b/osu.Game/Overlays/Direct/FilterControl.cs @@ -34,14 +34,13 @@ namespace osu.Game.Overlays.Direct public enum DirectSortCriteria { - Relevance, Title, Artist, - Creator, Difficulty, Ranked, Rating, Plays, Favourites, + Relevance, } } From 01202f09bec882209c314a34cf05543c3acaa0a0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 17:32:43 +0300 Subject: [PATCH 12/36] Expand SearchBeatmapSetsResponse --- osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs index 28863cb0e0..845c84430f 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs @@ -2,12 +2,20 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using Newtonsoft.Json; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { public class SearchBeatmapSetsResponse : ResponseWithCursor { + [JsonProperty("beatmapsets")] public IEnumerable BeatmapSets; + + [JsonProperty("error")] + public string Error; + + [JsonProperty("total")] + public int Total; } } From 255c8d3a1306149ff396c96a1a7997ba6a3e9912 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 17:33:48 +0300 Subject: [PATCH 13/36] Adjust SearchBeatmapSetsRequest for new usage --- .../API/Requests/SearchBeatmapSetsRequest.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index 5652b8d2bd..930ca8fdf1 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.ComponentModel; +using osu.Framework.IO.Network; using osu.Game.Overlays; using osu.Game.Overlays.Direct; using osu.Game.Rulesets; @@ -26,8 +27,21 @@ namespace osu.Game.Online.API.Requests this.direction = direction; } - // ReSharper disable once ImpureMethodCallOnReadonlyValueField - protected override string Target => $@"beatmapsets/search?q={query}&m={ruleset.ID ?? 0}&s={searchCategory.ToString().ToLowerInvariant()}&sort={sortCriteria.ToString().ToLowerInvariant()}_{directionString}"; + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.AddParameter("q", query); + + if (ruleset.ID.HasValue) + req.AddParameter("m", ruleset.ID.Value.ToString()); + + req.AddParameter("s", searchCategory.ToString().ToLowerInvariant()); + req.AddParameter("sort", $"{sortCriteria.ToString().ToLowerInvariant()}_{directionString}"); + + return req; + } + + protected override string Target => @"beatmapsets/search"; } public enum BeatmapSearchCategory From 8fcfb73d722b54380bd9b8b525eb38c38197b0ce Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 17:40:54 +0300 Subject: [PATCH 14/36] Implement BeatmapListingOverlay --- .../Online/TestSceneBeatmapListingOverlay.cs | 39 +++ osu.Game/Overlays/BeatmapListingOverlay.cs | 229 ++++++++++++++++++ 2 files changed, 268 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs create mode 100644 osu.Game/Overlays/BeatmapListingOverlay.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs new file mode 100644 index 0000000000..7c05d99c59 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs @@ -0,0 +1,39 @@ +// 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 osu.Game.Overlays; +using NUnit.Framework; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneBeatmapListingOverlay : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(BeatmapListingOverlay), + }; + + protected override bool UseOnlineAPI => true; + + private readonly BeatmapListingOverlay overlay; + + public TestSceneBeatmapListingOverlay() + { + Add(overlay = new BeatmapListingOverlay()); + } + + [Test] + public void TestShow() + { + AddStep("Show", overlay.Show); + } + + [Test] + public void TestHide() + { + AddStep("Hide", overlay.Hide); + } + } +} diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs new file mode 100644 index 0000000000..971a1b46d2 --- /dev/null +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -0,0 +1,229 @@ +// 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.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Threading; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.BeatmapListing; +using osu.Game.Overlays.Direct; +using osu.Game.Rulesets; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays +{ + public class BeatmapListingOverlay : FullscreenOverlay + { + [Resolved] + private PreviewTrackManager previewTrackManager { get; set; } + + [Resolved] + private RulesetStore rulesets { get; set; } + + private SearchBeatmapSetsRequest getSetsRequest; + private Container panelsPlaceholder; + private BeatmapListingSearchSection searchSection; + private BeatmapListingSortTabControl sortControl; + + public BeatmapListingOverlay() + : base(OverlayColourScheme.Blue) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourProvider.Background6 + }, + new BasicScrollContainer + { + RelativeSizeAxes = Axes.Both, + ScrollbarVisible = false, + Child = new ReverseChildIDFillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 10), + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Colour = Color4.Black.Opacity(0.25f), + Type = EdgeEffectType.Shadow, + Radius = 3, + Offset = new Vector2(0f, 1f), + }, + Children = new Drawable[] + { + new BeatmapListingHeader(), + searchSection = new BeatmapListingSearchSection(), + } + }, + new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourProvider.Background4, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + Height = 40, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourProvider.Background5 + }, + sortControl = new BeatmapListingSortTabControl + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Left = 20 } + } + } + }, + panelsPlaceholder = new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Padding = new MarginPadding { Vertical = 15, Horizontal = 20 }, + } + } + } + } + } + } + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + var sortCriteria = sortControl.Current; + var sortDirection = sortControl.SortDirection; + + searchSection.Query.BindValueChanged(query => + { + sortCriteria.Value = string.IsNullOrEmpty(query.NewValue) ? DirectSortCriteria.Ranked : DirectSortCriteria.Relevance; + sortDirection.Value = SortDirection.Descending; + + Scheduler.AddOnce(updateSearch); + }); + + searchSection.Query.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); + searchSection.Ruleset.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); + searchSection.Category.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); + sortCriteria.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); + sortDirection.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); + } + + private void updateSearch() + { + if (!IsLoaded) + return; + + if (State.Value == Visibility.Hidden) + return; + + if (API == null) + return; + + getSetsRequest?.Cancel(); + previewTrackManager.StopAnyPlaying(this); + + panelsPlaceholder.FadeColour(Color4.DimGray, 400, Easing.OutQuint); + + getSetsRequest = new SearchBeatmapSetsRequest( + searchSection.Query.Value, + searchSection.Ruleset.Value, + searchSection.Category.Value, + sortControl.Current.Value, + sortControl.SortDirection.Value); + + getSetsRequest.Success += response => Schedule(() => recreatePanels(response)); + + API.Queue(getSetsRequest); + } + + private void recreatePanels(SearchBeatmapSetsResponse response) + { + var beatmaps = response.BeatmapSets.Select(r => r.ToBeatmapSet(rulesets)).ToList(); + + var hasError = !string.IsNullOrEmpty(response.Error); + + if (response.Total == 0 || hasError) + { + searchSection.BeatmapSet = null; + panelsPlaceholder.Clear(); + panelsPlaceholder.FadeColour(Color4.White); + panelsPlaceholder.Add(new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = hasError ? response.Error : @"... nope, nothing found." + }); + return; + } + + var newPanels = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(10), + Alpha = 0, + ChildrenEnumerable = beatmaps.Select(b => new DirectGridPanel(b) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }) + }; + + LoadComponentAsync(newPanels, loaded => + { + panelsPlaceholder.Clear(); + panelsPlaceholder.FadeColour(Color4.White); + panelsPlaceholder.Add(loaded); + loaded.FadeIn(600, Easing.OutQuint); + searchSection.BeatmapSet = beatmaps.First(); + }); + } + } +} From 0c78c8cb4f19283c2b680e1db1d173fbc8fef07d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 17:44:15 +0300 Subject: [PATCH 15/36] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index b9b127309a..b9ef783b2a 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -53,7 +53,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index bd5219b872..6b8f8fee8c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -22,7 +22,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 2c1aff7d3c..f68bedc57f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -73,7 +73,7 @@ - + From 237be50e37159c0a7f3f97fc434c76a2f1e0c4aa Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 18:17:02 +0300 Subject: [PATCH 16/36] Implement DrawableErrorHandler component --- osu.Game/Overlays/BeatmapListingOverlay.cs | 90 ++++++++++++++++++---- 1 file changed, 76 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 971a1b46d2..eacf883339 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -2,12 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using System.Threading; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; using osu.Framework.Threading; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -31,6 +34,8 @@ namespace osu.Game.Overlays private RulesetStore rulesets { get; set; } private SearchBeatmapSetsRequest getSetsRequest; + private CancellationTokenSource cancellationToken; + private Container panelsPlaceholder; private BeatmapListingSearchSection searchSection; private BeatmapListingSortTabControl sortControl; @@ -121,7 +126,7 @@ namespace osu.Game.Overlays { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, - Padding = new MarginPadding { Vertical = 15, Horizontal = 20 }, + Padding = new MarginPadding { Horizontal = 20 }, } } } @@ -167,6 +172,7 @@ namespace osu.Game.Overlays return; getSetsRequest?.Cancel(); + cancellationToken?.Cancel(); previewTrackManager.StopAnyPlaying(this); panelsPlaceholder.FadeColour(Color4.DimGray, 400, Easing.OutQuint); @@ -185,30 +191,28 @@ namespace osu.Game.Overlays private void recreatePanels(SearchBeatmapSetsResponse response) { - var beatmaps = response.BeatmapSets.Select(r => r.ToBeatmapSet(rulesets)).ToList(); - var hasError = !string.IsNullOrEmpty(response.Error); if (response.Total == 0 || hasError) { searchSection.BeatmapSet = null; - panelsPlaceholder.Clear(); - panelsPlaceholder.FadeColour(Color4.White); - panelsPlaceholder.Add(new OsuSpriteText + + LoadComponentAsync(new DrawableErrorHandler(hasError ? response.Error : @"... nope, nothing found."), loaded => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = hasError ? response.Error : @"... nope, nothing found." - }); + addContentToPlaceholder(loaded); + }, (cancellationToken = new CancellationTokenSource()).Token); return; } + var beatmaps = response.BeatmapSets.Select(r => r.ToBeatmapSet(rulesets)).ToList(); + var newPanels = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Spacing = new Vector2(10), Alpha = 0, + Margin = new MarginPadding { Vertical = 15 }, ChildrenEnumerable = beatmaps.Select(b => new DirectGridPanel(b) { Anchor = Anchor.TopCentre, @@ -218,12 +222,70 @@ namespace osu.Game.Overlays LoadComponentAsync(newPanels, loaded => { - panelsPlaceholder.Clear(); - panelsPlaceholder.FadeColour(Color4.White); - panelsPlaceholder.Add(loaded); + addContentToPlaceholder(loaded); loaded.FadeIn(600, Easing.OutQuint); searchSection.BeatmapSet = beatmaps.First(); - }); + }, (cancellationToken = new CancellationTokenSource()).Token); + } + + private void addContentToPlaceholder(Drawable content) + { + panelsPlaceholder.Clear(); + panelsPlaceholder.FadeColour(Color4.White); + panelsPlaceholder.Add(content); + } + + protected override void Dispose(bool isDisposing) + { + getSetsRequest?.Cancel(); + cancellationToken?.Cancel(); + + base.Dispose(isDisposing); + } + + private class DrawableErrorHandler : CompositeDrawable + { + private readonly string error; + + public DrawableErrorHandler(string error) + { + this.error = error; + + RelativeSizeAxes = Axes.X; + Height = 250; + Margin = new MarginPadding { Top = 15 }; + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + AddInternal(new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + Texture = textures.Get(@"Online/not-found") + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = error, + } + } + }); + } } } } From 2ef3c7873605f8dcb7b61bacc5cf90bfe2359b3a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 18:19:15 +0300 Subject: [PATCH 17/36] Remove query binding duplicate --- osu.Game/Overlays/BeatmapListingOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index eacf883339..143e20d69f 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -153,7 +153,6 @@ namespace osu.Game.Overlays Scheduler.AddOnce(updateSearch); }); - searchSection.Query.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); searchSection.Ruleset.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); searchSection.Category.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); sortCriteria.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); From edef84d9c388588749a390be116240653f80bd8c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 19 Feb 2020 19:15:18 +0300 Subject: [PATCH 18/36] CI fixes --- osu.Game/Overlays/BeatmapListingOverlay.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 143e20d69f..546d0bc9bb 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -using osu.Framework.Threading; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; @@ -196,10 +195,9 @@ namespace osu.Game.Overlays { searchSection.BeatmapSet = null; - LoadComponentAsync(new DrawableErrorHandler(hasError ? response.Error : @"... nope, nothing found."), loaded => - { - addContentToPlaceholder(loaded); - }, (cancellationToken = new CancellationTokenSource()).Token); + LoadComponentAsync(new DrawableErrorHandler(hasError ? response.Error : @"... nope, nothing found."), + addContentToPlaceholder, + (cancellationToken = new CancellationTokenSource()).Token); return; } From 62227ad856efb44cf4cb26c31d2965b9e30e277e Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Wed, 19 Feb 2020 17:58:10 +0100 Subject: [PATCH 19/36] Add MaxCombo to BeatmapInfo --- osu.Game/Beatmaps/BeatmapInfo.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index bcc9ab885e..68d113ce40 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -51,6 +51,9 @@ namespace osu.Game.Beatmaps [NotMapped] public BeatmapOnlineInfo OnlineInfo { get; set; } + [NotMapped] + public int? MaxCombo { get; set; } + /// /// The playable length in milliseconds of this beatmap. /// From 23c9782f509c5af8f543bedcf57a7c5d1c8e2154 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Wed, 19 Feb 2020 17:58:41 +0100 Subject: [PATCH 20/36] Add maxCombo to APIBeatmap --- osu.Game/Online/API/Requests/Responses/APIBeatmap.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index f4d67a56aa..e023a2502f 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -61,6 +61,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"failtimes")] private BeatmapMetrics metrics { get; set; } + [JsonProperty(@"max_combo")] + private int? maxCombo { get; set; } + public BeatmapInfo ToBeatmap(RulesetStore rulesets) { var set = BeatmapSet?.ToBeatmapSet(rulesets); @@ -76,6 +79,7 @@ namespace osu.Game.Online.API.Requests.Responses Status = Status, BeatmapSet = set, Metrics = metrics, + MaxCombo = maxCombo, BaseDifficulty = new BeatmapDifficulty { DrainRate = drainRate, From 7ea67aa6726428198498d299e17f7a16c360caad Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Wed, 19 Feb 2020 17:58:59 +0100 Subject: [PATCH 21/36] Highlight max combo on beatmap leaderboards --- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 43a45bd2fc..cf7ecd7408 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -146,7 +146,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores new OsuSpriteText { Text = $@"{score.MaxCombo:N0}x", - Font = OsuFont.GetFont(size: text_size) + Font = OsuFont.GetFont(size: text_size), + Colour = score.MaxCombo == score.Beatmap.MaxCombo ? highAccuracyColour : Color4.White } }); From 84d6a8ae2ade456f1f4b4e71f2c43b1e4fe980b4 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Wed, 19 Feb 2020 19:42:56 +0100 Subject: [PATCH 22/36] Add null check --- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index cf7ecd7408..954eada612 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -147,7 +147,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Text = $@"{score.MaxCombo:N0}x", Font = OsuFont.GetFont(size: text_size), - Colour = score.MaxCombo == score.Beatmap.MaxCombo ? highAccuracyColour : Color4.White + Colour = score.MaxCombo == score.Beatmap?.MaxCombo ? highAccuracyColour : Color4.White } }); From b2d9004212c5221f751d4bba813f2d4630acf375 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 20 Feb 2020 08:37:23 +0900 Subject: [PATCH 23/36] Fix possible test failures due to async loads --- .../TestSceneDrawableRoomPlaylist.cs | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 4f54e451b7..9fbe8f7ffe 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Multiplayer typeof(DrawableRoomPlaylistItem) }; - private DrawableRoomPlaylist playlist; + private TestPlaylist playlist; [Test] public void TestNonEditableNonSelectable() @@ -211,30 +211,45 @@ namespace osu.Game.Tests.Visual.Multiplayer private void assertDeleteButtonVisibility(int index, bool visible) => AddAssert($"delete button {index} {(visible ? "is" : "is not")} visible", () => (playlist.ChildrenOfType().ElementAt(2 + index * 2).Alpha > 0) == visible); - private void createPlaylist(bool allowEdit, bool allowSelection) => AddStep("create playlist", () => + private void createPlaylist(bool allowEdit, bool allowSelection) { - Child = playlist = new DrawableRoomPlaylist(allowEdit, allowSelection) + AddStep("create playlist", () => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(500, 300) - }; - - for (int i = 0; i < 20; i++) - { - playlist.Items.Add(new PlaylistItem + Child = playlist = new TestPlaylist(allowEdit, allowSelection) { - ID = i, - Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, - Ruleset = { Value = new OsuRuleset().RulesetInfo }, - RequiredMods = + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(500, 300) + }; + + for (int i = 0; i < 20; i++) + { + playlist.Items.Add(new PlaylistItem { - new OsuModHardRock(), - new OsuModDoubleTime(), - new OsuModAutoplay() - } - }); + ID = i, + Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + RequiredMods = + { + new OsuModHardRock(), + new OsuModDoubleTime(), + new OsuModAutoplay() + } + }); + } + }); + + AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded)); + } + + private class TestPlaylist : DrawableRoomPlaylist + { + public new IReadOnlyDictionary> ItemMap => base.ItemMap; + + public TestPlaylist(bool allowEdit, bool allowSelection) + : base(allowEdit, allowSelection) + { } - }); + } } } From 7550685a614eaff25adef260a5344e254944be69 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 20 Feb 2020 02:43:13 +0300 Subject: [PATCH 24/36] DrawableErrorHandler -> NotFoundDrawable --- .../API/Requests/SearchBeatmapSetsResponse.cs | 3 --- osu.Game/Overlays/BeatmapListingOverlay.cs | 18 +++++------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs index 845c84430f..3c4fb11ed1 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs @@ -12,9 +12,6 @@ namespace osu.Game.Online.API.Requests [JsonProperty("beatmapsets")] public IEnumerable BeatmapSets; - [JsonProperty("error")] - public string Error; - [JsonProperty("total")] public int Total; } diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 546d0bc9bb..414e911f2e 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -189,15 +189,11 @@ namespace osu.Game.Overlays private void recreatePanels(SearchBeatmapSetsResponse response) { - var hasError = !string.IsNullOrEmpty(response.Error); - - if (response.Total == 0 || hasError) + if (response.Total == 0) { searchSection.BeatmapSet = null; - LoadComponentAsync(new DrawableErrorHandler(hasError ? response.Error : @"... nope, nothing found."), - addContentToPlaceholder, - (cancellationToken = new CancellationTokenSource()).Token); + LoadComponentAsync(new NotFoundDrawable(), addContentToPlaceholder, (cancellationToken = new CancellationTokenSource()).Token); return; } @@ -240,14 +236,10 @@ namespace osu.Game.Overlays base.Dispose(isDisposing); } - private class DrawableErrorHandler : CompositeDrawable + private class NotFoundDrawable : CompositeDrawable { - private readonly string error; - - public DrawableErrorHandler(string error) + public NotFoundDrawable() { - this.error = error; - RelativeSizeAxes = Axes.X; Height = 250; Margin = new MarginPadding { Top = 15 }; @@ -278,7 +270,7 @@ namespace osu.Game.Overlays { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = error, + Text = @"... nope, nothing found.", } } }); From 66ea7949358fe9ae9a7dd0c4e5839c39e63ca903 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 20 Feb 2020 02:54:35 +0300 Subject: [PATCH 25/36] Add debounce to the querying --- osu.Game/Overlays/BeatmapListingOverlay.cs | 32 +++++++++++++--------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 414e911f2e..2a812ddf96 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using System.Threading; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -11,6 +10,7 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Framework.Threading; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; @@ -33,7 +33,6 @@ namespace osu.Game.Overlays private RulesetStore rulesets { get; set; } private SearchBeatmapSetsRequest getSetsRequest; - private CancellationTokenSource cancellationToken; private Container panelsPlaceholder; private BeatmapListingSearchSection searchSection; @@ -149,13 +148,23 @@ namespace osu.Game.Overlays sortCriteria.Value = string.IsNullOrEmpty(query.NewValue) ? DirectSortCriteria.Ranked : DirectSortCriteria.Relevance; sortDirection.Value = SortDirection.Descending; - Scheduler.AddOnce(updateSearch); + queueUpdateSearch(true); }); - searchSection.Ruleset.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); - searchSection.Category.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); - sortCriteria.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); - sortDirection.BindValueChanged(_ => Scheduler.AddOnce(updateSearch)); + searchSection.Ruleset.BindValueChanged(_ => queueUpdateSearch()); + searchSection.Category.BindValueChanged(_ => queueUpdateSearch()); + sortCriteria.BindValueChanged(_ => queueUpdateSearch()); + sortDirection.BindValueChanged(_ => queueUpdateSearch()); + } + + private ScheduledDelegate queryChangedDebounce; + + private void queueUpdateSearch(bool queryTextChanged = false) + { + getSetsRequest?.Cancel(); + + queryChangedDebounce?.Cancel(); + queryChangedDebounce = Scheduler.AddDelayed(updateSearch, queryTextChanged ? 500 : 100); } private void updateSearch() @@ -169,8 +178,6 @@ namespace osu.Game.Overlays if (API == null) return; - getSetsRequest?.Cancel(); - cancellationToken?.Cancel(); previewTrackManager.StopAnyPlaying(this); panelsPlaceholder.FadeColour(Color4.DimGray, 400, Easing.OutQuint); @@ -192,8 +199,7 @@ namespace osu.Game.Overlays if (response.Total == 0) { searchSection.BeatmapSet = null; - - LoadComponentAsync(new NotFoundDrawable(), addContentToPlaceholder, (cancellationToken = new CancellationTokenSource()).Token); + LoadComponentAsync(new NotFoundDrawable(), addContentToPlaceholder); return; } @@ -218,7 +224,7 @@ namespace osu.Game.Overlays addContentToPlaceholder(loaded); loaded.FadeIn(600, Easing.OutQuint); searchSection.BeatmapSet = beatmaps.First(); - }, (cancellationToken = new CancellationTokenSource()).Token); + }); } private void addContentToPlaceholder(Drawable content) @@ -231,7 +237,7 @@ namespace osu.Game.Overlays protected override void Dispose(bool isDisposing) { getSetsRequest?.Cancel(); - cancellationToken?.Cancel(); + queryChangedDebounce?.Cancel(); base.Dispose(isDisposing); } From a8c735b66d7268f1eadeee59cacf8ae345839010 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 20 Feb 2020 04:19:50 +0300 Subject: [PATCH 26/36] Change default category value --- osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs index f47144e5d8..f9799d8a6b 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs @@ -104,6 +104,8 @@ namespace osu.Game.Overlays.BeatmapListing } } }); + + Category.Value = BeatmapSearchCategory.Leaderboard; } [BackgroundDependencyLoader] From 907c1b3d1c73d9eaca1c2d022ee27653ce13c111 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Feb 2020 10:48:12 +0900 Subject: [PATCH 27/36] Add missing test banana resources --- .../old-skin/fruit-bananas-overlay.png | Bin 0 -> 7823 bytes .../Resources/old-skin/fruit-bananas.png | Bin 0 -> 14274 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-bananas-overlay.png create mode 100644 osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-bananas.png diff --git a/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-bananas-overlay.png b/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-bananas-overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..3a6612378e5cc655ec5d9d8ea7c53486c5a6270b GIT binary patch literal 7823 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 a2zU=&wPGnM{AV5mfVTP*wOSSX=>GxIE#JKW literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-bananas.png b/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-bananas.png new file mode 100644 index 0000000000000000000000000000000000000000..afb8698b2d8ff7285d53e140bcf0c5379ef8a6c6 GIT binary patch literal 14274 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 literal 0 HcmV?d00001 From 1935a14288c3c9fedb9e73e45ffd1d7a77a20c92 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 20 Feb 2020 05:08:42 +0300 Subject: [PATCH 28/36] Adjust animations to be much smoother --- osu.Game/Overlays/BeatmapListingOverlay.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 2a812ddf96..da67226eac 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -35,6 +35,7 @@ namespace osu.Game.Overlays private SearchBeatmapSetsRequest getSetsRequest; private Container panelsPlaceholder; + private Drawable currentContent; private BeatmapListingSearchSection searchSection; private BeatmapListingSortTabControl sortControl; @@ -124,6 +125,8 @@ namespace osu.Game.Overlays { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, + AutoSizeEasing = Easing.Out, + AutoSizeDuration = 200, Padding = new MarginPadding { Horizontal = 20 }, } } @@ -180,7 +183,7 @@ namespace osu.Game.Overlays previewTrackManager.StopAnyPlaying(this); - panelsPlaceholder.FadeColour(Color4.DimGray, 400, Easing.OutQuint); + currentContent?.FadeColour(Color4.DimGray, 400, Easing.OutQuint); getSetsRequest = new SearchBeatmapSetsRequest( searchSection.Query.Value, @@ -222,16 +225,15 @@ namespace osu.Game.Overlays LoadComponentAsync(newPanels, loaded => { addContentToPlaceholder(loaded); - loaded.FadeIn(600, Easing.OutQuint); searchSection.BeatmapSet = beatmaps.First(); }); } private void addContentToPlaceholder(Drawable content) { - panelsPlaceholder.Clear(); - panelsPlaceholder.FadeColour(Color4.White); - panelsPlaceholder.Add(content); + currentContent?.FadeOut(100, Easing.OutQuint).Expire(); + panelsPlaceholder.Add(currentContent = content); + currentContent.FadeIn(200, Easing.OutQuint); } protected override void Dispose(bool isDisposing) @@ -248,6 +250,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.X; Height = 250; + Alpha = 0; Margin = new MarginPadding { Top = 15 }; } From 00d8be92356065111503c18f444e6a5c5b5d9931 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 20 Feb 2020 13:48:34 +0900 Subject: [PATCH 29/36] Adjust height transition --- osu.Game/Overlays/BeatmapListingOverlay.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index da67226eac..213e9a4244 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -125,8 +125,6 @@ namespace osu.Game.Overlays { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, - AutoSizeEasing = Easing.Out, - AutoSizeDuration = 200, Padding = new MarginPadding { Horizontal = 20 }, } } @@ -231,7 +229,19 @@ namespace osu.Game.Overlays private void addContentToPlaceholder(Drawable content) { - currentContent?.FadeOut(100, Easing.OutQuint).Expire(); + Drawable lastContent = currentContent; + + if (lastContent != null) + { + lastContent.FadeOut(100, Easing.OutQuint).Expire(); + + // Consider the case when the new content is smaller than the last content. + // If the auto-size computation is delayed until fade out completes, the background remain high for too long making the resulting transition to the smaller height look weird. + // At the same time, if the last content's height is bypassed immediately, there is a period where the new content is at Alpha = 0 when the auto-sized height will be 0. + // To resolve both of these issues, the bypass is delayed until a point when the content transitions (fade-in and fade-out) overlap and it looks good to do so. + lastContent.Delay(25).Schedule(() => lastContent.BypassAutoSizeAxes = Axes.Y); + } + panelsPlaceholder.Add(currentContent = content); currentContent.FadeIn(200, Easing.OutQuint); } From 17b669fdf74c456515dbd1daca4d0a1a86625c75 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 20 Feb 2020 14:32:16 +0900 Subject: [PATCH 30/36] Refactor to detail the sizing mode setting --- .../Screens/Multi/Components/OverlinedDisplay.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/OverlinedDisplay.cs b/osu.Game/Screens/Multi/Components/OverlinedDisplay.cs index 600fa99a9a..71cabd8b50 100644 --- a/osu.Game/Screens/Multi/Components/OverlinedDisplay.cs +++ b/osu.Game/Screens/Multi/Components/OverlinedDisplay.cs @@ -104,15 +104,13 @@ namespace osu.Game.Screens.Multi.Components new Dimension(AutoSizeAxes.HasFlag(Axes.Y) ? GridSizeMode.AutoSize : GridSizeMode.Distributed), }; - grid.AutoSizeAxes = Axes.None; - grid.RelativeSizeAxes = Axes.None; - grid.AutoSizeAxes = AutoSizeAxes; - grid.RelativeSizeAxes = ~AutoSizeAxes; + // Assigning to none is done so that setting auto and relative size modes doesn't cause exceptions to be thrown + grid.AutoSizeAxes = Content.AutoSizeAxes = Axes.None; + grid.RelativeSizeAxes = Content.RelativeSizeAxes = Axes.None; - Content.AutoSizeAxes = Axes.None; - Content.RelativeSizeAxes = Axes.None; - Content.AutoSizeAxes = grid.AutoSizeAxes; - Content.RelativeSizeAxes = grid.RelativeSizeAxes; + // Auto-size when required, otherwise eagerly relative-size + grid.AutoSizeAxes = Content.AutoSizeAxes = AutoSizeAxes; + grid.RelativeSizeAxes = Content.RelativeSizeAxes = ~AutoSizeAxes; } } } From c5fd969568c1c9c2e22acde5559007d55d5325ba Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 20 Feb 2020 14:33:13 +0900 Subject: [PATCH 31/36] Fix 0 size in test scene --- .../Visual/Multiplayer/TestSceneOverlinedPlaylist.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs index 4e38f6d2c2..9a6273d075 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs @@ -27,12 +27,11 @@ namespace osu.Game.Tests.Visual.Multiplayer }); } - Add(new Container + Add(new OverlinedPlaylist(false) { Anchor = Anchor.Centre, Origin = Anchor.Centre, Size = new Vector2(500), - Child = new OverlinedPlaylist(false) }); } } From 177935d644be16be513d48b9baa724aaf4b64a10 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 20 Feb 2020 14:45:35 +0900 Subject: [PATCH 32/36] Remove unused using --- osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs index 9a6273d075..14b7934dc7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Multi.Components; From 1a689231c2d14326d5b9b5525e9669e11d1fdaa7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 20 Feb 2020 14:51:25 +0900 Subject: [PATCH 33/36] Support null leaderboard position --- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 27 +++++++++++++++++++ .../API/Requests/Responses/APILegacyScores.cs | 2 +- .../Online/Leaderboards/LeaderboardScore.cs | 6 ++--- .../BeatmapSet/Scores/ScoresContainer.cs | 6 ++++- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 3eff75b020..1198488bda 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -59,6 +59,33 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep(@"None selected", () => leaderboard.SetRetrievalState(PlaceholderState.NoneSelected)); foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus))) AddStep($"{status} beatmap", () => showBeatmapWithStatus(status)); + AddStep("null personal best position", showPersonalBestWithNullPosition); + } + + private void showPersonalBestWithNullPosition() + { + leaderboard.TopScore = new APILegacyUserTopScoreInfo + { + Position = null, + Score = new APILegacyScoreInfo + { + Rank = ScoreRank.XH, + Accuracy = 1, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, }, + User = new User + { + Id = 6602580, + Username = @"waaiiru", + Country = new Country + { + FullName = @"Spain", + FlagName = @"ES", + }, + }, + } + }; } private void showPersonalBest() diff --git a/osu.Game/Online/API/Requests/Responses/APILegacyScores.cs b/osu.Game/Online/API/Requests/Responses/APILegacyScores.cs index 318fcb00de..75be9171b0 100644 --- a/osu.Game/Online/API/Requests/Responses/APILegacyScores.cs +++ b/osu.Game/Online/API/Requests/Responses/APILegacyScores.cs @@ -18,7 +18,7 @@ namespace osu.Game.Online.API.Requests.Responses public class APILegacyUserTopScoreInfo { [JsonProperty(@"position")] - public int Position; + public int? Position; [JsonProperty(@"score")] public APILegacyScoreInfo Score; diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 1f52a4481b..ba92b993a2 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -41,7 +41,7 @@ namespace osu.Game.Online.Leaderboards protected Container RankContainer { get; private set; } private readonly ScoreInfo score; - private readonly int rank; + private readonly int? rank; private readonly bool allowHighlight; private Box background; @@ -58,7 +58,7 @@ namespace osu.Game.Online.Leaderboards [Resolved(CanBeNull = true)] private DialogOverlay dialogOverlay { get; set; } - public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true) + public LeaderboardScore(ScoreInfo score, int? rank, bool allowHighlight = true) { this.score = score; this.rank = rank; @@ -90,7 +90,7 @@ namespace osu.Game.Online.Leaderboards Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 20, italics: true), - Text = rank.ToMetric(decimals: rank < 100000 ? 1 : 0), + Text = rank == null ? "-" : rank.Value.ToMetric(decimals: rank < 100000 ? 1 : 0), }, }, }, diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 2d8bd10b13..0d0dd08a0f 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -70,7 +71,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores topScoresContainer.Add(new DrawableTopScore(topScore)); if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID) - topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); + { + Debug.Assert(userScore.Position != null); + topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position.Value)); + } }); } From d79ca97fe901affe1c91172d18e246a78a840c2c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 20 Feb 2020 15:04:12 +0900 Subject: [PATCH 34/36] Make beatmap scores also support null position --- .../Visual/Online/TestSceneScoresContainer.cs | 29 +++++++++++++++++++ .../BeatmapSet/Scores/DrawableTopScore.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 6 +--- .../BeatmapSet/Scores/TopScoreUserSection.cs | 4 +-- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs index 3c959e05c1..51f4089058 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs @@ -195,6 +195,29 @@ namespace osu.Game.Tests.Visual.Online Position = 1337, }; + var myBestScoreWithNullPosition = new APILegacyUserTopScoreInfo + { + Score = new APILegacyScoreInfo + { + User = new User + { + Id = 7151382, + Username = @"Mayuri Hana", + Country = new Country + { + FullName = @"Thailand", + FlagName = @"TH", + }, + }, + Rank = ScoreRank.D, + PP = 160, + MaxCombo = 1234, + TotalScore = 123456, + Accuracy = 0.6543, + }, + Position = null, + }; + var oneScore = new APILegacyScores { Scores = new List @@ -250,6 +273,12 @@ namespace osu.Game.Tests.Visual.Online allScores.UserScore = myBestScore; scoresContainer.Scores = allScores; }); + + AddStep("Load scores with null my best position", () => + { + allScores.UserScore = myBestScoreWithNullPosition; + scoresContainer.Scores = allScores; + }); } private class TestScoresContainer : ScoresContainer diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index bb85b4a37b..cad37dd082 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { private readonly Box background; - public DrawableTopScore(ScoreInfo score, int position = 1) + public DrawableTopScore(ScoreInfo score, int? position = 1) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 0d0dd08a0f..2d8bd10b13 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -71,10 +70,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores topScoresContainer.Add(new DrawableTopScore(topScore)); if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID) - { - Debug.Assert(userScore.Position != null); - topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position.Value)); - } + topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); }); } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index 8a368aa535..9a67ea2b24 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -112,9 +112,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores }; } - public int ScorePosition + public int? ScorePosition { - set => rankText.Text = $"#{value}"; + set => rankText.Text = value == null ? "-" : $"#{value}"; } /// From 5970c102b4e25f7573d4375358a51a79cc4617c7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Feb 2020 15:14:40 +0900 Subject: [PATCH 35/36] Change API to be easier to understand --- .../Objects/Drawables/DrawableOsuHitObject.cs | 4 ---- .../Objects/Drawables/DrawableHitObject.cs | 23 ++++++++++++------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 1bb72a3176..a677cb6a72 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -1,13 +1,11 @@ // 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.Game.Rulesets.Objects.Drawables; using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Graphics.Containers; -using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -56,8 +54,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } - protected override void UpdateComboColour(Color4 proposedColour, IReadOnlyList comboColours) => AccentColour.Value = proposedColour; - protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(HitObject, judgement); } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index c5ce490845..67fe18e8dd 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -346,20 +346,27 @@ namespace osu.Game.Rulesets.Objects.Drawables private void updateComboColour() { - if (HitObject is IHasComboInformation combo) - { - var comboColours = CurrentSkin.GetConfig>(GlobalSkinColours.ComboColours)?.Value; - UpdateComboColour(comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White, comboColours); - } + if (!(HitObject is IHasComboInformation)) return; + + var comboColours = CurrentSkin.GetConfig>(GlobalSkinColours.ComboColours)?.Value; + + AccentColour.Value = GetComboColour(comboColours); } /// - /// Called when a combo colour change is proposed. + /// Called to retrieve the combo colour. Automatically assigned to . + /// Defaults to using to decide on a colour. /// - /// The proposed combo colour, based off the combo index. + /// + /// This will only be called if the implements . + /// /// A list of combo colours provided by the beatmap or skin. Can be null if not available. - protected virtual void UpdateComboColour(Color4 proposedColour, IReadOnlyList comboColours) + protected virtual Color4 GetComboColour(IReadOnlyList comboColours) { + if (!(HitObject is IHasComboInformation combo)) + throw new InvalidOperationException($"{nameof(HitObject)} must implement {nameof(IHasComboInformation)}"); + + return comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; } /// From 337a7986cf7ca5492bf9a0eaf1616e616faee12d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Feb 2020 15:19:12 +0900 Subject: [PATCH 36/36] Fix reference in test scene --- osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs index 7469771e0b..17dc27543d 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -76,8 +76,6 @@ namespace osu.Game.Tests.Gameplay : base(new TestHitObjectWithCombo()) { } - - protected override void UpdateComboColour(Color4 proposedColour, IReadOnlyList comboColours) => AccentColour.Value = proposedColour; } private class TestHitObjectWithCombo : HitObject, IHasComboInformation