From 7b414092afd261c953fd9f51f9bdf93632021523 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:35:41 +0300 Subject: [PATCH 01/40] Implement beatmap ruleset selector --- .../BeatmapSet/BeatmapRulesetSelector.cs | 50 ++++++ .../BeatmapSet/BeatmapRulesetTabItem.cs | 148 ++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs create mode 100644 osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs new file mode 100644 index 0000000000..0847272e1f --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -0,0 +1,50 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osuTK; +using System.Linq; + +namespace osu.Game.Overlays.BeatmapSet +{ + public class BeatmapRulesetSelector : RulesetSelector + { + private BeatmapSetInfo beatmapSet; + + public BeatmapSetInfo BeatmapSet + { + get => beatmapSet; + set + { + if (value == beatmapSet) + return; + + beatmapSet = value; + + foreach (BeatmapRulesetTabItem tab in TabContainer.TabItems) + tab.SetBeatmaps(beatmapSet?.Beatmaps.FindAll(b => b.Ruleset.Equals(tab.Value))); + + var firstRuleset = beatmapSet?.Beatmaps.OrderBy(b => b.Ruleset.ID).FirstOrDefault()?.Ruleset; + SelectTab(TabContainer.TabItems.FirstOrDefault(t => t.Value.Equals(firstRuleset))); + } + } + + public BeatmapRulesetSelector() + { + AutoSizeAxes = Axes.Both; + TabContainer.Spacing = new Vector2(10, 0); + } + + protected override TabItem CreateTabItem(RulesetInfo value) => new BeatmapRulesetTabItem(value); + + protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer + { + Direction = FillDirection.Horizontal, + AutoSizeAxes = Axes.Both, + }; + } +} diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs new file mode 100644 index 0000000000..19c9af13d5 --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -0,0 +1,148 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets; +using osuTK; +using osuTK.Graphics; +using System.Collections.Generic; +using System.Diagnostics; + +namespace osu.Game.Overlays.BeatmapSet +{ + public class BeatmapRulesetTabItem : TabItem + { + private readonly OsuSpriteText name, count; + private readonly Box bar; + + public override bool PropagatePositionalInputSubTree => Enabled.Value && !Active.Value && base.PropagatePositionalInputSubTree; + + public BeatmapRulesetTabItem(RulesetInfo value) + : base(value) + { + AutoSizeAxes = Axes.Both; + Masking = true; + + FillFlowContainer nameContainer; + + Children = new Drawable[] + { + nameContainer = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Bottom = 7.5f }, + Spacing = new Vector2(2.5f), + Children = new Drawable[] + { + name = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = value.Name, + Font = OsuFont.Default.With(size: 18), + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4f, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0.5f), + }, + count = new OsuSpriteText + { + Alpha = 0, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = 5f }, + Font = OsuFont.Default.With(weight: FontWeight.SemiBold), + } + } + } + } + }, + bar = new Box + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = 4f, + }, + new HoverClickSounds(), + }; + + Enabled.BindValueChanged(v => nameContainer.Alpha = v.NewValue ? 1f : 0.5f, true); + } + + [Resolved] + private OsuColour colour { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + count.Colour = colour.Gray9; + bar.Colour = colour.Blue; + + updateState(); + } + + public void SetBeatmaps(List beatmaps) + { + Trace.Assert(beatmaps?.TrueForAll(b => b.Ruleset.Equals(Value)) ?? true, "A beatmap has a ruleset not of this tab value"); + + count.Text = beatmaps?.Count.ToString(); + + var hasBeatmaps = (beatmaps?.Count ?? 0) > 0; + count.Alpha = hasBeatmaps ? 1f : 0f; + Enabled.Value = hasBeatmaps; + } + + private void updateState() + { + var isHoveredOrActive = IsHovered || Active.Value; + name.Colour = isHoveredOrActive ? colour.GrayE : colour.GrayC; + bar.MoveToY(isHoveredOrActive ? 0f : bar.Height, 120); + + name.Font = name.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular); + } + + #region Hovering and activation logic + + protected override void OnActivated() => updateState(); + + protected override void OnDeactivated() => updateState(); + + protected override bool OnHover(HoverEvent e) + { + updateState(); + return false; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateState(); + } + + #endregion + } +} From edddbdb7845a250002ee5dd111750b3290a29401 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:37:09 +0300 Subject: [PATCH 02/40] Add tests for beatmap ruleset selector --- .../Online/TestSceneBeatmapRulesetSelector.cs | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs new file mode 100644 index 0000000000..1f8df438fb --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs @@ -0,0 +1,102 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Beatmaps; +using osu.Game.Overlays.BeatmapSet; +using osu.Game.Rulesets; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneBeatmapRulesetSelector : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(BeatmapRulesetSelector), + typeof(BeatmapRulesetTabItem), + }; + + private readonly TestRulesetSelector selector; + + public TestSceneBeatmapRulesetSelector() + { + Add(selector = new TestRulesetSelector()); + } + + [Resolved] + private RulesetStore rulesets { get; set; } + + [Test] + public void TestMultipleRulesetsBeatmapSet() + { + var enabledRulesets = rulesets.AvailableRulesets.Skip(1).Take(2); + + AddStep("load multiple rulesets beatmapset", () => + { + selector.BeatmapSet = new BeatmapSetInfo + { + Beatmaps = enabledRulesets.Select(r => new BeatmapInfo { Ruleset = r }).ToList() + }; + }); + + var tabItems = selector.TabContainer.TabItems; + AddAssert("other rulesets disabled", () => tabItems.Except(tabItems.Where(t => enabledRulesets.Any(r => r.Equals(t.Value)))).All(t => !t.Enabled.Value)); + AddAssert("left-most ruleset selected", () => tabItems.First(t => t.Enabled.Value).Active.Value); + } + + [Test] + public void TestSingleRulesetBeatmapSet() + { + var enabledRuleset = rulesets.AvailableRulesets.Last(); + + AddStep("load single ruleset beatmapset", () => + { + selector.BeatmapSet = new BeatmapSetInfo + { + Beatmaps = new List + { + new BeatmapInfo + { + Ruleset = enabledRuleset + } + } + }; + }); + + AddAssert("single ruleset selected", () => selector.SelectedTab.Value.Equals(enabledRuleset)); + } + + [Test] + public void TestEmptyBeatmapSet() + { + AddStep("load empty beatmapset", () => selector.BeatmapSet = new BeatmapSetInfo + { + Beatmaps = new List() + }); + + AddAssert("no ruleset selected", () => selector.SelectedTab == null); + AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value)); + } + + [Test] + public void TestNullBeatmapSet() + { + AddStep("load null beatmapset", () => selector.BeatmapSet = null); + + AddAssert("no ruleset selected", () => selector.SelectedTab == null); + AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value)); + } + + private class TestRulesetSelector : BeatmapRulesetSelector + { + public new TabItem SelectedTab => base.SelectedTab; + + public new TabFillFlowContainer TabContainer => base.TabContainer; + } + } +} From 7d5f5d2fd9272e207bc26860e76f613ce01e38ec Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:55:33 +0300 Subject: [PATCH 03/40] Add ruleset selector to the beatmap overlay header --- osu.Game/Overlays/BeatmapSet/Header.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 260a989628..0e3d29c25b 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -3,6 +3,7 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -16,6 +17,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Overlays.Direct; +using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -39,6 +41,7 @@ namespace osu.Game.Overlays.BeatmapSet public bool DownloadButtonsVisible => downloadButtonsContainer.Any(); + public readonly BeatmapRulesetSelector RulesetSelector; public readonly BeatmapPicker Picker; private readonly FavouriteButton favouriteButton; @@ -69,12 +72,17 @@ namespace osu.Game.Overlays.BeatmapSet { RelativeSizeAxes = Axes.X, Height = tabs_height, - Children = new[] + Children = new Drawable[] { tabsBg = new Box { RelativeSizeAxes = Axes.Both, }, + RulesetSelector = new BeatmapRulesetSelector + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + } }, }, new Container @@ -214,6 +222,13 @@ namespace osu.Game.Overlays.BeatmapSet }; } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + dependencies.CacheAs>(RulesetSelector.Current); + return dependencies; + } + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -223,7 +238,7 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.BindValueChanged(setInfo => { - Picker.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; + Picker.BeatmapSet = RulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; cover.BeatmapSet = setInfo.NewValue; if (setInfo.NewValue == null) From 555c82e9c9077f8e363aebb12e73ff07127aa97f Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:56:42 +0300 Subject: [PATCH 04/40] Filter beatmap difficulties by current ruleset --- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 28947b6f22..e7a3d15401 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -17,6 +17,7 @@ using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -27,10 +28,11 @@ namespace osu.Game.Overlays.BeatmapSet private const float tile_icon_padding = 7; private const float tile_spacing = 2; - private readonly DifficultiesContainer difficulties; private readonly OsuSpriteText version, starRating; private readonly Statistic plays, favourites; + public readonly DifficultiesContainer Difficulties; + public readonly Bindable Beatmap = new Bindable(); private BeatmapSetInfo beatmapSet; @@ -50,11 +52,11 @@ namespace osu.Game.Overlays.BeatmapSet private void updateDisplay() { - difficulties.Clear(); + Difficulties.Clear(); if (BeatmapSet != null) { - difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty).Select(b => new DifficultySelectorButton(b) + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b) { State = DifficultySelectorState.NotSelected, OnHovered = beatmap => @@ -68,7 +70,7 @@ namespace osu.Game.Overlays.BeatmapSet } starRating.FadeOut(100); - Beatmap.Value = BeatmapSet?.Beatmaps.FirstOrDefault(); + Beatmap.Value = Difficulties.FirstOrDefault()?.Beatmap; plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0; favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0; @@ -89,7 +91,7 @@ namespace osu.Game.Overlays.BeatmapSet Direction = FillDirection.Vertical, Children = new Drawable[] { - difficulties = new DifficultiesContainer + Difficulties = new DifficultiesContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -147,6 +149,9 @@ namespace osu.Game.Overlays.BeatmapSet }; } + [Resolved] + private IBindable ruleset { get; set; } + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -158,6 +163,8 @@ namespace osu.Game.Overlays.BeatmapSet { base.LoadComplete(); + ruleset.ValueChanged += r => updateDisplay(); + // done here so everything can bind in intialization and get the first trigger Beatmap.TriggerChange(); } @@ -169,10 +176,10 @@ namespace osu.Game.Overlays.BeatmapSet private void updateDifficultyButtons() { - difficulties.Children.ToList().ForEach(diff => diff.State = diff.Beatmap == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected); + Difficulties.Children.ToList().ForEach(diff => diff.State = diff.Beatmap == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected); } - private class DifficultiesContainer : FillFlowContainer + public class DifficultiesContainer : FillFlowContainer { public Action OnLostHover; @@ -183,7 +190,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - private class DifficultySelectorButton : OsuClickableContainer, IStateful + public class DifficultySelectorButton : OsuClickableContainer, IStateful { private const float transition_duration = 100; private const float size = 52; @@ -320,7 +327,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - private enum DifficultySelectorState + public enum DifficultySelectorState { Selected, NotSelected, From 4f40a044258b392f8c0d42a672d5d492ab11779e Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:57:39 +0300 Subject: [PATCH 05/40] Add tests ensuring correct behaviour with ruleset selection --- .../Online/TestSceneBeatmapSetOverlay.cs | 70 +++++++++++++++---- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 9f03d947b9..6c7a3e4108 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; @@ -40,24 +41,19 @@ namespace osu.Game.Tests.Visual.Online typeof(PreviewButton), typeof(SuccessRate), typeof(BeatmapAvailability), + typeof(BeatmapRulesetSelector), + typeof(BeatmapRulesetTabItem), }; protected override bool UseOnlineAPI => true; - private RulesetInfo taikoRuleset; - private RulesetInfo maniaRuleset; - public TestSceneBeatmapSetOverlay() { Add(overlay = new TestBeatmapSetOverlay()); } - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) - { - taikoRuleset = rulesets.GetRuleset(1); - maniaRuleset = rulesets.GetRuleset(3); - } + [Resolved] + private RulesetStore rulesets { get; set; } [Test] public void TestLoading() @@ -111,7 +107,7 @@ namespace osu.Game.Tests.Visual.Online StarDifficulty = 9.99, Version = @"TEST", Length = 456000, - Ruleset = maniaRuleset, + Ruleset = rulesets.GetRuleset(3), BaseDifficulty = new BeatmapDifficulty { CircleSize = 1, @@ -189,7 +185,7 @@ namespace osu.Game.Tests.Visual.Online StarDifficulty = 5.67, Version = @"ANOTHER TEST", Length = 123000, - Ruleset = taikoRuleset, + Ruleset = rulesets.GetRuleset(1), BaseDifficulty = new BeatmapDifficulty { CircleSize = 9, @@ -217,6 +213,54 @@ namespace osu.Game.Tests.Visual.Online downloadAssert(false); } + [Test] + public void TestMultipleRulesets() + { + AddStep("show multiple rulesets beatmap", () => + { + var beatmaps = new List(); + + foreach (var ruleset in rulesets.AvailableRulesets.Skip(1)) + { + beatmaps.Add(new BeatmapInfo + { + Version = ruleset.Name, + Ruleset = ruleset, + BaseDifficulty = new BeatmapDifficulty(), + OnlineInfo = new BeatmapOnlineInfo(), + Metrics = new BeatmapMetrics + { + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), + }, + }); + } + + overlay.ShowBeatmapSet(new BeatmapSetInfo + { + Metadata = new BeatmapMetadata + { + Title = @"multiple rulesets beatmap", + Artist = @"none", + Author = new User + { + Username = "BanchoBot", + Id = 3, + } + }, + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers(), + }, + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }, + Beatmaps = beatmaps + }); + }); + + AddAssert("shown beatmaps of current ruleset", () => overlay.Header.Picker.Difficulties.All(b => b.Beatmap.Ruleset.Equals(overlay.Header.RulesetSelector.Current.Value))); + AddAssert("left-most beatmap selected", () => overlay.Header.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected); + } + [Test] public void TestHide() { @@ -281,12 +325,12 @@ namespace osu.Game.Tests.Visual.Online private void downloadAssert(bool shown) { - AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.DownloadButtonsVisible == shown); + AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.DownloadButtonsVisible == shown); } private class TestBeatmapSetOverlay : BeatmapSetOverlay { - public bool DownloadButtonsVisible => Header.DownloadButtonsVisible; + public new Header Header => base.Header; } } } From 0c4f24825969c64775705b8feb9297af2f4fc9ac Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 18:02:13 +0300 Subject: [PATCH 06/40] Fix CI issues --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index 0847272e1f..1abe103fc8 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapSet beatmapSet = value; - foreach (BeatmapRulesetTabItem tab in TabContainer.TabItems) + foreach (var tab in TabContainer.TabItems.OfType()) tab.SetBeatmaps(beatmapSet?.Beatmaps.FindAll(b => b.Ruleset.Equals(tab.Value))); var firstRuleset = beatmapSet?.Beatmaps.OrderBy(b => b.Ruleset.ID).FirstOrDefault()?.Ruleset; From 6985249d90e63e8e18ca92dd31c056eed82f35af Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 21:18:03 +0300 Subject: [PATCH 07/40] Simplify properties --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index 1abe103fc8..bfb188a83b 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -36,15 +36,15 @@ namespace osu.Game.Overlays.BeatmapSet public BeatmapRulesetSelector() { AutoSizeAxes = Axes.Both; - TabContainer.Spacing = new Vector2(10, 0); } protected override TabItem CreateTabItem(RulesetInfo value) => new BeatmapRulesetTabItem(value); protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer { - Direction = FillDirection.Horizontal, AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), }; } } From ba1a8547011d721f61ef1798b6dab6ed6d0e083e Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 5 Oct 2019 10:30:32 +0300 Subject: [PATCH 08/40] Use IEnumerable.Where<>() rather than List.FindAll() Saves a whole list allocation --- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index e7a3d15401..bffe779da1 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -56,7 +56,7 @@ namespace osu.Game.Overlays.BeatmapSet if (BeatmapSet != null) { - Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b) + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Where(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b) { State = DifficultySelectorState.NotSelected, OnHovered = beatmap => From 60133ba0c3fa62ef7f7cc6f8f14ea47f886b2015 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 15 Oct 2019 23:33:50 +0300 Subject: [PATCH 09/40] Propagate BeatmapSetInfo to tab items with bindable --- .../BeatmapSet/BeatmapRulesetSelector.cs | 22 +++++++--------- .../BeatmapSet/BeatmapRulesetTabItem.cs | 26 +++++++++---------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index bfb188a83b..a0bedc848e 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.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 osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; @@ -13,23 +14,17 @@ namespace osu.Game.Overlays.BeatmapSet { public class BeatmapRulesetSelector : RulesetSelector { - private BeatmapSetInfo beatmapSet; + private readonly Bindable beatmapSet = new Bindable(); public BeatmapSetInfo BeatmapSet { - get => beatmapSet; + get => beatmapSet.Value; set { - if (value == beatmapSet) - return; + // propagate value to tab items first to enable only available rulesets. + beatmapSet.Value = value; - beatmapSet = value; - - foreach (var tab in TabContainer.TabItems.OfType()) - tab.SetBeatmaps(beatmapSet?.Beatmaps.FindAll(b => b.Ruleset.Equals(tab.Value))); - - var firstRuleset = beatmapSet?.Beatmaps.OrderBy(b => b.Ruleset.ID).FirstOrDefault()?.Ruleset; - SelectTab(TabContainer.TabItems.FirstOrDefault(t => t.Value.Equals(firstRuleset))); + SelectTab(TabContainer.TabItems.FirstOrDefault(t => t.Enabled.Value)); } } @@ -38,7 +33,10 @@ namespace osu.Game.Overlays.BeatmapSet AutoSizeAxes = Axes.Both; } - protected override TabItem CreateTabItem(RulesetInfo value) => new BeatmapRulesetTabItem(value); + protected override TabItem CreateTabItem(RulesetInfo value) => new BeatmapRulesetTabItem(value) + { + BeatmapSet = { BindTarget = beatmapSet } + }; protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer { diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs index 19c9af13d5..5227bec92a 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,8 +16,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; -using System.Collections.Generic; -using System.Diagnostics; +using System.Linq; namespace osu.Game.Overlays.BeatmapSet { @@ -25,6 +25,8 @@ namespace osu.Game.Overlays.BeatmapSet private readonly OsuSpriteText name, count; private readonly Box bar; + public readonly Bindable BeatmapSet = new Bindable(); + public override bool PropagatePositionalInputSubTree => Enabled.Value && !Active.Value && base.PropagatePositionalInputSubTree; public BeatmapRulesetTabItem(RulesetInfo value) @@ -90,6 +92,15 @@ namespace osu.Game.Overlays.BeatmapSet new HoverClickSounds(), }; + BeatmapSet.BindValueChanged(setInfo => + { + var beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.Equals(Value)) ?? 0; + count.Text = beatmapsCount.ToString(); + + count.Alpha = beatmapsCount > 0 ? 1f : 0f; + Enabled.Value = beatmapsCount > 0; + }, true); + Enabled.BindValueChanged(v => nameContainer.Alpha = v.NewValue ? 1f : 0.5f, true); } @@ -106,17 +117,6 @@ namespace osu.Game.Overlays.BeatmapSet updateState(); } - public void SetBeatmaps(List beatmaps) - { - Trace.Assert(beatmaps?.TrueForAll(b => b.Ruleset.Equals(Value)) ?? true, "A beatmap has a ruleset not of this tab value"); - - count.Text = beatmaps?.Count.ToString(); - - var hasBeatmaps = (beatmaps?.Count ?? 0) > 0; - count.Alpha = hasBeatmaps ? 1f : 0f; - Enabled.Value = hasBeatmaps; - } - private void updateState() { var isHoveredOrActive = IsHovered || Active.Value; From b0e21c2749d24d58de0b4c92569244bdeed77460 Mon Sep 17 00:00:00 2001 From: nwabear Date: Fri, 25 Oct 2019 14:57:49 -0500 Subject: [PATCH 10/40] Fixed Issue #6442 --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 7 +++++++ osu.Game/Screens/Play/Player.cs | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index d5b3df27df..d37f053486 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -239,6 +239,11 @@ namespace osu.Game.Rulesets.UI continueResume(); } + public override void CancelResume() + { + ResumeOverlay.Hide(); + } + /// /// Creates and adds the visual representation of a to this . /// @@ -453,6 +458,8 @@ namespace osu.Game.Rulesets.UI /// The action to run when resuming is to be completed. public abstract void RequestResume(Action continueResume); + public abstract void CancelResume(); + /// /// Create a for the associated ruleset and link with this /// . diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0b363eac4d..7eccde4555 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -443,6 +443,11 @@ namespace osu.Game.Screens.Play { if (!canPause) return; + if (IsResuming) + { + DrawableRuleset.CancelResume(); + } + IsResuming = false; GameplayClockContainer.Stop(); PauseOverlay.Show(); From f8354eefc4e058b98fc9d834bc0be2bc441db1e4 Mon Sep 17 00:00:00 2001 From: nwabear Date: Fri, 25 Oct 2019 16:49:18 -0500 Subject: [PATCH 11/40] Added null check in the CancelResume method --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index d37f053486..d3e1118625 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -241,7 +241,7 @@ namespace osu.Game.Rulesets.UI public override void CancelResume() { - ResumeOverlay.Hide(); + ResumeOverlay?.Hide(); } /// From 9e2e87c8d13cf147b720825a5ff266c024cabf72 Mon Sep 17 00:00:00 2001 From: nwabear Date: Sat, 26 Oct 2019 14:29:52 -0500 Subject: [PATCH 12/40] added visual tests added small commenting added xmldoc for CancelResume(); --- .../Visual/Gameplay/TestScenePause.cs | 18 ++++++++++++++++++ osu.Game/Rulesets/UI/DrawableRuleset.cs | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index 2df22df659..64022b2410 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -69,6 +69,24 @@ namespace osu.Game.Tests.Visual.Gameplay confirmClockRunning(true); } + [Test] + public void TestPauseWithResumeOverlay() + { + AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); + AddUntilStep("wait for hitobjects", () => Player.ScoreProcessor.Health.Value < 1); + + pauseAndConfirm(); + + resume(); + confirmClockRunning(false); + confirmPauseOverlayShown(false); + + pauseAndConfirm(); + + AddUntilStep("resume overlay is not active", () => Player.DrawableRuleset.ResumeOverlay.State.Value == Visibility.Hidden); + confirmPaused(); + } + [Test] public void TestResumeWithResumeOverlaySkipped() { diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index d3e1118625..44e2e60be7 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -239,8 +239,10 @@ namespace osu.Game.Rulesets.UI continueResume(); } + public override void CancelResume() { + // called if the user pauses while the resume overlay is open ResumeOverlay?.Hide(); } @@ -458,6 +460,9 @@ namespace osu.Game.Rulesets.UI /// The action to run when resuming is to be completed. public abstract void RequestResume(Action continueResume); + /// + /// Invoked when the user requests to pause while the resume overlay is active. + /// public abstract void CancelResume(); /// From e35931fdfc7b6c94d401ab0076ce3e80f2edffcd Mon Sep 17 00:00:00 2001 From: nwabear Date: Sat, 26 Oct 2019 14:33:59 -0500 Subject: [PATCH 13/40] removed blank line --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 44e2e60be7..e005eea831 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -239,7 +239,6 @@ namespace osu.Game.Rulesets.UI continueResume(); } - public override void CancelResume() { // called if the user pauses while the resume overlay is open From 95ff48c123cc19c7388c1140f2dc93513898244d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 30 Oct 2019 14:38:06 +0900 Subject: [PATCH 14/40] Don't log cancelled join requests --- osu.Game/Screens/Multi/RoomManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/RoomManager.cs b/osu.Game/Screens/Multi/RoomManager.cs index 6f473aaafa..8ceff7edef 100644 --- a/osu.Game/Screens/Multi/RoomManager.cs +++ b/osu.Game/Screens/Multi/RoomManager.cs @@ -98,7 +98,8 @@ namespace osu.Game.Screens.Multi currentJoinRoomRequest.Failure += exception => { - Logger.Log($"Failed to join room: {exception}", level: LogLevel.Important); + if (!(exception is OperationCanceledException)) + Logger.Log($"Failed to join room: {exception}", level: LogLevel.Important); onError?.Invoke(exception.ToString()); }; From b6457f0ce957342b9d76c2f36b37f85bccf640ea Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 30 Oct 2019 14:41:54 +0900 Subject: [PATCH 15/40] Cancel room joins on part --- osu.Game/Screens/Multi/RoomManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/RoomManager.cs b/osu.Game/Screens/Multi/RoomManager.cs index 8ceff7edef..cdaba85b9e 100644 --- a/osu.Game/Screens/Multi/RoomManager.cs +++ b/osu.Game/Screens/Multi/RoomManager.cs @@ -87,9 +87,8 @@ namespace osu.Game.Screens.Multi public void JoinRoom(Room room, Action onSuccess = null, Action onError = null) { currentJoinRoomRequest?.Cancel(); - currentJoinRoomRequest = null; - currentJoinRoomRequest = new JoinRoomRequest(room, api.LocalUser.Value); + currentJoinRoomRequest.Success += () => { joinedRoom = room; @@ -108,6 +107,8 @@ namespace osu.Game.Screens.Multi public void PartRoom() { + currentJoinRoomRequest?.Cancel(); + if (joinedRoom == null) return; From f56d9fe50cf2933a1fd94afc90df7082ebaff331 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 30 Oct 2019 14:42:14 +0900 Subject: [PATCH 16/40] Forcefully part room when multiplayer exits --- osu.Game/Screens/Multi/Multiplayer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 90806bab6e..5945e9de13 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -212,6 +212,8 @@ namespace osu.Game.Screens.Multi public override bool OnExiting(IScreen next) { + roomManager.PartRoom(); + if (screenStack.CurrentScreen != null && !(screenStack.CurrentScreen is LoungeSubScreen)) { screenStack.Exit(); From 32dabf80a6f896cba970220d0e2435051a2c5982 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Oct 2019 13:42:11 +0900 Subject: [PATCH 17/40] Ensure forceful exit completely exits from mutliplayer Previously it may have gotten blocked by being in a sub screen. --- osu.Game/Screens/Multi/Multiplayer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 5945e9de13..941d7a2478 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -174,7 +174,10 @@ namespace osu.Game.Screens.Multi { // This is temporary since we don't currently have a way to force screens to be exited if (this.IsCurrentScreen()) - this.Exit(); + { + while (this.IsCurrentScreen()) + this.Exit(); + } else { this.MakeCurrent(); From 5b405abc5253480414eb421028d48c1cb019ef0b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Oct 2019 13:43:25 +0900 Subject: [PATCH 18/40] Schedule forcefullyExit call for safety Screen state may have changed at an inopportune moment. Run on local scheduler, not API scheduler to avoid any weirdness. --- osu.Game/Screens/Multi/Multiplayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 941d7a2478..86d52ff791 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -167,7 +167,7 @@ namespace osu.Game.Screens.Multi public void APIStateChanged(IAPIProvider api, APIState state) { if (state != APIState.Online) - forcefullyExit(); + Schedule(forcefullyExit); } private void forcefullyExit() From 0cd912fcd3ad364b8ade2a7d5e98685f3e3c68d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Oct 2019 15:04:13 +0900 Subject: [PATCH 19/40] Cover all non-APIAccess APIRequest calls with exception handling --- osu.Game/Beatmaps/BeatmapManager.cs | 11 ++++-- .../DownloadableArchiveModelManager.cs | 35 ++++++++++++------- .../Changelog/ChangelogSingleBuild.cs | 12 ++++++- osu.Game/Overlays/ChangelogOverlay.cs | 19 ++++++++-- 4 files changed, 60 insertions(+), 17 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index dd2044b4bc..6e485f642a 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -392,8 +392,15 @@ namespace osu.Game.Beatmaps req.Failure += e => { LogForModel(set, $"Online retrieval failed for {beatmap} ({e.Message})"); }; - // intentionally blocking to limit web request concurrency - req.Perform(api); + try + { + // intentionally blocking to limit web request concurrency + req.Perform(api); + } + catch (Exception e) + { + LogForModel(set, $"Online retrieval failed for {beatmap} ({e.Message})"); + } } } } diff --git a/osu.Game/Database/DownloadableArchiveModelManager.cs b/osu.Game/Database/DownloadableArchiveModelManager.cs index e3c6ad25e6..a81dff3475 100644 --- a/osu.Game/Database/DownloadableArchiveModelManager.cs +++ b/osu.Game/Database/DownloadableArchiveModelManager.cs @@ -86,16 +86,7 @@ namespace osu.Game.Database }, TaskCreationOptions.LongRunning); }; - request.Failure += error => - { - DownloadFailed?.Invoke(request); - - if (error is OperationCanceledException) return; - - notification.State = ProgressNotificationState.Cancelled; - Logger.Error(error, $"{HumanisedModelName.Titleize()} download failed!"); - currentDownloads.Remove(request); - }; + request.Failure += triggerFailure; notification.CancelRequested += () => { @@ -108,11 +99,31 @@ namespace osu.Game.Database currentDownloads.Add(request); PostNotification?.Invoke(notification); - Task.Factory.StartNew(() => request.Perform(api), TaskCreationOptions.LongRunning); + Task.Factory.StartNew(() => + { + try + { + request.Perform(api); + } + catch (Exception error) + { + triggerFailure(error); + } + }, TaskCreationOptions.LongRunning); DownloadBegan?.Invoke(request); - return true; + + void triggerFailure(Exception error) + { + DownloadFailed?.Invoke(request); + + if (error is OperationCanceledException) return; + + notification.State = ProgressNotificationState.Cancelled; + Logger.Error(error, $"{HumanisedModelName.Titleize()} download failed!"); + currentDownloads.Remove(request); + } } public bool IsAvailableLocally(TModel model) => CheckLocalAvailability(model, modelStore.ConsumableItems.Where(m => !m.DeletePending)); diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index 9c3504f477..adcd33fb48 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -44,7 +44,17 @@ namespace osu.Game.Overlays.Changelog req.Failure += _ => complete = true; // This is done on a separate thread to support cancellation below - Task.Run(() => req.Perform(api)); + Task.Run(() => + { + try + { + req.Perform(api); + } + catch + { + complete = true; + } + }); while (!complete) { diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index dfe3669813..559989af5c 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -170,6 +170,7 @@ namespace osu.Game.Overlays var tcs = new TaskCompletionSource(); var req = new GetChangelogRequest(); + req.Success += res => Schedule(() => { // remap streams to builds to ensure model equality @@ -183,8 +184,22 @@ namespace osu.Game.Overlays tcs.SetResult(true); }); - req.Failure += _ => initialFetchTask = null; - req.Perform(API); + + req.Failure += _ => + { + initialFetchTask = null; + tcs.SetResult(false); + }; + + try + { + req.Perform(API); + } + catch + { + initialFetchTask = null; + tcs.SetResult(false); + } await tcs.Task; }); From f8187fa30125db2a93b455bd369fe123903bbb44 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Oct 2019 16:23:10 +0900 Subject: [PATCH 20/40] Don't rely on masking for bar display --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs index 5227bec92a..8c150e6ed1 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -33,7 +33,6 @@ namespace osu.Game.Overlays.BeatmapSet : base(value) { AutoSizeAxes = Axes.Both; - Masking = true; FillFlowContainer nameContainer; @@ -87,7 +86,6 @@ namespace osu.Game.Overlays.BeatmapSet Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, - Height = 4f, }, new HoverClickSounds(), }; @@ -95,9 +93,10 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.BindValueChanged(setInfo => { var beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.Equals(Value)) ?? 0; - count.Text = beatmapsCount.ToString(); + count.Text = beatmapsCount.ToString(); count.Alpha = beatmapsCount > 0 ? 1f : 0f; + Enabled.Value = beatmapsCount > 0; }, true); @@ -120,9 +119,10 @@ namespace osu.Game.Overlays.BeatmapSet private void updateState() { var isHoveredOrActive = IsHovered || Active.Value; - name.Colour = isHoveredOrActive ? colour.GrayE : colour.GrayC; - bar.MoveToY(isHoveredOrActive ? 0f : bar.Height, 120); + bar.ResizeHeightTo(isHoveredOrActive ? 4 : 1, 200, Easing.OutQuint); + + name.Colour = isHoveredOrActive ? colour.GrayE : colour.GrayC; name.Font = name.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular); } From bf45fa630984d624828bbeaf34ee7498a93fc170 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Oct 2019 16:24:03 +0900 Subject: [PATCH 21/40] Use lambda function expression --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs index 8c150e6ed1..3fecfbdaaf 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -138,10 +138,7 @@ namespace osu.Game.Overlays.BeatmapSet return false; } - protected override void OnHoverLost(HoverLostEvent e) - { - updateState(); - } + protected override void OnHoverLost(HoverLostEvent e) => updateState(); #endregion } From fe93df718675d16c931a67b903e4fbeee7fe6dcc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Oct 2019 16:52:56 +0900 Subject: [PATCH 22/40] Remove unnecessary using statement --- osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 6c7a3e4108..286971bc90 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -3,7 +3,6 @@ using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; From 4f04abf2825d374f3deefd4bc013606f50d2400f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Oct 2019 16:54:28 +0900 Subject: [PATCH 23/40] Fix tabs to match design (should not show pinhair line) --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs index 3fecfbdaaf..cdea49afe7 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -120,7 +120,7 @@ namespace osu.Game.Overlays.BeatmapSet { var isHoveredOrActive = IsHovered || Active.Value; - bar.ResizeHeightTo(isHoveredOrActive ? 4 : 1, 200, Easing.OutQuint); + bar.ResizeHeightTo(isHoveredOrActive ? 4 : 0, 200, Easing.OutQuint); name.Colour = isHoveredOrActive ? colour.GrayE : colour.GrayC; name.Font = name.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular); From 3e3ff812291f343d1847ecd037914e38ddf70d50 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Oct 2019 17:13:00 +0900 Subject: [PATCH 24/40] Reorder methods --- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index bffe779da1..bf2a92cd4f 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -45,38 +45,10 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - updateDisplay(); } } - private void updateDisplay() - { - Difficulties.Clear(); - - if (BeatmapSet != null) - { - Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Where(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b) - { - State = DifficultySelectorState.NotSelected, - OnHovered = beatmap => - { - showBeatmap(beatmap); - starRating.Text = beatmap.StarDifficulty.ToString("Star Difficulty 0.##"); - starRating.FadeIn(100); - }, - OnClicked = beatmap => { Beatmap.Value = beatmap; }, - }); - } - - starRating.FadeOut(100); - Beatmap.Value = Difficulties.FirstOrDefault()?.Beatmap; - plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0; - favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0; - - updateDifficultyButtons(); - } - public BeatmapPicker() { RelativeSizeAxes = Axes.X; @@ -169,6 +141,33 @@ namespace osu.Game.Overlays.BeatmapSet Beatmap.TriggerChange(); } + private void updateDisplay() + { + Difficulties.Clear(); + + if (BeatmapSet != null) + { + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Where(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b) + { + State = DifficultySelectorState.NotSelected, + OnHovered = beatmap => + { + showBeatmap(beatmap); + starRating.Text = beatmap.StarDifficulty.ToString("Star Difficulty 0.##"); + starRating.FadeIn(100); + }, + OnClicked = beatmap => { Beatmap.Value = beatmap; }, + }); + } + + starRating.FadeOut(100); + Beatmap.Value = Difficulties.FirstOrDefault()?.Beatmap; + plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0; + favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0; + + updateDifficultyButtons(); + } + private void showBeatmap(BeatmapInfo beatmap) { version.Text = beatmap?.Version; From ce19b2ed36b04186014123222a12067e9301c927 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Oct 2019 17:16:26 +0900 Subject: [PATCH 25/40] Avoid using CreateChildDependencies with a *child* bindable Don't do this. --- osu.Game/Overlays/BeatmapSet/Header.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 0e3d29c25b..7b42e7e459 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -50,6 +50,9 @@ namespace osu.Game.Overlays.BeatmapSet private readonly LoadingAnimation loading; + [Cached(typeof(IBindable))] + private readonly Bindable ruleset = new Bindable(); + public Header() { ExternalLinkButton externalLink; @@ -80,6 +83,7 @@ namespace osu.Game.Overlays.BeatmapSet }, RulesetSelector = new BeatmapRulesetSelector { + Current = ruleset, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, } @@ -222,13 +226,6 @@ namespace osu.Game.Overlays.BeatmapSet }; } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs>(RulesetSelector.Current); - return dependencies; - } - [BackgroundDependencyLoader] private void load(OsuColour colours) { From ba65d0e4ee712fcc1f87b3f07205db05c1406c26 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Thu, 31 Oct 2019 12:39:09 +0000 Subject: [PATCH 26/40] Force ordering of issue templates --- .github/ISSUE_TEMPLATE/{mobile-issues.md => 00-mobile-issues.md} | 0 .github/ISSUE_TEMPLATE/{bug-issues.md => 01-bug-issues.md} | 0 .github/ISSUE_TEMPLATE/{crash-issues.md => 02-crash-issues.md} | 0 .../{missing-for-live-issues.md => 03-missing-for-live.md} | 0 .../{feature-request-issues.md => 04-feature-request-issues.md} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename .github/ISSUE_TEMPLATE/{mobile-issues.md => 00-mobile-issues.md} (100%) rename .github/ISSUE_TEMPLATE/{bug-issues.md => 01-bug-issues.md} (100%) rename .github/ISSUE_TEMPLATE/{crash-issues.md => 02-crash-issues.md} (100%) rename .github/ISSUE_TEMPLATE/{missing-for-live-issues.md => 03-missing-for-live.md} (100%) rename .github/ISSUE_TEMPLATE/{feature-request-issues.md => 04-feature-request-issues.md} (100%) diff --git a/.github/ISSUE_TEMPLATE/mobile-issues.md b/.github/ISSUE_TEMPLATE/00-mobile-issues.md similarity index 100% rename from .github/ISSUE_TEMPLATE/mobile-issues.md rename to .github/ISSUE_TEMPLATE/00-mobile-issues.md diff --git a/.github/ISSUE_TEMPLATE/bug-issues.md b/.github/ISSUE_TEMPLATE/01-bug-issues.md similarity index 100% rename from .github/ISSUE_TEMPLATE/bug-issues.md rename to .github/ISSUE_TEMPLATE/01-bug-issues.md diff --git a/.github/ISSUE_TEMPLATE/crash-issues.md b/.github/ISSUE_TEMPLATE/02-crash-issues.md similarity index 100% rename from .github/ISSUE_TEMPLATE/crash-issues.md rename to .github/ISSUE_TEMPLATE/02-crash-issues.md diff --git a/.github/ISSUE_TEMPLATE/missing-for-live-issues.md b/.github/ISSUE_TEMPLATE/03-missing-for-live.md similarity index 100% rename from .github/ISSUE_TEMPLATE/missing-for-live-issues.md rename to .github/ISSUE_TEMPLATE/03-missing-for-live.md diff --git a/.github/ISSUE_TEMPLATE/feature-request-issues.md b/.github/ISSUE_TEMPLATE/04-feature-request-issues.md similarity index 100% rename from .github/ISSUE_TEMPLATE/feature-request-issues.md rename to .github/ISSUE_TEMPLATE/04-feature-request-issues.md From 08b1631dbbfe496c0df15ad8aa2632dfa20b8e9f Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Thu, 31 Oct 2019 12:42:25 +0000 Subject: [PATCH 27/40] Add issue template config --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..69baeee60c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: osu!stable issues + url: https://github.com/ppy/osu-stable-issues + about: For issues regarding osu!stable (not osu!lazer), open them here. From 3ada1510d04f635ae36050060b8534f66c5e2a08 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Thu, 31 Oct 2019 13:09:36 +0000 Subject: [PATCH 28/40] Remove 'missing-for-live.md' --- ...ture-request-issues.md => 03-feature-request-issues.md} | 0 .github/ISSUE_TEMPLATE/03-missing-for-live.md | 7 ------- 2 files changed, 7 deletions(-) rename .github/ISSUE_TEMPLATE/{04-feature-request-issues.md => 03-feature-request-issues.md} (100%) delete mode 100644 .github/ISSUE_TEMPLATE/03-missing-for-live.md diff --git a/.github/ISSUE_TEMPLATE/04-feature-request-issues.md b/.github/ISSUE_TEMPLATE/03-feature-request-issues.md similarity index 100% rename from .github/ISSUE_TEMPLATE/04-feature-request-issues.md rename to .github/ISSUE_TEMPLATE/03-feature-request-issues.md diff --git a/.github/ISSUE_TEMPLATE/03-missing-for-live.md b/.github/ISSUE_TEMPLATE/03-missing-for-live.md deleted file mode 100644 index 5822da9c65..0000000000 --- a/.github/ISSUE_TEMPLATE/03-missing-for-live.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: Missing for Live -about: Features which are available in osu!stable but not yet in osu!lazer. ---- -**Describe the missing feature:** - -**Proposal designs of the feature:** From 0171b2ae7c0882e2d0ad7e499d4e4369b580af6b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 1 Nov 2019 12:10:03 +0900 Subject: [PATCH 29/40] Fix scrolling hitobjects expiring too soon --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index e00597dd56..857929ff9e 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -13,12 +13,6 @@ namespace osu.Game.Rulesets.UI.Scrolling { public class ScrollingHitObjectContainer : HitObjectContainer { - /// - /// A multiplier applied to the length of the scrolling area to determine a safe default lifetime end for hitobjects. - /// This is only used to limit the lifetime end within reason, as proper lifetime management should be implemented on hitobjects themselves. - /// - private const float safe_lifetime_end_multiplier = 2; - private readonly IBindable timeRange = new BindableDouble(); private readonly IBindable direction = new Bindable(); @@ -123,28 +117,22 @@ namespace osu.Game.Rulesets.UI.Scrolling if (cached.IsValid) return; - double endTime = hitObject.HitObject.StartTime; - if (hitObject.HitObject is IHasEndTime e) { - endTime = e.EndTime; - switch (direction.Value) { case ScrollingDirection.Up: case ScrollingDirection.Down: - hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime, timeRange.Value, scrollLength); + hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, e.EndTime, timeRange.Value, scrollLength); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime, timeRange.Value, scrollLength); + hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, e.EndTime, timeRange.Value, scrollLength); break; } } - hitObject.LifetimeEnd = scrollingInfo.Algorithm.TimeAt(scrollLength * safe_lifetime_end_multiplier, endTime, timeRange.Value, scrollLength); - foreach (var obj in hitObject.NestedHitObjects) { computeInitialStateRecursive(obj); From ac02bb005d982603c55002d8212af592453a584d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 14:11:18 +0900 Subject: [PATCH 30/40] Fix GameplayClockContainer operating on beatmap's track after scren exited --- osu.Game/Screens/Play/GameplayClockContainer.cs | 15 ++++++++++++++- osu.Game/Screens/Play/Player.cs | 4 ++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 6a03271b86..f2efbe6073 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -29,7 +30,7 @@ namespace osu.Game.Screens.Play /// /// The original source (usually a 's track). /// - private readonly IAdjustableClock sourceClock; + private IAdjustableClock sourceClock; public readonly BindableBool IsPaused = new BindableBool(); @@ -153,6 +154,18 @@ namespace osu.Game.Screens.Play IsPaused.Value = true; } + /// + /// Changes the backing clock to avoid using the originally provided beatmap's track. + /// + public void StopUsingBeatmapClock() + { + if (sourceClock != beatmap.Track) + return; + + sourceClock = new TrackVirtual(beatmap.Track.Length); + adjustableClock.ChangeSource(sourceClock); + } + public void ResetLocalAdjustments() { // In the case of replays, we may have changed the playback rate. diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0b363eac4d..4820c62da3 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -527,6 +527,10 @@ namespace osu.Game.Screens.Play GameplayClockContainer.ResetLocalAdjustments(); + // GameplayClockContainer performs seeks / start / stop operations on the beatmap's track. + // as we are no longer the current screen, we cannot guarantee the track is still usable. + GameplayClockContainer.StopUsingBeatmapClock(); + fadeOut(); return base.OnExiting(next); } From dcc8f6e82799b3fe7055068b446780ad5ed76113 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 14:43:52 +0900 Subject: [PATCH 31/40] Better group cancel conditional --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 7eccde4555..280ebca651 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -446,9 +446,9 @@ namespace osu.Game.Screens.Play if (IsResuming) { DrawableRuleset.CancelResume(); + IsResuming = false; } - IsResuming = false; GameplayClockContainer.Stop(); PauseOverlay.Show(); lastPauseActionTime = GameplayClockContainer.GameplayClock.CurrentTime; From 05002ea3e8cd308e46e8147f909920ebd56300b3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 14:50:38 +0900 Subject: [PATCH 32/40] Move Show/Hide code to PopIn/PopOut --- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 8347d255fa..aecfac3b70 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -38,9 +38,10 @@ namespace osu.Game.Rulesets.Osu.UI }); } - public override void Show() + protected override void PopIn() { - base.Show(); + base.PopIn(); + GameplayCursor.ActiveCursor.Hide(); cursorScaleContainer.MoveTo(GameplayCursor.ActiveCursor.Position); clickToResumeCursor.Appear(); @@ -55,13 +56,13 @@ namespace osu.Game.Rulesets.Osu.UI } } - public override void Hide() + protected override void PopOut() { + base.PopOut(); + localCursorContainer?.Expire(); localCursorContainer = null; - GameplayCursor.ActiveCursor.Show(); - - base.Hide(); + GameplayCursor?.ActiveCursor.Show(); } protected override bool OnHover(HoverEvent e) => true; From 14fec6f1f35e4cf9e9a0e65a535e407c68ba9ed5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 15:06:36 +0900 Subject: [PATCH 33/40] Move ReplayDownloadButton to correct namespace --- .../Visual/Gameplay/TestSceneReplayDownloadButton.cs | 2 +- osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs | 1 + .../{Play => Ranking/Pages}/ReplayDownloadButton.cs | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) rename osu.Game/Screens/{Play => Ranking/Pages}/ReplayDownloadButton.cs (98%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs index 0dfcda122f..4c870e04f5 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs @@ -7,11 +7,11 @@ using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; -using osu.Game.Screens.Play; using osu.Game.Users; using osuTK; using System; using System.Collections.Generic; +using osu.Game.Screens.Ranking.Pages; namespace osu.Game.Tests.Visual.Gameplay { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs index f3c8f89db7..c4b42f6356 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs @@ -26,6 +26,7 @@ namespace osu.Game.Tests.Visual.Gameplay typeof(Results), typeof(ResultsPage), typeof(ScoreResultsPage), + typeof(ReplayDownloadButton), typeof(LocalLeaderboardPage) }; diff --git a/osu.Game/Screens/Play/ReplayDownloadButton.cs b/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs similarity index 98% rename from osu.Game/Screens/Play/ReplayDownloadButton.cs rename to osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs index 290e00f287..c8f4ecd2d5 100644 --- a/osu.Game/Screens/Play/ReplayDownloadButton.cs +++ b/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs @@ -4,12 +4,12 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Online; -using osu.Game.Scoring; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Graphics.UserInterface; +using osu.Game.Online; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Scoring; -namespace osu.Game.Screens.Play +namespace osu.Game.Screens.Ranking.Pages { public class ReplayDownloadButton : DownloadTrackingComposite { From e23ea94383e293c26764125637ef4627232f436f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 15:33:38 +0900 Subject: [PATCH 34/40] Add one more level of null check --- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index aecfac3b70..3b18e41f30 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.UI localCursorContainer?.Expire(); localCursorContainer = null; - GameplayCursor?.ActiveCursor.Show(); + GameplayCursor?.ActiveCursor?.Show(); } protected override bool OnHover(HoverEvent e) => true; From 84d17f3702bdf25f37a1bfffa34a216a8ab031f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 15:32:06 +0900 Subject: [PATCH 35/40] Add retry button --- .../Gameplay/TestSceneReplayDownloadButton.cs | 2 - .../Visual/Gameplay/TestSceneResults.cs | 2 +- osu.Game/Screens/Play/Player.cs | 8 +-- .../Ranking/Pages/ReplayDownloadButton.cs | 2 + osu.Game/Screens/Ranking/Pages/RetryButton.cs | 59 +++++++++++++++++++ .../Screens/Ranking/Pages/ScoreResultsPage.cs | 11 +++- 6 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 osu.Game/Screens/Ranking/Pages/RetryButton.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs index 4c870e04f5..7b22fedbd5 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs @@ -8,7 +8,6 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; using osu.Game.Users; -using osuTK; using System; using System.Collections.Generic; using osu.Game.Screens.Ranking.Pages; @@ -42,7 +41,6 @@ namespace osu.Game.Tests.Visual.Gameplay { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(80, 40), }; }); } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs index c4b42f6356..bf26892539 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs @@ -22,10 +22,10 @@ namespace osu.Game.Tests.Visual.Gameplay public override IReadOnlyList RequiredTypes => new[] { - typeof(ScoreInfo), typeof(Results), typeof(ResultsPage), typeof(ScoreResultsPage), + typeof(RetryButton), typeof(ReplayDownloadButton), typeof(LocalLeaderboardPage) }; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0b363eac4d..38068ec751 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -30,6 +30,7 @@ using osu.Game.Users; namespace osu.Game.Screens.Play { + [Cached] public class Player : ScreenWithBeatmapBackground { public override bool AllowBackButton => false; // handled by HoldForMenuButton @@ -313,12 +314,11 @@ namespace osu.Game.Screens.Play public void Restart() { - if (!this.IsCurrentScreen()) return; - sampleRestart?.Play(); - RestartRequested?.Invoke(); - performImmediateExit(); + + if (this.IsCurrentScreen()) + performImmediateExit(); } private ScheduledDelegate completionProgressDelegate; diff --git a/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs b/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs index c8f4ecd2d5..73c647d6fa 100644 --- a/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs +++ b/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs @@ -8,6 +8,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Scoring; +using osuTK; namespace osu.Game.Screens.Ranking.Pages { @@ -33,6 +34,7 @@ namespace osu.Game.Screens.Ranking.Pages public ReplayDownloadButton(ScoreInfo score) : base(score) { + Size = new Vector2(50, 30); } [BackgroundDependencyLoader(true)] diff --git a/osu.Game/Screens/Ranking/Pages/RetryButton.cs b/osu.Game/Screens/Ranking/Pages/RetryButton.cs new file mode 100644 index 0000000000..c4f63b265d --- /dev/null +++ b/osu.Game/Screens/Ranking/Pages/RetryButton.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Screens; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Play; +using osuTK; + +namespace osu.Game.Screens.Ranking.Pages +{ + public class RetryButton : OsuAnimatedButton + { + private readonly Box background; + + [Resolved(canBeNull: true)] + private Player player { get; set; } + + public RetryButton() + { + Size = new Vector2(50, 30); + + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Depth = float.MaxValue + }, + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(13), + Icon = FontAwesome.Solid.ArrowCircleLeft, + }, + }; + + TooltipText = "Retry"; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Green; + + if (player != null) + Action = () => + { + player.Restart(); + player.MakeCurrent(); + }; + } + } +} diff --git a/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs b/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs index 56ae069a26..27cea99f1c 100644 --- a/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs +++ b/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs @@ -169,12 +169,19 @@ namespace osu.Game.Screens.Ranking.Pages }, }, }, - new ReplayDownloadButton(score) + new FillFlowContainer { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Margin = new MarginPadding { Bottom = 10 }, - Size = new Vector2(50, 30), + Spacing = new Vector2(5), + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new ReplayDownloadButton(score), + new RetryButton() + } }, }; From c532f7765737b6dfd9e7609eba0dde8fddc324ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 15:49:36 +0900 Subject: [PATCH 36/40] Add hold-to-retry support to results --- osu.Game/Screens/Ranking/Results.cs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index cac26b3dbf..a7ff1fe6a0 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -19,6 +19,7 @@ using osu.Game.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; using osu.Game.Scoring; +using osu.Game.Screens.Play; namespace osu.Game.Screens.Ranking { @@ -34,6 +35,9 @@ namespace osu.Game.Screens.Ranking private ResultModeTabControl modeChangeButtons; + [Resolved(canBeNull: true)] + private Player player { get; set; } + public override bool DisallowExternalBeatmapRulesetChanges => true; protected readonly ScoreInfo Score; @@ -100,10 +104,7 @@ namespace osu.Game.Screens.Ranking public override bool OnExiting(IScreen next) { - allCircles.ForEach(c => - { - c.ScaleTo(0, transition_time, Easing.OutSine); - }); + allCircles.ForEach(c => { c.ScaleTo(0, transition_time, Easing.OutSine); }); Background.ScaleTo(1f, transition_time / 4, Easing.OutQuint); @@ -253,7 +254,17 @@ namespace osu.Game.Screens.Ranking } } } - } + }, + new HotkeyRetryOverlay + { + Action = () => + { + if (!this.IsCurrentScreen()) return; + + player.Restart(); + player.MakeCurrent(); + }, + }, }; var pages = CreateResultPages(); From 14453da1d2b254af738c322f9fd9ba25bb078b0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 15:51:10 +0900 Subject: [PATCH 37/40] Centralise MakeCurrent call --- osu.Game/Screens/Play/Player.cs | 2 ++ osu.Game/Screens/Ranking/Pages/RetryButton.cs | 7 +------ osu.Game/Screens/Ranking/Results.cs | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 38068ec751..769688e829 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -319,6 +319,8 @@ namespace osu.Game.Screens.Play if (this.IsCurrentScreen()) performImmediateExit(); + else + this.MakeCurrent(); } private ScheduledDelegate completionProgressDelegate; diff --git a/osu.Game/Screens/Ranking/Pages/RetryButton.cs b/osu.Game/Screens/Ranking/Pages/RetryButton.cs index c4f63b265d..2a281224c1 100644 --- a/osu.Game/Screens/Ranking/Pages/RetryButton.cs +++ b/osu.Game/Screens/Ranking/Pages/RetryButton.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; -using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Play; @@ -49,11 +48,7 @@ namespace osu.Game.Screens.Ranking.Pages background.Colour = colours.Green; if (player != null) - Action = () => - { - player.Restart(); - player.MakeCurrent(); - }; + Action = () => player.Restart(); } } } diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index a7ff1fe6a0..ca2ee5adae 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -262,7 +262,6 @@ namespace osu.Game.Screens.Ranking if (!this.IsCurrentScreen()) return; player.Restart(); - player.MakeCurrent(); }, }, }; From daa0ebe2b57916f5408cdd5b3dbc1b0b6591e9f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 15:51:45 +0900 Subject: [PATCH 38/40] Add xmldoc --- osu.Game/Screens/Play/Player.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 769688e829..f97114f929 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -312,6 +312,10 @@ namespace osu.Game.Screens.Play this.Exit(); } + /// + /// Restart gameplay via a parent . + /// This can be called from a child screen in order to trigger the restart process. + /// public void Restart() { sampleRestart?.Play(); From 156d0ae9b91c1bd6ea03a7b753807b0bcb4260a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Nov 2019 16:08:44 +0900 Subject: [PATCH 39/40] Remove braces Co-Authored-By: Salman Ahmed --- osu.Game/Screens/Ranking/Results.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index ca2ee5adae..d89932e105 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -104,7 +104,7 @@ namespace osu.Game.Screens.Ranking public override bool OnExiting(IScreen next) { - allCircles.ForEach(c => { c.ScaleTo(0, transition_time, Easing.OutSine); }); + allCircles.ForEach(c => c.ScaleTo(0, transition_time, Easing.OutSine)); Background.ScaleTo(1f, transition_time / 4, Easing.OutQuint); From 5be7d439ae2f149772372bdce9356c1d88163764 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 2 Nov 2019 10:32:23 +0900 Subject: [PATCH 40/40] Add null check for nullable dependency --- osu.Game/Screens/Ranking/Results.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index d89932e105..3640197dad 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -261,7 +261,7 @@ namespace osu.Game.Screens.Ranking { if (!this.IsCurrentScreen()) return; - player.Restart(); + player?.Restart(); }, }, };