From a8cbd400d36b8997a0ba87ae1ec55227381764fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Oct 2020 13:17:13 +0900 Subject: [PATCH 001/104] Ensure virtual track time is long enough for test beatmaps --- osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs | 5 ++--- osu.Game/Tests/Visual/OsuTestScene.cs | 10 ++++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index ab4fb38657..1e43e5d148 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -180,9 +180,8 @@ namespace osu.Game.Tests.Beatmaps private readonly BeatmapInfo skinBeatmapInfo; private readonly IResourceStore resourceStore; - public TestWorkingBeatmap(BeatmapInfo skinBeatmapInfo, IResourceStore resourceStore, IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio, - double length = 60000) - : base(beatmap, storyboard, referenceClock, audio, length) + public TestWorkingBeatmap(BeatmapInfo skinBeatmapInfo, IResourceStore resourceStore, IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio) + : base(beatmap, storyboard, referenceClock, audio) { this.skinBeatmapInfo = skinBeatmapInfo; this.resourceStore = resourceStore; diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index b59a1db403..6e2fd0a6d7 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -23,6 +23,7 @@ using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; using osu.Game.Screens; using osu.Game.Storyboards; @@ -222,18 +223,19 @@ namespace osu.Game.Tests.Visual /// The storyboard. /// An optional clock which should be used instead of a stopwatch for virtual time progression. /// Audio manager. Required if a reference clock isn't provided. - /// The length of the returned virtual track. - public ClockBackedTestWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio, double length = 60000) + public ClockBackedTestWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio) : base(beatmap, storyboard, audio) { + double lastObjectTime = beatmap.HitObjects.LastOrDefault()?.GetEndTime() ?? 60000; + if (referenceClock != null) { store = new TrackVirtualStore(referenceClock); audio.AddItem(store); - track = store.GetVirtual(length); + track = store.GetVirtual(lastObjectTime); } else - track = audio?.Tracks.GetVirtual(length); + track = audio?.Tracks.GetVirtual(lastObjectTime); } ~ClockBackedTestWorkingBeatmap() From 21bf93a7c2b6d07e4e825c6b14f59a4ea3edd0af Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Oct 2020 13:29:36 +0900 Subject: [PATCH 002/104] Ensure there's a buffer after the last hitobject to allow certain replay tests to complete correctly --- osu.Game/Tests/Visual/OsuTestScene.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 6e2fd0a6d7..e3f07dbad4 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -226,16 +226,18 @@ namespace osu.Game.Tests.Visual public ClockBackedTestWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio) : base(beatmap, storyboard, audio) { - double lastObjectTime = beatmap.HitObjects.LastOrDefault()?.GetEndTime() ?? 60000; + var lastHitObject = beatmap.HitObjects.LastOrDefault(); + + double trackLength = lastHitObject?.GetEndTime() + 2000 ?? 60000; if (referenceClock != null) { store = new TrackVirtualStore(referenceClock); audio.AddItem(store); - track = store.GetVirtual(lastObjectTime); + track = store.GetVirtual(trackLength); } else - track = audio?.Tracks.GetVirtual(lastObjectTime); + track = audio?.Tracks.GetVirtual(trackLength); } ~ClockBackedTestWorkingBeatmap() From 4b8188065504cf88de4c8cb487a180f1a0696904 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Oct 2020 14:04:04 +0900 Subject: [PATCH 003/104] Account for potentially longer non-last objects --- osu.Game/Tests/Visual/OsuTestScene.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index e3f07dbad4..8886188d95 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -226,9 +226,11 @@ namespace osu.Game.Tests.Visual public ClockBackedTestWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio) : base(beatmap, storyboard, audio) { - var lastHitObject = beatmap.HitObjects.LastOrDefault(); + double trackLength = 60000; - double trackLength = lastHitObject?.GetEndTime() + 2000 ?? 60000; + if (beatmap.HitObjects.Count > 0) + // add buffer after last hitobject to allow for final replay frames etc. + trackLength = beatmap.HitObjects.Max(h => h.GetEndTime()) + 2000; if (referenceClock != null) { From 7fead6ee41dcf4a242eec2d0b13df47d6c2fd50c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Oct 2020 14:22:32 +0900 Subject: [PATCH 004/104] Add comment making mania test behaviour clearer --- osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs index ab840e1c46..e8c2472c3b 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs @@ -35,6 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests objects.Add(new Note { StartTime = time }); + // don't hit the first note if (i > 0) { frames.Add(new ManiaReplayFrame(time + 10, ManiaAction.Key1)); From 2871001cc294da01f2db8e8c35d84a86ab1503ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 22 Oct 2020 18:21:28 +0200 Subject: [PATCH 005/104] Add BackgroundSource.Seasonal --- osu.Game/Configuration/BackgroundSource.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Configuration/BackgroundSource.cs b/osu.Game/Configuration/BackgroundSource.cs index 5726e96eb1..beef9ef1de 100644 --- a/osu.Game/Configuration/BackgroundSource.cs +++ b/osu.Game/Configuration/BackgroundSource.cs @@ -6,6 +6,7 @@ namespace osu.Game.Configuration public enum BackgroundSource { Skin, - Beatmap + Beatmap, + Seasonal } } From cdb2d23578e6de7ca266a23a51b5fac2ed15b8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 22 Oct 2020 18:23:03 +0200 Subject: [PATCH 006/104] Set BackgroundSource.Seasonal as default setting --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 7d601c0cb9..5c5af701bb 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -130,7 +130,7 @@ namespace osu.Game.Configuration Set(OsuSetting.IntroSequence, IntroSequence.Triangles); - Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin); + Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Seasonal); } public OsuConfigManager(Storage storage) From 09d49aa0f7b2d953370e02897ef382bd3ea04f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 22 Oct 2020 18:25:01 +0200 Subject: [PATCH 007/104] Add GetSeasonalBackgroundsRequest --- .../Requests/GetSeasonalBackgroundsRequest.cs | 12 +++++++++++ .../Responses/APISeasonalBackgrounds.cs | 20 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 osu.Game/Online/API/Requests/GetSeasonalBackgroundsRequest.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APISeasonalBackgrounds.cs diff --git a/osu.Game/Online/API/Requests/GetSeasonalBackgroundsRequest.cs b/osu.Game/Online/API/Requests/GetSeasonalBackgroundsRequest.cs new file mode 100644 index 0000000000..941b47244a --- /dev/null +++ b/osu.Game/Online/API/Requests/GetSeasonalBackgroundsRequest.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetSeasonalBackgroundsRequest : APIRequest + { + protected override string Target => @"seasonal-backgrounds"; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APISeasonalBackgrounds.cs b/osu.Game/Online/API/Requests/Responses/APISeasonalBackgrounds.cs new file mode 100644 index 0000000000..6996ac4d9b --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APISeasonalBackgrounds.cs @@ -0,0 +1,20 @@ +// 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 Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APISeasonalBackgrounds + { + [JsonProperty("backgrounds")] + public List Backgrounds { get; set; } + } + + public class APISeasonalBackground + { + [JsonProperty("url")] + public string Url { get; set; } + } +} From c1d03a5baceb23be78f0d55458a9085ad5b652ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 23 Oct 2020 13:40:13 +0200 Subject: [PATCH 008/104] Add SeasonalBackgroundLoader and SeasonalBackground --- .../Backgrounds/SeasonalBackgroundLoader.cs | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs new file mode 100644 index 0000000000..af81b25cee --- /dev/null +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -0,0 +1,68 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Framework.Utils; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Graphics.Backgrounds +{ + [LongRunningLoad] + public class SeasonalBackgroundLoader : Component + { + private List backgrounds = new List(); + private int current; + + [BackgroundDependencyLoader] + private void load(IAPIProvider api) + { + var request = new GetSeasonalBackgroundsRequest(); + request.Success += response => + { + backgrounds = response.Backgrounds ?? backgrounds; + current = RNG.Next(0, backgrounds.Count); + }; + + api.PerformAsync(request); + } + + public SeasonalBackground LoadBackground(string fallbackTextureName) + { + string url = null; + + if (backgrounds.Any()) + { + current = (current + 1) % backgrounds.Count; + url = backgrounds[current].Url; + } + + return new SeasonalBackground(url, fallbackTextureName); + } + } + + [LongRunningLoad] + public class SeasonalBackground : Background + { + private readonly string url; + private readonly string fallbackTextureName; + + public SeasonalBackground([CanBeNull] string url, string fallbackTextureName = @"Backgrounds/bg1") + { + this.url = url; + this.fallbackTextureName = fallbackTextureName; + } + + [BackgroundDependencyLoader] + private void load(LargeTextureStore textures) + { + Sprite.Texture = textures.Get(url) ?? textures.Get(fallbackTextureName); + } + } +} From 81ebcd879668eb13cb28aa11bf4edfb8afb0fb99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 23 Oct 2020 13:41:00 +0200 Subject: [PATCH 009/104] Load SeasonalBackgroundLoader asynchronously --- .../Backgrounds/BackgroundScreenDefault.cs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index ef41c5be3d..ec91dcc99f 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.Backgrounds private Bindable skin; private Bindable mode; private Bindable introSequence; + private readonly SeasonalBackgroundLoader seasonalBackgroundLoader = new SeasonalBackgroundLoader(); [Resolved] private IBindable beatmap { get; set; } @@ -50,7 +51,7 @@ namespace osu.Game.Screens.Backgrounds currentDisplay = RNG.Next(0, background_count); - display(createBackground()); + LoadComponentAsync(seasonalBackgroundLoader, _ => LoadComponentAsync(createBackground(), display)); } private void display(Background newBackground) @@ -90,6 +91,10 @@ namespace osu.Game.Screens.Backgrounds { switch (mode.Value) { + case BackgroundSource.Seasonal: + newBackground = seasonalBackgroundLoader.LoadBackground(backgroundName); + break; + case BackgroundSource.Beatmap: newBackground = new BeatmapBackground(beatmap.Value, backgroundName); break; @@ -100,7 +105,18 @@ namespace osu.Game.Screens.Backgrounds } } else - newBackground = new Background(backgroundName); + { + switch (mode.Value) + { + case BackgroundSource.Seasonal: + newBackground = seasonalBackgroundLoader.LoadBackground(backgroundName); + break; + + default: + newBackground = new Background(backgroundName); + break; + } + } newBackground.Depth = currentDisplay; From ead3c195674a73f054dabccf0cfdb0d7f193bd58 Mon Sep 17 00:00:00 2001 From: Charlie Date: Mon, 26 Oct 2020 13:40:42 -0500 Subject: [PATCH 010/104] added function so circle is deleted when shift+right click --- .../Compose/Components/SelectionHandler.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 4caceedc5a..54e62649e1 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Audio; using osu.Game.Graphics; @@ -32,6 +33,8 @@ namespace osu.Game.Screens.Edit.Compose.Components /// public class SelectionHandler : CompositeDrawable, IKeyBindingHandler, IHasContextMenu { + private bool shiftPressed; + public IEnumerable SelectedBlueprints => selectedBlueprints; private readonly List selectedBlueprints; @@ -164,6 +167,17 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Whether any s could be reversed. public virtual bool HandleReverse() => false; + protected override bool OnKeyDown(KeyDownEvent e) + { + shiftPressed = e.ShiftPressed; + return false; + } + + protected override void OnKeyUp(KeyUpEvent e) + { + shiftPressed = e.ShiftPressed; + } + public bool OnPressed(PlatformAction action) { switch (action.ActionMethod) @@ -455,6 +469,12 @@ namespace osu.Game.Screens.Edit.Compose.Components { get { + if (shiftPressed) + { + deleteSelected(); + return null; + } + if (!selectedBlueprints.Any(b => b.IsHovered)) return Array.Empty(); From 123967056693f0f4b34d0eb04dc103ec39a33548 Mon Sep 17 00:00:00 2001 From: Charlie Date: Mon, 26 Oct 2020 14:28:53 -0500 Subject: [PATCH 011/104] moved right click shift delete functionality to HandleSelectionRequested + reduced func size --- .../Compose/Components/SelectionHandler.cs | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 54e62649e1..eeeacce4a7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -25,6 +25,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osuTK; +using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components { @@ -33,7 +34,6 @@ namespace osu.Game.Screens.Edit.Compose.Components /// public class SelectionHandler : CompositeDrawable, IKeyBindingHandler, IHasContextMenu { - private bool shiftPressed; public IEnumerable SelectedBlueprints => selectedBlueprints; private readonly List selectedBlueprints; @@ -167,17 +167,6 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Whether any s could be reversed. public virtual bool HandleReverse() => false; - protected override bool OnKeyDown(KeyDownEvent e) - { - shiftPressed = e.ShiftPressed; - return false; - } - - protected override void OnKeyUp(KeyUpEvent e) - { - shiftPressed = e.ShiftPressed; - } - public bool OnPressed(PlatformAction action) { switch (action.ActionMethod) @@ -237,6 +226,13 @@ namespace osu.Game.Screens.Edit.Compose.Components /// The blueprint. /// The input state at the point of selection. internal void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) + { + shiftClickDeleteCheck(blueprint, state); + multiSelectionHandler(blueprint, state); + + } + + private void multiSelectionHandler(SelectionBlueprint blueprint, InputState state) { if (state.Keyboard.ControlPressed) { @@ -255,6 +251,15 @@ namespace osu.Game.Screens.Edit.Compose.Components } } + private void shiftClickDeleteCheck(SelectionBlueprint blueprint, InputState state) + { + if (state.Keyboard.ShiftPressed && state.Mouse.IsPressed(MouseButton.Right)) + { + EditorBeatmap.Remove(blueprint.HitObject); + return; + } + } + private void deleteSelected() { EditorBeatmap.RemoveRange(selectedBlueprints.Select(b => b.HitObject)); @@ -469,12 +474,6 @@ namespace osu.Game.Screens.Edit.Compose.Components { get { - if (shiftPressed) - { - deleteSelected(); - return null; - } - if (!selectedBlueprints.Any(b => b.IsHovered)) return Array.Empty(); From ccaf6560ec619004ddd67b57dd62674f7b6520db Mon Sep 17 00:00:00 2001 From: Charlie Date: Mon, 26 Oct 2020 14:30:37 -0500 Subject: [PATCH 012/104] formatting --- osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index eeeacce4a7..f4b98c66b1 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -34,7 +34,6 @@ namespace osu.Game.Screens.Edit.Compose.Components /// public class SelectionHandler : CompositeDrawable, IKeyBindingHandler, IHasContextMenu { - public IEnumerable SelectedBlueprints => selectedBlueprints; private readonly List selectedBlueprints; @@ -229,7 +228,6 @@ namespace osu.Game.Screens.Edit.Compose.Components { shiftClickDeleteCheck(blueprint, state); multiSelectionHandler(blueprint, state); - } private void multiSelectionHandler(SelectionBlueprint blueprint, InputState state) From 255bb9d10092ede439c0d8c5f71b7ca707880a37 Mon Sep 17 00:00:00 2001 From: Charlie Date: Mon, 26 Oct 2020 14:52:59 -0500 Subject: [PATCH 013/104] fixed issue with returns --- .../Edit/Compose/Components/SelectionHandler.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index f4b98c66b1..f0a9e69321 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -226,11 +226,11 @@ namespace osu.Game.Screens.Edit.Compose.Components /// The input state at the point of selection. internal void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) { - shiftClickDeleteCheck(blueprint, state); - multiSelectionHandler(blueprint, state); + if (!shiftClickDeleteCheck(blueprint, state)) + handleMultiSelection(blueprint, state); } - private void multiSelectionHandler(SelectionBlueprint blueprint, InputState state) + private void handleMultiSelection(SelectionBlueprint blueprint, InputState state) { if (state.Keyboard.ControlPressed) { @@ -249,13 +249,14 @@ namespace osu.Game.Screens.Edit.Compose.Components } } - private void shiftClickDeleteCheck(SelectionBlueprint blueprint, InputState state) + private bool shiftClickDeleteCheck(SelectionBlueprint blueprint, InputState state) { if (state.Keyboard.ShiftPressed && state.Mouse.IsPressed(MouseButton.Right)) { EditorBeatmap.Remove(blueprint.HitObject); - return; + return true; } + return false; } private void deleteSelected() From 3f8c4c57d0682441a69bfed1c5a69bda07ef0979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 26 Oct 2020 22:16:28 +0100 Subject: [PATCH 014/104] Fix code style issues & restructure --- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 5 +++ .../Compose/Components/SelectionHandler.cs | 43 ++++++------------- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 4abdbfc244..f3816f6218 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -120,6 +120,11 @@ namespace osu.Game.Rulesets.Edit /// public void Deselect() => State = SelectionState.NotSelected; + /// + /// Toggles the selection state of this . + /// + public void ToggleSelection() => State = IsSelected ? SelectionState.NotSelected : SelectionState.Selected; + public bool IsSelected => State == SelectionState.Selected; /// diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index f0a9e69321..9cddb69d0b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Audio; using osu.Game.Graphics; @@ -225,38 +224,22 @@ namespace osu.Game.Screens.Edit.Compose.Components /// The blueprint. /// The input state at the point of selection. internal void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) - { - if (!shiftClickDeleteCheck(blueprint, state)) - handleMultiSelection(blueprint, state); - } - - private void handleMultiSelection(SelectionBlueprint blueprint, InputState state) - { - if (state.Keyboard.ControlPressed) - { - if (blueprint.IsSelected) - blueprint.Deselect(); - else - blueprint.Select(); - } - else - { - if (blueprint.IsSelected) - return; - - DeselectAll?.Invoke(); - blueprint.Select(); - } - } - - private bool shiftClickDeleteCheck(SelectionBlueprint blueprint, InputState state) { if (state.Keyboard.ShiftPressed && state.Mouse.IsPressed(MouseButton.Right)) - { EditorBeatmap.Remove(blueprint.HitObject); - return true; - } - return false; + else if (state.Keyboard.ControlPressed) + blueprint.ToggleSelection(); + else + ensureSelected(blueprint); + } + + private void ensureSelected(SelectionBlueprint blueprint) + { + if (blueprint.IsSelected) + return; + + DeselectAll?.Invoke(); + blueprint.Select(); } private void deleteSelected() From 27c1a4c4d3693dbc1f22b2c9427646c8ccf01977 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Oct 2020 12:53:54 +0900 Subject: [PATCH 015/104] Move right-click deletion logic to be handled at a SelectionBlueprint level --- .../Sliders/SliderSelectionBlueprint.cs | 4 ++-- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 17 +++++++++++++++++ .../Edit/Compose/Components/SelectionHandler.cs | 4 +--- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index d3fb5defae..ca9ec886d5 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -107,14 +107,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { case MouseButton.Right: rightClickPosition = e.MouseDownPosition; - return false; // Allow right click to be handled by context menu + break; case MouseButton.Left when e.ControlPressed && IsSelected: placementControlPointIndex = addControlPoint(e.MousePosition); return true; // Stop input from being handled and modifying the selection } - return false; + return base.OnMouseDown(e); } private int? placementControlPointIndex; diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index f3816f6218..87ef7e647f 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -8,10 +8,13 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Screens.Edit; using osuTK; +using osuTK.Input; namespace osu.Game.Rulesets.Edit { @@ -52,6 +55,20 @@ namespace osu.Game.Rulesets.Edit updateState(); } + [Resolved] + private EditorBeatmap editorBeatmap { get; set; } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (e.CurrentState.Keyboard.ShiftPressed && e.IsPressed(MouseButton.Right)) + { + editorBeatmap.Remove(HitObject); + return true; + } + + return base.OnMouseDown(e); + } + private SelectionState state; public event Action StateChanged; diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 9cddb69d0b..036edbeb84 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -225,9 +225,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// The input state at the point of selection. internal void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) { - if (state.Keyboard.ShiftPressed && state.Mouse.IsPressed(MouseButton.Right)) - EditorBeatmap.Remove(blueprint.HitObject); - else if (state.Keyboard.ControlPressed) + if (state.Keyboard.ControlPressed) blueprint.ToggleSelection(); else ensureSelected(blueprint); From 3c2e2f29bc8eb190daab56fea86ab00a1925871b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Oct 2020 13:17:44 +0900 Subject: [PATCH 016/104] Remove unused using statement --- osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 036edbeb84..24f88bf36d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -24,7 +24,6 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osuTK; -using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components { From 742a96484befff6d8c137cd749cfd648c7c65992 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Oct 2020 20:13:18 +0300 Subject: [PATCH 017/104] Add ability to set extra parameters to SearchBeatmapSetsRequest --- .../API/Requests/SearchBeatmapSetsRequest.cs | 28 ++++++++++++++++++- .../Overlays/BeatmapListing/SearchExtra.cs | 13 +++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/BeatmapListing/SearchExtra.cs diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index dde45b5aeb..f8cf747757 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -21,6 +21,8 @@ namespace osu.Game.Online.API.Requests public SearchLanguage Language { get; } + public SearchExtra Extra { get; } + private readonly string query; private readonly RulesetInfo ruleset; private readonly Cursor cursor; @@ -35,7 +37,8 @@ namespace osu.Game.Online.API.Requests SortCriteria sortCriteria = SortCriteria.Ranked, SortDirection sortDirection = SortDirection.Descending, SearchGenre genre = SearchGenre.Any, - SearchLanguage language = SearchLanguage.Any) + SearchLanguage language = SearchLanguage.Any, + SearchExtra extra = SearchExtra.Any) { this.query = string.IsNullOrEmpty(query) ? string.Empty : System.Uri.EscapeDataString(query); this.ruleset = ruleset; @@ -46,6 +49,7 @@ namespace osu.Game.Online.API.Requests SortDirection = sortDirection; Genre = genre; Language = language; + Extra = extra; } protected override WebRequest CreateWebRequest() @@ -68,6 +72,28 @@ namespace osu.Game.Online.API.Requests req.AddCursor(cursor); + if (Extra != SearchExtra.Any) + { + string extraString = string.Empty; + + switch (Extra) + { + case SearchExtra.Both: + extraString = "video.storyboard"; + break; + + case SearchExtra.Storyboard: + extraString = "storyboard"; + break; + + case SearchExtra.Video: + extraString = "video"; + break; + } + + req.AddParameter("e", extraString); + } + return req; } diff --git a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs new file mode 100644 index 0000000000..fd4896c46e --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Overlays.BeatmapListing +{ + public enum SearchExtra + { + Video, + Storyboard, + Both, + Any + } +} From 26a60d898cfd3404275ad59021931bf4a03ec94a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Oct 2020 21:22:20 +0300 Subject: [PATCH 018/104] Implement BeatmapSearchExtraFilterRow --- .../TestSceneBeatmapListingSearchControl.cs | 3 + .../BeatmapListingFilterControl.cs | 4 +- .../BeatmapListingSearchControl.cs | 4 + .../BeatmapSearchExtraFilterRow.cs | 97 +++++++++++++ .../BeatmapListing/BeatmapSearchFilterRow.cs | 127 +++++++++--------- .../BeatmapSearchRulesetFilterRow.cs | 3 +- .../Overlays/BeatmapListing/SearchExtra.cs | 4 +- 7 files changed, 176 insertions(+), 66 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs index a4698a9a32..9a410dd18c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs @@ -27,6 +27,7 @@ namespace osu.Game.Tests.Visual.UserInterface OsuSpriteText category; OsuSpriteText genre; OsuSpriteText language; + OsuSpriteText extra; Add(control = new BeatmapListingSearchControl { @@ -46,6 +47,7 @@ namespace osu.Game.Tests.Visual.UserInterface category = new OsuSpriteText(), genre = new OsuSpriteText(), language = new OsuSpriteText(), + extra = new OsuSpriteText() } }); @@ -54,6 +56,7 @@ namespace osu.Game.Tests.Visual.UserInterface control.Category.BindValueChanged(c => category.Text = $"Category: {c.NewValue}", true); control.Genre.BindValueChanged(g => genre.Text = $"Genre: {g.NewValue}", true); control.Language.BindValueChanged(l => language.Text = $"Language: {l.NewValue}", true); + control.Extra.BindValueChanged(e => extra.Text = $"Extra: {e.NewValue}", true); } [Test] diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index 494a0df8f8..37fbfe7093 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -130,6 +130,7 @@ namespace osu.Game.Overlays.BeatmapListing searchControl.Category.BindValueChanged(_ => queueUpdateSearch()); searchControl.Genre.BindValueChanged(_ => queueUpdateSearch()); searchControl.Language.BindValueChanged(_ => queueUpdateSearch()); + searchControl.Extra.BindValueChanged(_ => queueUpdateSearch()); sortCriteria.BindValueChanged(_ => queueUpdateSearch()); sortDirection.BindValueChanged(_ => queueUpdateSearch()); @@ -179,7 +180,8 @@ namespace osu.Game.Overlays.BeatmapListing sortControl.Current.Value, sortControl.SortDirection.Value, searchControl.Genre.Value, - searchControl.Language.Value); + searchControl.Language.Value, + searchControl.Extra.Value); getSetsRequest.Success += response => { diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index 29c4fe0d2e..437c26e36d 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -28,6 +28,8 @@ namespace osu.Game.Overlays.BeatmapListing public Bindable Language => languageFilter.Current; + public Bindable Extra => extraFilter.Current; + public BeatmapSetInfo BeatmapSet { set @@ -48,6 +50,7 @@ namespace osu.Game.Overlays.BeatmapListing private readonly BeatmapSearchFilterRow categoryFilter; private readonly BeatmapSearchFilterRow genreFilter; private readonly BeatmapSearchFilterRow languageFilter; + private readonly BeatmapSearchExtraFilterRow extraFilter; private readonly Box background; private readonly UpdateableBeatmapSetCover beatmapCover; @@ -105,6 +108,7 @@ namespace osu.Game.Overlays.BeatmapListing categoryFilter = new BeatmapSearchFilterRow(@"Categories"), genreFilter = new BeatmapSearchFilterRow(@"Genre"), languageFilter = new BeatmapSearchFilterRow(@"Language"), + extraFilter = new BeatmapSearchExtraFilterRow() } } } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs new file mode 100644 index 0000000000..6e81cd2976 --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs @@ -0,0 +1,97 @@ +// 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 osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osuTK; + +namespace osu.Game.Overlays.BeatmapListing +{ + public class BeatmapSearchExtraFilterRow : BeatmapSearchFilterRow + { + public BeatmapSearchExtraFilterRow() + : base("Extra") + { + } + + protected override Drawable CreateFilter() => new ExtraFilter(); + + private class ExtraFilter : FillFlowContainer, IHasCurrentValue + { + private readonly BindableWithCurrent current = new BindableWithCurrent(); + + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + + private readonly ExtraFilterTabItem videoItem; + private readonly ExtraFilterTabItem storyboardItem; + + public ExtraFilter() + { + Anchor = Anchor.BottomLeft; + Origin = Anchor.BottomLeft; + RelativeSizeAxes = Axes.X; + Height = 15; + Spacing = new Vector2(10, 0); + AddRange(new[] + { + videoItem = new ExtraFilterTabItem(SearchExtra.Video), + storyboardItem = new ExtraFilterTabItem(SearchExtra.Storyboard) + }); + + foreach (var item in Children) + item.StateUpdated += updateBindable; + } + + private void updateBindable() + { + if (videoItem.Active.Value && storyboardItem.Active.Value) + { + Current.Value = SearchExtra.Both; + return; + } + + if (videoItem.Active.Value) + { + Current.Value = SearchExtra.Video; + return; + } + + if (storyboardItem.Active.Value) + { + Current.Value = SearchExtra.Storyboard; + return; + } + + Current.Value = SearchExtra.Any; + } + } + + private class ExtraFilterTabItem : FilterTabItem + { + public event Action StateUpdated; + + public ExtraFilterTabItem(SearchExtra value) + : base(value) + { + Active.BindValueChanged(_ => StateUpdated?.Invoke()); + } + + protected override bool OnClick(ClickEvent e) + { + base.OnClick(e); + Active.Value = !Active.Value; + return true; + } + + protected override string CreateText(SearchExtra value) => $@"Has {value.ToString()}"; + } + } +} diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs index 45ef793deb..ad32475b25 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs @@ -32,6 +32,7 @@ namespace osu.Game.Overlays.BeatmapListing public BeatmapSearchFilterRow(string headerName) { + Drawable filter; AutoSizeAxes = Axes.Y; RelativeSizeAxes = Axes.X; AddInternal(new GridContainer @@ -49,7 +50,7 @@ namespace osu.Game.Overlays.BeatmapListing }, Content = new[] { - new Drawable[] + new[] { new OsuSpriteText { @@ -58,17 +59,17 @@ namespace osu.Game.Overlays.BeatmapListing Font = OsuFont.GetFont(size: 13), Text = headerName.Titleize() }, - CreateFilter().With(f => - { - f.Current = current; - }) + filter = CreateFilter() } } }); + + if (filter is IHasCurrentValue filterWithValue) + filterWithValue.Current = current; } [NotNull] - protected virtual BeatmapSearchFilter CreateFilter() => new BeatmapSearchFilter(); + protected virtual Drawable CreateFilter() => new BeatmapSearchFilter(); protected class BeatmapSearchFilter : TabControl { @@ -99,62 +100,6 @@ namespace osu.Game.Overlays.BeatmapListing protected override TabItem CreateTabItem(T value) => new FilterTabItem(value); - protected class FilterTabItem : TabItem - { - protected virtual float TextSize => 13; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - - private readonly OsuSpriteText text; - - public FilterTabItem(T value) - : base(value) - { - AutoSizeAxes = Axes.Both; - Anchor = Anchor.BottomLeft; - Origin = Anchor.BottomLeft; - AddRangeInternal(new Drawable[] - { - text = new OsuSpriteText - { - Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Regular), - Text = (value as Enum)?.GetDescription() ?? value.ToString() - }, - new HoverClickSounds() - }); - - Enabled.Value = true; - } - - [BackgroundDependencyLoader] - private void load() - { - updateState(); - } - - protected override bool OnHover(HoverEvent e) - { - base.OnHover(e); - updateState(); - return true; - } - - protected override void OnHoverLost(HoverLostEvent e) - { - base.OnHoverLost(e); - updateState(); - } - - protected override void OnActivated() => updateState(); - - protected override void OnDeactivated() => updateState(); - - private void updateState() => text.FadeColour(Active.Value ? Color4.White : getStateColour(), 200, Easing.OutQuint); - - private Color4 getStateColour() => IsHovered ? colourProvider.Light1 : colourProvider.Light3; - } - private class FilterDropdown : OsuTabDropdown { protected override DropdownHeader CreateHeader() => new FilterHeader @@ -172,5 +117,63 @@ namespace osu.Game.Overlays.BeatmapListing } } } + + protected class FilterTabItem : TabItem + { + protected virtual float TextSize => 13; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + private readonly OsuSpriteText text; + + public FilterTabItem(T value) + : base(value) + { + AutoSizeAxes = Axes.Both; + Anchor = Anchor.BottomLeft; + Origin = Anchor.BottomLeft; + AddRangeInternal(new Drawable[] + { + text = new OsuSpriteText + { + Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Regular), + Text = CreateText(value) + }, + new HoverClickSounds() + }); + + Enabled.Value = true; + } + + protected virtual string CreateText(T value) => (value as Enum)?.GetDescription() ?? value.ToString(); + + [BackgroundDependencyLoader] + private void load() + { + updateState(); + } + + protected override bool OnHover(HoverEvent e) + { + base.OnHover(e); + updateState(); + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + updateState(); + } + + protected override void OnActivated() => updateState(); + + protected override void OnDeactivated() => updateState(); + + private void updateState() => text.FadeColour(Active.Value ? Color4.White : getStateColour(), 200, Easing.OutQuint); + + private Color4 getStateColour() => IsHovered ? colourProvider.Light1 : colourProvider.Light3; + } } } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs index eebd896cf9..a8dc088e52 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Rulesets; namespace osu.Game.Overlays.BeatmapListing @@ -13,7 +14,7 @@ namespace osu.Game.Overlays.BeatmapListing { } - protected override BeatmapSearchFilter CreateFilter() => new RulesetFilter(); + protected override Drawable CreateFilter() => new RulesetFilter(); private class RulesetFilter : BeatmapSearchFilter { diff --git a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs index fd4896c46e..53900211e1 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs @@ -5,9 +5,9 @@ namespace osu.Game.Overlays.BeatmapListing { public enum SearchExtra { + Any, Video, Storyboard, - Both, - Any + Both } } From 1b40b56d41081be1a199bea0889727360e57de1c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Oct 2020 21:30:53 +0300 Subject: [PATCH 019/104] Add ability to search by play criteria --- .../TestSceneBeatmapListingSearchControl.cs | 5 ++++- .../Online/API/Requests/SearchBeatmapSetsRequest.cs | 9 ++++++++- .../BeatmapListing/BeatmapListingFilterControl.cs | 4 +++- .../BeatmapListing/BeatmapListingSearchControl.cs | 6 +++++- osu.Game/Overlays/BeatmapListing/SearchPlayed.cs | 12 ++++++++++++ 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapListing/SearchPlayed.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs index 9a410dd18c..5c9431aad1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs @@ -28,6 +28,7 @@ namespace osu.Game.Tests.Visual.UserInterface OsuSpriteText genre; OsuSpriteText language; OsuSpriteText extra; + OsuSpriteText played; Add(control = new BeatmapListingSearchControl { @@ -47,7 +48,8 @@ namespace osu.Game.Tests.Visual.UserInterface category = new OsuSpriteText(), genre = new OsuSpriteText(), language = new OsuSpriteText(), - extra = new OsuSpriteText() + extra = new OsuSpriteText(), + played = new OsuSpriteText() } }); @@ -57,6 +59,7 @@ namespace osu.Game.Tests.Visual.UserInterface control.Genre.BindValueChanged(g => genre.Text = $"Genre: {g.NewValue}", true); control.Language.BindValueChanged(l => language.Text = $"Language: {l.NewValue}", true); control.Extra.BindValueChanged(e => extra.Text = $"Extra: {e.NewValue}", true); + control.Played.BindValueChanged(p => played.Text = $"Played: {p.NewValue}", true); } [Test] diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index f8cf747757..12383e7457 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -23,6 +23,8 @@ namespace osu.Game.Online.API.Requests public SearchExtra Extra { get; } + public SearchPlayed Played { get; } + private readonly string query; private readonly RulesetInfo ruleset; private readonly Cursor cursor; @@ -38,7 +40,8 @@ namespace osu.Game.Online.API.Requests SortDirection sortDirection = SortDirection.Descending, SearchGenre genre = SearchGenre.Any, SearchLanguage language = SearchLanguage.Any, - SearchExtra extra = SearchExtra.Any) + SearchExtra extra = SearchExtra.Any, + SearchPlayed played = SearchPlayed.Any) { this.query = string.IsNullOrEmpty(query) ? string.Empty : System.Uri.EscapeDataString(query); this.ruleset = ruleset; @@ -50,6 +53,7 @@ namespace osu.Game.Online.API.Requests Genre = genre; Language = language; Extra = extra; + Played = played; } protected override WebRequest CreateWebRequest() @@ -94,6 +98,9 @@ namespace osu.Game.Online.API.Requests req.AddParameter("e", extraString); } + if (Played != SearchPlayed.Any) + req.AddParameter("played", Played.ToString().ToLowerInvariant()); + return req; } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index 37fbfe7093..3f09a7e3d1 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -131,6 +131,7 @@ namespace osu.Game.Overlays.BeatmapListing searchControl.Genre.BindValueChanged(_ => queueUpdateSearch()); searchControl.Language.BindValueChanged(_ => queueUpdateSearch()); searchControl.Extra.BindValueChanged(_ => queueUpdateSearch()); + searchControl.Played.BindValueChanged(_ => queueUpdateSearch()); sortCriteria.BindValueChanged(_ => queueUpdateSearch()); sortDirection.BindValueChanged(_ => queueUpdateSearch()); @@ -181,7 +182,8 @@ namespace osu.Game.Overlays.BeatmapListing sortControl.SortDirection.Value, searchControl.Genre.Value, searchControl.Language.Value, - searchControl.Extra.Value); + searchControl.Extra.Value, + searchControl.Played.Value); getSetsRequest.Success += response => { diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index 437c26e36d..80beed6217 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -30,6 +30,8 @@ namespace osu.Game.Overlays.BeatmapListing public Bindable Extra => extraFilter.Current; + public Bindable Played => playedFilter.Current; + public BeatmapSetInfo BeatmapSet { set @@ -51,6 +53,7 @@ namespace osu.Game.Overlays.BeatmapListing private readonly BeatmapSearchFilterRow genreFilter; private readonly BeatmapSearchFilterRow languageFilter; private readonly BeatmapSearchExtraFilterRow extraFilter; + private readonly BeatmapSearchFilterRow playedFilter; private readonly Box background; private readonly UpdateableBeatmapSetCover beatmapCover; @@ -108,7 +111,8 @@ namespace osu.Game.Overlays.BeatmapListing categoryFilter = new BeatmapSearchFilterRow(@"Categories"), genreFilter = new BeatmapSearchFilterRow(@"Genre"), languageFilter = new BeatmapSearchFilterRow(@"Language"), - extraFilter = new BeatmapSearchExtraFilterRow() + extraFilter = new BeatmapSearchExtraFilterRow(), + playedFilter = new BeatmapSearchFilterRow(@"Played") } } } diff --git a/osu.Game/Overlays/BeatmapListing/SearchPlayed.cs b/osu.Game/Overlays/BeatmapListing/SearchPlayed.cs new file mode 100644 index 0000000000..eb7fb46158 --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/SearchPlayed.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Overlays.BeatmapListing +{ + public enum SearchPlayed + { + Any, + Played, + Unplayed + } +} From 1710b396e7195f34b024166d74129701ffc21eac Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Oct 2020 22:27:29 +0300 Subject: [PATCH 020/104] Implement BeatmapSearchMultipleSelectionFilterRow --- .../TestSceneBeatmapListingSearchControl.cs | 3 +- .../API/Requests/SearchBeatmapSetsRequest.cs | 33 ++------ .../BeatmapListingSearchControl.cs | 3 +- .../BeatmapSearchExtraFilterRow.cs | 79 ++---------------- .../BeatmapListing/BeatmapSearchFilterRow.cs | 64 +------------- ...BeatmapSearchMultipleSelectionFilterRow.cs | 83 +++++++++++++++++++ .../Overlays/BeatmapListing/FilterTabItem.cs | 74 +++++++++++++++++ .../Overlays/BeatmapListing/SearchExtra.cs | 4 +- 8 files changed, 179 insertions(+), 164 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs create mode 100644 osu.Game/Overlays/BeatmapListing/FilterTabItem.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs index 5c9431aad1..9b0ef4d6f2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.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.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -58,7 +59,7 @@ namespace osu.Game.Tests.Visual.UserInterface control.Category.BindValueChanged(c => category.Text = $"Category: {c.NewValue}", true); control.Genre.BindValueChanged(g => genre.Text = $"Genre: {g.NewValue}", true); control.Language.BindValueChanged(l => language.Text = $"Language: {l.NewValue}", true); - control.Extra.BindValueChanged(e => extra.Text = $"Extra: {e.NewValue}", true); + control.Extra.BindValueChanged(e => extra.Text = $"Extra: {(e.NewValue == null ? "" : string.Join(".", e.NewValue.Select(i => i.ToString().ToLowerInvariant())))}", true); control.Played.BindValueChanged(p => played.Text = $"Played: {p.NewValue}", true); } diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index 12383e7457..20bbd46529 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; using osu.Framework.IO.Network; using osu.Game.Extensions; using osu.Game.Overlays; @@ -21,7 +23,7 @@ namespace osu.Game.Online.API.Requests public SearchLanguage Language { get; } - public SearchExtra Extra { get; } + public List Extra { get; } public SearchPlayed Played { get; } @@ -40,7 +42,7 @@ namespace osu.Game.Online.API.Requests SortDirection sortDirection = SortDirection.Descending, SearchGenre genre = SearchGenre.Any, SearchLanguage language = SearchLanguage.Any, - SearchExtra extra = SearchExtra.Any, + List extra = null, SearchPlayed played = SearchPlayed.Any) { this.query = string.IsNullOrEmpty(query) ? string.Empty : System.Uri.EscapeDataString(query); @@ -74,33 +76,14 @@ namespace osu.Game.Online.API.Requests req.AddParameter("sort", $"{SortCriteria.ToString().ToLowerInvariant()}_{directionString}"); - req.AddCursor(cursor); - - if (Extra != SearchExtra.Any) - { - string extraString = string.Empty; - - switch (Extra) - { - case SearchExtra.Both: - extraString = "video.storyboard"; - break; - - case SearchExtra.Storyboard: - extraString = "storyboard"; - break; - - case SearchExtra.Video: - extraString = "video"; - break; - } - - req.AddParameter("e", extraString); - } + if (Extra != null && Extra.Any()) + req.AddParameter("e", string.Join(".", Extra.Select(e => e.ToString().ToLowerInvariant()))); if (Played != SearchPlayed.Any) req.AddParameter("played", Played.ToString().ToLowerInvariant()); + req.AddCursor(cursor); + return req; } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index 80beed6217..f390db3f35 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osuTK.Graphics; using osu.Game.Rulesets; +using System.Collections.Generic; namespace osu.Game.Overlays.BeatmapListing { @@ -28,7 +29,7 @@ namespace osu.Game.Overlays.BeatmapListing public Bindable Language => languageFilter.Current; - public Bindable Extra => extraFilter.Current; + public Bindable> Extra => extraFilter.Current; public Bindable Played => playedFilter.Current; diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs index 6e81cd2976..385978096c 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs @@ -1,94 +1,31 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osuTK; - namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapSearchExtraFilterRow : BeatmapSearchFilterRow + public class BeatmapSearchExtraFilterRow : BeatmapSearchMultipleSelectionFilterRow { public BeatmapSearchExtraFilterRow() : base("Extra") { } - protected override Drawable CreateFilter() => new ExtraFilter(); + protected override MultipleSelectionFilter CreateMultipleSelectionFilter() => new ExtraFilter(); - private class ExtraFilter : FillFlowContainer, IHasCurrentValue + private class ExtraFilter : MultipleSelectionFilter { - private readonly BindableWithCurrent current = new BindableWithCurrent(); - - public Bindable Current + protected override MultipleSelectionFilterTabItem[] CreateItems() => new[] { - get => current.Current; - set => current.Current = value; - } - - private readonly ExtraFilterTabItem videoItem; - private readonly ExtraFilterTabItem storyboardItem; - - public ExtraFilter() - { - Anchor = Anchor.BottomLeft; - Origin = Anchor.BottomLeft; - RelativeSizeAxes = Axes.X; - Height = 15; - Spacing = new Vector2(10, 0); - AddRange(new[] - { - videoItem = new ExtraFilterTabItem(SearchExtra.Video), - storyboardItem = new ExtraFilterTabItem(SearchExtra.Storyboard) - }); - - foreach (var item in Children) - item.StateUpdated += updateBindable; - } - - private void updateBindable() - { - if (videoItem.Active.Value && storyboardItem.Active.Value) - { - Current.Value = SearchExtra.Both; - return; - } - - if (videoItem.Active.Value) - { - Current.Value = SearchExtra.Video; - return; - } - - if (storyboardItem.Active.Value) - { - Current.Value = SearchExtra.Storyboard; - return; - } - - Current.Value = SearchExtra.Any; - } + new ExtraFilterTabItem(SearchExtra.Video), + new ExtraFilterTabItem(SearchExtra.Storyboard) + }; } - private class ExtraFilterTabItem : FilterTabItem + private class ExtraFilterTabItem : MultipleSelectionFilterTabItem { - public event Action StateUpdated; - public ExtraFilterTabItem(SearchExtra value) : base(value) { - Active.BindValueChanged(_ => StateUpdated?.Invoke()); - } - - protected override bool OnClick(ClickEvent e) - { - base.OnClick(e); - Active.Value = !Active.Value; - return true; } protected override string CreateText(SearchExtra value) => $@"Has {value.ToString()}"; diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs index ad32475b25..aa0fc0d00e 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs @@ -1,20 +1,16 @@ // 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 JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osuTK; -using osuTK.Graphics; using Humanizer; using osu.Game.Utils; @@ -98,7 +94,7 @@ namespace osu.Game.Overlays.BeatmapListing protected override Dropdown CreateDropdown() => new FilterDropdown(); - protected override TabItem CreateTabItem(T value) => new FilterTabItem(value); + protected override TabItem CreateTabItem(T value) => new FilterTabItem(value); private class FilterDropdown : OsuTabDropdown { @@ -117,63 +113,5 @@ namespace osu.Game.Overlays.BeatmapListing } } } - - protected class FilterTabItem : TabItem - { - protected virtual float TextSize => 13; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - - private readonly OsuSpriteText text; - - public FilterTabItem(T value) - : base(value) - { - AutoSizeAxes = Axes.Both; - Anchor = Anchor.BottomLeft; - Origin = Anchor.BottomLeft; - AddRangeInternal(new Drawable[] - { - text = new OsuSpriteText - { - Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Regular), - Text = CreateText(value) - }, - new HoverClickSounds() - }); - - Enabled.Value = true; - } - - protected virtual string CreateText(T value) => (value as Enum)?.GetDescription() ?? value.ToString(); - - [BackgroundDependencyLoader] - private void load() - { - updateState(); - } - - protected override bool OnHover(HoverEvent e) - { - base.OnHover(e); - updateState(); - return true; - } - - protected override void OnHoverLost(HoverLostEvent e) - { - base.OnHoverLost(e); - updateState(); - } - - protected override void OnActivated() => updateState(); - - protected override void OnDeactivated() => updateState(); - - private void updateState() => text.FadeColour(Active.Value ? Color4.White : getStateColour(), 200, Easing.OutQuint); - - private Color4 getStateColour() => IsHovered ? colourProvider.Light1 : colourProvider.Light3; - } } } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs new file mode 100644 index 0000000000..c434e00ff3 --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -0,0 +1,83 @@ +// 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.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osuTK; + +namespace osu.Game.Overlays.BeatmapListing +{ + public abstract class BeatmapSearchMultipleSelectionFilterRow : BeatmapSearchFilterRow> + { + public BeatmapSearchMultipleSelectionFilterRow(string headerName) + : base(headerName) + { + } + + protected override Drawable CreateFilter() => CreateMultipleSelectionFilter(); + + protected abstract MultipleSelectionFilter CreateMultipleSelectionFilter(); + + protected abstract class MultipleSelectionFilter : FillFlowContainer, IHasCurrentValue> + { + private readonly BindableWithCurrent> current = new BindableWithCurrent>(); + + public Bindable> Current + { + get => current.Current; + set => current.Current = value; + } + + public MultipleSelectionFilter() + { + Anchor = Anchor.BottomLeft; + Origin = Anchor.BottomLeft; + RelativeSizeAxes = Axes.X; + Height = 15; + Spacing = new Vector2(10, 0); + AddRange(CreateItems()); + + foreach (var item in Children) + item.StateUpdated += updateBindable; + } + + protected abstract MultipleSelectionFilterTabItem[] CreateItems(); + + private void updateBindable() + { + var selectedValues = new List(); + + foreach (var item in Children) + { + if (item.Active.Value) + selectedValues.Add(item.Value); + } + + Current.Value = selectedValues; + } + } + + protected class MultipleSelectionFilterTabItem : FilterTabItem + { + public event Action StateUpdated; + + public MultipleSelectionFilterTabItem(T value) + : base(value) + { + Active.BindValueChanged(_ => StateUpdated?.Invoke()); + } + + protected override bool OnClick(ClickEvent e) + { + base.OnClick(e); + Active.Value = !Active.Value; + return true; + } + } + } +} diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs new file mode 100644 index 0000000000..32b48862e0 --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -0,0 +1,74 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osuTK.Graphics; + +namespace osu.Game.Overlays.BeatmapListing +{ + public class FilterTabItem : TabItem + { + protected virtual float TextSize => 13; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + private readonly OsuSpriteText text; + + public FilterTabItem(T value) + : base(value) + { + AutoSizeAxes = Axes.Both; + Anchor = Anchor.BottomLeft; + Origin = Anchor.BottomLeft; + AddRangeInternal(new Drawable[] + { + text = new OsuSpriteText + { + Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Regular), + Text = CreateText(value) + }, + new HoverClickSounds() + }); + + Enabled.Value = true; + } + + protected virtual string CreateText(T value) => (value as Enum)?.GetDescription() ?? value.ToString(); + + [BackgroundDependencyLoader] + private void load() + { + updateState(); + } + + protected override bool OnHover(HoverEvent e) + { + base.OnHover(e); + updateState(); + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + updateState(); + } + + protected override void OnActivated() => updateState(); + + protected override void OnDeactivated() => updateState(); + + private void updateState() => text.FadeColour(Active.Value ? Color4.White : getStateColour(), 200, Easing.OutQuint); + + private Color4 getStateColour() => IsHovered ? colourProvider.Light1 : colourProvider.Light3; + } +} diff --git a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs index 53900211e1..e9b3165d97 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs @@ -5,9 +5,7 @@ namespace osu.Game.Overlays.BeatmapListing { public enum SearchExtra { - Any, Video, - Storyboard, - Both + Storyboard } } From 008d1d697cee99eee4e5cf076dcb209f71189a9f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Oct 2020 23:14:48 +0300 Subject: [PATCH 021/104] Implement filtering by rank achieved --- .../TestSceneBeatmapListingSearchControl.cs | 3 ++ .../API/Requests/SearchBeatmapSetsRequest.cs | 7 ++++ .../BeatmapListingFilterControl.cs | 2 ++ .../BeatmapListingSearchControl.cs | 4 +++ .../BeatmapSearchExtraFilterRow.cs | 2 +- ...BeatmapSearchMultipleSelectionFilterRow.cs | 4 +-- .../BeatmapSearchRankFilterRow.cs | 35 +++++++++++++++++++ .../Overlays/BeatmapListing/FilterTabItem.cs | 10 +++--- .../Overlays/BeatmapListing/SearchRank.cs | 24 +++++++++++++ 9 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapListing/BeatmapSearchRankFilterRow.cs create mode 100644 osu.Game/Overlays/BeatmapListing/SearchRank.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs index 9b0ef4d6f2..ff8162293b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs @@ -29,6 +29,7 @@ namespace osu.Game.Tests.Visual.UserInterface OsuSpriteText genre; OsuSpriteText language; OsuSpriteText extra; + OsuSpriteText ranks; OsuSpriteText played; Add(control = new BeatmapListingSearchControl @@ -50,6 +51,7 @@ namespace osu.Game.Tests.Visual.UserInterface genre = new OsuSpriteText(), language = new OsuSpriteText(), extra = new OsuSpriteText(), + ranks = new OsuSpriteText(), played = new OsuSpriteText() } }); @@ -60,6 +62,7 @@ namespace osu.Game.Tests.Visual.UserInterface control.Genre.BindValueChanged(g => genre.Text = $"Genre: {g.NewValue}", true); control.Language.BindValueChanged(l => language.Text = $"Language: {l.NewValue}", true); control.Extra.BindValueChanged(e => extra.Text = $"Extra: {(e.NewValue == null ? "" : string.Join(".", e.NewValue.Select(i => i.ToString().ToLowerInvariant())))}", true); + control.Ranks.BindValueChanged(r => ranks.Text = $"Ranks: {(r.NewValue == null ? "" : string.Join(".", r.NewValue.Select(i => i.ToString())))}", true); control.Played.BindValueChanged(p => played.Text = $"Played: {p.NewValue}", true); } diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index 20bbd46529..f819a5778f 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -27,6 +27,8 @@ namespace osu.Game.Online.API.Requests public SearchPlayed Played { get; } + public List Ranks { get; } + private readonly string query; private readonly RulesetInfo ruleset; private readonly Cursor cursor; @@ -43,6 +45,7 @@ namespace osu.Game.Online.API.Requests SearchGenre genre = SearchGenre.Any, SearchLanguage language = SearchLanguage.Any, List extra = null, + List ranks = null, SearchPlayed played = SearchPlayed.Any) { this.query = string.IsNullOrEmpty(query) ? string.Empty : System.Uri.EscapeDataString(query); @@ -55,6 +58,7 @@ namespace osu.Game.Online.API.Requests Genre = genre; Language = language; Extra = extra; + Ranks = ranks; Played = played; } @@ -79,6 +83,9 @@ namespace osu.Game.Online.API.Requests if (Extra != null && Extra.Any()) req.AddParameter("e", string.Join(".", Extra.Select(e => e.ToString().ToLowerInvariant()))); + if (Ranks != null && Ranks.Any()) + req.AddParameter("r", string.Join(".", Ranks.Select(r => r.ToString()))); + if (Played != SearchPlayed.Any) req.AddParameter("played", Played.ToString().ToLowerInvariant()); diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index 3f09a7e3d1..86bf3276fe 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -131,6 +131,7 @@ namespace osu.Game.Overlays.BeatmapListing searchControl.Genre.BindValueChanged(_ => queueUpdateSearch()); searchControl.Language.BindValueChanged(_ => queueUpdateSearch()); searchControl.Extra.BindValueChanged(_ => queueUpdateSearch()); + searchControl.Ranks.BindValueChanged(_ => queueUpdateSearch()); searchControl.Played.BindValueChanged(_ => queueUpdateSearch()); sortCriteria.BindValueChanged(_ => queueUpdateSearch()); @@ -183,6 +184,7 @@ namespace osu.Game.Overlays.BeatmapListing searchControl.Genre.Value, searchControl.Language.Value, searchControl.Extra.Value, + searchControl.Ranks.Value, searchControl.Played.Value); getSetsRequest.Success += response => diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index f390db3f35..64bd7065b5 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -31,6 +31,8 @@ namespace osu.Game.Overlays.BeatmapListing public Bindable> Extra => extraFilter.Current; + public Bindable> Ranks => ranksFilter.Current; + public Bindable Played => playedFilter.Current; public BeatmapSetInfo BeatmapSet @@ -54,6 +56,7 @@ namespace osu.Game.Overlays.BeatmapListing private readonly BeatmapSearchFilterRow genreFilter; private readonly BeatmapSearchFilterRow languageFilter; private readonly BeatmapSearchExtraFilterRow extraFilter; + private readonly BeatmapSearchRankFilterRow ranksFilter; private readonly BeatmapSearchFilterRow playedFilter; private readonly Box background; @@ -113,6 +116,7 @@ namespace osu.Game.Overlays.BeatmapListing genreFilter = new BeatmapSearchFilterRow(@"Genre"), languageFilter = new BeatmapSearchFilterRow(@"Language"), extraFilter = new BeatmapSearchExtraFilterRow(), + ranksFilter = new BeatmapSearchRankFilterRow(), playedFilter = new BeatmapSearchFilterRow(@"Played") } } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs index 385978096c..d8bf18fb88 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs @@ -14,7 +14,7 @@ namespace osu.Game.Overlays.BeatmapListing private class ExtraFilter : MultipleSelectionFilter { - protected override MultipleSelectionFilterTabItem[] CreateItems() => new[] + protected override MultipleSelectionFilterTabItem[] CreateItems() => new MultipleSelectionFilterTabItem[] { new ExtraFilterTabItem(SearchExtra.Video), new ExtraFilterTabItem(SearchExtra.Storyboard) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index c434e00ff3..acf2c62afa 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -14,7 +14,7 @@ namespace osu.Game.Overlays.BeatmapListing { public abstract class BeatmapSearchMultipleSelectionFilterRow : BeatmapSearchFilterRow> { - public BeatmapSearchMultipleSelectionFilterRow(string headerName) + protected BeatmapSearchMultipleSelectionFilterRow(string headerName) : base(headerName) { } @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.BeatmapListing set => current.Current = value; } - public MultipleSelectionFilter() + protected MultipleSelectionFilter() { Anchor = Anchor.BottomLeft; Origin = Anchor.BottomLeft; diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchRankFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchRankFilterRow.cs new file mode 100644 index 0000000000..d521e8c90f --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchRankFilterRow.cs @@ -0,0 +1,35 @@ +// 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.Linq; +using osu.Framework.Extensions; + +namespace osu.Game.Overlays.BeatmapListing +{ + public class BeatmapSearchRankFilterRow : BeatmapSearchMultipleSelectionFilterRow + { + public BeatmapSearchRankFilterRow() + : base("Rank Achieved") + { + } + + protected override MultipleSelectionFilter CreateMultipleSelectionFilter() => new RankFilter(); + + private class RankFilter : MultipleSelectionFilter + { + protected override MultipleSelectionFilterTabItem[] CreateItems() + => ((SearchRank[])Enum.GetValues(typeof(SearchRank))).Select(v => new RankFilterTabItem(v)).ToArray(); + } + + private class RankFilterTabItem : MultipleSelectionFilterTabItem + { + public RankFilterTabItem(SearchRank value) + : base(value) + { + } + + protected override string CreateText(SearchRank value) => $@"{value.GetDescription() ?? value.ToString()}"; + } + } +} diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 32b48862e0..9bdd5b3fad 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -16,8 +16,6 @@ namespace osu.Game.Overlays.BeatmapListing { public class FilterTabItem : TabItem { - protected virtual float TextSize => 13; - [Resolved] private OverlayColourProvider colourProvider { get; set; } @@ -33,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapListing { text = new OsuSpriteText { - Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Regular), + Font = OsuFont.GetFont(size: 13, weight: FontWeight.Regular), Text = CreateText(value) }, new HoverClickSounds() @@ -67,7 +65,11 @@ namespace osu.Game.Overlays.BeatmapListing protected override void OnDeactivated() => updateState(); - private void updateState() => text.FadeColour(Active.Value ? Color4.White : getStateColour(), 200, Easing.OutQuint); + private void updateState() + { + text.FadeColour(Active.Value ? Color4.White : getStateColour(), 200, Easing.OutQuint); + text.Font = text.Font.With(weight: Active.Value ? FontWeight.SemiBold : FontWeight.Regular); + } private Color4 getStateColour() => IsHovered ? colourProvider.Light1 : colourProvider.Light3; } diff --git a/osu.Game/Overlays/BeatmapListing/SearchRank.cs b/osu.Game/Overlays/BeatmapListing/SearchRank.cs new file mode 100644 index 0000000000..8b1882026c --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/SearchRank.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 System.ComponentModel; + +namespace osu.Game.Overlays.BeatmapListing +{ + public enum SearchRank + { + [Description(@"Silver SS")] + XH, + + [Description(@"SS")] + X, + + [Description(@"Silver S")] + SH, + S, + A, + B, + C, + D + } +} From c4efceceb2a384af3468db13839c6668675038c3 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Oct 2020 23:57:11 +0300 Subject: [PATCH 022/104] Use char instead of sting for request parameter creation --- .../UserInterface/TestSceneBeatmapListingSearchControl.cs | 4 ++-- osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs index ff8162293b..e07aa71b1f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs @@ -61,8 +61,8 @@ namespace osu.Game.Tests.Visual.UserInterface control.Category.BindValueChanged(c => category.Text = $"Category: {c.NewValue}", true); control.Genre.BindValueChanged(g => genre.Text = $"Genre: {g.NewValue}", true); control.Language.BindValueChanged(l => language.Text = $"Language: {l.NewValue}", true); - control.Extra.BindValueChanged(e => extra.Text = $"Extra: {(e.NewValue == null ? "" : string.Join(".", e.NewValue.Select(i => i.ToString().ToLowerInvariant())))}", true); - control.Ranks.BindValueChanged(r => ranks.Text = $"Ranks: {(r.NewValue == null ? "" : string.Join(".", r.NewValue.Select(i => i.ToString())))}", true); + control.Extra.BindValueChanged(e => extra.Text = $"Extra: {(e.NewValue == null ? "" : string.Join('.', e.NewValue.Select(i => i.ToString().ToLowerInvariant())))}", true); + control.Ranks.BindValueChanged(r => ranks.Text = $"Ranks: {(r.NewValue == null ? "" : string.Join('.', r.NewValue.Select(i => i.ToString())))}", true); control.Played.BindValueChanged(p => played.Text = $"Played: {p.NewValue}", true); } diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index f819a5778f..248096d8b3 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -81,10 +81,10 @@ namespace osu.Game.Online.API.Requests req.AddParameter("sort", $"{SortCriteria.ToString().ToLowerInvariant()}_{directionString}"); if (Extra != null && Extra.Any()) - req.AddParameter("e", string.Join(".", Extra.Select(e => e.ToString().ToLowerInvariant()))); + req.AddParameter("e", string.Join('.', Extra.Select(e => e.ToString().ToLowerInvariant()))); if (Ranks != null && Ranks.Any()) - req.AddParameter("r", string.Join(".", Ranks.Select(r => r.ToString()))); + req.AddParameter("r", string.Join('.', Ranks.Select(r => r.ToString()))); if (Played != SearchPlayed.Any) req.AddParameter("played", Played.ToString().ToLowerInvariant()); From b4ec3b9fefa6206558cf3f3e0ea6541cac0948e6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 28 Oct 2020 01:41:46 +0300 Subject: [PATCH 023/104] Simplify MultipleSelectionFilterTabItem state changes --- .../BeatmapSearchMultipleSelectionFilterRow.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index acf2c62afa..35c982d35a 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.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; using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -43,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapListing AddRange(CreateItems()); foreach (var item in Children) - item.StateUpdated += updateBindable; + item.Active.BindValueChanged(_ => updateBindable()); } protected abstract MultipleSelectionFilterTabItem[] CreateItems(); @@ -64,18 +63,15 @@ namespace osu.Game.Overlays.BeatmapListing protected class MultipleSelectionFilterTabItem : FilterTabItem { - public event Action StateUpdated; - public MultipleSelectionFilterTabItem(T value) : base(value) { - Active.BindValueChanged(_ => StateUpdated?.Invoke()); } protected override bool OnClick(ClickEvent e) { base.OnClick(e); - Active.Value = !Active.Value; + Active.Toggle(); return true; } } From fd11346a289e03b0a5f2f1f2cd5d1da3a578fffe Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 28 Oct 2020 01:48:24 +0300 Subject: [PATCH 024/104] Update button colours --- osu.Game/Overlays/BeatmapListing/FilterTabItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 9bdd5b3fad..721a3c839c 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -67,10 +67,10 @@ namespace osu.Game.Overlays.BeatmapListing private void updateState() { - text.FadeColour(Active.Value ? Color4.White : getStateColour(), 200, Easing.OutQuint); + text.FadeColour(IsHovered ? colourProvider.Light1 : getStateColour(), 200, Easing.OutQuint); text.Font = text.Font.With(weight: Active.Value ? FontWeight.SemiBold : FontWeight.Regular); } - private Color4 getStateColour() => IsHovered ? colourProvider.Light1 : colourProvider.Light3; + private Color4 getStateColour() => Active.Value ? colourProvider.Content1 : colourProvider.Light2; } } From 03c5057a921d8ddf21666671c76e23bc396b8a60 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 28 Oct 2020 02:28:31 +0300 Subject: [PATCH 025/104] Simplify BeatmapSearchMultipleSelectionFilterRow --- .../BeatmapListingSearchControl.cs | 8 ++--- .../BeatmapSearchExtraFilterRow.cs | 34 ------------------ ...BeatmapSearchMultipleSelectionFilterRow.cs | 21 ++++++----- .../BeatmapSearchRankFilterRow.cs | 35 ------------------- .../Overlays/BeatmapListing/FilterTabItem.cs | 4 +-- .../Overlays/BeatmapListing/SearchExtra.cs | 4 +++ 6 files changed, 19 insertions(+), 87 deletions(-) delete mode 100644 osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs delete mode 100644 osu.Game/Overlays/BeatmapListing/BeatmapSearchRankFilterRow.cs diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index 64bd7065b5..a976890c7c 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -55,8 +55,8 @@ namespace osu.Game.Overlays.BeatmapListing private readonly BeatmapSearchFilterRow categoryFilter; private readonly BeatmapSearchFilterRow genreFilter; private readonly BeatmapSearchFilterRow languageFilter; - private readonly BeatmapSearchExtraFilterRow extraFilter; - private readonly BeatmapSearchRankFilterRow ranksFilter; + private readonly BeatmapSearchMultipleSelectionFilterRow extraFilter; + private readonly BeatmapSearchMultipleSelectionFilterRow ranksFilter; private readonly BeatmapSearchFilterRow playedFilter; private readonly Box background; @@ -115,8 +115,8 @@ namespace osu.Game.Overlays.BeatmapListing categoryFilter = new BeatmapSearchFilterRow(@"Categories"), genreFilter = new BeatmapSearchFilterRow(@"Genre"), languageFilter = new BeatmapSearchFilterRow(@"Language"), - extraFilter = new BeatmapSearchExtraFilterRow(), - ranksFilter = new BeatmapSearchRankFilterRow(), + extraFilter = new BeatmapSearchMultipleSelectionFilterRow(@"Extra"), + ranksFilter = new BeatmapSearchMultipleSelectionFilterRow(@"Rank Achieved"), playedFilter = new BeatmapSearchFilterRow(@"Played") } } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs deleted file mode 100644 index d8bf18fb88..0000000000 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchExtraFilterRow.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Overlays.BeatmapListing -{ - public class BeatmapSearchExtraFilterRow : BeatmapSearchMultipleSelectionFilterRow - { - public BeatmapSearchExtraFilterRow() - : base("Extra") - { - } - - protected override MultipleSelectionFilter CreateMultipleSelectionFilter() => new ExtraFilter(); - - private class ExtraFilter : MultipleSelectionFilter - { - protected override MultipleSelectionFilterTabItem[] CreateItems() => new MultipleSelectionFilterTabItem[] - { - new ExtraFilterTabItem(SearchExtra.Video), - new ExtraFilterTabItem(SearchExtra.Storyboard) - }; - } - - private class ExtraFilterTabItem : MultipleSelectionFilterTabItem - { - public ExtraFilterTabItem(SearchExtra value) - : base(value) - { - } - - protected override string CreateText(SearchExtra value) => $@"Has {value.ToString()}"; - } - } -} diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index 35c982d35a..cb89560e39 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -1,8 +1,10 @@ // 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.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; @@ -11,18 +13,16 @@ using osuTK; namespace osu.Game.Overlays.BeatmapListing { - public abstract class BeatmapSearchMultipleSelectionFilterRow : BeatmapSearchFilterRow> + public class BeatmapSearchMultipleSelectionFilterRow : BeatmapSearchFilterRow> { - protected BeatmapSearchMultipleSelectionFilterRow(string headerName) + public BeatmapSearchMultipleSelectionFilterRow(string headerName) : base(headerName) { } - protected override Drawable CreateFilter() => CreateMultipleSelectionFilter(); + protected override Drawable CreateFilter() => new MultipleSelectionFilter(); - protected abstract MultipleSelectionFilter CreateMultipleSelectionFilter(); - - protected abstract class MultipleSelectionFilter : FillFlowContainer, IHasCurrentValue> + private class MultipleSelectionFilter : FillFlowContainer, IHasCurrentValue> { private readonly BindableWithCurrent> current = new BindableWithCurrent>(); @@ -32,21 +32,20 @@ namespace osu.Game.Overlays.BeatmapListing set => current.Current = value; } - protected MultipleSelectionFilter() + public MultipleSelectionFilter() { Anchor = Anchor.BottomLeft; Origin = Anchor.BottomLeft; RelativeSizeAxes = Axes.X; Height = 15; Spacing = new Vector2(10, 0); - AddRange(CreateItems()); + + ((T[])Enum.GetValues(typeof(T))).ForEach(i => Add(new MultipleSelectionFilterTabItem(i))); foreach (var item in Children) item.Active.BindValueChanged(_ => updateBindable()); } - protected abstract MultipleSelectionFilterTabItem[] CreateItems(); - private void updateBindable() { var selectedValues = new List(); @@ -61,7 +60,7 @@ namespace osu.Game.Overlays.BeatmapListing } } - protected class MultipleSelectionFilterTabItem : FilterTabItem + private class MultipleSelectionFilterTabItem : FilterTabItem { public MultipleSelectionFilterTabItem(T value) : base(value) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchRankFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchRankFilterRow.cs deleted file mode 100644 index d521e8c90f..0000000000 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchRankFilterRow.cs +++ /dev/null @@ -1,35 +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.Linq; -using osu.Framework.Extensions; - -namespace osu.Game.Overlays.BeatmapListing -{ - public class BeatmapSearchRankFilterRow : BeatmapSearchMultipleSelectionFilterRow - { - public BeatmapSearchRankFilterRow() - : base("Rank Achieved") - { - } - - protected override MultipleSelectionFilter CreateMultipleSelectionFilter() => new RankFilter(); - - private class RankFilter : MultipleSelectionFilter - { - protected override MultipleSelectionFilterTabItem[] CreateItems() - => ((SearchRank[])Enum.GetValues(typeof(SearchRank))).Select(v => new RankFilterTabItem(v)).ToArray(); - } - - private class RankFilterTabItem : MultipleSelectionFilterTabItem - { - public RankFilterTabItem(SearchRank value) - : base(value) - { - } - - protected override string CreateText(SearchRank value) => $@"{value.GetDescription() ?? value.ToString()}"; - } - } -} diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 721a3c839c..244ef5a703 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.BeatmapListing text = new OsuSpriteText { Font = OsuFont.GetFont(size: 13, weight: FontWeight.Regular), - Text = CreateText(value) + Text = (value as Enum)?.GetDescription() ?? value.ToString() }, new HoverClickSounds() }); @@ -40,8 +40,6 @@ namespace osu.Game.Overlays.BeatmapListing Enabled.Value = true; } - protected virtual string CreateText(T value) => (value as Enum)?.GetDescription() ?? value.ToString(); - [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs index e9b3165d97..0ee60c4a95 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs @@ -1,11 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.ComponentModel; + namespace osu.Game.Overlays.BeatmapListing { public enum SearchExtra { + [Description("Has Video")] Video, + [Description("Has Storyboard")] Storyboard } } From 6fd3686c4d443ca4c4daad14e1f0885d7747b26f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 28 Oct 2020 02:36:35 +0300 Subject: [PATCH 026/104] Use IReadOnlyCollection instead of List in SearchBeatmapSetsRequest --- osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index 248096d8b3..708b58d954 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -23,11 +23,11 @@ namespace osu.Game.Online.API.Requests public SearchLanguage Language { get; } - public List Extra { get; } + public IReadOnlyCollection Extra { get; } public SearchPlayed Played { get; } - public List Ranks { get; } + public IReadOnlyCollection Ranks { get; } private readonly string query; private readonly RulesetInfo ruleset; @@ -44,8 +44,8 @@ namespace osu.Game.Online.API.Requests SortDirection sortDirection = SortDirection.Descending, SearchGenre genre = SearchGenre.Any, SearchLanguage language = SearchLanguage.Any, - List extra = null, - List ranks = null, + IReadOnlyCollection extra = null, + IReadOnlyCollection ranks = null, SearchPlayed played = SearchPlayed.Any) { this.query = string.IsNullOrEmpty(query) ? string.Empty : System.Uri.EscapeDataString(query); From 914bd537885c946c8bd5fda14aecde6c8b3bc90d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 28 Oct 2020 02:39:51 +0300 Subject: [PATCH 027/104] Add missing blank line --- osu.Game/Overlays/BeatmapListing/SearchExtra.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs index 0ee60c4a95..af37e3264f 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs @@ -9,6 +9,7 @@ namespace osu.Game.Overlays.BeatmapListing { [Description("Has Video")] Video, + [Description("Has Storyboard")] Storyboard } From 01b576c8611bfca9f3d2ba3bad5974ed06688759 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Oct 2020 13:32:39 +0900 Subject: [PATCH 028/104] Fix editor crash on exit when forcing exit twice in a row --- osu.Game/Screens/Edit/Editor.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c3560dff38..0aaa551af9 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -444,12 +444,21 @@ namespace osu.Game.Screens.Edit if (dialogOverlay == null || dialogOverlay.CurrentDialog is PromptForSaveDialog) { confirmExit(); - return true; + return false; } if (isNewBeatmap || HasUnsavedChanges) { - dialogOverlay?.Push(new PromptForSaveDialog(confirmExit, confirmExitWithSave)); + dialogOverlay?.Push(new PromptForSaveDialog(() => + { + confirmExit(); + this.Exit(); + }, () => + { + confirmExitWithSave(); + this.Exit(); + })); + return true; } } @@ -464,7 +473,6 @@ namespace osu.Game.Screens.Edit { exitConfirmed = true; Save(); - this.Exit(); } private void confirmExit() @@ -483,7 +491,6 @@ namespace osu.Game.Screens.Edit } exitConfirmed = true; - this.Exit(); } private readonly Bindable clipboard = new Bindable(); From 9b9a41596f4f651d03321e42eef89609d48954c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Oct 2020 14:42:23 +0900 Subject: [PATCH 029/104] Split out frame stability calculation to own method --- .../Rulesets/UI/FrameStabilityContainer.cs | 69 +++++++++++-------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 28b7975a89..94684f33ed 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -119,35 +119,19 @@ namespace osu.Game.Rulesets.UI if (parentGameplayClock == null) setClock(); // LoadComplete may not be run yet, but we still want the clock. + // each update start with considering things in valid state. validState = true; requireMoreUpdateLoops = false; - var newProposedTime = parentGameplayClock.CurrentTime; + // our goal is to catch up to the time provided by the parent clock. + var proposedTime = parentGameplayClock.CurrentTime; try { if (FrameStablePlayback) - { - if (firstConsumption) - { - // On the first update, frame-stability seeking would result in unexpected/unwanted behaviour. - // Instead we perform an initial seek to the proposed time. - - // process frame (in addition to finally clause) to clear out ElapsedTime - manualClock.CurrentTime = newProposedTime; - framedClock.ProcessFrame(); - - firstConsumption = false; - } - else if (manualClock.CurrentTime < gameplayStartTime) - manualClock.CurrentTime = newProposedTime = Math.Min(gameplayStartTime, newProposedTime); - else if (Math.Abs(manualClock.CurrentTime - newProposedTime) > sixty_frame_time * 1.2f) - { - newProposedTime = newProposedTime > manualClock.CurrentTime - ? Math.Min(newProposedTime, manualClock.CurrentTime + sixty_frame_time) - : Math.Max(newProposedTime, manualClock.CurrentTime - sixty_frame_time); - } - } + // if we require frame stability, the proposed time will be adjusted to move at most one known + // frame interval in the current direction. + applyFrameStability(ref proposedTime); if (isAttached) { @@ -156,7 +140,7 @@ namespace osu.Game.Rulesets.UI if (FrameStablePlayback) { // when stability is turned on, we shouldn't execute for time values the replay is unable to satisfy. - if ((newTime = ReplayInputHandler.SetFrameFromTime(newProposedTime)) == null) + if ((newTime = ReplayInputHandler.SetFrameFromTime(proposedTime)) == null) { // setting invalid state here ensures that gameplay will not continue (ie. our child // hierarchy won't be updated). @@ -173,7 +157,7 @@ namespace osu.Game.Rulesets.UI // when stability is disabled, we don't really care about accuracy. // looping over the replay will allow it to catch up and feed out the required values // for the current time. - while ((newTime = ReplayInputHandler.SetFrameFromTime(newProposedTime)) != newProposedTime) + while ((newTime = ReplayInputHandler.SetFrameFromTime(proposedTime)) != proposedTime) { if (newTime == null) { @@ -185,15 +169,15 @@ namespace osu.Game.Rulesets.UI } } - newProposedTime = newTime.Value; + proposedTime = newTime.Value; } } finally { - if (newProposedTime != manualClock.CurrentTime) - direction = newProposedTime > manualClock.CurrentTime ? 1 : -1; + if (proposedTime != manualClock.CurrentTime) + direction = proposedTime > manualClock.CurrentTime ? 1 : -1; - manualClock.CurrentTime = newProposedTime; + manualClock.CurrentTime = proposedTime; manualClock.Rate = Math.Abs(parentGameplayClock.Rate) * direction; manualClock.IsRunning = parentGameplayClock.IsRunning; @@ -209,6 +193,35 @@ namespace osu.Game.Rulesets.UI } } + /// + /// Apply frame stability modifier to a time. + /// + /// The time which is to be displayed. + private void applyFrameStability(ref double proposedTime) + { + if (firstConsumption) + { + // On the first update, frame-stability seeking would result in unexpected/unwanted behaviour. + // Instead we perform an initial seek to the proposed time. + + // process frame (in addition to finally clause) to clear out ElapsedTime + manualClock.CurrentTime = proposedTime; + framedClock.ProcessFrame(); + + firstConsumption = false; + return; + } + + if (manualClock.CurrentTime < gameplayStartTime) + manualClock.CurrentTime = proposedTime = Math.Min(gameplayStartTime, proposedTime); + else if (Math.Abs(manualClock.CurrentTime - proposedTime) > sixty_frame_time * 1.2f) + { + proposedTime = proposedTime > manualClock.CurrentTime + ? Math.Min(proposedTime, manualClock.CurrentTime + sixty_frame_time) + : Math.Max(proposedTime, manualClock.CurrentTime - sixty_frame_time); + } + } + private void setClock() { if (parentGameplayClock == null) From 8c9bda2ded2a973bd4896aa7795fb30830804af2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Oct 2020 14:53:31 +0900 Subject: [PATCH 030/104] Split out replay update method --- .../Rulesets/UI/FrameStabilityContainer.cs | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 94684f33ed..7f27b283e3 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.UI protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState; - private bool isAttached => ReplayInputHandler != null; + private bool hasReplayAttached => ReplayInputHandler != null; private const double sixty_frame_time = 1000.0 / 60; @@ -133,44 +133,8 @@ namespace osu.Game.Rulesets.UI // frame interval in the current direction. applyFrameStability(ref proposedTime); - if (isAttached) - { - double? newTime; - - if (FrameStablePlayback) - { - // when stability is turned on, we shouldn't execute for time values the replay is unable to satisfy. - if ((newTime = ReplayInputHandler.SetFrameFromTime(proposedTime)) == null) - { - // setting invalid state here ensures that gameplay will not continue (ie. our child - // hierarchy won't be updated). - validState = false; - - // potentially loop to catch-up playback. - requireMoreUpdateLoops = true; - - return; - } - } - else - { - // when stability is disabled, we don't really care about accuracy. - // looping over the replay will allow it to catch up and feed out the required values - // for the current time. - while ((newTime = ReplayInputHandler.SetFrameFromTime(proposedTime)) != proposedTime) - { - if (newTime == null) - { - // special case for when the replay actually can't arrive at the required time. - // protects from potential endless loop. - validState = false; - return; - } - } - } - - proposedTime = newTime.Value; - } + if (hasReplayAttached) + updateReplay(ref proposedTime); } finally { @@ -193,6 +157,49 @@ namespace osu.Game.Rulesets.UI } } + /// + /// Attempt to advance replay playback for a given time. + /// + /// The time which is to be displayed. + private bool updateReplay(ref double proposedTime) + { + double? newTime; + + if (FrameStablePlayback) + { + // when stability is turned on, we shouldn't execute for time values the replay is unable to satisfy. + if ((newTime = ReplayInputHandler.SetFrameFromTime(proposedTime)) == null) + { + // setting invalid state here ensures that gameplay will not continue (ie. our child + // hierarchy won't be updated). + validState = false; + + // potentially loop to catch-up playback. + requireMoreUpdateLoops = true; + + return false; + } + } + else + { + // when stability is disabled, we don't really care about accuracy. + // looping over the replay will allow it to catch up and feed out the required values + // for the current time. + while ((newTime = ReplayInputHandler.SetFrameFromTime(proposedTime)) != proposedTime) + { + if (newTime == null) + { + // special case for when the replay actually can't arrive at the required time. + // protects from potential endless loop. + return false; + } + } + } + + proposedTime = newTime.Value; + return true; + } + /// /// Apply frame stability modifier to a time. /// From a06516c9004ad7273ace9ce161d9851ec1b055d2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Oct 2020 15:11:53 +0900 Subject: [PATCH 031/104] Extract out frame stability state into enum for (hopefully) better clarity --- .../Rulesets/UI/FrameStabilityContainer.cs | 81 ++++++++++--------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 7f27b283e3..12e4dd8b01 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -73,19 +73,9 @@ namespace osu.Game.Rulesets.UI setClock(); } - /// - /// Whether we are running up-to-date with our parent clock. - /// If not, we will need to keep processing children until we catch up. - /// - private bool requireMoreUpdateLoops; + private PlaybackState state; - /// - /// Whether we are in a valid state (ie. should we keep processing children frames). - /// This should be set to false when the replay is, for instance, waiting for future frames to arrive. - /// - private bool validState; - - protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState; + protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && state != PlaybackState.NotValid; private bool hasReplayAttached => ReplayInputHandler != null; @@ -95,20 +85,19 @@ namespace osu.Game.Rulesets.UI public override bool UpdateSubTree() { - requireMoreUpdateLoops = true; - validState = !frameStableClock.IsPaused.Value; + state = frameStableClock.IsPaused.Value ? PlaybackState.NotValid : PlaybackState.Valid; - int loops = 0; + int loops = MaxCatchUpFrames; - while (validState && requireMoreUpdateLoops && loops++ < MaxCatchUpFrames) + while (state != PlaybackState.NotValid && loops-- > 0) { updateClock(); - if (validState) - { - base.UpdateSubTree(); - UpdateSubTreeMasking(this, ScreenSpaceDrawQuad.AABBFloat); - } + if (state == PlaybackState.NotValid) + break; + + base.UpdateSubTree(); + UpdateSubTreeMasking(this, ScreenSpaceDrawQuad.AABBFloat); } return true; @@ -120,8 +109,7 @@ namespace osu.Game.Rulesets.UI setClock(); // LoadComplete may not be run yet, but we still want the clock. // each update start with considering things in valid state. - validState = true; - requireMoreUpdateLoops = false; + state = PlaybackState.Valid; // our goal is to catch up to the time provided by the parent clock. var proposedTime = parentGameplayClock.CurrentTime; @@ -134,7 +122,7 @@ namespace osu.Game.Rulesets.UI applyFrameStability(ref proposedTime); if (hasReplayAttached) - updateReplay(ref proposedTime); + state = updateReplay(ref proposedTime); } finally { @@ -147,7 +135,9 @@ namespace osu.Game.Rulesets.UI double timeBehind = Math.Abs(manualClock.CurrentTime - parentGameplayClock.CurrentTime); - requireMoreUpdateLoops |= timeBehind != 0; + // determine whether catch-up is required. + if (state != PlaybackState.NotValid) + state = timeBehind > 0 ? PlaybackState.RequiresCatchUp : PlaybackState.Valid; frameStableClock.IsCatchingUp.Value = timeBehind > 200; @@ -161,24 +151,14 @@ namespace osu.Game.Rulesets.UI /// Attempt to advance replay playback for a given time. /// /// The time which is to be displayed. - private bool updateReplay(ref double proposedTime) + private PlaybackState updateReplay(ref double proposedTime) { double? newTime; if (FrameStablePlayback) { // when stability is turned on, we shouldn't execute for time values the replay is unable to satisfy. - if ((newTime = ReplayInputHandler.SetFrameFromTime(proposedTime)) == null) - { - // setting invalid state here ensures that gameplay will not continue (ie. our child - // hierarchy won't be updated). - validState = false; - - // potentially loop to catch-up playback. - requireMoreUpdateLoops = true; - - return false; - } + newTime = ReplayInputHandler.SetFrameFromTime(proposedTime); } else { @@ -191,13 +171,16 @@ namespace osu.Game.Rulesets.UI { // special case for when the replay actually can't arrive at the required time. // protects from potential endless loop. - return false; + break; } } } + if (newTime == null) + return PlaybackState.NotValid; + proposedTime = newTime.Value; - return true; + return PlaybackState.Valid; } /// @@ -244,6 +227,26 @@ namespace osu.Game.Rulesets.UI public ReplayInputHandler ReplayInputHandler { get; set; } + private enum PlaybackState + { + /// + /// Playback is not possible. Child hierarchy should not be processed. + /// + NotValid, + + /// + /// Whether we are running up-to-date with our parent clock. + /// If not, we will need to keep processing children until we catch up. + /// + RequiresCatchUp, + + /// + /// Whether we are in a valid state (ie. should we keep processing children frames). + /// This should be set to false when the replay is, for instance, waiting for future frames to arrive. + /// + Valid + } + private class FrameStabilityClock : GameplayClock, IFrameStableClock { public GameplayClock ParentGameplayClock; From 59e9c2639ad503eff93b7d848de21c12abfecfeb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Oct 2020 15:12:39 +0900 Subject: [PATCH 032/104] Remove try-finally --- .../Rulesets/UI/FrameStabilityContainer.cs | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 12e4dd8b01..4386acfcce 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -114,37 +114,32 @@ namespace osu.Game.Rulesets.UI // our goal is to catch up to the time provided by the parent clock. var proposedTime = parentGameplayClock.CurrentTime; - try - { - if (FrameStablePlayback) - // if we require frame stability, the proposed time will be adjusted to move at most one known - // frame interval in the current direction. - applyFrameStability(ref proposedTime); + if (FrameStablePlayback) + // if we require frame stability, the proposed time will be adjusted to move at most one known + // frame interval in the current direction. + applyFrameStability(ref proposedTime); - if (hasReplayAttached) - state = updateReplay(ref proposedTime); - } - finally - { - if (proposedTime != manualClock.CurrentTime) - direction = proposedTime > manualClock.CurrentTime ? 1 : -1; + if (hasReplayAttached) + state = updateReplay(ref proposedTime); - manualClock.CurrentTime = proposedTime; - manualClock.Rate = Math.Abs(parentGameplayClock.Rate) * direction; - manualClock.IsRunning = parentGameplayClock.IsRunning; + if (proposedTime != manualClock.CurrentTime) + direction = proposedTime >= manualClock.CurrentTime ? 1 : -1; - double timeBehind = Math.Abs(manualClock.CurrentTime - parentGameplayClock.CurrentTime); + manualClock.CurrentTime = proposedTime; + manualClock.Rate = Math.Abs(parentGameplayClock.Rate) * direction; + manualClock.IsRunning = parentGameplayClock.IsRunning; - // determine whether catch-up is required. - if (state != PlaybackState.NotValid) - state = timeBehind > 0 ? PlaybackState.RequiresCatchUp : PlaybackState.Valid; + double timeBehind = Math.Abs(manualClock.CurrentTime - parentGameplayClock.CurrentTime); - frameStableClock.IsCatchingUp.Value = timeBehind > 200; + // determine whether catch-up is required. + if (state != PlaybackState.NotValid) + state = timeBehind > 0 ? PlaybackState.RequiresCatchUp : PlaybackState.Valid; - // The manual clock time has changed in the above code. The framed clock now needs to be updated - // to ensure that the its time is valid for our children before input is processed - framedClock.ProcessFrame(); - } + frameStableClock.IsCatchingUp.Value = timeBehind > 200; + + // The manual clock time has changed in the above code. The framed clock now needs to be updated + // to ensure that the its time is valid for our children before input is processed + framedClock.ProcessFrame(); } /// From c9515653b303a8fc3ec8753aae6c7114f86f94fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Oct 2020 15:31:57 +0900 Subject: [PATCH 033/104] Restore previous directionality logic to avoid logic differences --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 4386acfcce..7e17c93bed 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -123,7 +123,7 @@ namespace osu.Game.Rulesets.UI state = updateReplay(ref proposedTime); if (proposedTime != manualClock.CurrentTime) - direction = proposedTime >= manualClock.CurrentTime ? 1 : -1; + direction = proposedTime > manualClock.CurrentTime ? 1 : -1; manualClock.CurrentTime = proposedTime; manualClock.Rate = Math.Abs(parentGameplayClock.Rate) * direction; From 2b1e79a4e8f324e4d0dcfa66c94b6db8112112d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Oct 2020 15:32:20 +0900 Subject: [PATCH 034/104] Simplify state changes further --- .../Rulesets/UI/FrameStabilityContainer.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 7e17c93bed..6548bee4ef 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -120,7 +120,12 @@ namespace osu.Game.Rulesets.UI applyFrameStability(ref proposedTime); if (hasReplayAttached) - state = updateReplay(ref proposedTime); + { + bool valid = updateReplay(ref proposedTime); + + if (!valid) + state = PlaybackState.NotValid; + } if (proposedTime != manualClock.CurrentTime) direction = proposedTime > manualClock.CurrentTime ? 1 : -1; @@ -132,8 +137,8 @@ namespace osu.Game.Rulesets.UI double timeBehind = Math.Abs(manualClock.CurrentTime - parentGameplayClock.CurrentTime); // determine whether catch-up is required. - if (state != PlaybackState.NotValid) - state = timeBehind > 0 ? PlaybackState.RequiresCatchUp : PlaybackState.Valid; + if (state == PlaybackState.Valid && timeBehind > 0) + state = PlaybackState.RequiresCatchUp; frameStableClock.IsCatchingUp.Value = timeBehind > 200; @@ -146,7 +151,8 @@ namespace osu.Game.Rulesets.UI /// Attempt to advance replay playback for a given time. /// /// The time which is to be displayed. - private PlaybackState updateReplay(ref double proposedTime) + /// Whether playback is still valid. + private bool updateReplay(ref double proposedTime) { double? newTime; @@ -172,10 +178,10 @@ namespace osu.Game.Rulesets.UI } if (newTime == null) - return PlaybackState.NotValid; + return false; proposedTime = newTime.Value; - return PlaybackState.Valid; + return true; } /// From 4f6081c7f3f48fcedc899665a32e89b4a757e45c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 28 Oct 2020 19:44:13 +0300 Subject: [PATCH 035/104] Use BindableList --- .../TestSceneBeatmapListingSearchControl.cs | 4 +-- .../BeatmapListingFilterControl.cs | 8 ++--- .../BeatmapListingSearchControl.cs | 5 ++- .../BeatmapListing/BeatmapSearchFilterRow.cs | 2 +- ...BeatmapSearchMultipleSelectionFilterRow.cs | 35 ++++++++----------- 5 files changed, 23 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs index e07aa71b1f..3f757031f8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs @@ -61,8 +61,8 @@ namespace osu.Game.Tests.Visual.UserInterface control.Category.BindValueChanged(c => category.Text = $"Category: {c.NewValue}", true); control.Genre.BindValueChanged(g => genre.Text = $"Genre: {g.NewValue}", true); control.Language.BindValueChanged(l => language.Text = $"Language: {l.NewValue}", true); - control.Extra.BindValueChanged(e => extra.Text = $"Extra: {(e.NewValue == null ? "" : string.Join('.', e.NewValue.Select(i => i.ToString().ToLowerInvariant())))}", true); - control.Ranks.BindValueChanged(r => ranks.Text = $"Ranks: {(r.NewValue == null ? "" : string.Join('.', r.NewValue.Select(i => i.ToString())))}", true); + control.Extra.BindCollectionChanged((u, v) => extra.Text = $"Extra: {(control.Extra.Any() ? string.Join('.', control.Extra.Select(i => i.ToString().ToLowerInvariant())) : "")}", true); + control.Ranks.BindCollectionChanged((u, v) => ranks.Text = $"Ranks: {(control.Ranks.Any() ? string.Join('.', control.Ranks.Select(i => i.ToString())) : "")}", true); control.Played.BindValueChanged(p => played.Text = $"Played: {p.NewValue}", true); } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index 86bf3276fe..71f0d8c522 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -130,8 +130,8 @@ namespace osu.Game.Overlays.BeatmapListing searchControl.Category.BindValueChanged(_ => queueUpdateSearch()); searchControl.Genre.BindValueChanged(_ => queueUpdateSearch()); searchControl.Language.BindValueChanged(_ => queueUpdateSearch()); - searchControl.Extra.BindValueChanged(_ => queueUpdateSearch()); - searchControl.Ranks.BindValueChanged(_ => queueUpdateSearch()); + searchControl.Extra.CollectionChanged += (u, v) => queueUpdateSearch(); + searchControl.Ranks.CollectionChanged += (u, v) => queueUpdateSearch(); searchControl.Played.BindValueChanged(_ => queueUpdateSearch()); sortCriteria.BindValueChanged(_ => queueUpdateSearch()); @@ -183,8 +183,8 @@ namespace osu.Game.Overlays.BeatmapListing sortControl.SortDirection.Value, searchControl.Genre.Value, searchControl.Language.Value, - searchControl.Extra.Value, - searchControl.Ranks.Value, + searchControl.Extra, + searchControl.Ranks, searchControl.Played.Value); getSetsRequest.Success += response => diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index a976890c7c..4fc5c5315b 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -13,7 +13,6 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osuTK.Graphics; using osu.Game.Rulesets; -using System.Collections.Generic; namespace osu.Game.Overlays.BeatmapListing { @@ -29,9 +28,9 @@ namespace osu.Game.Overlays.BeatmapListing public Bindable Language => languageFilter.Current; - public Bindable> Extra => extraFilter.Current; + public BindableList Extra => extraFilter.Current; - public Bindable> Ranks => ranksFilter.Current; + public BindableList Ranks => ranksFilter.Current; public Bindable Played => playedFilter.Current; diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs index aa0fc0d00e..b429a5277b 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs @@ -61,7 +61,7 @@ namespace osu.Game.Overlays.BeatmapListing }); if (filter is IHasCurrentValue filterWithValue) - filterWithValue.Current = current; + Current = filterWithValue.Current; } [NotNull] diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index cb89560e39..993b475f32 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -7,7 +7,6 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osuTK; @@ -15,22 +14,21 @@ namespace osu.Game.Overlays.BeatmapListing { public class BeatmapSearchMultipleSelectionFilterRow : BeatmapSearchFilterRow> { + public new readonly BindableList Current = new BindableList(); + + private MultipleSelectionFilter filter; + public BeatmapSearchMultipleSelectionFilterRow(string headerName) : base(headerName) { + Current.BindTo(filter.Current); } - protected override Drawable CreateFilter() => new MultipleSelectionFilter(); + protected override Drawable CreateFilter() => filter = new MultipleSelectionFilter(); - private class MultipleSelectionFilter : FillFlowContainer, IHasCurrentValue> + private class MultipleSelectionFilter : FillFlowContainer { - private readonly BindableWithCurrent> current = new BindableWithCurrent>(); - - public Bindable> Current - { - get => current.Current; - set => current.Current = value; - } + public readonly BindableList Current = new BindableList(); public MultipleSelectionFilter() { @@ -43,20 +41,15 @@ namespace osu.Game.Overlays.BeatmapListing ((T[])Enum.GetValues(typeof(T))).ForEach(i => Add(new MultipleSelectionFilterTabItem(i))); foreach (var item in Children) - item.Active.BindValueChanged(_ => updateBindable()); + item.Active.BindValueChanged(active => updateBindable(item.Value, active.NewValue)); } - private void updateBindable() + private void updateBindable(T value, bool active) { - var selectedValues = new List(); - - foreach (var item in Children) - { - if (item.Active.Value) - selectedValues.Add(item.Value); - } - - Current.Value = selectedValues; + if (active) + Current.Add(value); + else + Current.Remove(value); } } From 5c2c5f200075a4f7f19a089a9db3775a11b73668 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 28 Oct 2020 23:35:08 +0300 Subject: [PATCH 036/104] Use existing ScoreRank for rank filter --- .../API/Requests/SearchBeatmapSetsRequest.cs | 5 +- .../BeatmapListingSearchControl.cs | 7 +-- ...BeatmapSearchMultipleSelectionFilterRow.cs | 14 ++++-- .../BeatmapSearchScoreFilterRow.cs | 48 +++++++++++++++++++ .../Overlays/BeatmapListing/FilterTabItem.cs | 4 +- .../Overlays/BeatmapListing/SearchRank.cs | 24 ---------- 6 files changed, 68 insertions(+), 34 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs delete mode 100644 osu.Game/Overlays/BeatmapListing/SearchRank.cs diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index 708b58d954..ed67c5f5ca 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -8,6 +8,7 @@ using osu.Game.Extensions; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapListing; using osu.Game.Rulesets; +using osu.Game.Scoring; namespace osu.Game.Online.API.Requests { @@ -27,7 +28,7 @@ namespace osu.Game.Online.API.Requests public SearchPlayed Played { get; } - public IReadOnlyCollection Ranks { get; } + public IReadOnlyCollection Ranks { get; } private readonly string query; private readonly RulesetInfo ruleset; @@ -45,7 +46,7 @@ namespace osu.Game.Online.API.Requests SearchGenre genre = SearchGenre.Any, SearchLanguage language = SearchLanguage.Any, IReadOnlyCollection extra = null, - IReadOnlyCollection ranks = null, + IReadOnlyCollection ranks = null, SearchPlayed played = SearchPlayed.Any) { this.query = string.IsNullOrEmpty(query) ? string.Empty : System.Uri.EscapeDataString(query); diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index 4fc5c5315b..3694c9855e 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osuTK.Graphics; using osu.Game.Rulesets; +using osu.Game.Scoring; namespace osu.Game.Overlays.BeatmapListing { @@ -30,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapListing public BindableList Extra => extraFilter.Current; - public BindableList Ranks => ranksFilter.Current; + public BindableList Ranks => ranksFilter.Current; public Bindable Played => playedFilter.Current; @@ -55,7 +56,7 @@ namespace osu.Game.Overlays.BeatmapListing private readonly BeatmapSearchFilterRow genreFilter; private readonly BeatmapSearchFilterRow languageFilter; private readonly BeatmapSearchMultipleSelectionFilterRow extraFilter; - private readonly BeatmapSearchMultipleSelectionFilterRow ranksFilter; + private readonly BeatmapSearchScoreFilterRow ranksFilter; private readonly BeatmapSearchFilterRow playedFilter; private readonly Box background; @@ -115,7 +116,7 @@ namespace osu.Game.Overlays.BeatmapListing genreFilter = new BeatmapSearchFilterRow(@"Genre"), languageFilter = new BeatmapSearchFilterRow(@"Language"), extraFilter = new BeatmapSearchMultipleSelectionFilterRow(@"Extra"), - ranksFilter = new BeatmapSearchMultipleSelectionFilterRow(@"Rank Achieved"), + ranksFilter = new BeatmapSearchScoreFilterRow(), playedFilter = new BeatmapSearchFilterRow(@"Played") } } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index 993b475f32..87e60c5bdd 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -24,9 +24,11 @@ namespace osu.Game.Overlays.BeatmapListing Current.BindTo(filter.Current); } - protected override Drawable CreateFilter() => filter = new MultipleSelectionFilter(); + protected override Drawable CreateFilter() => filter = CreateMultipleSelectionFilter(); - private class MultipleSelectionFilter : FillFlowContainer + protected virtual MultipleSelectionFilter CreateMultipleSelectionFilter() => new MultipleSelectionFilter(); + + protected class MultipleSelectionFilter : FillFlowContainer { public readonly BindableList Current = new BindableList(); @@ -38,12 +40,16 @@ namespace osu.Game.Overlays.BeatmapListing Height = 15; Spacing = new Vector2(10, 0); - ((T[])Enum.GetValues(typeof(T))).ForEach(i => Add(new MultipleSelectionFilterTabItem(i))); + GetValues().ForEach(i => Add(CreateTabItem(i))); foreach (var item in Children) item.Active.BindValueChanged(active => updateBindable(item.Value, active.NewValue)); } + protected virtual T[] GetValues() => (T[])Enum.GetValues(typeof(T)); + + protected virtual MultipleSelectionFilterTabItem CreateTabItem(T value) => new MultipleSelectionFilterTabItem(value); + private void updateBindable(T value, bool active) { if (active) @@ -53,7 +59,7 @@ namespace osu.Game.Overlays.BeatmapListing } } - private class MultipleSelectionFilterTabItem : FilterTabItem + protected class MultipleSelectionFilterTabItem : FilterTabItem { public MultipleSelectionFilterTabItem(T value) : base(value) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs new file mode 100644 index 0000000000..f741850f07 --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs @@ -0,0 +1,48 @@ +// 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.Game.Scoring; + +namespace osu.Game.Overlays.BeatmapListing +{ + public class BeatmapSearchScoreFilterRow : BeatmapSearchMultipleSelectionFilterRow + { + public BeatmapSearchScoreFilterRow() + : base(@"Rank Achieved") + { + } + + protected override MultipleSelectionFilter CreateMultipleSelectionFilter() => new RankFilter(); + + private class RankFilter : MultipleSelectionFilter + { + protected override MultipleSelectionFilterTabItem CreateTabItem(ScoreRank value) => new RankItem(value); + + protected override ScoreRank[] GetValues() => base.GetValues().Reverse().ToArray(); + } + + private class RankItem : MultipleSelectionFilterTabItem + { + public RankItem(ScoreRank value) + : base(value) + { + } + + protected override string CreateText(ScoreRank value) + { + switch (value) + { + case ScoreRank.XH: + return @"Silver SS"; + + case ScoreRank.SH: + return @"Silver S"; + + default: + return base.CreateText(value); + } + } + } + } +} diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 244ef5a703..c45a82bef1 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.BeatmapListing text = new OsuSpriteText { Font = OsuFont.GetFont(size: 13, weight: FontWeight.Regular), - Text = (value as Enum)?.GetDescription() ?? value.ToString() + Text = CreateText(value) }, new HoverClickSounds() }); @@ -63,6 +63,8 @@ namespace osu.Game.Overlays.BeatmapListing protected override void OnDeactivated() => updateState(); + protected virtual string CreateText(T value) => (value as Enum)?.GetDescription() ?? value.ToString(); + private void updateState() { text.FadeColour(IsHovered ? colourProvider.Light1 : getStateColour(), 200, Easing.OutQuint); diff --git a/osu.Game/Overlays/BeatmapListing/SearchRank.cs b/osu.Game/Overlays/BeatmapListing/SearchRank.cs deleted file mode 100644 index 8b1882026c..0000000000 --- a/osu.Game/Overlays/BeatmapListing/SearchRank.cs +++ /dev/null @@ -1,24 +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.ComponentModel; - -namespace osu.Game.Overlays.BeatmapListing -{ - public enum SearchRank - { - [Description(@"Silver SS")] - XH, - - [Description(@"SS")] - X, - - [Description(@"Silver S")] - SH, - S, - A, - B, - C, - D - } -} From 202fe093065ef46560555d78402fbf3c49f8a762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Oct 2020 22:03:59 +0100 Subject: [PATCH 037/104] Group selection actions back up in SelectionHandler --- .../Sliders/SliderSelectionBlueprint.cs | 4 ++-- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 17 ----------------- .../Compose/Components/BlueprintContainer.cs | 7 ------- .../Edit/Compose/Components/SelectionHandler.cs | 5 ++++- 4 files changed, 6 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index ca9ec886d5..d3fb5defae 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -107,14 +107,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { case MouseButton.Right: rightClickPosition = e.MouseDownPosition; - break; + return false; // Allow right click to be handled by context menu case MouseButton.Left when e.ControlPressed && IsSelected: placementControlPointIndex = addControlPoint(e.MousePosition); return true; // Stop input from being handled and modifying the selection } - return base.OnMouseDown(e); + return false; } private int? placementControlPointIndex; diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 87ef7e647f..f3816f6218 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -8,13 +8,10 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Screens.Edit; using osuTK; -using osuTK.Input; namespace osu.Game.Rulesets.Edit { @@ -55,20 +52,6 @@ namespace osu.Game.Rulesets.Edit updateState(); } - [Resolved] - private EditorBeatmap editorBeatmap { get; set; } - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (e.CurrentState.Keyboard.ShiftPressed && e.IsPressed(MouseButton.Right)) - { - editorBeatmap.Remove(HitObject); - return true; - } - - return base.OnMouseDown(e); - } - private SelectionState state; public event Action StateChanged; diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 7751df29cf..5ac360d029 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -298,13 +298,6 @@ namespace osu.Game.Screens.Edit.Compose.Components { Debug.Assert(!clickSelectionBegan); - // Deselections are only allowed for control + left clicks - bool allowDeselection = e.ControlPressed && e.Button == MouseButton.Left; - - // Todo: This is probably incorrectly disallowing multiple selections on stacked objects - if (!allowDeselection && SelectionHandler.SelectedBlueprints.Any(s => s.IsHovered)) - return; - foreach (SelectionBlueprint blueprint in SelectionBlueprints.AliveChildren) { if (blueprint.IsHovered) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 24f88bf36d..01e23bafc5 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -24,6 +24,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osuTK; +using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components { @@ -224,7 +225,9 @@ namespace osu.Game.Screens.Edit.Compose.Components /// The input state at the point of selection. internal void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) { - if (state.Keyboard.ControlPressed) + if (state.Keyboard.ShiftPressed && state.Mouse.IsPressed(MouseButton.Right)) + EditorBeatmap.Remove(blueprint.HitObject); + else if (state.Keyboard.ControlPressed && state.Mouse.IsPressed(MouseButton.Left)) blueprint.ToggleSelection(); else ensureSelected(blueprint); From fa53549ed271a7ff3486ff77835c93baa03ec48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Oct 2020 22:57:03 +0100 Subject: [PATCH 038/104] Mark request fields as possibly-null --- osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index ed67c5f5ca..bbaa7e745f 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using osu.Framework.IO.Network; using osu.Game.Extensions; using osu.Game.Overlays; @@ -24,10 +25,12 @@ namespace osu.Game.Online.API.Requests public SearchLanguage Language { get; } + [CanBeNull] public IReadOnlyCollection Extra { get; } public SearchPlayed Played { get; } + [CanBeNull] public IReadOnlyCollection Ranks { get; } private readonly string query; From e77049eae39afb8cf363197079ccd9a4257c07b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Oct 2020 22:58:51 +0100 Subject: [PATCH 039/104] Use discard-like lambda parameter names --- .../Overlays/BeatmapListing/BeatmapListingFilterControl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index 71f0d8c522..3be38e3c1d 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -130,8 +130,8 @@ namespace osu.Game.Overlays.BeatmapListing searchControl.Category.BindValueChanged(_ => queueUpdateSearch()); searchControl.Genre.BindValueChanged(_ => queueUpdateSearch()); searchControl.Language.BindValueChanged(_ => queueUpdateSearch()); - searchControl.Extra.CollectionChanged += (u, v) => queueUpdateSearch(); - searchControl.Ranks.CollectionChanged += (u, v) => queueUpdateSearch(); + searchControl.Extra.CollectionChanged += (_, __) => queueUpdateSearch(); + searchControl.Ranks.CollectionChanged += (_, __) => queueUpdateSearch(); searchControl.Played.BindValueChanged(_ => queueUpdateSearch()); sortCriteria.BindValueChanged(_ => queueUpdateSearch()); From f5aedc96c4244974750c651a94976f17ed283ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Oct 2020 23:07:54 +0100 Subject: [PATCH 040/104] Rework multiple selection filter --- ...BeatmapSearchMultipleSelectionFilterRow.cs | 23 ++++++++++++------- .../BeatmapSearchScoreFilterRow.cs | 3 ++- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index 87e60c5bdd..ae669e91dd 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -3,8 +3,9 @@ using System; using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; @@ -32,7 +33,8 @@ namespace osu.Game.Overlays.BeatmapListing { public readonly BindableList Current = new BindableList(); - public MultipleSelectionFilter() + [BackgroundDependencyLoader] + private void load() { Anchor = Anchor.BottomLeft; Origin = Anchor.BottomLeft; @@ -40,17 +42,22 @@ namespace osu.Game.Overlays.BeatmapListing Height = 15; Spacing = new Vector2(10, 0); - GetValues().ForEach(i => Add(CreateTabItem(i))); - - foreach (var item in Children) - item.Active.BindValueChanged(active => updateBindable(item.Value, active.NewValue)); + AddRange(GetValues().Select(CreateTabItem)); } - protected virtual T[] GetValues() => (T[])Enum.GetValues(typeof(T)); + protected override void LoadComplete() + { + base.LoadComplete(); + + foreach (var item in Children) + item.Active.BindValueChanged(active => toggleItem(item.Value, active.NewValue)); + } + + protected virtual IEnumerable GetValues() => Enum.GetValues(typeof(T)).Cast(); protected virtual MultipleSelectionFilterTabItem CreateTabItem(T value) => new MultipleSelectionFilterTabItem(value); - private void updateBindable(T value, bool active) + private void toggleItem(T value, bool active) { if (active) Current.Add(value); diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs index f741850f07..dc642cb4cd 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.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.Collections.Generic; using System.Linq; using osu.Game.Scoring; @@ -19,7 +20,7 @@ namespace osu.Game.Overlays.BeatmapListing { protected override MultipleSelectionFilterTabItem CreateTabItem(ScoreRank value) => new RankItem(value); - protected override ScoreRank[] GetValues() => base.GetValues().Reverse().ToArray(); + protected override IEnumerable GetValues() => base.GetValues().Reverse(); } private class RankItem : MultipleSelectionFilterTabItem From a8cefb0d4ce014b5944559188d2faf063fdfcf83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Oct 2020 23:12:28 +0100 Subject: [PATCH 041/104] Rename method --- .../Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs | 5 +++-- osu.Game/Overlays/BeatmapListing/FilterTabItem.cs | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs index dc642cb4cd..804962adfb 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Extensions; using osu.Game.Scoring; namespace osu.Game.Overlays.BeatmapListing @@ -30,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapListing { } - protected override string CreateText(ScoreRank value) + protected override string LabelFor(ScoreRank value) { switch (value) { @@ -41,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapListing return @"Silver S"; default: - return base.CreateText(value); + return value.GetDescription(); } } } diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index c45a82bef1..43913c7ce2 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.BeatmapListing text = new OsuSpriteText { Font = OsuFont.GetFont(size: 13, weight: FontWeight.Regular), - Text = CreateText(value) + Text = LabelFor(value) }, new HoverClickSounds() }); @@ -63,7 +63,10 @@ namespace osu.Game.Overlays.BeatmapListing protected override void OnDeactivated() => updateState(); - protected virtual string CreateText(T value) => (value as Enum)?.GetDescription() ?? value.ToString(); + /// + /// Returns the label text to be used for the supplied . + /// + protected virtual string LabelFor(T value) => (value as Enum)?.GetDescription() ?? value.ToString(); private void updateState() { From 016e920aa9fff8a7b4c2aaf4236a70cfff5b3038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Oct 2020 23:14:52 +0100 Subject: [PATCH 042/104] Move filter tab item hierarchy construction to BDL --- osu.Game/Overlays/BeatmapListing/FilterTabItem.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 43913c7ce2..f02b515755 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -19,10 +19,15 @@ namespace osu.Game.Overlays.BeatmapListing [Resolved] private OverlayColourProvider colourProvider { get; set; } - private readonly OsuSpriteText text; + private OsuSpriteText text; public FilterTabItem(T value) : base(value) + { + } + + [BackgroundDependencyLoader] + private void load() { AutoSizeAxes = Axes.Both; Anchor = Anchor.BottomLeft; @@ -32,17 +37,12 @@ namespace osu.Game.Overlays.BeatmapListing text = new OsuSpriteText { Font = OsuFont.GetFont(size: 13, weight: FontWeight.Regular), - Text = LabelFor(value) + Text = LabelFor(Value) }, new HoverClickSounds() }); Enabled.Value = true; - } - - [BackgroundDependencyLoader] - private void load() - { updateState(); } From 1313ab89e76d0a0f5caaed1274c6a12971a34db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 28 Oct 2020 23:37:21 +0100 Subject: [PATCH 043/104] Add xmldoc to multiple selection row --- .../BeatmapSearchMultipleSelectionFilterRow.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index ae669e91dd..5dfa8e6109 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -25,8 +25,11 @@ namespace osu.Game.Overlays.BeatmapListing Current.BindTo(filter.Current); } - protected override Drawable CreateFilter() => filter = CreateMultipleSelectionFilter(); + protected sealed override Drawable CreateFilter() => filter = CreateMultipleSelectionFilter(); + /// + /// Creates a filter control that can be used to simultaneously select multiple values of type . + /// protected virtual MultipleSelectionFilter CreateMultipleSelectionFilter() => new MultipleSelectionFilter(); protected class MultipleSelectionFilter : FillFlowContainer @@ -53,8 +56,14 @@ namespace osu.Game.Overlays.BeatmapListing item.Active.BindValueChanged(active => toggleItem(item.Value, active.NewValue)); } + /// + /// Returns all values to be displayed in this filter row. + /// protected virtual IEnumerable GetValues() => Enum.GetValues(typeof(T)).Cast(); + /// + /// Creates a representing the supplied . + /// protected virtual MultipleSelectionFilterTabItem CreateTabItem(T value) => new MultipleSelectionFilterTabItem(value); private void toggleItem(T value, bool active) From 2e5a8b2287ce1b74f316671d9533faf87cb967f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 13:16:27 +0900 Subject: [PATCH 044/104] Fix xmldoc to read better in new context --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 6548bee4ef..595574115c 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -236,14 +236,13 @@ namespace osu.Game.Rulesets.UI NotValid, /// - /// Whether we are running up-to-date with our parent clock. - /// If not, we will need to keep processing children until we catch up. + /// Playback is running behind real-time. Catch-up will be attempted by processing more than once per + /// game loop (limited to a sane maximum to avoid frame drops). /// RequiresCatchUp, /// - /// Whether we are in a valid state (ie. should we keep processing children frames). - /// This should be set to false when the replay is, for instance, waiting for future frames to arrive. + /// In a valid state, progressing one child hierarchy loop per game loop. /// Valid } From c0960e60cb59a50ace68901ae8a71df26ebc0e7b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 14:52:34 +0900 Subject: [PATCH 045/104] Add note about testflight link Sick of getting asked about this. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7c749f3422..86c42dae12 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ If you are looking to install or test osu! without setting up a development envi | [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) | ------------- | ------------- | ------------- | ------------- | ------------- | +- The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets. + - When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/dependencies?tabs=netcore31&pivots=os-windows)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs. If your platform is not listed above, there is still a chance you can manually build it by following the instructions below. From 3751c357a35b82bbc90cefe72eefe1052582f466 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 15:19:05 +0900 Subject: [PATCH 046/104] 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 2d531cf01e..27846fdf53 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ca588b89d9..609ac0e5f9 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 9c22dec330..ebd38bc334 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -80,7 +80,7 @@ - + From 3ea27e23e8b8395b091221a78700f9c4b95aa347 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 15:20:10 +0900 Subject: [PATCH 047/104] Update namespace references --- osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs | 1 + osu.Game/Rulesets/UI/HitObjectContainer.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs index fde42bec04..9bfb6aa839 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Performance; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 9a0217a1eb..4cadfa9ad4 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Performance; using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.UI From 71e373ff511de83b10282992570165f087741551 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 16:11:25 +0900 Subject: [PATCH 048/104] Make results panels aware of whether they are a local score that has just been set --- osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs | 2 +- osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs | 2 +- .../Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs | 2 +- .../Ranking/Expanded/ExpandedPanelMiddleContent.cs | 8 ++++++-- osu.Game/Screens/Ranking/ResultsScreen.cs | 2 +- osu.Game/Screens/Ranking/ScorePanel.cs | 7 +++++-- osu.Game/Screens/Ranking/ScorePanelList.cs | 5 +++-- 7 files changed, 18 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs index 1e87893f39..f69ccc1773 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs @@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Ranking } } }, - new AccuracyCircle(score) + new AccuracyCircle(score, false) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs index 250fdc5ebd..5af55e99f8 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.Ranking private void addPanelStep(ScoreInfo score, PanelState state = PanelState.Expanded) => AddStep("add panel", () => { - Child = panel = new ScorePanel(score) + Child = panel = new ScorePanel(score, true) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 45da23f1f9..337665b51f 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -78,7 +78,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy private Container badges; private RankText rankText; - public AccuracyCircle(ScoreInfo score) + public AccuracyCircle(ScoreInfo score, bool withFlair) { this.score = score; } diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 30747438c3..5f8609d190 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -29,6 +29,8 @@ namespace osu.Game.Screens.Ranking.Expanded private const float padding = 10; private readonly ScoreInfo score; + private readonly bool withFlair; + private readonly List statisticDisplays = new List(); private FillFlowContainer starAndModDisplay; @@ -41,9 +43,11 @@ namespace osu.Game.Screens.Ranking.Expanded /// Creates a new . /// /// The score to display. - public ExpandedPanelMiddleContent(ScoreInfo score) + /// Whether to add flair for a new score being set. + public ExpandedPanelMiddleContent(ScoreInfo score, bool withFlair = false) { this.score = score; + this.withFlair = withFlair; RelativeSizeAxes = Axes.Both; Masking = true; @@ -116,7 +120,7 @@ namespace osu.Game.Screens.Ranking.Expanded Margin = new MarginPadding { Top = 40 }, RelativeSizeAxes = Axes.X, Height = 230, - Child = new AccuracyCircle(score) + Child = new AccuracyCircle(score, withFlair) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 026ce01857..f8bdf0140c 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -149,7 +149,7 @@ namespace osu.Game.Screens.Ranking }; if (Score != null) - ScorePanelList.AddScore(Score); + ScorePanelList.AddScore(Score, true); if (player != null && allowRetry) { diff --git a/osu.Game/Screens/Ranking/ScorePanel.cs b/osu.Game/Screens/Ranking/ScorePanel.cs index ee97ee55eb..6e6227da38 100644 --- a/osu.Game/Screens/Ranking/ScorePanel.cs +++ b/osu.Game/Screens/Ranking/ScorePanel.cs @@ -85,6 +85,8 @@ namespace osu.Game.Screens.Ranking public readonly ScoreInfo Score; + private readonly bool isNewLocalScore; + private Container content; private Container topLayerContainer; @@ -97,9 +99,10 @@ namespace osu.Game.Screens.Ranking private Container middleLayerContentContainer; private Drawable middleLayerContent; - public ScorePanel(ScoreInfo score) + public ScorePanel(ScoreInfo score, bool isNewLocalScore = false) { Score = score; + this.isNewLocalScore = isNewLocalScore; } [BackgroundDependencyLoader] @@ -209,7 +212,7 @@ namespace osu.Game.Screens.Ranking middleLayerBackground.FadeColour(expanded_middle_layer_colour, resize_duration, Easing.OutQuint); topLayerContentContainer.Add(topLayerContent = new ExpandedPanelTopContent(Score.User).With(d => d.Alpha = 0)); - middleLayerContentContainer.Add(middleLayerContent = new ExpandedPanelMiddleContent(Score).With(d => d.Alpha = 0)); + middleLayerContentContainer.Add(middleLayerContent = new ExpandedPanelMiddleContent(Score, isNewLocalScore).With(d => d.Alpha = 0)); break; case PanelState.Contracted: diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index 0d7d339df0..cc163ba762 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -95,9 +95,10 @@ namespace osu.Game.Screens.Ranking /// Adds a to this list. /// /// The to add. - public ScorePanel AddScore(ScoreInfo score) + /// Whether this is a score that has just been achieved locally. Controls whether flair is added to the display or not. + public ScorePanel AddScore(ScoreInfo score, bool isNewLocalScore = false) { - var panel = new ScorePanel(score) + var panel = new ScorePanel(score, isNewLocalScore) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, From 11f85779d5222f24fa9d0edd8097398417407b6a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 17:03:45 +0900 Subject: [PATCH 049/104] Fix panel expanded state being updated multiple times unnecessarily --- osu.Game/Screens/Ranking/ScorePanelList.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index cc163ba762..e85580a734 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -119,7 +119,10 @@ namespace osu.Game.Screens.Ranking })); if (SelectedScore.Value == score) - selectedScoreChanged(new ValueChangedEvent(SelectedScore.Value, SelectedScore.Value)); + { + if (IsLoaded) + SelectedScore.TriggerChange(); + } else { // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. @@ -143,11 +146,15 @@ namespace osu.Game.Screens.Ranking /// The to present. private void selectedScoreChanged(ValueChangedEvent score) { - // Contract the old panel. - foreach (var t in flow.Where(t => t.Panel.Score == score.OldValue)) + // avoid contracting panels unnecessarily when TriggerChange is fired manually. + if (score.OldValue != score.NewValue) { - t.Panel.State = PanelState.Contracted; - t.Margin = new MarginPadding(); + // Contract the old panel. + foreach (var t in flow.Where(t => t.Panel.Score == score.OldValue)) + { + t.Panel.State = PanelState.Contracted; + t.Margin = new MarginPadding(); + } } // Find the panel corresponding to the new score. From 0a0239a7c799b88049f4a4ca524a58d6f6839a2d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 17:04:33 +0900 Subject: [PATCH 050/104] Only play results panel animation once (and only for the local user) --- .../Ranking/Expanded/ExpandedPanelMiddleContent.cs | 3 +++ osu.Game/Screens/Ranking/ScorePanel.cs | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 5f8609d190..711763330c 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -270,6 +270,9 @@ namespace osu.Game.Screens.Ranking.Expanded delay += 200; } } + + if (!withFlair) + FinishTransforms(true); }); } } diff --git a/osu.Game/Screens/Ranking/ScorePanel.cs b/osu.Game/Screens/Ranking/ScorePanel.cs index 6e6227da38..df710e4eb8 100644 --- a/osu.Game/Screens/Ranking/ScorePanel.cs +++ b/osu.Game/Screens/Ranking/ScorePanel.cs @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Ranking public readonly ScoreInfo Score; - private readonly bool isNewLocalScore; + private bool displayWithFlair; private Container content; @@ -102,7 +102,7 @@ namespace osu.Game.Screens.Ranking public ScorePanel(ScoreInfo score, bool isNewLocalScore = false) { Score = score; - this.isNewLocalScore = isNewLocalScore; + displayWithFlair = isNewLocalScore; } [BackgroundDependencyLoader] @@ -191,7 +191,7 @@ namespace osu.Game.Screens.Ranking state = value; - if (LoadState >= LoadState.Ready) + if (IsLoaded) updateState(); StateChanged?.Invoke(value); @@ -212,7 +212,10 @@ namespace osu.Game.Screens.Ranking middleLayerBackground.FadeColour(expanded_middle_layer_colour, resize_duration, Easing.OutQuint); topLayerContentContainer.Add(topLayerContent = new ExpandedPanelTopContent(Score.User).With(d => d.Alpha = 0)); - middleLayerContentContainer.Add(middleLayerContent = new ExpandedPanelMiddleContent(Score, isNewLocalScore).With(d => d.Alpha = 0)); + middleLayerContentContainer.Add(middleLayerContent = new ExpandedPanelMiddleContent(Score, displayWithFlair).With(d => d.Alpha = 0)); + + // only the first expanded display should happen with flair. + displayWithFlair = false; break; case PanelState.Contracted: From 4dec46b33e977e8351f916a2c60c71a53a20b08a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 17:52:58 +0900 Subject: [PATCH 051/104] Attempt to fix in a less destructive way for now --- osu.Game/Tests/Visual/OsuTestScene.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 8886188d95..e32ed07863 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -230,7 +230,7 @@ namespace osu.Game.Tests.Visual if (beatmap.HitObjects.Count > 0) // add buffer after last hitobject to allow for final replay frames etc. - trackLength = beatmap.HitObjects.Max(h => h.GetEndTime()) + 2000; + trackLength = Math.Max(trackLength, beatmap.HitObjects.Max(h => h.GetEndTime()) + 2000); if (referenceClock != null) { From d69d78ab5d9278aaf31d20bd2895f664d1e3c2f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 15:20:10 +0900 Subject: [PATCH 052/104] Update namespace references --- osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs | 1 + osu.Game/Rulesets/UI/HitObjectContainer.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs index fde42bec04..9bfb6aa839 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Performance; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 9a0217a1eb..4cadfa9ad4 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Performance; using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.UI From 3491dea9e2aece3ab76f0b931a5c9ef599e6eba4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 18:51:54 +0900 Subject: [PATCH 053/104] Fix scroll logic running before children may be alive in flow --- osu.Game/Screens/Ranking/ScorePanelList.cs | 45 ++++++++++++---------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index e85580a734..4325d317c4 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -118,22 +118,24 @@ namespace osu.Game.Screens.Ranking d.Origin = Anchor.Centre; })); - if (SelectedScore.Value == score) + if (IsLoaded) { - if (IsLoaded) - SelectedScore.TriggerChange(); - } - else - { - // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. - // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. - if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) + if (SelectedScore.Value == score) { - // A somewhat hacky property is used here because we need to: - // 1) Scroll after the scroll container's visible range is updated. - // 2) Scroll before the scroll container's scroll position is updated. - // Without this, we would have a 1-frame positioning error which looks very jarring. - scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; + SelectedScore.TriggerChange(); + } + else + { + // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. + // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. + if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) + { + // A somewhat hacky property is used here because we need to: + // 1) Scroll after the scroll container's visible range is updated. + // 2) Scroll before the scroll container's scroll position is updated. + // Without this, we would have a 1-frame positioning error which looks very jarring. + scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; + } } } @@ -170,12 +172,15 @@ namespace osu.Game.Screens.Ranking expandedTrackingComponent.Margin = new MarginPadding { Horizontal = expanded_panel_spacing }; expandedPanel.State = PanelState.Expanded; - // Scroll to the new panel. This is done manually since we need: - // 1) To scroll after the scroll container's visible range is updated. - // 2) To account for the centre anchor/origins of panels. - // In the end, it's easier to compute the scroll position manually. - float scrollOffset = flow.GetPanelIndex(expandedPanel.Score) * (ScorePanel.CONTRACTED_WIDTH + panel_spacing); - scroll.ScrollTo(scrollOffset); + SchedulerAfterChildren.Add(() => + { + // Scroll to the new panel. This is done manually since we need: + // 1) To scroll after the scroll container's visible range is updated. + // 2) To account for the centre anchor/origins of panels. + // In the end, it's easier to compute the scroll position manually. + float scrollOffset = flow.GetPanelIndex(expandedPanel.Score) * (ScorePanel.CONTRACTED_WIDTH + panel_spacing); + scroll.ScrollTo(scrollOffset); + }); } protected override void Update() From 7be4dfabd8d384107b5a21a78ae6fa97f09fbeaa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 20:23:15 +0900 Subject: [PATCH 054/104] Revert "Update namespace references" This reverts commit d69d78ab5d9278aaf31d20bd2895f664d1e3c2f1. --- osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs | 1 - osu.Game/Rulesets/UI/HitObjectContainer.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs index 9bfb6aa839..fde42bec04 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Performance; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 4cadfa9ad4..9a0217a1eb 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Performance; using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.UI From 1c353b4745f1ea2bf2cb1a754d47478b7221c2b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Oct 2020 20:38:28 +0900 Subject: [PATCH 055/104] 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 27846fdf53..a4bcbd289d 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 609ac0e5f9..9be933c74a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index ebd38bc334..e26f8cc8b4 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -80,7 +80,7 @@ - + From 0c540537c9f3dde85e4ac74718be9d71a07c19b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 29 Oct 2020 14:30:50 +0100 Subject: [PATCH 056/104] Revert "Add BackgroundSource.Seasonal" This reverts commit 2871001cc294da01f2db8e8c35d84a86ab1503ac. --- osu.Game/Configuration/BackgroundSource.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Configuration/BackgroundSource.cs b/osu.Game/Configuration/BackgroundSource.cs index beef9ef1de..5726e96eb1 100644 --- a/osu.Game/Configuration/BackgroundSource.cs +++ b/osu.Game/Configuration/BackgroundSource.cs @@ -6,7 +6,6 @@ namespace osu.Game.Configuration public enum BackgroundSource { Skin, - Beatmap, - Seasonal + Beatmap } } From 7d523fee2896c71b7bb919cf99f41e88bb3ed2d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 29 Oct 2020 14:31:07 +0100 Subject: [PATCH 057/104] Revert "Set BackgroundSource.Seasonal as default setting" This reverts commit cdb2d23578e6de7ca266a23a51b5fac2ed15b8f4. --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 5c5af701bb..7d601c0cb9 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -130,7 +130,7 @@ namespace osu.Game.Configuration Set(OsuSetting.IntroSequence, IntroSequence.Triangles); - Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Seasonal); + Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin); } public OsuConfigManager(Storage storage) From b189e0b7cfd8e761b313ab3b1c27371ff270a056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 29 Oct 2020 16:01:22 +0100 Subject: [PATCH 058/104] Revert "Load SeasonalBackgroundLoader asynchronously" This reverts commit 81ebcd879668eb13cb28aa11bf4edfb8afb0fb99. --- .../Backgrounds/BackgroundScreenDefault.cs | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index ec91dcc99f..ef41c5be3d 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -25,7 +25,6 @@ namespace osu.Game.Screens.Backgrounds private Bindable skin; private Bindable mode; private Bindable introSequence; - private readonly SeasonalBackgroundLoader seasonalBackgroundLoader = new SeasonalBackgroundLoader(); [Resolved] private IBindable beatmap { get; set; } @@ -51,7 +50,7 @@ namespace osu.Game.Screens.Backgrounds currentDisplay = RNG.Next(0, background_count); - LoadComponentAsync(seasonalBackgroundLoader, _ => LoadComponentAsync(createBackground(), display)); + display(createBackground()); } private void display(Background newBackground) @@ -91,10 +90,6 @@ namespace osu.Game.Screens.Backgrounds { switch (mode.Value) { - case BackgroundSource.Seasonal: - newBackground = seasonalBackgroundLoader.LoadBackground(backgroundName); - break; - case BackgroundSource.Beatmap: newBackground = new BeatmapBackground(beatmap.Value, backgroundName); break; @@ -105,18 +100,7 @@ namespace osu.Game.Screens.Backgrounds } } else - { - switch (mode.Value) - { - case BackgroundSource.Seasonal: - newBackground = seasonalBackgroundLoader.LoadBackground(backgroundName); - break; - - default: - newBackground = new Background(backgroundName); - break; - } - } + newBackground = new Background(backgroundName); newBackground.Depth = currentDisplay; From 76c0a790b404ef1afd65e30078473126a8b677c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 29 Oct 2020 17:28:04 +0100 Subject: [PATCH 059/104] Add separate Seasonal Backgrounds setting (Always, Sometimes, Never) --- osu.Game/Configuration/OsuConfigManager.cs | 2 ++ osu.Game/Configuration/SeasonalBackgrounds.cs | 12 ++++++++++++ .../Settings/Sections/Audio/MainMenuSettings.cs | 6 ++++++ 3 files changed, 20 insertions(+) create mode 100644 osu.Game/Configuration/SeasonalBackgrounds.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 7d601c0cb9..9f7280eef4 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -131,6 +131,7 @@ namespace osu.Game.Configuration Set(OsuSetting.IntroSequence, IntroSequence.Triangles); Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin); + Set(OsuSetting.SeasonalBackgrounds, SeasonalBackgrounds.Sometimes); } public OsuConfigManager(Storage storage) @@ -239,5 +240,6 @@ namespace osu.Game.Configuration HitLighting, MenuBackgroundSource, GameplayDisableWinKey, + SeasonalBackgrounds } } diff --git a/osu.Game/Configuration/SeasonalBackgrounds.cs b/osu.Game/Configuration/SeasonalBackgrounds.cs new file mode 100644 index 0000000000..7708ae584f --- /dev/null +++ b/osu.Game/Configuration/SeasonalBackgrounds.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Configuration +{ + public enum SeasonalBackgrounds + { + Always, + Sometimes, + Never + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Audio/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/MainMenuSettings.cs index d5de32ed05..ee57c0cfa6 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/MainMenuSettings.cs @@ -39,6 +39,12 @@ namespace osu.Game.Overlays.Settings.Sections.Audio LabelText = "Background source", Current = config.GetBindable(OsuSetting.MenuBackgroundSource), Items = Enum.GetValues(typeof(BackgroundSource)).Cast() + }, + new SettingsDropdown + { + LabelText = "Seasonal backgrounds", + Current = config.GetBindable(OsuSetting.SeasonalBackgrounds), + Items = Enum.GetValues(typeof(SeasonalBackgrounds)).Cast() } }; } From 907e1921c720fc99cf9d76d135744fdf3d52fbeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 29 Oct 2020 17:31:42 +0100 Subject: [PATCH 060/104] Make SeasonalBackgroundLoader read from SessionStatics --- osu.Game/Configuration/SessionStatics.cs | 7 ++++++- .../Backgrounds/SeasonalBackgroundLoader.cs | 19 ++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 40b2adb867..326abed8fe 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -1,6 +1,9 @@ // 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.Online.API.Requests.Responses; + namespace osu.Game.Configuration { /// @@ -12,12 +15,14 @@ namespace osu.Game.Configuration { Set(Static.LoginOverlayDisplayed, false); Set(Static.MutedAudioNotificationShownOnce, false); + Set(Static.SeasonalBackgrounds, new List()); } } public enum Static { LoginOverlayDisplayed, - MutedAudioNotificationShownOnce + MutedAudioNotificationShownOnce, + SeasonalBackgrounds } } diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index af81b25cee..72785be3b4 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -5,9 +5,11 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; +using osu.Game.Configuration; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -17,17 +19,20 @@ namespace osu.Game.Graphics.Backgrounds [LongRunningLoad] public class SeasonalBackgroundLoader : Component { - private List backgrounds = new List(); + private Bindable> backgrounds; private int current; [BackgroundDependencyLoader] - private void load(IAPIProvider api) + private void load(SessionStatics sessionStatics, IAPIProvider api) { + backgrounds = sessionStatics.GetBindable>(Static.SeasonalBackgrounds); + if (backgrounds.Value.Any()) return; + var request = new GetSeasonalBackgroundsRequest(); request.Success += response => { - backgrounds = response.Backgrounds ?? backgrounds; - current = RNG.Next(0, backgrounds.Count); + backgrounds.Value = response.Backgrounds ?? backgrounds.Value; + current = RNG.Next(0, backgrounds.Value.Count); }; api.PerformAsync(request); @@ -37,10 +42,10 @@ namespace osu.Game.Graphics.Backgrounds { string url = null; - if (backgrounds.Any()) + if (backgrounds.Value.Any()) { - current = (current + 1) % backgrounds.Count; - url = backgrounds[current].Url; + current = (current + 1) % backgrounds.Value.Count; + url = backgrounds.Value[current].Url; } return new SeasonalBackground(url, fallbackTextureName); From bf4d99dfe7aa3ad5a4422430ae2079e4ef93d7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 29 Oct 2020 17:43:10 +0100 Subject: [PATCH 061/104] Load SeasonalBackgroundLoader asynchronously --- osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index ef41c5be3d..98552dda71 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.Backgrounds private Bindable skin; private Bindable mode; private Bindable introSequence; + private readonly SeasonalBackgroundLoader seasonalBackgroundLoader = new SeasonalBackgroundLoader(); [Resolved] private IBindable beatmap { get; set; } @@ -50,7 +51,7 @@ namespace osu.Game.Screens.Backgrounds currentDisplay = RNG.Next(0, background_count); - display(createBackground()); + LoadComponentAsync(seasonalBackgroundLoader, _ => LoadComponentAsync(createBackground(), display)); } private void display(Background newBackground) From 34371b8888980ec2de400b16924657449263ea1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 29 Oct 2020 17:44:23 +0100 Subject: [PATCH 062/104] Show next Background on showSeasonalBackgrounds.ValueChanged --- osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 98552dda71..1be19c5854 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.Backgrounds private Bindable skin; private Bindable mode; private Bindable introSequence; + private Bindable showSeasonalBackgrounds; private readonly SeasonalBackgroundLoader seasonalBackgroundLoader = new SeasonalBackgroundLoader(); [Resolved] @@ -42,12 +43,14 @@ namespace osu.Game.Screens.Backgrounds skin = skinManager.CurrentSkin.GetBoundCopy(); mode = config.GetBindable(OsuSetting.MenuBackgroundSource); introSequence = config.GetBindable(OsuSetting.IntroSequence); + showSeasonalBackgrounds = config.GetBindable(OsuSetting.SeasonalBackgrounds); user.ValueChanged += _ => Next(); skin.ValueChanged += _ => Next(); mode.ValueChanged += _ => Next(); beatmap.ValueChanged += _ => Next(); introSequence.ValueChanged += _ => Next(); + showSeasonalBackgrounds.ValueChanged += _ => Next(); currentDisplay = RNG.Next(0, background_count); From d9846fad37d4d2b9453621c2b225b9a3cf12cc8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 29 Oct 2020 18:03:36 +0100 Subject: [PATCH 063/104] Remove fallback texture parameter When there isn't a seasonal event, we don't want to fall back to the basic background here, but rather to the user selected background source. --- .../Backgrounds/SeasonalBackgroundLoader.cs | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index 72785be3b4..abd9664106 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -38,17 +37,14 @@ namespace osu.Game.Graphics.Backgrounds api.PerformAsync(request); } - public SeasonalBackground LoadBackground(string fallbackTextureName) + public SeasonalBackground LoadBackground() { - string url = null; + if (!backgrounds.Value.Any()) return null; - if (backgrounds.Value.Any()) - { - current = (current + 1) % backgrounds.Value.Count; - url = backgrounds.Value[current].Url; - } + current = (current + 1) % backgrounds.Value.Count; + string url = backgrounds.Value[current].Url; - return new SeasonalBackground(url, fallbackTextureName); + return new SeasonalBackground(url); } } @@ -56,18 +52,17 @@ namespace osu.Game.Graphics.Backgrounds public class SeasonalBackground : Background { private readonly string url; - private readonly string fallbackTextureName; + private const string fallback_texture_name = @"Backgrounds/bg1"; - public SeasonalBackground([CanBeNull] string url, string fallbackTextureName = @"Backgrounds/bg1") + public SeasonalBackground(string url) { this.url = url; - this.fallbackTextureName = fallbackTextureName; } [BackgroundDependencyLoader] private void load(LargeTextureStore textures) { - Sprite.Texture = textures.Get(url) ?? textures.Get(fallbackTextureName); + Sprite.Texture = textures.Get(url) ?? textures.Get(fallback_texture_name); } } } From fb1e09b3e793fae71caada4ad754d586ce7f5a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Thu, 29 Oct 2020 18:04:48 +0100 Subject: [PATCH 064/104] Load seasonal backgrounds according to setting --- .../Screens/Backgrounds/BackgroundScreenDefault.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 1be19c5854..70eafd4aff 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -106,6 +106,18 @@ namespace osu.Game.Screens.Backgrounds else newBackground = new Background(backgroundName); + switch (showSeasonalBackgrounds.Value) + { + case SeasonalBackgrounds.Sometimes: + if (RNG.NextBool()) + goto case SeasonalBackgrounds.Always; + break; + + case SeasonalBackgrounds.Always: + newBackground = seasonalBackgroundLoader.LoadBackground() ?? newBackground; + break; + } + newBackground.Depth = currentDisplay; return newBackground; From 0c1d12460fcc0304ce1889e21c684da5f107f59d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 10:30:11 +0900 Subject: [PATCH 065/104] Remove unused parameter --- osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs | 2 +- osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs | 2 +- osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs index f69ccc1773..1e87893f39 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs @@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Ranking } } }, - new AccuracyCircle(score, false) + new AccuracyCircle(score) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 337665b51f..45da23f1f9 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -78,7 +78,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy private Container badges; private RankText rankText; - public AccuracyCircle(ScoreInfo score, bool withFlair) + public AccuracyCircle(ScoreInfo score) { this.score = score; } diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 711763330c..cb4560802b 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -120,7 +120,7 @@ namespace osu.Game.Screens.Ranking.Expanded Margin = new MarginPadding { Top = 40 }, RelativeSizeAxes = Axes.X, Height = 230, - Child = new AccuracyCircle(score, withFlair) + Child = new AccuracyCircle(score) { Anchor = Anchor.Centre, Origin = Anchor.Centre, From 46d89d55f4e9b33edc97cb3696cf2a9ebcee7727 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 12:46:48 +0900 Subject: [PATCH 066/104] Add note about ScheduleAfterChildren requirement --- osu.Game/Screens/Ranking/ScorePanelList.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index 4325d317c4..77b3d8fc3b 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -172,7 +172,8 @@ namespace osu.Game.Screens.Ranking expandedTrackingComponent.Margin = new MarginPadding { Horizontal = expanded_panel_spacing }; expandedPanel.State = PanelState.Expanded; - SchedulerAfterChildren.Add(() => + // requires schedule after children to ensure the flow (and thus ScrollContainer's ScrollableExtent) has been updated. + ScheduleAfterChildren(() => { // Scroll to the new panel. This is done manually since we need: // 1) To scroll after the scroll container's visible range is updated. From 18f92818daed770f18d35fc74cc22c4da392e567 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 13:09:13 +0900 Subject: [PATCH 067/104] Show current HUD visibility mode as a tracked setting --- osu.Game/Configuration/OsuConfigManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 7d601c0cb9..46c5e61784 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -170,6 +170,7 @@ namespace osu.Game.Configuration public override TrackedSettings CreateTrackedSettings() => new TrackedSettings { new TrackedSetting(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled")), + new TrackedSetting(OsuSetting.HUDVisibilityMode, m => new SettingDescription(m, "HUD Visibility", m.GetDescription())), new TrackedSetting(OsuSetting.Scaling, m => new SettingDescription(m, "scaling", m.GetDescription())), }; } From 9bb86ccb832d8f838517c5d4ef7af8d018d2ed38 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 13:09:22 +0900 Subject: [PATCH 068/104] Change shift-tab to cycle available HUD visibility modes --- osu.Game/Screens/Play/HUDOverlay.cs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index b047d44f8a..623041d9ca 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -277,9 +277,25 @@ namespace osu.Game.Screens.Play switch (e.Key) { case Key.Tab: - configVisibilityMode.Value = configVisibilityMode.Value != HUDVisibilityMode.Never - ? HUDVisibilityMode.Never - : HUDVisibilityMode.HideDuringGameplay; + switch (configVisibilityMode.Value) + { + case HUDVisibilityMode.Never: + configVisibilityMode.Value = HUDVisibilityMode.HideDuringGameplay; + break; + + case HUDVisibilityMode.HideDuringGameplay: + configVisibilityMode.Value = HUDVisibilityMode.HideDuringBreaks; + break; + + case HUDVisibilityMode.HideDuringBreaks: + configVisibilityMode.Value = HUDVisibilityMode.Always; + break; + + case HUDVisibilityMode.Always: + configVisibilityMode.Value = HUDVisibilityMode.Never; + break; + } + return true; } } From c72017a7db4ad00ba2b63d976fca20c5ea9ac583 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 13:49:44 +0900 Subject: [PATCH 069/104] Remove "hide during breaks" option Probably wouldn't be used anyway. --- osu.Game/Configuration/HUDVisibilityMode.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Configuration/HUDVisibilityMode.cs b/osu.Game/Configuration/HUDVisibilityMode.cs index b0b55dd811..10f3f65355 100644 --- a/osu.Game/Configuration/HUDVisibilityMode.cs +++ b/osu.Game/Configuration/HUDVisibilityMode.cs @@ -12,9 +12,6 @@ namespace osu.Game.Configuration [Description("Hide during gameplay")] HideDuringGameplay, - [Description("Hide during breaks")] - HideDuringBreaks, - Always } } From b4eda65383cf80c56ac4991887836a12bb5a5be8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 13:53:51 +0900 Subject: [PATCH 070/104] Commit missing pieces --- osu.Game/Screens/Play/HUDOverlay.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 623041d9ca..0cfe6effc1 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -223,11 +223,6 @@ namespace osu.Game.Screens.Play ShowHud.Value = false; break; - case HUDVisibilityMode.HideDuringBreaks: - // always show during replay as we want the seek bar to be visible. - ShowHud.Value = replayLoaded.Value || !IsBreakTime.Value; - break; - case HUDVisibilityMode.HideDuringGameplay: // always show during replay as we want the seek bar to be visible. ShowHud.Value = replayLoaded.Value || IsBreakTime.Value; @@ -284,10 +279,6 @@ namespace osu.Game.Screens.Play break; case HUDVisibilityMode.HideDuringGameplay: - configVisibilityMode.Value = HUDVisibilityMode.HideDuringBreaks; - break; - - case HUDVisibilityMode.HideDuringBreaks: configVisibilityMode.Value = HUDVisibilityMode.Always; break; From 53bd31c69e6acada773346e350ffc12430ae651d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 14:00:07 +0900 Subject: [PATCH 071/104] Commit missing test pieces --- osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 6ec673704c..6764501569 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestExternalHideDoesntAffectConfig() { - HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringBreaks; + HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay; createNew(); From 8928aa6d92990ce761c205e80ac3c20b1a4feffe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 14:19:40 +0900 Subject: [PATCH 072/104] Add key binding to show HUD while held --- .../Input/Bindings/GlobalActionContainer.cs | 4 +++ osu.Game/Screens/Play/HUDOverlay.cs | 36 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 41be4cfcc3..3de4bb1f9d 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -67,6 +67,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Control, InputKey.Plus }, GlobalAction.IncreaseScrollSpeed), new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed), new KeyBinding(InputKey.MouseMiddle, GlobalAction.PauseGameplay), + new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), }; public IEnumerable AudioControlKeyBindings => new[] @@ -187,5 +188,8 @@ namespace osu.Game.Input.Bindings [Description("Timing Mode")] EditorTimingMode, + + [Description("Hold for HUD")] + HoldForHUD, } } diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index b047d44f8a..c38c2ee5f7 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -8,8 +8,10 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Configuration; +using osu.Game.Input.Bindings; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; @@ -22,7 +24,7 @@ using osuTK.Input; namespace osu.Game.Screens.Play { [Cached] - public class HUDOverlay : Container + public class HUDOverlay : Container, IKeyBindingHandler { public const float FADE_DURATION = 400; @@ -67,6 +69,8 @@ namespace osu.Game.Screens.Play internal readonly IBindable IsBreakTime = new Bindable(); + private bool holdingForHUD; + private IEnumerable hideTargets => new Drawable[] { visibilityContainer, KeyCounter }; public HUDOverlay(ScoreProcessor scoreProcessor, HealthProcessor healthProcessor, DrawableRuleset drawableRuleset, IReadOnlyList mods) @@ -217,6 +221,12 @@ namespace osu.Game.Screens.Play if (ShowHud.Disabled) return; + if (holdingForHUD) + { + ShowHud.Value = true; + return; + } + switch (configVisibilityMode.Value) { case HUDVisibilityMode.Never: @@ -351,5 +361,29 @@ namespace osu.Game.Screens.Play HealthDisplay?.BindHealthProcessor(processor); FailingLayer?.BindHealthProcessor(processor); } + + public bool OnPressed(GlobalAction action) + { + switch (action) + { + case GlobalAction.HoldForHUD: + holdingForHUD = true; + updateVisibility(); + return true; + } + + return false; + } + + public void OnReleased(GlobalAction action) + { + switch (action) + { + case GlobalAction.HoldForHUD: + holdingForHUD = false; + updateVisibility(); + break; + } + } } } From bd7871d9f511b09ddd224759e3b9365f043c27d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 14:20:00 +0900 Subject: [PATCH 073/104] Update test scene to be non-skinnable (and add test covering momentary display) --- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 6ec673704c..136c9e191d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -2,29 +2,23 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Configuration; -using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu; using osu.Game.Screens.Play; using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneHUDOverlay : SkinnableTestScene + public class TestSceneHUDOverlay : OsuManualInputManagerTestScene { private HUDOverlay hudOverlay; - private IEnumerable hudOverlays => CreatedDrawables.OfType(); - // best way to check without exposing. private Drawable hideTarget => hudOverlay.KeyCounter; private FillFlowContainer keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType>().First(); @@ -37,17 +31,9 @@ namespace osu.Game.Tests.Visual.Gameplay { createNew(); - AddRepeatStep("increase combo", () => - { - foreach (var hud in hudOverlays) - hud.ComboCounter.Current.Value++; - }, 10); + AddRepeatStep("increase combo", () => { hudOverlay.ComboCounter.Current.Value++; }, 10); - AddStep("reset combo", () => - { - foreach (var hud in hudOverlays) - hud.ComboCounter.Current.Value = 0; - }); + AddStep("reset combo", () => { hudOverlay.ComboCounter.Current.Value = 0; }); } [Test] @@ -77,7 +63,7 @@ namespace osu.Game.Tests.Visual.Gameplay { createNew(); - AddStep("set showhud false", () => hudOverlays.ForEach(h => h.ShowHud.Value = false)); + AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false); AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent); AddAssert("pause button is still visible", () => hudOverlay.HoldToQuit.IsPresent); @@ -86,6 +72,27 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("key counter flow not affected", () => keyCounterFlow.IsPresent); } + [Test] + public void TestMomentaryShowHUD() + { + createNew(); + + HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringBreaks; + AddStep("get original config value", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode)); + + AddStep("set hud to never show", () => config.Set(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); + + AddUntilStep("wait for fade", () => !hideTarget.IsPresent); + + AddStep("trigger momentary show", () => InputManager.PressKey(Key.ControlLeft)); + AddUntilStep("wait for visible", () => hideTarget.IsPresent); + + AddStep("stop trigering", () => InputManager.ReleaseKey(Key.ControlLeft)); + AddUntilStep("wait for fade", () => !hideTarget.IsPresent); + + AddStep("set original config value", () => config.Set(OsuSetting.HUDVisibilityMode, originalConfigValue)); + } + [Test] public void TestExternalHideDoesntAffectConfig() { @@ -113,14 +120,14 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("set keycounter visible false", () => { config.Set(OsuSetting.KeyOverlay, false); - hudOverlays.ForEach(h => h.KeyCounter.AlwaysVisible.Value = false); + hudOverlay.KeyCounter.AlwaysVisible.Value = false; }); - AddStep("set showhud false", () => hudOverlays.ForEach(h => h.ShowHud.Value = false)); + AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false); AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent); AddAssert("key counters hidden", () => !keyCounterFlow.IsPresent); - AddStep("set showhud true", () => hudOverlays.ForEach(h => h.ShowHud.Value = true)); + AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true); AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent); AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent); @@ -131,22 +138,17 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("create overlay", () => { - SetContents(() => - { - hudOverlay = new HUDOverlay(null, null, null, Array.Empty()); + hudOverlay = new HUDOverlay(null, null, null, Array.Empty()); - // Add any key just to display the key counter visually. - hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space)); + // Add any key just to display the key counter visually. + hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space)); - hudOverlay.ComboCounter.Current.Value = 1; + hudOverlay.ComboCounter.Current.Value = 1; - action?.Invoke(hudOverlay); + action?.Invoke(hudOverlay); - return hudOverlay; - }); + Child = hudOverlay; }); } - - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); } } From 984a243eff796505ee9f2ca6e85ae2a00233e3a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Oct 2020 14:23:24 +0900 Subject: [PATCH 074/104] Add skinnable test scene for HUD overlay --- .../Gameplay/TestSceneSkinnableHUDOverlay.cs | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs new file mode 100644 index 0000000000..fec1610160 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -0,0 +1,99 @@ +// 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.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Configuration; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Play; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSkinnableHUDOverlay : SkinnableTestScene + { + private HUDOverlay hudOverlay; + + private IEnumerable hudOverlays => CreatedDrawables.OfType(); + + // best way to check without exposing. + private Drawable hideTarget => hudOverlay.KeyCounter; + private FillFlowContainer keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType>().First(); + + [Resolved] + private OsuConfigManager config { get; set; } + + [Test] + public void TestComboCounterIncrementing() + { + createNew(); + + AddRepeatStep("increase combo", () => + { + foreach (var hud in hudOverlays) + hud.ComboCounter.Current.Value++; + }, 10); + + AddStep("reset combo", () => + { + foreach (var hud in hudOverlays) + hud.ComboCounter.Current.Value = 0; + }); + } + + [Test] + public void TestFadesInOnLoadComplete() + { + float? initialAlpha = null; + + createNew(h => h.OnLoadComplete += _ => initialAlpha = hideTarget.Alpha); + AddUntilStep("wait for load", () => hudOverlay.IsAlive); + AddAssert("initial alpha was less than 1", () => initialAlpha < 1); + } + + [Test] + public void TestHideExternally() + { + createNew(); + + AddStep("set showhud false", () => hudOverlays.ForEach(h => h.ShowHud.Value = false)); + + AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent); + AddAssert("pause button is still visible", () => hudOverlay.HoldToQuit.IsPresent); + + // Key counter flow container should not be affected by this, only the key counter display will be hidden as checked above. + AddAssert("key counter flow not affected", () => keyCounterFlow.IsPresent); + } + + private void createNew(Action action = null) + { + AddStep("create overlay", () => + { + SetContents(() => + { + hudOverlay = new HUDOverlay(null, null, null, Array.Empty()); + + // Add any key just to display the key counter visually. + hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space)); + + hudOverlay.ComboCounter.Current.Value = 1; + + action?.Invoke(hudOverlay); + + return hudOverlay; + }); + }); + } + + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + } +} From 43f9c1ebead2fb96e7f5994868ce43c93133d3ce Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Oct 2020 18:26:38 +0900 Subject: [PATCH 075/104] Fix HUD test having out of date value --- osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 9744575878..f9914e0193 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -77,7 +77,8 @@ namespace osu.Game.Tests.Visual.Gameplay { createNew(); - HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringBreaks; + HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay; + AddStep("get original config value", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode)); AddStep("set hud to never show", () => config.Set(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); From f27ce7521d69295e7af78478118e436db6f400ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 30 Oct 2020 10:27:43 +0100 Subject: [PATCH 076/104] Make "Sometimes" setting depend on season end date, rather than chance --- osu.Game/Configuration/SessionStatics.cs | 5 ++++- osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 8 ++++++++ .../API/Requests/Responses/APISeasonalBackgrounds.cs | 4 ++++ osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 2 +- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 326abed8fe..8100e0fb12 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.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; using System.Collections.Generic; using osu.Game.Online.API.Requests.Responses; @@ -15,6 +16,7 @@ namespace osu.Game.Configuration { Set(Static.LoginOverlayDisplayed, false); Set(Static.MutedAudioNotificationShownOnce, false); + Set(Static.SeasonEndDate, DateTimeOffset.MinValue); Set(Static.SeasonalBackgrounds, new List()); } } @@ -23,6 +25,7 @@ namespace osu.Game.Configuration { LoginOverlayDisplayed, MutedAudioNotificationShownOnce, - SeasonalBackgrounds + SeasonEndDate, + SeasonalBackgrounds, } } diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index abd9664106..d806c62650 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.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; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; @@ -18,19 +19,24 @@ namespace osu.Game.Graphics.Backgrounds [LongRunningLoad] public class SeasonalBackgroundLoader : Component { + private Bindable endDate; private Bindable> backgrounds; private int current; [BackgroundDependencyLoader] private void load(SessionStatics sessionStatics, IAPIProvider api) { + endDate = sessionStatics.GetBindable(Static.SeasonEndDate); backgrounds = sessionStatics.GetBindable>(Static.SeasonalBackgrounds); + if (backgrounds.Value.Any()) return; var request = new GetSeasonalBackgroundsRequest(); request.Success += response => { + endDate.Value = response.EndDate; backgrounds.Value = response.Backgrounds ?? backgrounds.Value; + current = RNG.Next(0, backgrounds.Value.Count); }; @@ -46,6 +52,8 @@ namespace osu.Game.Graphics.Backgrounds return new SeasonalBackground(url); } + + public bool IsInSeason() => DateTimeOffset.Now < endDate.Value; } [LongRunningLoad] diff --git a/osu.Game/Online/API/Requests/Responses/APISeasonalBackgrounds.cs b/osu.Game/Online/API/Requests/Responses/APISeasonalBackgrounds.cs index 6996ac4d9b..8e395f7397 100644 --- a/osu.Game/Online/API/Requests/Responses/APISeasonalBackgrounds.cs +++ b/osu.Game/Online/API/Requests/Responses/APISeasonalBackgrounds.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; using System.Collections.Generic; using Newtonsoft.Json; @@ -8,6 +9,9 @@ namespace osu.Game.Online.API.Requests.Responses { public class APISeasonalBackgrounds { + [JsonProperty("ends_at")] + public DateTimeOffset EndDate; + [JsonProperty("backgrounds")] public List Backgrounds { get; set; } } diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 70eafd4aff..de73c82d5c 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -109,7 +109,7 @@ namespace osu.Game.Screens.Backgrounds switch (showSeasonalBackgrounds.Value) { case SeasonalBackgrounds.Sometimes: - if (RNG.NextBool()) + if (seasonalBackgroundLoader.IsInSeason()) goto case SeasonalBackgrounds.Always; break; From a1fa6588f6a933c97551f78b98e21734f06e0c10 Mon Sep 17 00:00:00 2001 From: cadon0 Date: Sat, 31 Oct 2020 01:03:57 +1300 Subject: [PATCH 077/104] Fix "bounce" when metadata container text is empty --- osu.Game/Screens/Select/BeatmapDetails.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 0ee52f3e48..71f78c5c95 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -300,6 +300,7 @@ namespace osu.Game.Screens.Select public MetadataSection(string title) { + Alpha = 0; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; From 4e3fb615d25c6a2edfbec009401ec73f925840f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 30 Oct 2020 15:54:10 +0100 Subject: [PATCH 078/104] Rename "SeasonalBackgrounds" to "SeasonalBackgroundMode" --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- ...nalBackgrounds.cs => SeasonalBackgroundMode.cs} | 2 +- .../Settings/Sections/Audio/MainMenuSettings.cs | 6 +++--- .../Screens/Backgrounds/BackgroundScreenDefault.cs | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) rename osu.Game/Configuration/{SeasonalBackgrounds.cs => SeasonalBackgroundMode.cs} (86%) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index e579898c05..e0971d238a 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -131,7 +131,7 @@ namespace osu.Game.Configuration Set(OsuSetting.IntroSequence, IntroSequence.Triangles); Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin); - Set(OsuSetting.SeasonalBackgrounds, SeasonalBackgrounds.Sometimes); + Set(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Sometimes); } public OsuConfigManager(Storage storage) @@ -241,6 +241,6 @@ namespace osu.Game.Configuration HitLighting, MenuBackgroundSource, GameplayDisableWinKey, - SeasonalBackgrounds + SeasonalBackgroundMode } } diff --git a/osu.Game/Configuration/SeasonalBackgrounds.cs b/osu.Game/Configuration/SeasonalBackgroundMode.cs similarity index 86% rename from osu.Game/Configuration/SeasonalBackgrounds.cs rename to osu.Game/Configuration/SeasonalBackgroundMode.cs index 7708ae584f..406736b2a4 100644 --- a/osu.Game/Configuration/SeasonalBackgrounds.cs +++ b/osu.Game/Configuration/SeasonalBackgroundMode.cs @@ -3,7 +3,7 @@ namespace osu.Game.Configuration { - public enum SeasonalBackgrounds + public enum SeasonalBackgroundMode { Always, Sometimes, diff --git a/osu.Game/Overlays/Settings/Sections/Audio/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/MainMenuSettings.cs index ee57c0cfa6..7682967d10 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/MainMenuSettings.cs @@ -40,11 +40,11 @@ namespace osu.Game.Overlays.Settings.Sections.Audio Current = config.GetBindable(OsuSetting.MenuBackgroundSource), Items = Enum.GetValues(typeof(BackgroundSource)).Cast() }, - new SettingsDropdown + new SettingsDropdown { LabelText = "Seasonal backgrounds", - Current = config.GetBindable(OsuSetting.SeasonalBackgrounds), - Items = Enum.GetValues(typeof(SeasonalBackgrounds)).Cast() + Current = config.GetBindable(OsuSetting.SeasonalBackgroundMode), + Items = Enum.GetValues(typeof(SeasonalBackgroundMode)).Cast() } }; } diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index de73c82d5c..a5bdcee8d4 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Backgrounds private Bindable skin; private Bindable mode; private Bindable introSequence; - private Bindable showSeasonalBackgrounds; + private Bindable seasonalBackgroundMode; private readonly SeasonalBackgroundLoader seasonalBackgroundLoader = new SeasonalBackgroundLoader(); [Resolved] @@ -43,14 +43,14 @@ namespace osu.Game.Screens.Backgrounds skin = skinManager.CurrentSkin.GetBoundCopy(); mode = config.GetBindable(OsuSetting.MenuBackgroundSource); introSequence = config.GetBindable(OsuSetting.IntroSequence); - showSeasonalBackgrounds = config.GetBindable(OsuSetting.SeasonalBackgrounds); + seasonalBackgroundMode = config.GetBindable(OsuSetting.SeasonalBackgroundMode); user.ValueChanged += _ => Next(); skin.ValueChanged += _ => Next(); mode.ValueChanged += _ => Next(); beatmap.ValueChanged += _ => Next(); introSequence.ValueChanged += _ => Next(); - showSeasonalBackgrounds.ValueChanged += _ => Next(); + seasonalBackgroundMode.ValueChanged += _ => Next(); currentDisplay = RNG.Next(0, background_count); @@ -106,14 +106,14 @@ namespace osu.Game.Screens.Backgrounds else newBackground = new Background(backgroundName); - switch (showSeasonalBackgrounds.Value) + switch (seasonalBackgroundMode.Value) { - case SeasonalBackgrounds.Sometimes: + case SeasonalBackgroundMode.Sometimes: if (seasonalBackgroundLoader.IsInSeason()) - goto case SeasonalBackgrounds.Always; + goto case SeasonalBackgroundMode.Always; break; - case SeasonalBackgrounds.Always: + case SeasonalBackgroundMode.Always: newBackground = seasonalBackgroundLoader.LoadBackground() ?? newBackground; break; } From d19dd4eef6ba621616f684b5b07d41d154d68f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 30 Oct 2020 15:56:19 +0100 Subject: [PATCH 079/104] IsInSeason() -> IsInSeason --- osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 2 +- osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index d806c62650..ff1a2c9f37 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -53,7 +53,7 @@ namespace osu.Game.Graphics.Backgrounds return new SeasonalBackground(url); } - public bool IsInSeason() => DateTimeOffset.Now < endDate.Value; + public bool IsInSeason => DateTimeOffset.Now < endDate.Value; } [LongRunningLoad] diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index a5bdcee8d4..5fa4ddc041 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -109,7 +109,7 @@ namespace osu.Game.Screens.Backgrounds switch (seasonalBackgroundMode.Value) { case SeasonalBackgroundMode.Sometimes: - if (seasonalBackgroundLoader.IsInSeason()) + if (seasonalBackgroundLoader.IsInSeason) goto case SeasonalBackgroundMode.Always; break; From 6f6a8e2a8fe09581630728d0e347b48e91c3f80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 30 Oct 2020 16:06:48 +0100 Subject: [PATCH 080/104] Convert switch to if --- .../Screens/Backgrounds/BackgroundScreenDefault.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 5fa4ddc041..39ecd70084 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -106,16 +106,10 @@ namespace osu.Game.Screens.Backgrounds else newBackground = new Background(backgroundName); - switch (seasonalBackgroundMode.Value) + if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Always + || seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && seasonalBackgroundLoader.IsInSeason) { - case SeasonalBackgroundMode.Sometimes: - if (seasonalBackgroundLoader.IsInSeason) - goto case SeasonalBackgroundMode.Always; - break; - - case SeasonalBackgroundMode.Always: - newBackground = seasonalBackgroundLoader.LoadBackground() ?? newBackground; - break; + newBackground = seasonalBackgroundLoader.LoadBackground() ?? newBackground; } newBackground.Depth = currentDisplay; From f6eb5680ec53626707452cf08c0926713fbf2ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 30 Oct 2020 16:43:18 +0100 Subject: [PATCH 081/104] Save full api response in SessionStatics --- osu.Game/Configuration/SessionStatics.cs | 8 ++----- .../Backgrounds/SeasonalBackgroundLoader.cs | 24 ++++++++----------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 8100e0fb12..199889391b 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Configuration @@ -16,8 +14,7 @@ namespace osu.Game.Configuration { Set(Static.LoginOverlayDisplayed, false); Set(Static.MutedAudioNotificationShownOnce, false); - Set(Static.SeasonEndDate, DateTimeOffset.MinValue); - Set(Static.SeasonalBackgrounds, new List()); + Set(Static.SeasonalBackgroundsResponse, null); } } @@ -25,7 +22,6 @@ namespace osu.Game.Configuration { LoginOverlayDisplayed, MutedAudioNotificationShownOnce, - SeasonEndDate, - SeasonalBackgrounds, + SeasonalBackgroundsResponse, } } diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index ff1a2c9f37..c884756c80 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -19,25 +18,21 @@ namespace osu.Game.Graphics.Backgrounds [LongRunningLoad] public class SeasonalBackgroundLoader : Component { - private Bindable endDate; - private Bindable> backgrounds; + private Bindable cachedResponse; private int current; [BackgroundDependencyLoader] private void load(SessionStatics sessionStatics, IAPIProvider api) { - endDate = sessionStatics.GetBindable(Static.SeasonEndDate); - backgrounds = sessionStatics.GetBindable>(Static.SeasonalBackgrounds); + cachedResponse = sessionStatics.GetBindable(Static.SeasonalBackgroundsResponse); - if (backgrounds.Value.Any()) return; + if (cachedResponse.Value != null) return; var request = new GetSeasonalBackgroundsRequest(); request.Success += response => { - endDate.Value = response.EndDate; - backgrounds.Value = response.Backgrounds ?? backgrounds.Value; - - current = RNG.Next(0, backgrounds.Value.Count); + cachedResponse.Value = response; + current = RNG.Next(0, cachedResponse.Value.Backgrounds.Count); }; api.PerformAsync(request); @@ -45,15 +40,16 @@ namespace osu.Game.Graphics.Backgrounds public SeasonalBackground LoadBackground() { - if (!backgrounds.Value.Any()) return null; + var backgrounds = cachedResponse.Value.Backgrounds; + if (!backgrounds.Any()) return null; - current = (current + 1) % backgrounds.Value.Count; - string url = backgrounds.Value[current].Url; + current = (current + 1) % backgrounds.Count; + string url = backgrounds[current].Url; return new SeasonalBackground(url); } - public bool IsInSeason => DateTimeOffset.Now < endDate.Value; + public bool IsInSeason => DateTimeOffset.Now < cachedResponse.Value.EndDate; } [LongRunningLoad] From 0b46c19b23995f42e35b82877b41404200f109ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 30 Oct 2020 17:16:51 +0100 Subject: [PATCH 082/104] Move seasonalBackgroundMode check up and early return if available --- .../Backgrounds/BackgroundScreenDefault.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 39ecd70084..b65b45060f 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -79,6 +79,18 @@ namespace osu.Game.Screens.Backgrounds Background newBackground; string backgroundName; + if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Always + || seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && seasonalBackgroundLoader.IsInSeason) + { + var seasonalBackground = seasonalBackgroundLoader.LoadBackground(); + + if (seasonalBackground != null) + { + seasonalBackground.Depth = currentDisplay; + return seasonalBackground; + } + } + switch (introSequence.Value) { case IntroSequence.Welcome: @@ -106,12 +118,6 @@ namespace osu.Game.Screens.Backgrounds else newBackground = new Background(backgroundName); - if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Always - || seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && seasonalBackgroundLoader.IsInSeason) - { - newBackground = seasonalBackgroundLoader.LoadBackground() ?? newBackground; - } - newBackground.Depth = currentDisplay; return newBackground; From 51a58269add518f7ea68f590fceeff11612cc5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 30 Oct 2020 17:57:29 +0100 Subject: [PATCH 083/104] Fix nullref in case of successfull request but no backgrounds available --- osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index c884756c80..daceb05fd7 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -32,7 +32,7 @@ namespace osu.Game.Graphics.Backgrounds request.Success += response => { cachedResponse.Value = response; - current = RNG.Next(0, cachedResponse.Value.Backgrounds.Count); + current = RNG.Next(0, response.Backgrounds?.Count ?? 0); }; api.PerformAsync(request); @@ -41,7 +41,7 @@ namespace osu.Game.Graphics.Backgrounds public SeasonalBackground LoadBackground() { var backgrounds = cachedResponse.Value.Backgrounds; - if (!backgrounds.Any()) return null; + if (backgrounds == null || !backgrounds.Any()) return null; current = (current + 1) % backgrounds.Count; string url = backgrounds[current].Url; From d5dfd1dffeee753cb47d70afc87a1b3055e1962e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20H=C3=BCbner?= Date: Fri, 30 Oct 2020 18:07:07 +0100 Subject: [PATCH 084/104] Insert optional parentheses --- osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index b65b45060f..45374e1223 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -80,7 +80,7 @@ namespace osu.Game.Screens.Backgrounds string backgroundName; if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Always - || seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && seasonalBackgroundLoader.IsInSeason) + || (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && seasonalBackgroundLoader.IsInSeason)) { var seasonalBackground = seasonalBackgroundLoader.LoadBackground(); From 82ef85569bffe30e64a00414ddb8465348d645d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 19:35:08 +0100 Subject: [PATCH 085/104] Fix nullref when querying IsInSeason before request completion --- osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index daceb05fd7..2963d57a97 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -49,7 +49,7 @@ namespace osu.Game.Graphics.Backgrounds return new SeasonalBackground(url); } - public bool IsInSeason => DateTimeOffset.Now < cachedResponse.Value.EndDate; + public bool IsInSeason => cachedResponse.Value != null && DateTimeOffset.Now < cachedResponse.Value.EndDate; } [LongRunningLoad] From 20c27c69431eb680781338c4e0deba1f2a1658ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 19:55:17 +0100 Subject: [PATCH 086/104] Rename lookup & field --- osu.Game/Configuration/SessionStatics.cs | 4 ++-- .../Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 199889391b..c470058ae8 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -14,7 +14,7 @@ namespace osu.Game.Configuration { Set(Static.LoginOverlayDisplayed, false); Set(Static.MutedAudioNotificationShownOnce, false); - Set(Static.SeasonalBackgroundsResponse, null); + Set(Static.SeasonalBackgrounds, null); } } @@ -22,6 +22,6 @@ namespace osu.Game.Configuration { LoginOverlayDisplayed, MutedAudioNotificationShownOnce, - SeasonalBackgroundsResponse, + SeasonalBackgrounds, } } diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index 2963d57a97..1c38e67451 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -18,20 +18,20 @@ namespace osu.Game.Graphics.Backgrounds [LongRunningLoad] public class SeasonalBackgroundLoader : Component { - private Bindable cachedResponse; + private Bindable seasonalBackgrounds; private int current; [BackgroundDependencyLoader] private void load(SessionStatics sessionStatics, IAPIProvider api) { - cachedResponse = sessionStatics.GetBindable(Static.SeasonalBackgroundsResponse); + seasonalBackgrounds = sessionStatics.GetBindable(Static.SeasonalBackgrounds); - if (cachedResponse.Value != null) return; + if (seasonalBackgrounds.Value != null) return; var request = new GetSeasonalBackgroundsRequest(); request.Success += response => { - cachedResponse.Value = response; + seasonalBackgrounds.Value = response; current = RNG.Next(0, response.Backgrounds?.Count ?? 0); }; @@ -40,7 +40,7 @@ namespace osu.Game.Graphics.Backgrounds public SeasonalBackground LoadBackground() { - var backgrounds = cachedResponse.Value.Backgrounds; + var backgrounds = seasonalBackgrounds.Value.Backgrounds; if (backgrounds == null || !backgrounds.Any()) return null; current = (current + 1) % backgrounds.Count; @@ -49,7 +49,7 @@ namespace osu.Game.Graphics.Backgrounds return new SeasonalBackground(url); } - public bool IsInSeason => cachedResponse.Value != null && DateTimeOffset.Now < cachedResponse.Value.EndDate; + public bool IsInSeason => seasonalBackgrounds.Value != null && DateTimeOffset.Now < seasonalBackgrounds.Value.EndDate; } [LongRunningLoad] From aeab2be5d1968c7a1a6a712afc2897033891bb6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 19:56:52 +0100 Subject: [PATCH 087/104] Add xmldoc to SeasonalBackgroundMode --- osu.Game/Configuration/SeasonalBackgroundMode.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Configuration/SeasonalBackgroundMode.cs b/osu.Game/Configuration/SeasonalBackgroundMode.cs index 406736b2a4..6ef835ce5f 100644 --- a/osu.Game/Configuration/SeasonalBackgroundMode.cs +++ b/osu.Game/Configuration/SeasonalBackgroundMode.cs @@ -5,8 +5,19 @@ namespace osu.Game.Configuration { public enum SeasonalBackgroundMode { + /// + /// Seasonal backgrounds are shown regardless of season, if at all available. + /// Always, + + /// + /// Seasonal backgrounds are shown only during their corresponding season. + /// Sometimes, + + /// + /// Seasonal backgrounds are never shown. + /// Never } } From cf0e8e0a620faaa77ba490ab3e71b9901eabd658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 19:59:52 +0100 Subject: [PATCH 088/104] Document nullability of seasonal backgrounds --- osu.Game/Configuration/SessionStatics.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index c470058ae8..03bc434aac 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -22,6 +22,11 @@ namespace osu.Game.Configuration { LoginOverlayDisplayed, MutedAudioNotificationShownOnce, + + /// + /// Info about seasonal backgrounds available fetched from API - see . + /// Value under this lookup can be null if there are no backgrounds available (or API is not reachable). + /// SeasonalBackgrounds, } } From 67a325f47dd608f625711a4e38b8968ee514716e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 20:32:14 +0100 Subject: [PATCH 089/104] Move config setting logic to background loader --- .../Backgrounds/SeasonalBackgroundLoader.cs | 17 +++++++++++++---- .../Backgrounds/BackgroundScreenDefault.cs | 14 +++++--------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index 1c38e67451..a9b9929c79 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -18,12 +18,14 @@ namespace osu.Game.Graphics.Backgrounds [LongRunningLoad] public class SeasonalBackgroundLoader : Component { + private Bindable seasonalBackgroundMode; private Bindable seasonalBackgrounds; private int current; [BackgroundDependencyLoader] - private void load(SessionStatics sessionStatics, IAPIProvider api) + private void load(OsuConfigManager config, SessionStatics sessionStatics, IAPIProvider api) { + seasonalBackgroundMode = config.GetBindable(OsuSetting.SeasonalBackgroundMode); seasonalBackgrounds = sessionStatics.GetBindable(Static.SeasonalBackgrounds); if (seasonalBackgrounds.Value != null) return; @@ -38,10 +40,17 @@ namespace osu.Game.Graphics.Backgrounds api.PerformAsync(request); } - public SeasonalBackground LoadBackground() + public SeasonalBackground LoadNextBackground() { + if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Never + || (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && !isInSeason)) + { + return null; + } + var backgrounds = seasonalBackgrounds.Value.Backgrounds; - if (backgrounds == null || !backgrounds.Any()) return null; + if (backgrounds == null || !backgrounds.Any()) + return null; current = (current + 1) % backgrounds.Count; string url = backgrounds[current].Url; @@ -49,7 +58,7 @@ namespace osu.Game.Graphics.Backgrounds return new SeasonalBackground(url); } - public bool IsInSeason => seasonalBackgrounds.Value != null && DateTimeOffset.Now < seasonalBackgrounds.Value.EndDate; + private bool isInSeason => seasonalBackgrounds.Value != null && DateTimeOffset.Now < seasonalBackgrounds.Value.EndDate; } [LongRunningLoad] diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 45374e1223..cbe0841537 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -79,16 +79,12 @@ namespace osu.Game.Screens.Backgrounds Background newBackground; string backgroundName; - if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Always - || (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && seasonalBackgroundLoader.IsInSeason)) - { - var seasonalBackground = seasonalBackgroundLoader.LoadBackground(); + var seasonalBackground = seasonalBackgroundLoader.LoadNextBackground(); - if (seasonalBackground != null) - { - seasonalBackground.Depth = currentDisplay; - return seasonalBackground; - } + if (seasonalBackground != null) + { + seasonalBackground.Depth = currentDisplay; + return seasonalBackground; } switch (introSequence.Value) From 8632f0d77f18b6fb65aee838bced622aba6bdc84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 21:24:20 +0100 Subject: [PATCH 090/104] Add test coverage --- .../TestSceneSeasonalBackgroundLoader.cs | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs diff --git a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs new file mode 100644 index 0000000000..8f5990aeb1 --- /dev/null +++ b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs @@ -0,0 +1,200 @@ +// 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.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Textures; +using osu.Game.Configuration; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Tests.Visual.Background +{ + public class TestSceneSeasonalBackgroundLoader : ScreenTestScene + { + [Resolved] + private OsuConfigManager config { get; set; } + + [Resolved] + private SessionStatics statics { get; set; } + + [Cached(typeof(LargeTextureStore))] + private LookupLoggingTextureStore textureStore = new LookupLoggingTextureStore(); + + private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; + + private SeasonalBackgroundLoader backgroundLoader; + private Container backgroundContainer; + + // in real usages these would be online URLs, but correct execution of this test + // shouldn't be coupled to existence of online assets. + private static readonly List seasonal_background_urls = new List + { + "Backgrounds/bg2", + "Backgrounds/bg4", + "Backgrounds/bg3" + }; + + [BackgroundDependencyLoader] + private void load(LargeTextureStore wrappedStore) + { + textureStore.AddStore(wrappedStore); + + Add(backgroundContainer = new Container + { + RelativeSizeAxes = Axes.Both + }); + } + + [SetUp] + public void SetUp() => Schedule(() => + { + // reset API response in statics to avoid test crosstalk. + statics.Set(Static.SeasonalBackgrounds, null); + textureStore.PerformedLookups.Clear(); + dummyAPI.SetState(APIState.Online); + + backgroundContainer.Clear(); + }); + + [TestCase(-5)] + [TestCase(5)] + public void TestAlwaysSeasonal(int daysOffset) + { + registerBackgroundsResponse(DateTimeOffset.Now.AddDays(daysOffset)); + setSeasonalBackgroundMode(SeasonalBackgroundMode.Always); + + createLoader(); + + for (int i = 0; i < 4; ++i) + loadNextBackground(); + + AddAssert("all backgrounds cycled", () => new HashSet(textureStore.PerformedLookups).SetEquals(seasonal_background_urls)); + } + + [TestCase(-5)] + [TestCase(5)] + public void TestNeverSeasonal(int daysOffset) + { + registerBackgroundsResponse(DateTimeOffset.Now.AddDays(daysOffset)); + setSeasonalBackgroundMode(SeasonalBackgroundMode.Never); + + createLoader(); + + assertNoBackgrounds(); + } + + [Test] + public void TestSometimesInSeason() + { + registerBackgroundsResponse(DateTimeOffset.Now.AddDays(5)); + setSeasonalBackgroundMode(SeasonalBackgroundMode.Sometimes); + + createLoader(); + + assertAnyBackground(); + } + + [Test] + public void TestSometimesOutOfSeason() + { + registerBackgroundsResponse(DateTimeOffset.Now.AddDays(-10)); + setSeasonalBackgroundMode(SeasonalBackgroundMode.Sometimes); + + createLoader(); + + assertNoBackgrounds(); + } + + [Test] + public void TestDelayedConnectivity() + { + registerBackgroundsResponse(DateTimeOffset.Now.AddDays(30)); + setSeasonalBackgroundMode(SeasonalBackgroundMode.Always); + AddStep("go offline", () => dummyAPI.SetState(APIState.Offline)); + + createLoader(); + assertNoBackgrounds(); + + AddStep("go online", () => dummyAPI.SetState(APIState.Online)); + + assertAnyBackground(); + } + + private void registerBackgroundsResponse(DateTimeOffset endDate) + => AddStep("setup request handler", () => + { + dummyAPI.HandleRequest = request => + { + if (dummyAPI.State.Value != APIState.Online || !(request is GetSeasonalBackgroundsRequest backgroundsRequest)) + return; + + backgroundsRequest.TriggerSuccess(new APISeasonalBackgrounds + { + Backgrounds = seasonal_background_urls.Select(url => new APISeasonalBackground { Url = url }).ToList(), + EndDate = endDate + }); + }; + }); + + private void setSeasonalBackgroundMode(SeasonalBackgroundMode mode) + => AddStep($"set seasonal mode to {mode}", () => config.Set(OsuSetting.SeasonalBackgroundMode, mode)); + + private void createLoader() + { + AddStep("create loader", () => + { + if (backgroundLoader != null) + Remove(backgroundLoader); + + LoadComponentAsync(backgroundLoader = new SeasonalBackgroundLoader(), Add); + }); + + AddUntilStep("wait for loaded", () => backgroundLoader.IsLoaded); + } + + private void loadNextBackground() + { + SeasonalBackground background = null; + + AddStep("create next background", () => + { + background = backgroundLoader.LoadNextBackground(); + LoadComponentAsync(background, bg => backgroundContainer.Child = bg); + }); + + AddUntilStep("background loaded", () => background.IsLoaded); + } + + private void assertAnyBackground() + { + loadNextBackground(); + AddAssert("background looked up", () => textureStore.PerformedLookups.Any()); + } + + private void assertNoBackgrounds() + { + AddAssert("no background available", () => backgroundLoader.LoadNextBackground() == null); + AddAssert("no lookups performed", () => !textureStore.PerformedLookups.Any()); + } + + private class LookupLoggingTextureStore : LargeTextureStore + { + public List PerformedLookups { get; } = new List(); + + public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT) + { + PerformedLookups.Add(name); + return base.Get(name, wrapModeS, wrapModeT); + } + } + } +} From 29ad09990259245b8b828a49add4411a90d5f88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 21:49:14 +0100 Subject: [PATCH 091/104] Allow to fetch if going online after launch --- .../Backgrounds/SeasonalBackgroundLoader.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index a9b9929c79..ff290dd99e 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -18,17 +18,29 @@ namespace osu.Game.Graphics.Backgrounds [LongRunningLoad] public class SeasonalBackgroundLoader : Component { + [Resolved] + private IAPIProvider api { get; set; } + + private readonly IBindable apiState = new Bindable(); private Bindable seasonalBackgroundMode; private Bindable seasonalBackgrounds; + private int current; [BackgroundDependencyLoader] - private void load(OsuConfigManager config, SessionStatics sessionStatics, IAPIProvider api) + private void load(OsuConfigManager config, SessionStatics sessionStatics) { seasonalBackgroundMode = config.GetBindable(OsuSetting.SeasonalBackgroundMode); seasonalBackgrounds = sessionStatics.GetBindable(Static.SeasonalBackgrounds); - if (seasonalBackgrounds.Value != null) return; + apiState.BindTo(api.State); + apiState.BindValueChanged(fetchSeasonalBackgrounds, true); + } + + private void fetchSeasonalBackgrounds(ValueChangedEvent stateChanged) + { + if (seasonalBackgrounds.Value != null || stateChanged.NewValue != APIState.Online) + return; var request = new GetSeasonalBackgroundsRequest(); request.Success += response => @@ -48,7 +60,7 @@ namespace osu.Game.Graphics.Backgrounds return null; } - var backgrounds = seasonalBackgrounds.Value.Backgrounds; + var backgrounds = seasonalBackgrounds.Value?.Backgrounds; if (backgrounds == null || !backgrounds.Any()) return null; From 38cf90a69b8734343b68fce3646b618f4d3ad6a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 22:03:26 +0100 Subject: [PATCH 092/104] Change background to seasonal right after login --- .../Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 9 +++++++++ osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 4 +--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index ff290dd99e..b439d98083 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -18,6 +18,12 @@ namespace osu.Game.Graphics.Backgrounds [LongRunningLoad] public class SeasonalBackgroundLoader : Component { + /// + /// Fired when background change should be changed due to receiving backgrounds from API + /// or when the user setting is changed (as it might require unloading the seasonal background). + /// + public event Action SeasonalBackgroundChanged; + [Resolved] private IAPIProvider api { get; set; } @@ -31,7 +37,10 @@ namespace osu.Game.Graphics.Backgrounds private void load(OsuConfigManager config, SessionStatics sessionStatics) { seasonalBackgroundMode = config.GetBindable(OsuSetting.SeasonalBackgroundMode); + seasonalBackgroundMode.BindValueChanged(_ => SeasonalBackgroundChanged?.Invoke()); + seasonalBackgrounds = sessionStatics.GetBindable(Static.SeasonalBackgrounds); + seasonalBackgrounds.BindValueChanged(_ => SeasonalBackgroundChanged?.Invoke()); apiState.BindTo(api.State); apiState.BindValueChanged(fetchSeasonalBackgrounds, true); diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index cbe0841537..f392386bf9 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -25,7 +25,6 @@ namespace osu.Game.Screens.Backgrounds private Bindable skin; private Bindable mode; private Bindable introSequence; - private Bindable seasonalBackgroundMode; private readonly SeasonalBackgroundLoader seasonalBackgroundLoader = new SeasonalBackgroundLoader(); [Resolved] @@ -43,14 +42,13 @@ namespace osu.Game.Screens.Backgrounds skin = skinManager.CurrentSkin.GetBoundCopy(); mode = config.GetBindable(OsuSetting.MenuBackgroundSource); introSequence = config.GetBindable(OsuSetting.IntroSequence); - seasonalBackgroundMode = config.GetBindable(OsuSetting.SeasonalBackgroundMode); user.ValueChanged += _ => Next(); skin.ValueChanged += _ => Next(); mode.ValueChanged += _ => Next(); beatmap.ValueChanged += _ => Next(); introSequence.ValueChanged += _ => Next(); - seasonalBackgroundMode.ValueChanged += _ => Next(); + seasonalBackgroundLoader.SeasonalBackgroundChanged += Next; currentDisplay = RNG.Next(0, background_count); From 391dd73843b52fcf559b6b23eb56171c89e7c37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 22:39:34 +0100 Subject: [PATCH 093/104] Fix typo in comment --- osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index b439d98083..03b7300011 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.Backgrounds public class SeasonalBackgroundLoader : Component { /// - /// Fired when background change should be changed due to receiving backgrounds from API + /// Fired when background should be changed due to receiving backgrounds from API /// or when the user setting is changed (as it might require unloading the seasonal background). /// public event Action SeasonalBackgroundChanged; From 78842ab95ae90862c704ee3c350cd08b8c6126e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Oct 2020 22:40:24 +0100 Subject: [PATCH 094/104] Improve look & behaviour of background transitions --- .../Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 2 ++ osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index 03b7300011..99f3a8a6e8 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -97,6 +97,8 @@ namespace osu.Game.Graphics.Backgrounds private void load(LargeTextureStore textures) { Sprite.Texture = textures.Get(url) ?? textures.Get(fallback_texture_name); + // ensure we're not loading in without a transition. + this.FadeInFromZero(200, Easing.InOutSine); } } } diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index f392386bf9..3f6210310f 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.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.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -52,7 +53,8 @@ namespace osu.Game.Screens.Backgrounds currentDisplay = RNG.Next(0, background_count); - LoadComponentAsync(seasonalBackgroundLoader, _ => LoadComponentAsync(createBackground(), display)); + LoadComponentAsync(seasonalBackgroundLoader); + Next(); } private void display(Background newBackground) @@ -65,11 +67,14 @@ namespace osu.Game.Screens.Backgrounds } private ScheduledDelegate nextTask; + private CancellationTokenSource cancellationTokenSource; public void Next() { nextTask?.Cancel(); - nextTask = Scheduler.AddDelayed(() => { LoadComponentAsync(createBackground(), display); }, 100); + cancellationTokenSource?.Cancel(); + cancellationTokenSource = new CancellationTokenSource(); + nextTask = Scheduler.AddDelayed(() => LoadComponentAsync(createBackground(), display, cancellationTokenSource.Token), 100); } private Background createBackground() From 003994ab7518cf821204a5ba417c9b9bb4c35ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Oct 2020 12:21:07 +0100 Subject: [PATCH 095/104] Bind UpdateVisibility() directly to source of truth --- .../Edit/Compose/Components/BlueprintContainer.cs | 9 +-------- .../Edit/Compose/Components/SelectionHandler.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 5ac360d029..fa98358dbe 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -210,10 +210,7 @@ namespace osu.Game.Screens.Edit.Compose.Components } if (DragBox.State == Visibility.Visible) - { DragBox.Hide(); - SelectionHandler.UpdateVisibility(); - } } protected override bool OnKeyDown(KeyDownEvent e) @@ -352,11 +349,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// Selects all s. /// - private void selectAll() - { - SelectionBlueprints.ToList().ForEach(m => m.Select()); - SelectionHandler.UpdateVisibility(); - } + private void selectAll() => SelectionBlueprints.ToList().ForEach(m => m.Select()); /// /// Deselects all selected s. diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 01e23bafc5..07ae283667 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -201,8 +201,6 @@ namespace osu.Game.Screens.Edit.Compose.Components // there are potentially multiple SelectionHandlers active, but we only want to add hitobjects to the selected list once. if (!EditorBeatmap.SelectedHitObjects.Contains(blueprint.HitObject)) EditorBeatmap.SelectedHitObjects.Add(blueprint.HitObject); - - UpdateVisibility(); } /// @@ -214,8 +212,6 @@ namespace osu.Game.Screens.Edit.Compose.Components selectedBlueprints.Remove(blueprint); EditorBeatmap.SelectedHitObjects.Remove(blueprint.HitObject); - - UpdateVisibility(); } /// @@ -254,7 +250,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// Updates whether this is visible. /// - internal void UpdateVisibility() + private void updateVisibility() { int count = selectedBlueprints.Count; @@ -421,7 +417,11 @@ namespace osu.Game.Screens.Edit.Compose.Components // bring in updates from selection changes EditorBeatmap.HitObjectUpdated += _ => UpdateTernaryStates(); - EditorBeatmap.SelectedHitObjects.CollectionChanged += (sender, args) => UpdateTernaryStates(); + EditorBeatmap.SelectedHitObjects.CollectionChanged += (sender, args) => + { + updateVisibility(); + UpdateTernaryStates(); + }; } /// From 3322b8a7ea03d97e3c18acf58965d0c7798d4ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Oct 2020 12:25:02 +0100 Subject: [PATCH 096/104] Run OnSelectionChanged() on each change --- .../Screens/Edit/Compose/Components/SelectionHandler.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 07ae283667..0547b15e3d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -257,16 +257,15 @@ namespace osu.Game.Screens.Edit.Compose.Components selectionDetailsText.Text = count > 0 ? count.ToString() : string.Empty; if (count > 0) - { Show(); - OnSelectionChanged(); - } else Hide(); + + OnSelectionChanged(); } /// - /// Triggered whenever more than one object is selected, on each change. + /// Triggered whenever the set of selected objects changes. /// Should update the selection box's state to match supported operations. /// protected virtual void OnSelectionChanged() From d74c19e2d703f6e57139727692a3473ea7bd55fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Oct 2020 12:28:35 +0100 Subject: [PATCH 097/104] Shorten show/hide code --- .../Screens/Edit/Compose/Components/SelectionHandler.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 0547b15e3d..41098cc84c 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -256,11 +256,7 @@ namespace osu.Game.Screens.Edit.Compose.Components selectionDetailsText.Text = count > 0 ? count.ToString() : string.Empty; - if (count > 0) - Show(); - else - Hide(); - + this.FadeTo(count > 0 ? 1 : 0); OnSelectionChanged(); } From 007c27d3ffa987afdfc5c3502c27d4a89f8538fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Oct 2020 14:45:11 +0100 Subject: [PATCH 098/104] Schedule visibility update once per frame --- osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 41098cc84c..5c1b41d848 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -414,7 +414,7 @@ namespace osu.Game.Screens.Edit.Compose.Components EditorBeatmap.HitObjectUpdated += _ => UpdateTernaryStates(); EditorBeatmap.SelectedHitObjects.CollectionChanged += (sender, args) => { - updateVisibility(); + Scheduler.AddOnce(updateVisibility); UpdateTernaryStates(); }; } From a9a3489e92b200d99c335cd52aab2c93e4cf3a17 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Oct 2020 22:51:31 +0900 Subject: [PATCH 099/104] Fix potential null reference when loading background As seen in https://discordapp.com/channels/188630481301012481/188630652340404224/772094427342569493. Caused due to async load of the loader, which means it may not be ready before Next() is called. --- osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 1 - osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index 99f3a8a6e8..a48da37804 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -15,7 +15,6 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Graphics.Backgrounds { - [LongRunningLoad] public class SeasonalBackgroundLoader : Component { /// diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 3f6210310f..8beb955824 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -44,6 +44,8 @@ namespace osu.Game.Screens.Backgrounds mode = config.GetBindable(OsuSetting.MenuBackgroundSource); introSequence = config.GetBindable(OsuSetting.IntroSequence); + AddInternal(seasonalBackgroundLoader); + user.ValueChanged += _ => Next(); skin.ValueChanged += _ => Next(); mode.ValueChanged += _ => Next(); @@ -53,7 +55,6 @@ namespace osu.Game.Screens.Backgrounds currentDisplay = RNG.Next(0, background_count); - LoadComponentAsync(seasonalBackgroundLoader); Next(); } From 2065680e9d1d12183c5493dfc639fff9b74ee97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Oct 2020 17:01:45 +0100 Subject: [PATCH 100/104] Simplify test case --- .../Background/TestSceneSeasonalBackgroundLoader.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs index 8f5990aeb1..fba0d92d4b 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs @@ -149,18 +149,14 @@ namespace osu.Game.Tests.Visual.Background => AddStep($"set seasonal mode to {mode}", () => config.Set(OsuSetting.SeasonalBackgroundMode, mode)); private void createLoader() - { - AddStep("create loader", () => + => AddStep("create loader", () => { if (backgroundLoader != null) Remove(backgroundLoader); - LoadComponentAsync(backgroundLoader = new SeasonalBackgroundLoader(), Add); + Add(backgroundLoader = new SeasonalBackgroundLoader()); }); - AddUntilStep("wait for loaded", () => backgroundLoader.IsLoaded); - } - private void loadNextBackground() { SeasonalBackground background = null; From 8a54fdd4e6427b079f8d1f45205270d1f487b007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Nov 2020 14:25:33 +0100 Subject: [PATCH 101/104] Ensure LoadOszIntoOsu returns actual imported map --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 80fbda8e1d..b941313103 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -821,15 +821,13 @@ namespace osu.Game.Tests.Beatmaps.IO var manager = osu.Dependencies.Get(); - await manager.Import(temp); - - var imported = manager.GetAllUsableBeatmapSets(); + var importedSet = await manager.Import(temp); ensureLoaded(osu); waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000); - return imported.LastOrDefault(); + return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.ID); } private void deleteBeatmapSet(BeatmapSetInfo imported, OsuGameBase osu) From 6e9ed76251ea86fbc6f216953d964ae0ccc61f62 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 1 Nov 2020 17:14:57 +0000 Subject: [PATCH 102/104] Bump Microsoft.Build.Traversal from 2.1.1 to 2.2.3 Bumps [Microsoft.Build.Traversal](https://github.com/Microsoft/MSBuildSdks) from 2.1.1 to 2.2.3. - [Release notes](https://github.com/Microsoft/MSBuildSdks/releases) - [Changelog](https://github.com/microsoft/MSBuildSdks/blob/master/RELEASE.md) - [Commits](https://github.com/Microsoft/MSBuildSdks/compare/Microsoft.Build.Traversal.2.1.1...Microsoft.Build.Traversal.2.2.3) Signed-off-by: dependabot-preview[bot] --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index a9a531f59c..10b61047ac 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,6 @@ "version": "3.1.100" }, "msbuild-sdks": { - "Microsoft.Build.Traversal": "2.1.1" + "Microsoft.Build.Traversal": "2.2.3" } } \ No newline at end of file From 79e610d31b9017e9d13e82fd704a32fc72c5e768 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 1 Nov 2020 17:15:23 +0000 Subject: [PATCH 103/104] Bump Microsoft.CodeAnalysis.BannedApiAnalyzers from 3.3.0 to 3.3.1 Bumps [Microsoft.CodeAnalysis.BannedApiAnalyzers](https://github.com/dotnet/roslyn-analyzers) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/dotnet/roslyn-analyzers/releases) - [Changelog](https://github.com/dotnet/roslyn-analyzers/blob/master/PostReleaseActivities.md) - [Commits](https://github.com/dotnet/roslyn-analyzers/compare/v3.3.0...v3.3.1) Signed-off-by: dependabot-preview[bot] --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 2d3478f256..056216f14b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -16,7 +16,7 @@ - + From 71d55f16f3853f3e9f3cc56bb4cf981d957e9840 Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 1 Nov 2020 13:50:38 -0800 Subject: [PATCH 104/104] Fix edit beatmap options button not resuming back to song select --- osu.Game/Screens/Select/PlaySongSelect.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 19769f487d..ee8825640c 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -32,11 +32,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader] private void load(OsuColour colours) { - BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => - { - ValidForResume = false; - Edit(); - }); + BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); ((PlayBeatmapDetailArea)BeatmapDetails).Leaderboard.ScoreSelected += PresentScore; }