From 18b4317e99921e133aed5549a00e0b31445a63cf Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 1 Dec 2022 11:57:50 +0100 Subject: [PATCH 01/88] Create Basic V2 footer and test --- .../SongSelect/TestSceneSongSelectFooterV2.cs | 29 ++++++++++++++ osu.Game/Screens/Select/FooterV2/FooterV2.cs | 39 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs create mode 100644 osu.Game/Screens/Select/FooterV2/FooterV2.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs new file mode 100644 index 0000000000..d61c86b69b --- /dev/null +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs @@ -0,0 +1,29 @@ +// 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.Graphics; +using osu.Game.Screens.Select.FooterV2; + +namespace osu.Game.Tests.Visual.SongSelect +{ + public partial class TestSceneSongSelectFooterV2 : OsuManualInputManagerTestScene + { + [SetUp] + public void SetUp() => Schedule(() => + { + FooterV2 footer; + + Child = footer = new FooterV2 + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }; + }); + + [Test] + public void TestBasic() + { + } + } +} diff --git a/osu.Game/Screens/Select/FooterV2/FooterV2.cs b/osu.Game/Screens/Select/FooterV2/FooterV2.cs new file mode 100644 index 0000000000..10050e24fc --- /dev/null +++ b/osu.Game/Screens/Select/FooterV2/FooterV2.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Select.FooterV2 +{ + public partial class FooterV2 : CompositeDrawable + { + //Should be 60, setting to 50 for now for the sake of matching the current BackButton height. + private const int height = 50; + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + RelativeSizeAxes = Axes.X; + Height = height; + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colour.B5 + } + }; + } + + protected override bool OnMouseDown(MouseDownEvent e) => true; + + protected override bool OnClick(ClickEvent e) => true; + + protected override bool OnHover(HoverEvent e) => true; + } +} From 774eb178a19ca8689f5eb6f5306d229bbc385bbc Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 1 Dec 2022 13:13:37 +0100 Subject: [PATCH 02/88] Add basic button design and footer button addition flow --- .../SongSelect/TestSceneSongSelectFooterV2.cs | 2 + .../Screens/Select/FooterV2/FooterButtonV2.cs | 65 +++++++++++++++++++ osu.Game/Screens/Select/FooterV2/FooterV2.cs | 51 +++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs index d61c86b69b..5a7797b3da 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs @@ -19,6 +19,8 @@ namespace osu.Game.Tests.Visual.SongSelect Anchor = Anchor.Centre, Origin = Anchor.Centre }; + + footer.AddButton(new FooterButtonV2()); }); [Test] diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs new file mode 100644 index 0000000000..daad52eb5e --- /dev/null +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -0,0 +1,65 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Graphics.Containers; +using osu.Game.Input.Bindings; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Screens.Select.FooterV2 +{ + public partial class FooterButtonV2 : OsuClickableContainer, IKeyBindingHandler + { + private const int button_height = 120; + private const int button_width = 140; + private const int corner_radius = 10; + + public const float SHEAR_WIDTH = 16; + + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + + protected static readonly Vector2 SHEAR = new Vector2(SHEAR_WIDTH / button_height, 0); + + [BackgroundDependencyLoader] + private void load() + { + Shear = SHEAR; + Size = new Vector2(button_width, button_height); + Masking = true; + CornerRadius = corner_radius; + InternalChildren = new Drawable[] + { + new Box + { + Colour = colourProvider.Background3, + RelativeSizeAxes = Axes.Both + }, + + //For elements that should not be sheared. + new Container + { + Shear = -SHEAR + } + }; + } + + public Action Hovered = null!; + public Action HoverLost = null!; + public GlobalAction? Hotkey; + + public bool OnPressed(KeyBindingPressEvent e) + { + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) { } + } +} diff --git a/osu.Game/Screens/Select/FooterV2/FooterV2.cs b/osu.Game/Screens/Select/FooterV2/FooterV2.cs index 10050e24fc..54b2f08eda 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterV2.cs @@ -1,12 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osuTK; namespace osu.Game.Screens.Select.FooterV2 { @@ -14,6 +17,33 @@ namespace osu.Game.Screens.Select.FooterV2 { //Should be 60, setting to 50 for now for the sake of matching the current BackButton height. private const int height = 50; + private const int padding = 80; + + private readonly List overlays = new List(); + + public void AddButton(FooterButtonV2 button, OverlayContainer? overlay = null) + { + if (overlay != null) + { + overlays.Add(overlay); + button.Action = () => showOverlay(overlay); + } + + buttons.Add(button); + } + + private void showOverlay(OverlayContainer overlay) + { + foreach (var o in overlays) + { + if (o == overlay) + o.ToggleVisibility(); + else + o.Hide(); + } + } + + private FillFlowContainer buttons = null!; [BackgroundDependencyLoader] private void load(OsuColour colour) @@ -26,6 +56,27 @@ namespace osu.Game.Screens.Select.FooterV2 { RelativeSizeAxes = Axes.Both, Colour = colour.B5 + }, + new FillFlowContainer + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Position = new Vector2(TwoLayerButton.SIZE_EXTENDED.X + padding, 40), + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(padding, 0), + Children = new Drawable[] + { + buttons = new FillFlowContainer + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(-FooterButtonV2.SHEAR_WIDTH, 5), + AutoSizeAxes = Axes.Both + } + } } }; } From 1530495e7c8e86d47f0bb82d914d116c1c3fc847 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 1 Dec 2022 15:34:09 +0100 Subject: [PATCH 03/88] Add button "accent" colour, bottom bar, icon, text --- .../SongSelect/TestSceneSongSelectFooterV2.cs | 4 +- .../Select/FooterV2/FooterButtonFreeModsV2.cs | 21 ++++++ .../Select/FooterV2/FooterButtonModsV2.cs | 20 ++++++ .../Select/FooterV2/FooterButtonOptionsV2.cs | 20 ++++++ .../Select/FooterV2/FooterButtonRandomV2.cs | 20 ++++++ .../Screens/Select/FooterV2/FooterButtonV2.cs | 72 ++++++++++++++++++- osu.Game/Screens/Select/FooterV2/FooterV2.cs | 2 +- 7 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Screens/Select/FooterV2/FooterButtonFreeModsV2.cs create mode 100644 osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs create mode 100644 osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs create mode 100644 osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs index 5a7797b3da..b23739e0ca 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs @@ -20,7 +20,9 @@ namespace osu.Game.Tests.Visual.SongSelect Origin = Anchor.Centre }; - footer.AddButton(new FooterButtonV2()); + footer.AddButton(new FooterButtonModsV2()); + footer.AddButton(new FooterButtonRandomV2()); + footer.AddButton(new FooterButtonOptionsV2()); }); [Test] diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonFreeModsV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonFreeModsV2.cs new file mode 100644 index 0000000000..523a2afa36 --- /dev/null +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonFreeModsV2.cs @@ -0,0 +1,21 @@ +// 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.Sprites; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Select.FooterV2 +{ + public partial class FooterButtonFreeModsV2 : FooterButtonV2 + { + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + //No design exists for this button! + Icon = FontAwesome.Solid.ExpandArrowsAlt; + Text = "Freemods"; + AccentColour = colour.Yellow; + } + } +} diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs new file mode 100644 index 0000000000..fe6ebd5506 --- /dev/null +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; + +namespace osu.Game.Screens.Select.FooterV2 +{ + public partial class FooterButtonModsV2 : FooterButtonV2 + { + [BackgroundDependencyLoader] + private void load() + { + Text = "Mods"; + Icon = FontAwesome.Solid.ArrowsAlt; + AccentColour = Colour4.FromHex("#B2FF66"); + } + } +} diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs new file mode 100644 index 0000000000..211feb0b53 --- /dev/null +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; + +namespace osu.Game.Screens.Select.FooterV2 +{ + public partial class FooterButtonOptionsV2 : FooterButtonV2 + { + [BackgroundDependencyLoader] + private void load() + { + Text = "Options"; + Icon = FontAwesome.Solid.Cog; + AccentColour = Colour4.FromHex("#8C66FF"); + } + } +} diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs new file mode 100644 index 0000000000..ccc5caa049 --- /dev/null +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; + +namespace osu.Game.Screens.Select.FooterV2 +{ + public partial class FooterButtonRandomV2 : FooterButtonV2 + { + [BackgroundDependencyLoader] + private void load() + { + Text = "Random"; + Icon = FontAwesome.Solid.Random; + AccentColour = Colour4.FromHex("#66CCFF"); + } + } +} diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index daad52eb5e..264db1c770 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -5,10 +5,13 @@ using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; using osu.Game.Overlays; using osuTK; @@ -23,14 +26,47 @@ namespace osu.Game.Screens.Select.FooterV2 public const float SHEAR_WIDTH = 16; + protected static readonly Vector2 SHEAR = new Vector2(SHEAR_WIDTH / button_height, 0); + [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); - protected static readonly Vector2 SHEAR = new Vector2(SHEAR_WIDTH / button_height, 0); + private Colour4 buttonAccentColour; + + protected Colour4 AccentColour + { + set + { + buttonAccentColour = value; + bar.Colour = buttonAccentColour; + icon.Colour = buttonAccentColour; + } + } + + protected IconUsage Icon + { + set => icon.Icon = value; + } + + protected string Text + { + set => text.Text = value; + } + + private SpriteIcon icon = null!; + private OsuSpriteText text = null!; + private Box bar = null!; [BackgroundDependencyLoader] private void load() { + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 5, + Roundness = 10, + Colour = Colour4.Black.Opacity(0.25f) + }; Shear = SHEAR; Size = new Vector2(button_width, button_height); Masking = true; @@ -46,7 +82,39 @@ namespace osu.Game.Screens.Select.FooterV2 //For elements that should not be sheared. new Container { - Shear = -SHEAR + Shear = -SHEAR, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + icon = new SpriteIcon + { + //We want to offset this by the same amount as the text for aesthetic purposes + Position = new Vector2(-SHEAR_WIDTH * (52f / button_height), 12), + Size = new Vector2(20), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + }, + text = new OsuSpriteText + { + Position = new Vector2(-SHEAR_WIDTH * (52f / button_height), 42), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + }, + new Container + { + //Offset the bar to centre it with consideration for the shearing + Position = new Vector2(-SHEAR_WIDTH * (80f / button_height), -40), + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + Size = new Vector2(120, 6), + Masking = true, + CornerRadius = 3, + Child = bar = new Box + { + RelativeSizeAxes = Axes.Both, + } + } + } } }; } diff --git a/osu.Game/Screens/Select/FooterV2/FooterV2.cs b/osu.Game/Screens/Select/FooterV2/FooterV2.cs index 54b2f08eda..719512b1ab 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterV2.cs @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Select.FooterV2 Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Direction = FillDirection.Horizontal, - Spacing = new Vector2(-FooterButtonV2.SHEAR_WIDTH, 5), + Spacing = new Vector2(-FooterButtonV2.SHEAR_WIDTH + 7, 0), AutoSizeAxes = Axes.Both } } From d7cea51551e403c606c0c8017589576bb8e234dd Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 1 Dec 2022 16:29:52 +0100 Subject: [PATCH 04/88] Add functionality of Random button --- .../SongSelect/TestSceneSongSelectFooterV2.cs | 78 +++++++++- .../Select/FooterV2/FooterButtonRandomV2.cs | 142 +++++++++++++++++- .../Screens/Select/FooterV2/FooterButtonV2.cs | 59 ++++++-- 3 files changed, 266 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs index b23739e0ca..4ca193a2c6 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs @@ -1,17 +1,29 @@ // 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.Graphics; +using osu.Framework.Testing; using osu.Game.Screens.Select.FooterV2; +using osuTK; +using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneSongSelectFooterV2 : OsuManualInputManagerTestScene { + private FooterButtonRandomV2 randomButton = null!; + + private bool nextRandomCalled; + private bool previousRandomCalled; + [SetUp] public void SetUp() => Schedule(() => { + nextRandomCalled = false; + previousRandomCalled = false; + FooterV2 footer; Child = footer = new FooterV2 @@ -21,13 +33,75 @@ namespace osu.Game.Tests.Visual.SongSelect }; footer.AddButton(new FooterButtonModsV2()); - footer.AddButton(new FooterButtonRandomV2()); + footer.AddButton(randomButton = new FooterButtonRandomV2 + { + NextRandom = () => nextRandomCalled = true, + PreviousRandom = () => previousRandomCalled = true + }); footer.AddButton(new FooterButtonOptionsV2()); + + InputManager.MoveMouseTo(Vector2.Zero); }); [Test] - public void TestBasic() + public void TestState() { + AddRepeatStep("toggle options state", () => this.ChildrenOfType().Last().Enabled.Toggle(), 20); + } + + [Test] + public void TestFooterRandom() + { + AddStep("press F2", () => InputManager.Key(Key.F2)); + AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled); + } + + [Test] + public void TestFooterRandomViaMouse() + { + AddStep("click button", () => + { + InputManager.MoveMouseTo(randomButton); + InputManager.Click(MouseButton.Left); + }); + AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled); + } + + [Test] + public void TestFooterRewind() + { + AddStep("press Shift+F2", () => + { + InputManager.PressKey(Key.LShift); + InputManager.PressKey(Key.F2); + InputManager.ReleaseKey(Key.F2); + InputManager.ReleaseKey(Key.LShift); + }); + AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); + } + + [Test] + public void TestFooterRewindViaShiftMouseLeft() + { + AddStep("shift + click button", () => + { + InputManager.PressKey(Key.LShift); + InputManager.MoveMouseTo(randomButton); + InputManager.Click(MouseButton.Left); + InputManager.ReleaseKey(Key.LShift); + }); + AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); + } + + [Test] + public void TestFooterRewindViaMouseRight() + { + AddStep("right click button", () => + { + InputManager.MoveMouseTo(randomButton); + InputManager.Click(MouseButton.Right); + }); + AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs index ccc5caa049..7da31c6dad 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs @@ -1,20 +1,160 @@ // 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.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Input.Bindings; +using osuTK; +using osuTK.Input; namespace osu.Game.Screens.Select.FooterV2 { public partial class FooterButtonRandomV2 : FooterButtonV2 { + public Action NextRandom { get; set; } = null!; + public Action PreviousRandom { get; set; } = null!; + + private Container persistentText = null!; + private OsuSpriteText randomSpriteText = null!; + private OsuSpriteText rewindSpriteText = null!; + private bool rewindSearch; + [BackgroundDependencyLoader] private void load() { - Text = "Random"; + //TODO: use https://fontawesome.com/icons/shuffle?s=solid&f=classic when local Fontawesome is updated Icon = FontAwesome.Solid.Random; AccentColour = Colour4.FromHex("#66CCFF"); + TextContainer.Add(persistentText = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AlwaysPresent = true, + AutoSizeAxes = Axes.Both, + Children = new[] + { + randomSpriteText = new OsuSpriteText + { + Font = OsuFont.TorusAlternate.With(size: 16), + AlwaysPresent = true, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "Random", + }, + rewindSpriteText = new OsuSpriteText + { + Font = OsuFont.TorusAlternate.With(size: 16), + AlwaysPresent = true, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "Rewind", + Alpha = 0f, + } + } + }); + + Action = () => + { + if (rewindSearch) + { + const double fade_time = 500; + + OsuSpriteText fallingRewind; + + TextContainer.Add(fallingRewind = new OsuSpriteText + { + Alpha = 0, + Text = rewindSpriteText.Text, + AlwaysPresent = true, // make sure the button is sized large enough to always show this + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre + }); + + fallingRewind.FadeOutFromOne(fade_time, Easing.In); + fallingRewind.MoveTo(Vector2.Zero).MoveTo(new Vector2(0, 10), fade_time, Easing.In); + fallingRewind.Expire(); + + persistentText.FadeInFromZero(fade_time, Easing.In); + + PreviousRandom.Invoke(); + } + else + { + NextRandom.Invoke(); + } + }; + } + + protected override bool OnKeyDown(KeyDownEvent e) + { + updateText(e.ShiftPressed); + return base.OnKeyDown(e); + } + + protected override void OnKeyUp(KeyUpEvent e) + { + updateText(e.ShiftPressed); + base.OnKeyUp(e); + } + + protected override bool OnClick(ClickEvent e) + { + try + { + // this uses OR to handle rewinding when clicks are triggered by other sources (i.e. right button in OnMouseUp). + rewindSearch |= e.ShiftPressed; + return base.OnClick(e); + } + finally + { + rewindSearch = false; + } + } + + protected override void OnMouseUp(MouseUpEvent e) + { + if (e.Button == MouseButton.Right) + { + rewindSearch = true; + TriggerClick(); + return; + } + + base.OnMouseUp(e); + } + + public override bool OnPressed(KeyBindingPressEvent e) + { + rewindSearch = e.Action == GlobalAction.SelectPreviousRandom; + + if (e.Action != GlobalAction.SelectNextRandom && e.Action != GlobalAction.SelectPreviousRandom) + { + return false; + } + + if (!e.Repeat) + TriggerClick(); + return true; + } + + public override void OnReleased(KeyBindingReleaseEvent e) + { + if (e.Action == GlobalAction.SelectPreviousRandom) + { + rewindSearch = false; + } + } + + private void updateText(bool rewind = false) + { + randomSpriteText.Alpha = rewind ? 0 : 1; + rewindSpriteText.Alpha = rewind ? 1 : 0; } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 264db1c770..5125aaa552 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -10,6 +10,8 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; @@ -48,13 +50,14 @@ namespace osu.Game.Screens.Select.FooterV2 set => icon.Icon = value; } - protected string Text + protected LocalisableString Text { set => text.Text = value; } + private SpriteText text = null!; private SpriteIcon icon = null!; - private OsuSpriteText text = null!; + protected Container TextContainer = null!; private Box bar = null!; [BackgroundDependencyLoader] @@ -86,6 +89,18 @@ namespace osu.Game.Screens.Select.FooterV2 RelativeSizeAxes = Axes.Both, Children = new Drawable[] { + TextContainer = new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Position = new Vector2(-SHEAR_WIDTH * (52f / button_height), 42), + AutoSizeAxes = Axes.Both, + Child = text = new OsuSpriteText + { + Font = OsuFont.TorusAlternate.With(size: 16), + AlwaysPresent = true + } + }, icon = new SpriteIcon { //We want to offset this by the same amount as the text for aesthetic purposes @@ -94,12 +109,6 @@ namespace osu.Game.Screens.Select.FooterV2 Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre }, - text = new OsuSpriteText - { - Position = new Vector2(-SHEAR_WIDTH * (52f / button_height), 42), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - }, new Container { //Offset the bar to centre it with consideration for the shearing @@ -123,11 +132,41 @@ namespace osu.Game.Screens.Select.FooterV2 public Action HoverLost = null!; public GlobalAction? Hotkey; - public bool OnPressed(KeyBindingPressEvent e) + protected override void UpdateAfterChildren() { + } + + protected override bool OnHover(HoverEvent e) + { + Hovered?.Invoke(); + + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + HoverLost?.Invoke(); + } + + protected override bool OnClick(ClickEvent e) + { + if (!Enabled.Value) + return true; + + return base.OnClick(e); + } + + public virtual bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == Hotkey && !e.Repeat) + { + TriggerClick(); + return true; + } + return false; } - public void OnReleased(KeyBindingReleaseEvent e) { } + public virtual void OnReleased(KeyBindingReleaseEvent e) { } } } From 55a21a75a4c30e255bf1d98486a16f87526c9cd6 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 1 Dec 2022 22:07:28 +0100 Subject: [PATCH 05/88] Add hover lightening --- .../Screens/Select/FooterV2/FooterButtonV2.cs | 24 +++++++++++++++---- osu.Game/Screens/Select/FooterV2/FooterV2.cs | 2 +- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 5125aaa552..81883700bd 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -59,6 +60,7 @@ namespace osu.Game.Screens.Select.FooterV2 private SpriteIcon icon = null!; protected Container TextContainer = null!; private Box bar = null!; + private Box backGroundBox = null!; [BackgroundDependencyLoader] private void load() @@ -76,7 +78,7 @@ namespace osu.Game.Screens.Select.FooterV2 CornerRadius = corner_radius; InternalChildren = new Drawable[] { - new Box + backGroundBox = new Box { Colour = colourProvider.Background3, RelativeSizeAxes = Axes.Both @@ -138,14 +140,21 @@ namespace osu.Game.Screens.Select.FooterV2 protected override bool OnHover(HoverEvent e) { - Hovered?.Invoke(); - + updateHover(true); return true; } protected override void OnHoverLost(HoverLostEvent e) { - HoverLost?.Invoke(); + updateHover(false); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (!Enabled.Value) + return true; + + return base.OnMouseDown(e); } protected override bool OnClick(ClickEvent e) @@ -168,5 +177,12 @@ namespace osu.Game.Screens.Select.FooterV2 } public virtual void OnReleased(KeyBindingReleaseEvent e) { } + + private void updateHover(bool hovered) + { + Colour4 targetColour = hovered ? colourProvider.Background3.Lighten(.3f) : colourProvider.Background3; + + backGroundBox.FadeColour(targetColour, 500, Easing.OutQuint); + } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterV2.cs b/osu.Game/Screens/Select/FooterV2/FooterV2.cs index 719512b1ab..82e6323507 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterV2.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.Select.FooterV2 { - public partial class FooterV2 : CompositeDrawable + public partial class FooterV2 : Container { //Should be 60, setting to 50 for now for the sake of matching the current BackButton height. private const int height = 50; From ea882f687433beabfe8858ac53f27c2beccdb157 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 1 Dec 2022 22:31:14 +0100 Subject: [PATCH 06/88] Add disabled button dimming. --- .../Screens/Select/FooterV2/FooterButtonV2.cs | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 81883700bd..26a0335baf 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.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 osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -130,23 +129,27 @@ namespace osu.Game.Screens.Select.FooterV2 }; } - public Action Hovered = null!; - public Action HoverLost = null!; + protected override void LoadComplete() + { + base.LoadComplete(); + Enabled.BindValueChanged(_ => updateDisplay(), true); + } + public GlobalAction? Hotkey; - protected override void UpdateAfterChildren() - { - } + private bool isHovered; protected override bool OnHover(HoverEvent e) { - updateHover(true); + isHovered = true; + updateDisplay(); return true; } protected override void OnHoverLost(HoverLostEvent e) { - updateHover(false); + isHovered = false; + updateDisplay(); } protected override bool OnMouseDown(MouseDownEvent e) @@ -178,11 +181,16 @@ namespace osu.Game.Screens.Select.FooterV2 public virtual void OnReleased(KeyBindingReleaseEvent e) { } - private void updateHover(bool hovered) + private void updateDisplay() { - Colour4 targetColour = hovered ? colourProvider.Background3.Lighten(.3f) : colourProvider.Background3; + if (!Enabled.Value) + { + backGroundBox.FadeColour(colourProvider.Background3.Darken(.3f)); + return; + } - backGroundBox.FadeColour(targetColour, 500, Easing.OutQuint); + //Hover logic. + backGroundBox.FadeColour(isHovered && Enabled.Value ? colourProvider.Background3.Lighten(.3f) : colourProvider.Background3, 500, Easing.OutQuint); } } } From c5bad816db30d851b86aafe33f2ff940789b370b Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 2 Dec 2022 18:44:21 +0100 Subject: [PATCH 07/88] Add button colouring whilst corresponding overlay is present --- .../SongSelect/TestSceneSongSelectFooterV2.cs | 47 +++++++++++++++++-- .../Screens/Select/FooterV2/FooterButtonV2.cs | 20 +++++++- osu.Game/Screens/Select/FooterV2/FooterV2.cs | 1 + 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs index 4ca193a2c6..a1ba8daf8e 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs @@ -3,8 +3,12 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Overlays; +using osu.Game.Overlays.Mods; using osu.Game.Screens.Select.FooterV2; using osuTK; using osuTK.Input; @@ -14,10 +18,13 @@ namespace osu.Game.Tests.Visual.SongSelect public partial class TestSceneSongSelectFooterV2 : OsuManualInputManagerTestScene { private FooterButtonRandomV2 randomButton = null!; + private FooterButtonModsV2 modsButton = null!; private bool nextRandomCalled; private bool previousRandomCalled; + private DummyOverlay overlay = null!; + [SetUp] public void SetUp() => Schedule(() => { @@ -26,13 +33,17 @@ namespace osu.Game.Tests.Visual.SongSelect FooterV2 footer; - Child = footer = new FooterV2 + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre + footer = new FooterV2 + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }, + overlay = new DummyOverlay() }; - footer.AddButton(new FooterButtonModsV2()); + footer.AddButton(modsButton = new FooterButtonModsV2(), overlay); footer.AddButton(randomButton = new FooterButtonRandomV2 { NextRandom = () => nextRandomCalled = true, @@ -41,6 +52,8 @@ namespace osu.Game.Tests.Visual.SongSelect footer.AddButton(new FooterButtonOptionsV2()); InputManager.MoveMouseTo(Vector2.Zero); + + overlay.Hide(); }); [Test] @@ -103,5 +116,31 @@ namespace osu.Game.Tests.Visual.SongSelect }); AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); } + + [Test] + public void TestOverlayPresent() + { + AddStep("Press F1", () => + { + InputManager.MoveMouseTo(modsButton); + InputManager.Click(MouseButton.Left); + }); + AddAssert("Overlay visible", () => overlay.State.Value == Visibility.Visible); + AddStep("Hide", () => overlay.Hide()); + } + + private partial class DummyOverlay : ShearedOverlayContainer + { + public DummyOverlay() + : base(OverlayColourScheme.Green) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Header.Title = "An overlay"; + } + } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 26a0335baf..7fb9bf42bd 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.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; @@ -25,9 +26,12 @@ namespace osu.Game.Screens.Select.FooterV2 private const int button_height = 120; private const int button_width = 140; private const int corner_radius = 10; + private const int transition_length = 500; public const float SHEAR_WIDTH = 16; + public Bindable OverlayState = new Bindable(); + protected static readonly Vector2 SHEAR = new Vector2(SHEAR_WIDTH / button_height, 0); [Cached] @@ -133,6 +137,7 @@ namespace osu.Game.Screens.Select.FooterV2 { base.LoadComplete(); Enabled.BindValueChanged(_ => updateDisplay(), true); + OverlayState.BindValueChanged(_ => updateDisplay()); } public GlobalAction? Hotkey; @@ -185,12 +190,23 @@ namespace osu.Game.Screens.Select.FooterV2 { if (!Enabled.Value) { - backGroundBox.FadeColour(colourProvider.Background3.Darken(.3f)); + backGroundBox.FadeColour(colourProvider.Background3.Darken(0.3f), transition_length, Easing.OutQuint); return; } + switch (OverlayState.Value) + { + case Visibility.Visible: + backGroundBox.FadeColour(buttonAccentColour.Darken(0.5f), transition_length, Easing.OutQuint); + return; + + case Visibility.Hidden: + backGroundBox.FadeColour(buttonAccentColour, transition_length, Easing.OutQuint); + break; + } + //Hover logic. - backGroundBox.FadeColour(isHovered && Enabled.Value ? colourProvider.Background3.Lighten(.3f) : colourProvider.Background3, 500, Easing.OutQuint); + backGroundBox.FadeColour(isHovered && Enabled.Value ? colourProvider.Background3.Lighten(.3f) : colourProvider.Background3, transition_length, Easing.OutQuint); } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterV2.cs b/osu.Game/Screens/Select/FooterV2/FooterV2.cs index 82e6323507..8ac26c2e58 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterV2.cs @@ -27,6 +27,7 @@ namespace osu.Game.Screens.Select.FooterV2 { overlays.Add(overlay); button.Action = () => showOverlay(overlay); + button.OverlayState.BindTo(overlay.State); } buttons.Add(button); From 7373d79ba6bd7e152d0918c0694a67968c74459c Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 2 Dec 2022 19:16:25 +0100 Subject: [PATCH 08/88] Use OsuColour instead of hex for button accent colour --- osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs | 6 +++--- osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs | 6 +++--- osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs index fe6ebd5506..daa1de2e7b 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs @@ -2,19 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; namespace osu.Game.Screens.Select.FooterV2 { public partial class FooterButtonModsV2 : FooterButtonV2 { [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colour) { Text = "Mods"; Icon = FontAwesome.Solid.ArrowsAlt; - AccentColour = Colour4.FromHex("#B2FF66"); + AccentColour = colour.Lime1; } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs index 211feb0b53..be0fdef9db 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs @@ -2,19 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; namespace osu.Game.Screens.Select.FooterV2 { public partial class FooterButtonOptionsV2 : FooterButtonV2 { [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colour) { Text = "Options"; Icon = FontAwesome.Solid.Cog; - AccentColour = Colour4.FromHex("#8C66FF"); + AccentColour = colour.Purple1; } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs index 7da31c6dad..3ecf616a16 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs @@ -26,11 +26,11 @@ namespace osu.Game.Screens.Select.FooterV2 private bool rewindSearch; [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colour) { //TODO: use https://fontawesome.com/icons/shuffle?s=solid&f=classic when local Fontawesome is updated Icon = FontAwesome.Solid.Random; - AccentColour = Colour4.FromHex("#66CCFF"); + AccentColour = colour.Blue1; TextContainer.Add(persistentText = new Container { Anchor = Anchor.Centre, From 407b0a0ad3c29948162df5eae5e230335f93de7b Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 19 Dec 2022 11:30:23 +0100 Subject: [PATCH 09/88] Address issues from Joehuu review --- .../Select/FooterV2/FooterButtonModsV2.cs | 2 +- .../Select/FooterV2/FooterButtonRandomV2.cs | 4 +-- .../Screens/Select/FooterV2/FooterButtonV2.cs | 30 +++++++++++-------- osu.Game/Screens/Select/FooterV2/FooterV2.cs | 11 ++----- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs index daa1de2e7b..b8c9f0b34b 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Select.FooterV2 private void load(OsuColour colour) { Text = "Mods"; - Icon = FontAwesome.Solid.ArrowsAlt; + Icon = FontAwesome.Solid.ExchangeAlt; AccentColour = colour.Lime1; } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs index 3ecf616a16..ebb9c4b6e5 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Select.FooterV2 { randomSpriteText = new OsuSpriteText { - Font = OsuFont.TorusAlternate.With(size: 16), + Font = OsuFont.TorusAlternate.With(size: 19), AlwaysPresent = true, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Select.FooterV2 }, rewindSpriteText = new OsuSpriteText { - Font = OsuFont.TorusAlternate.With(size: 16), + Font = OsuFont.TorusAlternate.With(size: 19), AlwaysPresent = true, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 7fb9bf42bd..d7d018afc3 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -23,12 +23,13 @@ namespace osu.Game.Screens.Select.FooterV2 { public partial class FooterButtonV2 : OsuClickableContainer, IKeyBindingHandler { - private const int button_height = 120; + private const int button_height = 90; private const int button_width = 140; private const int corner_radius = 10; private const int transition_length = 500; - public const float SHEAR_WIDTH = 16; + //Accounts for corner radius margin on bottom, would be 12 + public const float SHEAR_WIDTH = 13.5f; public Bindable OverlayState = new Bindable(); @@ -63,7 +64,7 @@ namespace osu.Game.Screens.Select.FooterV2 private SpriteIcon icon = null!; protected Container TextContainer = null!; private Box bar = null!; - private Box backGroundBox = null!; + private Box backgroundBox = null!; [BackgroundDependencyLoader] private void load() @@ -81,7 +82,7 @@ namespace osu.Game.Screens.Select.FooterV2 CornerRadius = corner_radius; InternalChildren = new Drawable[] { - backGroundBox = new Box + backgroundBox = new Box { Colour = colourProvider.Background3, RelativeSizeAxes = Axes.Both @@ -90,6 +91,8 @@ namespace osu.Game.Screens.Select.FooterV2 //For elements that should not be sheared. new Container { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, Shear = -SHEAR, RelativeSizeAxes = Axes.Both, Children = new Drawable[] @@ -98,18 +101,18 @@ namespace osu.Game.Screens.Select.FooterV2 { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Position = new Vector2(-SHEAR_WIDTH * (52f / button_height), 42), + Y = 42, AutoSizeAxes = Axes.Both, Child = text = new OsuSpriteText { - Font = OsuFont.TorusAlternate.With(size: 16), + //figma design says the size is 16, but due to the issues with font sizes 19 matches better + Font = OsuFont.TorusAlternate.With(size: 19), AlwaysPresent = true } }, icon = new SpriteIcon { - //We want to offset this by the same amount as the text for aesthetic purposes - Position = new Vector2(-SHEAR_WIDTH * (52f / button_height), 12), + Y = 12, Size = new Vector2(20), Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre @@ -117,7 +120,7 @@ namespace osu.Game.Screens.Select.FooterV2 new Container { //Offset the bar to centre it with consideration for the shearing - Position = new Vector2(-SHEAR_WIDTH * (80f / button_height), -40), + Position = new Vector2(-0.15f * 35, -10), Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, Size = new Vector2(120, 6), @@ -136,6 +139,7 @@ namespace osu.Game.Screens.Select.FooterV2 protected override void LoadComplete() { base.LoadComplete(); + Enabled.BindValueChanged(_ => updateDisplay(), true); OverlayState.BindValueChanged(_ => updateDisplay()); } @@ -190,23 +194,23 @@ namespace osu.Game.Screens.Select.FooterV2 { if (!Enabled.Value) { - backGroundBox.FadeColour(colourProvider.Background3.Darken(0.3f), transition_length, Easing.OutQuint); + backgroundBox.FadeColour(colourProvider.Background3.Darken(0.3f), transition_length, Easing.OutQuint); return; } switch (OverlayState.Value) { case Visibility.Visible: - backGroundBox.FadeColour(buttonAccentColour.Darken(0.5f), transition_length, Easing.OutQuint); + backgroundBox.FadeColour(buttonAccentColour.Darken(0.5f), transition_length, Easing.OutQuint); return; case Visibility.Hidden: - backGroundBox.FadeColour(buttonAccentColour, transition_length, Easing.OutQuint); + backgroundBox.FadeColour(buttonAccentColour, transition_length, Easing.OutQuint); break; } //Hover logic. - backGroundBox.FadeColour(isHovered && Enabled.Value ? colourProvider.Background3.Lighten(.3f) : colourProvider.Background3, transition_length, Easing.OutQuint); + backgroundBox.FadeColour(isHovered && Enabled.Value ? colourProvider.Background3.Lighten(.3f) : colourProvider.Background3, transition_length, Easing.OutQuint); } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterV2.cs b/osu.Game/Screens/Select/FooterV2/FooterV2.cs index 8ac26c2e58..7e2d9d6695 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterV2.cs @@ -6,14 +6,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osuTK; namespace osu.Game.Screens.Select.FooterV2 { - public partial class FooterV2 : Container + public partial class FooterV2 : InputBlockingContainer { //Should be 60, setting to 50 for now for the sake of matching the current BackButton height. private const int height = 50; @@ -62,7 +61,7 @@ namespace osu.Game.Screens.Select.FooterV2 { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Position = new Vector2(TwoLayerButton.SIZE_EXTENDED.X + padding, 40), + Position = new Vector2(TwoLayerButton.SIZE_EXTENDED.X + padding, 10), RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, Direction = FillDirection.Horizontal, @@ -81,11 +80,5 @@ namespace osu.Game.Screens.Select.FooterV2 } }; } - - protected override bool OnMouseDown(MouseDownEvent e) => true; - - protected override bool OnClick(ClickEvent e) => true; - - protected override bool OnHover(HoverEvent e) => true; } } From 626f4b0dfd0b22b02eaf3ab5c046a1597b62085b Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 19 Dec 2022 16:35:20 +0100 Subject: [PATCH 10/88] fix test failures, improve button logic --- .../Select/FooterV2/FooterButtonOptionsV2.cs | 2 + .../Select/FooterV2/FooterButtonRandomV2.cs | 3 +- .../Screens/Select/FooterV2/FooterButtonV2.cs | 57 +++++++------------ osu.Game/Screens/Select/FooterV2/FooterV2.cs | 2 + 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs index be0fdef9db..87cca0042a 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Input.Bindings; namespace osu.Game.Screens.Select.FooterV2 { @@ -15,6 +16,7 @@ namespace osu.Game.Screens.Select.FooterV2 Text = "Options"; Icon = FontAwesome.Solid.Cog; AccentColour = colour.Purple1; + Hotkey = GlobalAction.ToggleBeatmapOptions; } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs index ebb9c4b6e5..e3882588d9 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs @@ -73,7 +73,8 @@ namespace osu.Game.Screens.Select.FooterV2 Text = rewindSpriteText.Text, AlwaysPresent = true, // make sure the button is sized large enough to always show this Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre + Origin = Anchor.BottomCentre, + Font = OsuFont.TorusAlternate.With(size: 19), }); fallingRewind.FadeOutFromOne(fade_time, Easing.In); diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index d7d018afc3..ea4db1f8fa 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -60,14 +60,14 @@ namespace osu.Game.Screens.Select.FooterV2 set => text.Text = value; } - private SpriteText text = null!; - private SpriteIcon icon = null!; - protected Container TextContainer = null!; - private Box bar = null!; - private Box backgroundBox = null!; + private readonly SpriteText text; + private readonly SpriteIcon icon; - [BackgroundDependencyLoader] - private void load() + protected Container TextContainer; + private readonly Box bar; + private readonly Box backgroundBox; + + public FooterButtonV2() { EdgeEffect = new EdgeEffectParameters { @@ -146,46 +146,33 @@ namespace osu.Game.Screens.Select.FooterV2 public GlobalAction? Hotkey; - private bool isHovered; - protected override bool OnHover(HoverEvent e) { - isHovered = true; updateDisplay(); return true; } protected override void OnHoverLost(HoverLostEvent e) { - isHovered = false; updateDisplay(); } protected override bool OnMouseDown(MouseDownEvent e) { - if (!Enabled.Value) - return true; - - return base.OnMouseDown(e); + return !Enabled.Value || base.OnMouseDown(e); } protected override bool OnClick(ClickEvent e) { - if (!Enabled.Value) - return true; - - return base.OnClick(e); + return !Enabled.Value || base.OnClick(e); } public virtual bool OnPressed(KeyBindingPressEvent e) { - if (e.Action == Hotkey && !e.Repeat) - { - TriggerClick(); - return true; - } + if (e.Action != Hotkey || e.Repeat) return false; - return false; + TriggerClick(); + return true; } public virtual void OnReleased(KeyBindingReleaseEvent e) { } @@ -198,19 +185,19 @@ namespace osu.Game.Screens.Select.FooterV2 return; } - switch (OverlayState.Value) + if (OverlayState.Value == Visibility.Visible) { - case Visibility.Visible: - backgroundBox.FadeColour(buttonAccentColour.Darken(0.5f), transition_length, Easing.OutQuint); - return; - - case Visibility.Hidden: - backgroundBox.FadeColour(buttonAccentColour, transition_length, Easing.OutQuint); - break; + backgroundBox.FadeColour(buttonAccentColour.Darken(0.5f), transition_length, Easing.OutQuint); + return; } - //Hover logic. - backgroundBox.FadeColour(isHovered && Enabled.Value ? colourProvider.Background3.Lighten(.3f) : colourProvider.Background3, transition_length, Easing.OutQuint); + if (IsHovered) + { + backgroundBox.FadeColour(colourProvider.Background3.Lighten(0.3f), transition_length, Easing.OutQuint); + return; + } + + backgroundBox.FadeColour(colourProvider.Background3, transition_length, Easing.OutQuint); } } } diff --git a/osu.Game/Screens/Select/FooterV2/FooterV2.cs b/osu.Game/Screens/Select/FooterV2/FooterV2.cs index 7e2d9d6695..2bfa03d319 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterV2.cs @@ -20,6 +20,8 @@ namespace osu.Game.Screens.Select.FooterV2 private readonly List overlays = new List(); + /// The button to be added. + /// The to be toggled by this button. public void AddButton(FooterButtonV2 button, OverlayContainer? overlay = null) { if (overlay != null) From 680646d3a6b41a133fb6e0ab15537d2a1710dbc1 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 29 Dec 2022 12:02:08 +0100 Subject: [PATCH 11/88] Make offsetting of bottom bar more readable --- osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index ea4db1f8fa..342f5d1bd7 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -119,8 +119,9 @@ namespace osu.Game.Screens.Select.FooterV2 }, new Container { - //Offset the bar to centre it with consideration for the shearing - Position = new Vector2(-0.15f * 35, -10), + // The X offset has to multiplied as such to account for the fact that we only want to offset by the distance from the CenterLeft point of the container + // not the whole shear width + Position = new Vector2(-SHEAR.X * (button_height / 2 - 10), -10), Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, Size = new Vector2(120, 6), From 92a755c5da93c4077ace0342b784539e21072941 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Tue, 17 Jan 2023 22:16:59 +0100 Subject: [PATCH 12/88] adjust colourbar to position itself in a more simple fashion --- .../Screens/Select/FooterV2/FooterButtonV2.cs | 47 ++++++++----------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 342f5d1bd7..33bf062abb 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -117,21 +117,22 @@ namespace osu.Game.Screens.Select.FooterV2 Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre }, - new Container - { - // The X offset has to multiplied as such to account for the fact that we only want to offset by the distance from the CenterLeft point of the container - // not the whole shear width - Position = new Vector2(-SHEAR.X * (button_height / 2 - 10), -10), - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - Size = new Vector2(120, 6), - Masking = true, - CornerRadius = 3, - Child = bar = new Box - { - RelativeSizeAxes = Axes.Both, - } - } + } + }, + new Container + { + // The X offset has to multiplied as such to account for the fact that we only want to offset by the distance from the CenterLeft point of the container + // not the whole shear width + Shear = -SHEAR, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + Y = -10, + Size = new Vector2(120, 6), + Masking = true, + CornerRadius = 3, + Child = bar = new Box + { + RelativeSizeAxes = Axes.Both, } } }; @@ -153,20 +154,10 @@ namespace osu.Game.Screens.Select.FooterV2 return true; } - protected override void OnHoverLost(HoverLostEvent e) - { - updateDisplay(); - } + protected override void OnHoverLost(HoverLostEvent e) => updateDisplay(); - protected override bool OnMouseDown(MouseDownEvent e) - { - return !Enabled.Value || base.OnMouseDown(e); - } - - protected override bool OnClick(ClickEvent e) - { - return !Enabled.Value || base.OnClick(e); - } + protected override bool OnMouseDown(MouseDownEvent e) => !Enabled.Value || base.OnMouseDown(e); + protected override bool OnClick(ClickEvent e) => !Enabled.Value || base.OnClick(e); public virtual bool OnPressed(KeyBindingPressEvent e) { From bc94f1b7732dd09d25b660eb150ac38a655f41f6 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 23 Jan 2023 16:43:38 +0100 Subject: [PATCH 13/88] add free mods button to test --- osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs index a1ba8daf8e..534bd0ad28 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs @@ -50,6 +50,7 @@ namespace osu.Game.Tests.Visual.SongSelect PreviousRandom = () => previousRandomCalled = true }); footer.AddButton(new FooterButtonOptionsV2()); + footer.AddButton(new FooterButtonFreeModsV2()); InputManager.MoveMouseTo(Vector2.Zero); From 41f5e5143af134be4a018f0830c68a90c479c2fa Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 30 Jan 2023 12:56:39 +0100 Subject: [PATCH 14/88] Remove ```onclick``` and ```mousedown``` override --- osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 33bf062abb..a4cdf8b71b 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -80,11 +80,10 @@ namespace osu.Game.Screens.Select.FooterV2 Size = new Vector2(button_width, button_height); Masking = true; CornerRadius = corner_radius; - InternalChildren = new Drawable[] + Children = new Drawable[] { backgroundBox = new Box { - Colour = colourProvider.Background3, RelativeSizeAxes = Axes.Both }, @@ -142,6 +141,9 @@ namespace osu.Game.Screens.Select.FooterV2 { base.LoadComplete(); + // We want the first colour assignment for the background to be instantaneous + backgroundBox.Colour = Enabled.Value ? colourProvider.Background3 : colourProvider.Background3.Darken(0.3f); + Enabled.BindValueChanged(_ => updateDisplay(), true); OverlayState.BindValueChanged(_ => updateDisplay()); } @@ -156,9 +158,6 @@ namespace osu.Game.Screens.Select.FooterV2 protected override void OnHoverLost(HoverLostEvent e) => updateDisplay(); - protected override bool OnMouseDown(MouseDownEvent e) => !Enabled.Value || base.OnMouseDown(e); - protected override bool OnClick(ClickEvent e) => !Enabled.Value || base.OnClick(e); - public virtual bool OnPressed(KeyBindingPressEvent e) { if (e.Action != Hotkey || e.Repeat) return false; From f5d579144b0aa390cabc5321483841418db6674f Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 30 Jan 2023 12:57:24 +0100 Subject: [PATCH 15/88] Remove free mods button --- .../SongSelect/TestSceneSongSelectFooterV2.cs | 1 - .../Select/FooterV2/FooterButtonFreeModsV2.cs | 21 ------------------- 2 files changed, 22 deletions(-) delete mode 100644 osu.Game/Screens/Select/FooterV2/FooterButtonFreeModsV2.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs index 534bd0ad28..a1ba8daf8e 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs @@ -50,7 +50,6 @@ namespace osu.Game.Tests.Visual.SongSelect PreviousRandom = () => previousRandomCalled = true }); footer.AddButton(new FooterButtonOptionsV2()); - footer.AddButton(new FooterButtonFreeModsV2()); InputManager.MoveMouseTo(Vector2.Zero); diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonFreeModsV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonFreeModsV2.cs deleted file mode 100644 index 523a2afa36..0000000000 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonFreeModsV2.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; - -namespace osu.Game.Screens.Select.FooterV2 -{ - public partial class FooterButtonFreeModsV2 : FooterButtonV2 - { - [BackgroundDependencyLoader] - private void load(OsuColour colour) - { - //No design exists for this button! - Icon = FontAwesome.Solid.ExpandArrowsAlt; - Text = "Freemods"; - AccentColour = colour.Yellow; - } - } -} From 80fd1a0bc7d85e8dae00089cea00bf14a762c7c7 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 2 Feb 2023 18:29:12 +0100 Subject: [PATCH 16/88] Remove leftover comment regarding X axis offsets --- osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index a4cdf8b71b..94b21666ac 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -120,8 +120,6 @@ namespace osu.Game.Screens.Select.FooterV2 }, new Container { - // The X offset has to multiplied as such to account for the fact that we only want to offset by the distance from the CenterLeft point of the container - // not the whole shear width Shear = -SHEAR, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, From a1200b8fe87fb5c56e34469dcc21e9d2470f4584 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 16:24:19 +0900 Subject: [PATCH 17/88] Adjust footer button colour handling to read better and take into account mouse down --- .../SongSelect/TestSceneSongSelectFooterV2.cs | 5 +-- .../Screens/Select/FooterV2/FooterButtonV2.cs | 45 +++++++++++++------ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs index a1ba8daf8e..773d067c15 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs @@ -10,7 +10,6 @@ using osu.Framework.Testing; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Screens.Select.FooterV2; -using osuTK; using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect @@ -51,15 +50,13 @@ namespace osu.Game.Tests.Visual.SongSelect }); footer.AddButton(new FooterButtonOptionsV2()); - InputManager.MoveMouseTo(Vector2.Zero); - overlay.Hide(); }); [Test] public void TestState() { - AddRepeatStep("toggle options state", () => this.ChildrenOfType().Last().Enabled.Toggle(), 20); + AddToggleStep("set options enabled state", state => this.ChildrenOfType().Last().Enabled.Value = state); } [Test] diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 94b21666ac..123ec51bd4 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -18,6 +18,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; using osu.Game.Overlays; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Select.FooterV2 { @@ -148,12 +149,28 @@ namespace osu.Game.Screens.Select.FooterV2 public GlobalAction? Hotkey; + private bool handlingMouse; + protected override bool OnHover(HoverEvent e) { updateDisplay(); return true; } + protected override bool OnMouseDown(MouseDownEvent e) + { + handlingMouse = true; + updateDisplay(); + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + handlingMouse = false; + updateDisplay(); + base.OnMouseUp(e); + } + protected override void OnHoverLost(HoverLostEvent e) => updateDisplay(); public virtual bool OnPressed(KeyBindingPressEvent e) @@ -168,25 +185,27 @@ namespace osu.Game.Screens.Select.FooterV2 private void updateDisplay() { + Color4 backgroundColour = colourProvider.Background3; + if (!Enabled.Value) { - backgroundBox.FadeColour(colourProvider.Background3.Darken(0.3f), transition_length, Easing.OutQuint); - return; + backgroundColour = colourProvider.Background3.Darken(0.4f); } - - if (OverlayState.Value == Visibility.Visible) + else { - backgroundBox.FadeColour(buttonAccentColour.Darken(0.5f), transition_length, Easing.OutQuint); - return; + if (OverlayState.Value == Visibility.Visible) + backgroundColour = buttonAccentColour.Darken(0.5f); + + if (IsHovered) + { + backgroundColour = backgroundColour.Lighten(0.3f); + + if (handlingMouse) + backgroundColour = backgroundColour.Lighten(0.3f); + } } - if (IsHovered) - { - backgroundBox.FadeColour(colourProvider.Background3.Lighten(0.3f), transition_length, Easing.OutQuint); - return; - } - - backgroundBox.FadeColour(colourProvider.Background3, transition_length, Easing.OutQuint); + backgroundBox.FadeColour(backgroundColour, transition_length, Easing.OutQuint); } } } From 4248453616387e1507ba1fd42969d730de113ec6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 16:25:54 +0900 Subject: [PATCH 18/88] Use `FinishTransforms` rather than manual duplication of background colour logic --- osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 123ec51bd4..eee2e50b25 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -140,11 +140,10 @@ namespace osu.Game.Screens.Select.FooterV2 { base.LoadComplete(); - // We want the first colour assignment for the background to be instantaneous - backgroundBox.Colour = Enabled.Value ? colourProvider.Background3 : colourProvider.Background3.Darken(0.3f); - - Enabled.BindValueChanged(_ => updateDisplay(), true); OverlayState.BindValueChanged(_ => updateDisplay()); + Enabled.BindValueChanged(_ => updateDisplay(), true); + + FinishTransforms(true); } public GlobalAction? Hotkey; From 48f7e0163c14fe4a491c5959d0387303456b3cbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 16:26:54 +0900 Subject: [PATCH 19/88] Adjust comments and formatting of comments --- osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index eee2e50b25..409d9daaae 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Select.FooterV2 private const int corner_radius = 10; private const int transition_length = 500; - //Accounts for corner radius margin on bottom, would be 12 + // This should be 12 by design, but an extra allowance is added due to the corner radius specification. public const float SHEAR_WIDTH = 13.5f; public Bindable OverlayState = new Bindable(); @@ -88,7 +88,7 @@ namespace osu.Game.Screens.Select.FooterV2 RelativeSizeAxes = Axes.Both }, - //For elements that should not be sheared. + // For elements that should not be sheared. new Container { Anchor = Anchor.CentreLeft, @@ -105,7 +105,7 @@ namespace osu.Game.Screens.Select.FooterV2 AutoSizeAxes = Axes.Both, Child = text = new OsuSpriteText { - //figma design says the size is 16, but due to the issues with font sizes 19 matches better + // figma design says the size is 16, but due to the issues with font sizes 19 matches better Font = OsuFont.TorusAlternate.With(size: 19), AlwaysPresent = true } From d5b2d9ce9722c3127d4252e4b6b92388f758ba03 Mon Sep 17 00:00:00 2001 From: tsrk Date: Sun, 5 Feb 2023 23:58:08 +0000 Subject: [PATCH 20/88] feat: add support for spectating status --- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 3 +++ osu.Game/Users/UserActivity.cs | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index 240fbcf662..bd9e3917a5 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Screens; using osu.Game.Online.Spectator; using osu.Game.Scoring; +using osu.Game.Users; namespace osu.Game.Screens.Play { @@ -14,6 +15,8 @@ namespace osu.Game.Screens.Play { private readonly Score score; + protected override UserActivity InitialActivity => new UserActivity.Spectating(score.ScoreInfo.User); + public SoloSpectatorPlayer(Score score, PlayerConfiguration configuration = null) : base(score, configuration) { diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 6de797ca3a..950c486f22 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -5,6 +5,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osuTK.Graphics; @@ -92,7 +93,14 @@ namespace osu.Game.Users public class Spectating : UserActivity { - public override string Status => @"Spectating a game"; + private readonly APIUser user; + + public Spectating(APIUser user) + { + this.user = user; + } + + public override string Status => @$"Spectating {user.Username}"; } public class SearchingForLobby : UserActivity From bf273597ea726ef7d493b8db17889b9f0c93561c Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 00:41:10 +0000 Subject: [PATCH 21/88] feat: actually support status also for Replays --- osu.Game/Screens/Play/ReplayPlayer.cs | 3 +++ osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 2 +- osu.Game/Users/UserActivity.cs | 16 ++++++++-------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index c5ef6b1585..e2b8ad7011 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; +using osu.Game.Users; namespace osu.Game.Screens.Play { @@ -24,6 +25,8 @@ namespace osu.Game.Screens.Play private readonly bool replayIsFailedScore; + protected override UserActivity InitialActivity => new UserActivity.Watching(); + // Disallow replays from failing. (see https://github.com/ppy/osu/issues/6108) protected override bool CheckModsAllowFailure() { diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index bd9e3917a5..65b66166c0 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Play { private readonly Score score; - protected override UserActivity InitialActivity => new UserActivity.Spectating(score.ScoreInfo.User); + protected override UserActivity InitialActivity => new UserActivity.Spectating(); public SoloSpectatorPlayer(Score score, PlayerConfiguration configuration = null) : base(score, configuration) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 950c486f22..d652730621 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -5,7 +5,6 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osuTK.Graphics; @@ -91,16 +90,17 @@ namespace osu.Game.Users public override string Status => @"Editing a beatmap"; } - public class Spectating : UserActivity + public class Watching : UserActivity { - private readonly APIUser user; + protected virtual string Verb => @"Watching"; - public Spectating(APIUser user) - { - this.user = user; - } + public override string Status => @$"{Verb} a game"; + } - public override string Status => @$"Spectating {user.Username}"; + public class Spectating : Watching + { + protected override string Verb => @"Spectating"; + public override string Status => @$"{Verb} a game"; } public class SearchingForLobby : UserActivity From e878bb42a4670796186cd5c926cea35cf1b36039 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 00:53:56 +0000 Subject: [PATCH 22/88] test: add test for watching activity --- osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index 4c1df850b2..eaf2ca5ac0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -107,6 +107,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("set online status", () => status.Value = new UserStatusOnline()); AddStep("idle", () => activity.Value = null); + AddStep("watching", () => activity.Value = new UserActivity.Watching()); AddStep("spectating", () => activity.Value = new UserActivity.Spectating()); AddStep("solo (osu!)", () => activity.Value = soloGameStatusForRuleset(0)); AddStep("solo (osu!taiko)", () => activity.Value = soloGameStatusForRuleset(1)); From b3f38b0f4c463c147dc3a646fe02f6270e597283 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 00:56:11 +0000 Subject: [PATCH 23/88] quality: remove redundant `Status` override --- osu.Game/Users/UserActivity.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index d652730621..37b5a2bf1e 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -100,7 +100,6 @@ namespace osu.Game.Users public class Spectating : Watching { protected override string Verb => @"Spectating"; - public override string Status => @$"{Verb} a game"; } public class SearchingForLobby : UserActivity From bc89f8dc5b9d40aa92bcc88249e7165e4b72f9fc Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 12:44:00 +0000 Subject: [PATCH 24/88] feat: add name and rulset verb display support --- osu.Desktop/DiscordRichPresence.cs | 5 +++- .../Visual/Online/TestSceneUserPanel.cs | 14 ++++++++-- osu.Game/Screens/Play/ReplayPlayer.cs | 2 +- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 2 +- osu.Game/Users/UserActivity.cs | 28 ++++++++++++++++++- 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 2c4577f239..6ca86c64c4 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -98,7 +98,7 @@ namespace osu.Desktop if (status.Value is UserStatusOnline && activity.Value != null) { - presence.State = truncate(activity.Value.Status); + presence.State = truncate(privacyMode.Value == DiscordRichPresenceMode.Limited ? activity.Value.LimitedStatus : activity.Value.Status); presence.Details = truncate(getDetails(activity.Value)); if (getBeatmap(activity.Value) is IBeatmapInfo beatmap && beatmap.OnlineID > 0) @@ -186,6 +186,9 @@ namespace osu.Desktop case UserActivity.Editing edit: return edit.BeatmapInfo.ToString() ?? string.Empty; + case UserActivity.Watching watching: + return watching.BeatmapInfo.ToString(); + case UserActivity.InLobby lobby: return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index eaf2ca5ac0..64a42ee6ce 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -11,6 +11,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; +using osu.Game.Scoring; +using osu.Game.Tests.Beatmaps; using osu.Game.Users; using osuTK; @@ -107,8 +109,8 @@ namespace osu.Game.Tests.Visual.Online AddStep("set online status", () => status.Value = new UserStatusOnline()); AddStep("idle", () => activity.Value = null); - AddStep("watching", () => activity.Value = new UserActivity.Watching()); - AddStep("spectating", () => activity.Value = new UserActivity.Spectating()); + AddStep("watching", () => activity.Value = new UserActivity.Watching(createScore(@"nats"))); + AddStep("spectating", () => activity.Value = new UserActivity.Spectating(createScore(@"mrekk"))); AddStep("solo (osu!)", () => activity.Value = soloGameStatusForRuleset(0)); AddStep("solo (osu!taiko)", () => activity.Value = soloGameStatusForRuleset(1)); AddStep("solo (osu!catch)", () => activity.Value = soloGameStatusForRuleset(2)); @@ -133,6 +135,14 @@ namespace osu.Game.Tests.Visual.Online private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.InSoloGame(null, rulesetStore.GetRuleset(rulesetId)); + private ScoreInfo createScore(string name) => new ScoreInfo(new TestBeatmap(Ruleset.Value).BeatmapInfo) + { + User = new APIUser + { + Username = name, + } + }; + private partial class TestUserListPanel : UserListPanel { public TestUserListPanel(APIUser user) diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index e2b8ad7011..9e87969687 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Play private readonly bool replayIsFailedScore; - protected override UserActivity InitialActivity => new UserActivity.Watching(); + protected override UserActivity InitialActivity => new UserActivity.Watching(Score.ScoreInfo); // Disallow replays from failing. (see https://github.com/ppy/osu/issues/6108) protected override bool CheckModsAllowFailure() diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index 65b66166c0..8a9cda2af7 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Play { private readonly Score score; - protected override UserActivity InitialActivity => new UserActivity.Spectating(); + protected override UserActivity InitialActivity => new UserActivity.Spectating(Score.ScoreInfo); public SoloSpectatorPlayer(Score score, PlayerConfiguration configuration = null) : base(score, configuration) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 37b5a2bf1e..99d68e7564 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -4,9 +4,11 @@ #nullable disable using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Online.Rooms; using osu.Game.Rulesets; +using osu.Game.Scoring; using osuTK.Graphics; namespace osu.Game.Users @@ -14,6 +16,12 @@ namespace osu.Game.Users public abstract class UserActivity { public abstract string Status { get; } + + /// + /// This property is used when the is + /// + public virtual string LimitedStatus => Status; + public virtual Color4 GetAppropriateColour(OsuColour colours) => colours.GreenDarker; public class Modding : UserActivity @@ -92,14 +100,32 @@ namespace osu.Game.Users public class Watching : UserActivity { + private readonly ScoreInfo score; + + private string username => score.User.Username; + private string playingVerb => score.BeatmapInfo.Ruleset.CreateInstance().PlayingVerb; + + public BeatmapInfo BeatmapInfo => score.BeatmapInfo; + + public Watching(ScoreInfo score) + { + this.score = score; + } + protected virtual string Verb => @"Watching"; - public override string Status => @$"{Verb} a game"; + public override string Status => @$"{Verb} {username} {playingVerb.ToLowerInvariant()}"; + public override string LimitedStatus => $@"{Verb} a game"; } public class Spectating : Watching { protected override string Verb => @"Spectating"; + + public Spectating(ScoreInfo score) + : base(score) + { + } } public class SearchingForLobby : UserActivity From 1baaae35a9748c913a744c1c6fbdb4f90d7bdb08 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 20:07:16 +0000 Subject: [PATCH 25/88] quality: Simplify string --- osu.Game/Users/UserActivity.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 99d68e7564..b62cd7edd5 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -102,8 +102,7 @@ namespace osu.Game.Users { private readonly ScoreInfo score; - private string username => score.User.Username; - private string playingVerb => score.BeatmapInfo.Ruleset.CreateInstance().PlayingVerb; + protected string Username => score.User.Username; public BeatmapInfo BeatmapInfo => score.BeatmapInfo; @@ -112,15 +111,12 @@ namespace osu.Game.Users this.score = score; } - protected virtual string Verb => @"Watching"; - - public override string Status => @$"{Verb} {username} {playingVerb.ToLowerInvariant()}"; - public override string LimitedStatus => $@"{Verb} a game"; + public override string Status => $@"Watching {Username}"; } public class Spectating : Watching { - protected override string Verb => @"Spectating"; + public override string Status => $@"Spectating {Username}"; public Spectating(ScoreInfo score) : base(score) From da10166628e01a3cd607a9337edc8546c80cbdb8 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 21:30:55 +0000 Subject: [PATCH 26/88] quality: convert getter property to method so that sensible information can be hidden via an argument --- osu.Desktop/DiscordRichPresence.cs | 2 +- osu.Game/Users/ExtendedUserPanel.cs | 2 +- osu.Game/Users/UserActivity.cs | 28 +++++++++++----------------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 6ca86c64c4..e24fe1a1ec 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -98,7 +98,7 @@ namespace osu.Desktop if (status.Value is UserStatusOnline && activity.Value != null) { - presence.State = truncate(privacyMode.Value == DiscordRichPresenceMode.Limited ? activity.Value.LimitedStatus : activity.Value.Status); + presence.State = truncate(activity.Value.GetStatus(privacyMode.Value == DiscordRichPresenceMode.Limited)); presence.Details = truncate(getDetails(activity.Value)); if (getBeatmap(activity.Value) is IBeatmapInfo beatmap && beatmap.OnlineID > 0) diff --git a/osu.Game/Users/ExtendedUserPanel.cs b/osu.Game/Users/ExtendedUserPanel.cs index 4ea3c036c1..3c1b68f9ef 100644 --- a/osu.Game/Users/ExtendedUserPanel.cs +++ b/osu.Game/Users/ExtendedUserPanel.cs @@ -106,7 +106,7 @@ namespace osu.Game.Users // Set status message based on activity (if we have one) and status is not offline if (activity != null && !(status is UserStatusOffline)) { - statusMessage.Text = activity.Status; + statusMessage.Text = activity.GetStatus(); statusIcon.FadeColour(activity.GetAppropriateColour(Colours), 500, Easing.OutQuint); return; } diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index b62cd7edd5..0e6e3ca5f2 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -4,7 +4,6 @@ #nullable disable using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Online.Rooms; using osu.Game.Rulesets; @@ -15,24 +14,19 @@ namespace osu.Game.Users { public abstract class UserActivity { - public abstract string Status { get; } - - /// - /// This property is used when the is - /// - public virtual string LimitedStatus => Status; + public abstract string GetStatus(bool hideIdentifiableInformation = false); public virtual Color4 GetAppropriateColour(OsuColour colours) => colours.GreenDarker; public class Modding : UserActivity { - public override string Status => "Modding a map"; + public override string GetStatus(bool hideIdentifiableInformation = false) => "Modding a map"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark; } public class ChoosingBeatmap : UserActivity { - public override string Status => "Choosing a beatmap"; + public override string GetStatus(bool hideIdentifiableInformation = false) => "Choosing a beatmap"; } public abstract class InGame : UserActivity @@ -47,7 +41,7 @@ namespace osu.Game.Users Ruleset = ruleset; } - public override string Status => Ruleset.CreateInstance().PlayingVerb; + public override string GetStatus(bool hideIdentifiableInformation = false) => Ruleset.CreateInstance().PlayingVerb; } public class InMultiplayerGame : InGame @@ -57,7 +51,7 @@ namespace osu.Game.Users { } - public override string Status => $@"{base.Status} with others"; + public override string GetStatus(bool hideIdentifiableInformation = false) => $@"{base.GetStatus(hideIdentifiableInformation)} with others"; } public class SpectatingMultiplayerGame : InGame @@ -67,7 +61,7 @@ namespace osu.Game.Users { } - public override string Status => $"Watching others {base.Status.ToLowerInvariant()}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => $"Watching others {base.GetStatus(hideIdentifiableInformation).ToLowerInvariant()}"; } public class InPlaylistGame : InGame @@ -95,7 +89,7 @@ namespace osu.Game.Users BeatmapInfo = info; } - public override string Status => @"Editing a beatmap"; + public override string GetStatus(bool hideIdentifiableInformation = false) => @"Editing a beatmap"; } public class Watching : UserActivity @@ -111,12 +105,12 @@ namespace osu.Game.Users this.score = score; } - public override string Status => $@"Watching {Username}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a game" : $@"Watching {Username}"; } public class Spectating : Watching { - public override string Status => $@"Spectating {Username}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a game" : $@"Spectating {Username}"; public Spectating(ScoreInfo score) : base(score) @@ -126,12 +120,12 @@ namespace osu.Game.Users public class SearchingForLobby : UserActivity { - public override string Status => @"Looking for a lobby"; + public override string GetStatus(bool hideIdentifiableInformation = false) => @"Looking for a lobby"; } public class InLobby : UserActivity { - public override string Status => @"In a lobby"; + public override string GetStatus(bool hideIdentifiableInformation = false) => @"In a lobby"; public readonly Room Room; From ee65c658937f3ff845c229bbf5edd97d8e73af17 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Feb 2023 11:31:28 +0900 Subject: [PATCH 27/88] Attempt to fix channel join / leave loop I don't have a solid way to repro the issue, but this should hopefully help in resolving it. Either way, I think this change brings more correct behaviour (if a websocket message comes through that we have left the channel, I don't believe we should be sending a request to leave that channel again). --- osu.Game/Online/Chat/ChannelManager.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 7ab678775f..701a1cd040 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -95,7 +95,7 @@ namespace osu.Game.Online.Chat { connector.ChannelJoined += ch => Schedule(() => joinChannel(ch)); - connector.ChannelParted += ch => Schedule(() => LeaveChannel(getChannel(ch))); + connector.ChannelParted += ch => Schedule(() => leaveChannel(getChannel(ch), false)); connector.NewMessages += msgs => Schedule(() => addMessages(msgs)); @@ -558,7 +558,9 @@ namespace osu.Game.Online.Chat /// Leave the specified channel. Can be called from any thread. /// /// The channel to leave. - public void LeaveChannel(Channel channel) => Schedule(() => + public void LeaveChannel(Channel channel) => Schedule(() => leaveChannel(channel, true)); + + private void leaveChannel(Channel channel, bool sendLeaveRequest) { if (channel == null) return; @@ -584,7 +586,7 @@ namespace osu.Game.Online.Chat api.Queue(new LeaveChannelRequest(channel)); channel.Joined.Value = false; } - }); + } /// /// Opens the most recently closed channel that has not already been reopened, From df1355ea4be54fac4a7c306892d35111fbe3960f Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Mon, 6 Feb 2023 13:34:54 +0000 Subject: [PATCH 28/88] Taiko hit objects now snap to hit target --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index ff4edf35fa..ef87522eea 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -207,6 +207,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables const float gravity_time = 300; const float gravity_travel_height = 200; + MainPiece.MoveToX(-X); // Visually snap hit object to hit target + this.ScaleTo(0.8f, gravity_time * 2, Easing.OutQuad); this.MoveToY(-gravity_travel_height, gravity_time, Easing.Out) From 6ace6bfee17fbf0ffcb4d8f3c88a23d22acf2332 Mon Sep 17 00:00:00 2001 From: Walavouchey <36758269+Walavouchey@users.noreply.github.com> Date: Tue, 7 Feb 2023 11:16:36 +0100 Subject: [PATCH 29/88] ensure `AccuracyCircle` doesn't land in gaps created by `RankNotch`es --- .../Visual/Ranking/TestSceneAccuracyCircle.cs | 9 +++++ .../Expanded/Accuracy/AccuracyCircle.cs | 34 ++++++++++++++++++- .../Ranking/Expanded/Accuracy/RankNotch.cs | 2 +- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs index 0145a1dfef..314e275ca3 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs @@ -24,11 +24,20 @@ namespace osu.Game.Tests.Visual.Ranking { public partial class TestSceneAccuracyCircle : OsuTestScene { + [TestCase(0, ScoreRank.D)] [TestCase(0.2, ScoreRank.D)] [TestCase(0.5, ScoreRank.D)] + [TestCase(0.699, ScoreRank.D)] + [TestCase(0.7, ScoreRank.C)] [TestCase(0.75, ScoreRank.C)] + [TestCase(0.799, ScoreRank.C)] + [TestCase(0.80, ScoreRank.B)] [TestCase(0.85, ScoreRank.B)] + [TestCase(0.899, ScoreRank.B)] + [TestCase(0.9, ScoreRank.A)] [TestCase(0.925, ScoreRank.A)] + [TestCase(0.949, ScoreRank.A)] + [TestCase(0.95, ScoreRank.S)] [TestCase(0.975, ScoreRank.S)] [TestCase(0.9999, ScoreRank.S)] [TestCase(1, ScoreRank.X)] diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 8e04bb68fb..3cb09734c5 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -73,6 +73,11 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// private const double virtual_ss_percentage = 0.01; + /// + /// The width of a in terms of accuracy. + /// + public const double NOTCH_WIDTH_PERCENTAGE = 0.002; + /// /// The easing for the circle filling transforms. /// @@ -263,7 +268,34 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy using (BeginDelayedSequence(ACCURACY_TRANSFORM_DELAY)) { - double targetAccuracy = score.Rank == ScoreRank.X || score.Rank == ScoreRank.XH ? 1 : Math.Min(1 - virtual_ss_percentage, score.Accuracy); + double targetAccuracy = score.Accuracy; + + // Ensure the gauge overshoots or undershoots a bit so it doesn't land in the gaps of the inner graded circle (caused by `RankNotch`es), + // to prevent ambiguity on what grade it's pointing at. + double[] notchPercentages = { 0.7, 0.8, 0.9, 0.95 }; + + foreach (double p in notchPercentages) + { + if (targetAccuracy > p - NOTCH_WIDTH_PERCENTAGE / 2 && targetAccuracy < p + NOTCH_WIDTH_PERCENTAGE / 2) + { + int tippingDirection = targetAccuracy - p >= 0 ? 1 : -1; // We "round up" here to match rank criteria + targetAccuracy = p + tippingDirection * (NOTCH_WIDTH_PERCENTAGE / 2); + break; + } + } + + // The final gap between 99.999...% (S) and 100% (SS) is exaggerated by `virtual_ss_percentage`. We don't want to land there either. + if (score.Rank == ScoreRank.X || score.Rank == ScoreRank.XH) + targetAccuracy = 1; + else + targetAccuracy = Math.Min(1 - virtual_ss_percentage - NOTCH_WIDTH_PERCENTAGE / 2, targetAccuracy); + + // The accuracy circle gauge visually fills up a bit too much. + // This wouldn't normally matter but we want it to align properly with the inner graded circle in the above cases. + const double visual_alignment_offset = 0.001; + + if (targetAccuracy < 1 && targetAccuracy >= visual_alignment_offset) + targetAccuracy -= visual_alignment_offset; accuracyCircle.FillTo(targetAccuracy, ACCURACY_TRANSFORM_DURATION, ACCURACY_TRANSFORM_EASING); diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs index 7e73767318..32f2eb2fa5 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.Y, Height = AccuracyCircle.RANK_CIRCLE_RADIUS, - Width = 1f, + Width = (float)AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 360f, Colour = OsuColour.Gray(0.3f), EdgeSmoothness = new Vector2(1f) } From 0531c010ebeb17037059d34b21aa948849ca67d2 Mon Sep 17 00:00:00 2001 From: Walavouchey <36758269+Walavouchey@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:08:37 +0100 Subject: [PATCH 30/88] display `RankBadge`s on on their sector centres the D `RankBadge` does this anyway. the A and S badges are slightly off centre to prevent overlap with the SS badge --- .../Ranking/Expanded/Accuracy/AccuracyCircle.cs | 12 ++++++------ .../Screens/Ranking/Expanded/Accuracy/RankBadge.cs | 11 +++++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 3cb09734c5..9ee63b40dd 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -220,12 +220,12 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Padding = new MarginPadding { Vertical = -15, Horizontal = -20 }, Children = new[] { - new RankBadge(1, getRank(ScoreRank.X)), - new RankBadge(0.95, getRank(ScoreRank.S)), - new RankBadge(0.9, getRank(ScoreRank.A)), - new RankBadge(0.8, getRank(ScoreRank.B)), - new RankBadge(0.7, getRank(ScoreRank.C)), - new RankBadge(0.35, getRank(ScoreRank.D)), + new RankBadge(1, 1, getRank(ScoreRank.X)), + new RankBadge(0.95, 0.95 + (0.025 - virtual_ss_percentage) / 2, getRank(ScoreRank.S)), + new RankBadge(0.9, 0.9125, getRank(ScoreRank.A)), + new RankBadge(0.8, 0.85, getRank(ScoreRank.B)), + new RankBadge(0.7, 0.75, getRank(ScoreRank.C)), + new RankBadge(0, 0.35, getRank(ScoreRank.D)), } }, rankText = new RankText(score.Rank) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs index 5432b4cbeb..7af327828e 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs @@ -27,6 +27,11 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// public readonly double Accuracy; + /// + /// The position around the to display this badge. + /// + private readonly double displayPosition; + private readonly ScoreRank rank; private Drawable rankContainer; @@ -36,10 +41,12 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// Creates a new . /// /// The accuracy value corresponding to . + /// The position around the to display this badge. /// The to be displayed in this . - public RankBadge(double accuracy, ScoreRank rank) + public RankBadge(double accuracy, double position, ScoreRank rank) { Accuracy = accuracy; + displayPosition = position; this.rank = rank; RelativeSizeAxes = Axes.Both; @@ -92,7 +99,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy base.Update(); // Starts at -90deg (top) and moves counter-clockwise by the accuracy - rankContainer.Position = circlePosition(-MathF.PI / 2 - (1 - (float)Accuracy) * MathF.PI * 2); + rankContainer.Position = circlePosition(-MathF.PI / 2 - (1 - (float)displayPosition) * MathF.PI * 2); } private Vector2 circlePosition(float t) From ee40444fd3c96b37b32d3defb8b7509267244b45 Mon Sep 17 00:00:00 2001 From: Walavouchey <36758269+Walavouchey@users.noreply.github.com> Date: Wed, 8 Feb 2023 23:59:19 +0100 Subject: [PATCH 31/88] use `Precision.AlmostEquals` for bounds check --- osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 9ee63b40dd..24daea21f3 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -276,7 +276,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy foreach (double p in notchPercentages) { - if (targetAccuracy > p - NOTCH_WIDTH_PERCENTAGE / 2 && targetAccuracy < p + NOTCH_WIDTH_PERCENTAGE / 2) + if (Precision.AlmostEquals(p, targetAccuracy, NOTCH_WIDTH_PERCENTAGE / 2)) { int tippingDirection = targetAccuracy - p >= 0 ? 1 : -1; // We "round up" here to match rank criteria targetAccuracy = p + tippingDirection * (NOTCH_WIDTH_PERCENTAGE / 2); From 9544a1d26d6cf819aa192c689fea10e78bb4ac11 Mon Sep 17 00:00:00 2001 From: Walavouchey <36758269+Walavouchey@users.noreply.github.com> Date: Thu, 9 Feb 2023 00:02:32 +0100 Subject: [PATCH 32/88] use values closer to the extremities for test cases --- .../Visual/Ranking/TestSceneAccuracyCircle.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs index 314e275ca3..f94cf9eb58 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs @@ -27,16 +27,16 @@ namespace osu.Game.Tests.Visual.Ranking [TestCase(0, ScoreRank.D)] [TestCase(0.2, ScoreRank.D)] [TestCase(0.5, ScoreRank.D)] - [TestCase(0.699, ScoreRank.D)] + [TestCase(0.6999, ScoreRank.D)] [TestCase(0.7, ScoreRank.C)] [TestCase(0.75, ScoreRank.C)] - [TestCase(0.799, ScoreRank.C)] - [TestCase(0.80, ScoreRank.B)] + [TestCase(0.7999, ScoreRank.C)] + [TestCase(0.8, ScoreRank.B)] [TestCase(0.85, ScoreRank.B)] - [TestCase(0.899, ScoreRank.B)] + [TestCase(0.8999, ScoreRank.B)] [TestCase(0.9, ScoreRank.A)] [TestCase(0.925, ScoreRank.A)] - [TestCase(0.949, ScoreRank.A)] + [TestCase(0.9499, ScoreRank.A)] [TestCase(0.95, ScoreRank.S)] [TestCase(0.975, ScoreRank.S)] [TestCase(0.9999, ScoreRank.S)] From fd93bd3f501de37fa7ca43e7e0a52efe2566cb5f Mon Sep 17 00:00:00 2001 From: Walavouchey <36758269+Walavouchey@users.noreply.github.com> Date: Thu, 9 Feb 2023 00:34:28 +0100 Subject: [PATCH 33/88] move rank accuracy requirements to class-local constants --- .../Expanded/Accuracy/AccuracyCircle.cs | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 24daea21f3..9606c2bf22 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -28,6 +28,18 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// public partial class AccuracyCircle : CompositeDrawable { + private const double accuracy_x = 1; + + private const double accuracy_s = 0.95; + + private const double accuracy_a = 0.9; + + private const double accuracy_b = 0.8; + + private const double accuracy_c = 0.7; + + private const double accuracy_d = 0; + /// /// Duration for the transforms causing this component to appear. /// @@ -150,49 +162,49 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.X), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = 1 } + Current = { Value = accuracy_x } }, new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.S), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = 1 - virtual_ss_percentage } + Current = { Value = accuracy_x - virtual_ss_percentage } }, new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.A), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = 0.95f } + Current = { Value = accuracy_s } }, new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.B), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = 0.9f } + Current = { Value = accuracy_a } }, new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.C), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = 0.8f } + Current = { Value = accuracy_b } }, new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.D), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = 0.7f } + Current = { Value = accuracy_c } }, - new RankNotch(0), - new RankNotch((float)(1 - virtual_ss_percentage)), - new RankNotch(0.95f), - new RankNotch(0.9f), - new RankNotch(0.8f), - new RankNotch(0.7f), + new RankNotch((float)accuracy_x), + new RankNotch((float)(accuracy_x - virtual_ss_percentage)), + new RankNotch((float)accuracy_s), + new RankNotch((float)accuracy_a), + new RankNotch((float)accuracy_b), + new RankNotch((float)accuracy_c), new BufferedContainer { Name = "Graded circle mask", @@ -220,12 +232,13 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Padding = new MarginPadding { Vertical = -15, Horizontal = -20 }, Children = new[] { - new RankBadge(1, 1, getRank(ScoreRank.X)), - new RankBadge(0.95, 0.95 + (0.025 - virtual_ss_percentage) / 2, getRank(ScoreRank.S)), - new RankBadge(0.9, 0.9125, getRank(ScoreRank.A)), - new RankBadge(0.8, 0.85, getRank(ScoreRank.B)), - new RankBadge(0.7, 0.75, getRank(ScoreRank.C)), - new RankBadge(0, 0.35, getRank(ScoreRank.D)), + // The S and A badges are moved down slightly to prevent collision with the SS badge. + new RankBadge(accuracy_x, accuracy_x, getRank(ScoreRank.X)), + new RankBadge(accuracy_s, Interpolation.Lerp(accuracy_s, (accuracy_x - virtual_ss_percentage), 0.25), getRank(ScoreRank.S)), + new RankBadge(accuracy_a, Interpolation.Lerp(accuracy_a, accuracy_s, 0.25), getRank(ScoreRank.A)), + new RankBadge(accuracy_b, Interpolation.Lerp(accuracy_b, accuracy_a, 0.5), getRank(ScoreRank.B)), + new RankBadge(accuracy_c, Interpolation.Lerp(accuracy_c, accuracy_b, 0.5), getRank(ScoreRank.C)), + new RankBadge(accuracy_d, Interpolation.Lerp(accuracy_d, accuracy_c, 0.5), getRank(ScoreRank.D)), } }, rankText = new RankText(score.Rank) @@ -269,11 +282,16 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy using (BeginDelayedSequence(ACCURACY_TRANSFORM_DELAY)) { double targetAccuracy = score.Accuracy; + double[] notchPercentages = + { + accuracy_s, + accuracy_a, + accuracy_b, + accuracy_c, + }; // Ensure the gauge overshoots or undershoots a bit so it doesn't land in the gaps of the inner graded circle (caused by `RankNotch`es), // to prevent ambiguity on what grade it's pointing at. - double[] notchPercentages = { 0.7, 0.8, 0.9, 0.95 }; - foreach (double p in notchPercentages) { if (Precision.AlmostEquals(p, targetAccuracy, NOTCH_WIDTH_PERCENTAGE / 2)) @@ -288,7 +306,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy if (score.Rank == ScoreRank.X || score.Rank == ScoreRank.XH) targetAccuracy = 1; else - targetAccuracy = Math.Min(1 - virtual_ss_percentage - NOTCH_WIDTH_PERCENTAGE / 2, targetAccuracy); + targetAccuracy = Math.Min(accuracy_x - virtual_ss_percentage - NOTCH_WIDTH_PERCENTAGE / 2, targetAccuracy); // The accuracy circle gauge visually fills up a bit too much. // This wouldn't normally matter but we want it to align properly with the inner graded circle in the above cases. @@ -325,7 +343,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy if (badge.Accuracy > score.Accuracy) continue; - using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, Math.Min(1 - virtual_ss_percentage, badge.Accuracy) / targetAccuracy) * ACCURACY_TRANSFORM_DURATION)) + using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, Math.Min(accuracy_x - virtual_ss_percentage, badge.Accuracy) / targetAccuracy) * ACCURACY_TRANSFORM_DURATION)) { badge.Appear(); From 57312279f02049028fbc97f41f94be8192f323c0 Mon Sep 17 00:00:00 2001 From: Walavouchey <36758269+Walavouchey@users.noreply.github.com> Date: Thu, 9 Feb 2023 02:20:05 +0100 Subject: [PATCH 34/88] adjust `RankNotch` gap size to match original value --- osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 9606c2bf22..31ce3ddf95 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -88,7 +88,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// /// The width of a in terms of accuracy. /// - public const double NOTCH_WIDTH_PERCENTAGE = 0.002; + public const double NOTCH_WIDTH_PERCENTAGE = 1.0 / 360; /// /// The easing for the circle filling transforms. From cf009432cc5af59b8a35e809468ece6472eb2561 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Feb 2023 15:41:45 +0900 Subject: [PATCH 35/88] Centralise accuracy cutoff constants and add lookup helper methods --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 93 +++++++++++++++---- .../Expanded/Accuracy/AccuracyCircle.cs | 18 ++-- 2 files changed, 81 insertions(+), 30 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index b5f42ec2cc..1e03a3ff80 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -7,21 +7,28 @@ using System.Diagnostics; using System.Diagnostics.Contracts; using System.Linq; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Extensions; +using osu.Game.Localisation; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Replays; using osu.Game.Scoring; -using osu.Framework.Localisation; -using osu.Game.Localisation; namespace osu.Game.Rulesets.Scoring { public partial class ScoreProcessor : JudgementProcessor { + private const double accuracy_cutoff_x = 1; + private const double accuracy_cutoff_s = 0.95; + private const double accuracy_cutoff_a = 0.9; + private const double accuracy_cutoff_b = 0.8; + private const double accuracy_cutoff_c = 0.7; + private const double accuracy_cutoff_d = 0; + private const double max_score = 1000000; /// @@ -160,7 +167,7 @@ namespace osu.Game.Rulesets.Scoring Combo.ValueChanged += combo => HighestCombo.Value = Math.Max(HighestCombo.Value, combo.NewValue); Accuracy.ValueChanged += accuracy => { - Rank.Value = rankFrom(accuracy.NewValue); + Rank.Value = RankFromAccuracy(accuracy.NewValue); foreach (var mod in Mods.Value.OfType()) Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue); }; @@ -369,22 +376,6 @@ namespace osu.Game.Rulesets.Scoring } } - private ScoreRank rankFrom(double acc) - { - if (acc == 1) - return ScoreRank.X; - if (acc >= 0.95) - return ScoreRank.S; - if (acc >= 0.9) - return ScoreRank.A; - if (acc >= 0.8) - return ScoreRank.B; - if (acc >= 0.7) - return ScoreRank.C; - - return ScoreRank.D; - } - /// /// Resets this ScoreProcessor to a default state. /// @@ -583,6 +574,70 @@ namespace osu.Game.Rulesets.Scoring hitEvents.Clear(); } + #region Static helper methods + + /// + /// Given an accuracy (0..1), return the correct . + /// + public static ScoreRank RankFromAccuracy(double accuracy) + { + switch (accuracy) + { + case accuracy_cutoff_x: + return ScoreRank.X; + + case >= accuracy_cutoff_s: + return ScoreRank.S; + + case >= accuracy_cutoff_a: + return ScoreRank.A; + + case >= accuracy_cutoff_b: + return ScoreRank.B; + + case >= accuracy_cutoff_c: + return ScoreRank.C; + + default: + return ScoreRank.D; + } + } + + /// + /// Given a , return the cutoff accuracy (0..1). + /// Accuracy must be great or equal to the cutoff to qualify for the provided rank. + /// + public static double AccuracyCutoffFromRank(ScoreRank rank) + { + switch (rank) + { + case ScoreRank.X: + case ScoreRank.XH: + return accuracy_cutoff_x; + + case ScoreRank.S: + case ScoreRank.SH: + return accuracy_cutoff_s; + + case ScoreRank.A: + return accuracy_cutoff_a; + + case ScoreRank.B: + return accuracy_cutoff_b; + + case ScoreRank.C: + return accuracy_cutoff_c; + + case ScoreRank.D: + return accuracy_cutoff_d; + + default: + throw new ArgumentOutOfRangeException(nameof(rank), rank, null); + } + } + + #endregion + /// /// Stores the required scoring data that fulfils the minimum requirements for a to calculate score. /// diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 31ce3ddf95..2ec4270c3c 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -17,6 +17,7 @@ using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Skinning; using osuTK; @@ -28,17 +29,12 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// public partial class AccuracyCircle : CompositeDrawable { - private const double accuracy_x = 1; - - private const double accuracy_s = 0.95; - - private const double accuracy_a = 0.9; - - private const double accuracy_b = 0.8; - - private const double accuracy_c = 0.7; - - private const double accuracy_d = 0; + private static readonly double accuracy_x = ScoreProcessor.AccuracyCutoffFromRank(ScoreRank.X); + private static readonly double accuracy_s = ScoreProcessor.AccuracyCutoffFromRank(ScoreRank.S); + private static readonly double accuracy_a = ScoreProcessor.AccuracyCutoffFromRank(ScoreRank.A); + private static readonly double accuracy_b = ScoreProcessor.AccuracyCutoffFromRank(ScoreRank.B); + private static readonly double accuracy_c = ScoreProcessor.AccuracyCutoffFromRank(ScoreRank.C); + private static readonly double accuracy_d = ScoreProcessor.AccuracyCutoffFromRank(ScoreRank.D); /// /// Duration for the transforms causing this component to appear. From 92eb6b6717852dfeb7f3babcadc5a707af4423bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Feb 2023 15:41:55 +0900 Subject: [PATCH 36/88] Simplify `TestSceneAccuracyCircle` test specifications --- .../Visual/Ranking/TestSceneAccuracyCircle.cs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs index f94cf9eb58..bf18bd3e51 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs @@ -24,26 +24,26 @@ namespace osu.Game.Tests.Visual.Ranking { public partial class TestSceneAccuracyCircle : OsuTestScene { - [TestCase(0, ScoreRank.D)] - [TestCase(0.2, ScoreRank.D)] - [TestCase(0.5, ScoreRank.D)] - [TestCase(0.6999, ScoreRank.D)] - [TestCase(0.7, ScoreRank.C)] - [TestCase(0.75, ScoreRank.C)] - [TestCase(0.7999, ScoreRank.C)] - [TestCase(0.8, ScoreRank.B)] - [TestCase(0.85, ScoreRank.B)] - [TestCase(0.8999, ScoreRank.B)] - [TestCase(0.9, ScoreRank.A)] - [TestCase(0.925, ScoreRank.A)] - [TestCase(0.9499, ScoreRank.A)] - [TestCase(0.95, ScoreRank.S)] - [TestCase(0.975, ScoreRank.S)] - [TestCase(0.9999, ScoreRank.S)] - [TestCase(1, ScoreRank.X)] - public void TestRank(double accuracy, ScoreRank rank) + [TestCase(0)] + [TestCase(0.2)] + [TestCase(0.5)] + [TestCase(0.6999)] + [TestCase(0.7)] + [TestCase(0.75)] + [TestCase(0.7999)] + [TestCase(0.8)] + [TestCase(0.85)] + [TestCase(0.8999)] + [TestCase(0.9)] + [TestCase(0.925)] + [TestCase(0.9499)] + [TestCase(0.95)] + [TestCase(0.975)] + [TestCase(0.9999)] + [TestCase(1)] + public void TestRank(double accuracy) { - var score = createScore(accuracy, rank); + var score = createScore(accuracy, ScoreProcessor.RankFromAccuracy(accuracy)); addCircleStep(score); } From 34d1890f1c85089168b6e69f16532b0edfb09447 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Feb 2023 17:57:51 +0900 Subject: [PATCH 37/88] Change snapping to only apply to classic mod --- osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs | 10 +++++++++- .../Objects/Drawables/DrawableHit.cs | 3 ++- .../Rulesets/Objects/Drawables/DrawableHitObject.cs | 9 +++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 2ccdfd40e5..300c72a854 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -2,13 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset + public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IApplicableToDrawableHitObject { public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -18,5 +20,11 @@ namespace osu.Game.Rulesets.Taiko.Mods var playfield = (TaikoPlayfield)drawableRuleset.Playfield; playfield.ClassicHitTargetPosition.Value = true; } + + public void ApplyToDrawableHitObject(DrawableHitObject drawable) + { + if (drawable is DrawableHit) + drawable.SnapJudgementLocation = true; + } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index ef87522eea..62c8457c58 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -207,7 +207,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables const float gravity_time = 300; const float gravity_travel_height = 200; - MainPiece.MoveToX(-X); // Visually snap hit object to hit target + if (SnapJudgementLocation) + MainPiece.MoveToX(-X); this.ScaleTo(0.8f, gravity_time * 2, Easing.OutQuad); diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 39f0888882..01550a113f 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -662,6 +662,15 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public virtual double MaximumJudgementOffset => HitObject.HitWindows?.WindowFor(HitResult.Miss) ?? 0; + /// + /// Whether the location of the hit should be snapped to the hit target before animating. + /// + /// + /// This is how osu-stable worked, but notably is not how TnT works. + /// It results in less visual feedback on hit accuracy. + /// + public bool SnapJudgementLocation { get; set; } + /// /// Applies the of this , notifying responders such as /// the of the . From 2c1154afc67966742980e498a89adca96698031f Mon Sep 17 00:00:00 2001 From: Ruki Date: Thu, 9 Feb 2023 17:15:30 +0000 Subject: [PATCH 38/88] refactor: improve wording Co-authored-by: Joseph Madamba --- osu.Game/Users/UserActivity.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 0e6e3ca5f2..b1c3fac382 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -105,12 +105,12 @@ namespace osu.Game.Users this.score = score; } - public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a game" : $@"Watching {Username}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a replay" : $@"Watching {Username}'s replay"; } public class Spectating : Watching { - public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a game" : $@"Spectating {Username}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a user" : $@"Spectating {Username}"; public Spectating(ScoreInfo score) : base(score) From 2e2ab4081bdb293e927e89412024d4ec49509fd3 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Thu, 9 Feb 2023 21:22:34 +0100 Subject: [PATCH 39/88] Make `LargeBonus` a valid `HitResult` in taiko --- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 9944c0c6b7..4f435e73b3 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -209,9 +209,8 @@ namespace osu.Game.Rulesets.Taiko HitResult.Great, HitResult.Ok, - HitResult.SmallTickHit, - HitResult.SmallBonus, + HitResult.LargeBonus, }; } @@ -220,6 +219,9 @@ namespace osu.Game.Rulesets.Taiko switch (result) { case HitResult.SmallBonus: + return "drum tick"; + + case HitResult.LargeBonus: return "bonus"; } From 0b41dbf579564149ba596fdb03f639b109dc3cf2 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 9 Feb 2023 12:59:26 -0800 Subject: [PATCH 40/88] Remove code bloat from `ClickableAvatar` --- osu.Game/Users/Drawables/ClickableAvatar.cs | 46 +++----------------- osu.Game/Users/Drawables/UpdateableAvatar.cs | 1 - 2 files changed, 5 insertions(+), 42 deletions(-) diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index 5a3009dfcd..4f4c69be83 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -4,26 +4,17 @@ #nullable disable using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users.Drawables { - public partial class ClickableAvatar : Container + public partial class ClickableAvatar : OsuClickableContainer { private const string default_tooltip_text = "view profile"; - /// - /// Whether to open the user's profile when clicked. - /// - public bool OpenOnClick - { - set => clickableArea.Enabled.Value = clickableArea.Action != null && value; - } + public override LocalisableString TooltipText { get; set; } = default_tooltip_text; /// /// By default, the tooltip will show "view profile" as avatars are usually displayed next to a username. @@ -31,7 +22,7 @@ namespace osu.Game.Users.Drawables /// public bool ShowUsernameTooltip { - set => clickableArea.TooltipText = value ? (user?.Username ?? string.Empty) : default_tooltip_text; + set => TooltipText = value ? (user?.Username ?? string.Empty) : default_tooltip_text; } private readonly APIUser user; @@ -39,30 +30,22 @@ namespace osu.Game.Users.Drawables [Resolved(CanBeNull = true)] private OsuGame game { get; set; } - private readonly ClickableArea clickableArea; - /// /// A clickable avatar for the specified user, with UI sounds included. - /// If is true, clicking will open the user's profile. /// /// The user. A null value will get a placeholder avatar. public ClickableAvatar(APIUser user = null) { this.user = user; - Add(clickableArea = new ClickableArea - { - RelativeSizeAxes = Axes.Both, - }); - if (user?.Id != APIUser.SYSTEM_USER_ID) - clickableArea.Action = openProfile; + Action = openProfile; } [BackgroundDependencyLoader] private void load() { - LoadComponentAsync(new DrawableAvatar(user), clickableArea.Add); + LoadComponentAsync(new DrawableAvatar(user), Add); } private void openProfile() @@ -70,24 +53,5 @@ namespace osu.Game.Users.Drawables if (user?.Id > 1 || !string.IsNullOrEmpty(user?.Username)) game?.ShowUser(user); } - - private partial class ClickableArea : OsuClickableContainer - { - private LocalisableString tooltip = default_tooltip_text; - - public override LocalisableString TooltipText - { - get => Enabled.Value ? tooltip : default; - set => tooltip = value; - } - - protected override bool OnClick(ClickEvent e) - { - if (!Enabled.Value) - return false; - - return base.OnClick(e); - } - } } } diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index 9c04eb5706..9611156624 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs @@ -76,7 +76,6 @@ namespace osu.Game.Users.Drawables { return new ClickableAvatar(user) { - OpenOnClick = true, ShowUsernameTooltip = showUsernameTooltip, RelativeSizeAxes = Axes.Both, }; From f0d11f44fc8191d6231056b1a5636757e8d0aef6 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Thu, 9 Feb 2023 22:18:12 +0100 Subject: [PATCH 41/88] Always add to additions soundbank in `convertSoundType` --- .../Objects/Legacy/ConvertHitObjectParser.cs | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 930ee0448f..68ca6bc506 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -439,19 +439,20 @@ namespace osu.Game.Rulesets.Objects.Legacy private List convertSoundType(LegacyHitSoundType type, SampleBankInfo bankInfo) { - // Todo: This should return the normal SampleInfos if the specified sample file isn't found, but that's a pretty edge-case scenario - if (!string.IsNullOrEmpty(bankInfo.Filename)) - { - return new List { new FileHitSampleInfo(bankInfo.Filename, bankInfo.Volume) }; - } + var soundTypes = new List(); - var soundTypes = new List + if (string.IsNullOrEmpty(bankInfo.Filename)) { - new LegacyHitSampleInfo(HitSampleInfo.HIT_NORMAL, bankInfo.BankForNormal, bankInfo.Volume, bankInfo.CustomSampleBank, - // if the sound type doesn't have the Normal flag set, attach it anyway as a layered sample. - // None also counts as a normal non-layered sample: https://osu.ppy.sh/help/wiki/osu!_File_Formats/Osu_(file_format)#hitsounds - type != LegacyHitSoundType.None && !type.HasFlagFast(LegacyHitSoundType.Normal)) - }; + soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_NORMAL, bankInfo.BankForNormal, bankInfo.Volume, bankInfo.CustomSampleBank, + // if the sound type doesn't have the Normal flag set, attach it anyway as a layered sample. + // None also counts as a normal non-layered sample: https://osu.ppy.sh/help/wiki/osu!_File_Formats/Osu_(file_format)#hitsounds + type != LegacyHitSoundType.None && !type.HasFlagFast(LegacyHitSoundType.Normal))); + } + else + { + // Todo: This should set the normal SampleInfo if the specified sample file isn't found, but that's a pretty edge-case scenario + soundTypes.Add(new FileHitSampleInfo(bankInfo.Filename, bankInfo.Volume)); + } if (type.HasFlagFast(LegacyHitSoundType.Finish)) soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_FINISH, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.CustomSampleBank)); From 51816b92c6a2264653ec553c9509e575af5aa3f1 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Thu, 9 Feb 2023 23:23:58 +0100 Subject: [PATCH 42/88] Add conversion tests --- .../TaikoBeatmapConversionTest.cs | 1 + .../file-hitsamples-expected-conversion.json | 1 + .../Testing/Beatmaps/file-hitsamples.osu | 22 +++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/file-hitsamples-expected-conversion.json create mode 100644 osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/file-hitsamples.osu diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs index 796f5721bb..781a686700 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs @@ -25,6 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Tests [TestCase("slider-conversion-v6")] [TestCase("slider-conversion-v14")] [TestCase("slider-generating-drumroll-2")] + [TestCase("file-hitsamples")] public void Test(string name) => base.Test(name); protected override IEnumerable CreateConvertValue(HitObject hitObject) diff --git a/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/file-hitsamples-expected-conversion.json b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/file-hitsamples-expected-conversion.json new file mode 100644 index 0000000000..70348a3871 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/file-hitsamples-expected-conversion.json @@ -0,0 +1 @@ +{"Mappings":[{"StartTime":500.0,"Objects":[{"StartTime":500.0,"EndTime":500.0,"IsRim":false,"IsCentre":true,"IsDrumRoll":false,"IsSwell":false,"IsStrong":false}]},{"StartTime":1000.0,"Objects":[{"StartTime":1000.0,"EndTime":1000.0,"IsRim":true,"IsCentre":false,"IsDrumRoll":false,"IsSwell":false,"IsStrong":false}]},{"StartTime":1500.0,"Objects":[{"StartTime":1500.0,"EndTime":1500.0,"IsRim":true,"IsCentre":false,"IsDrumRoll":false,"IsSwell":false,"IsStrong":false}]},{"StartTime":2000.0,"Objects":[{"StartTime":2000.0,"EndTime":2000.0,"IsRim":true,"IsCentre":false,"IsDrumRoll":false,"IsSwell":false,"IsStrong":false}]},{"StartTime":2500.0,"Objects":[{"StartTime":2500.0,"EndTime":2500.0,"IsRim":false,"IsCentre":true,"IsDrumRoll":false,"IsSwell":false,"IsStrong":true}]},{"StartTime":3000.0,"Objects":[{"StartTime":3000.0,"EndTime":3000.0,"IsRim":true,"IsCentre":false,"IsDrumRoll":false,"IsSwell":false,"IsStrong":true}]},{"StartTime":3500.0,"Objects":[{"StartTime":3500.0,"EndTime":3500.0,"IsRim":true,"IsCentre":false,"IsDrumRoll":false,"IsSwell":false,"IsStrong":true}]},{"StartTime":4000.0,"Objects":[{"StartTime":4000.0,"EndTime":4000.0,"IsRim":true,"IsCentre":false,"IsDrumRoll":false,"IsSwell":false,"IsStrong":true}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/file-hitsamples.osu b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/file-hitsamples.osu new file mode 100644 index 0000000000..5d4bcb52a1 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/file-hitsamples.osu @@ -0,0 +1,22 @@ +osu file format v14 + +[Difficulty] +HPDrainRate:5 +CircleSize:7 +OverallDifficulty:6.5 +ApproachRate:10 +SliderMultiplier:1.9 +SliderTickRate:1 + +[TimingPoints] +500,500,4,2,1,50,1,0 + +[HitObjects] +256,192,500,1,0,0:0:0:0:sample.ogg +256,192,1000,1,8,0:0:0:0:sample.ogg +256,192,1500,1,2,0:0:0:0:sample.ogg +256,192,2000,1,10,0:0:0:0:sample.ogg +256,192,2500,1,4,0:0:0:0:sample.ogg +256,192,3000,1,12,0:0:0:0:sample.ogg +256,192,3500,1,6,0:0:0:0:sample.ogg +256,192,4000,1,14,0:0:0:0:sample.ogg From 96c1832af407a9f8cf3d014ea6f4f17e609b02eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 10 Feb 2023 00:07:24 +0100 Subject: [PATCH 43/88] Fix grammar in xmldoc Co-authored-by: Walavouchey <36758269+Walavouchey@users.noreply.github.com> --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 1e03a3ff80..7fc8980cf5 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -605,7 +605,7 @@ namespace osu.Game.Rulesets.Scoring /// /// Given a , return the cutoff accuracy (0..1). - /// Accuracy must be great or equal to the cutoff to qualify for the provided rank. + /// Accuracy must be greater than or equal to the cutoff to qualify for the provided rank. /// public static double AccuracyCutoffFromRank(ScoreRank rank) { From a86f06df96aec0d499585666127ce17a17e9920b Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 9 Feb 2023 16:09:38 -0800 Subject: [PATCH 44/88] Add back `Enabled` checks to `TooltipText` and `OnClick` to fix guest case --- osu.Game/Users/Drawables/ClickableAvatar.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index 4f4c69be83..475d1c616e 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Framework.Allocation; +using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; @@ -14,7 +15,13 @@ namespace osu.Game.Users.Drawables { private const string default_tooltip_text = "view profile"; - public override LocalisableString TooltipText { get; set; } = default_tooltip_text; + private LocalisableString tooltip = default_tooltip_text; + + public override LocalisableString TooltipText + { + get => Enabled.Value ? tooltip : default; + set => tooltip = value; + } /// /// By default, the tooltip will show "view profile" as avatars are usually displayed next to a username. @@ -53,5 +60,13 @@ namespace osu.Game.Users.Drawables if (user?.Id > 1 || !string.IsNullOrEmpty(user?.Username)) game?.ShowUser(user); } + + protected override bool OnClick(ClickEvent e) + { + if (!Enabled.Value) + return false; + + return base.OnClick(e); + } } } From 68c37585e53b16203b2ec7b68e0cf58b4bf385f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 16:22:06 +0900 Subject: [PATCH 45/88] Use `string.Empty` instead of `default` --- osu.Game/Users/Drawables/ClickableAvatar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index 475d1c616e..76adf49913 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -19,7 +19,7 @@ namespace osu.Game.Users.Drawables public override LocalisableString TooltipText { - get => Enabled.Value ? tooltip : default; + get => Enabled.Value ? tooltip : string.Empty; set => tooltip = value; } From 5866b67a5b53c6a7f0df477e8b0a1daa8d388d21 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 16:24:44 +0900 Subject: [PATCH 46/88] Simplify tooltip implementation --- osu.Game/Users/Drawables/ClickableAvatar.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index 76adf49913..e13fb6a819 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework.Allocation; using osu.Framework.Input.Events; using osu.Framework.Localisation; @@ -15,22 +16,23 @@ namespace osu.Game.Users.Drawables { private const string default_tooltip_text = "view profile"; - private LocalisableString tooltip = default_tooltip_text; - public override LocalisableString TooltipText { - get => Enabled.Value ? tooltip : string.Empty; - set => tooltip = value; + get + { + if (!Enabled.Value) + return string.Empty; + + return ShowUsernameTooltip ? (user?.Username ?? string.Empty) : default_tooltip_text; + } + set => throw new InvalidOperationException(); } /// /// By default, the tooltip will show "view profile" as avatars are usually displayed next to a username. /// Setting this to true exposes the username via tooltip for special cases where this is not true. /// - public bool ShowUsernameTooltip - { - set => TooltipText = value ? (user?.Username ?? string.Empty) : default_tooltip_text; - } + public bool ShowUsernameTooltip { get; set; } private readonly APIUser user; From 199fb0fd8563e1baa242428fa75b9560b6dc3704 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 16:25:14 +0900 Subject: [PATCH 47/88] Apply NRT to `ClickableAvatar` and `UpdateableAvatar` --- osu.Game/Users/Drawables/ClickableAvatar.cs | 10 ++++------ osu.Game/Users/Drawables/UpdateableAvatar.cs | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index e13fb6a819..bb57958239 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Input.Events; @@ -34,16 +32,16 @@ namespace osu.Game.Users.Drawables /// public bool ShowUsernameTooltip { get; set; } - private readonly APIUser user; + private readonly APIUser? user; - [Resolved(CanBeNull = true)] - private OsuGame game { get; set; } + [Resolved] + private OsuGame? game { get; set; } /// /// A clickable avatar for the specified user, with UI sounds included. /// /// The user. A null value will get a placeholder avatar. - public ClickableAvatar(APIUser user = null) + public ClickableAvatar(APIUser? user = null) { this.user = user; diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index 9611156624..c659685807 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -13,9 +11,9 @@ namespace osu.Game.Users.Drawables /// /// An avatar which can update to a new user when needed. /// - public partial class UpdateableAvatar : ModelBackedDrawable + public partial class UpdateableAvatar : ModelBackedDrawable { - public APIUser User + public APIUser? User { get => Model; set => Model = value; @@ -58,7 +56,7 @@ namespace osu.Game.Users.Drawables /// If set to true, hover/click sounds will play and clicking the avatar will open the user's profile. /// Whether to show the username rather than "view profile" on the tooltip. (note: this only applies if is also true) /// Whether to show a default guest representation on null user (as opposed to nothing). - public UpdateableAvatar(APIUser user = null, bool isInteractive = true, bool showUsernameTooltip = false, bool showGuestOnNull = true) + public UpdateableAvatar(APIUser? user = null, bool isInteractive = true, bool showUsernameTooltip = false, bool showGuestOnNull = true) { this.isInteractive = isInteractive; this.showUsernameTooltip = showUsernameTooltip; @@ -67,7 +65,7 @@ namespace osu.Game.Users.Drawables User = user; } - protected override Drawable CreateDrawable(APIUser user) + protected override Drawable? CreateDrawable(APIUser? user) { if (user == null && !showGuestOnNull) return null; From 1df6fc631104e0338eeced59f6b7fa91836ac9a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 17:03:27 +0900 Subject: [PATCH 48/88] Use `if` statements rather than conditional `case` --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 30 ++++++++------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 7fc8980cf5..96f6922224 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -581,26 +581,18 @@ namespace osu.Game.Rulesets.Scoring /// public static ScoreRank RankFromAccuracy(double accuracy) { - switch (accuracy) - { - case accuracy_cutoff_x: - return ScoreRank.X; + if (accuracy == accuracy_cutoff_x) + return ScoreRank.X; + if (accuracy >= accuracy_cutoff_s) + return ScoreRank.S; + if (accuracy >= accuracy_cutoff_a) + return ScoreRank.A; + if (accuracy >= accuracy_cutoff_b) + return ScoreRank.B; + if (accuracy >= accuracy_cutoff_c) + return ScoreRank.C; - case >= accuracy_cutoff_s: - return ScoreRank.S; - - case >= accuracy_cutoff_a: - return ScoreRank.A; - - case >= accuracy_cutoff_b: - return ScoreRank.B; - - case >= accuracy_cutoff_c: - return ScoreRank.C; - - default: - return ScoreRank.D; - } + return ScoreRank.D; } /// From 03e623d1d221ff30159f6940c60f3adc484afe23 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 17:37:31 +0900 Subject: [PATCH 49/88] Move `ControlPointList` to own file --- .../Screens/Edit/Timing/ControlPointList.cs | 209 ++++++++++++++++++ osu.Game/Screens/Edit/Timing/TimingScreen.cs | 198 ----------------- 2 files changed, 209 insertions(+), 198 deletions(-) create mode 100644 osu.Game/Screens/Edit/Timing/ControlPointList.cs diff --git a/osu.Game/Screens/Edit/Timing/ControlPointList.cs b/osu.Game/Screens/Edit/Timing/ControlPointList.cs new file mode 100644 index 0000000000..555c36aac0 --- /dev/null +++ b/osu.Game/Screens/Edit/Timing/ControlPointList.cs @@ -0,0 +1,209 @@ +// 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.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Screens.Edit.Timing +{ + public partial class ControlPointList : CompositeDrawable + { + private OsuButton deleteButton = null!; + private ControlPointTable table = null!; + private OsuScrollContainer scroll = null!; + private RoundedButton addButton = null!; + + private readonly IBindableList controlPointGroups = new BindableList(); + + [Resolved] + private EditorClock clock { get; set; } = null!; + + [Resolved] + protected EditorBeatmap Beatmap { get; private set; } = null!; + + [Resolved] + private Bindable selectedGroup { get; set; } = null!; + + [Resolved] + private IEditorChangeHandler? changeHandler { get; set; } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colours) + { + RelativeSizeAxes = Axes.Both; + + const float margins = 10; + InternalChildren = new Drawable[] + { + new Box + { + Colour = colours.Background4, + RelativeSizeAxes = Axes.Both, + }, + new Box + { + Colour = colours.Background3, + RelativeSizeAxes = Axes.Y, + Width = ControlPointTable.TIMING_COLUMN_WIDTH + margins, + }, + scroll = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = table = new ControlPointTable(), + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding(margins), + Spacing = new Vector2(5), + Children = new Drawable[] + { + deleteButton = new RoundedButton + { + Text = "-", + Size = new Vector2(30, 30), + Action = delete, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + }, + addButton = new RoundedButton + { + Action = addNew, + Size = new Vector2(160, 30), + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + }, + } + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + selectedGroup.BindValueChanged(selected => + { + deleteButton.Enabled.Value = selected.NewValue != null; + + addButton.Text = selected.NewValue != null + ? "+ Clone to current time" + : "+ Add at current time"; + }, true); + + controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups); + controlPointGroups.BindCollectionChanged((_, _) => + { + table.ControlGroups = controlPointGroups; + changeHandler?.SaveState(); + }, true); + + table.OnRowSelected += drawable => scroll.ScrollIntoView(drawable); + } + + protected override bool OnClick(ClickEvent e) + { + selectedGroup.Value = null; + return true; + } + + protected override void Update() + { + base.Update(); + + trackActivePoint(); + + addButton.Enabled.Value = clock.CurrentTimeAccurate != selectedGroup.Value?.Time; + } + + private Type? trackedType; + + /// + /// Given the user has selected a control point group, we want to track any group which is + /// active at the current point in time which matches the type the user has selected. + /// + /// So if the user is currently looking at a timing point and seeks into the future, a + /// future timing point would be automatically selected if it is now the new "current" point. + /// + private void trackActivePoint() + { + // For simplicity only match on the first type of the active control point. + if (selectedGroup.Value == null) + trackedType = null; + else + { + // If the selected group only has one control point, update the tracking type. + if (selectedGroup.Value.ControlPoints.Count == 1) + trackedType = selectedGroup.Value?.ControlPoints.Single().GetType(); + // If the selected group has more than one control point, choose the first as the tracking type + // if we don't already have a singular tracked type. + else if (trackedType == null) + trackedType = selectedGroup.Value?.ControlPoints.FirstOrDefault()?.GetType(); + } + + if (trackedType != null) + { + // We don't have an efficient way of looking up groups currently, only individual point types. + // To improve the efficiency of this in the future, we should reconsider the overall structure of ControlPointInfo. + + // Find the next group which has the same type as the selected one. + var found = Beatmap.ControlPointInfo.Groups + .Where(g => g.ControlPoints.Any(cp => cp.GetType() == trackedType)) + .LastOrDefault(g => g.Time <= clock.CurrentTimeAccurate); + + if (found != null) + selectedGroup.Value = found; + } + } + + private void delete() + { + if (selectedGroup.Value == null) + return; + + Beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value); + + selectedGroup.Value = Beatmap.ControlPointInfo.Groups.FirstOrDefault(g => g.Time >= clock.CurrentTime); + } + + private void addNew() + { + bool isFirstControlPoint = !Beatmap.ControlPointInfo.TimingPoints.Any(); + + var group = Beatmap.ControlPointInfo.GroupAt(clock.CurrentTime, true); + + if (isFirstControlPoint) + group.Add(new TimingControlPoint()); + else + { + // Try and create matching types from the currently selected control point. + var selected = selectedGroup.Value; + + if (selected != null && !ReferenceEquals(selected, group)) + { + foreach (var controlPoint in selected.ControlPoints) + { + group.Add(controlPoint.DeepClone()); + } + } + } + + selectedGroup.Value = group; + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 2450909929..a948da10cd 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -1,20 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Overlays; -using osuTK; namespace osu.Game.Screens.Edit.Timing { @@ -45,194 +36,5 @@ namespace osu.Game.Screens.Edit.Timing }, } }; - - public partial class ControlPointList : CompositeDrawable - { - private OsuButton deleteButton = null!; - private ControlPointTable table = null!; - private OsuScrollContainer scroll = null!; - private RoundedButton addButton = null!; - - private readonly IBindableList controlPointGroups = new BindableList(); - - [Resolved] - private EditorClock clock { get; set; } = null!; - - [Resolved] - protected EditorBeatmap Beatmap { get; private set; } = null!; - - [Resolved] - private Bindable selectedGroup { get; set; } = null!; - - [Resolved] - private IEditorChangeHandler? changeHandler { get; set; } - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colours) - { - RelativeSizeAxes = Axes.Both; - - const float margins = 10; - InternalChildren = new Drawable[] - { - new Box - { - Colour = colours.Background4, - RelativeSizeAxes = Axes.Both, - }, - new Box - { - Colour = colours.Background3, - RelativeSizeAxes = Axes.Y, - Width = ControlPointTable.TIMING_COLUMN_WIDTH + margins, - }, - scroll = new OsuScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = table = new ControlPointTable(), - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Direction = FillDirection.Horizontal, - Margin = new MarginPadding(margins), - Spacing = new Vector2(5), - Children = new Drawable[] - { - deleteButton = new RoundedButton - { - Text = "-", - Size = new Vector2(30, 30), - Action = delete, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - }, - addButton = new RoundedButton - { - Action = addNew, - Size = new Vector2(160, 30), - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - }, - } - }, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - selectedGroup.BindValueChanged(selected => - { - deleteButton.Enabled.Value = selected.NewValue != null; - - addButton.Text = selected.NewValue != null - ? "+ Clone to current time" - : "+ Add at current time"; - }, true); - - controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups); - controlPointGroups.BindCollectionChanged((_, _) => - { - table.ControlGroups = controlPointGroups; - changeHandler?.SaveState(); - }, true); - - table.OnRowSelected += drawable => scroll.ScrollIntoView(drawable); - } - - protected override bool OnClick(ClickEvent e) - { - selectedGroup.Value = null; - return true; - } - - protected override void Update() - { - base.Update(); - - trackActivePoint(); - - addButton.Enabled.Value = clock.CurrentTimeAccurate != selectedGroup.Value?.Time; - } - - private Type? trackedType; - - /// - /// Given the user has selected a control point group, we want to track any group which is - /// active at the current point in time which matches the type the user has selected. - /// - /// So if the user is currently looking at a timing point and seeks into the future, a - /// future timing point would be automatically selected if it is now the new "current" point. - /// - private void trackActivePoint() - { - // For simplicity only match on the first type of the active control point. - if (selectedGroup.Value == null) - trackedType = null; - else - { - // If the selected group only has one control point, update the tracking type. - if (selectedGroup.Value.ControlPoints.Count == 1) - trackedType = selectedGroup.Value?.ControlPoints.Single().GetType(); - // If the selected group has more than one control point, choose the first as the tracking type - // if we don't already have a singular tracked type. - else if (trackedType == null) - trackedType = selectedGroup.Value?.ControlPoints.FirstOrDefault()?.GetType(); - } - - if (trackedType != null) - { - // We don't have an efficient way of looking up groups currently, only individual point types. - // To improve the efficiency of this in the future, we should reconsider the overall structure of ControlPointInfo. - - // Find the next group which has the same type as the selected one. - var found = Beatmap.ControlPointInfo.Groups - .Where(g => g.ControlPoints.Any(cp => cp.GetType() == trackedType)) - .LastOrDefault(g => g.Time <= clock.CurrentTimeAccurate); - - if (found != null) - selectedGroup.Value = found; - } - } - - private void delete() - { - if (selectedGroup.Value == null) - return; - - Beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value); - - selectedGroup.Value = Beatmap.ControlPointInfo.Groups.FirstOrDefault(g => g.Time >= clock.CurrentTime); - } - - private void addNew() - { - bool isFirstControlPoint = !Beatmap.ControlPointInfo.TimingPoints.Any(); - - var group = Beatmap.ControlPointInfo.GroupAt(clock.CurrentTime, true); - - if (isFirstControlPoint) - group.Add(new TimingControlPoint()); - else - { - // Try and create matching types from the currently selected control point. - var selected = selectedGroup.Value; - - if (selected != null && !ReferenceEquals(selected, group)) - { - foreach (var controlPoint in selected.ControlPoints) - { - group.Add(controlPoint.DeepClone()); - } - } - } - - selectedGroup.Value = group; - } - } } } From 6d876fdb9af03782e74420c752cd40bed7394156 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 17:44:05 +0900 Subject: [PATCH 50/88] Automatically select the closest timing point on entering the timing screen --- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index a948da10cd..5d75ae2db5 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -14,6 +14,9 @@ namespace osu.Game.Screens.Edit.Timing [Cached] public readonly Bindable SelectedGroup = new Bindable(); + [Resolved] + private EditorClock? editorClock { get; set; } + public TimingScreen() : base(EditorScreenMode.Timing) { @@ -36,5 +39,19 @@ namespace osu.Game.Screens.Edit.Timing }, } }; + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (editorClock != null) + { + // When entering the timing screen, let's choose to closest valid timing point. + // This will emulate the osu-stable behaviour where a metronome and timing information + // are presented on entering the screen. + var nearestTimingPoint = EditorBeatmap.ControlPointInfo.TimingPointAt(editorClock.CurrentTime); + SelectedGroup.Value = EditorBeatmap.ControlPointInfo.GroupAt(nearestTimingPoint.Time); + } + } } } From 4f7d26b776a15b38f8ed8a2534dc7b1f3d2a80eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 18:29:39 +0900 Subject: [PATCH 51/88] Actually apply new parameter --- osu.Game/Online/Chat/ChannelManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 701a1cd040..e95bc128c8 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -583,7 +583,8 @@ namespace osu.Game.Online.Chat if (channel.Joined.Value) { - api.Queue(new LeaveChannelRequest(channel)); + if (sendLeaveRequest) + api.Queue(new LeaveChannelRequest(channel)); channel.Joined.Value = false; } } From 96fbd04698655ad7bb68f6048a2eb2e432b5a02a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 18:56:00 +0900 Subject: [PATCH 52/88] Add failing test coverage of skip no longer working in replay playback --- .../Visual/Gameplay/TestSceneReplayPlayer.cs | 82 +++++++++++++++---- .../Visual/RateAdjustedBeatmapTestScene.cs | 2 - 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs index 334d01f915..3e415af86e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs @@ -1,32 +1,64 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System.Linq; using NUnit.Framework; using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Play; +using osu.Game.Tests.Beatmaps; using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneReplayPlayer : RateAdjustedBeatmapTestScene { - protected TestReplayPlayer Player; - - public override void SetUpSteps() - { - base.SetUpSteps(); - - AddStep("Initialise player", () => Player = CreatePlayer(new OsuRuleset())); - AddStep("Load player", () => LoadScreen(Player)); - AddUntilStep("player loaded", () => Player.IsLoaded); - } + protected TestReplayPlayer Player = null!; [Test] public void TestPauseViaSpace() { + loadPlayerWithBeatmap(); + + double? lastTime = null; + + AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0); + + AddStep("Pause playback with space", () => InputManager.Key(Key.Space)); + + AddAssert("player not exited", () => Player.IsCurrentScreen()); + + AddUntilStep("Time stopped progressing", () => + { + double current = Player.GameplayClockContainer.CurrentTime; + bool changed = lastTime != current; + lastTime = current; + + return !changed; + }); + + AddWaitStep("wait some", 10); + + AddAssert("Time still stopped", () => lastTime == Player.GameplayClockContainer.CurrentTime); + } + + [Test] + public void TestPauseViaSpaceWithSkip() + { + loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo) + { + BeatmapInfo = { AudioLeadIn = 60000 } + }); + + AddUntilStep("wait for skip overlay", () => Player.ChildrenOfType().First().IsButtonVisible); + + AddStep("Skip with space", () => InputManager.Key(Key.Space)); + + AddAssert("Player not paused", () => !Player.DrawableRuleset.IsPaused.Value); + double? lastTime = null; AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0); @@ -52,6 +84,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestPauseViaMiddleMouse() { + loadPlayerWithBeatmap(); + double? lastTime = null; AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0); @@ -77,6 +111,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestSeekBackwards() { + loadPlayerWithBeatmap(); + double? lastTime = null; AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0); @@ -93,6 +129,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestSeekForwards() { + loadPlayerWithBeatmap(); + double? lastTime = null; AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0); @@ -106,12 +144,26 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("Jumped forwards", () => Player.GameplayClockContainer.CurrentTime - lastTime > 500); } - protected TestReplayPlayer CreatePlayer(Ruleset ruleset) + private void loadPlayerWithBeatmap(IBeatmap? beatmap = null) { - Beatmap.Value = CreateWorkingBeatmap(ruleset.RulesetInfo); + AddStep("create player", () => + { + CreatePlayer(new OsuRuleset(), beatmap); + }); + + AddStep("Load player", () => LoadScreen(Player)); + AddUntilStep("player loaded", () => Player.IsLoaded); + } + + protected void CreatePlayer(Ruleset ruleset, IBeatmap? beatmap = null) + { + Beatmap.Value = beatmap != null + ? CreateWorkingBeatmap(beatmap) + : CreateWorkingBeatmap(ruleset.RulesetInfo); + SelectedMods.Value = new[] { ruleset.GetAutoplayMod() }; - return new TestReplayPlayer(false); + Player = new TestReplayPlayer(false); } } } diff --git a/osu.Game/Tests/Visual/RateAdjustedBeatmapTestScene.cs b/osu.Game/Tests/Visual/RateAdjustedBeatmapTestScene.cs index 0f3f9f2199..a77ea80958 100644 --- a/osu.Game/Tests/Visual/RateAdjustedBeatmapTestScene.cs +++ b/osu.Game/Tests/Visual/RateAdjustedBeatmapTestScene.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. -#nullable disable - namespace osu.Game.Tests.Visual { /// From 5c795f492f7c284b3ca4657ad1a3bb7133b32e69 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 18:57:21 +0900 Subject: [PATCH 53/88] Reorder game key bindings to allow skip overlay to have precedence over replay controls --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 9d14ce95cf..d580eea248 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -35,8 +35,8 @@ namespace osu.Game.Input.Bindings // It is used to decide the order of precedence, with the earlier items having higher precedence. public override IEnumerable DefaultKeyBindings => GlobalKeyBindings .Concat(EditorKeyBindings) - .Concat(ReplayKeyBindings) .Concat(InGameKeyBindings) + .Concat(ReplayKeyBindings) .Concat(SongSelectKeyBindings) .Concat(AudioControlKeyBindings) // Overlay bindings may conflict with more local cases like the editor so they are checked last. From 81c3e0da317acb6af9b2ec8741f3db105505c821 Mon Sep 17 00:00:00 2001 From: Terochi Date: Fri, 10 Feb 2023 17:58:48 +0100 Subject: [PATCH 54/88] Fixed timeLeft counter in SongProgressInfo being out of bounds after rotation --- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 7f9f353ded..c04ecd671f 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -121,8 +121,8 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both, Child = new UprightAspectMaintainingContainer { - Origin = Anchor.CentreRight, - Anchor = Anchor.CentreRight, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, Scaling = ScaleMode.Vertical, ScalingFactor = 0.5f, From 11296c4ffe179ad172e0d1233244865445a91291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 10 Feb 2023 21:25:19 +0100 Subject: [PATCH 55/88] Use better exception type --- osu.Game/Users/Drawables/ClickableAvatar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index bb57958239..e74ffc9d54 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -23,7 +23,7 @@ namespace osu.Game.Users.Drawables return ShowUsernameTooltip ? (user?.Username ?? string.Empty) : default_tooltip_text; } - set => throw new InvalidOperationException(); + set => throw new NotSupportedException(); } /// From d30d054b4c4ad7de66af26ff41985658854f6f15 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 9 Feb 2023 21:28:51 -0800 Subject: [PATCH 56/88] Add ability to abort dangerous dialog button on hover lost --- osu.Game/Graphics/Containers/HoldToConfirmContainer.cs | 2 +- osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index cbe327bac7..0ac368dca7 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -102,7 +102,7 @@ namespace osu.Game.Graphics.Containers /// protected void AbortConfirm() { - if (!AllowMultipleFires && Fired) return; + if (!confirming || (!AllowMultipleFires && Fired)) return; confirming = false; Fired = false; diff --git a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs index 6b3716ac8d..dac589919f 100644 --- a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs +++ b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs @@ -95,6 +95,16 @@ namespace osu.Game.Overlays.Dialog } } + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + + if (!e.HasAnyButtonPressed) return; + + lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF); + AbortConfirm(); + } + private void progressChanged(ValueChangedEvent progress) { if (progress.NewValue < progress.OldValue) return; From bfd83768c1368f1c07f6d85ed03b44b71c5b1033 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 10 Feb 2023 17:58:34 -0800 Subject: [PATCH 57/88] Fix skin component previews on toolbox buttons having incorrect size for one frame --- osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index a8d64c1de8..28ceaf09fc 100644 --- a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -148,9 +148,9 @@ namespace osu.Game.Overlays.SkinEditor component.Origin = Anchor.Centre; } - protected override void Update() + protected override void UpdateAfterChildren() { - base.Update(); + base.UpdateAfterChildren(); if (component.DrawSize != Vector2.Zero) { From 94d6ab1ec7580ab03804a6436c4ec7ed62221e3a Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 10 Feb 2023 19:09:30 -0800 Subject: [PATCH 58/88] Continue confirming when rehovering if mouse is still down --- .../Overlays/Dialog/PopupDialogDangerousButton.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs index dac589919f..5cbdf54aad 100644 --- a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs +++ b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs @@ -57,6 +57,7 @@ namespace osu.Game.Overlays.Dialog private Sample confirmSample; private double lastTickPlaybackTime; private AudioFilter lowPassFilter = null!; + private bool mouseDown; [BackgroundDependencyLoader] private void load(AudioManager audio) @@ -83,6 +84,7 @@ namespace osu.Game.Overlays.Dialog protected override bool OnMouseDown(MouseDownEvent e) { BeginConfirm(); + mouseDown = true; return true; } @@ -92,14 +94,23 @@ namespace osu.Game.Overlays.Dialog { lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF); AbortConfirm(); + mouseDown = false; } } + protected override bool OnHover(HoverEvent e) + { + if (mouseDown) + BeginConfirm(); + + return base.OnHover(e); + } + protected override void OnHoverLost(HoverLostEvent e) { base.OnHoverLost(e); - if (!e.HasAnyButtonPressed) return; + if (!mouseDown) return; lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF); AbortConfirm(); From 86c86759105289ea88f2d719771deef1286ace18 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 11 Feb 2023 13:52:24 +0900 Subject: [PATCH 59/88] Update realm and other dependencies --- ...u.Game.Rulesets.EmptyFreeform.Tests.csproj | 4 ++-- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 4 ++-- ....Game.Rulesets.EmptyScrolling.Tests.csproj | 4 ++-- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 4 ++-- osu.Desktop/osu.Desktop.csproj | 5 +++-- .../osu.Game.Benchmarks.csproj | 5 +++-- .../osu.Game.Rulesets.Catch.Tests.csproj | 5 +++-- .../osu.Game.Rulesets.Catch.csproj | 4 ++++ .../osu.Game.Rulesets.Mania.Tests.csproj | 5 +++-- .../osu.Game.Rulesets.Mania.csproj | 4 ++++ .../osu.Game.Rulesets.Osu.Tests.csproj | 7 ++++--- .../osu.Game.Rulesets.Osu.csproj | 4 ++++ .../osu.Game.Rulesets.Taiko.Tests.csproj | 5 +++-- .../osu.Game.Rulesets.Taiko.csproj | 4 ++++ osu.Game.Tests/osu.Game.Tests.csproj | 7 ++++--- .../osu.Game.Tournament.Tests.csproj | 5 +++-- .../osu.Game.Tournament.csproj | 1 + osu.Game/osu.Game.csproj | 21 ++++++++++--------- 18 files changed, 62 insertions(+), 36 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj index 52b728a115..a1c53ece03 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj @@ -9,9 +9,9 @@ false - + - + diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 95b96adab0..683e9fd5e8 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -9,9 +9,9 @@ false - + - + diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj index d12403016d..b7a7fff18a 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj @@ -9,9 +9,9 @@ false - + - + diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 95b96adab0..683e9fd5e8 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -9,9 +9,9 @@ false - + - + diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 1f4544098b..6a89b2b018 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -26,8 +26,9 @@ - - + + + diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj index f47b069373..c6ed0d78be 100644 --- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj +++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj @@ -7,9 +7,10 @@ - + - + + diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 5a2e8e0bf0..131471592c 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -1,9 +1,10 @@  - + - + + WinExe diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index ecce7c1b3f..ee4399267c 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -15,4 +15,8 @@ + + + + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index be51dc0e4c..f2bde15494 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -1,9 +1,10 @@  - + - + + WinExe diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 72f172188e..7f59e32ed2 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -15,4 +15,8 @@ + + + + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index c10c3ffb15..38467a354e 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -1,10 +1,11 @@  - - + + - + + WinExe diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index bf776fe5dd..1bcf6e4308 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -15,4 +15,8 @@ + + + + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 6af1beff69..9878f0cfcc 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -1,9 +1,10 @@  - + - + + WinExe diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index f0e1cb8e8f..2f8681420c 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -15,4 +15,8 @@ + + + + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 24969414d0..9ea8bc0e7d 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -2,11 +2,12 @@ - + - - + + + WinExe diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index 9f2a088a4b..c54fe6b9a6 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -4,9 +4,10 @@ osu.Game.Tournament.Tests.TournamentTestRunner - + - + + WinExe diff --git a/osu.Game.Tournament/osu.Game.Tournament.csproj b/osu.Game.Tournament/osu.Game.Tournament.csproj index ab67e490cd..3822a80489 100644 --- a/osu.Game.Tournament/osu.Game.Tournament.csproj +++ b/osu.Game.Tournament/osu.Game.Tournament.csproj @@ -10,5 +10,6 @@ + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index cdb3d9b66b..b057e98b63 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,29 +18,29 @@ - + - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - + @@ -48,5 +48,6 @@ + From 20f3ab167e4c5585b3a4e8bd24a67ab0a3e2a166 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 11 Feb 2023 19:36:40 +0900 Subject: [PATCH 60/88] Re-centralise `BannedApiAnalysers` nuget package --- Directory.Build.props | 2 +- osu.Desktop/osu.Desktop.csproj | 1 - osu.Game.Benchmarks/osu.Game.Benchmarks.csproj | 1 - .../osu.Game.Rulesets.Catch.Tests.csproj | 1 - osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj | 4 ---- .../osu.Game.Rulesets.Mania.Tests.csproj | 1 - osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj | 4 ---- .../osu.Game.Rulesets.Osu.Tests.csproj | 1 - osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj | 4 ---- .../osu.Game.Rulesets.Taiko.Tests.csproj | 1 - osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj | 4 ---- osu.Game.Tests/osu.Game.Tests.csproj | 1 - osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj | 1 - osu.Game.Tournament/osu.Game.Tournament.csproj | 1 - osu.Game/osu.Game.csproj | 1 - 15 files changed, 1 insertion(+), 27 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 235feea8ce..3b6b985961 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -17,7 +17,7 @@ - + diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 6a89b2b018..f1b9c92429 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -28,7 +28,6 @@ - diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj index c6ed0d78be..4719d54138 100644 --- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj +++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj @@ -10,7 +10,6 @@ - diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 131471592c..01922b2a96 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -4,7 +4,6 @@ - WinExe diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index ee4399267c..ecce7c1b3f 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -15,8 +15,4 @@ - - - - diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index f2bde15494..027bf60a0c 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -4,7 +4,6 @@ - WinExe diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 7f59e32ed2..72f172188e 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -15,8 +15,4 @@ - - - - diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 38467a354e..57900bffd7 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -5,7 +5,6 @@ - WinExe diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 1bcf6e4308..bf776fe5dd 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -15,8 +15,4 @@ - - - - diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 9878f0cfcc..0c39ad988b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -4,7 +4,6 @@ - WinExe diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index 2f8681420c..f0e1cb8e8f 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -15,8 +15,4 @@ - - - - diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 9ea8bc0e7d..59a786a11d 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -7,7 +7,6 @@ - WinExe diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index c54fe6b9a6..5847079161 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -7,7 +7,6 @@ - WinExe diff --git a/osu.Game.Tournament/osu.Game.Tournament.csproj b/osu.Game.Tournament/osu.Game.Tournament.csproj index 3822a80489..ab67e490cd 100644 --- a/osu.Game.Tournament/osu.Game.Tournament.csproj +++ b/osu.Game.Tournament/osu.Game.Tournament.csproj @@ -10,6 +10,5 @@ - diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b057e98b63..65ea301cbd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -48,6 +48,5 @@ - From a3cc0d23b3e366c1d269f27fea020fb87a405eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 11 Feb 2023 16:26:32 +0100 Subject: [PATCH 61/88] Fix typo in xmldoc --- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 5d75ae2db5..3f911f5067 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Timing if (editorClock != null) { - // When entering the timing screen, let's choose to closest valid timing point. + // When entering the timing screen, let's choose the closest valid timing point. // This will emulate the osu-stable behaviour where a metronome and timing information // are presented on entering the screen. var nearestTimingPoint = EditorBeatmap.ControlPointInfo.TimingPointAt(editorClock.CurrentTime); From 8d9245c1d4f72db4307da7492d65bd09fc48bc02 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 11 Feb 2023 12:54:16 -0800 Subject: [PATCH 62/88] Make `AbortConfirm()` virtual and override with filter logic --- osu.Game/Graphics/Containers/HoldToConfirmContainer.cs | 2 +- osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index 0ac368dca7..9f21512825 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -100,7 +100,7 @@ namespace osu.Game.Graphics.Containers /// /// Abort any ongoing confirmation. Should be called when the container's interaction is no longer valid (ie. the user releases a key). /// - protected void AbortConfirm() + protected virtual void AbortConfirm() { if (!confirming || (!AllowMultipleFires && Fired)) return; diff --git a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs index 5cbdf54aad..19d7ea7a87 100644 --- a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs +++ b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs @@ -74,6 +74,12 @@ namespace osu.Game.Overlays.Dialog Progress.BindValueChanged(progressChanged); } + protected override void AbortConfirm() + { + lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF); + base.AbortConfirm(); + } + protected override void Confirm() { lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF); @@ -92,7 +98,6 @@ namespace osu.Game.Overlays.Dialog { if (!e.HasAnyButtonPressed) { - lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF); AbortConfirm(); mouseDown = false; } @@ -112,7 +117,6 @@ namespace osu.Game.Overlays.Dialog if (!mouseDown) return; - lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF); AbortConfirm(); } From 9d09141ab735232f3e24cbbb73b33e4934a6ccbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 12 Feb 2023 16:08:23 +0900 Subject: [PATCH 63/88] Move taiko-specific property out of `DrawableHitObject` --- osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs | 4 ++-- .../Objects/Drawables/DrawableTaikoHitObject.cs | 9 +++++++++ osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 9 --------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 300c72a854..d0361b1c8d 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -23,8 +23,8 @@ namespace osu.Game.Rulesets.Taiko.Mods public void ApplyToDrawableHitObject(DrawableHitObject drawable) { - if (drawable is DrawableHit) - drawable.SnapJudgementLocation = true; + if (drawable is DrawableTaikoHitObject hit) + hit.SnapJudgementLocation = true; } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 6172b75d2c..f912b5882c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -25,6 +25,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private readonly Container nonProxiedContent; + /// + /// Whether the location of the hit should be snapped to the hit target before animating. + /// + /// + /// This is how osu-stable worked, but notably is not how TnT works. + /// It results in less visual feedback on hit accuracy. + /// + public bool SnapJudgementLocation { get; set; } + protected DrawableTaikoHitObject([CanBeNull] TaikoHitObject hitObject) : base(hitObject) { diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 01550a113f..39f0888882 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -662,15 +662,6 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public virtual double MaximumJudgementOffset => HitObject.HitWindows?.WindowFor(HitResult.Miss) ?? 0; - /// - /// Whether the location of the hit should be snapped to the hit target before animating. - /// - /// - /// This is how osu-stable worked, but notably is not how TnT works. - /// It results in less visual feedback on hit accuracy. - /// - public bool SnapJudgementLocation { get; set; } - /// /// Applies the of this , notifying responders such as /// the of the . From 67b6df31725e2cefa9b530dd669646ce5349b2e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Feb 2023 13:31:29 +0100 Subject: [PATCH 64/88] Reword ambiguous xmldoc --- .../Objects/Drawables/DrawableTaikoHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index f912b5882c..f695c505a4 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// /// /// This is how osu-stable worked, but notably is not how TnT works. - /// It results in less visual feedback on hit accuracy. + /// Not snapping results in less visual feedback on hit accuracy. /// public bool SnapJudgementLocation { get; set; } From afb66d8af41517dc1ad85ed2f5798ea997a20193 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 12 Feb 2023 12:32:17 -0800 Subject: [PATCH 65/88] Make user activity class names more specific --- osu.Desktop/DiscordRichPresence.cs | 6 +++--- .../Visual/Online/TestSceneNowPlayingCommand.cs | 2 +- .../Visual/Online/TestSceneUserPanel.cs | 8 ++++---- osu.Game/Online/Chat/NowPlayingCommand.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Play/ReplayPlayer.cs | 2 +- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 2 +- osu.Game/Users/UserActivity.cs | 16 ++++++++-------- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index e24fe1a1ec..fe3e08537e 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -169,7 +169,7 @@ namespace osu.Desktop case UserActivity.InGame game: return game.BeatmapInfo; - case UserActivity.Editing edit: + case UserActivity.EditingBeatmap edit: return edit.BeatmapInfo; } @@ -183,10 +183,10 @@ namespace osu.Desktop case UserActivity.InGame game: return game.BeatmapInfo.ToString() ?? string.Empty; - case UserActivity.Editing edit: + case UserActivity.EditingBeatmap edit: return edit.BeatmapInfo.ToString() ?? string.Empty; - case UserActivity.Watching watching: + case UserActivity.WatchingReplay watching: return watching.BeatmapInfo.ToString(); case UserActivity.InLobby lobby: diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs index 4675410164..10c2b2b9e1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestEditActivity() { - AddStep("Set activity", () => api.Activity.Value = new UserActivity.Editing(new BeatmapInfo())); + AddStep("Set activity", () => api.Activity.Value = new UserActivity.EditingBeatmap(new BeatmapInfo())); AddStep("Run command", () => Add(new NowPlayingCommand(new Channel()))); diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index 64a42ee6ce..765af8cd8b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -109,15 +109,15 @@ namespace osu.Game.Tests.Visual.Online AddStep("set online status", () => status.Value = new UserStatusOnline()); AddStep("idle", () => activity.Value = null); - AddStep("watching", () => activity.Value = new UserActivity.Watching(createScore(@"nats"))); - AddStep("spectating", () => activity.Value = new UserActivity.Spectating(createScore(@"mrekk"))); + AddStep("watching replay", () => activity.Value = new UserActivity.WatchingReplay(createScore(@"nats"))); + AddStep("spectating user", () => activity.Value = new UserActivity.SpectatingUser(createScore(@"mrekk"))); AddStep("solo (osu!)", () => activity.Value = soloGameStatusForRuleset(0)); AddStep("solo (osu!taiko)", () => activity.Value = soloGameStatusForRuleset(1)); AddStep("solo (osu!catch)", () => activity.Value = soloGameStatusForRuleset(2)); AddStep("solo (osu!mania)", () => activity.Value = soloGameStatusForRuleset(3)); AddStep("choosing", () => activity.Value = new UserActivity.ChoosingBeatmap()); - AddStep("editing", () => activity.Value = new UserActivity.Editing(null)); - AddStep("modding", () => activity.Value = new UserActivity.Modding()); + AddStep("editing beatmap", () => activity.Value = new UserActivity.EditingBeatmap(null)); + AddStep("modding beatmap", () => activity.Value = new UserActivity.ModdingBeatmap()); } [Test] diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 9902704883..e7018d6993 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -61,7 +61,7 @@ namespace osu.Game.Online.Chat beatmapInfo = game.BeatmapInfo; break; - case UserActivity.Editing edit: + case UserActivity.EditingBeatmap edit: verb = "editing"; beatmapInfo = edit.BeatmapInfo; break; diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 0622cbebae..d9c2db9cec 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -157,7 +157,7 @@ namespace osu.Game.Screens.Edit private bool isNewBeatmap; - protected override UserActivity InitialActivity => new UserActivity.Editing(Beatmap.Value.BeatmapInfo); + protected override UserActivity InitialActivity => new UserActivity.EditingBeatmap(Beatmap.Value.BeatmapInfo); protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 9e87969687..8a4e63d21c 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Play private readonly bool replayIsFailedScore; - protected override UserActivity InitialActivity => new UserActivity.Watching(Score.ScoreInfo); + protected override UserActivity InitialActivity => new UserActivity.WatchingReplay(Score.ScoreInfo); // Disallow replays from failing. (see https://github.com/ppy/osu/issues/6108) protected override bool CheckModsAllowFailure() diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index 8a9cda2af7..c9d1f4acaa 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Play { private readonly Score score; - protected override UserActivity InitialActivity => new UserActivity.Spectating(Score.ScoreInfo); + protected override UserActivity InitialActivity => new UserActivity.SpectatingUser(Score.ScoreInfo); public SoloSpectatorPlayer(Score score, PlayerConfiguration configuration = null) : base(score, configuration) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index b1c3fac382..a1575d5fc4 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -18,9 +18,9 @@ namespace osu.Game.Users public virtual Color4 GetAppropriateColour(OsuColour colours) => colours.GreenDarker; - public class Modding : UserActivity + public class ModdingBeatmap : UserActivity { - public override string GetStatus(bool hideIdentifiableInformation = false) => "Modding a map"; + public override string GetStatus(bool hideIdentifiableInformation = false) => "Modding a beatmap"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark; } @@ -80,11 +80,11 @@ namespace osu.Game.Users } } - public class Editing : UserActivity + public class EditingBeatmap : UserActivity { public IBeatmapInfo BeatmapInfo { get; } - public Editing(IBeatmapInfo info) + public EditingBeatmap(IBeatmapInfo info) { BeatmapInfo = info; } @@ -92,7 +92,7 @@ namespace osu.Game.Users public override string GetStatus(bool hideIdentifiableInformation = false) => @"Editing a beatmap"; } - public class Watching : UserActivity + public class WatchingReplay : UserActivity { private readonly ScoreInfo score; @@ -100,7 +100,7 @@ namespace osu.Game.Users public BeatmapInfo BeatmapInfo => score.BeatmapInfo; - public Watching(ScoreInfo score) + public WatchingReplay(ScoreInfo score) { this.score = score; } @@ -108,11 +108,11 @@ namespace osu.Game.Users public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a replay" : $@"Watching {Username}'s replay"; } - public class Spectating : Watching + public class SpectatingUser : WatchingReplay { public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a user" : $@"Spectating {Username}"; - public Spectating(ScoreInfo score) + public SpectatingUser(ScoreInfo score) : base(score) { } From bbeef53569409900ae56816b0fefd83831d06b19 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 12 Feb 2023 13:04:12 -0800 Subject: [PATCH 66/88] Add `TestingBeatmap` activity --- osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs | 1 + osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs | 3 +++ osu.Game/Users/UserActivity.cs | 10 ++++++++++ 3 files changed, 14 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index 765af8cd8b..737bc948d6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -118,6 +118,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("choosing", () => activity.Value = new UserActivity.ChoosingBeatmap()); AddStep("editing beatmap", () => activity.Value = new UserActivity.EditingBeatmap(null)); AddStep("modding beatmap", () => activity.Value = new UserActivity.ModdingBeatmap()); + AddStep("testing beatmap", () => activity.Value = new UserActivity.TestingBeatmap(null, null)); } [Test] diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index e7db1c105b..7dff05667d 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs @@ -7,6 +7,7 @@ using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Screens.Play; +using osu.Game.Users; namespace osu.Game.Screens.Edit.GameplayTest { @@ -15,6 +16,8 @@ namespace osu.Game.Screens.Edit.GameplayTest private readonly Editor editor; private readonly EditorState editorState; + protected override UserActivity InitialActivity => new UserActivity.TestingBeatmap(Beatmap.Value.BeatmapInfo, Ruleset.Value); + [Resolved] private MusicController musicController { get; set; } = null!; diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index a1575d5fc4..4e0fad34d0 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -80,6 +80,16 @@ namespace osu.Game.Users } } + public class TestingBeatmap : InGame + { + public override string GetStatus(bool hideIdentifiableInformation = false) => "Testing a beatmap"; + + public TestingBeatmap(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset) + : base(beatmapInfo, ruleset) + { + } + } + public class EditingBeatmap : UserActivity { public IBeatmapInfo BeatmapInfo { get; } From cb51b9e350530b6e98f89ef627157452127fa099 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 12 Feb 2023 13:11:55 -0800 Subject: [PATCH 67/88] Use existing `ModdingBeatmap` activity --- osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 11 ++++++++++- osu.Game/Users/UserActivity.cs | 7 ++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index 737bc948d6..a047e2f0c5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("solo (osu!mania)", () => activity.Value = soloGameStatusForRuleset(3)); AddStep("choosing", () => activity.Value = new UserActivity.ChoosingBeatmap()); AddStep("editing beatmap", () => activity.Value = new UserActivity.EditingBeatmap(null)); - AddStep("modding beatmap", () => activity.Value = new UserActivity.ModdingBeatmap()); + AddStep("modding beatmap", () => activity.Value = new UserActivity.ModdingBeatmap(null)); AddStep("testing beatmap", () => activity.Value = new UserActivity.TestingBeatmap(null, null)); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index d9c2db9cec..bd133383d1 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -157,7 +157,16 @@ namespace osu.Game.Screens.Edit private bool isNewBeatmap; - protected override UserActivity InitialActivity => new UserActivity.EditingBeatmap(Beatmap.Value.BeatmapInfo); + protected override UserActivity InitialActivity + { + get + { + if (Beatmap.Value.Metadata.Author.OnlineID == api.LocalUser.Value.OnlineID) + return new UserActivity.EditingBeatmap(Beatmap.Value.BeatmapInfo); + + return new UserActivity.ModdingBeatmap(Beatmap.Value.BeatmapInfo); + } + } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 4e0fad34d0..0b11d12c46 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -18,10 +18,15 @@ namespace osu.Game.Users public virtual Color4 GetAppropriateColour(OsuColour colours) => colours.GreenDarker; - public class ModdingBeatmap : UserActivity + public class ModdingBeatmap : EditingBeatmap { public override string GetStatus(bool hideIdentifiableInformation = false) => "Modding a beatmap"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark; + + public ModdingBeatmap(IBeatmapInfo info) + : base(info) + { + } } public class ChoosingBeatmap : UserActivity From 006356e61777968d96957304cb31233c4587104b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 13 Feb 2023 14:17:33 +0300 Subject: [PATCH 68/88] Add TestSceneLetterboxOverlay --- .../Gameplay/TestSceneLetterboxOverlay.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneLetterboxOverlay.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneLetterboxOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneLetterboxOverlay.cs new file mode 100644 index 0000000000..ce93837925 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneLetterboxOverlay.cs @@ -0,0 +1,24 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Game.Screens.Play.Break; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public partial class TestSceneLetterboxOverlay : OsuTestScene + { + public TestSceneLetterboxOverlay() + { + AddRange(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both + }, + new LetterboxOverlay() + }); + } + } +} From 35bc0a29d8a890b936737035fd33f962fb7eae9d Mon Sep 17 00:00:00 2001 From: PC Date: Mon, 13 Feb 2023 15:11:55 +0300 Subject: [PATCH 69/88] Add setting skin on notification click --- osu.Game/Skinning/SkinManager.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index fca7dc0f5e..02be3abab7 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -87,6 +87,15 @@ namespace osu.Game.Skinning skinImporter = new SkinImporter(storage, realm, this) { PostNotification = obj => PostNotification?.Invoke(obj), + PresentImport = skins => + { + switch (skins.Count()) + { + case 1: + CurrentSkinInfo.Value = skins.Last(); + break; + } + }, }; var defaultSkins = new[] From 2dee783401b06da5dc9663b1ad4e6cfdfdca4419 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 13 Feb 2023 15:14:25 +0300 Subject: [PATCH 70/88] Remove not needed containers --- .../Screens/Play/Break/LetterboxOverlay.cs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/Break/LetterboxOverlay.cs b/osu.Game/Screens/Play/Break/LetterboxOverlay.cs index 92b432831d..c4e2dbf403 100644 --- a/osu.Game/Screens/Play/Break/LetterboxOverlay.cs +++ b/osu.Game/Screens/Play/Break/LetterboxOverlay.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -22,29 +20,21 @@ namespace osu.Game.Screens.Play.Break RelativeSizeAxes = Axes.Both; InternalChildren = new Drawable[] { - new Container + new Box { Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, RelativeSizeAxes = Axes.X, Height = height, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.Black, transparent_black), - } + Colour = ColourInfo.GradientVertical(Color4.Black, transparent_black), }, - new Container + new Box { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, Height = height, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(transparent_black, Color4.Black), - } + Colour = ColourInfo.GradientVertical(transparent_black, Color4.Black), } }; } From a22a36bfe0c24a6bbbced56b9562ba0c2d4f1efd Mon Sep 17 00:00:00 2001 From: PC Date: Mon, 13 Feb 2023 20:31:09 +0300 Subject: [PATCH 71/88] Add navigation to skin settings on multiple import --- .../Overlays/Settings/Sections/SkinSection.cs | 23 +++++++++++++++++++ osu.Game/Skinning/SkinManager.cs | 12 +++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 5cf8157812..189db829bf 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -10,6 +10,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Logging; @@ -49,6 +50,9 @@ namespace osu.Game.Overlays.Settings.Sections [Resolved] private RealmAccess realm { get; set; } + [Resolved] + private SettingsOverlay settings { get; set; } + private IDisposable realmSubscription; [BackgroundDependencyLoader(permitNulls: true)] @@ -91,6 +95,25 @@ namespace osu.Game.Overlays.Settings.Sections skins.SelectRandomSkin(); } }); + + skins.PresentSkinsImport += presentSkinsImport; + } + + private void presentSkinsImport(IEnumerable> importedSkins) + { + switch (importedSkins.Count()) + { + case 1: + skins.CurrentSkinInfo.Value = importedSkins.Last(); + break; + + case > 1: + if (settings?.State.Value == Visibility.Hidden) + settings?.ToggleVisibility(); + + settings?.SectionsContainer.ScrollTo(this); + break; + } } private void skinsChanged(IRealmCollection sender, ChangeSet changes, Exception error) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 02be3abab7..2921a5bc17 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -44,6 +44,8 @@ namespace osu.Game.Skinning /// public Skin DefaultClassicSkin { get; } + public Action>> PresentSkinsImport { get; set; } + private readonly AudioManager audio; private readonly Scheduler scheduler; @@ -87,15 +89,7 @@ namespace osu.Game.Skinning skinImporter = new SkinImporter(storage, realm, this) { PostNotification = obj => PostNotification?.Invoke(obj), - PresentImport = skins => - { - switch (skins.Count()) - { - case 1: - CurrentSkinInfo.Value = skins.Last(); - break; - } - }, + PresentImport = skins => PresentSkinsImport?.Invoke(skins), }; var defaultSkins = new[] From 637b07efe6eb4f6619b66a5c0a1214c39ef6ffdd Mon Sep 17 00:00:00 2001 From: PC Date: Mon, 13 Feb 2023 22:36:51 +0300 Subject: [PATCH 72/88] Remove `Resolved` attribute --- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 189db829bf..f83ec95f93 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -50,9 +50,6 @@ namespace osu.Game.Overlays.Settings.Sections [Resolved] private RealmAccess realm { get; set; } - [Resolved] - private SettingsOverlay settings { get; set; } - private IDisposable realmSubscription; [BackgroundDependencyLoader(permitNulls: true)] @@ -101,6 +98,8 @@ namespace osu.Game.Overlays.Settings.Sections private void presentSkinsImport(IEnumerable> importedSkins) { + SettingsOverlay settings = this.FindClosestParent(); + switch (importedSkins.Count()) { case 1: From 46b13f2565316020c88cd0d0e81421b09721947b Mon Sep 17 00:00:00 2001 From: PC Date: Mon, 13 Feb 2023 22:44:11 +0300 Subject: [PATCH 73/88] Improve code quality --- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index f83ec95f93..cb1083c519 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -107,10 +107,10 @@ namespace osu.Game.Overlays.Settings.Sections break; case > 1: - if (settings?.State.Value == Visibility.Hidden) - settings?.ToggleVisibility(); + if (settings.State.Value == Visibility.Hidden) + settings.ToggleVisibility(); - settings?.SectionsContainer.ScrollTo(this); + settings.SectionsContainer.ScrollTo(this); break; } } From 10ab228d76270572fcfd335b3edcbe85efdf00e8 Mon Sep 17 00:00:00 2001 From: PC Date: Mon, 13 Feb 2023 22:47:29 +0300 Subject: [PATCH 74/88] Improve xml doc --- osu.Game/Skinning/SkinManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 2921a5bc17..8b7c886b3b 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -44,6 +44,9 @@ namespace osu.Game.Skinning /// public Skin DefaultClassicSkin { get; } + /// + /// Presents imported skin(s) to a user + /// public Action>> PresentSkinsImport { get; set; } private readonly AudioManager audio; From 6e6421caea281efd081f9a11b5bfa87cea10cf70 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 13 Feb 2023 22:07:09 +0100 Subject: [PATCH 75/88] Change FooterV2.cs colour to use `ColourProvider` instead of `OsuColour`. Remove unnecessary `FillFlowContainer` --- .../SongSelect/TestSceneSongSelectFooterV2.cs | 3 +++ osu.Game/Screens/Select/FooterV2/FooterV2.cs | 25 ++++++------------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs index 773d067c15..72adbfc104 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs @@ -24,6 +24,9 @@ namespace osu.Game.Tests.Visual.SongSelect private DummyOverlay overlay = null!; + [Cached] + private OverlayColourProvider colourProvider { get; set; } = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + [SetUp] public void SetUp() => Schedule(() => { diff --git a/osu.Game/Screens/Select/FooterV2/FooterV2.cs b/osu.Game/Screens/Select/FooterV2/FooterV2.cs index 2bfa03d319..cd95f3eb6c 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterV2.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; using osuTK; namespace osu.Game.Screens.Select.FooterV2 @@ -48,7 +49,7 @@ namespace osu.Game.Screens.Select.FooterV2 private FillFlowContainer buttons = null!; [BackgroundDependencyLoader] - private void load(OsuColour colour) + private void load(OverlayColourProvider colourProvider) { RelativeSizeAxes = Axes.X; Height = height; @@ -57,28 +58,16 @@ namespace osu.Game.Screens.Select.FooterV2 new Box { RelativeSizeAxes = Axes.Both, - Colour = colour.B5 + Colour = colourProvider.Background5 }, - new FillFlowContainer + buttons = new FillFlowContainer { + Position = new Vector2(TwoLayerButton.SIZE_EXTENDED.X + padding, 10), Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Position = new Vector2(TwoLayerButton.SIZE_EXTENDED.X + padding, 10), - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, Direction = FillDirection.Horizontal, - Spacing = new Vector2(padding, 0), - Children = new Drawable[] - { - buttons = new FillFlowContainer - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(-FooterButtonV2.SHEAR_WIDTH + 7, 0), - AutoSizeAxes = Axes.Both - } - } + Spacing = new Vector2(-FooterButtonV2.SHEAR_WIDTH + 7, 0), + AutoSizeAxes = Axes.Both } }; } From 61584ba63c30b7f30f6338dc7262fd12f9d8ca25 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 13 Feb 2023 22:15:29 +0100 Subject: [PATCH 76/88] Fix corner_radius missing in some parts of `FooterButtonV2.cs`. Adjust shadow radius value to 5 to match figma. --- osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 409d9daaae..9d94475a8f 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -74,8 +74,7 @@ namespace osu.Game.Screens.Select.FooterV2 { Type = EdgeEffectType.Shadow, Radius = 5, - Roundness = 10, - Colour = Colour4.Black.Opacity(0.25f) + Colour = Colour4.Black.Opacity(0.5f) }; Shear = SHEAR; Size = new Vector2(button_width, button_height); @@ -124,7 +123,7 @@ namespace osu.Game.Screens.Select.FooterV2 Shear = -SHEAR, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, - Y = -10, + Y = -corner_radius, Size = new Vector2(120, 6), Masking = true, CornerRadius = 3, From be52d0a60c960451749a4bd3d6bc7256bfb65d76 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 13 Feb 2023 22:17:02 +0100 Subject: [PATCH 77/88] Add note explaining shadow opacity pass ColourProvider in from test, instead of hard coding it in `FooterButtonV2.cs` --- osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index 9d94475a8f..c172b6725a 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -36,8 +36,8 @@ namespace osu.Game.Screens.Select.FooterV2 protected static readonly Vector2 SHEAR = new Vector2(SHEAR_WIDTH / button_height, 0); - [Cached] - private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; private Colour4 buttonAccentColour; @@ -74,7 +74,8 @@ namespace osu.Game.Screens.Select.FooterV2 { Type = EdgeEffectType.Shadow, Radius = 5, - Colour = Colour4.Black.Opacity(0.5f) + // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. + Colour = Colour4.Black.Opacity(0.25f) }; Shear = SHEAR; Size = new Vector2(button_width, button_height); From ae9a17d76bc29eb45e7792af8b9250477e751217 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 13 Feb 2023 22:20:41 +0100 Subject: [PATCH 78/88] Add offset to `FooterButtonV2.cs` shadow --- osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index c172b6725a..d85eafa15f 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -75,7 +75,8 @@ namespace osu.Game.Screens.Select.FooterV2 Type = EdgeEffectType.Shadow, Radius = 5, // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. - Colour = Colour4.Black.Opacity(0.25f) + Colour = Colour4.Black.Opacity(0.25f), + Offset = new Vector2(0, 2), }; Shear = SHEAR; Size = new Vector2(button_width, button_height); From 7f7e72705faf247c1ef9e3d107550359c3ea6254 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 13 Feb 2023 14:15:37 -0800 Subject: [PATCH 79/88] Fix beatmap card song preview progress sometimes showing past progress for one frame --- osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs index f808fd21b7..8304cdfc08 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs @@ -75,9 +75,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons Playing.BindValueChanged(updateState, true); } - protected override void Update() + protected override void UpdateAfterChildren() { - base.Update(); + base.UpdateAfterChildren(); if (Playing.Value && previewTrack != null && previewTrack.TrackLoaded) progress.Value = previewTrack.CurrentTime / previewTrack.Length; From 5006dbe3db1f6f8056b27e5d4e58eba526885e55 Mon Sep 17 00:00:00 2001 From: MK56 <74463310+mk56-spn@users.noreply.github.com> Date: Tue, 14 Feb 2023 00:07:02 +0100 Subject: [PATCH 80/88] Update osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs Co-authored-by: Joseph Madamba --- osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs index d85eafa15f..2f5046d2bb 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Select.FooterV2 EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, - Radius = 5, + Radius = 4, // Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad. Colour = Colour4.Black.Opacity(0.25f), Offset = new Vector2(0, 2), From f8f485e4c8b8d4e149bbbb244d1098d9353f1c62 Mon Sep 17 00:00:00 2001 From: PC Date: Tue, 14 Feb 2023 02:29:50 +0300 Subject: [PATCH 81/88] Move `PresentSkinsImport` to `OsuGame`. Replace switch with if statement --- osu.Game/OsuGame.cs | 20 +++++++++++++++++ .../Overlays/Settings/Sections/SkinSection.cs | 22 ------------------- osu.Game/Skinning/SkinManager.cs | 6 ----- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index df3d8b99f4..900c07b3c5 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -49,6 +49,7 @@ using osu.Game.Overlays; using osu.Game.Overlays.BeatmapListing; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; +using osu.Game.Overlays.Settings.Sections; using osu.Game.Overlays.SkinEditor; using osu.Game.Overlays.Toolbar; using osu.Game.Overlays.Volume; @@ -60,6 +61,7 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; +using osu.Game.Skinning; using osu.Game.Updater; using osu.Game.Users; using osu.Game.Utils; @@ -501,6 +503,23 @@ namespace osu.Game /// The build version of the update stream public void ShowChangelogBuild(string updateStream, string version) => waitForReady(() => changelogOverlay, _ => changelogOverlay.ShowBuild(updateStream, version)); + /// + /// Present ether a skin select if one skin was imported or navigate to the skin selection menu if multiple skins were imported immediately. + /// + /// List of imported skins + public void PresentSkins(IEnumerable> importedSkins) + { + int importedSkinsCount = importedSkins.Count(); + + if (importedSkinsCount == 1) + SkinManager.CurrentSkinInfo.Value = importedSkins.Single(); + else if (importedSkinsCount > 1) + { + Settings.Show(); + Settings.SectionsContainer.ScrollTo(Settings.SectionsContainer.Single(container => container is SkinSection)); + } + } + /// /// Present a beatmap at song select immediately. /// The user should have already requested this interactively. @@ -777,6 +796,7 @@ namespace osu.Game // todo: all archive managers should be able to be looped here. SkinManager.PostNotification = n => Notifications.Post(n); + SkinManager.PresentImport = PresentSkins; BeatmapManager.PostNotification = n => Notifications.Post(n); BeatmapManager.PresentImport = items => PresentBeatmap(items.First().Value); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index cb1083c519..5cf8157812 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -10,7 +10,6 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Logging; @@ -92,27 +91,6 @@ namespace osu.Game.Overlays.Settings.Sections skins.SelectRandomSkin(); } }); - - skins.PresentSkinsImport += presentSkinsImport; - } - - private void presentSkinsImport(IEnumerable> importedSkins) - { - SettingsOverlay settings = this.FindClosestParent(); - - switch (importedSkins.Count()) - { - case 1: - skins.CurrentSkinInfo.Value = importedSkins.Last(); - break; - - case > 1: - if (settings.State.Value == Visibility.Hidden) - settings.ToggleVisibility(); - - settings.SectionsContainer.ScrollTo(this); - break; - } } private void skinsChanged(IRealmCollection sender, ChangeSet changes, Exception error) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 8b7c886b3b..fca7dc0f5e 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -44,11 +44,6 @@ namespace osu.Game.Skinning /// public Skin DefaultClassicSkin { get; } - /// - /// Presents imported skin(s) to a user - /// - public Action>> PresentSkinsImport { get; set; } - private readonly AudioManager audio; private readonly Scheduler scheduler; @@ -92,7 +87,6 @@ namespace osu.Game.Skinning skinImporter = new SkinImporter(storage, realm, this) { PostNotification = obj => PostNotification?.Invoke(obj), - PresentImport = skins => PresentSkinsImport?.Invoke(skins), }; var defaultSkins = new[] From 24a5a1061f792e4f2b5c6bc6927bda47f051693f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 13 Feb 2023 10:18:45 -0800 Subject: [PATCH 82/88] Fix `OsuClickableContainer` sounds not being blocked by nested drawables --- osu.Game/Graphics/Containers/OsuClickableContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index 6fe1de2216..fceee90d06 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -46,8 +46,8 @@ namespace osu.Game.Graphics.Containers AddRangeInternal(new Drawable[] { + CreateHoverSounds(sampleSet), content, - CreateHoverSounds(sampleSet) }); } From f0ebb920b905a6daa0fe1bc381e50c841f449626 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 13:54:00 +0900 Subject: [PATCH 83/88] Make `Action`s nullable --- osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs index e3882588d9..70d1c0c19e 100644 --- a/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs +++ b/osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs @@ -17,8 +17,8 @@ namespace osu.Game.Screens.Select.FooterV2 { public partial class FooterButtonRandomV2 : FooterButtonV2 { - public Action NextRandom { get; set; } = null!; - public Action PreviousRandom { get; set; } = null!; + public Action? NextRandom { get; set; } + public Action? PreviousRandom { get; set; } private Container persistentText = null!; private OsuSpriteText randomSpriteText = null!; @@ -83,11 +83,11 @@ namespace osu.Game.Screens.Select.FooterV2 persistentText.FadeInFromZero(fade_time, Easing.In); - PreviousRandom.Invoke(); + PreviousRandom?.Invoke(); } else { - NextRandom.Invoke(); + NextRandom?.Invoke(); } }; } From 90643912262ef9e79531802aaa49a0eddb489ce3 Mon Sep 17 00:00:00 2001 From: PC Date: Tue, 14 Feb 2023 08:24:03 +0300 Subject: [PATCH 84/88] Use `ChildrenOfType` instead of linq --- osu.Game/OsuGame.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 900c07b3c5..ddba5667d8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -29,6 +29,7 @@ using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Framework.Testing; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Collections; @@ -516,7 +517,7 @@ namespace osu.Game else if (importedSkinsCount > 1) { Settings.Show(); - Settings.SectionsContainer.ScrollTo(Settings.SectionsContainer.Single(container => container is SkinSection)); + Settings.SectionsContainer.ScrollTo(Settings.SectionsContainer.ChildrenOfType().Single()); } } From ea624b8ad0fa0d9fd78e192edb986abb360f6b3f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 13 Feb 2023 22:39:34 -0800 Subject: [PATCH 85/88] Reset preview track when stopping instead --- osu.Game/Audio/PreviewTrack.cs | 3 +++ osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 2c63c16274..d625566ee7 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -98,6 +98,9 @@ namespace osu.Game.Audio Track.Stop(); + // Ensure the track is reset immediately on stopping, so the next time it is started it has a correct time value. + Track.Seek(0); + Stopped?.Invoke(); } diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs index 8304cdfc08..f808fd21b7 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs @@ -75,9 +75,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons Playing.BindValueChanged(updateState, true); } - protected override void UpdateAfterChildren() + protected override void Update() { - base.UpdateAfterChildren(); + base.Update(); if (Playing.Value && previewTrack != null && previewTrack.TrackLoaded) progress.Value = previewTrack.CurrentTime / previewTrack.Length; From ca2603324cf28123ce3448ff90119034920043dc Mon Sep 17 00:00:00 2001 From: PC Date: Tue, 14 Feb 2023 09:43:40 +0300 Subject: [PATCH 86/88] Change present from skin selection tab to `SkinCollection.First()` --- osu.Game/OsuGame.cs | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ddba5667d8..56e17107b6 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -29,7 +29,6 @@ using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Screens; -using osu.Framework.Testing; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Collections; @@ -50,7 +49,6 @@ using osu.Game.Overlays; using osu.Game.Overlays.BeatmapListing; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; -using osu.Game.Overlays.Settings.Sections; using osu.Game.Overlays.SkinEditor; using osu.Game.Overlays.Toolbar; using osu.Game.Overlays.Volume; @@ -505,21 +503,10 @@ namespace osu.Game public void ShowChangelogBuild(string updateStream, string version) => waitForReady(() => changelogOverlay, _ => changelogOverlay.ShowBuild(updateStream, version)); /// - /// Present ether a skin select if one skin was imported or navigate to the skin selection menu if multiple skins were imported immediately. + /// Present a skin select immediately. /// - /// List of imported skins - public void PresentSkins(IEnumerable> importedSkins) - { - int importedSkinsCount = importedSkins.Count(); - - if (importedSkinsCount == 1) - SkinManager.CurrentSkinInfo.Value = importedSkins.Single(); - else if (importedSkinsCount > 1) - { - Settings.Show(); - Settings.SectionsContainer.ScrollTo(Settings.SectionsContainer.ChildrenOfType().Single()); - } - } + /// Skin to select + public void PresentSkin(Live importedSkin) => SkinManager.CurrentSkinInfo.Value = importedSkin; /// /// Present a beatmap at song select immediately. @@ -797,7 +784,7 @@ namespace osu.Game // todo: all archive managers should be able to be looped here. SkinManager.PostNotification = n => Notifications.Post(n); - SkinManager.PresentImport = PresentSkins; + SkinManager.PresentImport = items => PresentSkin(items.First()); BeatmapManager.PostNotification = n => Notifications.Post(n); BeatmapManager.PresentImport = items => PresentBeatmap(items.First().Value); From 21429e164ff7e6364a24c50bd382984cf10977c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 15:55:31 +0900 Subject: [PATCH 87/88] Fix comment grammar --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 56e17107b6..6fc420e437 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -505,7 +505,7 @@ namespace osu.Game /// /// Present a skin select immediately. /// - /// Skin to select + /// The skin to select. public void PresentSkin(Live importedSkin) => SkinManager.CurrentSkinInfo.Value = importedSkin; /// From 0ad245e9e031468bbbb86e30f8f641397160bcab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 16:00:22 +0900 Subject: [PATCH 88/88] Rewrite implementation to match other implementations --- osu.Game/OsuGame.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 6fc420e437..7c9b03bd5b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -505,8 +505,19 @@ namespace osu.Game /// /// Present a skin select immediately. /// - /// The skin to select. - public void PresentSkin(Live importedSkin) => SkinManager.CurrentSkinInfo.Value = importedSkin; + /// The skin to select. + public void PresentSkin(SkinInfo skin) + { + var databasedSkin = SkinManager.Query(s => s.ID == skin.ID); + + if (databasedSkin == null) + { + Logger.Log("The requested skin could not be loaded.", LoggingTarget.Information); + return; + } + + SkinManager.CurrentSkinInfo.Value = databasedSkin; + } /// /// Present a beatmap at song select immediately. @@ -784,7 +795,7 @@ namespace osu.Game // todo: all archive managers should be able to be looped here. SkinManager.PostNotification = n => Notifications.Post(n); - SkinManager.PresentImport = items => PresentSkin(items.First()); + SkinManager.PresentImport = items => PresentSkin(items.First().Value); BeatmapManager.PostNotification = n => Notifications.Post(n); BeatmapManager.PresentImport = items => PresentBeatmap(items.First().Value);