From c1077d909ca5e41270522714e8457733a36043f2 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Sat, 17 Sep 2022 21:09:34 +0200 Subject: [PATCH 001/516] Basic avatar HUD implementation --- osu.Game/Screens/Play/HUD/SkinnableAvatar.cs | 50 ++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 osu.Game/Screens/Play/HUD/SkinnableAvatar.cs diff --git a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs new file mode 100644 index 0000000000..abec4402a7 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs @@ -0,0 +1,50 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; +using osu.Game.Skinning; +using osu.Game.Users.Drawables; +using osuTK; + +namespace osu.Game.Screens.Play.HUD +{ + public class SkinnableAvatar : CompositeDrawable, ISkinnableDrawable + { + [SettingSource("Corner radius", "How much the edges should be rounded.")] + public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0) + { + MinValue = 0, + MaxValue = 100, + Precision = 0.01f + }; + + [Resolved] + private GameplayState gameplayState { get; set; } = null!; + + private readonly UpdateableAvatar avatar; + + public SkinnableAvatar() + { + Size = new Vector2(128f); + InternalChild = avatar = new UpdateableAvatar(isInteractive: false) + { + RelativeSizeAxes = Axes.Both, + Masking = true + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + avatar.User = gameplayState.Score.ScoreInfo.User; + CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue); + } + + public bool UsesFixedAnchor { get; set; } + } +} From ecf71df8a23bfca5cbe5a78daef23908135d92c2 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Sun, 18 Sep 2022 00:04:56 +0200 Subject: [PATCH 002/516] Change CornerRadius Max Value --- osu.Game/Screens/Play/HUD/SkinnableAvatar.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs index abec4402a7..d675176a0a 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs @@ -15,10 +15,10 @@ namespace osu.Game.Screens.Play.HUD public class SkinnableAvatar : CompositeDrawable, ISkinnableDrawable { [SettingSource("Corner radius", "How much the edges should be rounded.")] - public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0) + public new BindableFloat CornerRadius { get; set; } = new BindableFloat { MinValue = 0, - MaxValue = 100, + MaxValue = 63, Precision = 0.01f }; From 18b4317e99921e133aed5549a00e0b31445a63cf Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 1 Dec 2022 11:57:50 +0100 Subject: [PATCH 003/516] 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 004/516] 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 005/516] 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 006/516] 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 007/516] 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 008/516] 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 009/516] 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 010/516] 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 011/516] 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 012/516] 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 013/516] 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 83b8d8ad8cb8cb00cf58ba148fb427b0bde86e94 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 1 Jan 2023 16:48:47 -0800 Subject: [PATCH 014/516] Add failing replay player mouse middle pause test --- .../Visual/Gameplay/TestSceneReplayPlayer.cs | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs index e0a6a60ff2..601fe445f0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs @@ -4,6 +4,7 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Screens; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osuTK.Input; @@ -23,14 +24,29 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("player loaded", () => Player.IsLoaded); } - [Test] - public void TestPause() + [TestCase("space")] + [TestCase("mouse middle")] + public void TestPause(string action) { double? lastTime = null; AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0); - AddStep("Pause playback", () => InputManager.Key(Key.Space)); + AddStep("Pause playback", () => + { + switch (action) + { + case "space": + InputManager.Key(Key.Space); + break; + + case "mouse middle": + InputManager.Click(MouseButton.Middle); + break; + } + }); + + AddAssert("player not exited", () => Player.IsCurrentScreen()); AddUntilStep("Time stopped progressing", () => { From d79ee29f29c64a1922bf32c2f1de34be6b5e8e68 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 1 Jan 2023 18:00:39 -0800 Subject: [PATCH 015/516] Make replays pause with middle mouse button instead of exiting --- .../Screens/Play/HUD/HoldForMenuButton.cs | 19 ++++++++++++++++++- osu.Game/Screens/Play/Player.cs | 3 ++- osu.Game/Screens/Play/ReplayPlayer.cs | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index f902e0903d..0921a9f18a 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -31,6 +31,8 @@ namespace osu.Game.Screens.Play.HUD public readonly Bindable IsPaused = new Bindable(); + public readonly Bindable ReplayLoaded = new Bindable(); + private HoldButton button; public Action Action { get; set; } @@ -60,6 +62,7 @@ namespace osu.Game.Screens.Play.HUD HoverGained = () => text.FadeIn(500, Easing.OutQuint), HoverLost = () => text.FadeOut(500, Easing.OutQuint), IsPaused = { BindTarget = IsPaused }, + ReplayLoaded = { BindTarget = ReplayLoaded }, Action = () => Action(), } }; @@ -110,6 +113,8 @@ namespace osu.Game.Screens.Play.HUD public readonly Bindable IsPaused = new Bindable(); + public readonly Bindable ReplayLoaded = new Bindable(); + protected override bool AllowMultipleFires => true; public Action HoverGained; @@ -251,7 +256,14 @@ namespace osu.Game.Screens.Play.HUD switch (e.Action) { case GlobalAction.Back: - case GlobalAction.PauseGameplay: // in the future this behaviour will differ for replays etc. + if (!pendingAnimation) + BeginConfirm(); + return true; + + case GlobalAction.PauseGameplay: + // handled by replay player + if (ReplayLoaded.Value) return false; + if (!pendingAnimation) BeginConfirm(); return true; @@ -265,7 +277,12 @@ namespace osu.Game.Screens.Play.HUD switch (e.Action) { case GlobalAction.Back: + AbortConfirm(); + break; + case GlobalAction.PauseGameplay: + if (ReplayLoaded.Value) return; + AbortConfirm(); break; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 05133fba35..7fe81987c8 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -433,7 +433,8 @@ namespace osu.Game.Screens.Play HoldToQuit = { Action = () => PerformExit(true), - IsPaused = { BindTarget = GameplayClockContainer.IsPaused } + IsPaused = { BindTarget = GameplayClockContainer.IsPaused }, + ReplayLoaded = { BindTarget = DrawableRuleset.HasReplayLoaded }, }, KeyCounter = { diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index c5ef6b1585..77ee7bc113 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -81,6 +81,7 @@ namespace osu.Game.Screens.Play return true; case GlobalAction.TogglePauseReplay: + case GlobalAction.PauseGameplay: if (GameplayClockContainer.IsPaused.Value) GameplayClockContainer.Start(); else From 93a57b6871a98d94f898cfa6afbf5504ab9932c9 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 7 Jan 2023 11:28:09 -0800 Subject: [PATCH 016/516] Separate pausing test instead of using test cases --- .../Visual/Gameplay/TestSceneReplayPlayer.cs | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs index 601fe445f0..334d01f915 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs @@ -24,28 +24,40 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("player loaded", () => Player.IsLoaded); } - [TestCase("space")] - [TestCase("mouse middle")] - public void TestPause(string action) + [Test] + public void TestPauseViaSpace() { double? lastTime = null; AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0); - AddStep("Pause playback", () => - { - switch (action) - { - case "space": - InputManager.Key(Key.Space); - break; + AddStep("Pause playback with space", () => InputManager.Key(Key.Space)); - case "mouse middle": - InputManager.Click(MouseButton.Middle); - break; - } + 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 TestPauseViaMiddleMouse() + { + double? lastTime = null; + + AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0); + + AddStep("Pause playback with middle mouse", () => InputManager.Click(MouseButton.Middle)); + AddAssert("player not exited", () => Player.IsCurrentScreen()); AddUntilStep("Time stopped progressing", () => From 45bae5d42470b12cb4900ccb24f1cf79ad05204f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 5 Jan 2023 13:05:20 -0800 Subject: [PATCH 017/516] Add middle mouse to toggle pause replay instead of using pause gameplay keybinds --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 1 + osu.Game/Screens/Play/ReplayPlayer.cs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 07cef50dec..3826139716 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -113,6 +113,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Shift, InputKey.Tab }, GlobalAction.ToggleInGameInterface), new KeyBinding(InputKey.MouseMiddle, GlobalAction.PauseGameplay), new KeyBinding(InputKey.Space, GlobalAction.TogglePauseReplay), + new KeyBinding(InputKey.MouseMiddle, GlobalAction.TogglePauseReplay), new KeyBinding(InputKey.Left, GlobalAction.SeekReplayBackward), new KeyBinding(InputKey.Right, GlobalAction.SeekReplayForward), new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 77ee7bc113..c5ef6b1585 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -81,7 +81,6 @@ namespace osu.Game.Screens.Play return true; case GlobalAction.TogglePauseReplay: - case GlobalAction.PauseGameplay: if (GameplayClockContainer.IsPaused.Value) GameplayClockContainer.Start(); else From 85396ba9d4016552504babdef678a8b7fbd65a2e Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 9 Jan 2023 19:26:43 +0000 Subject: [PATCH 018/516] Added ruleset config stuff for Taiko; Added ruleset settings entry for Taiko touch control scheme --- .../TaikoRulesetConfigManager.cs | 28 +++++++++++++++ .../Configuration/TaikoTouchControlScheme.cs | 14 ++++++++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 8 +++++ .../TaikoSettingsSubsection.cs | 36 +++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs create mode 100644 osu.Game.Rulesets.Taiko/Configuration/TaikoTouchControlScheme.cs create mode 100644 osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs diff --git a/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs b/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs new file mode 100644 index 0000000000..c3bc7f6439 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Configuration; +using osu.Game.Rulesets.Configuration; + +namespace osu.Game.Rulesets.Taiko.Configuration +{ + public class TaikoRulesetConfigManager : RulesetConfigManager + { + public TaikoRulesetConfigManager(SettingsStore? settings, RulesetInfo ruleset, int? variant = null) + : base(settings, ruleset, variant) + { + } + + protected override void InitialiseDefaults() + { + base.InitialiseDefaults(); + + SetDefault(TaikoRulesetSetting.TouchControlScheme, TaikoTouchControlScheme.KDDK); + } + } + + public enum TaikoRulesetSetting + { + TouchControlScheme + } +} diff --git a/osu.Game.Rulesets.Taiko/Configuration/TaikoTouchControlScheme.cs b/osu.Game.Rulesets.Taiko/Configuration/TaikoTouchControlScheme.cs new file mode 100644 index 0000000000..b9aee7eff7 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Configuration/TaikoTouchControlScheme.cs @@ -0,0 +1,14 @@ +// 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.Rulesets.Taiko.Configuration +{ + public enum TaikoTouchControlScheme + { + KDDK, + DDKK, + KKDD + } +} diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index fe12cf9765..e5a1a5d7ce 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -28,9 +28,13 @@ using osu.Game.Rulesets.Taiko.Skinning.Argon; using osu.Game.Rulesets.Taiko.Skinning.Legacy; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.UI; +using osu.Game.Overlays.Settings; using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics; using osu.Game.Skinning; +using osu.Game.Rulesets.Configuration; +using osu.Game.Configuration; +using osu.Game.Rulesets.Taiko.Configuration; namespace osu.Game.Rulesets.Taiko { @@ -193,6 +197,10 @@ namespace osu.Game.Rulesets.Taiko public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame(); + public override IRulesetConfigManager CreateConfig(SettingsStore? settings) => new TaikoRulesetConfigManager(settings, RulesetInfo); + + public override RulesetSettingsSubsection CreateSettings() => new TaikoSettingsSubsection(this); + protected override IEnumerable GetValidHitResults() { return new[] diff --git a/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs b/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs new file mode 100644 index 0000000000..297a02df5b --- /dev/null +++ b/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs @@ -0,0 +1,36 @@ +// 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.Localisation; +using osu.Game.Overlays.Settings; +using osu.Game.Rulesets.Taiko.Configuration; + +namespace osu.Game.Rulesets.Taiko +{ + public partial class TaikoSettingsSubsection : RulesetSettingsSubsection + { + protected override LocalisableString Header => "osu!taiko"; + + public TaikoSettingsSubsection(TaikoRuleset ruleset) + : base(ruleset) + { + } + + [BackgroundDependencyLoader] + private void load() + { + var config = (TaikoRulesetConfigManager)Config; + + Children = new Drawable[] + { + new SettingsEnumDropdown + { + LabelText = "Touch Control Scheme", + Current = config.GetBindable(TaikoRulesetSetting.TouchControlScheme) + } + }; + } + } +} From 46ffded1db0b8486800b9e5baa71bf87f9c838d4 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 10 Jan 2023 08:27:21 +0000 Subject: [PATCH 019/516] Taiko touch control scheme setting now *almost* works (need to implement getting control scheme from config); Drum display is incorrect --- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- .../UI/DrumTouchInputArea.cs | 93 ++++++++++++++++--- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index e5a1a5d7ce..094a84d3fa 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -198,7 +198,7 @@ namespace osu.Game.Rulesets.Taiko public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame(); public override IRulesetConfigManager CreateConfig(SettingsStore? settings) => new TaikoRulesetConfigManager(settings, RulesetInfo); - + public override RulesetSettingsSubsection CreateSettings() => new TaikoSettingsSubsection(this); protected override IEnumerable GetValidHitResults() diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 0232c10d65..91829fd66a 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -1,6 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable disable +#pragma warning disable IDE0001 // Simplify Names + +using System; using System.Collections.Generic; using System.Diagnostics; using osu.Framework.Allocation; @@ -11,11 +15,13 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Rulesets.Taiko.Configuration; using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.UI { + using TaikoInput = TaikoAction; /// /// An overlay that captures and displays osu!taiko mouse and touch input. /// @@ -27,6 +33,7 @@ namespace osu.Game.Rulesets.Taiko.UI private KeyBindingContainer keyBindingContainer = null!; + private readonly Dictionary trackedActions = new Dictionary(); private Container mainContent = null!; @@ -37,7 +44,7 @@ namespace osu.Game.Rulesets.Taiko.UI private QuarterCircle rightRim = null!; [BackgroundDependencyLoader] - private void load(TaikoInputManager taikoInputManager, OsuColour colours) + private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config, OsuColour colours) { Debug.Assert(taikoInputManager.KeyBindingContainer != null); keyBindingContainer = taikoInputManager.KeyBindingContainer; @@ -47,6 +54,7 @@ namespace osu.Game.Rulesets.Taiko.UI const float centre_region = 0.80f; + var touchControlScheme = config.GetBindable(TaikoRulesetSetting.TouchControlScheme).Value; Children = new Drawable[] { new Container @@ -65,27 +73,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(TaikoAction.LeftRim, colours.Blue) + leftRim = new QuarterCircle(TaikoInput.LeftRim, touchControlScheme, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - rightRim = new QuarterCircle(TaikoAction.RightRim, colours.Blue) + rightRim = new QuarterCircle(TaikoInput.RightRim, touchControlScheme, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - leftCentre = new QuarterCircle(TaikoAction.LeftCentre, colours.Pink) + leftCentre = new QuarterCircle(TaikoInput.LeftCentre, touchControlScheme, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightCentre = new QuarterCircle(TaikoAction.RightCentre, colours.Pink) + rightCentre = new QuarterCircle(TaikoInput.RightCentre, touchControlScheme, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -123,14 +131,14 @@ namespace osu.Game.Rulesets.Taiko.UI { Show(); - TaikoAction taikoAction = getTaikoActionFromInput(position); + TaikoInput taikoInput = getTaikoActionFromPosition(position); // Not too sure how this can happen, but let's avoid throwing. if (trackedActions.ContainsKey(source)) return; - trackedActions.Add(source, taikoAction); - keyBindingContainer.TriggerPressed(taikoAction); + trackedActions.Add(source, taikoInput); + keyBindingContainer.TriggerPressed(taikoInput); } private void handleUp(object source) @@ -142,15 +150,61 @@ namespace osu.Game.Rulesets.Taiko.UI private bool validMouse(MouseButtonEvent e) => leftRim.Contains(e.ScreenSpaceMouseDownPosition) || rightRim.Contains(e.ScreenSpaceMouseDownPosition); - private TaikoAction getTaikoActionFromInput(Vector2 inputPosition) +#pragma warning disable format + private TaikoAction getTaikoActionFromPosition(TaikoInput input) + { + switch (TaikoTouchControlScheme.DDKK) + { + case TaikoTouchControlScheme.KDDK: +#pragma warning disable CS0162 // Unreachable code detected + switch (input) + { + case TaikoInput.LeftRim: return TaikoAction.LeftRim; + case TaikoInput.LeftCentre: return TaikoAction.LeftCentre; + case TaikoInput.RightCentre: return TaikoAction.RightCentre; + case TaikoInput.RightRim: return TaikoAction.RightRim; + } +#pragma warning restore CS0162 // Unreachable code detected + break; + + case TaikoTouchControlScheme.DDKK: + switch (input) + { + case TaikoInput.LeftRim: return TaikoAction.LeftCentre; + case TaikoInput.LeftCentre: return TaikoAction.RightCentre; + case TaikoInput.RightCentre: return TaikoAction.LeftRim; + case TaikoInput.RightRim: return TaikoAction.RightRim; + } + break; + + case TaikoTouchControlScheme.KKDD: +#pragma warning disable CS0162 // Unreachable code detected + switch (input) + { + case TaikoInput.LeftRim: return TaikoAction.LeftRim; + case TaikoInput.LeftCentre: return TaikoAction.RightRim; + case TaikoInput.RightCentre: return TaikoAction.LeftCentre; + case TaikoInput.RightRim: return TaikoAction.RightCentre; + } +#pragma warning restore CS0162 // Unreachable code detected + break; + } + return TaikoAction.LeftCentre; + } + +#pragma warning restore format + private TaikoAction getTaikoActionFromPosition(Vector2 inputPosition) { bool centreHit = leftCentre.Contains(inputPosition) || rightCentre.Contains(inputPosition); bool leftSide = ToLocalSpace(inputPosition).X < DrawWidth / 2; + TaikoInput input; if (leftSide) - return centreHit ? TaikoAction.LeftCentre : TaikoAction.LeftRim; + input = centreHit ? TaikoInput.LeftCentre : TaikoInput.LeftRim; + else + input = centreHit ? TaikoInput.RightCentre : TaikoInput.RightRim; - return centreHit ? TaikoAction.RightCentre : TaikoAction.RightRim; + return getTaikoActionFromPosition(input); } protected override void PopIn() @@ -173,8 +227,23 @@ namespace osu.Game.Rulesets.Taiko.UI public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); - public QuarterCircle(TaikoAction handledAction, Color4 colour) + public QuarterCircle(TaikoAction handledAction, TaikoTouchControlScheme touchControlScheme, OsuColour colours) { + Color4 colour = ((Func)(() => + { +#pragma warning disable format + switch (handledAction) + { + case TaikoAction.LeftRim: return colours.Blue; + case TaikoAction.LeftCentre: return colours.Red; + case TaikoAction.RightCentre: return colours.Red; + case TaikoAction.RightRim: return colours.Blue; + } +#pragma warning restore format + return colours.Red; + }))(); + + this.handledAction = handledAction; RelativeSizeAxes = Axes.Both; From ee80cc988ec80a78e0303e42ccfafb9cdfa0260f Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 10:32:00 +0000 Subject: [PATCH 020/516] Fixed drums not displaying correctly; Fixed typo on a function name --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 91829fd66a..69c2942e45 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -73,27 +73,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(TaikoInput.LeftRim, touchControlScheme, colours) + leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim), touchControlScheme, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - rightRim = new QuarterCircle(TaikoInput.RightRim, touchControlScheme, colours) + rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim), touchControlScheme, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - leftCentre = new QuarterCircle(TaikoInput.LeftCentre, touchControlScheme, colours) + leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre), touchControlScheme, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightCentre = new QuarterCircle(TaikoInput.RightCentre, touchControlScheme, colours) + rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre), touchControlScheme, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -151,7 +151,7 @@ namespace osu.Game.Rulesets.Taiko.UI leftRim.Contains(e.ScreenSpaceMouseDownPosition) || rightRim.Contains(e.ScreenSpaceMouseDownPosition); #pragma warning disable format - private TaikoAction getTaikoActionFromPosition(TaikoInput input) + private TaikoAction getTaikoActionFromInput(TaikoInput input) { switch (TaikoTouchControlScheme.DDKK) { @@ -204,7 +204,7 @@ namespace osu.Game.Rulesets.Taiko.UI else input = centreHit ? TaikoInput.RightCentre : TaikoInput.RightRim; - return getTaikoActionFromPosition(input); + return getTaikoActionFromInput(input); } protected override void PopIn() From 3785dd01368a2faefffde17f2abbfab95140c814 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 10:59:57 +0000 Subject: [PATCH 021/516] Taiko touch control scheme is now read from settings --- .../TaikoRulesetConfigManager.cs | 2 ++ .../UI/DrumTouchInputArea.cs | 21 ++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs b/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs index c3bc7f6439..7e2c7e89b4 100644 --- a/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs +++ b/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Configuration.Tracking; +using System; using osu.Game.Configuration; using osu.Game.Rulesets.Configuration; diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 69c2942e45..aa786f2573 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -27,6 +28,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// public partial class DrumTouchInputArea : VisibilityContainer { + // visibility state affects our child. we always want to handle input. public override bool PropagatePositionalInputSubTree => true; public override bool PropagateNonPositionalInputSubTree => true; @@ -43,6 +45,8 @@ namespace osu.Game.Rulesets.Taiko.UI private QuarterCircle leftRim = null!; private QuarterCircle rightRim = null!; + private Bindable touchControlScheme = new Bindable(); + [BackgroundDependencyLoader] private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config, OsuColour colours) { @@ -54,7 +58,7 @@ namespace osu.Game.Rulesets.Taiko.UI const float centre_region = 0.80f; - var touchControlScheme = config.GetBindable(TaikoRulesetSetting.TouchControlScheme).Value; + config.BindWith(TaikoRulesetSetting.TouchControlScheme, touchControlScheme); Children = new Drawable[] { new Container @@ -73,27 +77,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim), touchControlScheme, colours) + leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim), touchControlScheme.Value, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim), touchControlScheme, colours) + rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim), touchControlScheme.Value, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre), touchControlScheme, colours) + leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre), touchControlScheme.Value, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre), touchControlScheme, colours) + rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre), touchControlScheme.Value, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -153,10 +157,10 @@ namespace osu.Game.Rulesets.Taiko.UI #pragma warning disable format private TaikoAction getTaikoActionFromInput(TaikoInput input) { - switch (TaikoTouchControlScheme.DDKK) + switch (touchControlScheme.Value) { case TaikoTouchControlScheme.KDDK: -#pragma warning disable CS0162 // Unreachable code detected + switch (input) { case TaikoInput.LeftRim: return TaikoAction.LeftRim; @@ -164,7 +168,6 @@ namespace osu.Game.Rulesets.Taiko.UI case TaikoInput.RightCentre: return TaikoAction.RightCentre; case TaikoInput.RightRim: return TaikoAction.RightRim; } -#pragma warning restore CS0162 // Unreachable code detected break; case TaikoTouchControlScheme.DDKK: @@ -178,7 +181,6 @@ namespace osu.Game.Rulesets.Taiko.UI break; case TaikoTouchControlScheme.KKDD: -#pragma warning disable CS0162 // Unreachable code detected switch (input) { case TaikoInput.LeftRim: return TaikoAction.LeftRim; @@ -186,7 +188,6 @@ namespace osu.Game.Rulesets.Taiko.UI case TaikoInput.RightCentre: return TaikoAction.LeftCentre; case TaikoInput.RightRim: return TaikoAction.RightCentre; } -#pragma warning restore CS0162 // Unreachable code detected break; } return TaikoAction.LeftCentre; From fd054081b8ec8aad0604c6f596c3d3479c03b207 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 11:29:38 +0000 Subject: [PATCH 022/516] Better name for touch control scheme config bindable --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index aa786f2573..17efcba1d5 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Taiko.UI private QuarterCircle leftRim = null!; private QuarterCircle rightRim = null!; - private Bindable touchControlScheme = new Bindable(); + private Bindable configTouchControlScheme = new Bindable(); [BackgroundDependencyLoader] private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config, OsuColour colours) @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Taiko.UI const float centre_region = 0.80f; - config.BindWith(TaikoRulesetSetting.TouchControlScheme, touchControlScheme); + config.BindWith(TaikoRulesetSetting.TouchControlScheme, configTouchControlScheme); Children = new Drawable[] { new Container @@ -77,27 +77,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim), touchControlScheme.Value, colours) + leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim), configTouchControlScheme.Value, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim), touchControlScheme.Value, colours) + rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim), configTouchControlScheme.Value, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre), touchControlScheme.Value, colours) + leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre), configTouchControlScheme.Value, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre), touchControlScheme.Value, colours) + rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre), configTouchControlScheme.Value, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -157,7 +157,7 @@ namespace osu.Game.Rulesets.Taiko.UI #pragma warning disable format private TaikoAction getTaikoActionFromInput(TaikoInput input) { - switch (touchControlScheme.Value) + switch (configTouchControlScheme.Value) { case TaikoTouchControlScheme.KDDK: From e3d14db285995ba6f86086b82d852ee45cae9265 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 11:38:32 +0000 Subject: [PATCH 023/516] Removed unnecessary QuarterCircle paramenters --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 17efcba1d5..0f14e5d06f 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -47,8 +47,10 @@ namespace osu.Game.Rulesets.Taiko.UI private Bindable configTouchControlScheme = new Bindable(); + private static OsuColour colours; + [BackgroundDependencyLoader] - private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config, OsuColour colours) + private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config, OsuColour _colours) { Debug.Assert(taikoInputManager.KeyBindingContainer != null); keyBindingContainer = taikoInputManager.KeyBindingContainer; @@ -59,6 +61,8 @@ namespace osu.Game.Rulesets.Taiko.UI const float centre_region = 0.80f; config.BindWith(TaikoRulesetSetting.TouchControlScheme, configTouchControlScheme); + colours = _colours; + Children = new Drawable[] { new Container @@ -77,27 +81,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim), configTouchControlScheme.Value, colours) + leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim), configTouchControlScheme.Value, colours) + rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre), configTouchControlScheme.Value, colours) + leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre), configTouchControlScheme.Value, colours) + rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -228,7 +232,7 @@ namespace osu.Game.Rulesets.Taiko.UI public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); - public QuarterCircle(TaikoAction handledAction, TaikoTouchControlScheme touchControlScheme, OsuColour colours) + public QuarterCircle(TaikoAction handledAction) { Color4 colour = ((Func)(() => { From b694e0d441c440fb84100c16f1ecd19f1cc5a3ba Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 11:43:28 +0000 Subject: [PATCH 024/516] Added a comment and fixed some wonky formatting --- .../UI/DrumTouchInputArea.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 0f14e5d06f..5a6dc70ea3 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.UI { - using TaikoInput = TaikoAction; + using TaikoInput = TaikoAction; // Functionally identical to TaikoAction, it's just a readability thing /// /// An overlay that captures and displays osu!taiko mouse and touch input. /// @@ -158,7 +158,7 @@ namespace osu.Game.Rulesets.Taiko.UI private bool validMouse(MouseButtonEvent e) => leftRim.Contains(e.ScreenSpaceMouseDownPosition) || rightRim.Contains(e.ScreenSpaceMouseDownPosition); -#pragma warning disable format + #pragma warning disable format private TaikoAction getTaikoActionFromInput(TaikoInput input) { switch (configTouchControlScheme.Value) @@ -177,28 +177,28 @@ namespace osu.Game.Rulesets.Taiko.UI case TaikoTouchControlScheme.DDKK: switch (input) { - case TaikoInput.LeftRim: return TaikoAction.LeftCentre; - case TaikoInput.LeftCentre: return TaikoAction.RightCentre; + case TaikoInput.LeftRim: return TaikoAction.LeftCentre; + case TaikoInput.LeftCentre: return TaikoAction.RightCentre; case TaikoInput.RightCentre: return TaikoAction.LeftRim; - case TaikoInput.RightRim: return TaikoAction.RightRim; + case TaikoInput.RightRim: return TaikoAction.RightRim; } break; case TaikoTouchControlScheme.KKDD: switch (input) { - case TaikoInput.LeftRim: return TaikoAction.LeftRim; - case TaikoInput.LeftCentre: return TaikoAction.RightRim; + case TaikoInput.LeftRim: return TaikoAction.LeftRim; + case TaikoInput.LeftCentre: return TaikoAction.RightRim; case TaikoInput.RightCentre: return TaikoAction.LeftCentre; - case TaikoInput.RightRim: return TaikoAction.RightCentre; + case TaikoInput.RightRim: return TaikoAction.RightCentre; } break; } return TaikoAction.LeftCentre; } + #pragma warning restore format -#pragma warning restore format - private TaikoAction getTaikoActionFromPosition(Vector2 inputPosition) + private TaikoAction getTaikoActionFromPosition(Vector2 inputPosition) { bool centreHit = leftCentre.Contains(inputPosition) || rightCentre.Contains(inputPosition); bool leftSide = ToLocalSpace(inputPosition).X < DrawWidth / 2; @@ -236,15 +236,15 @@ namespace osu.Game.Rulesets.Taiko.UI { Color4 colour = ((Func)(() => { -#pragma warning disable format + #pragma warning disable format switch (handledAction) { - case TaikoAction.LeftRim: return colours.Blue; - case TaikoAction.LeftCentre: return colours.Red; + case TaikoAction.LeftRim: return colours.Blue; + case TaikoAction.LeftCentre: return colours.Red; case TaikoAction.RightCentre: return colours.Red; - case TaikoAction.RightRim: return colours.Blue; + case TaikoAction.RightRim: return colours.Blue; } -#pragma warning restore format + #pragma warning restore format return colours.Red; }))(); From 4949b44888af25e824303b297222dcf83899a793 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 11:57:21 +0000 Subject: [PATCH 025/516] Updated touch control scheme setting capitalization to be consistent with the rest of the settings menu --- osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs b/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs index 297a02df5b..9fe861c08c 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko { new SettingsEnumDropdown { - LabelText = "Touch Control Scheme", + LabelText = "Touch control scheme", Current = config.GetBindable(TaikoRulesetSetting.TouchControlScheme) } }; From a8f4f0042179cc20045b9b66f77e6583fec7a2f3 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 12:04:06 +0000 Subject: [PATCH 026/516] Removed nullable --- .../Configuration/TaikoTouchControlScheme.cs | 2 -- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Configuration/TaikoTouchControlScheme.cs b/osu.Game.Rulesets.Taiko/Configuration/TaikoTouchControlScheme.cs index b9aee7eff7..74e4a53746 100644 --- a/osu.Game.Rulesets.Taiko/Configuration/TaikoTouchControlScheme.cs +++ b/osu.Game.Rulesets.Taiko/Configuration/TaikoTouchControlScheme.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.Rulesets.Taiko.Configuration { public enum TaikoTouchControlScheme diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 5a6dc70ea3..02454a5355 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.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. -#nullable disable #pragma warning disable IDE0001 // Simplify Names using System; From 906ea80d52ca03d93feb05de12751a49200fa21e Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 12:11:33 +0000 Subject: [PATCH 027/516] Further improved method of getting OsuColour --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 02454a5355..523c28f8cb 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -46,8 +46,6 @@ namespace osu.Game.Rulesets.Taiko.UI private Bindable configTouchControlScheme = new Bindable(); - private static OsuColour colours; - [BackgroundDependencyLoader] private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config, OsuColour _colours) { @@ -60,7 +58,6 @@ namespace osu.Game.Rulesets.Taiko.UI const float centre_region = 0.80f; config.BindWith(TaikoRulesetSetting.TouchControlScheme, configTouchControlScheme); - colours = _colours; Children = new Drawable[] { @@ -231,6 +228,9 @@ namespace osu.Game.Rulesets.Taiko.UI public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); + [Resolved] + private OsuColour colours { get; set; } = null!; + public QuarterCircle(TaikoAction handledAction) { Color4 colour = ((Func)(() => From ffd6168a618243faa33b27558adc17b312b995bf Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 12:13:51 +0000 Subject: [PATCH 028/516] Removed unnecessary newlines --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 523c28f8cb..29f64dab93 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -27,14 +27,12 @@ namespace osu.Game.Rulesets.Taiko.UI /// public partial class DrumTouchInputArea : VisibilityContainer { - // visibility state affects our child. we always want to handle input. public override bool PropagatePositionalInputSubTree => true; public override bool PropagateNonPositionalInputSubTree => true; private KeyBindingContainer keyBindingContainer = null!; - private readonly Dictionary trackedActions = new Dictionary(); private Container mainContent = null!; @@ -247,7 +245,6 @@ namespace osu.Game.Rulesets.Taiko.UI return colours.Red; }))(); - this.handledAction = handledAction; RelativeSizeAxes = Axes.Both; From bf555e4579ca2c05a14ed8fac5593ce2efbdd645 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 12:44:27 +0000 Subject: [PATCH 029/516] Removed unnecessary directives that were added automatically and I forgot to remove --- .../Configuration/TaikoRulesetConfigManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs b/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs index 7e2c7e89b4..c3bc7f6439 100644 --- a/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs +++ b/osu.Game.Rulesets.Taiko/Configuration/TaikoRulesetConfigManager.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Configuration.Tracking; -using System; using osu.Game.Configuration; using osu.Game.Rulesets.Configuration; From b3e620c8e57720b6caaa9ca50e912909b3fff429 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 10 Jan 2023 13:07:07 +0000 Subject: [PATCH 030/516] Removed unnecessary parameter --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 29f64dab93..cdd9024e9d 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Taiko.UI private Bindable configTouchControlScheme = new Bindable(); [BackgroundDependencyLoader] - private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config, OsuColour _colours) + private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config) { Debug.Assert(taikoInputManager.KeyBindingContainer != null); keyBindingContainer = taikoInputManager.KeyBindingContainer; From 362c9050df9b3ad1e889628db439203ab4b7e1c3 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 10 Jan 2023 15:08:18 +0000 Subject: [PATCH 031/516] Fixed OsuColour shenanigans --- .../UI/DrumTouchInputArea.cs | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index cdd9024e9d..50c7a7f69b 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -3,7 +3,6 @@ #pragma warning disable IDE0001 // Simplify Names -using System; using System.Collections.Generic; using System.Diagnostics; using osu.Framework.Allocation; @@ -44,6 +43,9 @@ namespace osu.Game.Rulesets.Taiko.UI private Bindable configTouchControlScheme = new Bindable(); + [Resolved] + private OsuColour colours { get; set; } = null!; + [BackgroundDependencyLoader] private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config) { @@ -75,27 +77,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim)) + leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim), getColourFromTaikoAction(getTaikoActionFromInput(TaikoInput.LeftRim))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim)) + rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim), getColourFromTaikoAction(getTaikoActionFromInput(TaikoInput.RightRim))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre)) + leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre), getColourFromTaikoAction(getTaikoActionFromInput(TaikoInput.LeftCentre))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre)) + rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre), getColourFromTaikoAction(getTaikoActionFromInput(TaikoInput.RightCentre))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -216,6 +218,19 @@ namespace osu.Game.Rulesets.Taiko.UI mainContent.FadeOut(300); } + private Color4 getColourFromTaikoAction(TaikoAction handledAction) + { + #pragma warning disable format + switch (handledAction) + { + case TaikoAction.LeftRim: return colours.Blue; + case TaikoAction.LeftCentre: return colours.Red; + case TaikoAction.RightCentre: return colours.Red; + case TaikoAction.RightRim: return colours.Blue; + } + #pragma warning restore format + return colours.Red; + } private partial class QuarterCircle : CompositeDrawable, IKeyBindingHandler { private readonly Circle overlay; @@ -226,24 +241,8 @@ namespace osu.Game.Rulesets.Taiko.UI public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); - [Resolved] - private OsuColour colours { get; set; } = null!; - - public QuarterCircle(TaikoAction handledAction) + public QuarterCircle(TaikoAction handledAction, Color4 colour) { - Color4 colour = ((Func)(() => - { - #pragma warning disable format - switch (handledAction) - { - case TaikoAction.LeftRim: return colours.Blue; - case TaikoAction.LeftCentre: return colours.Red; - case TaikoAction.RightCentre: return colours.Red; - case TaikoAction.RightRim: return colours.Blue; - } - #pragma warning restore format - return colours.Red; - }))(); this.handledAction = handledAction; RelativeSizeAxes = Axes.Both; From 21b617062ac8b027320f23c658ee103004da8315 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 10 Jan 2023 16:24:02 +0000 Subject: [PATCH 032/516] Removed an unnecessary newline --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 50c7a7f69b..d92f99fc0b 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -243,7 +243,6 @@ namespace osu.Game.Rulesets.Taiko.UI public QuarterCircle(TaikoAction handledAction, Color4 colour) { - this.handledAction = handledAction; RelativeSizeAxes = Axes.Both; From 18e114904a6f24f14e5651b7ac764a3edefca987 Mon Sep 17 00:00:00 2001 From: OpenSauce <48618519+OpenSauce04@users.noreply.github.com> Date: Tue, 10 Jan 2023 19:13:10 +0000 Subject: [PATCH 033/516] configTouchControlScheme is now read only Co-authored-by: Stedoss <29103029+Stedoss@users.noreply.github.com> --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index d92f99fc0b..76566b2ada 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.UI private QuarterCircle leftRim = null!; private QuarterCircle rightRim = null!; - private Bindable configTouchControlScheme = new Bindable(); + private readonly Bindable configTouchControlScheme = new Bindable(); [Resolved] private OsuColour colours { get; set; } = null!; From 7cb5ca905a4b1e976fcc9833e8106d99142e77a4 Mon Sep 17 00:00:00 2001 From: OpenSauce <48618519+OpenSauce04@users.noreply.github.com> Date: Tue, 10 Jan 2023 19:17:33 +0000 Subject: [PATCH 034/516] Simplified getColourFromTaikoAction switch case Co-authored-by: Stedoss <29103029+Stedoss@users.noreply.github.com> --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 76566b2ada..3a921267e2 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -223,10 +223,12 @@ namespace osu.Game.Rulesets.Taiko.UI #pragma warning disable format switch (handledAction) { - case TaikoAction.LeftRim: return colours.Blue; - case TaikoAction.LeftCentre: return colours.Red; - case TaikoAction.RightCentre: return colours.Red; - case TaikoAction.RightRim: return colours.Blue; + case TaikoAction.LeftRim: + case TaikoAction.RightRim: + return colours.Blue; + case TaikoAction.LeftCentre: + case TaikoAction.RightCentre: + return colours.Red; } #pragma warning restore format return colours.Red; From edd2084a0e6bb4b45041dcd3e2b965dd84080661 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 10 Jan 2023 19:21:04 +0000 Subject: [PATCH 035/516] Replaced all instances of TaikoInput with TaikoAction --- .../UI/DrumTouchInputArea.cs | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index d92f99fc0b..87804a9389 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -20,7 +20,6 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.UI { - using TaikoInput = TaikoAction; // Functionally identical to TaikoAction, it's just a readability thing /// /// An overlay that captures and displays osu!taiko mouse and touch input. /// @@ -77,27 +76,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftRim), getColourFromTaikoAction(getTaikoActionFromInput(TaikoInput.LeftRim))) + leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoAction.LeftRim), getColourFromTaikoAction(getTaikoActionFromInput(TaikoAction.LeftRim))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightRim), getColourFromTaikoAction(getTaikoActionFromInput(TaikoInput.RightRim))) + rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoAction.RightRim), getColourFromTaikoAction(getTaikoActionFromInput(TaikoAction.RightRim))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.LeftCentre), getColourFromTaikoAction(getTaikoActionFromInput(TaikoInput.LeftCentre))) + leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoAction.LeftCentre), getColourFromTaikoAction(getTaikoActionFromInput(TaikoAction.LeftCentre))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoInput.RightCentre), getColourFromTaikoAction(getTaikoActionFromInput(TaikoInput.RightCentre))) + rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoAction.RightCentre), getColourFromTaikoAction(getTaikoActionFromInput(TaikoAction.RightCentre))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -135,14 +134,14 @@ namespace osu.Game.Rulesets.Taiko.UI { Show(); - TaikoInput taikoInput = getTaikoActionFromPosition(position); + TaikoAction TaikoAction = getTaikoActionFromPosition(position); // Not too sure how this can happen, but let's avoid throwing. if (trackedActions.ContainsKey(source)) return; - trackedActions.Add(source, taikoInput); - keyBindingContainer.TriggerPressed(taikoInput); + trackedActions.Add(source, TaikoAction); + keyBindingContainer.TriggerPressed(TaikoAction); } private void handleUp(object source) @@ -155,7 +154,7 @@ namespace osu.Game.Rulesets.Taiko.UI leftRim.Contains(e.ScreenSpaceMouseDownPosition) || rightRim.Contains(e.ScreenSpaceMouseDownPosition); #pragma warning disable format - private TaikoAction getTaikoActionFromInput(TaikoInput input) + private TaikoAction getTaikoActionFromInput(TaikoAction input) { switch (configTouchControlScheme.Value) { @@ -163,30 +162,30 @@ namespace osu.Game.Rulesets.Taiko.UI switch (input) { - case TaikoInput.LeftRim: return TaikoAction.LeftRim; - case TaikoInput.LeftCentre: return TaikoAction.LeftCentre; - case TaikoInput.RightCentre: return TaikoAction.RightCentre; - case TaikoInput.RightRim: return TaikoAction.RightRim; + case TaikoAction.LeftRim: return TaikoAction.LeftRim; + case TaikoAction.LeftCentre: return TaikoAction.LeftCentre; + case TaikoAction.RightCentre: return TaikoAction.RightCentre; + case TaikoAction.RightRim: return TaikoAction.RightRim; } break; case TaikoTouchControlScheme.DDKK: switch (input) { - case TaikoInput.LeftRim: return TaikoAction.LeftCentre; - case TaikoInput.LeftCentre: return TaikoAction.RightCentre; - case TaikoInput.RightCentre: return TaikoAction.LeftRim; - case TaikoInput.RightRim: return TaikoAction.RightRim; + case TaikoAction.LeftRim: return TaikoAction.LeftCentre; + case TaikoAction.LeftCentre: return TaikoAction.RightCentre; + case TaikoAction.RightCentre: return TaikoAction.LeftRim; + case TaikoAction.RightRim: return TaikoAction.RightRim; } break; case TaikoTouchControlScheme.KKDD: switch (input) { - case TaikoInput.LeftRim: return TaikoAction.LeftRim; - case TaikoInput.LeftCentre: return TaikoAction.RightRim; - case TaikoInput.RightCentre: return TaikoAction.LeftCentre; - case TaikoInput.RightRim: return TaikoAction.RightCentre; + case TaikoAction.LeftRim: return TaikoAction.LeftRim; + case TaikoAction.LeftCentre: return TaikoAction.RightRim; + case TaikoAction.RightCentre: return TaikoAction.LeftCentre; + case TaikoAction.RightRim: return TaikoAction.RightCentre; } break; } @@ -198,12 +197,12 @@ namespace osu.Game.Rulesets.Taiko.UI { bool centreHit = leftCentre.Contains(inputPosition) || rightCentre.Contains(inputPosition); bool leftSide = ToLocalSpace(inputPosition).X < DrawWidth / 2; - TaikoInput input; + TaikoAction input; if (leftSide) - input = centreHit ? TaikoInput.LeftCentre : TaikoInput.LeftRim; + input = centreHit ? TaikoAction.LeftCentre : TaikoAction.LeftRim; else - input = centreHit ? TaikoInput.RightCentre : TaikoInput.RightRim; + input = centreHit ? TaikoAction.RightCentre : TaikoAction.RightRim; return getTaikoActionFromInput(input); } From 2800eeac560f8a498e480c3cb21982798b4ee605 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 10 Jan 2023 19:23:49 +0000 Subject: [PATCH 036/516] Simplified formatting; Removed warning suppressors --- .../UI/DrumTouchInputArea.cs | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index c1e98b7102..25ea930fe3 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.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. -#pragma warning disable IDE0001 // Simplify Names - using System.Collections.Generic; using System.Diagnostics; using osu.Framework.Allocation; @@ -153,7 +151,6 @@ namespace osu.Game.Rulesets.Taiko.UI private bool validMouse(MouseButtonEvent e) => leftRim.Contains(e.ScreenSpaceMouseDownPosition) || rightRim.Contains(e.ScreenSpaceMouseDownPosition); - #pragma warning disable format private TaikoAction getTaikoActionFromInput(TaikoAction input) { switch (configTouchControlScheme.Value) @@ -162,36 +159,35 @@ namespace osu.Game.Rulesets.Taiko.UI switch (input) { - case TaikoAction.LeftRim: return TaikoAction.LeftRim; - case TaikoAction.LeftCentre: return TaikoAction.LeftCentre; + case TaikoAction.LeftRim: return TaikoAction.LeftRim; + case TaikoAction.LeftCentre: return TaikoAction.LeftCentre; case TaikoAction.RightCentre: return TaikoAction.RightCentre; - case TaikoAction.RightRim: return TaikoAction.RightRim; + case TaikoAction.RightRim: return TaikoAction.RightRim; } break; case TaikoTouchControlScheme.DDKK: switch (input) { - case TaikoAction.LeftRim: return TaikoAction.LeftCentre; - case TaikoAction.LeftCentre: return TaikoAction.RightCentre; + case TaikoAction.LeftRim: return TaikoAction.LeftCentre; + case TaikoAction.LeftCentre: return TaikoAction.RightCentre; case TaikoAction.RightCentre: return TaikoAction.LeftRim; - case TaikoAction.RightRim: return TaikoAction.RightRim; + case TaikoAction.RightRim: return TaikoAction.RightRim; } break; case TaikoTouchControlScheme.KKDD: switch (input) { - case TaikoAction.LeftRim: return TaikoAction.LeftRim; - case TaikoAction.LeftCentre: return TaikoAction.RightRim; + case TaikoAction.LeftRim: return TaikoAction.LeftRim; + case TaikoAction.LeftCentre: return TaikoAction.RightRim; case TaikoAction.RightCentre: return TaikoAction.LeftCentre; - case TaikoAction.RightRim: return TaikoAction.RightCentre; + case TaikoAction.RightRim: return TaikoAction.RightCentre; } break; } return TaikoAction.LeftCentre; } - #pragma warning restore format private TaikoAction getTaikoActionFromPosition(Vector2 inputPosition) { @@ -219,7 +215,6 @@ namespace osu.Game.Rulesets.Taiko.UI private Color4 getColourFromTaikoAction(TaikoAction handledAction) { - #pragma warning disable format switch (handledAction) { case TaikoAction.LeftRim: @@ -229,7 +224,6 @@ namespace osu.Game.Rulesets.Taiko.UI case TaikoAction.RightCentre: return colours.Red; } - #pragma warning restore format return colours.Red; } private partial class QuarterCircle : CompositeDrawable, IKeyBindingHandler From 2b58862567e37ecd81fac5625f70155b74c2d902 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 10 Jan 2023 19:31:31 +0000 Subject: [PATCH 037/516] Added ArgumentOutOfRangeException throws --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 25ea930fe3..b39025e6dc 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Diagnostics; using osu.Framework.Allocation; @@ -186,7 +187,7 @@ namespace osu.Game.Rulesets.Taiko.UI } break; } - return TaikoAction.LeftCentre; + throw new ArgumentOutOfRangeException(); } private TaikoAction getTaikoActionFromPosition(Vector2 inputPosition) @@ -224,7 +225,7 @@ namespace osu.Game.Rulesets.Taiko.UI case TaikoAction.RightCentre: return colours.Red; } - return colours.Red; + throw new ArgumentOutOfRangeException(); } private partial class QuarterCircle : CompositeDrawable, IKeyBindingHandler { From 57467e7b3905ed6008dba82d6429050b29485ed3 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 10 Jan 2023 20:04:57 +0000 Subject: [PATCH 038/516] Touchscreen drum now uses a 2d array rather than nested switches to get TaikoActions for control scheme --- .../UI/DrumTouchInputArea.cs | 94 ++++++++----------- 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index b39025e6dc..8dad25c8e4 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -75,34 +75,34 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(getTaikoActionFromInput(TaikoAction.LeftRim), getColourFromTaikoAction(getTaikoActionFromInput(TaikoAction.LeftRim))) + leftRim = new QuarterCircle(getTaikoActionFromDrumSegment(0), getColourFromTaikoAction(getTaikoActionFromDrumSegment(0))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - rightRim = new QuarterCircle(getTaikoActionFromInput(TaikoAction.RightRim), getColourFromTaikoAction(getTaikoActionFromInput(TaikoAction.RightRim))) - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomRight, - X = 2, - Rotation = 90, - }, - leftCentre = new QuarterCircle(getTaikoActionFromInput(TaikoAction.LeftCentre), getColourFromTaikoAction(getTaikoActionFromInput(TaikoAction.LeftCentre))) + leftCentre = new QuarterCircle(getTaikoActionFromDrumSegment(1), getColourFromTaikoAction(getTaikoActionFromDrumSegment(1))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightCentre = new QuarterCircle(getTaikoActionFromInput(TaikoAction.RightCentre), getColourFromTaikoAction(getTaikoActionFromInput(TaikoAction.RightCentre))) + rightCentre = new QuarterCircle(getTaikoActionFromDrumSegment(2), getColourFromTaikoAction(getTaikoActionFromDrumSegment(2))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Scale = new Vector2(centre_region), Rotation = 90, - } + }, + rightRim = new QuarterCircle(getTaikoActionFromDrumSegment(3), getColourFromTaikoAction(getTaikoActionFromDrumSegment(3))) + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomRight, + X = 2, + Rotation = 90, + }, } }, } @@ -110,6 +110,32 @@ namespace osu.Game.Rulesets.Taiko.UI }; } + private readonly TaikoAction[,] mappedTaikoAction = { + { // KDDK + TaikoAction.LeftRim, + TaikoAction.LeftCentre, + TaikoAction.RightCentre, + TaikoAction.RightRim + }, + { // DDKK + TaikoAction.LeftCentre, + TaikoAction.RightCentre, + TaikoAction.LeftRim, + TaikoAction.RightRim + }, + { // KKDD + TaikoAction.LeftRim, + TaikoAction.RightRim, + TaikoAction.LeftCentre, + TaikoAction.RightCentre + } + }; + + private TaikoAction getTaikoActionFromDrumSegment(int drumSegment) + { + return mappedTaikoAction[(int)configTouchControlScheme.Value, drumSegment]; + } + protected override bool OnKeyDown(KeyDownEvent e) { // Hide whenever the keyboard is used. @@ -152,56 +178,18 @@ namespace osu.Game.Rulesets.Taiko.UI private bool validMouse(MouseButtonEvent e) => leftRim.Contains(e.ScreenSpaceMouseDownPosition) || rightRim.Contains(e.ScreenSpaceMouseDownPosition); - private TaikoAction getTaikoActionFromInput(TaikoAction input) - { - switch (configTouchControlScheme.Value) - { - case TaikoTouchControlScheme.KDDK: - - switch (input) - { - case TaikoAction.LeftRim: return TaikoAction.LeftRim; - case TaikoAction.LeftCentre: return TaikoAction.LeftCentre; - case TaikoAction.RightCentre: return TaikoAction.RightCentre; - case TaikoAction.RightRim: return TaikoAction.RightRim; - } - break; - - case TaikoTouchControlScheme.DDKK: - switch (input) - { - case TaikoAction.LeftRim: return TaikoAction.LeftCentre; - case TaikoAction.LeftCentre: return TaikoAction.RightCentre; - case TaikoAction.RightCentre: return TaikoAction.LeftRim; - case TaikoAction.RightRim: return TaikoAction.RightRim; - } - break; - - case TaikoTouchControlScheme.KKDD: - switch (input) - { - case TaikoAction.LeftRim: return TaikoAction.LeftRim; - case TaikoAction.LeftCentre: return TaikoAction.RightRim; - case TaikoAction.RightCentre: return TaikoAction.LeftCentre; - case TaikoAction.RightRim: return TaikoAction.RightCentre; - } - break; - } - throw new ArgumentOutOfRangeException(); - } - private TaikoAction getTaikoActionFromPosition(Vector2 inputPosition) { bool centreHit = leftCentre.Contains(inputPosition) || rightCentre.Contains(inputPosition); bool leftSide = ToLocalSpace(inputPosition).X < DrawWidth / 2; - TaikoAction input; + int drumSegment; if (leftSide) - input = centreHit ? TaikoAction.LeftCentre : TaikoAction.LeftRim; + drumSegment = centreHit ? 1 : 0; else - input = centreHit ? TaikoAction.RightCentre : TaikoAction.RightRim; + drumSegment = centreHit ? 2 : 3; - return getTaikoActionFromInput(input); + return getTaikoActionFromDrumSegment(drumSegment); } protected override void PopIn() From ce37760b276b9c95d6215eca9ad1aafcae06f047 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 10 Jan 2023 20:05:41 +0000 Subject: [PATCH 039/516] Removed unnecessary coma --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 8dad25c8e4..31654ac17d 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Taiko.UI Origin = Anchor.BottomRight, X = 2, Rotation = 90, - }, + } } }, } From 944c6759d912934d7ce1fc99ab045e4ddd884e00 Mon Sep 17 00:00:00 2001 From: OpenSauce <48618519+OpenSauce04@users.noreply.github.com> Date: Tue, 10 Jan 2023 23:13:22 +0000 Subject: [PATCH 040/516] Fixed right rim being incorrectly layered above right centre --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 31654ac17d..b7a0d46d51 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -88,6 +88,13 @@ namespace osu.Game.Rulesets.Taiko.UI X = -2, Scale = new Vector2(centre_region), }, + rightRim = new QuarterCircle(getTaikoActionFromDrumSegment(3), getColourFromTaikoAction(getTaikoActionFromDrumSegment(3))) + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomRight, + X = 2, + Rotation = 90, + }, rightCentre = new QuarterCircle(getTaikoActionFromDrumSegment(2), getColourFromTaikoAction(getTaikoActionFromDrumSegment(2))) { Anchor = Anchor.BottomCentre, @@ -95,13 +102,6 @@ namespace osu.Game.Rulesets.Taiko.UI X = 2, Scale = new Vector2(centre_region), Rotation = 90, - }, - rightRim = new QuarterCircle(getTaikoActionFromDrumSegment(3), getColourFromTaikoAction(getTaikoActionFromDrumSegment(3))) - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomRight, - X = 2, - Rotation = 90, } } }, From d2247f704d2db5ca09cdffb9fe1103fa0f080aa5 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Wed, 11 Jan 2023 11:26:26 +0000 Subject: [PATCH 041/516] Fixed DrumTouchInputArea test crashing --- osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs index 6514b760bb..ee780204a2 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs @@ -45,5 +45,7 @@ namespace osu.Game.Rulesets.Taiko.Tests { AddStep("show drum", () => drumTouchInputArea.Show()); } + + protected override Ruleset CreateRuleset() => new TaikoRuleset(); } } From 32d1d5a34a874e9c868bcf414ae1478c9e6b58bc Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Wed, 11 Jan 2023 12:04:52 +0000 Subject: [PATCH 042/516] Added tests for new Taiko touch control schemes --- .../TestSceneDrumTouchInputArea.cs | 44 ++++++++++--------- .../UI/DrumTouchInputArea.cs | 6 ++- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs index ee780204a2..6b02b0078a 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs @@ -3,7 +3,7 @@ using NUnit.Framework; using osu.Framework.Graphics; -using osu.Framework.Testing; +using osu.Game.Rulesets.Taiko.Configuration; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Tests.Visual; @@ -14,35 +14,37 @@ namespace osu.Game.Rulesets.Taiko.Tests { private DrumTouchInputArea drumTouchInputArea = null!; - [SetUpSteps] - public void SetUpSteps() + private void createDrum(TaikoTouchControlScheme _forcedControlScheme) { - AddStep("create drum", () => + Child = new TaikoInputManager(new TaikoRuleset().RulesetInfo) { - Child = new TaikoInputManager(new TaikoRuleset().RulesetInfo) - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new InputDrum { - new InputDrum - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Height = 0.2f, - }, - drumTouchInputArea = new DrumTouchInputArea - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Height = 0.2f, }, - }; - }); + drumTouchInputArea = new DrumTouchInputArea + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + ForceControlScheme = _forcedControlScheme + } + } + }; } [Test] public void TestDrum() { + AddStep("create drum (kddk)", () => createDrum(TaikoTouchControlScheme.KDDK)); + AddStep("show drum", () => drumTouchInputArea.Show()); + AddStep("create drum (ddkk)", () => createDrum(TaikoTouchControlScheme.DDKK)); + AddStep("show drum", () => drumTouchInputArea.Show()); + AddStep("create drum (kkdd)", () => createDrum(TaikoTouchControlScheme.KKDD)); AddStep("show drum", () => drumTouchInputArea.Show()); } diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index b7a0d46d51..8208aaba39 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -24,6 +24,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// public partial class DrumTouchInputArea : VisibilityContainer { + public TaikoTouchControlScheme? ForceControlScheme { get; set; } // visibility state affects our child. we always want to handle input. public override bool PropagatePositionalInputSubTree => true; public override bool PropagateNonPositionalInputSubTree => true; @@ -55,7 +56,10 @@ namespace osu.Game.Rulesets.Taiko.UI const float centre_region = 0.80f; - config.BindWith(TaikoRulesetSetting.TouchControlScheme, configTouchControlScheme); + if (ForceControlScheme == null) + config.BindWith(TaikoRulesetSetting.TouchControlScheme, configTouchControlScheme); + else + configTouchControlScheme.Value = (TaikoTouchControlScheme)ForceControlScheme; Children = new Drawable[] { From a0ff03def3b5ab3defc691b3715c931e5cf9c099 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Wed, 11 Jan 2023 20:06:43 +0000 Subject: [PATCH 043/516] Fixed some formatting --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 8208aaba39..681ddb65ad 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -114,20 +114,24 @@ namespace osu.Game.Rulesets.Taiko.UI }; } - private readonly TaikoAction[,] mappedTaikoAction = { - { // KDDK + private readonly TaikoAction[,] mappedTaikoAction = + { + { + // KDDK TaikoAction.LeftRim, TaikoAction.LeftCentre, TaikoAction.RightCentre, TaikoAction.RightRim }, - { // DDKK + { + // DDKK TaikoAction.LeftCentre, TaikoAction.RightCentre, TaikoAction.LeftRim, TaikoAction.RightRim }, - { // KKDD + { + // KKDD TaikoAction.LeftRim, TaikoAction.RightRim, TaikoAction.LeftCentre, From 026a223129658b44528ea5dffad105b0699f80ea Mon Sep 17 00:00:00 2001 From: OpenSauce <48618519+OpenSauce04@users.noreply.github.com> Date: Wed, 11 Jan 2023 20:39:45 +0000 Subject: [PATCH 044/516] Cleaner way of getting ForceControlScheme value Co-authored-by: Susko3 --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 681ddb65ad..a8bad36381 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Taiko.UI if (ForceControlScheme == null) config.BindWith(TaikoRulesetSetting.TouchControlScheme, configTouchControlScheme); else - configTouchControlScheme.Value = (TaikoTouchControlScheme)ForceControlScheme; + configTouchControlScheme.Value = ForceControlScheme.Value; Children = new Drawable[] { From 985b126cba7568018769942fb1bf0cdf10d37036 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Thu, 12 Jan 2023 16:06:03 +0000 Subject: [PATCH 045/516] getTaikoActionFromDrumSegment and getColorFromTaikoAction are now run from within QuarterCircle constructor --- .../UI/DrumTouchInputArea.cs | 63 +++++++++++-------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index a8bad36381..99a21e231d 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.UI private QuarterCircle leftRim = null!; private QuarterCircle rightRim = null!; - private readonly Bindable configTouchControlScheme = new Bindable(); + private static readonly Bindable configTouchControlScheme = new Bindable(); [Resolved] private OsuColour colours { get; set; } = null!; @@ -79,27 +79,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(getTaikoActionFromDrumSegment(0), getColourFromTaikoAction(getTaikoActionFromDrumSegment(0))) + leftRim = new QuarterCircle(0, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - leftCentre = new QuarterCircle(getTaikoActionFromDrumSegment(1), getColourFromTaikoAction(getTaikoActionFromDrumSegment(1))) + leftCentre = new QuarterCircle(1, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightRim = new QuarterCircle(getTaikoActionFromDrumSegment(3), getColourFromTaikoAction(getTaikoActionFromDrumSegment(3))) + rightRim = new QuarterCircle(3, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - rightCentre = new QuarterCircle(getTaikoActionFromDrumSegment(2), getColourFromTaikoAction(getTaikoActionFromDrumSegment(2))) + rightCentre = new QuarterCircle(2, colours) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko.UI }; } - private readonly TaikoAction[,] mappedTaikoAction = + private static readonly TaikoAction[,] mappedTaikoAction = { { // KDDK @@ -139,7 +139,7 @@ namespace osu.Game.Rulesets.Taiko.UI } }; - private TaikoAction getTaikoActionFromDrumSegment(int drumSegment) + private static TaikoAction getTaikoActionFromDrumSegment(int drumSegment) { return mappedTaikoAction[(int)configTouchControlScheme.Value, drumSegment]; } @@ -210,36 +210,35 @@ namespace osu.Game.Rulesets.Taiko.UI mainContent.FadeOut(300); } - private Color4 getColourFromTaikoAction(TaikoAction handledAction) - { - switch (handledAction) - { - case TaikoAction.LeftRim: - case TaikoAction.RightRim: - return colours.Blue; - case TaikoAction.LeftCentre: - case TaikoAction.RightCentre: - return colours.Red; - } - throw new ArgumentOutOfRangeException(); - } private partial class QuarterCircle : CompositeDrawable, IKeyBindingHandler { private readonly Circle overlay; - private readonly TaikoAction handledAction; + private readonly int drumSegment; + + private readonly TaikoAction taikoAction; + + private readonly OsuColour colours; + + private readonly Color4 colour; private readonly Circle circle; public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); - public QuarterCircle(TaikoAction handledAction, Color4 colour) + public QuarterCircle(int drumSegment, OsuColour colours) { - this.handledAction = handledAction; + this.drumSegment = drumSegment; + this.colours = colours; + RelativeSizeAxes = Axes.Both; FillMode = FillMode.Fit; + taikoAction = getTaikoActionFromDrumSegment(drumSegment); + + colour = getColorFromTaikoAction(taikoAction); + InternalChildren = new Drawable[] { new Container @@ -268,16 +267,30 @@ namespace osu.Game.Rulesets.Taiko.UI }; } + private Color4 getColorFromTaikoAction(TaikoAction handledAction) + { + switch (handledAction) + { + case TaikoAction.LeftRim: + case TaikoAction.RightRim: + return colours.Blue; + case TaikoAction.LeftCentre: + case TaikoAction.RightCentre: + return colours.Red; + } + throw new ArgumentOutOfRangeException(); + } + public bool OnPressed(KeyBindingPressEvent e) { - if (e.Action == handledAction) + if (e.Action == taikoAction) overlay.FadeTo(1f, 80, Easing.OutQuint); return false; } public void OnReleased(KeyBindingReleaseEvent e) { - if (e.Action == handledAction) + if (e.Action == taikoAction) overlay.FadeOut(1000, Easing.OutQuint); } } From 767c3cb523913350eee131dcff80b6bcd758dd2e Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Thu, 12 Jan 2023 17:20:07 +0000 Subject: [PATCH 046/516] Revert "getTaikoActionFromDrumSegment and getColorFromTaikoAction are now run from within QuarterCircle constructor" This reverts commit 985b126cba7568018769942fb1bf0cdf10d37036. I really don't think this is going to work cleanly --- .../UI/DrumTouchInputArea.cs | 63 ++++++++----------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 99a21e231d..a8bad36381 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.UI private QuarterCircle leftRim = null!; private QuarterCircle rightRim = null!; - private static readonly Bindable configTouchControlScheme = new Bindable(); + private readonly Bindable configTouchControlScheme = new Bindable(); [Resolved] private OsuColour colours { get; set; } = null!; @@ -79,27 +79,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(0, colours) + leftRim = new QuarterCircle(getTaikoActionFromDrumSegment(0), getColourFromTaikoAction(getTaikoActionFromDrumSegment(0))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - leftCentre = new QuarterCircle(1, colours) + leftCentre = new QuarterCircle(getTaikoActionFromDrumSegment(1), getColourFromTaikoAction(getTaikoActionFromDrumSegment(1))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightRim = new QuarterCircle(3, colours) + rightRim = new QuarterCircle(getTaikoActionFromDrumSegment(3), getColourFromTaikoAction(getTaikoActionFromDrumSegment(3))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - rightCentre = new QuarterCircle(2, colours) + rightCentre = new QuarterCircle(getTaikoActionFromDrumSegment(2), getColourFromTaikoAction(getTaikoActionFromDrumSegment(2))) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko.UI }; } - private static readonly TaikoAction[,] mappedTaikoAction = + private readonly TaikoAction[,] mappedTaikoAction = { { // KDDK @@ -139,7 +139,7 @@ namespace osu.Game.Rulesets.Taiko.UI } }; - private static TaikoAction getTaikoActionFromDrumSegment(int drumSegment) + private TaikoAction getTaikoActionFromDrumSegment(int drumSegment) { return mappedTaikoAction[(int)configTouchControlScheme.Value, drumSegment]; } @@ -210,35 +210,36 @@ namespace osu.Game.Rulesets.Taiko.UI mainContent.FadeOut(300); } + private Color4 getColourFromTaikoAction(TaikoAction handledAction) + { + switch (handledAction) + { + case TaikoAction.LeftRim: + case TaikoAction.RightRim: + return colours.Blue; + case TaikoAction.LeftCentre: + case TaikoAction.RightCentre: + return colours.Red; + } + throw new ArgumentOutOfRangeException(); + } private partial class QuarterCircle : CompositeDrawable, IKeyBindingHandler { private readonly Circle overlay; - private readonly int drumSegment; - - private readonly TaikoAction taikoAction; - - private readonly OsuColour colours; - - private readonly Color4 colour; + private readonly TaikoAction handledAction; private readonly Circle circle; public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); - public QuarterCircle(int drumSegment, OsuColour colours) + public QuarterCircle(TaikoAction handledAction, Color4 colour) { - this.drumSegment = drumSegment; - this.colours = colours; - + this.handledAction = handledAction; RelativeSizeAxes = Axes.Both; FillMode = FillMode.Fit; - taikoAction = getTaikoActionFromDrumSegment(drumSegment); - - colour = getColorFromTaikoAction(taikoAction); - InternalChildren = new Drawable[] { new Container @@ -267,30 +268,16 @@ namespace osu.Game.Rulesets.Taiko.UI }; } - private Color4 getColorFromTaikoAction(TaikoAction handledAction) - { - switch (handledAction) - { - case TaikoAction.LeftRim: - case TaikoAction.RightRim: - return colours.Blue; - case TaikoAction.LeftCentre: - case TaikoAction.RightCentre: - return colours.Red; - } - throw new ArgumentOutOfRangeException(); - } - public bool OnPressed(KeyBindingPressEvent e) { - if (e.Action == taikoAction) + if (e.Action == handledAction) overlay.FadeTo(1f, 80, Easing.OutQuint); return false; } public void OnReleased(KeyBindingReleaseEvent e) { - if (e.Action == taikoAction) + if (e.Action == handledAction) overlay.FadeOut(1000, Easing.OutQuint); } } From 927fccb7be4bcf5589a9b7593b1dc9506a2543fe Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Thu, 12 Jan 2023 17:55:05 +0000 Subject: [PATCH 047/516] Taiko touch control scheme can now be changed mid-map --- .../UI/DrumTouchInputArea.cs | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index a8bad36381..1fe45a96dd 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -57,7 +57,10 @@ namespace osu.Game.Rulesets.Taiko.UI const float centre_region = 0.80f; if (ForceControlScheme == null) + { config.BindWith(TaikoRulesetSetting.TouchControlScheme, configTouchControlScheme); + configTouchControlScheme.ValueChanged += reloadTouchDrums; + } else configTouchControlScheme.Value = ForceControlScheme.Value; @@ -225,11 +228,11 @@ namespace osu.Game.Rulesets.Taiko.UI } private partial class QuarterCircle : CompositeDrawable, IKeyBindingHandler { - private readonly Circle overlay; + private TaikoAction handledAction; - private readonly TaikoAction handledAction; + private Circle overlay; - private readonly Circle circle; + private Circle circle; public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); @@ -280,6 +283,22 @@ namespace osu.Game.Rulesets.Taiko.UI if (e.Action == handledAction) overlay.FadeOut(1000, Easing.OutQuint); } + + public void ReloadDrumSegmentProperties(TaikoAction handledAction, Color4 colour) + { + this.handledAction = handledAction; + + circle.Colour = colour.Multiply(1.4f).Darken(2.8f); + overlay.Colour = colour; + } + } + + private void reloadTouchDrums(object _) + { + leftRim.ReloadDrumSegmentProperties(getTaikoActionFromDrumSegment(0), getColourFromTaikoAction(getTaikoActionFromDrumSegment(0))); + leftCentre.ReloadDrumSegmentProperties(getTaikoActionFromDrumSegment(1), getColourFromTaikoAction(getTaikoActionFromDrumSegment(1))); + rightRim.ReloadDrumSegmentProperties(getTaikoActionFromDrumSegment(3), getColourFromTaikoAction(getTaikoActionFromDrumSegment(3))); + rightCentre.ReloadDrumSegmentProperties(getTaikoActionFromDrumSegment(2), getColourFromTaikoAction(getTaikoActionFromDrumSegment(2))); } } } From f2ec0b21766c1c00856b98e01607e1c6b9a36a34 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Thu, 12 Jan 2023 18:17:50 +0000 Subject: [PATCH 048/516] Made QuarterCircle property loading less clapped --- .../UI/DrumTouchInputArea.cs | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 1fe45a96dd..6e91ed10a5 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -45,6 +45,23 @@ namespace osu.Game.Rulesets.Taiko.UI [Resolved] private OsuColour colours { get; set; } = null!; + private class DrumSegmentProperties + { + public TaikoAction TaikoAction { get; set; } + public Color4 Color { get; set; } + + public DrumSegmentProperties(TaikoAction taikoAction, Color4 color) + { + TaikoAction = taikoAction; + Color = color; + } + } + + private DrumSegmentProperties getDrumSegmentProperties(int drumSegment) + { + var taikoAction = getTaikoActionFromDrumSegment(drumSegment); + return new DrumSegmentProperties(taikoAction, getColourFromTaikoAction(taikoAction)); + } [BackgroundDependencyLoader] private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config) { @@ -82,27 +99,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(getTaikoActionFromDrumSegment(0), getColourFromTaikoAction(getTaikoActionFromDrumSegment(0))) + leftRim = new QuarterCircle(getDrumSegmentProperties(0)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - leftCentre = new QuarterCircle(getTaikoActionFromDrumSegment(1), getColourFromTaikoAction(getTaikoActionFromDrumSegment(1))) + leftCentre = new QuarterCircle(getDrumSegmentProperties(1)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightRim = new QuarterCircle(getTaikoActionFromDrumSegment(3), getColourFromTaikoAction(getTaikoActionFromDrumSegment(3))) + rightRim = new QuarterCircle(getDrumSegmentProperties(3)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - rightCentre = new QuarterCircle(getTaikoActionFromDrumSegment(2), getColourFromTaikoAction(getTaikoActionFromDrumSegment(2))) + rightCentre = new QuarterCircle(getDrumSegmentProperties(2)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -236,13 +253,16 @@ namespace osu.Game.Rulesets.Taiko.UI public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); - public QuarterCircle(TaikoAction handledAction, Color4 colour) + public QuarterCircle(DrumSegmentProperties properties) { - this.handledAction = handledAction; + handledAction = properties.TaikoAction; + RelativeSizeAxes = Axes.Both; FillMode = FillMode.Fit; + var colour = properties.Color; + InternalChildren = new Drawable[] { new Container @@ -284,9 +304,11 @@ namespace osu.Game.Rulesets.Taiko.UI overlay.FadeOut(1000, Easing.OutQuint); } - public void ReloadDrumSegmentProperties(TaikoAction handledAction, Color4 colour) + public void SetProperties(DrumSegmentProperties properties) { - this.handledAction = handledAction; + handledAction = properties.TaikoAction; + + var colour = properties.Color; circle.Colour = colour.Multiply(1.4f).Darken(2.8f); overlay.Colour = colour; @@ -295,10 +317,10 @@ namespace osu.Game.Rulesets.Taiko.UI private void reloadTouchDrums(object _) { - leftRim.ReloadDrumSegmentProperties(getTaikoActionFromDrumSegment(0), getColourFromTaikoAction(getTaikoActionFromDrumSegment(0))); - leftCentre.ReloadDrumSegmentProperties(getTaikoActionFromDrumSegment(1), getColourFromTaikoAction(getTaikoActionFromDrumSegment(1))); - rightRim.ReloadDrumSegmentProperties(getTaikoActionFromDrumSegment(3), getColourFromTaikoAction(getTaikoActionFromDrumSegment(3))); - rightCentre.ReloadDrumSegmentProperties(getTaikoActionFromDrumSegment(2), getColourFromTaikoAction(getTaikoActionFromDrumSegment(2))); + leftRim.SetProperties(getDrumSegmentProperties(0)); + leftCentre.SetProperties(getDrumSegmentProperties(1)); + rightRim.SetProperties(getDrumSegmentProperties(3)); + rightCentre.SetProperties(getDrumSegmentProperties(2)); } } } From 92def3daf4720535073cb264dd485f9672eabf9a Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Thu, 12 Jan 2023 18:20:03 +0000 Subject: [PATCH 049/516] Renamed QuarterCircle class to DrumSegment --- .../UI/DrumTouchInputArea.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 6e91ed10a5..753b7f2da9 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -35,10 +35,10 @@ namespace osu.Game.Rulesets.Taiko.UI private Container mainContent = null!; - private QuarterCircle leftCentre = null!; - private QuarterCircle rightCentre = null!; - private QuarterCircle leftRim = null!; - private QuarterCircle rightRim = null!; + private DrumSegment leftCentre = null!; + private DrumSegment rightCentre = null!; + private DrumSegment leftRim = null!; + private DrumSegment rightRim = null!; private readonly Bindable configTouchControlScheme = new Bindable(); @@ -99,27 +99,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new QuarterCircle(getDrumSegmentProperties(0)) + leftRim = new DrumSegment(getDrumSegmentProperties(0)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - leftCentre = new QuarterCircle(getDrumSegmentProperties(1)) + leftCentre = new DrumSegment(getDrumSegmentProperties(1)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightRim = new QuarterCircle(getDrumSegmentProperties(3)) + rightRim = new DrumSegment(getDrumSegmentProperties(3)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - rightCentre = new QuarterCircle(getDrumSegmentProperties(2)) + rightCentre = new DrumSegment(getDrumSegmentProperties(2)) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -243,7 +243,7 @@ namespace osu.Game.Rulesets.Taiko.UI } throw new ArgumentOutOfRangeException(); } - private partial class QuarterCircle : CompositeDrawable, IKeyBindingHandler + private partial class DrumSegment : CompositeDrawable, IKeyBindingHandler { private TaikoAction handledAction; @@ -253,7 +253,7 @@ namespace osu.Game.Rulesets.Taiko.UI public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); - public QuarterCircle(DrumSegmentProperties properties) + public DrumSegment(DrumSegmentProperties properties) { handledAction = properties.TaikoAction; From 25a920732fa6cba7c51ab1eaf44f16b0df79e627 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Thu, 12 Jan 2023 19:04:37 +0000 Subject: [PATCH 050/516] Addressed code formatting issues --- .../TestSceneDrumTouchInputArea.cs | 6 +++--- .../UI/DrumTouchInputArea.cs | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs index 6b02b0078a..23b871dcd8 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs @@ -14,13 +14,13 @@ namespace osu.Game.Rulesets.Taiko.Tests { private DrumTouchInputArea drumTouchInputArea = null!; - private void createDrum(TaikoTouchControlScheme _forcedControlScheme) + private void createDrum(TaikoTouchControlScheme forcedControlScheme) { Child = new TaikoInputManager(new TaikoRuleset().RulesetInfo) { RelativeSizeAxes = Axes.Both, Children = new Drawable[] - { + { new InputDrum { Anchor = Anchor.TopCentre, @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Tests { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - ForceControlScheme = _forcedControlScheme + ForceControlScheme = forcedControlScheme } } }; diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index 753b7f2da9..e4c20dd1bf 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -25,6 +25,7 @@ namespace osu.Game.Rulesets.Taiko.UI public partial class DrumTouchInputArea : VisibilityContainer { public TaikoTouchControlScheme? ForceControlScheme { get; set; } + // visibility state affects our child. we always want to handle input. public override bool PropagatePositionalInputSubTree => true; public override bool PropagateNonPositionalInputSubTree => true; @@ -62,10 +63,12 @@ namespace osu.Game.Rulesets.Taiko.UI var taikoAction = getTaikoActionFromDrumSegment(drumSegment); return new DrumSegmentProperties(taikoAction, getColourFromTaikoAction(taikoAction)); } + [BackgroundDependencyLoader] private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config) { Debug.Assert(taikoInputManager.KeyBindingContainer != null); + keyBindingContainer = taikoInputManager.KeyBindingContainer; // Container should handle input everywhere. @@ -187,14 +190,14 @@ namespace osu.Game.Rulesets.Taiko.UI { Show(); - TaikoAction TaikoAction = getTaikoActionFromPosition(position); + TaikoAction taikoAction = getTaikoActionFromPosition(position); // Not too sure how this can happen, but let's avoid throwing. if (trackedActions.ContainsKey(source)) return; - trackedActions.Add(source, TaikoAction); - keyBindingContainer.TriggerPressed(TaikoAction); + trackedActions.Add(source, taikoAction); + keyBindingContainer.TriggerPressed(taikoAction); } private void handleUp(object source) @@ -236,20 +239,25 @@ namespace osu.Game.Rulesets.Taiko.UI { case TaikoAction.LeftRim: case TaikoAction.RightRim: + return colours.Blue; + case TaikoAction.LeftCentre: case TaikoAction.RightCentre: + return colours.Red; } + throw new ArgumentOutOfRangeException(); } + private partial class DrumSegment : CompositeDrawable, IKeyBindingHandler { private TaikoAction handledAction; - private Circle overlay; + private readonly Circle overlay; - private Circle circle; + private readonly Circle circle; public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); From 87ee9ab813e023d0d51bea755ba3f5db16356353 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Wed, 12 Oct 2022 19:04:45 +0200 Subject: [PATCH 051/516] Added custom menu items in DrawableCarouselBeatmap --- .../Carousel/DrawableCarouselBeatmap.cs | 19 ++++++++----------- osu.Game/Screens/Select/PlaySongSelect.cs | 12 ++++++++++++ osu.Game/Screens/Select/SongSelect.cs | 3 +++ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 4e10961e55..4c8f986563 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -49,8 +49,9 @@ namespace osu.Game.Screens.Select.Carousel private Sprite background; - private Action startRequested; - private Action editRequested; + private MenuItem[] customMenuItems; + + private Action selectRequested; private Action hideRequested; private Triangles triangles; @@ -86,9 +87,8 @@ namespace osu.Game.Screens.Select.Carousel if (songSelect != null) { - startRequested = b => songSelect.FinaliseSelection(b); - if (songSelect.AllowEditing) - editRequested = songSelect.Edit; + customMenuItems = songSelect.CustomMenuItems.Select(f => f.Invoke(beatmapInfo)).ToArray(); + selectRequested = b => songSelect.FinaliseSelection(b); } if (manager != null) @@ -195,7 +195,7 @@ namespace osu.Game.Screens.Select.Carousel protected override bool OnClick(ClickEvent e) { if (Item.State.Value == CarouselItemState.Selected) - startRequested?.Invoke(beatmapInfo); + selectRequested?.Invoke(beatmapInfo); return base.OnClick(e); } @@ -229,11 +229,8 @@ namespace osu.Game.Screens.Select.Carousel { List items = new List(); - if (startRequested != null) - items.Add(new OsuMenuItem("Play", MenuItemType.Highlighted, () => startRequested(beatmapInfo))); - - if (editRequested != null) - items.Add(new OsuMenuItem(CommonStrings.ButtonsEdit, MenuItemType.Standard, () => editRequested(beatmapInfo))); + if (customMenuItems != null) + items.AddRange(customMenuItems); if (beatmapInfo.OnlineID > 0 && beatmapOverlay != null) items.Add(new OsuMenuItem("Details...", MenuItemType.Standard, () => beatmapOverlay.FetchAndShowBeatmap(beatmapInfo.OnlineID))); diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index f73cfe8d55..15356baf44 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -1,15 +1,20 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -29,6 +34,13 @@ namespace osu.Game.Screens.Select public override bool AllowExternalScreenChange => true; + public override Func[] CustomMenuItems => + new Func[] + { + b => new OsuMenuItem("Play", MenuItemType.Highlighted, () => FinaliseSelection(b)), + b => new OsuMenuItem(CommonStrings.ButtonsEdit, MenuItemType.Standard, () => Edit(b)) + }; + protected override UserActivity InitialActivity => new UserActivity.ChoosingBeatmap(); private PlayBeatmapDetailArea playBeatmapDetailArea = null!; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index f4804c6a6c..38f4b8ef40 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -37,6 +37,7 @@ using osu.Game.Collections; using osu.Game.Graphics.UserInterface; using System.Diagnostics; using JetBrains.Annotations; +using osu.Framework.Graphics.UserInterface; using osu.Game.Screens.Play; using osu.Game.Skinning; @@ -84,6 +85,8 @@ namespace osu.Game.Screens.Select public bool BeatmapSetsLoaded => IsLoaded && Carousel?.BeatmapSetsLoaded == true; + public virtual Func[] CustomMenuItems => new Func[] { b => new OsuMenuItem(@"Select", MenuItemType.Highlighted, () => FinaliseSelection(b)) }; + [Resolved] private Bindable> selectedMods { get; set; } From 1c0a6505756ef2ace70ae5d24dbddca14ef961e1 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 16 Jan 2023 00:17:26 +0100 Subject: [PATCH 052/516] Fix typo --- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 15356baf44..92a23048c7 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -101,7 +101,7 @@ namespace osu.Game.Screens.Select { notifications?.Post(new SimpleNotification { - Text = "The current ruleset doesn't have an autoplay mod avalaible!" + Text = "The current ruleset doesn't have an autoplay mod available!" }); return false; } From 832d033777eeeffff5e419343416a876d4deb43a Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 16 Jan 2023 01:09:04 +0100 Subject: [PATCH 053/516] Fix merge issues --- .../Screens/Select/Carousel/DrawableCarouselBeatmap.cs | 8 ++++---- osu.Game/Screens/Select/PlaySongSelect.cs | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 75c367acba..a831271bb4 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -47,10 +47,10 @@ namespace osu.Game.Screens.Select.Carousel private Sprite background = null!; - private MenuItem[] customMenuItems; + private MenuItem[]? customMenuItems; - private Action selectRequested; - private Action hideRequested; + private Action? selectRequested; + private Action? hideRequested; private Triangles triangles = null!; @@ -192,7 +192,7 @@ namespace osu.Game.Screens.Select.Carousel protected override bool OnClick(ClickEvent e) { - if (Item.State.Value == CarouselItemState.Selected) + if (Item?.State.Value == CarouselItemState.Selected) selectRequested?.Invoke(beatmapInfo); return base.OnClick(e); diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index aebdfb8a04..c6c2b69fd8 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -15,7 +15,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -39,7 +38,7 @@ namespace osu.Game.Screens.Select new Func[] { b => new OsuMenuItem("Play", MenuItemType.Highlighted, () => FinaliseSelection(b)), - b => new OsuMenuItem(CommonStrings.ButtonsEdit, MenuItemType.Standard, () => Edit(b)) + b => new OsuMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsEdit, MenuItemType.Standard, () => Edit(b)) }; protected override UserActivity InitialActivity => new UserActivity.ChoosingBeatmap(); From 92a755c5da93c4077ace0342b784539e21072941 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Tue, 17 Jan 2023 22:16:59 +0100 Subject: [PATCH 054/516] 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 812a4b412a2c1b13a1e1215a00f863ef6fd83e45 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 19 Jan 2023 19:43:23 +0900 Subject: [PATCH 055/516] Move judgement result revert logic to Playfield Previously, some judgement results were not reverted when the source DHO is not alive (e.g. frames skipped in editor). Now, all results are reverted in the exact reverse order. --- .../TestSceneCatcher.cs | 6 +-- .../UI/CatchComboDisplay.cs | 4 +- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 4 +- osu.Game.Rulesets.Catch/UI/Catcher.cs | 6 +-- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 6 +-- .../Judgements/JudgementResultEntry.cs | 26 +++++++++++++ .../Objects/Drawables/DrawableHitObject.cs | 35 ++++++----------- .../Objects/HitObjectLifetimeEntry.cs | 5 +++ osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- osu.Game/Rulesets/UI/HitObjectContainer.cs | 8 ---- osu.Game/Rulesets/UI/Playfield.cs | 38 ++++++++++++++++--- 11 files changed, 90 insertions(+), 50 deletions(-) create mode 100644 osu.Game/Rulesets/Judgements/JudgementResultEntry.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index e8231b07ad..11e3a5be57 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -74,12 +74,12 @@ namespace osu.Game.Rulesets.Catch.Tests }); AddStep("revert second result", () => { - catcher.OnRevertResult(drawableObject2, result2); + catcher.OnRevertResult(result2); }); checkHyperDash(true); AddStep("revert first result", () => { - catcher.OnRevertResult(drawableObject1, result1); + catcher.OnRevertResult(result1); }); checkHyperDash(false); } @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Catch.Tests checkState(CatcherAnimationState.Kiai); AddStep("revert result", () => { - catcher.OnRevertResult(drawableObject, result); + catcher.OnRevertResult(result); }); checkState(CatcherAnimationState.Idle); } diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index dbbe905879..3d0062d32f 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -63,12 +63,12 @@ namespace osu.Game.Rulesets.Catch.UI updateCombo(result.ComboAtJudgement + 1, judgedObject.AccentColour.Value); } - public void OnRevertResult(DrawableCatchHitObject judgedObject, JudgementResult result) + public void OnRevertResult(JudgementResult result) { if (!result.Type.AffectsCombo() || !result.HasResult) return; - updateCombo(result.ComboAtJudgement, judgedObject.AccentColour.Value); + updateCombo(result.ComboAtJudgement, null); } private void updateCombo(int newCombo, Color4? hitObjectColour) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index c33d021876..cf7337fd0d 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Catch.UI private void onNewResult(DrawableHitObject judgedObject, JudgementResult result) => CatcherArea.OnNewResult((DrawableCatchHitObject)judgedObject, result); - private void onRevertResult(DrawableHitObject judgedObject, JudgementResult result) - => CatcherArea.OnRevertResult((DrawableCatchHitObject)judgedObject, result); + private void onRevertResult(JudgementResult result) + => CatcherArea.OnRevertResult(result); } } diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 411330f6fc..1c52c092ec 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -254,7 +254,7 @@ namespace osu.Game.Rulesets.Catch.UI } } - public void OnRevertResult(DrawableCatchHitObject drawableObject, JudgementResult result) + public void OnRevertResult(JudgementResult result) { var catchResult = (CatchJudgementResult)result; @@ -268,8 +268,8 @@ namespace osu.Game.Rulesets.Catch.UI SetHyperDashState(); } - caughtObjectContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject, false); - droppedObjectTarget.RemoveAll(d => d.HitObject == drawableObject.HitObject, false); + caughtObjectContainer.RemoveAll(d => d.HitObject == result.HitObject, false); + droppedObjectTarget.RemoveAll(d => d.HitObject == result.HitObject, false); } /// diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 4f7535d13a..1b99270b65 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -73,10 +73,10 @@ namespace osu.Game.Rulesets.Catch.UI comboDisplay.OnNewResult(hitObject, result); } - public void OnRevertResult(DrawableCatchHitObject hitObject, JudgementResult result) + public void OnRevertResult(JudgementResult result) { - comboDisplay.OnRevertResult(hitObject, result); - Catcher.OnRevertResult(hitObject, result); + comboDisplay.OnRevertResult(result); + Catcher.OnRevertResult(result); } protected override void Update() diff --git a/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs b/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs new file mode 100644 index 0000000000..c3f44804c3 --- /dev/null +++ b/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs @@ -0,0 +1,26 @@ +// 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.Game.Rulesets.Objects; + +namespace osu.Game.Rulesets.Judgements +{ + internal class JudgementResultEntry : IComparable + { + public readonly double Time; + + public readonly HitObjectLifetimeEntry HitObjectEntry; + + public readonly JudgementResult Result; + + public JudgementResultEntry(double time, HitObjectLifetimeEntry hitObjectEntry, JudgementResult result) + { + Time = time; + HitObjectEntry = hitObjectEntry; + Result = result; + } + + public int CompareTo(JudgementResultEntry? other) => Time.CompareTo(other?.Time); + } +} \ No newline at end of file diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index be5a7f71e7..02fc5637d8 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -82,6 +82,9 @@ namespace osu.Game.Rulesets.Objects.Drawables /// /// Invoked by this or a nested prior to a being reverted. /// + /// + /// This is only invoked if this is alive when the result is reverted. + /// public event Action OnRevertResult; /// @@ -222,6 +225,8 @@ namespace osu.Game.Rulesets.Objects.Drawables ensureEntryHasResult(); + entry.RevertResult += onRevertResult; + foreach (var h in HitObject.NestedHitObjects) { var pooledDrawableNested = pooledObjectProvider?.GetPooledDrawableRepresentation(h, this); @@ -234,7 +239,6 @@ namespace osu.Game.Rulesets.Objects.Drawables OnNestedDrawableCreated?.Invoke(drawableNested); drawableNested.OnNewResult += onNewResult; - drawableNested.OnRevertResult += onRevertResult; drawableNested.ApplyCustomUpdateState += onApplyCustomUpdateState; // This is only necessary for non-pooled DHOs. For pooled DHOs, this is handled inside GetPooledDrawableRepresentation(). @@ -309,7 +313,6 @@ namespace osu.Game.Rulesets.Objects.Drawables foreach (var obj in nestedHitObjects) { obj.OnNewResult -= onNewResult; - obj.OnRevertResult -= onRevertResult; obj.ApplyCustomUpdateState -= onApplyCustomUpdateState; } @@ -318,6 +321,8 @@ namespace osu.Game.Rulesets.Objects.Drawables HitObject.DefaultsApplied -= onDefaultsApplied; + entry.RevertResult -= onRevertResult; + OnFree(); ParentHitObject = null; @@ -366,7 +371,11 @@ namespace osu.Game.Rulesets.Objects.Drawables private void onNewResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnNewResult?.Invoke(drawableHitObject, result); - private void onRevertResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnRevertResult?.Invoke(drawableHitObject, result); + private void onRevertResult() + { + updateState(ArmedState.Idle); + OnRevertResult?.Invoke(this, Result); + } private void onApplyCustomUpdateState(DrawableHitObject drawableHitObject, ArmedState state) => ApplyCustomUpdateState?.Invoke(drawableHitObject, state); @@ -578,26 +587,6 @@ namespace osu.Game.Rulesets.Objects.Drawables #endregion - protected override void Update() - { - base.Update(); - - if (Result != null && Result.HasResult) - { - double endTime = HitObject.GetEndTime(); - - if (Result.TimeOffset + endTime > Time.Current) - { - OnRevertResult?.Invoke(this, Result); - - Result.TimeOffset = 0; - Result.Type = HitResult.None; - - updateState(ArmedState.Idle); - } - } - } - public override bool UpdateSubTreeMasking(Drawable source, RectangleF maskingBounds) => false; protected override void UpdateAfterChildren() diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index fedf419973..b517f6b9e6 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Bindables; using osu.Framework.Graphics.Performance; using osu.Game.Rulesets.Judgements; @@ -26,6 +27,8 @@ namespace osu.Game.Rulesets.Objects private readonly IBindable startTimeBindable = new BindableDouble(); + internal event Action? RevertResult; + /// /// Creates a new . /// @@ -95,5 +98,7 @@ namespace osu.Game.Rulesets.Objects /// Set using . /// internal void SetInitialLifetime() => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; + + internal void OnRevertResult() => RevertResult?.Invoke(); } } diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 71b452c309..8edc5517cb 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.UI playfield = new Lazy(() => CreatePlayfield().With(p => { p.NewResult += (_, r) => NewResult?.Invoke(r); - p.RevertResult += (_, r) => RevertResult?.Invoke(r); + p.RevertResult += r => RevertResult?.Invoke(r); })); } diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 7cbf49aa31..099be486b3 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -28,11 +28,6 @@ namespace osu.Game.Rulesets.UI /// public event Action NewResult; - /// - /// Invoked when a judgement is reverted. - /// - public event Action RevertResult; - /// /// Invoked when a becomes used by a . /// @@ -111,7 +106,6 @@ namespace osu.Game.Rulesets.UI private void addDrawable(DrawableHitObject drawable) { drawable.OnNewResult += onNewResult; - drawable.OnRevertResult += onRevertResult; bindStartTime(drawable); AddInternal(drawable); @@ -120,7 +114,6 @@ namespace osu.Game.Rulesets.UI private void removeDrawable(DrawableHitObject drawable) { drawable.OnNewResult -= onNewResult; - drawable.OnRevertResult -= onRevertResult; unbindStartTime(drawable); @@ -154,7 +147,6 @@ namespace osu.Game.Rulesets.UI #endregion private void onNewResult(DrawableHitObject d, JudgementResult r) => NewResult?.Invoke(d, r); - private void onRevertResult(DrawableHitObject d, JudgementResult r) => RevertResult?.Invoke(d, r); #region Comparator + StartTime tracking diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index a7881678f1..9535ebb9ed 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -22,6 +22,8 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Skinning; using osuTK; using osu.Game.Rulesets.Objects.Pooling; +using osu.Game.Rulesets.Scoring; +using osu.Framework.Extensions.ObjectExtensions; namespace osu.Game.Rulesets.UI { @@ -35,9 +37,9 @@ namespace osu.Game.Rulesets.UI public event Action NewResult; /// - /// Invoked when a judgement is reverted. + /// Invoked when a judgement result is reverted. /// - public event Action RevertResult; + public event Action RevertResult; /// /// The contained in this Playfield. @@ -98,6 +100,8 @@ namespace osu.Game.Rulesets.UI private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager(); + private readonly Stack judgementResults; + /// /// Creates a new . /// @@ -107,14 +111,15 @@ namespace osu.Game.Rulesets.UI hitObjectContainerLazy = new Lazy(() => CreateHitObjectContainer().With(h => { - h.NewResult += (d, r) => NewResult?.Invoke(d, r); - h.RevertResult += (d, r) => RevertResult?.Invoke(d, r); + h.NewResult += onNewResult; h.HitObjectUsageBegan += o => HitObjectUsageBegan?.Invoke(o); h.HitObjectUsageFinished += o => HitObjectUsageFinished?.Invoke(o); })); entryManager.OnEntryAdded += onEntryAdded; entryManager.OnEntryRemoved += onEntryRemoved; + + judgementResults = new Stack(); } [BackgroundDependencyLoader] @@ -224,7 +229,7 @@ namespace osu.Game.Rulesets.UI otherPlayfield.DisplayJudgements.BindTo(DisplayJudgements); otherPlayfield.NewResult += (d, r) => NewResult?.Invoke(d, r); - otherPlayfield.RevertResult += (d, r) => RevertResult?.Invoke(d, r); + otherPlayfield.RevertResult += r => RevertResult?.Invoke(r); otherPlayfield.HitObjectUsageBegan += h => HitObjectUsageBegan?.Invoke(h); otherPlayfield.HitObjectUsageFinished += h => HitObjectUsageFinished?.Invoke(h); @@ -252,6 +257,10 @@ namespace osu.Game.Rulesets.UI updatable.Update(this); } } + + // When rewinding, revert future judgements in the reverse order. + while (judgementResults.Count > 0 && Time.Current < judgementResults.Peek().Time) + revertResult(judgementResults.Pop()); } /// @@ -443,6 +452,25 @@ namespace osu.Game.Rulesets.UI #endregion + private void onNewResult(DrawableHitObject drawable, JudgementResult result) + { + // Not using result.TimeAbsolute because that might change and also there is a potential precision issue. + judgementResults.Push(new JudgementResultEntry(Time.Current, drawable.Entry.AsNonNull(), result)); + + NewResult?.Invoke(drawable, result); + } + + private void revertResult(JudgementResultEntry entry) + { + var result = entry.Result; + RevertResult?.Invoke(result); + + result.TimeOffset = 0; + result.Type = HitResult.None; + + entry.HitObjectEntry.OnRevertResult(); + } + #region Editor logic /// From 32acaa44be3009b3120e05753308e157c8f0219a Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 19 Jan 2023 19:52:37 +0900 Subject: [PATCH 056/516] Remove now-redundant code --- .../TestSceneCatcher.cs | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 11e3a5be57..f60ae29f77 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -60,17 +60,15 @@ namespace osu.Game.Rulesets.Catch.Tests [Test] public void TestCatcherHyperStateReverted() { - DrawableCatchHitObject drawableObject1 = null; - DrawableCatchHitObject drawableObject2 = null; JudgementResult result1 = null; JudgementResult result2 = null; AddStep("catch hyper fruit", () => { - attemptCatch(new Fruit { HyperDashTarget = new Fruit { X = 100 } }, out drawableObject1, out result1); + result1 = attemptCatch(new Fruit { HyperDashTarget = new Fruit { X = 100 } }); }); AddStep("catch normal fruit", () => { - attemptCatch(new Fruit(), out drawableObject2, out result2); + result2 = attemptCatch(new Fruit()); }); AddStep("revert second result", () => { @@ -87,11 +85,10 @@ namespace osu.Game.Rulesets.Catch.Tests [Test] public void TestCatcherAnimationStateReverted() { - DrawableCatchHitObject drawableObject = null; JudgementResult result = null; AddStep("catch kiai fruit", () => { - attemptCatch(new TestKiaiFruit(), out drawableObject, out result); + result = attemptCatch(new TestKiaiFruit()); }); checkState(CatcherAnimationState.Kiai); AddStep("revert result", () => @@ -268,23 +265,19 @@ namespace osu.Game.Rulesets.Catch.Tests private void checkHyperDash(bool state) => AddAssert($"catcher is {(state ? "" : "not ")}hyper dashing", () => catcher.HyperDashing == state); - private void attemptCatch(CatchHitObject hitObject) - { - attemptCatch(() => hitObject, 1); - } - private void attemptCatch(Func hitObject, int count) { for (int i = 0; i < count; i++) - attemptCatch(hitObject(), out _, out _); + attemptCatch(hitObject()); } - private void attemptCatch(CatchHitObject hitObject, out DrawableCatchHitObject drawableObject, out JudgementResult result) + private JudgementResult attemptCatch(CatchHitObject hitObject) { hitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - drawableObject = createDrawableObject(hitObject); - result = createResult(hitObject); + var drawableObject = createDrawableObject(hitObject); + var result = createResult(hitObject); applyResult(drawableObject, result); + return result; } private void applyResult(DrawableCatchHitObject drawableObject, JudgementResult result) From 11e1b22bf5be695bebc5dad23ea9c2aa268d4be7 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 19 Jan 2023 20:53:35 +0900 Subject: [PATCH 057/516] Move MaximumJudgementOffset to HitObject We want to access this property for computing lifetime --- .../Objects/Drawables/DrawableHoldNote.cs | 2 -- .../Objects/Drawables/DrawableHoldNoteTail.cs | 11 +---------- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 2 ++ osu.Game.Rulesets.Mania/Objects/TailNote.cs | 9 +++++++++ .../Objects/Drawables/DrawableSpinnerTick.cs | 2 -- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 4 ++-- osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs | 7 +++++++ .../Objects/Drawables/DrawableDrumRollTick.cs | 2 -- osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs | 2 ++ .../Objects/Drawables/DrawableHitObject.cs | 14 +------------- osu.Game/Rulesets/Objects/HitObject.cs | 8 ++++++++ 11 files changed, 32 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 759d2346e8..8863de5ee3 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -69,8 +69,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// private double? releaseTime; - public override double MaximumJudgementOffset => Tail.MaximumJudgementOffset; - public DrawableHoldNote() : this(null) { diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs index bf477277c6..20ea962994 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs @@ -15,13 +15,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// public partial class DrawableHoldNoteTail : DrawableNote { - /// - /// Lenience of release hit windows. This is to make cases where the hold note release - /// is timed alongside presses of other hit objects less awkward. - /// Todo: This shouldn't exist for non-LegacyBeatmapDecoder beatmaps - /// - private const double release_window_lenience = 1.5; - protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteTail; protected DrawableHoldNote HoldNote => (DrawableHoldNote)ParentHitObject; @@ -40,14 +33,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables public void UpdateResult() => base.UpdateResult(true); - public override double MaximumJudgementOffset => base.MaximumJudgementOffset * release_window_lenience; - protected override void CheckForResult(bool userTriggered, double timeOffset) { Debug.Assert(HitObject.HitWindows != null); // Factor in the release lenience - timeOffset /= release_window_lenience; + timeOffset /= TailNote.RELEASE_WINDOW_LENIENCE; if (!userTriggered) { diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 22fab15c1b..c367886efe 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -81,6 +81,8 @@ namespace osu.Game.Rulesets.Mania.Objects /// public TailNote Tail { get; private set; } + public override double MaximumJudgementOffset => Tail.MaximumJudgementOffset; + /// /// The time between ticks of this hold. /// diff --git a/osu.Game.Rulesets.Mania/Objects/TailNote.cs b/osu.Game.Rulesets.Mania/Objects/TailNote.cs index cda8e2fa31..d6dc25079a 100644 --- a/osu.Game.Rulesets.Mania/Objects/TailNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/TailNote.cs @@ -10,6 +10,15 @@ namespace osu.Game.Rulesets.Mania.Objects { public class TailNote : Note { + /// + /// Lenience of release hit windows. This is to make cases where the hold note release + /// is timed alongside presses of other hit objects less awkward. + /// Todo: This shouldn't exist for non-LegacyBeatmapDecoder beatmaps + /// + public const double RELEASE_WINDOW_LENIENCE = 1.5; + public override Judgement CreateJudgement() => new ManiaJudgement(); + + public override double MaximumJudgementOffset => base.MaximumJudgementOffset * RELEASE_WINDOW_LENIENCE; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs index b9ce07363c..34253e3d4f 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs @@ -25,8 +25,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Origin = Anchor.Centre; } - public override double MaximumJudgementOffset => DrawableSpinner.HitObject.Duration; - /// /// Apply a judgement result. /// diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index 0e1fe56cea..ed6f8a9a6a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -71,8 +71,8 @@ namespace osu.Game.Rulesets.Osu.Objects double startTime = StartTime + (float)(i + 1) / totalSpins * Duration; AddNested(i < SpinsRequired - ? new SpinnerTick { StartTime = startTime } - : new SpinnerBonusTick { StartTime = startTime }); + ? new SpinnerTick { StartTime = startTime, SpinnerDuration = Duration } + : new SpinnerBonusTick { StartTime = startTime, SpinnerDuration = Duration }); } } diff --git a/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs b/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs index 650d02c675..c890f3771b 100644 --- a/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs @@ -11,10 +11,17 @@ namespace osu.Game.Rulesets.Osu.Objects { public class SpinnerTick : OsuHitObject { + /// + /// Duration of the containing this spinner tick. + /// + public double SpinnerDuration { get; set; } + public override Judgement CreateJudgement() => new OsuSpinnerTickJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; + public override double MaximumJudgementOffset => SpinnerDuration; + public class OsuSpinnerTickJudgement : OsuJudgement { public override HitResult MaxResult => HitResult.SmallBonus; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 45e25ee7dc..abecd19545 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -37,8 +37,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollTick), _ => new TickPiece()); - public override double MaximumJudgementOffset => HitObject.HitWindow; - protected override void OnApply() { base.OnApply(); diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs index 433fdab908..6bcb8674e6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs @@ -31,6 +31,8 @@ namespace osu.Game.Rulesets.Taiko.Objects protected override HitWindows CreateHitWindows() => HitWindows.Empty; + public override double MaximumJudgementOffset => HitWindow; + protected override StrongNestedHitObject CreateStrongNestedHit(double startTime) => new StrongNestedHit { StartTime = startTime }; public class StrongNestedHit : StrongNestedHitObject diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index be5a7f71e7..43431d7703 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -651,18 +651,6 @@ namespace osu.Game.Rulesets.Objects.Drawables UpdateResult(false); } - /// - /// The maximum offset from the end time of at which this can be judged. - /// The time offset of will be clamped to this value during . - /// - /// Defaults to the miss window of . - /// - /// - /// - /// This does not affect the time offset provided to invocations of . - /// - public virtual double MaximumJudgementOffset => HitObject.HitWindows?.WindowFor(HitResult.Miss) ?? 0; - /// /// Applies the of this , notifying responders such as /// the of the . @@ -684,7 +672,7 @@ namespace osu.Game.Rulesets.Objects.Drawables $"{GetType().ReadableName()} applied an invalid hit result (was: {Result.Type}, expected: [{Result.Judgement.MinResult} ... {Result.Judgement.MaxResult}])."); } - Result.TimeOffset = Math.Min(MaximumJudgementOffset, Time.Current - HitObject.GetEndTime()); + Result.TimeOffset = Math.Min(HitObject.MaximumJudgementOffset, Time.Current - HitObject.GetEndTime()); if (Result.HasResult) updateState(Result.IsHit ? ArmedState.Hit : ArmedState.Miss); diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 0f79e58201..25f538d211 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -200,6 +200,14 @@ namespace osu.Game.Rulesets.Objects [NotNull] protected virtual HitWindows CreateHitWindows() => new HitWindows(); + /// + /// The maximum offset from the end time of at which this can be judged. + /// + /// Defaults to the miss window. + /// + /// + public virtual double MaximumJudgementOffset => HitWindows?.WindowFor(HitResult.Miss) ?? 0; + public IList CreateSlidingSamples() { var slidingSamples = new List(); From d8f9b7d02f2a4e3b86976b45226f7488ef1639f8 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 19 Jan 2023 21:25:21 +0900 Subject: [PATCH 058/516] Use MaximumJudgementOffset for lifetime --- osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 3559a1521c..b93a427196 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -232,8 +232,7 @@ namespace osu.Game.Rulesets.UI.Scrolling double computedStartTime = computeDisplayStartTime(entry); // always load the hitobject before its first judgement offset - double judgementOffset = entry.HitObject.HitWindows?.WindowFor(Scoring.HitResult.Miss) ?? 0; - entry.LifetimeStart = Math.Min(entry.HitObject.StartTime - judgementOffset, computedStartTime); + entry.LifetimeStart = Math.Min(entry.HitObject.StartTime - entry.HitObject.MaximumJudgementOffset, computedStartTime); } private void updateLayoutRecursive(DrawableHitObject hitObject, double? parentHitObjectStartTime = null) From 75a1a2ec2f2d136a510f05c2371b6d37fc8270a9 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sun, 22 Jan 2023 03:44:59 +0100 Subject: [PATCH 059/516] Hide `ResumeOverlay` when `OsuModAutopilot` is enabled --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 1 + osu.Game/Rulesets/Mods/Mod.cs | 3 +++ osu.Game/Rulesets/UI/DrawableRuleset.cs | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 6772cfe0be..99a35f4d69 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -23,6 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Automation; public override LocalisableString Description => @"Automatic cursor movement - just follow the rhythm."; public override double ScoreMultiplier => 0.1; + public override bool HidesResumeOverlay => true; public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail), typeof(ModAutoplay), typeof(OsuModMagnetised), typeof(OsuModRepel) }; public bool PerformFail() => false; diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 04d55bc5fe..4f85bf4663 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -107,6 +107,9 @@ namespace osu.Game.Rulesets.Mods [JsonIgnore] public virtual bool RequiresConfiguration => false; + [JsonIgnore] + public virtual bool HidesResumeOverlay => false; + /// /// The mods this mod cannot be enabled with. /// diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 71b452c309..38dbb1308f 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -230,7 +230,9 @@ namespace osu.Game.Rulesets.UI public override void RequestResume(Action continueResume) { - if (ResumeOverlay != null && (Cursor == null || (Cursor.LastFrameState == Visibility.Visible && Contains(Cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre)))) + if (ResumeOverlay != null + && (Cursor == null || (Cursor.LastFrameState == Visibility.Visible && Contains(Cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre))) + && Mods.All(mod => !mod.HidesResumeOverlay)) { ResumeOverlay.GameplayCursor = Cursor; ResumeOverlay.ResumeAction = continueResume; From 64c96549101a7006ea946f80d23a2aebb019a16c Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 13:32:05 -0300 Subject: [PATCH 060/516] Make probationary groups a bit transparent --- .../Online/TestSceneUserProfileOverlay.cs | 4 +++- .../Profile/Header/Components/GroupBadge.cs | 21 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index fc8c2c0b6e..67de015708 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -90,7 +90,9 @@ namespace osu.Game.Tests.Visual.Online { new APIUserGroup { Colour = "#EB47D0", ShortName = "DEV", Name = "Developers" }, new APIUserGroup { Colour = "#A347EB", ShortName = "BN", Name = "Beatmap Nominators", Playmodes = new[] { "mania" } }, - new APIUserGroup { Colour = "#A347EB", ShortName = "BN", Name = "Beatmap Nominators", Playmodes = new[] { "osu", "taiko" } } + new APIUserGroup { Colour = "#A347EB", ShortName = "BN", Name = "Beatmap Nominators", Playmodes = new[] { "osu", "taiko" } }, + new APIUserGroup { Colour = "#A347EB", ShortName = "BN", Name = "Beatmap Nominators", Playmodes = new[] { "osu", "taiko", "fruits", "mania" } }, + new APIUserGroup { Colour = "#A347EB", ShortName = "BN", Name = "Beatmap Nominators (Probationary)", Playmodes = new[] { "osu", "taiko", "fruits", "mania" }, IsProbationary = true } }, ProfileOrder = new[] { diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index 4d6ee36254..afe7f278d4 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -42,12 +42,15 @@ namespace osu.Game.Overlays.Profile.Header.Components { FillFlowContainer innerContainer; - AddRangeInternal(new Drawable[] + // Normal background color is 0.75 opacity, probationary doesn't have this cause it will make them a bit transparent + var bgColor = group.IsProbationary ? colourProvider?.Background6 ?? Colour4.Black : (colourProvider?.Background6 ?? Colour4.Black).Opacity(0.75f); + + var groupDrawables = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, - Colour = colourProvider?.Background6 ?? Colour4.Black + Colour = bgColor }, innerContainer = new FillFlowContainer { @@ -68,7 +71,19 @@ namespace osu.Game.Overlays.Profile.Header.Components } } } - }); + }; + + AddRangeInternal(groupDrawables); + + // Probationary groups have an opacity of 60% + if (group.IsProbationary) + { + foreach (var drawable in groupDrawables) + { + drawable.Alpha = 0.6f; + } + } + if (group.Playmodes?.Length > 0) { From 933fc8cc836c6824c34752344e879e73df8984de Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 13:33:36 -0300 Subject: [PATCH 061/516] Fix comment --- osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index afe7f278d4..4634ab4381 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { FillFlowContainer innerContainer; - // Normal background color is 0.75 opacity, probationary doesn't have this cause it will make them a bit transparent + // Normal background color is 0.75 opacity, probationary doesn't have this cause they are a bit transparent already var bgColor = group.IsProbationary ? colourProvider?.Background6 ?? Colour4.Black : (colourProvider?.Background6 ?? Colour4.Black).Opacity(0.75f); var groupDrawables = new Drawable[] From de5eb63ceb17829ef6f8822ae07bc9dabc40808b Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 13:38:13 -0300 Subject: [PATCH 062/516] Fix codefactor --- osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index 4634ab4381..435cd43634 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -84,7 +84,6 @@ namespace osu.Game.Overlays.Profile.Header.Components } } - if (group.Playmodes?.Length > 0) { innerContainer.AddRange(group.Playmodes.Select(p => From e60a089f1a725c21d2842fc52f0e1ea3c9c73ad3 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 15:02:02 -0300 Subject: [PATCH 063/516] Set alpha on container instead of children --- osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index 435cd43634..e21b616a17 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -78,10 +78,7 @@ namespace osu.Game.Overlays.Profile.Header.Components // Probationary groups have an opacity of 60% if (group.IsProbationary) { - foreach (var drawable in groupDrawables) - { - drawable.Alpha = 0.6f; - } + Alpha = 0.6f; } if (group.Playmodes?.Length > 0) From aeebbe4003ce85c3b8e48f6db68026daae3e0785 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 15:12:40 -0300 Subject: [PATCH 064/516] Add group badges test from #22280 --- .../Visual/Online/TestSceneGroupBagdes.cs | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs b/osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs new file mode 100644 index 0000000000..61158c0788 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs @@ -0,0 +1,92 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.Profile.Header.Components; +using osuTK; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public partial class TestSceneGroupBagdes : OsuTestScene + { + public TestSceneGroupBagdes() + { + var groups = new[] + { + new APIUser(), + new APIUser + { + Groups = new[] + { + new APIUserGroup { Colour = "#EB47D0", ShortName = "DEV", Name = "Developers" }, + } + }, + new APIUser + { + Groups = new[] + { + new APIUserGroup { Colour = "#EB47D0", ShortName = "DEV", Name = "Developers" }, + new APIUserGroup { Colour = "#A347EB", ShortName = "BN", Name = "Beatmap Nominators", Playmodes = new[] { "osu", "taiko" } } + } + }, + new APIUser + { + Groups = new[] + { + new APIUserGroup { Colour = "#0066FF", ShortName = "PPY", Name = "peppy" }, + new APIUserGroup { Colour = "#EB47D0", ShortName = "DEV", Name = "Developers" }, + new APIUserGroup { Colour = "#A347EB", ShortName = "BN", Name = "Beatmap Nominators", Playmodes = new[] { "osu", "taiko" } } + } + }, + new APIUser + { + Groups = new[] + { + new APIUserGroup { Colour = "#0066FF", ShortName = "PPY", Name = "peppy" }, + new APIUserGroup { Colour = "#EB47D0", ShortName = "DEV", Name = "Developers" }, + new APIUserGroup { Colour = "#999999", ShortName = "ALM", Name = "osu! Alumni" }, + new APIUserGroup { Colour = "#A347EB", ShortName = "BN", Name = "Beatmap Nominators", Playmodes = new[] { "osu", "taiko" } }, + new APIUserGroup { Colour = "#A347EB", ShortName = "BN", Name = "Beatmap Nominators (Probationary)", Playmodes = new[] { "osu", "taiko" }, IsProbationary = true } + } + } + }; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.DarkGray + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(40), + Children = new[] + { + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + ChildrenEnumerable = groups.Select(g => new GroupBadgeFlow { User = { Value = g } }) + }, + } + } + }; + } + } +} From 55976df3073110e3b1fe8672b257870e8d867744 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 16:43:03 -0300 Subject: [PATCH 065/516] Fix typo in test class name --- osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs b/osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs index 61158c0788..cbf9c33b78 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs @@ -13,9 +13,9 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public partial class TestSceneGroupBagdes : OsuTestScene + public partial class TestSceneGroupBadges : OsuTestScene { - public TestSceneGroupBagdes() + public TestSceneGroupBadges() { var groups = new[] { From b62d4deb6f32b36eba85a7af306d3c2f4309dae1 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 17:17:19 -0300 Subject: [PATCH 066/516] Fix also typo on filename --- .../Online/{TestSceneGroupBagdes.cs => TestSceneGroupBadges.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game.Tests/Visual/Online/{TestSceneGroupBagdes.cs => TestSceneGroupBadges.cs} (100%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs b/osu.Game.Tests/Visual/Online/TestSceneGroupBadges.cs similarity index 100% rename from osu.Game.Tests/Visual/Online/TestSceneGroupBagdes.cs rename to osu.Game.Tests/Visual/Online/TestSceneGroupBadges.cs From 8d4889d5ce45655673059837e130a2fca99bda70 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 17:42:53 -0300 Subject: [PATCH 067/516] Cleanup --- .../Profile/Header/Components/GroupBadge.cs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index e21b616a17..50eb37b74e 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -35,6 +35,11 @@ namespace osu.Game.Overlays.Profile.Header.Components CornerRadius = 8; TooltipText = group.Name; + + if (group.IsProbationary) + { + Alpha = 0.6f; + } } [BackgroundDependencyLoader] @@ -42,15 +47,15 @@ namespace osu.Game.Overlays.Profile.Header.Components { FillFlowContainer innerContainer; - // Normal background color is 0.75 opacity, probationary doesn't have this cause they are a bit transparent already - var bgColor = group.IsProbationary ? colourProvider?.Background6 ?? Colour4.Black : (colourProvider?.Background6 ?? Colour4.Black).Opacity(0.75f); + var bgColor = colourProvider?.Background6 ?? Colour4.Black; - var groupDrawables = new Drawable[] + AddRangeInternal(new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, - Colour = bgColor + // Normal background color is 0.75 opacity, probationary doesn't have this cause they are a bit transparent already + Colour = group.IsProbationary ? bgColor : bgColor.Opacity(0.75f), }, innerContainer = new FillFlowContainer { @@ -71,15 +76,7 @@ namespace osu.Game.Overlays.Profile.Header.Components } } } - }; - - AddRangeInternal(groupDrawables); - - // Probationary groups have an opacity of 60% - if (group.IsProbationary) - { - Alpha = 0.6f; - } + }); if (group.Playmodes?.Length > 0) { From f8537c1cbe98bc38f0423e8eabdc2332a21d22ab Mon Sep 17 00:00:00 2001 From: Susko3 Date: Sun, 22 Jan 2023 22:19:04 +0100 Subject: [PATCH 068/516] Delegate file deletion to `ImportTask` to allow overriding it --- osu.Game/Database/ImportTask.cs | 9 +++++++++ osu.Game/Database/RealmArchiveModelImporter.cs | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/ImportTask.cs b/osu.Game/Database/ImportTask.cs index e7f599d85f..def20bc1fb 100644 --- a/osu.Game/Database/ImportTask.cs +++ b/osu.Game/Database/ImportTask.cs @@ -51,6 +51,15 @@ namespace osu.Game.Database : getReaderFrom(Path); } + /// + /// Deletes the file that is encapsulated by this . + /// + public virtual void DeleteFile() + { + if (File.Exists(Path)) + File.Delete(Path); + } + /// /// Creates an from a stream. /// diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index db8861c281..9d06c14b4b 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -201,8 +201,8 @@ namespace osu.Game.Database // TODO: Add a check to prevent files from storage to be deleted. try { - if (import != null && File.Exists(task.Path) && ShouldDeleteArchive(task.Path)) - File.Delete(task.Path); + if (import != null && ShouldDeleteArchive(task.Path)) + task.DeleteFile(); } catch (Exception e) { From de21864bd133e1d63c534b4c9406d5948e7938da Mon Sep 17 00:00:00 2001 From: Susko3 Date: Sun, 22 Jan 2023 22:47:16 +0100 Subject: [PATCH 069/516] Move logic to `AndroidImportTask` and add delete mechanism --- osu.Android/AndroidImportTask.cs | 57 ++++++++++++++++++++++++++++++++ osu.Android/OsuGameActivity.cs | 28 ++++------------ 2 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 osu.Android/AndroidImportTask.cs diff --git a/osu.Android/AndroidImportTask.cs b/osu.Android/AndroidImportTask.cs new file mode 100644 index 0000000000..ec946f71f3 --- /dev/null +++ b/osu.Android/AndroidImportTask.cs @@ -0,0 +1,57 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.IO; +using System.Threading.Tasks; +using Android.Content; +using Android.Net; +using Android.Provider; +using osu.Game.Database; + +namespace osu.Android +{ + public class AndroidImportTask : ImportTask + { + private readonly ContentResolver contentResolver; + + private readonly Uri uri; + + private AndroidImportTask(Stream stream, string filename, ContentResolver contentResolver, Uri uri) + : base(stream, filename) + { + this.contentResolver = contentResolver; + this.uri = uri; + } + + public override void DeleteFile() + { + contentResolver.Delete(uri, null, null); + } + + public static async Task Create(ContentResolver contentResolver, Uri uri) + { + // there are more performant overloads of this method, but this one is the most backwards-compatible + // (dates back to API 1). + + var cursor = contentResolver.Query(uri, null, null, null, null); + + if (cursor == null) + return null; + + cursor.MoveToFirst(); + + int filenameColumn = cursor.GetColumnIndex(IOpenableColumns.DisplayName); + string filename = cursor.GetString(filenameColumn); + + // SharpCompress requires archive streams to be seekable, which the stream opened by + // OpenInputStream() seems to not necessarily be. + // copy to an arbitrary-access memory stream to be able to proceed with the import. + var copy = new MemoryStream(); + + using (var stream = contentResolver.OpenInputStream(uri)) + await stream.CopyToAsync(copy).ConfigureAwait(false); + + return new AndroidImportTask(copy, filename, contentResolver, uri); + } + } +} diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index ca3d628447..f0a6e4733c 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; @@ -14,7 +13,6 @@ using Android.Content; using Android.Content.PM; using Android.Graphics; using Android.OS; -using Android.Provider; using Android.Views; using osu.Framework.Android; using osu.Game.Database; @@ -131,28 +129,14 @@ namespace osu.Android await Task.WhenAll(uris.Select(async uri => { - // there are more performant overloads of this method, but this one is the most backwards-compatible - // (dates back to API 1). - var cursor = ContentResolver?.Query(uri, null, null, null, null); + var task = await AndroidImportTask.Create(ContentResolver!, uri).ConfigureAwait(false); - if (cursor == null) - return; - - cursor.MoveToFirst(); - - int filenameColumn = cursor.GetColumnIndex(IOpenableColumns.DisplayName); - string filename = cursor.GetString(filenameColumn); - - // SharpCompress requires archive streams to be seekable, which the stream opened by - // OpenInputStream() seems to not necessarily be. - // copy to an arbitrary-access memory stream to be able to proceed with the import. - var copy = new MemoryStream(); - using (var stream = ContentResolver.OpenInputStream(uri)) - await stream.CopyToAsync(copy).ConfigureAwait(false); - - lock (tasks) + if (task != null) { - tasks.Add(new ImportTask(copy, filename)); + lock (tasks) + { + tasks.Add(task); + } } })).ConfigureAwait(false); From e16105d0593411dbb84e9b0cc5949fbb8d9e1737 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Sun, 22 Jan 2023 23:11:50 +0100 Subject: [PATCH 070/516] Fix NRT and add more safety --- osu.Android/AndroidImportTask.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Android/AndroidImportTask.cs b/osu.Android/AndroidImportTask.cs index ec946f71f3..7273a6da5c 100644 --- a/osu.Android/AndroidImportTask.cs +++ b/osu.Android/AndroidImportTask.cs @@ -38,10 +38,11 @@ namespace osu.Android if (cursor == null) return null; - cursor.MoveToFirst(); + if (!cursor.MoveToFirst()) + return null; int filenameColumn = cursor.GetColumnIndex(IOpenableColumns.DisplayName); - string filename = cursor.GetString(filenameColumn); + string filename = cursor.GetString(filenameColumn) ?? uri.Path ?? string.Empty; // SharpCompress requires archive streams to be seekable, which the stream opened by // OpenInputStream() seems to not necessarily be. @@ -49,7 +50,12 @@ namespace osu.Android var copy = new MemoryStream(); using (var stream = contentResolver.OpenInputStream(uri)) + { + if (stream == null) + return null; + await stream.CopyToAsync(copy).ConfigureAwait(false); + } return new AndroidImportTask(copy, filename, contentResolver, uri); } From 8405a3e1722f0b3b3d11d2ff33a08fb1dfdafb56 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 23 Jan 2023 18:51:55 +0900 Subject: [PATCH 071/516] Add test for RevertResult --- .../Gameplay/TestScenePoolingRuleset.cs | 57 +++++++++++++++---- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs index 55ee6c9fc9..22ab74cc30 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs @@ -19,7 +19,6 @@ using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Difficulty; -using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -37,6 +36,8 @@ namespace osu.Game.Tests.Visual.Gameplay private TestDrawablePoolingRuleset drawableRuleset; + private TestPlayfield playfield => (TestPlayfield)drawableRuleset.Playfield; + [Test] public void TestReusedWithHitObjectsSpacedFarApart() { @@ -133,29 +134,49 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("no DHOs shown", () => !this.ChildrenOfType().Any()); } + [Test] + public void TestRevertResult() + { + ManualClock clock = null; + Beatmap beatmap; + + createTest(beatmap = new Beatmap + { + HitObjects = + { + new TestHitObject { StartTime = 0 }, + new TestHitObject { StartTime = 500 }, + new TestHitObject { StartTime = 1000 }, + } + }, 10, () => new FramedClock(clock = new ManualClock())); + + AddStep("fast forward to end", () => clock.CurrentTime = beatmap.HitObjects[^1].GetEndTime() + 100); + AddUntilStep("all judged", () => playfield.JudgedObjects.Count == 3); + + AddStep("rewind to middle", () => clock.CurrentTime = beatmap.HitObjects[1].StartTime - 100); + AddUntilStep("some results reverted", () => playfield.JudgedObjects.Count == 1); + + AddStep("fast forward to end", () => clock.CurrentTime = beatmap.HitObjects[^1].GetEndTime() + 100); + AddUntilStep("all judged", () => playfield.JudgedObjects.Count == 3); + + AddStep("disable frame stability", () => drawableRuleset.FrameStablePlayback = false); + AddStep("instant seek to start", () => clock.CurrentTime = beatmap.HitObjects[0].StartTime - 100); + AddAssert("all results reverted", () => playfield.JudgedObjects.Count == 0); + } + [Test] public void TestApplyHitResultOnKilled() { ManualClock clock = null; - bool anyJudged = false; - - void onNewResult(JudgementResult _) => anyJudged = true; var beatmap = new Beatmap(); beatmap.HitObjects.Add(new TestKilledHitObject { Duration = 20 }); createTest(beatmap, 10, () => new FramedClock(clock = new ManualClock())); - AddStep("subscribe to new result", () => - { - anyJudged = false; - drawableRuleset.NewResult += onNewResult; - }); AddStep("skip past object", () => clock.CurrentTime = beatmap.HitObjects[0].GetEndTime() + 1000); - AddAssert("object judged", () => anyJudged); - - AddStep("clean up", () => drawableRuleset.NewResult -= onNewResult); + AddAssert("object judged", () => playfield.JudgedObjects.Count == 1); } private void createTest(IBeatmap beatmap, int poolSize, Func createClock = null) @@ -212,12 +233,24 @@ namespace osu.Game.Tests.Visual.Gameplay private partial class TestPlayfield : Playfield { + public readonly HashSet JudgedObjects = new HashSet(); + private readonly int poolSize; public TestPlayfield(int poolSize) { this.poolSize = poolSize; AddInternal(HitObjectContainer); + NewResult += (_, r) => + { + Assert.That(JudgedObjects, Has.No.Member(r.HitObject)); + JudgedObjects.Add(r.HitObject); + }; + RevertResult += r => + { + Assert.That(JudgedObjects, Has.Member(r.HitObject)); + JudgedObjects.Remove(r.HitObject); + }; } [BackgroundDependencyLoader] From bc94f1b7732dd09d25b660eb150ac38a655f41f6 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 23 Jan 2023 16:43:38 +0100 Subject: [PATCH 072/516] 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 8b47af6503b5a93e98940d31b96d13b1858361f5 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Tue, 24 Jan 2023 00:49:09 +0100 Subject: [PATCH 073/516] Remove `HidesResumeOverlay` and set `ResumeOverlay` to `null` in `OsuModAutopilot` --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 3 ++- osu.Game/Rulesets/Mods/Mod.cs | 3 --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 99a35f4d69..276724c169 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Automation; public override LocalisableString Description => @"Automatic cursor movement - just follow the rhythm."; public override double ScoreMultiplier => 0.1; - public override bool HidesResumeOverlay => true; public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail), typeof(ModAutoplay), typeof(OsuModMagnetised), typeof(OsuModRepel) }; public bool PerformFail() => false; @@ -55,6 +54,8 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { + drawableRuleset.ResumeOverlay = null; + // Grab the input manager to disable the user's cursor, and for future use inputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager; inputManager.AllowUserCursorMovement = false; diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 4f85bf4663..04d55bc5fe 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -107,9 +107,6 @@ namespace osu.Game.Rulesets.Mods [JsonIgnore] public virtual bool RequiresConfiguration => false; - [JsonIgnore] - public virtual bool HidesResumeOverlay => false; - /// /// The mods this mod cannot be enabled with. /// diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 38dbb1308f..403dee5651 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -230,9 +230,7 @@ namespace osu.Game.Rulesets.UI public override void RequestResume(Action continueResume) { - if (ResumeOverlay != null - && (Cursor == null || (Cursor.LastFrameState == Visibility.Visible && Contains(Cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre))) - && Mods.All(mod => !mod.HidesResumeOverlay)) + if (ResumeOverlay != null && (Cursor == null || (Cursor.LastFrameState == Visibility.Visible && Contains(Cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre)))) { ResumeOverlay.GameplayCursor = Cursor; ResumeOverlay.ResumeAction = continueResume; @@ -507,7 +505,7 @@ namespace osu.Game.Rulesets.UI /// /// An optional overlay used when resuming gameplay from a paused state. /// - public ResumeOverlay ResumeOverlay { get; protected set; } + public ResumeOverlay ResumeOverlay { get; set; } /// /// Returns first available provided by a . From e66e43e17ce3330f5924738a28de44f6593c2bc2 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 24 Jan 2023 14:15:17 +0900 Subject: [PATCH 074/516] Remove unused code --- osu.Game/Rulesets/Judgements/JudgementResultEntry.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs b/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs index c3f44804c3..b9d75d3acb 100644 --- a/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs +++ b/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs @@ -1,12 +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 osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Judgements { - internal class JudgementResultEntry : IComparable + internal class JudgementResultEntry { public readonly double Time; @@ -20,7 +19,5 @@ namespace osu.Game.Rulesets.Judgements HitObjectEntry = hitObjectEntry; Result = result; } - - public int CompareTo(JudgementResultEntry? other) => Time.CompareTo(other?.Time); } } \ No newline at end of file From cc87923179ccaa9533be0a2501e31f95e6aba6c8 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 24 Jan 2023 14:19:24 +0900 Subject: [PATCH 075/516] Fix OnRevertResult timing --- osu.Game/Rulesets/UI/Playfield.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 9535ebb9ed..1d9390ea14 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -464,11 +464,10 @@ namespace osu.Game.Rulesets.UI { var result = entry.Result; RevertResult?.Invoke(result); + entry.HitObjectEntry.OnRevertResult(); result.TimeOffset = 0; result.Type = HitResult.None; - - entry.HitObjectEntry.OnRevertResult(); } #region Editor logic From efef97d5be5f9bcf38c67713c572f3e48c0c5625 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 24 Jan 2023 15:35:06 +0900 Subject: [PATCH 076/516] Store Result.TimeAbsolute separately from offset Calculating from TimeOffset is bad because it loses precision. The result time won't change anymore even If `HitObject.GetEndTime()` changes later. --- osu.Game/Rulesets/Judgements/JudgementResult.cs | 17 ++++++++++++++--- .../Rulesets/Judgements/JudgementResultEntry.cs | 5 ++--- .../Objects/Drawables/DrawableHitObject.cs | 3 ++- osu.Game/Rulesets/UI/Playfield.cs | 5 ++--- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/JudgementResult.cs b/osu.Game/Rulesets/Judgements/JudgementResult.cs index 2685cb4e2a..9fdbdae396 100644 --- a/osu.Game/Rulesets/Judgements/JudgementResult.cs +++ b/osu.Game/Rulesets/Judgements/JudgementResult.cs @@ -33,16 +33,19 @@ namespace osu.Game.Rulesets.Judgements public readonly Judgement Judgement; /// - /// The offset from a perfect hit at which this occurred. + /// The offset of from the end time of , clamped by . /// Populated when this is applied via . /// public double TimeOffset { get; internal set; } /// /// The absolute time at which this occurred. - /// Equal to the (end) time of the + . + /// Populated when this is applied via . /// - public double TimeAbsolute => HitObject.GetEndTime() + TimeOffset; + /// + /// This is initially set to the end time of . + /// + public double TimeAbsolute { get; internal set; } /// /// The combo prior to this occurring. @@ -83,6 +86,14 @@ namespace osu.Game.Rulesets.Judgements { HitObject = hitObject; Judgement = judgement; + Reset(); + } + + internal void Reset() + { + Type = HitResult.None; + TimeOffset = 0; + TimeAbsolute = HitObject.GetEndTime(); } public override string ToString() => $"{Type} (Score:{Judgement.NumericResultFor(this)} HP:{Judgement.HealthIncreaseFor(this)} {Judgement})"; diff --git a/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs b/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs index b9d75d3acb..09351e6974 100644 --- a/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs +++ b/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs @@ -7,15 +7,14 @@ namespace osu.Game.Rulesets.Judgements { internal class JudgementResultEntry { - public readonly double Time; + public double Time => Result.TimeAbsolute; public readonly HitObjectLifetimeEntry HitObjectEntry; public readonly JudgementResult Result; - public JudgementResultEntry(double time, HitObjectLifetimeEntry hitObjectEntry, JudgementResult result) + public JudgementResultEntry(HitObjectLifetimeEntry hitObjectEntry, JudgementResult result) { - Time = time; HitObjectEntry = hitObjectEntry; Result = result; } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 02fc5637d8..0c59d638b6 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -673,7 +673,8 @@ namespace osu.Game.Rulesets.Objects.Drawables $"{GetType().ReadableName()} applied an invalid hit result (was: {Result.Type}, expected: [{Result.Judgement.MinResult} ... {Result.Judgement.MaxResult}])."); } - Result.TimeOffset = Math.Min(MaximumJudgementOffset, Time.Current - HitObject.GetEndTime()); + Result.TimeAbsolute = Time.Current; + Result.TimeOffset = Math.Min(MaximumJudgementOffset, Result.TimeAbsolute - HitObject.GetEndTime()); if (Result.HasResult) updateState(Result.IsHit ? ArmedState.Hit : ArmedState.Miss); diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 1d9390ea14..40e84a60e3 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -455,7 +455,7 @@ namespace osu.Game.Rulesets.UI private void onNewResult(DrawableHitObject drawable, JudgementResult result) { // Not using result.TimeAbsolute because that might change and also there is a potential precision issue. - judgementResults.Push(new JudgementResultEntry(Time.Current, drawable.Entry.AsNonNull(), result)); + judgementResults.Push(new JudgementResultEntry(drawable.Entry.AsNonNull(), result)); NewResult?.Invoke(drawable, result); } @@ -466,8 +466,7 @@ namespace osu.Game.Rulesets.UI RevertResult?.Invoke(result); entry.HitObjectEntry.OnRevertResult(); - result.TimeOffset = 0; - result.Type = HitResult.None; + result.Reset(); } #region Editor logic From e1702a8ee9d50cf15f1a2cd02a64d03a245a0d3f Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 24 Jan 2023 15:43:57 +0900 Subject: [PATCH 077/516] Fix inspection issue --- osu.Game/Rulesets/UI/Playfield.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 40e84a60e3..3ec31db4b9 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -22,7 +22,6 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Skinning; using osuTK; using osu.Game.Rulesets.Objects.Pooling; -using osu.Game.Rulesets.Scoring; using osu.Framework.Extensions.ObjectExtensions; namespace osu.Game.Rulesets.UI From e3a5c233e9b8510e6e199eeabf39de0ad8a5145b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 17:39:35 +0900 Subject: [PATCH 078/516] Update test to use newer assetion logic --- osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs index 22ab74cc30..0469df1de3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs @@ -151,17 +151,17 @@ namespace osu.Game.Tests.Visual.Gameplay }, 10, () => new FramedClock(clock = new ManualClock())); AddStep("fast forward to end", () => clock.CurrentTime = beatmap.HitObjects[^1].GetEndTime() + 100); - AddUntilStep("all judged", () => playfield.JudgedObjects.Count == 3); + AddUntilStep("all judged", () => playfield.JudgedObjects.Count, () => Is.EqualTo(3)); AddStep("rewind to middle", () => clock.CurrentTime = beatmap.HitObjects[1].StartTime - 100); - AddUntilStep("some results reverted", () => playfield.JudgedObjects.Count == 1); + AddUntilStep("some results reverted", () => playfield.JudgedObjects.Count, () => Is.EqualTo(1)); AddStep("fast forward to end", () => clock.CurrentTime = beatmap.HitObjects[^1].GetEndTime() + 100); - AddUntilStep("all judged", () => playfield.JudgedObjects.Count == 3); + AddUntilStep("all judged", () => playfield.JudgedObjects.Count, () => Is.EqualTo(3)); AddStep("disable frame stability", () => drawableRuleset.FrameStablePlayback = false); AddStep("instant seek to start", () => clock.CurrentTime = beatmap.HitObjects[0].StartTime - 100); - AddAssert("all results reverted", () => playfield.JudgedObjects.Count == 0); + AddAssert("all results reverted", () => playfield.JudgedObjects.Count, () => Is.EqualTo(0)); } [Test] From 0eaebfd40a7a67e6ba9bd9f164b56d9140ce02bc Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Wed, 25 Jan 2023 10:22:42 -0300 Subject: [PATCH 079/516] Use Alpha instead of opacity on bg color --- osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index 50eb37b74e..4feb25e60b 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -47,15 +47,14 @@ namespace osu.Game.Overlays.Profile.Header.Components { FillFlowContainer innerContainer; - var bgColor = colourProvider?.Background6 ?? Colour4.Black; - AddRangeInternal(new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, // Normal background color is 0.75 opacity, probationary doesn't have this cause they are a bit transparent already - Colour = group.IsProbationary ? bgColor : bgColor.Opacity(0.75f), + Colour = colourProvider?.Background6 ?? Colour4.Black, + Alpha = group.IsProbationary ? 1 : 0.75f, }, innerContainer = new FillFlowContainer { From 398813147548513d6ceb47ea74f813dfed2adea9 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 12:12:56 +0100 Subject: [PATCH 080/516] Rename OsuSliderBar.cs as NormalSliderBar.cs --- osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs | 2 +- osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs | 8 ++++---- .../UserInterface/TestSceneModDifficultyAdjustSettings.cs | 4 ++-- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 2 +- osu.Game/Graphics/UserInterface/ExpandableSlider.cs | 4 ++-- .../UserInterface/{OsuSliderBar.cs => NormalSliderBar.cs} | 4 ++-- osu.Game/Graphics/UserInterface/RangeSlider.cs | 2 +- osu.Game/Graphics/UserInterface/TimeSlider.cs | 2 +- osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs | 2 +- .../Overlays/Settings/Sections/Audio/VolumeSettings.cs | 2 +- .../Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 2 +- .../Overlays/Settings/Sections/Input/MouseSettings.cs | 2 +- osu.Game/Overlays/Settings/Sections/SizeSlider.cs | 2 +- osu.Game/Overlays/Settings/SettingsSlider.cs | 4 ++-- osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs | 2 +- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 2 +- osu.Game/Rulesets/Mods/ModMuted.cs | 2 +- osu.Game/Rulesets/Mods/ModNoScope.cs | 2 +- osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs | 4 ++-- 19 files changed, 27 insertions(+), 27 deletions(-) rename osu.Game/Graphics/UserInterface/{OsuSliderBar.cs => NormalSliderBar.cs} (98%) diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs index f5a5771386..5642fb4bdb 100644 --- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Mania }; } - private partial class ManiaScrollSlider : OsuSliderBar + private partial class ManiaScrollSlider : NormalSliderBar { public override LocalisableString TooltipText => RulesetSettingsStrings.ScrollSpeedTooltip(Current.Value, (int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)); } diff --git a/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs b/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs index cc72731493..791a5651b6 100644 --- a/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs +++ b/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs @@ -31,8 +31,8 @@ namespace osu.Game.Tests.Visual.Audio private WaveformTestBeatmap beatmap; - private OsuSliderBar lowPassSlider; - private OsuSliderBar highPassSlider; + private NormalSliderBar lowPassSlider; + private NormalSliderBar highPassSlider; [BackgroundDependencyLoader] private void load(AudioManager audio) @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual.Audio Text = $"Low Pass: {lowPassFilter.Cutoff}hz", Font = new FontUsage(size: 40) }, - lowPassSlider = new OsuSliderBar + lowPassSlider = new NormalSliderBar { Width = 500, Height = 50, @@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.Audio Text = $"High Pass: {highPassFilter.Cutoff}hz", Font = new FontUsage(size: 40) }, - highPassSlider = new OsuSliderBar + highPassSlider = new NormalSliderBar { Width = 500, Height = 50, diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs index f45f5b9f59..5e2b5ca4ff 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs @@ -261,7 +261,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep($"Set {name} slider to {value}", () => this.ChildrenOfType().First(c => c.LabelText == name) - .ChildrenOfType>().First().Current.Value = value); + .ChildrenOfType>().First().Current.Value = value); } private void checkBindableAtValue(string name, float? expectedValue) @@ -275,7 +275,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddAssert($"Slider {name} at {expectedValue}", () => this.ChildrenOfType().First(c => c.LabelText == name) - .ChildrenOfType>().First().Current.Value == expectedValue); + .ChildrenOfType>().First().Current.Value == expectedValue); } private void setBeatmapWithDifficultyParameters(float value) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index eff320a575..1cbb798981 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -270,7 +270,7 @@ namespace osu.Game.Tests.Visual.UserInterface createScreen(); AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); - AddStep("set setting", () => modSelectOverlay.ChildrenOfType>().First().Current.Value = 8); + AddStep("set setting", () => modSelectOverlay.ChildrenOfType>().First().Current.Value = 8); AddAssert("ensure setting is propagated", () => SelectedMods.Value.OfType().Single().CircleSize.Value == 8); diff --git a/osu.Game/Graphics/UserInterface/ExpandableSlider.cs b/osu.Game/Graphics/UserInterface/ExpandableSlider.cs index 9669fe89a5..e960f55501 100644 --- a/osu.Game/Graphics/UserInterface/ExpandableSlider.cs +++ b/osu.Game/Graphics/UserInterface/ExpandableSlider.cs @@ -21,7 +21,7 @@ namespace osu.Game.Graphics.UserInterface /// public partial class ExpandableSlider : CompositeDrawable, IExpandable, IHasCurrentValue where T : struct, IEquatable, IComparable, IConvertible - where TSlider : OsuSliderBar, new() + where TSlider : NormalSliderBar, new() { private readonly OsuSpriteText label; private readonly TSlider slider; @@ -130,7 +130,7 @@ namespace osu.Game.Graphics.UserInterface /// /// An implementation for the UI slider bar control. /// - public partial class ExpandableSlider : ExpandableSlider> + public partial class ExpandableSlider : ExpandableSlider> where T : struct, IEquatable, IComparable, IConvertible { } diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs similarity index 98% rename from osu.Game/Graphics/UserInterface/OsuSliderBar.cs rename to osu.Game/Graphics/UserInterface/NormalSliderBar.cs index 6d6a591673..71422f097f 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs @@ -25,7 +25,7 @@ using osu.Game.Utils; namespace osu.Game.Graphics.UserInterface { - public partial class OsuSliderBar : SliderBar, IHasTooltip, IHasAccentColour + public partial class NormalSliderBar : SliderBar, IHasTooltip, IHasAccentColour where T : struct, IEquatable, IComparable, IConvertible { /// @@ -77,7 +77,7 @@ namespace osu.Game.Graphics.UserInterface } } - public OsuSliderBar() + public NormalSliderBar() { Height = Nub.HEIGHT; RangePadding = Nub.EXPANDED_SIZE / 2; diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs index 4e23b06c2b..2f3dc07a91 100644 --- a/osu.Game/Graphics/UserInterface/RangeSlider.cs +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -158,7 +158,7 @@ namespace osu.Game.Graphics.UserInterface && screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X; } - protected partial class BoundSlider : OsuSliderBar + protected partial class BoundSlider : NormalSliderBar { public string? DefaultString; public LocalisableString? DefaultTooltip; diff --git a/osu.Game/Graphics/UserInterface/TimeSlider.cs b/osu.Game/Graphics/UserInterface/TimeSlider.cs index 46f0821033..15fc0a465b 100644 --- a/osu.Game/Graphics/UserInterface/TimeSlider.cs +++ b/osu.Game/Graphics/UserInterface/TimeSlider.cs @@ -10,7 +10,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A slider bar which displays a millisecond time value. /// - public partial class TimeSlider : OsuSliderBar + public partial class TimeSlider : NormalSliderBar { public override LocalisableString TooltipText => $"{Current.Value:N0} ms"; } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index 1bcb1bcdf4..75aedc298e 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.FirstRunSetup public override bool? AllowTrackAdjustments => false; } - private partial class UIScaleSlider : OsuSliderBar + private partial class UIScaleSlider : NormalSliderBar { public override LocalisableString TooltipText => base.TooltipText + "x"; } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs index a83707b5f6..0c62cb169f 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { protected override Drawable CreateControl() { - var sliderBar = (OsuSliderBar)base.CreateControl(); + var sliderBar = (NormalSliderBar)base.CreateControl(); sliderBar.PlaySamplesOnAdjust = false; return sliderBar; } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index f140c14a0b..805cf4ca0b 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -329,7 +329,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } } - private partial class UIScaleSlider : OsuSliderBar + private partial class UIScaleSlider : NormalSliderBar { public override LocalisableString TooltipText => base.TooltipText + "x"; } diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index 5a6338dc09..f403012793 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -135,7 +135,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - public partial class SensitivitySlider : OsuSliderBar + public partial class SensitivitySlider : NormalSliderBar { public override LocalisableString TooltipText => Current.Disabled ? MouseSettingsStrings.EnableHighPrecisionForSensitivityAdjust : $"{base.TooltipText}x"; } diff --git a/osu.Game/Overlays/Settings/Sections/SizeSlider.cs b/osu.Game/Overlays/Settings/Sections/SizeSlider.cs index 26d6147bb7..b596212007 100644 --- a/osu.Game/Overlays/Settings/Sections/SizeSlider.cs +++ b/osu.Game/Overlays/Settings/Sections/SizeSlider.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Settings.Sections /// /// A slider intended to show a "size" multiplier number, where 1x is 1.0. /// - public partial class SizeSlider : OsuSliderBar + public partial class SizeSlider : NormalSliderBar where T : struct, IEquatable, IComparable, IConvertible, IFormattable { public override LocalisableString TooltipText => Current.Value.ToString(@"0.##x", NumberFormatInfo.CurrentInfo); diff --git a/osu.Game/Overlays/Settings/SettingsSlider.cs b/osu.Game/Overlays/Settings/SettingsSlider.cs index babac8ec69..a7305b4e03 100644 --- a/osu.Game/Overlays/Settings/SettingsSlider.cs +++ b/osu.Game/Overlays/Settings/SettingsSlider.cs @@ -10,14 +10,14 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public partial class SettingsSlider : SettingsSlider> + public partial class SettingsSlider : SettingsSlider> where T : struct, IEquatable, IComparable, IConvertible { } public partial class SettingsSlider : SettingsItem where TValue : struct, IEquatable, IComparable, IConvertible - where TSlider : OsuSliderBar, new() + where TSlider : NormalSliderBar, new() { protected override Drawable CreateControl() => new TSlider { diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index 38ced4c9e7..58810fc127 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Mods { InternalChildren = new Drawable[] { - new OsuSliderBar + new NormalSliderBar { RelativeSizeAxes = Axes.X, Current = currentNumber, diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index 59fbfe49b6..a7b00ac88b 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mods } } - public partial class PercentSlider : OsuSliderBar + public partial class PercentSlider : NormalSliderBar { public PercentSlider() { diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 59c4cfa85b..d2d8284083 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Mods public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; } - public partial class MuteComboSlider : OsuSliderBar + public partial class MuteComboSlider : NormalSliderBar { public override LocalisableString TooltipText => Current.Value == 0 ? "always muted" : base.TooltipText; } diff --git a/osu.Game/Rulesets/Mods/ModNoScope.cs b/osu.Game/Rulesets/Mods/ModNoScope.cs index cfac44066e..3736eca780 100644 --- a/osu.Game/Rulesets/Mods/ModNoScope.cs +++ b/osu.Game/Rulesets/Mods/ModNoScope.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mods } } - public partial class HiddenComboSlider : OsuSliderBar + public partial class HiddenComboSlider : NormalSliderBar { public override LocalisableString TooltipText => Current.Value == 0 ? "always hidden" : base.TooltipText; } diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs index 45d4995753..985a414bc0 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs @@ -15,11 +15,11 @@ namespace osu.Game.Screens.Play.PlayerSettings public partial class PlayerSliderBar : SettingsSlider where T : struct, IEquatable, IComparable, IConvertible { - public OsuSliderBar Bar => (OsuSliderBar)Control; + public NormalSliderBar Bar => (NormalSliderBar)Control; protected override Drawable CreateControl() => new SliderBar(); - protected partial class SliderBar : OsuSliderBar + protected partial class SliderBar : NormalSliderBar { public SliderBar() { From ac3ad9cf8d21cf7daa4b0806c114b3087255747e Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 12:16:51 +0100 Subject: [PATCH 081/516] Implement OsuSliderBar.cs as base ( non framework side ) class from which NormalSliderBar.cs inherits --- osu.Game/Graphics/UserInterface/NormalSliderBar.cs | 3 +-- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 13 +++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/OsuSliderBar.cs diff --git a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs index 71422f097f..0d06995ccf 100644 --- a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs @@ -14,7 +14,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; @@ -25,7 +24,7 @@ using osu.Game.Utils; namespace osu.Game.Graphics.UserInterface { - public partial class NormalSliderBar : SliderBar, IHasTooltip, IHasAccentColour + public partial class NormalSliderBar : OsuSliderBar, IHasTooltip, IHasAccentColour where T : struct, IEquatable, IComparable, IConvertible { /// diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs new file mode 100644 index 0000000000..d82850d181 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Graphics.UserInterface; + +namespace osu.Game.Graphics.UserInterface +{ + public abstract partial class OsuSliderBar : SliderBar + where T : struct, IEquatable, IComparable, IConvertible + { + } +} From 9afc8681ef12f9ddcb8f021f1629e97a8ff10804 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 12:25:05 +0100 Subject: [PATCH 082/516] Extract tooltip implementation into base OsuSliderBar.cs from NormalSliderBar.cs --- .../Graphics/UserInterface/NormalSliderBar.cs | 37 +----------- .../Graphics/UserInterface/OsuSliderBar.cs | 56 ++++++++++++++++++- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs index 0d06995ccf..1a894046d9 100644 --- a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs @@ -14,24 +14,16 @@ using osu.Framework.Audio.Sample; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; -using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Overlays; -using osu.Game.Utils; namespace osu.Game.Graphics.UserInterface { - public partial class NormalSliderBar : OsuSliderBar, IHasTooltip, IHasAccentColour + public partial class NormalSliderBar : OsuSliderBar, IHasAccentColour where T : struct, IEquatable, IComparable, IConvertible { - /// - /// Maximum number of decimal digits to be displayed in the tooltip. - /// - private const int max_decimal_digits = 5; - private Sample sample; private double lastSampleTime; private T lastSampleValue; @@ -41,17 +33,10 @@ namespace osu.Game.Graphics.UserInterface protected readonly Box RightBox; private readonly Container nubContainer; - public virtual LocalisableString TooltipText { get; private set; } - public bool PlaySamplesOnAdjust { get; set; } = true; private readonly HoverClickSounds hoverClickSounds; - /// - /// Whether to format the tooltip as a percentage or the actual value. - /// - public bool DisplayAsPercentage { get; set; } - private Color4 accentColour; public Color4 AccentColour @@ -150,7 +135,6 @@ namespace osu.Game.Graphics.UserInterface protected override void LoadComplete() { base.LoadComplete(); - CurrentNumber.BindValueChanged(current => TooltipText = getTooltipText(current.NewValue), true); Current.BindDisabledChanged(disabled => { @@ -189,7 +173,6 @@ namespace osu.Game.Graphics.UserInterface { base.OnUserChange(value); playSample(value); - TooltipText = getTooltipText(value); } private void playSample(T value) @@ -217,24 +200,6 @@ namespace osu.Game.Graphics.UserInterface channel.Play(); } - private LocalisableString getTooltipText(T value) - { - if (CurrentNumber.IsInteger) - return value.ToInt32(NumberFormatInfo.InvariantInfo).ToString("N0"); - - double floatValue = value.ToDouble(NumberFormatInfo.InvariantInfo); - - if (DisplayAsPercentage) - return floatValue.ToString("0%"); - - decimal decimalPrecision = normalise(CurrentNumber.Precision.ToDecimal(NumberFormatInfo.InvariantInfo), max_decimal_digits); - - // Find the number of significant digits (we could have less than 5 after normalize()) - int significantDigits = FormatUtils.FindPrecision(decimalPrecision); - - return floatValue.ToString($"N{significantDigits}"); - } - protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index d82850d181..6a8f81a4b6 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -2,12 +2,66 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Globalization; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Localisation; +using osu.Game.Utils; namespace osu.Game.Graphics.UserInterface { - public abstract partial class OsuSliderBar : SliderBar + public abstract partial class OsuSliderBar : SliderBar, IHasTooltip where T : struct, IEquatable, IComparable, IConvertible { + public virtual LocalisableString TooltipText { get; private set; } + + /// + /// Maximum number of decimal digits to be displayed in the tooltip. + /// + private const int max_decimal_digits = 5; + + /// + /// Whether to format the tooltip as a percentage or the actual value. + /// + public bool DisplayAsPercentage { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + CurrentNumber.BindValueChanged(current => TooltipText = getTooltipText(current.NewValue), true); + } + + protected override void OnUserChange(T value) + { + base.OnUserChange(value); + TooltipText = getTooltipText(value); + } + + private LocalisableString getTooltipText(T value) + { + if (CurrentNumber.IsInteger) + return value.ToInt32(NumberFormatInfo.InvariantInfo).ToString("N0"); + + double floatValue = value.ToDouble(NumberFormatInfo.InvariantInfo); + + if (DisplayAsPercentage) + return floatValue.ToString("0%"); + + decimal decimalPrecision = normalise(CurrentNumber.Precision.ToDecimal(NumberFormatInfo.InvariantInfo), max_decimal_digits); + + // Find the number of significant digits (we could have less than 5 after normalize()) + int significantDigits = FormatUtils.FindPrecision(decimalPrecision); + + return floatValue.ToString($"N{significantDigits}"); + } + + /// + /// Removes all non-significant digits, keeping at most a requested number of decimal digits. + /// + /// The decimal to normalize. + /// The maximum number of decimal digits to keep. The final result may have fewer decimal digits than this value. + /// The normalised decimal. + private decimal normalise(decimal d, int sd) + => decimal.Parse(Math.Round(d, sd).ToString(string.Concat("0.", new string('#', sd)), CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); } } From fc99165df7f5e3a046d1cd754f2b10da78022bcc Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 12:36:05 +0100 Subject: [PATCH 083/516] Extract samples into base OsuSliderBar.cs from NormalSliderBar.cs --- .../Graphics/UserInterface/NormalSliderBar.cs | 55 +------------------ .../Graphics/UserInterface/OsuSliderBar.cs | 45 +++++++++++++++ 2 files changed, 47 insertions(+), 53 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs index 1a894046d9..902609d7a6 100644 --- a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs @@ -4,37 +4,27 @@ #nullable disable using System; -using System.Globalization; using JetBrains.Annotations; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; -using osu.Framework.Utils; using osu.Game.Overlays; namespace osu.Game.Graphics.UserInterface { - public partial class NormalSliderBar : OsuSliderBar, IHasAccentColour + public partial class NormalSliderBar : OsuSliderBar where T : struct, IEquatable, IComparable, IConvertible { - private Sample sample; - private double lastSampleTime; - private T lastSampleValue; - protected readonly Nub Nub; protected readonly Box LeftBox; protected readonly Box RightBox; private readonly Container nubContainer; - public bool PlaySamplesOnAdjust { get; set; } = true; - private readonly HoverClickSounds hoverClickSounds; private Color4 accentColour; @@ -118,9 +108,8 @@ namespace osu.Game.Graphics.UserInterface } [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, [CanBeNull] OverlayColourProvider colourProvider, OsuColour colours) + private void load([CanBeNull] OverlayColourProvider colourProvider, OsuColour colours) { - sample = audio.Samples.Get(@"UI/notch-tick"); AccentColour = colourProvider?.Highlight1 ?? colours.Pink; BackgroundColour = colourProvider?.Background5 ?? colours.PinkDarker.Darken(1); } @@ -169,37 +158,6 @@ namespace osu.Game.Graphics.UserInterface Nub.Glowing = !Current.Disabled && (IsHovered || IsDragged); } - protected override void OnUserChange(T value) - { - base.OnUserChange(value); - playSample(value); - } - - private void playSample(T value) - { - if (!PlaySamplesOnAdjust) - return; - - if (Clock == null || Clock.CurrentTime - lastSampleTime <= 30) - return; - - if (value.Equals(lastSampleValue)) - return; - - lastSampleValue = value; - lastSampleTime = Clock.CurrentTime; - - var channel = sample.GetChannel(); - - channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + NormalizedValue * 0.2f; - - // intentionally pitched down, even when hitting max. - if (NormalizedValue == 0 || NormalizedValue == 1) - channel.Frequency.Value -= 0.5f; - - channel.Play(); - } - protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -211,14 +169,5 @@ namespace osu.Game.Graphics.UserInterface { Nub.MoveToX(value, 250, Easing.OutQuint); } - - /// - /// Removes all non-significant digits, keeping at most a requested number of decimal digits. - /// - /// The decimal to normalize. - /// The maximum number of decimal digits to keep. The final result may have fewer decimal digits than this value. - /// The normalised decimal. - private decimal normalise(decimal d, int sd) - => decimal.Parse(Math.Round(d, sd).ToString(string.Concat("0.", new string('#', sd)), CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); } } diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 6a8f81a4b6..ee1f75c419 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -3,9 +3,13 @@ using System; using System.Globalization; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; +using osu.Framework.Utils; using osu.Game.Utils; namespace osu.Game.Graphics.UserInterface @@ -13,6 +17,19 @@ namespace osu.Game.Graphics.UserInterface public abstract partial class OsuSliderBar : SliderBar, IHasTooltip where T : struct, IEquatable, IComparable, IConvertible { + private Sample sample = null!; + + private double lastSampleTime; + private T lastSampleValue; + + public bool PlaySamplesOnAdjust { get; set; } = true; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sample = audio.Samples.Get(@"UI/notch-tick"); + } + public virtual LocalisableString TooltipText { get; private set; } /// @@ -34,9 +51,37 @@ namespace osu.Game.Graphics.UserInterface protected override void OnUserChange(T value) { base.OnUserChange(value); + + playSample(value); + TooltipText = getTooltipText(value); } + private void playSample(T value) + { + if (!PlaySamplesOnAdjust) + return; + + if (Clock == null || Clock.CurrentTime - lastSampleTime <= 30) + return; + + if (value.Equals(lastSampleValue)) + return; + + lastSampleValue = value; + lastSampleTime = Clock.CurrentTime; + + var channel = sample.GetChannel(); + + channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + NormalizedValue * 0.2f; + + // intentionally pitched down, even when hitting max. + if (NormalizedValue == 0 || NormalizedValue == 1) + channel.Frequency.Value -= 0.5f; + + channel.Play(); + } + private LocalisableString getTooltipText(T value) { if (CurrentNumber.IsInteger) From 7355397e83e9bf2df030445622ae95ac36369368 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 12:58:58 +0100 Subject: [PATCH 084/516] Enable NRT on NormalSliderBar.cs --- osu.Game/Graphics/UserInterface/NormalSliderBar.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs index 902609d7a6..92febaa6e6 100644 --- a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs @@ -1,10 +1,7 @@ // 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 JetBrains.Annotations; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; @@ -108,7 +105,7 @@ namespace osu.Game.Graphics.UserInterface } [BackgroundDependencyLoader(true)] - private void load([CanBeNull] OverlayColourProvider colourProvider, OsuColour colours) + private void load(OverlayColourProvider? colourProvider, OsuColour colours) { AccentColour = colourProvider?.Highlight1 ?? colours.Pink; BackgroundColour = colourProvider?.Background5 ?? colours.PinkDarker.Darken(1); From 374c3b56f6f2e8b74fd87c538baa5354bf59d708 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 13:21:20 +0100 Subject: [PATCH 085/516] Rename Nub.cs to NormalNub.cs --- .../UserInterface/TestSceneRangeSlider.cs | 2 +- .../UserInterface/{Nub.cs => NormalNub.cs} | 4 +-- .../Graphics/UserInterface/NormalSliderBar.cs | 18 ++++++------ .../Graphics/UserInterface/OsuCheckbox.cs | 28 +++++++++---------- .../Graphics/UserInterface/RangeSlider.cs | 18 ++++++------ .../OsuDirectorySelectorHiddenToggle.cs | 6 ++-- osu.Game/Overlays/Mods/ModColumn.cs | 6 ++-- .../Play/PlayerSettings/PlayerCheckbox.cs | 6 ++-- .../Play/PlayerSettings/PlayerSliderBar.cs | 6 ++-- 9 files changed, 47 insertions(+), 47 deletions(-) rename osu.Game/Graphics/UserInterface/{Nub.cs => NormalNub.cs} (97%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs index b780764e7f..0100b2a1a0 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.UserInterface LowerBound = customStart, UpperBound = customEnd, TooltipSuffix = "suffix", - NubWidth = Nub.HEIGHT * 2, + NubWidth = NormalNub.HEIGHT * 2, DefaultStringLowerBound = "Start", DefaultStringUpperBound = "End", MinRange = 10 diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/NormalNub.cs similarity index 97% rename from osu.Game/Graphics/UserInterface/Nub.cs rename to osu.Game/Graphics/UserInterface/NormalNub.cs index 7921dcf593..549b3ffa04 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/NormalNub.cs @@ -19,7 +19,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.UserInterface { - public partial class Nub : Container, IHasCurrentValue, IHasAccentColour + public partial class NormalNub : Container, IHasCurrentValue, IHasAccentColour { public const float HEIGHT = 15; @@ -30,7 +30,7 @@ namespace osu.Game.Graphics.UserInterface private readonly Box fill; private readonly Container main; - public Nub() + public NormalNub() { Size = new Vector2(EXPANDED_SIZE, HEIGHT); diff --git a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs index 92febaa6e6..bc27c9af4c 100644 --- a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface public partial class NormalSliderBar : OsuSliderBar where T : struct, IEquatable, IComparable, IConvertible { - protected readonly Nub Nub; + protected readonly NormalNub NormalNub; protected readonly Box LeftBox; protected readonly Box RightBox; private readonly Container nubContainer; @@ -50,8 +50,8 @@ namespace osu.Game.Graphics.UserInterface public NormalSliderBar() { - Height = Nub.HEIGHT; - RangePadding = Nub.EXPANDED_SIZE / 2; + Height = NormalNub.HEIGHT; + RangePadding = NormalNub.EXPANDED_SIZE / 2; Children = new Drawable[] { new Container @@ -93,7 +93,7 @@ namespace osu.Game.Graphics.UserInterface nubContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = Nub = new Nub + Child = NormalNub = new NormalNub { Origin = Anchor.TopCentre, RelativePositionAxes = Axes.X, @@ -142,7 +142,7 @@ namespace osu.Game.Graphics.UserInterface } protected override bool ShouldHandleAsRelativeDrag(MouseDownEvent e) - => Nub.ReceivePositionalInputAt(e.ScreenSpaceMouseDownPosition); + => NormalNub.ReceivePositionalInputAt(e.ScreenSpaceMouseDownPosition); protected override void OnDragEnd(DragEndEvent e) { @@ -152,19 +152,19 @@ namespace osu.Game.Graphics.UserInterface private void updateGlow() { - Nub.Glowing = !Current.Disabled && (IsHovered || IsDragged); + NormalNub.Glowing = !Current.Disabled && (IsHovered || IsDragged); } protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); - LeftBox.Scale = new Vector2(Math.Clamp(RangePadding + Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, Math.Max(0, DrawWidth)), 1); - RightBox.Scale = new Vector2(Math.Clamp(DrawWidth - Nub.DrawPosition.X - RangePadding - Nub.DrawWidth / 2, 0, Math.Max(0, DrawWidth)), 1); + LeftBox.Scale = new Vector2(Math.Clamp(RangePadding + NormalNub.DrawPosition.X - NormalNub.DrawWidth / 2, 0, Math.Max(0, DrawWidth)), 1); + RightBox.Scale = new Vector2(Math.Clamp(DrawWidth - NormalNub.DrawPosition.X - RangePadding - NormalNub.DrawWidth / 2, 0, Math.Max(0, DrawWidth)), 1); } protected override void UpdateValue(float value) { - Nub.MoveToX(value, 250, Easing.OutQuint); + NormalNub.MoveToX(value, 250, Easing.OutQuint); } } } diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs index 160105af1a..982706f87b 100644 --- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs @@ -41,7 +41,7 @@ namespace osu.Game.Graphics.UserInterface } } - protected readonly Nub Nub; + protected readonly NormalNub NormalNub; protected readonly OsuTextFlowContainer LabelTextFlowContainer; private Sample sampleChecked; @@ -61,28 +61,28 @@ namespace osu.Game.Graphics.UserInterface AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, }, - Nub = new Nub(), + NormalNub = new NormalNub(), new HoverSounds() }; if (nubOnRight) { - Nub.Anchor = Anchor.CentreRight; - Nub.Origin = Anchor.CentreRight; - Nub.Margin = new MarginPadding { Right = nub_padding }; - LabelTextFlowContainer.Padding = new MarginPadding { Right = Nub.EXPANDED_SIZE + nub_padding * 2 }; + NormalNub.Anchor = Anchor.CentreRight; + NormalNub.Origin = Anchor.CentreRight; + NormalNub.Margin = new MarginPadding { Right = nub_padding }; + LabelTextFlowContainer.Padding = new MarginPadding { Right = NormalNub.EXPANDED_SIZE + nub_padding * 2 }; } else { - Nub.Anchor = Anchor.CentreLeft; - Nub.Origin = Anchor.CentreLeft; - Nub.Margin = new MarginPadding { Left = nub_padding }; - LabelTextFlowContainer.Padding = new MarginPadding { Left = Nub.EXPANDED_SIZE + nub_padding * 2 }; + NormalNub.Anchor = Anchor.CentreLeft; + NormalNub.Origin = Anchor.CentreLeft; + NormalNub.Margin = new MarginPadding { Left = nub_padding }; + LabelTextFlowContainer.Padding = new MarginPadding { Left = NormalNub.EXPANDED_SIZE + nub_padding * 2 }; } - Nub.Current.BindTo(Current); + NormalNub.Current.BindTo(Current); - Current.DisabledChanged += disabled => LabelTextFlowContainer.Alpha = Nub.Alpha = disabled ? 0.3f : 1; + Current.DisabledChanged += disabled => LabelTextFlowContainer.Alpha = NormalNub.Alpha = disabled ? 0.3f : 1; } /// @@ -101,13 +101,13 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(HoverEvent e) { - Nub.Glowing = true; + NormalNub.Glowing = true; return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - Nub.Glowing = false; + NormalNub.Glowing = false; base.OnHoverLost(e); } diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs index 2f3dc07a91..963c859198 100644 --- a/osu.Game/Graphics/UserInterface/RangeSlider.cs +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -141,7 +141,7 @@ namespace osu.Game.Graphics.UserInterface public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) - && screenSpacePos.X <= Nub.ScreenSpaceDrawQuad.TopRight.X; + && screenSpacePos.X <= NormalNub.ScreenSpaceDrawQuad.TopRight.X; } private partial class UpperBoundSlider : BoundSlider @@ -155,7 +155,7 @@ namespace osu.Game.Graphics.UserInterface public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) - && screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X; + && screenSpacePos.X >= NormalNub.ScreenSpaceDrawQuad.TopLeft.X; } protected partial class BoundSlider : NormalSliderBar @@ -163,7 +163,7 @@ namespace osu.Game.Graphics.UserInterface public string? DefaultString; public LocalisableString? DefaultTooltip; public string? TooltipSuffix; - public float NubWidth { get; set; } = Nub.HEIGHT; + public float NubWidth { get; set; } = NormalNub.HEIGHT; public override LocalisableString TooltipText => (Current.IsDefault ? DefaultTooltip : Current.Value.ToString($@"0.## {TooltipSuffix}")) ?? Current.Value.ToString($@"0.## {TooltipSuffix}"); @@ -177,12 +177,12 @@ namespace osu.Game.Graphics.UserInterface protected override void LoadComplete() { base.LoadComplete(); - Nub.Width = NubWidth; - RangePadding = Nub.Width / 2; + NormalNub.Width = NubWidth; + RangePadding = NormalNub.Width / 2; OsuSpriteText currentDisplay; - Nub.Add(currentDisplay = new OsuSpriteText + NormalNub.Add(currentDisplay = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -203,9 +203,9 @@ namespace osu.Game.Graphics.UserInterface if (colourProvider == null) return; AccentColour = colourProvider.Background2; - Nub.AccentColour = colourProvider.Background2; - Nub.GlowingAccentColour = colourProvider.Background1; - Nub.GlowColour = colourProvider.Background2; + NormalNub.AccentColour = colourProvider.Background2; + NormalNub.GlowingAccentColour = colourProvider.Background1; + NormalNub.GlowColour = colourProvider.Background2; } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs index 7665ed507f..79f72495c8 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs @@ -30,9 +30,9 @@ namespace osu.Game.Graphics.UserInterfaceV2 if (overlayColourProvider != null) return; - Nub.AccentColour = colours.GreySeaFoamLighter; - Nub.GlowingAccentColour = Color4.White; - Nub.GlowColour = Color4.White; + NormalNub.AccentColour = colours.GreySeaFoamLighter; + NormalNub.GlowingAccentColour = Color4.White; + NormalNub.GlowColour = Color4.White; } } } diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index 5d9f616e5f..97a766259a 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -267,9 +267,9 @@ namespace osu.Game.Overlays.Mods private void updateState() { - Nub.AccentColour = AccentColour; - Nub.GlowingAccentColour = AccentHoverColour; - Nub.GlowColour = AccentHoverColour.Opacity(0.2f); + NormalNub.AccentColour = AccentColour; + NormalNub.GlowingAccentColour = AccentHoverColour; + NormalNub.GlowColour = AccentHoverColour.Opacity(0.2f); } protected override void OnUserChange(bool value) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs index 49c9cbf385..960904282d 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs @@ -18,9 +18,9 @@ namespace osu.Game.Screens.Play.PlayerSettings [BackgroundDependencyLoader] private void load(OsuColour colours) { - Nub.AccentColour = colours.Yellow; - Nub.GlowingAccentColour = colours.YellowLighter; - Nub.GlowColour = colours.YellowDark; + NormalNub.AccentColour = colours.Yellow; + NormalNub.GlowingAccentColour = colours.YellowLighter; + NormalNub.GlowColour = colours.YellowDark; } } } diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs index 985a414bc0..b54207886e 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs @@ -30,9 +30,9 @@ namespace osu.Game.Screens.Play.PlayerSettings private void load(OsuColour colours) { AccentColour = colours.Yellow; - Nub.AccentColour = colours.Yellow; - Nub.GlowingAccentColour = colours.YellowLighter; - Nub.GlowColour = colours.YellowDark; + NormalNub.AccentColour = colours.Yellow; + NormalNub.GlowingAccentColour = colours.YellowLighter; + NormalNub.GlowColour = colours.YellowDark; } } } From 63efe79abcdd7465f0b7f137efbcfe66424b0d2c Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 13:22:49 +0100 Subject: [PATCH 086/516] Enable NRT for NormalNub.cs --- osu.Game/Graphics/UserInterface/NormalNub.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/NormalNub.cs b/osu.Game/Graphics/UserInterface/NormalNub.cs index 549b3ffa04..1affbabd9d 100644 --- a/osu.Game/Graphics/UserInterface/NormalNub.cs +++ b/osu.Game/Graphics/UserInterface/NormalNub.cs @@ -1,10 +1,7 @@ // 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 JetBrains.Annotations; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; @@ -58,7 +55,7 @@ namespace osu.Game.Graphics.UserInterface } [BackgroundDependencyLoader(true)] - private void load([CanBeNull] OverlayColourProvider colourProvider, OsuColour colours) + private void load(OverlayColourProvider? colourProvider, OsuColour colours) { AccentColour = colourProvider?.Highlight1 ?? colours.Pink; GlowingAccentColour = colourProvider?.Highlight1.Lighten(0.2f) ?? colours.PinkLighter; From b8ae689b31e87437732c4fa59422f386acc0614c Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 13:41:14 +0100 Subject: [PATCH 087/516] Re-add Nub.cs and move logic from NormalNub.cs to it. --- osu.Game/Graphics/UserInterface/NormalNub.cs | 170 ++----------------- osu.Game/Graphics/UserInterface/Nub.cs | 162 ++++++++++++++++++ 2 files changed, 174 insertions(+), 158 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/Nub.cs diff --git a/osu.Game/Graphics/UserInterface/NormalNub.cs b/osu.Game/Graphics/UserInterface/NormalNub.cs index 1affbabd9d..1fe87da7a8 100644 --- a/osu.Game/Graphics/UserInterface/NormalNub.cs +++ b/osu.Game/Graphics/UserInterface/NormalNub.cs @@ -1,180 +1,34 @@ // 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 osuTK; -using osuTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Overlays; +using osuTK; namespace osu.Game.Graphics.UserInterface { - public partial class NormalNub : Container, IHasCurrentValue, IHasAccentColour + public partial class NormalNub : Nub { public const float HEIGHT = 15; public const float EXPANDED_SIZE = 50; - private const float border_width = 3; - - private readonly Box fill; - private readonly Container main; - public NormalNub() { Size = new Vector2(EXPANDED_SIZE, HEIGHT); + } - InternalChildren = new[] + protected override Container CreateNubContainer() + { + return new CircularContainer { - main = new CircularContainer - { - BorderColour = Color4.White, - BorderThickness = border_width, - Masking = true, - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Children = new Drawable[] - { - fill = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true, - }, - } - }, + BorderColour = Colour4.White, + BorderThickness = BORDER_WIDTH, + Masking = true, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, }; } - - [BackgroundDependencyLoader(true)] - private void load(OverlayColourProvider? colourProvider, OsuColour colours) - { - AccentColour = colourProvider?.Highlight1 ?? colours.Pink; - GlowingAccentColour = colourProvider?.Highlight1.Lighten(0.2f) ?? colours.PinkLighter; - GlowColour = colourProvider?.Highlight1 ?? colours.PinkLighter; - - main.EdgeEffect = new EdgeEffectParameters - { - Colour = GlowColour.Opacity(0), - Type = EdgeEffectType.Glow, - Radius = 8, - Roundness = 4, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Current.BindValueChanged(onCurrentValueChanged, true); - } - - private bool glowing; - - public bool Glowing - { - get => glowing; - set - { - glowing = value; - - if (value) - { - main.FadeColour(GlowingAccentColour.Lighten(0.5f), 40, Easing.OutQuint) - .Then() - .FadeColour(GlowingAccentColour, 800, Easing.OutQuint); - - main.FadeEdgeEffectTo(Color4.White.Opacity(0.1f), 40, Easing.OutQuint) - .Then() - .FadeEdgeEffectTo(GlowColour.Opacity(0.1f), 800, Easing.OutQuint); - } - else - { - main.FadeEdgeEffectTo(GlowColour.Opacity(0), 800, Easing.OutQuint); - main.FadeColour(AccentColour, 800, Easing.OutQuint); - } - } - } - - private readonly Bindable current = new Bindable(); - - public Bindable Current - { - get => current; - set - { - ArgumentNullException.ThrowIfNull(value); - - current.UnbindBindings(); - current.BindTo(value); - } - } - - private Color4 accentColour; - - public Color4 AccentColour - { - get => accentColour; - set - { - accentColour = value; - if (!Glowing) - main.Colour = value; - } - } - - private Color4 glowingAccentColour; - - public Color4 GlowingAccentColour - { - get => glowingAccentColour; - set - { - glowingAccentColour = value; - if (Glowing) - main.Colour = value; - } - } - - private Color4 glowColour; - - public Color4 GlowColour - { - get => glowColour; - set - { - glowColour = value; - - var effect = main.EdgeEffect; - effect.Colour = Glowing ? value : value.Opacity(0); - main.EdgeEffect = effect; - } - } - - private void onCurrentValueChanged(ValueChangedEvent filled) - { - const double duration = 200; - - fill.FadeTo(filled.NewValue ? 1 : 0, duration, Easing.OutQuint); - - if (filled.NewValue) - { - main.ResizeWidthTo(1, duration, Easing.OutElasticHalf); - main.TransformTo(nameof(BorderThickness), 8.5f, duration, Easing.OutElasticHalf); - } - else - { - main.ResizeWidthTo(0.75f, duration, Easing.OutQuint); - main.TransformTo(nameof(BorderThickness), border_width, duration, Easing.OutQuint); - } - } } } diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs new file mode 100644 index 0000000000..7830381d10 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -0,0 +1,162 @@ +// 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.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Overlays; +using osuTK.Graphics; + +namespace osu.Game.Graphics.UserInterface +{ + public abstract partial class Nub : Container, IHasCurrentValue, IHasAccentColour + { + protected const float BORDER_WIDTH = 3; + + private readonly Box fill; + private readonly Container main; + + protected abstract Container CreateNubContainer(); + + protected Nub() + { + InternalChild = main = CreateNubContainer(); + + main.Add(fill = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + }); + } + + [BackgroundDependencyLoader(true)] + private void load(OverlayColourProvider? colourProvider, OsuColour colours) + { + AccentColour = colourProvider?.Highlight1 ?? colours.Pink; + GlowingAccentColour = colourProvider?.Highlight1.Lighten(0.2f) ?? colours.PinkLighter; + GlowColour = colourProvider?.Highlight1 ?? colours.PinkLighter; + + main.EdgeEffect = new EdgeEffectParameters + { + Colour = GlowColour.Opacity(0), + Type = EdgeEffectType.Glow, + Radius = 8, + Roundness = 4, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindValueChanged(onCurrentValueChanged, true); + } + + private bool glowing; + + public bool Glowing + { + get => glowing; + set + { + glowing = value; + + if (value) + { + main.FadeColour(GlowingAccentColour.Lighten(0.5f), 40, Easing.OutQuint) + .Then() + .FadeColour(GlowingAccentColour, 800, Easing.OutQuint); + + main.FadeEdgeEffectTo(Color4.White.Opacity(0.1f), 40, Easing.OutQuint) + .Then() + .FadeEdgeEffectTo(GlowColour.Opacity(0.1f), 800, Easing.OutQuint); + } + else + { + main.FadeEdgeEffectTo(GlowColour.Opacity(0), 800, Easing.OutQuint); + main.FadeColour(AccentColour, 800, Easing.OutQuint); + } + } + } + + private readonly Bindable current = new Bindable(); + + public Bindable Current + { + get => current; + set + { + ArgumentNullException.ThrowIfNull(value); + + current.UnbindBindings(); + current.BindTo(value); + } + } + + private Color4 accentColour; + + public Color4 AccentColour + { + get => accentColour; + set + { + accentColour = value; + if (!Glowing) + main.Colour = value; + } + } + + private Color4 glowingAccentColour; + + public Color4 GlowingAccentColour + { + get => glowingAccentColour; + set + { + glowingAccentColour = value; + if (Glowing) + main.Colour = value; + } + } + + private Color4 glowColour; + + public Color4 GlowColour + { + get => glowColour; + set + { + glowColour = value; + + var effect = main.EdgeEffect; + effect.Colour = Glowing ? value : value.Opacity(0); + main.EdgeEffect = effect; + } + } + + private void onCurrentValueChanged(ValueChangedEvent filled) + { + const double duration = 200; + + fill.FadeTo(filled.NewValue ? 1 : 0, duration, Easing.OutQuint); + + if (filled.NewValue) + { + main.ResizeWidthTo(1, duration, Easing.OutElasticHalf); + main.TransformTo(nameof(BorderThickness), 8.5f, duration, Easing.OutElasticHalf); + } + else + { + main.ResizeWidthTo(0.75f, duration, Easing.OutQuint); + main.TransformTo(nameof(BorderThickness), BORDER_WIDTH, duration, Easing.OutQuint); + } + } + } +} From 6dfb9630d62c19c5330a4090fcb3a94115bce64d Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 13:53:17 +0100 Subject: [PATCH 088/516] Implement ShearedNub.cs as well as tweak the syntax in NormalNub.cs --- osu.Game/Graphics/UserInterface/NormalNub.cs | 6 ++--- osu.Game/Graphics/UserInterface/Nub.cs | 4 +++ osu.Game/Graphics/UserInterface/ShearedNub.cs | 27 +++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/ShearedNub.cs diff --git a/osu.Game/Graphics/UserInterface/NormalNub.cs b/osu.Game/Graphics/UserInterface/NormalNub.cs index 1fe87da7a8..e6939d060b 100644 --- a/osu.Game/Graphics/UserInterface/NormalNub.cs +++ b/osu.Game/Graphics/UserInterface/NormalNub.cs @@ -18,9 +18,8 @@ namespace osu.Game.Graphics.UserInterface Size = new Vector2(EXPANDED_SIZE, HEIGHT); } - protected override Container CreateNubContainer() - { - return new CircularContainer + protected override Container CreateNubContainer() => + new CircularContainer { BorderColour = Colour4.White, BorderThickness = BORDER_WIDTH, @@ -29,6 +28,5 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, }; - } } } diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 7830381d10..6f875e8594 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -22,6 +22,10 @@ namespace osu.Game.Graphics.UserInterface private readonly Box fill; private readonly Container main; + /// + /// Implements the shape for the nub, allowing for any type of container to be used. + /// + /// protected abstract Container CreateNubContainer(); protected Nub() diff --git a/osu.Game/Graphics/UserInterface/ShearedNub.cs b/osu.Game/Graphics/UserInterface/ShearedNub.cs new file mode 100644 index 0000000000..6c3fbaf7e6 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/ShearedNub.cs @@ -0,0 +1,27 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; + +namespace osu.Game.Graphics.UserInterface +{ + public partial class ShearedNub : Nub + { + public static readonly Vector2 SHEAR = new Vector2(0.15f, 0); + + protected override Container CreateNubContainer() => + new Container + { + Shear = SHEAR, + BorderColour = Colour4.White, + BorderThickness = BORDER_WIDTH, + Masking = true, + CornerRadius = 5, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }; + } +} From 2f90ffccfc19fad4cc8bc0e03f3a6d50d71cdab0 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 14:39:11 +0100 Subject: [PATCH 089/516] Implement ShearedSliderBar.cs and corresponding TestSceneShearedSliderBar.cs --- .../TestSceneShearedSliderBar.cs | 37 ++++ osu.Game/Graphics/UserInterface/ShearedNub.cs | 8 + .../UserInterface/ShearedSliderBar.cs | 170 ++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneShearedSliderBar.cs create mode 100644 osu.Game/Graphics/UserInterface/ShearedSliderBar.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSliderBar.cs new file mode 100644 index 0000000000..c2d0de95e0 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSliderBar.cs @@ -0,0 +1,37 @@ +// 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.Bindables; +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public partial class TestSceneShearedSlider : OsuTestScene + { + [Cached] + private OverlayColourProvider colourProvider { get; set; } = new OverlayColourProvider(OverlayColourScheme.Purple); + + private readonly BindableDouble current = new BindableDouble(5) + { + Precision = 0.1f, + MinValue = 0, + MaxValue = 15 + }; + + [BackgroundDependencyLoader] + private void load() + { + Child = new ShearedSliderBar + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Current = current, + RelativeSizeAxes = Axes.X, + Width = 0.4f + }; + } + } +} diff --git a/osu.Game/Graphics/UserInterface/ShearedNub.cs b/osu.Game/Graphics/UserInterface/ShearedNub.cs index 6c3fbaf7e6..6bee4fc3b7 100644 --- a/osu.Game/Graphics/UserInterface/ShearedNub.cs +++ b/osu.Game/Graphics/UserInterface/ShearedNub.cs @@ -9,8 +9,16 @@ namespace osu.Game.Graphics.UserInterface { public partial class ShearedNub : Nub { + public const int HEIGHT = 30; + public const float EXPANDED_SIZE = 50; + public static readonly Vector2 SHEAR = new Vector2(0.15f, 0); + public ShearedNub() + { + Size = new Vector2(EXPANDED_SIZE, HEIGHT); + } + protected override Container CreateNubContainer() => new Container { diff --git a/osu.Game/Graphics/UserInterface/ShearedSliderBar.cs b/osu.Game/Graphics/UserInterface/ShearedSliderBar.cs new file mode 100644 index 0000000000..08d5fd8992 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/ShearedSliderBar.cs @@ -0,0 +1,170 @@ +// 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 osuTK; +using osuTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Overlays; +using static osu.Game.Graphics.UserInterface.ShearedNub; + +namespace osu.Game.Graphics.UserInterface +{ + public partial class ShearedSliderBar : OsuSliderBar + where T : struct, IEquatable, IComparable, IConvertible + { + protected readonly ShearedNub Nub; + protected readonly Box LeftBox; + protected readonly Box RightBox; + private readonly Container nubContainer; + + private readonly HoverClickSounds hoverClickSounds; + + private Color4 accentColour; + + public Color4 AccentColour + { + get => accentColour; + set + { + accentColour = value; + LeftBox.Colour = value; + } + } + + private Colour4 backgroundColour; + + public Color4 BackgroundColour + { + get => backgroundColour; + set + { + backgroundColour = value; + RightBox.Colour = value; + } + } + + public ShearedSliderBar() + { + Shear = SHEAR; + Height = HEIGHT; + RangePadding = EXPANDED_SIZE / 2; + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Padding = new MarginPadding { Horizontal = 2 }, + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Masking = true, + CornerRadius = 5, + Children = new Drawable[] + { + LeftBox = new Box + { + EdgeSmoothness = new Vector2(0, 0.5f), + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + RightBox = new Box + { + EdgeSmoothness = new Vector2(0, 0.5f), + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + }, + }, + }, + }, + nubContainer = new Container + { + Shear = -SHEAR, + RelativeSizeAxes = Axes.Both, + Child = Nub = new ShearedNub + { + X = -SHEAR.X * HEIGHT / 2f, + Origin = Anchor.TopCentre, + RelativePositionAxes = Axes.X, + Current = { Value = true } + }, + }, + hoverClickSounds = new HoverClickSounds() + }; + } + + [BackgroundDependencyLoader(true)] + private void load(OverlayColourProvider? colourProvider, OsuColour colours) + { + AccentColour = colourProvider?.Highlight1 ?? colours.Pink; + BackgroundColour = colourProvider?.Background5 ?? colours.PinkDarker.Darken(1); + } + + protected override void Update() + { + base.Update(); + + nubContainer.Padding = new MarginPadding { Horizontal = RangePadding }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindDisabledChanged(disabled => + { + Alpha = disabled ? 0.3f : 1; + hoverClickSounds.Enabled.Value = !disabled; + }, true); + } + + protected override bool OnHover(HoverEvent e) + { + updateGlow(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateGlow(); + base.OnHoverLost(e); + } + + protected override bool ShouldHandleAsRelativeDrag(MouseDownEvent e) + => Nub.ReceivePositionalInputAt(e.ScreenSpaceMouseDownPosition); + + protected override void OnDragEnd(DragEndEvent e) + { + updateGlow(); + base.OnDragEnd(e); + } + + private void updateGlow() + { + Nub.Glowing = !Current.Disabled && (IsHovered || IsDragged); + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + LeftBox.Scale = new Vector2(Math.Clamp(RangePadding + Nub.DrawPosition.X - Nub.DrawWidth / 2.1f, 0, Math.Max(0, DrawWidth)), 1); + RightBox.Scale = new Vector2(Math.Clamp(DrawWidth - Nub.DrawPosition.X - RangePadding - Nub.DrawWidth / 2.1f, 0, Math.Max(0, DrawWidth)), 1); + } + + protected override void UpdateValue(float value) + { + Nub.MoveToX(value, 250, Easing.OutQuint); + } + } +} From 88406946748daa7f64cb815f6679c58952a6ca43 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 15:00:48 +0100 Subject: [PATCH 090/516] Adjust some padding details on ShearedSliderBar.cs as well as colouration tweaks. --- osu.Game/Graphics/UserInterface/ShearedSliderBar.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ShearedSliderBar.cs b/osu.Game/Graphics/UserInterface/ShearedSliderBar.cs index 08d5fd8992..a18a6a259c 100644 --- a/osu.Game/Graphics/UserInterface/ShearedSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/ShearedSliderBar.cs @@ -33,7 +33,10 @@ namespace osu.Game.Graphics.UserInterface set { accentColour = value; - LeftBox.Colour = value; + + // We want to slightly darken the colour for the box because the sheared slider has the boxes at the same height as the nub, + // making the nub invisible when not hovered. + LeftBox.Colour = value.Darken(0.1f); } } @@ -158,8 +161,8 @@ namespace osu.Game.Graphics.UserInterface protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); - LeftBox.Scale = new Vector2(Math.Clamp(RangePadding + Nub.DrawPosition.X - Nub.DrawWidth / 2.1f, 0, Math.Max(0, DrawWidth)), 1); - RightBox.Scale = new Vector2(Math.Clamp(DrawWidth - Nub.DrawPosition.X - RangePadding - Nub.DrawWidth / 2.1f, 0, Math.Max(0, DrawWidth)), 1); + LeftBox.Scale = new Vector2(Math.Clamp(RangePadding + Nub.DrawPosition.X - Nub.DrawWidth / 2.15f, 0, Math.Max(0, DrawWidth)), 1); + RightBox.Scale = new Vector2(Math.Clamp(DrawWidth - Nub.DrawPosition.X - RangePadding - Nub.DrawWidth / 2.15f, 0, Math.Max(0, DrawWidth)), 1); } protected override void UpdateValue(float value) From a630f1113ff51fa615cd1048e8e2f5b3436364e1 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 15:01:27 +0100 Subject: [PATCH 091/516] Rename nub object in NormalSliderBar.cs class --- .../Graphics/UserInterface/NormalSliderBar.cs | 14 +++++++------- osu.Game/Graphics/UserInterface/RangeSlider.cs | 16 ++++++++-------- .../Play/PlayerSettings/PlayerSliderBar.cs | 6 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs index bc27c9af4c..3a3603e1de 100644 --- a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface public partial class NormalSliderBar : OsuSliderBar where T : struct, IEquatable, IComparable, IConvertible { - protected readonly NormalNub NormalNub; + protected readonly NormalNub Nub; protected readonly Box LeftBox; protected readonly Box RightBox; private readonly Container nubContainer; @@ -93,7 +93,7 @@ namespace osu.Game.Graphics.UserInterface nubContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = NormalNub = new NormalNub + Child = Nub = new NormalNub { Origin = Anchor.TopCentre, RelativePositionAxes = Axes.X, @@ -142,7 +142,7 @@ namespace osu.Game.Graphics.UserInterface } protected override bool ShouldHandleAsRelativeDrag(MouseDownEvent e) - => NormalNub.ReceivePositionalInputAt(e.ScreenSpaceMouseDownPosition); + => Nub.ReceivePositionalInputAt(e.ScreenSpaceMouseDownPosition); protected override void OnDragEnd(DragEndEvent e) { @@ -152,19 +152,19 @@ namespace osu.Game.Graphics.UserInterface private void updateGlow() { - NormalNub.Glowing = !Current.Disabled && (IsHovered || IsDragged); + Nub.Glowing = !Current.Disabled && (IsHovered || IsDragged); } protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); - LeftBox.Scale = new Vector2(Math.Clamp(RangePadding + NormalNub.DrawPosition.X - NormalNub.DrawWidth / 2, 0, Math.Max(0, DrawWidth)), 1); - RightBox.Scale = new Vector2(Math.Clamp(DrawWidth - NormalNub.DrawPosition.X - RangePadding - NormalNub.DrawWidth / 2, 0, Math.Max(0, DrawWidth)), 1); + LeftBox.Scale = new Vector2(Math.Clamp(RangePadding + Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, Math.Max(0, DrawWidth)), 1); + RightBox.Scale = new Vector2(Math.Clamp(DrawWidth - Nub.DrawPosition.X - RangePadding - Nub.DrawWidth / 2, 0, Math.Max(0, DrawWidth)), 1); } protected override void UpdateValue(float value) { - NormalNub.MoveToX(value, 250, Easing.OutQuint); + Nub.MoveToX(value, 250, Easing.OutQuint); } } } diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs index 963c859198..806209d548 100644 --- a/osu.Game/Graphics/UserInterface/RangeSlider.cs +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -141,7 +141,7 @@ namespace osu.Game.Graphics.UserInterface public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) - && screenSpacePos.X <= NormalNub.ScreenSpaceDrawQuad.TopRight.X; + && screenSpacePos.X <= Nub.ScreenSpaceDrawQuad.TopRight.X; } private partial class UpperBoundSlider : BoundSlider @@ -155,7 +155,7 @@ namespace osu.Game.Graphics.UserInterface public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) - && screenSpacePos.X >= NormalNub.ScreenSpaceDrawQuad.TopLeft.X; + && screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X; } protected partial class BoundSlider : NormalSliderBar @@ -177,12 +177,12 @@ namespace osu.Game.Graphics.UserInterface protected override void LoadComplete() { base.LoadComplete(); - NormalNub.Width = NubWidth; - RangePadding = NormalNub.Width / 2; + Nub.Width = NubWidth; + RangePadding = Nub.Width / 2; OsuSpriteText currentDisplay; - NormalNub.Add(currentDisplay = new OsuSpriteText + Nub.Add(currentDisplay = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -203,9 +203,9 @@ namespace osu.Game.Graphics.UserInterface if (colourProvider == null) return; AccentColour = colourProvider.Background2; - NormalNub.AccentColour = colourProvider.Background2; - NormalNub.GlowingAccentColour = colourProvider.Background1; - NormalNub.GlowColour = colourProvider.Background2; + Nub.AccentColour = colourProvider.Background2; + Nub.GlowingAccentColour = colourProvider.Background1; + Nub.GlowColour = colourProvider.Background2; } } } diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs index b54207886e..985a414bc0 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs @@ -30,9 +30,9 @@ namespace osu.Game.Screens.Play.PlayerSettings private void load(OsuColour colours) { AccentColour = colours.Yellow; - NormalNub.AccentColour = colours.Yellow; - NormalNub.GlowingAccentColour = colours.YellowLighter; - NormalNub.GlowColour = colours.YellowDark; + Nub.AccentColour = colours.Yellow; + Nub.GlowingAccentColour = colours.YellowLighter; + Nub.GlowColour = colours.YellowDark; } } } From 1de0bed83d0b8889900ef3b1ebcac52f178ef4a7 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Thu, 26 Jan 2023 11:09:16 -0300 Subject: [PATCH 092/516] fix comment --- osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index 4feb25e60b..ce1b0db76d 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -52,8 +52,8 @@ namespace osu.Game.Overlays.Profile.Header.Components new Box { RelativeSizeAxes = Axes.Both, - // Normal background color is 0.75 opacity, probationary doesn't have this cause they are a bit transparent already Colour = colourProvider?.Background6 ?? Colour4.Black, + // Normal badges background opacity is 75%, probationary is full opacity as the whole badge gets a bit transparent Alpha = group.IsProbationary ? 1 : 0.75f, }, innerContainer = new FillFlowContainer From 76146b5c5372d2146aa557e09aabe882e1646209 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 15:12:52 +0100 Subject: [PATCH 093/516] Address naming discrepancy in TestSceneShearedSliderBar.cs --- .../Visual/UserInterface/TestSceneShearedSliderBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSliderBar.cs index c2d0de95e0..766f22d867 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSliderBar.cs @@ -9,7 +9,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { - public partial class TestSceneShearedSlider : OsuTestScene + public partial class TestSceneShearedSliderBar : OsuTestScene { [Cached] private OverlayColourProvider colourProvider { get; set; } = new OverlayColourProvider(OverlayColourScheme.Purple); From 091cc155d33ba19b4f99f7c2243c683773f38065 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 16:10:02 +0100 Subject: [PATCH 094/516] Fix nub naming in OsuCheckbox.cs and associated classes --- .../Graphics/UserInterface/OsuCheckbox.cs | 24 +++++++++---------- .../OsuDirectorySelectorHiddenToggle.cs | 6 ++--- osu.Game/Overlays/Mods/ModColumn.cs | 6 ++--- .../Play/PlayerSettings/PlayerCheckbox.cs | 6 ++--- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs index 982706f87b..877493dd5c 100644 --- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs @@ -41,7 +41,7 @@ namespace osu.Game.Graphics.UserInterface } } - protected readonly NormalNub NormalNub; + protected readonly NormalNub Nub; protected readonly OsuTextFlowContainer LabelTextFlowContainer; private Sample sampleChecked; @@ -61,28 +61,28 @@ namespace osu.Game.Graphics.UserInterface AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, }, - NormalNub = new NormalNub(), + Nub = new NormalNub(), new HoverSounds() }; if (nubOnRight) { - NormalNub.Anchor = Anchor.CentreRight; - NormalNub.Origin = Anchor.CentreRight; - NormalNub.Margin = new MarginPadding { Right = nub_padding }; + Nub.Anchor = Anchor.CentreRight; + Nub.Origin = Anchor.CentreRight; + Nub.Margin = new MarginPadding { Right = nub_padding }; LabelTextFlowContainer.Padding = new MarginPadding { Right = NormalNub.EXPANDED_SIZE + nub_padding * 2 }; } else { - NormalNub.Anchor = Anchor.CentreLeft; - NormalNub.Origin = Anchor.CentreLeft; - NormalNub.Margin = new MarginPadding { Left = nub_padding }; + Nub.Anchor = Anchor.CentreLeft; + Nub.Origin = Anchor.CentreLeft; + Nub.Margin = new MarginPadding { Left = nub_padding }; LabelTextFlowContainer.Padding = new MarginPadding { Left = NormalNub.EXPANDED_SIZE + nub_padding * 2 }; } - NormalNub.Current.BindTo(Current); + Nub.Current.BindTo(Current); - Current.DisabledChanged += disabled => LabelTextFlowContainer.Alpha = NormalNub.Alpha = disabled ? 0.3f : 1; + Current.DisabledChanged += disabled => LabelTextFlowContainer.Alpha = Nub.Alpha = disabled ? 0.3f : 1; } /// @@ -101,13 +101,13 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(HoverEvent e) { - NormalNub.Glowing = true; + Nub.Glowing = true; return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - NormalNub.Glowing = false; + Nub.Glowing = false; base.OnHoverLost(e); } diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs index 79f72495c8..7665ed507f 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs @@ -30,9 +30,9 @@ namespace osu.Game.Graphics.UserInterfaceV2 if (overlayColourProvider != null) return; - NormalNub.AccentColour = colours.GreySeaFoamLighter; - NormalNub.GlowingAccentColour = Color4.White; - NormalNub.GlowColour = Color4.White; + Nub.AccentColour = colours.GreySeaFoamLighter; + Nub.GlowingAccentColour = Color4.White; + Nub.GlowColour = Color4.White; } } } diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index 97a766259a..5d9f616e5f 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -267,9 +267,9 @@ namespace osu.Game.Overlays.Mods private void updateState() { - NormalNub.AccentColour = AccentColour; - NormalNub.GlowingAccentColour = AccentHoverColour; - NormalNub.GlowColour = AccentHoverColour.Opacity(0.2f); + Nub.AccentColour = AccentColour; + Nub.GlowingAccentColour = AccentHoverColour; + Nub.GlowColour = AccentHoverColour.Opacity(0.2f); } protected override void OnUserChange(bool value) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs index 960904282d..49c9cbf385 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs @@ -18,9 +18,9 @@ namespace osu.Game.Screens.Play.PlayerSettings [BackgroundDependencyLoader] private void load(OsuColour colours) { - NormalNub.AccentColour = colours.Yellow; - NormalNub.GlowingAccentColour = colours.YellowLighter; - NormalNub.GlowColour = colours.YellowDark; + Nub.AccentColour = colours.Yellow; + Nub.GlowingAccentColour = colours.YellowLighter; + Nub.GlowColour = colours.YellowDark; } } } From 27578c48f5fd43a42cde43acb290c10dac9c3fe4 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 27 Jan 2023 19:35:44 +0900 Subject: [PATCH 095/516] Remove JudgementResultEntry It is not needed anymore as TimeAbsolute is stored raw. --- .../Judgements/JudgementResultEntry.cs | 22 ------------------- osu.Game/Rulesets/UI/Playfield.cs | 18 ++++++++------- 2 files changed, 10 insertions(+), 30 deletions(-) delete mode 100644 osu.Game/Rulesets/Judgements/JudgementResultEntry.cs diff --git a/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs b/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs deleted file mode 100644 index 09351e6974..0000000000 --- a/osu.Game/Rulesets/Judgements/JudgementResultEntry.cs +++ /dev/null @@ -1,22 +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.Game.Rulesets.Objects; - -namespace osu.Game.Rulesets.Judgements -{ - internal class JudgementResultEntry - { - public double Time => Result.TimeAbsolute; - - public readonly HitObjectLifetimeEntry HitObjectEntry; - - public readonly JudgementResult Result; - - public JudgementResultEntry(HitObjectLifetimeEntry hitObjectEntry, JudgementResult result) - { - HitObjectEntry = hitObjectEntry; - Result = result; - } - } -} \ No newline at end of file diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 3ec31db4b9..5d6a8de33c 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.UI private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager(); - private readonly Stack judgementResults; + private readonly Stack judgedEntries; /// /// Creates a new . @@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.UI entryManager.OnEntryAdded += onEntryAdded; entryManager.OnEntryRemoved += onEntryRemoved; - judgementResults = new Stack(); + judgedEntries = new Stack(); } [BackgroundDependencyLoader] @@ -258,8 +258,8 @@ namespace osu.Game.Rulesets.UI } // When rewinding, revert future judgements in the reverse order. - while (judgementResults.Count > 0 && Time.Current < judgementResults.Peek().Time) - revertResult(judgementResults.Pop()); + while (judgedEntries.Count > 0 && Time.Current < judgedEntries.Peek().Result.AsNonNull().TimeAbsolute) + revertResult(judgedEntries.Pop()); } /// @@ -453,17 +453,19 @@ namespace osu.Game.Rulesets.UI private void onNewResult(DrawableHitObject drawable, JudgementResult result) { - // Not using result.TimeAbsolute because that might change and also there is a potential precision issue. - judgementResults.Push(new JudgementResultEntry(drawable.Entry.AsNonNull(), result)); + Debug.Assert(result != null && drawable.Entry?.Result == result); + judgedEntries.Push(drawable.Entry.AsNonNull()); NewResult?.Invoke(drawable, result); } - private void revertResult(JudgementResultEntry entry) + private void revertResult(HitObjectLifetimeEntry entry) { var result = entry.Result; + Debug.Assert(result != null); + RevertResult?.Invoke(result); - entry.HitObjectEntry.OnRevertResult(); + entry.OnRevertResult(); result.Reset(); } From 41f5e5143af134be4a018f0830c68a90c479c2fa Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 30 Jan 2023 12:56:39 +0100 Subject: [PATCH 096/516] 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 097/516] 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 8645e705fd73e2dde122c4905fb0a78d06f6a336 Mon Sep 17 00:00:00 2001 From: tsrk Date: Wed, 1 Feb 2023 23:44:00 +0000 Subject: [PATCH 098/516] feat: add localisation for Skin editor components --- .../BarHitErrorMeterStrings.cs | 89 +++++++++++++++++++ .../BeatmapAttributeTextStrings.cs | 34 +++++++ .../ColourHitErrorMeterStrings.cs | 54 +++++++++++ .../FontAdjustableSkinComponentStrings.cs | 24 +++++ .../GameplayAccuracyCounterStrings.cs | 39 ++++++++ .../JudgementCounterDisplayStrings.cs | 50 +++++++++++ .../SkinnableSpriteStrings.cs | 24 +++++ .../SongProgressStrings.cs | 24 +++++ .../TextElementStrings.cs | 24 +++++ osu.Game/Localisation/SkinEditorStrings.cs | 5 ++ .../Screens/Play/HUD/ArgonSongProgress.cs | 3 +- .../Screens/Play/HUD/DefaultSongProgress.cs | 3 +- .../Play/HUD/GameplayAccuracyCounter.cs | 11 +-- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 22 +++-- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 11 ++- .../JudgementCounterDisplay.cs | 15 +++- .../Components/BeatmapAttributeText.cs | 5 +- osu.Game/Skinning/Components/TextElement.cs | 3 +- osu.Game/Skinning/Editor/SkinEditor.cs | 4 +- .../Skinning/FontAdjustableSkinComponent.cs | 3 +- osu.Game/Skinning/SkinnableSprite.cs | 3 +- 21 files changed, 424 insertions(+), 26 deletions(-) create mode 100644 osu.Game/Localisation/SkinEditorComponents/BarHitErrorMeterStrings.cs create mode 100644 osu.Game/Localisation/SkinEditorComponents/BeatmapAttributeTextStrings.cs create mode 100644 osu.Game/Localisation/SkinEditorComponents/ColourHitErrorMeterStrings.cs create mode 100644 osu.Game/Localisation/SkinEditorComponents/FontAdjustableSkinComponentStrings.cs create mode 100644 osu.Game/Localisation/SkinEditorComponents/GameplayAccuracyCounterStrings.cs create mode 100644 osu.Game/Localisation/SkinEditorComponents/JudgementCounterDisplayStrings.cs create mode 100644 osu.Game/Localisation/SkinEditorComponents/SkinnableSpriteStrings.cs create mode 100644 osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs create mode 100644 osu.Game/Localisation/SkinEditorComponents/TextElementStrings.cs diff --git a/osu.Game/Localisation/SkinEditorComponents/BarHitErrorMeterStrings.cs b/osu.Game/Localisation/SkinEditorComponents/BarHitErrorMeterStrings.cs new file mode 100644 index 0000000000..ea372a5207 --- /dev/null +++ b/osu.Game/Localisation/SkinEditorComponents/BarHitErrorMeterStrings.cs @@ -0,0 +1,89 @@ +// 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.Localisation; + +namespace osu.Game.Localisation.SkinEditorComponents +{ + public static class BarHitErrorMeterStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.BarHitErrorMeter"; + + /// + /// "Judgement line thickness" + /// + public static LocalisableString JudgementLineThickness => new TranslatableString(getKey(@"judgement_line_thickness"), "Judgement line thickness"); + + /// + /// "How thick the individual lines should be." + /// + public static LocalisableString JudgementLineThicknessDescription => new TranslatableString(getKey(@"judgement_line_thickness_description"), "How thick the individual lines should be."); + + /// + /// "Show colour bars" + /// + public static LocalisableString ColourBarVisibility => new TranslatableString(getKey(@"colour_bar_visibility"), "Show colour bars"); + + /// + /// "Show moving average arrow" + /// + public static LocalisableString ShowMovingAverage => new TranslatableString(getKey(@"show_moving_average"), "Show moving average arrow"); + + /// + /// "Whether an arrow should move beneath the bar showing the average error." + /// + public static LocalisableString ShowMovingAverageDescription => new TranslatableString(getKey(@"show_moving_average_description"), "Whether an arrow should move beneath the bar showing the average error."); + + /// + /// "Centre marker style" + /// + public static LocalisableString CentreMarkerStyle => new TranslatableString(getKey(@"centre_marker_style"), "Centre marker style"); + + /// + /// "How to signify the centre of the display" + /// + public static LocalisableString CentreMarkerStyleDescription => new TranslatableString(getKey(@"centre_marker_style_description"), "How to signify the centre of the display"); + + /// + /// "None" + /// + public static LocalisableString CentreMarkerStylesNone => new TranslatableString(getKey(@"centre_marker_styles_none"), "None"); + + /// + /// "Circle" + /// + public static LocalisableString CentreMarkerStylesCircle => new TranslatableString(getKey(@"centre_marker_styles_circle"), "Circle"); + + /// + /// "Line" + /// + public static LocalisableString CentreMarkerStylesLine => new TranslatableString(getKey(@"centre_marker_styles_line"), "Line"); + + /// + /// "Label style" + /// + public static LocalisableString LabelStyle => new TranslatableString(getKey(@"label_style"), "Label style"); + + /// + /// "How to show early/late extremities" + /// + public static LocalisableString LabelStyleDescription => new TranslatableString(getKey(@"label_style_description"), "How to show early/late extremities"); + + /// + /// "None" + /// + public static LocalisableString LabelStylesNone => new TranslatableString(getKey(@"label_styles_none"), "None"); + + /// + /// "Icons" + /// + public static LocalisableString LabelStylesIcons => new TranslatableString(getKey(@"label_styles_icons"), "Icons"); + + /// + /// "Text" + /// + public static LocalisableString LabelStylesText => new TranslatableString(getKey(@"label_styles_text"), "Text"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/SkinEditorComponents/BeatmapAttributeTextStrings.cs b/osu.Game/Localisation/SkinEditorComponents/BeatmapAttributeTextStrings.cs new file mode 100644 index 0000000000..faafa7e304 --- /dev/null +++ b/osu.Game/Localisation/SkinEditorComponents/BeatmapAttributeTextStrings.cs @@ -0,0 +1,34 @@ +// 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.Localisation; + +namespace osu.Game.Localisation.SkinEditorComponents +{ + public static class BeatmapAttributeTextStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.BeatmapAttributeText"; + + /// + /// "Attribute" + /// + public static LocalisableString Attribute => new TranslatableString(getKey(@"attribute"), "Attribute"); + + /// + /// "The attribute to be displayed." + /// + public static LocalisableString AttributeDescription => new TranslatableString(getKey(@"attribute_description"), "The attribute to be displayed."); + + /// + /// "Template" + /// + public static LocalisableString Template => new TranslatableString(getKey(@"template"), "Template"); + + /// + /// "Supports {{Label}} and {{Value}}, but also including arbitrary attributes like {{StarRating}} (see attribute list for supported values)." + /// + public static LocalisableString TemplateDescription => new TranslatableString(getKey(@"template_description"), @"Supports {{Label}} and {{Value}}, but also including arbitrary attributes like {{StarRating}} (see attribute list for supported values)."); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/SkinEditorComponents/ColourHitErrorMeterStrings.cs b/osu.Game/Localisation/SkinEditorComponents/ColourHitErrorMeterStrings.cs new file mode 100644 index 0000000000..fec5781c3d --- /dev/null +++ b/osu.Game/Localisation/SkinEditorComponents/ColourHitErrorMeterStrings.cs @@ -0,0 +1,54 @@ +// 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.Localisation; + +namespace osu.Game.Localisation.SkinEditorComponents +{ + public static class ColourHitErrorMeterStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.ColourHitError"; + + /// + /// "Judgement count" + /// + public static LocalisableString JudgementCount => new TranslatableString(getKey(@"judgement_count"), "Judgement count"); + + /// + /// "The number of displayed judgements" + /// + public static LocalisableString JudgementCountDescription => new TranslatableString(getKey(@"judgement_count_description"), "The number of displayed judgements"); + + /// + /// "Judgement spacing" + /// + public static LocalisableString JudgementSpacing => new TranslatableString(getKey(@"judgement_spacing"), "Judgement spacing"); + + /// + /// "The space between each displayed judgement" + /// + public static LocalisableString JudgementSpacingDescription => new TranslatableString(getKey(@"judgement_spacing_description"), "The space between each displayed judgement"); + + /// + /// "Judgement shape" + /// + public static LocalisableString JudgementShape => new TranslatableString(getKey(@"judgement_shape"), "Judgement shape"); + + /// + /// "The shape of each displayed judgement" + /// + public static LocalisableString JudgementShapeDescription => new TranslatableString(getKey(@"judgement_shape_description"), "The shape of each displayed judgement"); + + /// + /// "Circle" + /// + public static LocalisableString ShapeStyleCircle => new TranslatableString(getKey(@"shape_style_cricle"), "Circle"); + + /// + /// "Square" + /// + public static LocalisableString ShapeStyleSquare => new TranslatableString(getKey(@"shape_style_square"), "Square"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/SkinEditorComponents/FontAdjustableSkinComponentStrings.cs b/osu.Game/Localisation/SkinEditorComponents/FontAdjustableSkinComponentStrings.cs new file mode 100644 index 0000000000..9b92854faa --- /dev/null +++ b/osu.Game/Localisation/SkinEditorComponents/FontAdjustableSkinComponentStrings.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.Localisation; + +namespace osu.Game.Localisation.SkinEditorComponents +{ + public static class FontAdjustableSkinComponentStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.FontAdjustableSkinComponent"; + + /// + /// "Font" + /// + public static LocalisableString Font => new TranslatableString(getKey(@"font"), "Font"); + + /// + /// "The font to use." + /// + public static LocalisableString FontDescription => new TranslatableString(getKey(@"font_description"), "The font to use."); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/SkinEditorComponents/GameplayAccuracyCounterStrings.cs b/osu.Game/Localisation/SkinEditorComponents/GameplayAccuracyCounterStrings.cs new file mode 100644 index 0000000000..33a742a95e --- /dev/null +++ b/osu.Game/Localisation/SkinEditorComponents/GameplayAccuracyCounterStrings.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.Localisation; + +namespace osu.Game.Localisation.SkinEditorComponents +{ + public static class GameplayAccuracyCounterStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.GameplayAccuracyCounter"; + + /// + /// "Accuracy display mode" + /// + public static LocalisableString AccuracyDisplay => new TranslatableString(getKey(@"accuracy_display"), "Accuracy display mode"); + + /// + /// "Which accuracy mode should be displayed." + /// + public static LocalisableString AccuracyDisplayDescription => new TranslatableString(getKey(@"accuracy_display_description"), "Which accuracy mode should be displayed."); + + /// + /// "Standard" + /// + public static LocalisableString AccuracyDisplayModeStandard => new TranslatableString(getKey(@"accuracy_display_mode_standard"), "Standard"); + + /// + /// "Maximum achievable" + /// + public static LocalisableString AccuracyDisplayModeMax => new TranslatableString(getKey(@"accuracy_display_mode_max"), "Maximum achievable"); + + /// + /// "Minimum achievable" + /// + public static LocalisableString AccuracyDisplayModeMin => new TranslatableString(getKey(@"accuracy_display_mode_min"), "Minimum achievable"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/SkinEditorComponents/JudgementCounterDisplayStrings.cs b/osu.Game/Localisation/SkinEditorComponents/JudgementCounterDisplayStrings.cs new file mode 100644 index 0000000000..75f0241e56 --- /dev/null +++ b/osu.Game/Localisation/SkinEditorComponents/JudgementCounterDisplayStrings.cs @@ -0,0 +1,50 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation.SkinEditorComponents +{ + public static class JudgementCounterDisplayStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.JudgementCounterDisplay"; + + /// + /// "Display mode" + /// + public static LocalisableString JudgementDisplayMode => new TranslatableString(getKey(@"judgement_display_mode"), "Display mode"); + + /// + /// "Counter direction" + /// + public static LocalisableString FlowDirection => new TranslatableString(getKey(@"flow_direction"), "Counter direction"); + + /// + /// "Show judgement names" + /// + public static LocalisableString ShowJudgementNames => new TranslatableString(getKey(@"show_judgement_names"), "Show judgement names"); + + /// + /// "Show max judgement" + /// + public static LocalisableString ShowMaxJudgement => new TranslatableString(getKey(@"show_max_judgement"), "Show max judgement"); + + /// + /// "Simple" + /// + public static LocalisableString JudgementDisplayModeSimple => new TranslatableString(getKey(@"judgement_display_mode_simple"), "Simple"); + + /// + /// "Normal" + /// + public static LocalisableString JudgementDisplayModeNormal => new TranslatableString(getKey(@"judgement_display_mode_normal"), "Normal"); + + /// + /// "All" + /// + public static LocalisableString JudgementDisplayModeAll => new TranslatableString(getKey(@"judgement_display_mode_all"), "All"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} + diff --git a/osu.Game/Localisation/SkinEditorComponents/SkinnableSpriteStrings.cs b/osu.Game/Localisation/SkinEditorComponents/SkinnableSpriteStrings.cs new file mode 100644 index 0000000000..f67acb493c --- /dev/null +++ b/osu.Game/Localisation/SkinEditorComponents/SkinnableSpriteStrings.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.Localisation; + +namespace osu.Game.Localisation.SkinEditorComponents +{ + public static class SkinnableSpriteStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.SkinnableSprite"; + + /// + /// "Sprite name" + /// + public static LocalisableString SpriteName => new TranslatableString(getKey(@"sprite_name"), "Sprite name"); + + /// + /// "The filename of the sprite" + /// + public static LocalisableString SpriteNameDescription => new TranslatableString(getKey(@"sprite_name_description"), "The filename of the sprite"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs b/osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs new file mode 100644 index 0000000000..9719cdef52 --- /dev/null +++ b/osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.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.Localisation; + +namespace osu.Game.Localisation.SkinEditorComponents +{ + public static class SongProgressStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.SongProgressStrings"; + + /// + /// "Show difficulty graph" + /// + public static LocalisableString ShowGraph => new TranslatableString(getKey(@"show_graph"), "Show difficulty graph"); + + /// + /// "Whether a graph displaying difficulty throughout the beatmap should be shown" + /// + public static LocalisableString ShowGraphDescription => new TranslatableString(getKey(@"show_graph_description"), "Whether a graph displaying difficulty throughout the beatmap should be shown"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/SkinEditorComponents/TextElementStrings.cs b/osu.Game/Localisation/SkinEditorComponents/TextElementStrings.cs new file mode 100644 index 0000000000..e969da60bf --- /dev/null +++ b/osu.Game/Localisation/SkinEditorComponents/TextElementStrings.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.Localisation; + +namespace osu.Game.Localisation.SkinEditorComponents +{ + public static class TextElementStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.TextElement"; + + /// + /// "Text" + /// + public static LocalisableString TextElementText => new TranslatableString(getKey(@"text_element_text"), "Text"); + + /// + /// "The text to be displayed." + /// + public static LocalisableString TextElementTextDescription => new TranslatableString(getKey(@"text_element_text_description"), "The text to be displayed."); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/SkinEditorStrings.cs b/osu.Game/Localisation/SkinEditorStrings.cs index b2e5f3aeb6..d9744cf6c8 100644 --- a/osu.Game/Localisation/SkinEditorStrings.cs +++ b/osu.Game/Localisation/SkinEditorStrings.cs @@ -39,6 +39,11 @@ namespace osu.Game.Localisation /// public static LocalisableString Settings(string arg0) => new TranslatableString(getKey(@"settings"), @"Settings ({0})", arg0); + /// + /// "Curently editing" + /// + public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), "Curently editing"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index bfee6d295e..075e5af163 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; using osu.Game.Graphics; +using osu.Game.Localisation.SkinEditorComponents; using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HUD @@ -21,7 +22,7 @@ namespace osu.Game.Screens.Play.HUD private const float bar_height = 10; - [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] + [SettingSource(typeof(SongProgressStrings), nameof(SongProgressStrings.ShowGraph), nameof(SongProgressStrings.ShowGraphDescription))] public Bindable ShowGraph { get; } = new BindableBool(true); [Resolved] diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 91a34fe374..1c051c24ae 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -7,6 +7,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Configuration; using osu.Game.Graphics; +using osu.Game.Localisation.SkinEditorComponents; using osu.Game.Rulesets.Objects; using osuTK; @@ -26,7 +27,7 @@ namespace osu.Game.Screens.Play.HUD private readonly DefaultSongProgressGraph graph; private readonly SongProgressInfo info; - [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] + [SettingSource(typeof(SongProgressStrings), nameof(SongProgressStrings.ShowGraph), nameof(SongProgressStrings.ShowGraphDescription))] public Bindable ShowGraph { get; } = new BindableBool(true); [Resolved] diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index ca7fef8f73..d044b3d98a 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -1,18 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation.SkinEditorComponents; using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD { public abstract partial class GameplayAccuracyCounter : PercentageCounter { - [SettingSource("Accuracy display mode", "Which accuracy mode should be displayed.")] + [SettingSource(typeof(GameplayAccuracyCounterStrings), nameof(GameplayAccuracyCounterStrings.AccuracyDisplay), nameof(GameplayAccuracyCounterStrings.AccuracyDisplayDescription))] public Bindable AccuracyDisplay { get; } = new Bindable(); [Resolved] @@ -51,13 +52,13 @@ namespace osu.Game.Screens.Play.HUD public enum AccuracyDisplayMode { - [Description("Standard")] + [LocalisableDescription(typeof(GameplayAccuracyCounterStrings), nameof(GameplayAccuracyCounterStrings.AccuracyDisplayModeStandard))] Standard, - [Description("Maximum achievable")] + [LocalisableDescription(typeof(GameplayAccuracyCounterStrings), nameof(GameplayAccuracyCounterStrings.AccuracyDisplayModeMax))] MaximumAchievable, - [Description("Minimum achievable")] + [LocalisableDescription(typeof(GameplayAccuracyCounterStrings), nameof(GameplayAccuracyCounterStrings.AccuracyDisplayModeMin))] MinimumAchievable } } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 0337f66bd9..5d0efe7b77 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -12,10 +12,12 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation.SkinEditorComponents; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; @@ -25,7 +27,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [Cached] public partial class BarHitErrorMeter : HitErrorMeter { - [SettingSource("Judgement line thickness", "How thick the individual lines should be.")] + [SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.JudgementLineThickness), nameof(BarHitErrorMeterStrings.JudgementLineThicknessDescription))] public BindableNumber JudgementLineThickness { get; } = new BindableNumber(4) { MinValue = 1, @@ -33,16 +35,16 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Precision = 0.1f, }; - [SettingSource("Show colour bars")] + [SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.ColourBarVisibility))] public Bindable ColourBarVisibility { get; } = new Bindable(true); - [SettingSource("Show moving average arrow", "Whether an arrow should move beneath the bar showing the average error.")] + [SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.ShowMovingAverage), nameof(BarHitErrorMeterStrings.ShowMovingAverageDescription))] public Bindable ShowMovingAverage { get; } = new BindableBool(true); - [SettingSource("Centre marker style", "How to signify the centre of the display")] + [SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.CentreMarkerStyle), nameof(BarHitErrorMeterStrings.CentreMarkerStyleDescription))] public Bindable CentreMarkerStyle { get; } = new Bindable(CentreMarkerStyles.Circle); - [SettingSource("Label style", "How to show early/late extremities")] + [SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStyle), nameof(BarHitErrorMeterStrings.LabelStyleDescription))] public Bindable LabelStyle { get; } = new Bindable(LabelStyles.Icons); private const int judgement_line_width = 14; @@ -487,15 +489,25 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public enum CentreMarkerStyles { + [LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.CentreMarkerStylesNone))] None, + + [LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.CentreMarkerStylesCircle))] Circle, + + [LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.CentreMarkerStylesLine))] Line } public enum LabelStyles { + [LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStylesNone))] None, + + [LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStylesIcons))] Icons, + + [LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStylesIcons))] Text } } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index ec5dc5f52f..28e2006c2f 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -9,7 +9,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation.SkinEditorComponents; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; @@ -23,21 +25,21 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private const int animation_duration = 200; private const int drawable_judgement_size = 8; - [SettingSource("Judgement count", "The number of displayed judgements")] + [SettingSource(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.JudgementCount), nameof(ColourHitErrorMeterStrings.JudgementCountDescription))] public BindableNumber JudgementCount { get; } = new BindableNumber(20) { MinValue = 1, MaxValue = 50, }; - [SettingSource("Judgement spacing", "The space between each displayed judgement")] + [SettingSource(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.JudgementSpacing), nameof(ColourHitErrorMeterStrings.JudgementSpacingDescription))] public BindableNumber JudgementSpacing { get; } = new BindableNumber(2) { MinValue = 0, MaxValue = 10, }; - [SettingSource("Judgement shape", "The shape of each displayed judgement")] + [SettingSource(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.JudgementShape), nameof(ColourHitErrorMeterStrings.JudgementShapeDescription))] public Bindable JudgementShape { get; } = new Bindable(); private readonly JudgementFlow judgementsFlow; @@ -192,7 +194,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public enum ShapeStyle { + [LocalisableDescription(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.ShapeStyleCircle))] Circle, + + [LocalisableDescription(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.ShapeStyleSquare))] Square } } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 82f24c736e..d047b8e5fb 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -6,7 +6,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation.SkinEditorComponents; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; using osuTK; @@ -19,16 +21,16 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter public bool UsesFixedAnchor { get; set; } - [SettingSource("Display mode")] + [SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayMode))] public Bindable Mode { get; set; } = new Bindable(); - [SettingSource("Counter direction")] + [SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.FlowDirection))] public Bindable FlowDirection { get; set; } = new Bindable(); - [SettingSource("Show judgement names")] + [SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.ShowJudgementNames))] public BindableBool ShowJudgementNames { get; set; } = new BindableBool(true); - [SettingSource("Show max judgement")] + [SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.ShowMaxJudgement))] public BindableBool ShowMaxJudgement { get; set; } = new BindableBool(true); [Resolved] @@ -130,8 +132,13 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter public enum DisplayMode { + [LocalisableDescription(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayModeSimple))] Simple, + + [LocalisableDescription(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayModeNormal))] Normal, + + [LocalisableDescription(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayModeAll))] All } } diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index 68bb1e7ddc..d2e724f760 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -18,6 +18,7 @@ using osu.Game.Configuration; using osu.Game.Extensions; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; +using osu.Game.Localisation.SkinEditorComponents; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Skinning.Components @@ -25,10 +26,10 @@ namespace osu.Game.Skinning.Components [UsedImplicitly] public partial class BeatmapAttributeText : FontAdjustableSkinComponent { - [SettingSource("Attribute", "The attribute to be displayed.")] + [SettingSource(typeof(BeatmapAttributeTextStrings), nameof(BeatmapAttributeTextStrings.Attribute), nameof(BeatmapAttributeTextStrings.AttributeDescription))] public Bindable Attribute { get; } = new Bindable(BeatmapAttribute.StarRating); - [SettingSource("Template", "Supports {Label} and {Value}, but also including arbitrary attributes like {StarRating} (see attribute list for supported values).")] + [SettingSource(typeof(BeatmapAttributeTextStrings), nameof(BeatmapAttributeTextStrings.Template), nameof(BeatmapAttributeTextStrings.TemplateDescription))] public Bindable Template { get; set; } = new Bindable("{Label}: {Value}"); [Resolved] diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs index d87fb125bb..9adc065b88 100644 --- a/osu.Game/Skinning/Components/TextElement.cs +++ b/osu.Game/Skinning/Components/TextElement.cs @@ -8,13 +8,14 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation.SkinEditorComponents; namespace osu.Game.Skinning.Components { [UsedImplicitly] public partial class TextElement : FontAdjustableSkinComponent { - [SettingSource("Text", "The text to be displayed.")] + [SettingSource(typeof(TextElementStrings), nameof(TextElementStrings.TextElementText), nameof(TextElementStrings.TextElementTextDescription))] public Bindable Text { get; } = new Bindable("Circles!"); private readonly OsuSpriteText text; diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 98b4e960dd..74391e5269 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -254,13 +254,13 @@ namespace osu.Game.Skinning.Editor headerText.AddParagraph(SkinEditorStrings.SkinEditor, cp => cp.Font = OsuFont.Default.With(size: 16)); headerText.NewParagraph(); - headerText.AddText("Currently editing ", cp => + headerText.AddText(SkinEditorStrings.CurrentlyEditing, cp => { cp.Font = OsuFont.Default.With(size: 12); cp.Colour = colours.Yellow; }); - headerText.AddText($"{currentSkin.Value.SkinInfo}", cp => + headerText.AddText($" {currentSkin.Value.SkinInfo}", cp => { cp.Font = OsuFont.Default.With(size: 12, weight: FontWeight.Bold); cp.Colour = colours.Yellow; diff --git a/osu.Game/Skinning/FontAdjustableSkinComponent.cs b/osu.Game/Skinning/FontAdjustableSkinComponent.cs index ee73417bfe..51d4aa9fee 100644 --- a/osu.Game/Skinning/FontAdjustableSkinComponent.cs +++ b/osu.Game/Skinning/FontAdjustableSkinComponent.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; +using osu.Game.Localisation.SkinEditorComponents; namespace osu.Game.Skinning { @@ -16,7 +17,7 @@ namespace osu.Game.Skinning { public bool UsesFixedAnchor { get; set; } - [SettingSource("Font", "The font to use.")] + [SettingSource(typeof(FontAdjustableSkinComponentStrings), nameof(FontAdjustableSkinComponentStrings.Font), nameof(FontAdjustableSkinComponentStrings.FontDescription))] public Bindable Font { get; } = new Bindable(Typeface.Torus); /// diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index a66f3e0549..a5ed2a4b64 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Configuration; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation.SkinEditorComponents; using osu.Game.Overlays.Settings; using osuTK; @@ -27,7 +28,7 @@ namespace osu.Game.Skinning [Resolved] private TextureStore textures { get; set; } = null!; - [SettingSource("Sprite name", "The filename of the sprite", SettingControlType = typeof(SpriteSelectorControl))] + [SettingSource(typeof(SkinnableSpriteStrings), nameof(SkinnableSpriteStrings.SpriteName), nameof(SkinnableSpriteStrings.SpriteNameDescription), SettingControlType = typeof(SpriteSelectorControl))] public Bindable SpriteName { get; } = new Bindable(string.Empty); [Resolved] From ddfa95e6ef280939d8a19d146e8c8a07727ef8b9 Mon Sep 17 00:00:00 2001 From: tsrk Date: Thu, 2 Feb 2023 00:01:48 +0000 Subject: [PATCH 099/516] refactor: fix typos --- .../Localisation/SkinEditorComponents/SongProgressStrings.cs | 2 +- osu.Game/Localisation/SkinEditorStrings.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs b/osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs index 9719cdef52..0e4d7ea34d 100644 --- a/osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs +++ b/osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs @@ -7,7 +7,7 @@ namespace osu.Game.Localisation.SkinEditorComponents { public static class SongProgressStrings { - private const string prefix = @"osu.Game.Resources.Localisation.SongProgressStrings"; + private const string prefix = @"osu.Game.Resources.Localisation.SongProgress"; /// /// "Show difficulty graph" diff --git a/osu.Game/Localisation/SkinEditorStrings.cs b/osu.Game/Localisation/SkinEditorStrings.cs index d9744cf6c8..5cf2e5b5c5 100644 --- a/osu.Game/Localisation/SkinEditorStrings.cs +++ b/osu.Game/Localisation/SkinEditorStrings.cs @@ -40,9 +40,9 @@ namespace osu.Game.Localisation public static LocalisableString Settings(string arg0) => new TranslatableString(getKey(@"settings"), @"Settings ({0})", arg0); /// - /// "Curently editing" + /// "Currently editing" /// - public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), "Curently editing"); + public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), "Currently editing"); private static string getKey(string key) => $@"{prefix}:{key}"; } From 0fb6a637091235afc715db3c1a3e67544acc00ad Mon Sep 17 00:00:00 2001 From: tsrk Date: Thu, 2 Feb 2023 00:46:14 +0000 Subject: [PATCH 100/516] refactor: change namespacing to allow osu-localisation-analyzer to process all strings --- .../{SkinEditorComponents => }/BarHitErrorMeterStrings.cs | 2 +- .../{SkinEditorComponents => }/BeatmapAttributeTextStrings.cs | 2 +- .../{SkinEditorComponents => }/ColourHitErrorMeterStrings.cs | 2 +- .../FontAdjustableSkinComponentStrings.cs | 2 +- .../GameplayAccuracyCounterStrings.cs | 2 +- .../JudgementCounterDisplayStrings.cs | 2 +- .../{SkinEditorComponents => }/SkinnableSpriteStrings.cs | 2 +- .../{SkinEditorComponents => }/SongProgressStrings.cs | 2 +- .../{SkinEditorComponents => }/TextElementStrings.cs | 2 +- osu.Game/Screens/Play/HUD/ArgonSongProgress.cs | 2 +- osu.Game/Screens/Play/HUD/DefaultSongProgress.cs | 2 +- osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs | 2 +- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 +- osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 2 +- .../Play/HUD/JudgementCounter/JudgementCounterDisplay.cs | 2 +- osu.Game/Skinning/Components/BeatmapAttributeText.cs | 1 - osu.Game/Skinning/Components/TextElement.cs | 2 +- osu.Game/Skinning/FontAdjustableSkinComponent.cs | 2 +- osu.Game/Skinning/SkinnableSprite.cs | 2 +- 19 files changed, 18 insertions(+), 19 deletions(-) rename osu.Game/Localisation/{SkinEditorComponents => }/BarHitErrorMeterStrings.cs (98%) rename osu.Game/Localisation/{SkinEditorComponents => }/BeatmapAttributeTextStrings.cs (96%) rename osu.Game/Localisation/{SkinEditorComponents => }/ColourHitErrorMeterStrings.cs (97%) rename osu.Game/Localisation/{SkinEditorComponents => }/FontAdjustableSkinComponentStrings.cs (93%) rename osu.Game/Localisation/{SkinEditorComponents => }/GameplayAccuracyCounterStrings.cs (96%) rename osu.Game/Localisation/{SkinEditorComponents => }/JudgementCounterDisplayStrings.cs (97%) rename osu.Game/Localisation/{SkinEditorComponents => }/SkinnableSpriteStrings.cs (94%) rename osu.Game/Localisation/{SkinEditorComponents => }/SongProgressStrings.cs (94%) rename osu.Game/Localisation/{SkinEditorComponents => }/TextElementStrings.cs (94%) diff --git a/osu.Game/Localisation/SkinEditorComponents/BarHitErrorMeterStrings.cs b/osu.Game/Localisation/BarHitErrorMeterStrings.cs similarity index 98% rename from osu.Game/Localisation/SkinEditorComponents/BarHitErrorMeterStrings.cs rename to osu.Game/Localisation/BarHitErrorMeterStrings.cs index ea372a5207..171c3e223e 100644 --- a/osu.Game/Localisation/SkinEditorComponents/BarHitErrorMeterStrings.cs +++ b/osu.Game/Localisation/BarHitErrorMeterStrings.cs @@ -3,7 +3,7 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation.SkinEditorComponents +namespace osu.Game.Localisation { public static class BarHitErrorMeterStrings { diff --git a/osu.Game/Localisation/SkinEditorComponents/BeatmapAttributeTextStrings.cs b/osu.Game/Localisation/BeatmapAttributeTextStrings.cs similarity index 96% rename from osu.Game/Localisation/SkinEditorComponents/BeatmapAttributeTextStrings.cs rename to osu.Game/Localisation/BeatmapAttributeTextStrings.cs index faafa7e304..1ceb482cf4 100644 --- a/osu.Game/Localisation/SkinEditorComponents/BeatmapAttributeTextStrings.cs +++ b/osu.Game/Localisation/BeatmapAttributeTextStrings.cs @@ -3,7 +3,7 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation.SkinEditorComponents +namespace osu.Game.Localisation { public static class BeatmapAttributeTextStrings { diff --git a/osu.Game/Localisation/SkinEditorComponents/ColourHitErrorMeterStrings.cs b/osu.Game/Localisation/ColourHitErrorMeterStrings.cs similarity index 97% rename from osu.Game/Localisation/SkinEditorComponents/ColourHitErrorMeterStrings.cs rename to osu.Game/Localisation/ColourHitErrorMeterStrings.cs index fec5781c3d..13682c9c85 100644 --- a/osu.Game/Localisation/SkinEditorComponents/ColourHitErrorMeterStrings.cs +++ b/osu.Game/Localisation/ColourHitErrorMeterStrings.cs @@ -3,7 +3,7 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation.SkinEditorComponents +namespace osu.Game.Localisation { public static class ColourHitErrorMeterStrings { diff --git a/osu.Game/Localisation/SkinEditorComponents/FontAdjustableSkinComponentStrings.cs b/osu.Game/Localisation/FontAdjustableSkinComponentStrings.cs similarity index 93% rename from osu.Game/Localisation/SkinEditorComponents/FontAdjustableSkinComponentStrings.cs rename to osu.Game/Localisation/FontAdjustableSkinComponentStrings.cs index 9b92854faa..76f9f2f8b9 100644 --- a/osu.Game/Localisation/SkinEditorComponents/FontAdjustableSkinComponentStrings.cs +++ b/osu.Game/Localisation/FontAdjustableSkinComponentStrings.cs @@ -3,7 +3,7 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation.SkinEditorComponents +namespace osu.Game.Localisation { public static class FontAdjustableSkinComponentStrings { diff --git a/osu.Game/Localisation/SkinEditorComponents/GameplayAccuracyCounterStrings.cs b/osu.Game/Localisation/GameplayAccuracyCounterStrings.cs similarity index 96% rename from osu.Game/Localisation/SkinEditorComponents/GameplayAccuracyCounterStrings.cs rename to osu.Game/Localisation/GameplayAccuracyCounterStrings.cs index 33a742a95e..c9e936d8af 100644 --- a/osu.Game/Localisation/SkinEditorComponents/GameplayAccuracyCounterStrings.cs +++ b/osu.Game/Localisation/GameplayAccuracyCounterStrings.cs @@ -3,7 +3,7 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation.SkinEditorComponents +namespace osu.Game.Localisation { public static class GameplayAccuracyCounterStrings { diff --git a/osu.Game/Localisation/SkinEditorComponents/JudgementCounterDisplayStrings.cs b/osu.Game/Localisation/JudgementCounterDisplayStrings.cs similarity index 97% rename from osu.Game/Localisation/SkinEditorComponents/JudgementCounterDisplayStrings.cs rename to osu.Game/Localisation/JudgementCounterDisplayStrings.cs index 75f0241e56..fbc22e96fd 100644 --- a/osu.Game/Localisation/SkinEditorComponents/JudgementCounterDisplayStrings.cs +++ b/osu.Game/Localisation/JudgementCounterDisplayStrings.cs @@ -3,7 +3,7 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation.SkinEditorComponents +namespace osu.Game.Localisation { public static class JudgementCounterDisplayStrings { diff --git a/osu.Game/Localisation/SkinEditorComponents/SkinnableSpriteStrings.cs b/osu.Game/Localisation/SkinnableSpriteStrings.cs similarity index 94% rename from osu.Game/Localisation/SkinEditorComponents/SkinnableSpriteStrings.cs rename to osu.Game/Localisation/SkinnableSpriteStrings.cs index f67acb493c..6192f5e43d 100644 --- a/osu.Game/Localisation/SkinEditorComponents/SkinnableSpriteStrings.cs +++ b/osu.Game/Localisation/SkinnableSpriteStrings.cs @@ -3,7 +3,7 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation.SkinEditorComponents +namespace osu.Game.Localisation { public static class SkinnableSpriteStrings { diff --git a/osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs b/osu.Game/Localisation/SongProgressStrings.cs similarity index 94% rename from osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs rename to osu.Game/Localisation/SongProgressStrings.cs index 0e4d7ea34d..033560ebb0 100644 --- a/osu.Game/Localisation/SkinEditorComponents/SongProgressStrings.cs +++ b/osu.Game/Localisation/SongProgressStrings.cs @@ -3,7 +3,7 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation.SkinEditorComponents +namespace osu.Game.Localisation { public static class SongProgressStrings { diff --git a/osu.Game/Localisation/SkinEditorComponents/TextElementStrings.cs b/osu.Game/Localisation/TextElementStrings.cs similarity index 94% rename from osu.Game/Localisation/SkinEditorComponents/TextElementStrings.cs rename to osu.Game/Localisation/TextElementStrings.cs index e969da60bf..6257b80d72 100644 --- a/osu.Game/Localisation/SkinEditorComponents/TextElementStrings.cs +++ b/osu.Game/Localisation/TextElementStrings.cs @@ -3,7 +3,7 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation.SkinEditorComponents +namespace osu.Game.Localisation { public static class TextElementStrings { diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index 075e5af163..6c5ba52f27 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; using osu.Game.Graphics; -using osu.Game.Localisation.SkinEditorComponents; +using osu.Game.Localisation; using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HUD diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 1c051c24ae..fccefd49a4 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -7,7 +7,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Configuration; using osu.Game.Graphics; -using osu.Game.Localisation.SkinEditorComponents; +using osu.Game.Localisation; using osu.Game.Rulesets.Objects; using osuTK; diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index d044b3d98a..3a7c97632d 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -6,7 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation.SkinEditorComponents; +using osu.Game.Localisation; using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 5d0efe7b77..3507987fe4 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -17,7 +17,7 @@ using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Localisation.SkinEditorComponents; +using osu.Game.Localisation; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 28e2006c2f..ac49e9ca5e 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Game.Configuration; -using osu.Game.Localisation.SkinEditorComponents; +using osu.Game.Localisation; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index d047b8e5fb..31b0b9ebc5 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; using osu.Game.Configuration; -using osu.Game.Localisation.SkinEditorComponents; +using osu.Game.Localisation; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; using osuTK; diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index d2e724f760..e8b2d547a9 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -18,7 +18,6 @@ using osu.Game.Configuration; using osu.Game.Extensions; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; -using osu.Game.Localisation.SkinEditorComponents; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Skinning.Components diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs index 9adc065b88..c160f3f9d0 100644 --- a/osu.Game/Skinning/Components/TextElement.cs +++ b/osu.Game/Skinning/Components/TextElement.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Localisation.SkinEditorComponents; +using osu.Game.Localisation; namespace osu.Game.Skinning.Components { diff --git a/osu.Game/Skinning/FontAdjustableSkinComponent.cs b/osu.Game/Skinning/FontAdjustableSkinComponent.cs index 51d4aa9fee..9c28621d48 100644 --- a/osu.Game/Skinning/FontAdjustableSkinComponent.cs +++ b/osu.Game/Skinning/FontAdjustableSkinComponent.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; -using osu.Game.Localisation.SkinEditorComponents; +using osu.Game.Localisation; namespace osu.Game.Skinning { diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index a5ed2a4b64..3deb264bc8 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Configuration; using osu.Game.Graphics.Sprites; -using osu.Game.Localisation.SkinEditorComponents; +using osu.Game.Localisation; using osu.Game.Overlays.Settings; using osuTK; From 8dc2e6872e3723cadcf36453f3bf57cc74dba4ad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 18:21:04 +0900 Subject: [PATCH 101/516] Move skin editor to overlays namespace --- osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs | 2 +- .../Visual/Gameplay/TestSceneSkinEditorComponentsList.cs | 2 +- .../Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs | 2 +- osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs | 2 +- .../Visual/Navigation/TestSceneSkinEditorNavigation.cs | 2 +- osu.Game/OsuGame.cs | 2 +- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +- .../Editor => Overlays/SkinEditor}/SkinBlueprint.cs | 3 ++- .../Editor => Overlays/SkinEditor}/SkinBlueprintContainer.cs | 5 +++-- .../Editor => Overlays/SkinEditor}/SkinComponentToolbox.cs | 4 ++-- .../{Skinning/Editor => Overlays/SkinEditor}/SkinEditor.cs | 4 ++-- .../Editor => Overlays/SkinEditor}/SkinEditorOverlay.cs | 2 +- .../Editor => Overlays/SkinEditor}/SkinEditorSceneLibrary.cs | 3 +-- .../Editor => Overlays/SkinEditor}/SkinSelectionHandler.cs | 3 ++- .../Editor => Overlays/SkinEditor}/SkinSettingsToolbox.cs | 2 +- 15 files changed, 21 insertions(+), 19 deletions(-) rename osu.Game/{Skinning/Editor => Overlays/SkinEditor}/SkinBlueprint.cs (98%) rename osu.Game/{Skinning/Editor => Overlays/SkinEditor}/SkinBlueprintContainer.cs (98%) rename osu.Game/{Skinning/Editor => Overlays/SkinEditor}/SkinComponentToolbox.cs (99%) rename osu.Game/{Skinning/Editor => Overlays/SkinEditor}/SkinEditor.cs (99%) rename osu.Game/{Skinning/Editor => Overlays/SkinEditor}/SkinEditorOverlay.cs (99%) rename osu.Game/{Skinning/Editor => Overlays/SkinEditor}/SkinEditorSceneLibrary.cs (98%) rename osu.Game/{Skinning/Editor => Overlays/SkinEditor}/SkinSelectionHandler.cs (99%) rename osu.Game/{Skinning/Editor => Overlays/SkinEditor}/SkinSettingsToolbox.cs (96%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 48dbda9da6..86d97b4999 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -9,11 +9,11 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Overlays; using osu.Game.Overlays.Settings; +using osu.Game.Overlays.SkinEditor; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Skinning; -using osu.Game.Skinning.Editor; using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs index 05a550a24d..2ae5e6f998 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs @@ -7,9 +7,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Overlays; +using osu.Game.Overlays.SkinEditor; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; -using osu.Game.Skinning.Editor; namespace osu.Game.Tests.Visual.Gameplay { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index ad3911f50b..d5b6ac38cb 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -8,11 +8,11 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Timing; +using osu.Game.Overlays.SkinEditor; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; -using osu.Game.Skinning.Editor; using osu.Game.Tests.Gameplay; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs index 7d39d48378..bd75825da2 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs @@ -8,8 +8,8 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Game.Overlays.Settings.Sections; +using osu.Game.Overlays.SkinEditor; using osu.Game.Skinning; -using osu.Game.Skinning.Editor; namespace osu.Game.Tests.Visual.Navigation { diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 845cfdd6df..467b943ea0 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -12,11 +12,11 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Framework.Threading; using osu.Game.Overlays.Settings; +using osu.Game.Overlays.SkinEditor; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD.HitErrorMeters; -using osu.Game.Skinning.Editor; using osu.Game.Tests.Beatmaps.IO; using osuTK; using osuTK.Input; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4113c9be8f..df3d8b99f4 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.SkinEditor; using osu.Game.Overlays.Toolbar; using osu.Game.Overlays.Volume; using osu.Game.Performance; @@ -59,7 +60,6 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; -using osu.Game.Skinning.Editor; using osu.Game.Updater; using osu.Game.Users; using osu.Game.Utils; diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index f75656cc99..5cf8157812 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -17,9 +17,9 @@ using osu.Framework.Platform; using osu.Game.Database; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; +using osu.Game.Overlays.SkinEditor; using osu.Game.Screens.Select; using osu.Game.Skinning; -using osu.Game.Skinning.Editor; using Realms; namespace osu.Game.Overlays.Settings.Sections diff --git a/osu.Game/Skinning/Editor/SkinBlueprint.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs similarity index 98% rename from osu.Game/Skinning/Editor/SkinBlueprint.cs rename to osu.Game/Overlays/SkinEditor/SkinBlueprint.cs index c5e822a17a..893bc4bac2 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprint.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs @@ -11,10 +11,11 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Edit; +using osu.Game.Skinning; using osuTK; using osuTK.Graphics; -namespace osu.Game.Skinning.Editor +namespace osu.Game.Overlays.SkinEditor { public partial class SkinBlueprint : SelectionBlueprint { diff --git a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs similarity index 98% rename from osu.Game/Skinning/Editor/SkinBlueprintContainer.cs rename to osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs index 2998136aca..9f99242fc5 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs @@ -8,16 +8,17 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Framework.Screens; using osu.Framework.Testing; -using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Screens; using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Skinning; using osuTK; using osuTK.Input; -namespace osu.Game.Skinning.Editor +namespace osu.Game.Overlays.SkinEditor { public partial class SkinBlueprintContainer : BlueprintContainer { diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs similarity index 99% rename from osu.Game/Skinning/Editor/SkinComponentToolbox.cs rename to osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index 9985b81059..6017a98944 100644 --- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -11,12 +11,12 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; -using osu.Game.Overlays; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Play.HUD; +using osu.Game.Skinning; using osuTK; -namespace osu.Game.Skinning.Editor +namespace osu.Game.Overlays.SkinEditor { public partial class SkinComponentToolbox : EditorSidebarSection { diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs similarity index 99% rename from osu.Game/Skinning/Editor/SkinEditor.cs rename to osu.Game/Overlays/SkinEditor/SkinEditor.cs index 5c0c8b2427..ad89057d12 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -23,12 +23,12 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; -using osu.Game.Overlays; using osu.Game.Overlays.OSD; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Edit.Components.Menus; +using osu.Game.Skinning; -namespace osu.Game.Skinning.Editor +namespace osu.Game.Overlays.SkinEditor { [Cached(typeof(SkinEditor))] public partial class SkinEditor : VisibilityContainer, ICanAcceptFiles, IKeyBindingHandler diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs similarity index 99% rename from osu.Game/Skinning/Editor/SkinEditorOverlay.cs rename to osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs index f15afc7feb..4eff87c5f4 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs @@ -14,7 +14,7 @@ using osu.Game.Screens; using osu.Game.Screens.Edit.Components; using osuTK; -namespace osu.Game.Skinning.Editor +namespace osu.Game.Overlays.SkinEditor { /// /// A container which handles loading a skin editor on user request for a specified target. diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs similarity index 98% rename from osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs rename to osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs index 0936be3ee8..61195d7175 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs @@ -14,7 +14,6 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; -using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens; @@ -23,7 +22,7 @@ using osu.Game.Screens.Select; using osu.Game.Utils; using osuTK; -namespace osu.Game.Skinning.Editor +namespace osu.Game.Overlays.SkinEditor { public partial class SkinEditorSceneLibrary : CompositeDrawable { diff --git a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs similarity index 99% rename from osu.Game/Skinning/Editor/SkinSelectionHandler.cs rename to osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs index d67cbef481..129b9c1b44 100644 --- a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs @@ -14,9 +14,10 @@ using osu.Game.Extensions; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Skinning; using osuTK; -namespace osu.Game.Skinning.Editor +namespace osu.Game.Overlays.SkinEditor { public partial class SkinSelectionHandler : SelectionHandler { diff --git a/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinSettingsToolbox.cs similarity index 96% rename from osu.Game/Skinning/Editor/SkinSettingsToolbox.cs rename to osu.Game/Overlays/SkinEditor/SkinSettingsToolbox.cs index 6afe92c6b2..5a48dee973 100644 --- a/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinSettingsToolbox.cs @@ -9,7 +9,7 @@ using osu.Game.Localisation; using osu.Game.Screens.Edit.Components; using osuTK; -namespace osu.Game.Skinning.Editor +namespace osu.Game.Overlays.SkinEditor { internal partial class SkinSettingsToolbox : EditorSidebarSection { From 175b9fc5c918a1a4601912dc3b7dcbe16a85f7b5 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 2 Feb 2023 08:34:38 +0300 Subject: [PATCH 102/516] Specify texelSize value in the Triangles background --- osu.Game/Graphics/Backgrounds/Triangles.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 6750d74a08..ca5f5d06d3 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -253,6 +253,7 @@ namespace osu.Game.Graphics.Backgrounds private class TrianglesDrawNode : DrawNode { private float fill = 1f; + private float texelSize = 0f; protected new Triangles Source => (Triangles)base.Source; @@ -296,6 +297,7 @@ namespace osu.Game.Graphics.Backgrounds shader.Bind(); shader.GetUniform("thickness").UpdateValue(ref fill); + shader.GetUniform("texelSize").UpdateValue(ref texelSize); foreach (TriangleParticle particle in parts) { From 500e9c7944be4ba4f43cc2c5b0db5ce4aa54c60f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Feb 2023 14:53:58 +0900 Subject: [PATCH 103/516] Refactor into a method rather than property --- .../Select/Carousel/DrawableCarouselBeatmap.cs | 8 ++++---- osu.Game/Screens/Select/PlaySongSelect.cs | 15 +++++++-------- osu.Game/Screens/Select/SongSelect.cs | 5 ++++- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index a831271bb4..94a91205b9 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -47,7 +47,7 @@ namespace osu.Game.Screens.Select.Carousel private Sprite background = null!; - private MenuItem[]? customMenuItems; + private MenuItem[]? mainMenuItems; private Action? selectRequested; private Action? hideRequested; @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Select.Carousel if (songSelect != null) { - customMenuItems = songSelect.CustomMenuItems.Select(f => f.Invoke(beatmapInfo)).ToArray(); + mainMenuItems = songSelect.CreateMenuItemsForBeatmap(beatmapInfo); selectRequested = b => songSelect.FinaliseSelection(b); } @@ -227,8 +227,8 @@ namespace osu.Game.Screens.Select.Carousel { List items = new List(); - if (customMenuItems != null) - items.AddRange(customMenuItems); + if (mainMenuItems != null) + items.AddRange(mainMenuItems); if (beatmapInfo.OnlineID > 0 && beatmapOverlay != null) items.Add(new OsuMenuItem("Details...", MenuItemType.Standard, () => beatmapOverlay.FetchAndShowBeatmap(beatmapInfo.OnlineID))); diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index c6c2b69fd8..e2d89609c2 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; @@ -12,9 +11,9 @@ using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -22,6 +21,7 @@ using osu.Game.Screens.Ranking; using osu.Game.Users; using osu.Game.Utils; using osuTK.Input; +using NotificationsStrings = osu.Game.Localisation.NotificationsStrings; namespace osu.Game.Screens.Select { @@ -34,12 +34,11 @@ namespace osu.Game.Screens.Select public override bool AllowExternalScreenChange => true; - public override Func[] CustomMenuItems => - new Func[] - { - b => new OsuMenuItem("Play", MenuItemType.Highlighted, () => FinaliseSelection(b)), - b => new OsuMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsEdit, MenuItemType.Standard, () => Edit(b)) - }; + public override MenuItem[] CreateMenuItemsForBeatmap(BeatmapInfo b) => new MenuItem[] + { + new OsuMenuItem("Play", MenuItemType.Highlighted, () => FinaliseSelection(b)), + new OsuMenuItem(CommonStrings.ButtonsEdit, MenuItemType.Standard, () => Edit(b)) + }; protected override UserActivity InitialActivity => new UserActivity.ChoosingBeatmap(); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 61728dd9fd..56616ea323 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -84,7 +84,10 @@ namespace osu.Game.Screens.Select public bool BeatmapSetsLoaded => IsLoaded && Carousel.BeatmapSetsLoaded; - public virtual Func[] CustomMenuItems => new Func[] { b => new OsuMenuItem(@"Select", MenuItemType.Highlighted, () => FinaliseSelection(b)) }; + public virtual MenuItem[] CreateMenuItemsForBeatmap(BeatmapInfo b) => new MenuItem[] + { + new OsuMenuItem(@"Select", MenuItemType.Highlighted, () => FinaliseSelection(b)) + }; [Resolved] private Bindable> selectedMods { get; set; } = null!; From 91fbf388da5cfdd6071c5f6f99330634aaa74934 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Feb 2023 14:58:52 +0900 Subject: [PATCH 104/516] Use localisation strings from `ButtonSystem` for better consistency --- osu.Game/Screens/Select/PlaySongSelect.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index e2d89609c2..b855325d00 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; @@ -11,9 +12,9 @@ using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -21,7 +22,6 @@ using osu.Game.Screens.Ranking; using osu.Game.Users; using osu.Game.Utils; using osuTK.Input; -using NotificationsStrings = osu.Game.Localisation.NotificationsStrings; namespace osu.Game.Screens.Select { @@ -36,8 +36,8 @@ namespace osu.Game.Screens.Select public override MenuItem[] CreateMenuItemsForBeatmap(BeatmapInfo b) => new MenuItem[] { - new OsuMenuItem("Play", MenuItemType.Highlighted, () => FinaliseSelection(b)), - new OsuMenuItem(CommonStrings.ButtonsEdit, MenuItemType.Standard, () => Edit(b)) + new OsuMenuItem(ButtonSystemStrings.Play.ToSentence(), MenuItemType.Highlighted, () => FinaliseSelection(b)), + new OsuMenuItem(ButtonSystemStrings.Edit.ToSentence(), MenuItemType.Standard, () => Edit(b)) }; protected override UserActivity InitialActivity => new UserActivity.ChoosingBeatmap(); @@ -47,7 +47,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader] private void load(OsuColour colours) { - BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); + BeatmapOptions.AddButton(ButtonSystemStrings.Edit.ToSentence(), @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); } protected void PresentScore(ScoreInfo score) => From 659b78058f767f311fe0ce751910eb1ad4310e6b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Feb 2023 15:25:45 +0900 Subject: [PATCH 105/516] Move replay specific key bindings to their own section --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 9 +++++++-- osu.Game/Localisation/InputSettingsStrings.cs | 5 +++++ .../Sections/Input/GlobalKeyBindingsSection.cs | 12 ++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 3826139716..9d14ce95cf 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -35,6 +35,7 @@ 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(SongSelectKeyBindings) .Concat(AudioControlKeyBindings) @@ -112,12 +113,16 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.F4 }, GlobalAction.IncreaseScrollSpeed), new KeyBinding(new[] { InputKey.Shift, InputKey.Tab }, GlobalAction.ToggleInGameInterface), new KeyBinding(InputKey.MouseMiddle, GlobalAction.PauseGameplay), + new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), + new KeyBinding(InputKey.Tab, GlobalAction.ToggleChatFocus), + }; + + public IEnumerable ReplayKeyBindings => new[] + { new KeyBinding(InputKey.Space, GlobalAction.TogglePauseReplay), new KeyBinding(InputKey.MouseMiddle, GlobalAction.TogglePauseReplay), new KeyBinding(InputKey.Left, GlobalAction.SeekReplayBackward), new KeyBinding(InputKey.Right, GlobalAction.SeekReplayForward), - new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), - new KeyBinding(InputKey.Tab, GlobalAction.ToggleChatFocus), }; public IEnumerable SongSelectKeyBindings => new[] diff --git a/osu.Game/Localisation/InputSettingsStrings.cs b/osu.Game/Localisation/InputSettingsStrings.cs index a0da6cc2f7..2c9b175dfb 100644 --- a/osu.Game/Localisation/InputSettingsStrings.cs +++ b/osu.Game/Localisation/InputSettingsStrings.cs @@ -34,6 +34,11 @@ namespace osu.Game.Localisation /// public static LocalisableString InGameSection => new TranslatableString(getKey(@"in_game_section"), @"In Game"); + /// + /// "Replay" + /// + public static LocalisableString ReplaySection => new TranslatableString(getKey(@"replay_section"), @"Replay"); + /// /// "Audio" /// diff --git a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs index 862bbbede0..291e9a93cf 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs @@ -25,6 +25,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input Add(new AudioControlKeyBindingsSubsection(manager)); Add(new SongSelectKeyBindingSubsection(manager)); Add(new InGameKeyBindingsSubsection(manager)); + Add(new ReplayKeyBindingsSubsection(manager)); Add(new EditorKeyBindingsSubsection(manager)); } @@ -72,6 +73,17 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } + private partial class ReplayKeyBindingsSubsection : KeyBindingsSubsection + { + protected override LocalisableString Header => InputSettingsStrings.ReplaySection; + + public ReplayKeyBindingsSubsection(GlobalActionContainer manager) + : base(null) + { + Defaults = manager.ReplayKeyBindings; + } + } + private partial class AudioControlKeyBindingsSubsection : KeyBindingsSubsection { protected override LocalisableString Header => InputSettingsStrings.AudioSection; From eb62ba09aa8feb6604e16cf32602bd6be0fd769e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Feb 2023 16:20:36 +0900 Subject: [PATCH 106/516] Completely refactor to match project code standards --- .../TestSceneDrumTouchInputArea.cs | 25 ++- .../UI/DrumTouchInputArea.cs | 209 +++++++++--------- 2 files changed, 121 insertions(+), 113 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs index 23b871dcd8..5fb85df82b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs @@ -2,6 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Game.Rulesets.Taiko.Configuration; using osu.Game.Rulesets.Taiko.UI; @@ -14,7 +17,16 @@ namespace osu.Game.Rulesets.Taiko.Tests { private DrumTouchInputArea drumTouchInputArea = null!; - private void createDrum(TaikoTouchControlScheme forcedControlScheme) + private readonly Bindable controlScheme = new Bindable(); + + [BackgroundDependencyLoader] + private void load() + { + var config = (TaikoRulesetConfigManager)RulesetConfigs.GetConfigFor(Ruleset.Value.CreateInstance()).AsNonNull(); + config.BindWith(TaikoRulesetSetting.TouchControlScheme, controlScheme); + } + + private void createDrum() { Child = new TaikoInputManager(new TaikoRuleset().RulesetInfo) { @@ -31,7 +43,6 @@ namespace osu.Game.Rulesets.Taiko.Tests { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - ForceControlScheme = forcedControlScheme } } }; @@ -40,12 +51,12 @@ namespace osu.Game.Rulesets.Taiko.Tests [Test] public void TestDrum() { - AddStep("create drum (kddk)", () => createDrum(TaikoTouchControlScheme.KDDK)); - AddStep("show drum", () => drumTouchInputArea.Show()); - AddStep("create drum (ddkk)", () => createDrum(TaikoTouchControlScheme.DDKK)); - AddStep("show drum", () => drumTouchInputArea.Show()); - AddStep("create drum (kkdd)", () => createDrum(TaikoTouchControlScheme.KKDD)); + AddStep("create drum", createDrum); AddStep("show drum", () => drumTouchInputArea.Show()); + + AddStep("change scheme (kddk)", () => controlScheme.Value = TaikoTouchControlScheme.KDDK); + AddStep("change scheme (kkdd)", () => controlScheme.Value = TaikoTouchControlScheme.KKDD); + AddStep("change scheme (ddkk)", () => controlScheme.Value = TaikoTouchControlScheme.DDKK); } protected override Ruleset CreateRuleset() => new TaikoRuleset(); diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index e4c20dd1bf..a7a02895da 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -24,8 +24,6 @@ namespace osu.Game.Rulesets.Taiko.UI /// public partial class DrumTouchInputArea : VisibilityContainer { - public TaikoTouchControlScheme? ForceControlScheme { get; set; } - // visibility state affects our child. we always want to handle input. public override bool PropagatePositionalInputSubTree => true; public override bool PropagateNonPositionalInputSubTree => true; @@ -43,27 +41,6 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Bindable configTouchControlScheme = new Bindable(); - [Resolved] - private OsuColour colours { get; set; } = null!; - - private class DrumSegmentProperties - { - public TaikoAction TaikoAction { get; set; } - public Color4 Color { get; set; } - - public DrumSegmentProperties(TaikoAction taikoAction, Color4 color) - { - TaikoAction = taikoAction; - Color = color; - } - } - - private DrumSegmentProperties getDrumSegmentProperties(int drumSegment) - { - var taikoAction = getTaikoActionFromDrumSegment(drumSegment); - return new DrumSegmentProperties(taikoAction, getColourFromTaikoAction(taikoAction)); - } - [BackgroundDependencyLoader] private void load(TaikoInputManager taikoInputManager, TaikoRulesetConfigManager config) { @@ -76,14 +53,6 @@ namespace osu.Game.Rulesets.Taiko.UI const float centre_region = 0.80f; - if (ForceControlScheme == null) - { - config.BindWith(TaikoRulesetSetting.TouchControlScheme, configTouchControlScheme); - configTouchControlScheme.ValueChanged += reloadTouchDrums; - } - else - configTouchControlScheme.Value = ForceControlScheme.Value; - Children = new Drawable[] { new Container @@ -102,27 +71,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new DrumSegment(getDrumSegmentProperties(0)) + leftRim = new DrumSegment(TaikoAction.LeftRim) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - leftCentre = new DrumSegment(getDrumSegmentProperties(1)) + leftCentre = new DrumSegment(TaikoAction.LeftCentre) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightRim = new DrumSegment(getDrumSegmentProperties(3)) + rightRim = new DrumSegment(TaikoAction.RightCentre) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - rightCentre = new DrumSegment(getDrumSegmentProperties(2)) + rightCentre = new DrumSegment(TaikoAction.RightRim) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -135,36 +104,17 @@ namespace osu.Game.Rulesets.Taiko.UI } }, }; - } - private readonly TaikoAction[,] mappedTaikoAction = - { + config.BindWith(TaikoRulesetSetting.TouchControlScheme, configTouchControlScheme); + configTouchControlScheme.BindValueChanged(scheme => { - // KDDK - TaikoAction.LeftRim, - TaikoAction.LeftCentre, - TaikoAction.RightCentre, - TaikoAction.RightRim - }, - { - // DDKK - TaikoAction.LeftCentre, - TaikoAction.RightCentre, - TaikoAction.LeftRim, - TaikoAction.RightRim - }, - { - // KKDD - TaikoAction.LeftRim, - TaikoAction.RightRim, - TaikoAction.LeftCentre, - TaikoAction.RightCentre - } - }; + var actions = getOrderedActionsForScheme(scheme.NewValue); - private TaikoAction getTaikoActionFromDrumSegment(int drumSegment) - { - return mappedTaikoAction[(int)configTouchControlScheme.Value, drumSegment]; + leftRim.Action = actions[0]; + leftCentre.Action = actions[1]; + rightCentre.Action = actions[2]; + rightRim.Action = actions[3]; + }, true); } protected override bool OnKeyDown(KeyDownEvent e) @@ -186,6 +136,42 @@ namespace osu.Game.Rulesets.Taiko.UI base.OnTouchUp(e); } + private static TaikoAction[] getOrderedActionsForScheme(TaikoTouchControlScheme scheme) + { + switch (scheme) + { + case TaikoTouchControlScheme.KDDK: + return new[] + { + TaikoAction.LeftRim, + TaikoAction.LeftCentre, + TaikoAction.RightCentre, + TaikoAction.RightRim + }; + + case TaikoTouchControlScheme.DDKK: + return new[] + { + TaikoAction.LeftCentre, + TaikoAction.RightCentre, + TaikoAction.LeftRim, + TaikoAction.RightRim + }; + + case TaikoTouchControlScheme.KKDD: + return new[] + { + TaikoAction.LeftRim, + TaikoAction.RightRim, + TaikoAction.LeftCentre, + TaikoAction.RightCentre + }; + + default: + throw new ArgumentOutOfRangeException(nameof(scheme), scheme, null); + } + } + private void handleDown(object source, Vector2 position) { Show(); @@ -213,14 +199,11 @@ namespace osu.Game.Rulesets.Taiko.UI { bool centreHit = leftCentre.Contains(inputPosition) || rightCentre.Contains(inputPosition); bool leftSide = ToLocalSpace(inputPosition).X < DrawWidth / 2; - int drumSegment; if (leftSide) - drumSegment = centreHit ? 1 : 0; - else - drumSegment = centreHit ? 2 : 3; + return centreHit ? leftCentre.Action : leftRim.Action; - return getTaikoActionFromDrumSegment(drumSegment); + return centreHit ? rightCentre.Action : rightRim.Action; } protected override void PopIn() @@ -233,44 +216,44 @@ namespace osu.Game.Rulesets.Taiko.UI mainContent.FadeOut(300); } - private Color4 getColourFromTaikoAction(TaikoAction handledAction) - { - switch (handledAction) - { - case TaikoAction.LeftRim: - case TaikoAction.RightRim: - - return colours.Blue; - - case TaikoAction.LeftCentre: - case TaikoAction.RightCentre: - - return colours.Red; - } - - throw new ArgumentOutOfRangeException(); - } - private partial class DrumSegment : CompositeDrawable, IKeyBindingHandler { - private TaikoAction handledAction; + private TaikoAction action; - private readonly Circle overlay; + public TaikoAction Action + { + get => action; + set + { + if (action == value) + return; - private readonly Circle circle; + action = value; + updateColoursFromAction(); + } + } + + private Circle overlay = null!; + + private Circle circle = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); - public DrumSegment(DrumSegmentProperties properties) + public DrumSegment(TaikoAction action) { - handledAction = properties.TaikoAction; + Action = action; RelativeSizeAxes = Axes.Both; FillMode = FillMode.Fit; + } - var colour = properties.Color; - + [BackgroundDependencyLoader] + private void load() + { InternalChildren = new Drawable[] { new Container @@ -282,7 +265,6 @@ namespace osu.Game.Rulesets.Taiko.UI circle = new Circle { RelativeSizeAxes = Axes.Both, - Colour = colour.Multiply(1.4f).Darken(2.8f), Alpha = 0.8f, Scale = new Vector2(2), }, @@ -291,7 +273,6 @@ namespace osu.Game.Rulesets.Taiko.UI Alpha = 0, RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, - Colour = colour, Scale = new Vector2(2), } } @@ -299,36 +280,52 @@ namespace osu.Game.Rulesets.Taiko.UI }; } + protected override void LoadComplete() + { + base.LoadComplete(); + + updateColoursFromAction(); + } + public bool OnPressed(KeyBindingPressEvent e) { - if (e.Action == handledAction) + if (e.Action == Action) overlay.FadeTo(1f, 80, Easing.OutQuint); return false; } public void OnReleased(KeyBindingReleaseEvent e) { - if (e.Action == handledAction) + if (e.Action == Action) overlay.FadeOut(1000, Easing.OutQuint); } - public void SetProperties(DrumSegmentProperties properties) + private void updateColoursFromAction() { - handledAction = properties.TaikoAction; + if (!IsLoaded) + return; - var colour = properties.Color; + var colour = getColourFromTaikoAction(action); circle.Colour = colour.Multiply(1.4f).Darken(2.8f); overlay.Colour = colour; } - } - private void reloadTouchDrums(object _) - { - leftRim.SetProperties(getDrumSegmentProperties(0)); - leftCentre.SetProperties(getDrumSegmentProperties(1)); - rightRim.SetProperties(getDrumSegmentProperties(3)); - rightCentre.SetProperties(getDrumSegmentProperties(2)); + private Color4 getColourFromTaikoAction(TaikoAction handledAction) + { + switch (handledAction) + { + case TaikoAction.LeftRim: + case TaikoAction.RightRim: + return colours.Blue; + + case TaikoAction.LeftCentre: + case TaikoAction.RightCentre: + return colours.Pink; + } + + throw new ArgumentOutOfRangeException(); + } } } } From ffbaf453f8c21e8722345f80c6a4cee6f6064a4f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Feb 2023 16:25:23 +0900 Subject: [PATCH 107/516] Revert misordered drawable order This will completely change the visual appearance of this control... not sure why it was changed. --- osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index a7a02895da..cf697cf061 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -77,13 +77,6 @@ namespace osu.Game.Rulesets.Taiko.UI Origin = Anchor.BottomRight, X = -2, }, - leftCentre = new DrumSegment(TaikoAction.LeftCentre) - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomRight, - X = -2, - Scale = new Vector2(centre_region), - }, rightRim = new DrumSegment(TaikoAction.RightCentre) { Anchor = Anchor.BottomCentre, @@ -91,6 +84,13 @@ namespace osu.Game.Rulesets.Taiko.UI X = 2, Rotation = 90, }, + leftCentre = new DrumSegment(TaikoAction.LeftCentre) + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomRight, + X = -2, + Scale = new Vector2(centre_region), + }, rightCentre = new DrumSegment(TaikoAction.RightRim) { Anchor = Anchor.BottomCentre, From 843d9914c49c8c98c93fb7e5e0716e443ac972ab Mon Sep 17 00:00:00 2001 From: tsrk Date: Thu, 2 Feb 2023 08:18:56 +0000 Subject: [PATCH 108/516] quality: remove new line --- osu.Game/Localisation/JudgementCounterDisplayStrings.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Localisation/JudgementCounterDisplayStrings.cs b/osu.Game/Localisation/JudgementCounterDisplayStrings.cs index fbc22e96fd..aeba06b2e7 100644 --- a/osu.Game/Localisation/JudgementCounterDisplayStrings.cs +++ b/osu.Game/Localisation/JudgementCounterDisplayStrings.cs @@ -47,4 +47,3 @@ namespace osu.Game.Localisation private static string getKey(string key) => $"{prefix}:{key}"; } } - From 26efb8e8423ccc7e4aa559d2aea28090d4fc3b61 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Feb 2023 18:33:31 +0900 Subject: [PATCH 109/516] Replace white box legacy placeholder with something that visually fits --- .../SkinEditor/SkinBlueprintContainer.cs | 72 +++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs index 9f99242fc5..a448b3d0c1 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs @@ -8,11 +8,15 @@ 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.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Rulesets.Edit; -using osu.Game.Screens; using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Skinning; using osuTK; @@ -45,9 +49,7 @@ namespace osu.Game.Overlays.SkinEditor if (targetContainers.Length == 0) { - string targetScreen = target.ChildrenOfType().LastOrDefault()?.GetType().Name ?? "this screen"; - - AddInternal(new ScreenWhiteBox.UnderConstructionMessage(targetScreen, "doesn't support skin customisation just yet.")); + AddInternal(new NonSkinnableScreenPlaceholder()); return; } @@ -158,5 +160,65 @@ namespace osu.Game.Overlays.SkinEditor foreach (var list in targetComponents) list.UnbindAll(); } + + public partial class NonSkinnableScreenPlaceholder : CompositeDrawable + { + [Resolved] + private SkinEditorOverlay? skinEditorOverlay { get; set; } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = colourProvider.Dark6, + RelativeSizeAxes = Axes.Both, + Alpha = 0.95f, + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(0, 5), + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new SpriteIcon + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Icon = FontAwesome.Solid.ExclamationCircle, + Size = new Vector2(24), + Y = -5, + }, + new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(weight: FontWeight.SemiBold, size: 18)) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + TextAnchor = Anchor.Centre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = "Please navigate to a skinnable screen using the scene library", + }, + new RoundedButton + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 200, + Margin = new MarginPadding { Top = 20 }, + Action = () => skinEditorOverlay?.Hide(), + Text = "Return to game" + } + } + }, + }; + } + } } } From 9b6d95b3d6ff4c01e371fc0b8898ad14498c8d44 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Feb 2023 18:33:45 +0900 Subject: [PATCH 110/516] Adjust skin editor pop in/out to be more snappy --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index ad89057d12..479a559643 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.SkinEditor [Cached(typeof(SkinEditor))] public partial class SkinEditor : VisibilityContainer, ICanAcceptFiles, IKeyBindingHandler { - public const double TRANSITION_DURATION = 500; + public const double TRANSITION_DURATION = 300; public const float MENU_HEIGHT = 40; @@ -361,7 +361,6 @@ namespace osu.Game.Overlays.SkinEditor { this // align animation to happen after the majority of the ScalingContainer animation completes. - .Delay(ScalingContainer.TRANSITION_DURATION * 0.3f) .FadeIn(TRANSITION_DURATION, Easing.OutQuint); } From 015f4f2b388a5de891f1fb58f6d3eb536e0dc8e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Feb 2023 18:42:33 +0900 Subject: [PATCH 111/516] Avoid showing skin save message when changing scenes after making no changes --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 9 +++++---- .../Overlays/SkinEditor/SkinEditorOverlay.cs | 2 +- osu.Game/Skinning/SkinImporter.cs | 16 ++++++++++++++-- osu.Game/Skinning/SkinManager.cs | 8 ++++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index ad89057d12..4ef45b8df5 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -125,7 +125,7 @@ namespace osu.Game.Overlays.SkinEditor { Items = new[] { - new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, Save), + new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, revert), new EditorMenuItemSpacer(), new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()), @@ -333,7 +333,7 @@ namespace osu.Game.Overlays.SkinEditor } } - public void Save() + public void Save(bool userTriggered = true) { if (!hasBegunMutating) return; @@ -343,8 +343,9 @@ namespace osu.Game.Overlays.SkinEditor foreach (var t in targetContainers) currentSkin.Value.UpdateDrawableTarget(t); - skins.Save(skins.CurrentSkin.Value); - onScreenDisplay?.Display(new SkinEditorToast(ToastStrings.SkinSaved, currentSkin.Value.SkinInfo.ToString() ?? "Unknown")); + // In the case the save was user triggered, always show the save message to make them feel confident. + if (skins.Save(skins.CurrentSkin.Value) || userTriggered) + onScreenDisplay?.Display(new SkinEditorToast(ToastStrings.SkinSaved, currentSkin.Value.SkinInfo.ToString() ?? "Unknown")); } protected override bool OnHover(HoverEvent e) => true; diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs index 4eff87c5f4..b8da3e3f67 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs @@ -147,7 +147,7 @@ namespace osu.Game.Overlays.SkinEditor if (skinEditor == null) return; - skinEditor.Save(); + skinEditor.Save(false); // ensure the toolbar is re-hidden even if a new screen decides to try and show it. updateComponentVisibility(); diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index 1685562cc7..7485a89404 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -179,8 +179,14 @@ namespace osu.Game.Skinning private Skin createInstance(SkinInfo item) => item.CreateInstance(skinResources); - public void Save(Skin skin) + /// + /// Save a skin. Updates any drawable layouts that are out of date. + /// + /// Whether any change actually occurred. + public bool Save(Skin skin) { + bool hadChanges = false; + skin.SkinInfo.PerformWrite(s => { // Update for safety @@ -212,8 +218,14 @@ namespace osu.Game.Skinning } } - s.Hash = ComputeHash(s); + string newHash = ComputeHash(s); + + hadChanges = newHash != s.Hash; + + s.Hash = newHash; }); + + return hadChanges; } } } diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index a4cf83b32e..70173d9c2a 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -192,12 +192,16 @@ namespace osu.Game.Skinning }); } - public void Save(Skin skin) + /// + /// Save a skin. Updates any drawable layouts that are out of date. + /// + /// Whether any change actually occurred. + public bool Save(Skin skin) { if (!skin.SkinInfo.IsManaged) throw new InvalidOperationException($"Attempting to save a skin which is not yet tracked. Call {nameof(EnsureMutableSkin)} first."); - skinImporter.Save(skin); + return skinImporter.Save(skin); } /// From 23e9bdd5543b40b8054d88b8636aafee18c043c1 Mon Sep 17 00:00:00 2001 From: Wleter Date: Thu, 2 Feb 2023 14:22:30 +0100 Subject: [PATCH 112/516] check every snap position in blueprint --- .../Edit/OsuHitObjectComposer.cs | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 09ddc420a7..8a1d8f597c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -187,28 +187,18 @@ namespace osu.Game.Rulesets.Osu.Edit if (b.IsSelected) continue; - var hitObject = (OsuHitObject)b.Item; + var snapPositions = b.ScreenSpaceSnapPoints; - Vector2? snap = checkSnap(hitObject.Position); - if (snap == null && hitObject.Position != hitObject.EndPosition) - snap = checkSnap(hitObject.EndPosition); + var filteredSnapPositions = snapPositions.Cast().FirstOrDefault(p => Vector2.Distance(p.Value, screenSpacePosition) < snapRadius); - if (snap != null) + if (filteredSnapPositions.HasValue) { + var snap = filteredSnapPositions.Value; + // only return distance portion, since time is not really valid - snapResult = new SnapResult(snap.Value, null, playfield); + snapResult = new SnapResult(snap, null, playfield); return true; } - - Vector2? checkSnap(Vector2 checkPos) - { - Vector2 checkScreenPos = playfield.GamefieldToScreenSpace(checkPos); - - if (Vector2.Distance(checkScreenPos, screenSpacePosition) < snapRadius) - return checkScreenPos; - - return null; - } } snapResult = null; From 7c5a65bdb7a328fea885de5d5494107f606869ce Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 2 Feb 2023 17:23:09 +0100 Subject: [PATCH 113/516] Rename NormalNub.cs to RoundedNub.cs --- .../Visual/UserInterface/TestSceneRangeSlider.cs | 2 +- osu.Game/Graphics/UserInterface/NormalSliderBar.cs | 8 ++++---- osu.Game/Graphics/UserInterface/OsuCheckbox.cs | 8 ++++---- osu.Game/Graphics/UserInterface/RangeSlider.cs | 2 +- .../UserInterface/{NormalNub.cs => RoundedNub.cs} | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) rename osu.Game/Graphics/UserInterface/{NormalNub.cs => RoundedNub.cs} (92%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs index 0100b2a1a0..1b91459615 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.UserInterface LowerBound = customStart, UpperBound = customEnd, TooltipSuffix = "suffix", - NubWidth = NormalNub.HEIGHT * 2, + NubWidth = RoundedNub.HEIGHT * 2, DefaultStringLowerBound = "Start", DefaultStringUpperBound = "End", MinRange = 10 diff --git a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs index 3a3603e1de..573aa5e40d 100644 --- a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/NormalSliderBar.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface public partial class NormalSliderBar : OsuSliderBar where T : struct, IEquatable, IComparable, IConvertible { - protected readonly NormalNub Nub; + protected readonly RoundedNub Nub; protected readonly Box LeftBox; protected readonly Box RightBox; private readonly Container nubContainer; @@ -50,8 +50,8 @@ namespace osu.Game.Graphics.UserInterface public NormalSliderBar() { - Height = NormalNub.HEIGHT; - RangePadding = NormalNub.EXPANDED_SIZE / 2; + Height = RoundedNub.HEIGHT; + RangePadding = RoundedNub.EXPANDED_SIZE / 2; Children = new Drawable[] { new Container @@ -93,7 +93,7 @@ namespace osu.Game.Graphics.UserInterface nubContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = Nub = new NormalNub + Child = Nub = new RoundedNub { Origin = Anchor.TopCentre, RelativePositionAxes = Axes.X, diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs index 877493dd5c..2fae4e2cb5 100644 --- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs @@ -41,7 +41,7 @@ namespace osu.Game.Graphics.UserInterface } } - protected readonly NormalNub Nub; + protected readonly RoundedNub Nub; protected readonly OsuTextFlowContainer LabelTextFlowContainer; private Sample sampleChecked; @@ -61,7 +61,7 @@ namespace osu.Game.Graphics.UserInterface AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, }, - Nub = new NormalNub(), + Nub = new RoundedNub(), new HoverSounds() }; @@ -70,14 +70,14 @@ namespace osu.Game.Graphics.UserInterface Nub.Anchor = Anchor.CentreRight; Nub.Origin = Anchor.CentreRight; Nub.Margin = new MarginPadding { Right = nub_padding }; - LabelTextFlowContainer.Padding = new MarginPadding { Right = NormalNub.EXPANDED_SIZE + nub_padding * 2 }; + LabelTextFlowContainer.Padding = new MarginPadding { Right = RoundedNub.EXPANDED_SIZE + nub_padding * 2 }; } else { Nub.Anchor = Anchor.CentreLeft; Nub.Origin = Anchor.CentreLeft; Nub.Margin = new MarginPadding { Left = nub_padding }; - LabelTextFlowContainer.Padding = new MarginPadding { Left = NormalNub.EXPANDED_SIZE + nub_padding * 2 }; + LabelTextFlowContainer.Padding = new MarginPadding { Left = RoundedNub.EXPANDED_SIZE + nub_padding * 2 }; } Nub.Current.BindTo(Current); diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs index 806209d548..76096f7ed0 100644 --- a/osu.Game/Graphics/UserInterface/RangeSlider.cs +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -163,7 +163,7 @@ namespace osu.Game.Graphics.UserInterface public string? DefaultString; public LocalisableString? DefaultTooltip; public string? TooltipSuffix; - public float NubWidth { get; set; } = NormalNub.HEIGHT; + public float NubWidth { get; set; } = RoundedNub.HEIGHT; public override LocalisableString TooltipText => (Current.IsDefault ? DefaultTooltip : Current.Value.ToString($@"0.## {TooltipSuffix}")) ?? Current.Value.ToString($@"0.## {TooltipSuffix}"); diff --git a/osu.Game/Graphics/UserInterface/NormalNub.cs b/osu.Game/Graphics/UserInterface/RoundedNub.cs similarity index 92% rename from osu.Game/Graphics/UserInterface/NormalNub.cs rename to osu.Game/Graphics/UserInterface/RoundedNub.cs index e6939d060b..3bdfadfe22 100644 --- a/osu.Game/Graphics/UserInterface/NormalNub.cs +++ b/osu.Game/Graphics/UserInterface/RoundedNub.cs @@ -7,13 +7,13 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public partial class NormalNub : Nub + public partial class RoundedNub : Nub { public const float HEIGHT = 15; public const float EXPANDED_SIZE = 50; - public NormalNub() + public RoundedNub() { Size = new Vector2(EXPANDED_SIZE, HEIGHT); } From 3f0ce75bf5f937565f13b022059e5e10c97f331f Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 2 Feb 2023 17:24:45 +0100 Subject: [PATCH 114/516] Rename NormalSliderBar.cs to RoundedSliderBar.cs --- osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs | 2 +- osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs | 8 ++++---- .../UserInterface/TestSceneModDifficultyAdjustSettings.cs | 4 ++-- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 2 +- osu.Game/Graphics/UserInterface/ExpandableSlider.cs | 4 ++-- osu.Game/Graphics/UserInterface/RangeSlider.cs | 2 +- .../{NormalSliderBar.cs => RoundedSliderBar.cs} | 4 ++-- osu.Game/Graphics/UserInterface/TimeSlider.cs | 2 +- osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs | 2 +- .../Overlays/Settings/Sections/Audio/VolumeSettings.cs | 2 +- .../Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 2 +- .../Overlays/Settings/Sections/Input/MouseSettings.cs | 2 +- osu.Game/Overlays/Settings/Sections/SizeSlider.cs | 2 +- osu.Game/Overlays/Settings/SettingsSlider.cs | 4 ++-- osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs | 2 +- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 2 +- osu.Game/Rulesets/Mods/ModMuted.cs | 2 +- osu.Game/Rulesets/Mods/ModNoScope.cs | 2 +- osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs | 4 ++-- 19 files changed, 27 insertions(+), 27 deletions(-) rename osu.Game/Graphics/UserInterface/{NormalSliderBar.cs => RoundedSliderBar.cs} (98%) diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs index 5642fb4bdb..fc0b4a9ed9 100644 --- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Mania }; } - private partial class ManiaScrollSlider : NormalSliderBar + private partial class ManiaScrollSlider : RoundedSliderBar { public override LocalisableString TooltipText => RulesetSettingsStrings.ScrollSpeedTooltip(Current.Value, (int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)); } diff --git a/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs b/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs index 791a5651b6..d96c19a13e 100644 --- a/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs +++ b/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs @@ -31,8 +31,8 @@ namespace osu.Game.Tests.Visual.Audio private WaveformTestBeatmap beatmap; - private NormalSliderBar lowPassSlider; - private NormalSliderBar highPassSlider; + private RoundedSliderBar lowPassSlider; + private RoundedSliderBar highPassSlider; [BackgroundDependencyLoader] private void load(AudioManager audio) @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual.Audio Text = $"Low Pass: {lowPassFilter.Cutoff}hz", Font = new FontUsage(size: 40) }, - lowPassSlider = new NormalSliderBar + lowPassSlider = new RoundedSliderBar { Width = 500, Height = 50, @@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.Audio Text = $"High Pass: {highPassFilter.Cutoff}hz", Font = new FontUsage(size: 40) }, - highPassSlider = new NormalSliderBar + highPassSlider = new RoundedSliderBar { Width = 500, Height = 50, diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs index 5e2b5ca4ff..307f436f84 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs @@ -261,7 +261,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep($"Set {name} slider to {value}", () => this.ChildrenOfType().First(c => c.LabelText == name) - .ChildrenOfType>().First().Current.Value = value); + .ChildrenOfType>().First().Current.Value = value); } private void checkBindableAtValue(string name, float? expectedValue) @@ -275,7 +275,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddAssert($"Slider {name} at {expectedValue}", () => this.ChildrenOfType().First(c => c.LabelText == name) - .ChildrenOfType>().First().Current.Value == expectedValue); + .ChildrenOfType>().First().Current.Value == expectedValue); } private void setBeatmapWithDifficultyParameters(float value) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 1cbb798981..5ccaebd721 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -270,7 +270,7 @@ namespace osu.Game.Tests.Visual.UserInterface createScreen(); AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); - AddStep("set setting", () => modSelectOverlay.ChildrenOfType>().First().Current.Value = 8); + AddStep("set setting", () => modSelectOverlay.ChildrenOfType>().First().Current.Value = 8); AddAssert("ensure setting is propagated", () => SelectedMods.Value.OfType().Single().CircleSize.Value == 8); diff --git a/osu.Game/Graphics/UserInterface/ExpandableSlider.cs b/osu.Game/Graphics/UserInterface/ExpandableSlider.cs index e960f55501..5bc17303d8 100644 --- a/osu.Game/Graphics/UserInterface/ExpandableSlider.cs +++ b/osu.Game/Graphics/UserInterface/ExpandableSlider.cs @@ -21,7 +21,7 @@ namespace osu.Game.Graphics.UserInterface /// public partial class ExpandableSlider : CompositeDrawable, IExpandable, IHasCurrentValue where T : struct, IEquatable, IComparable, IConvertible - where TSlider : NormalSliderBar, new() + where TSlider : RoundedSliderBar, new() { private readonly OsuSpriteText label; private readonly TSlider slider; @@ -130,7 +130,7 @@ namespace osu.Game.Graphics.UserInterface /// /// An implementation for the UI slider bar control. /// - public partial class ExpandableSlider : ExpandableSlider> + public partial class ExpandableSlider : ExpandableSlider> where T : struct, IEquatable, IComparable, IConvertible { } diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs index 76096f7ed0..575327b50b 100644 --- a/osu.Game/Graphics/UserInterface/RangeSlider.cs +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -158,7 +158,7 @@ namespace osu.Game.Graphics.UserInterface && screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X; } - protected partial class BoundSlider : NormalSliderBar + protected partial class BoundSlider : RoundedSliderBar { public string? DefaultString; public LocalisableString? DefaultTooltip; diff --git a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs b/osu.Game/Graphics/UserInterface/RoundedSliderBar.cs similarity index 98% rename from osu.Game/Graphics/UserInterface/NormalSliderBar.cs rename to osu.Game/Graphics/UserInterface/RoundedSliderBar.cs index 573aa5e40d..765e1d5105 100644 --- a/osu.Game/Graphics/UserInterface/NormalSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/RoundedSliderBar.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.UserInterface { - public partial class NormalSliderBar : OsuSliderBar + public partial class RoundedSliderBar : OsuSliderBar where T : struct, IEquatable, IComparable, IConvertible { protected readonly RoundedNub Nub; @@ -48,7 +48,7 @@ namespace osu.Game.Graphics.UserInterface } } - public NormalSliderBar() + public RoundedSliderBar() { Height = RoundedNub.HEIGHT; RangePadding = RoundedNub.EXPANDED_SIZE / 2; diff --git a/osu.Game/Graphics/UserInterface/TimeSlider.cs b/osu.Game/Graphics/UserInterface/TimeSlider.cs index 15fc0a465b..e4058827f3 100644 --- a/osu.Game/Graphics/UserInterface/TimeSlider.cs +++ b/osu.Game/Graphics/UserInterface/TimeSlider.cs @@ -10,7 +10,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A slider bar which displays a millisecond time value. /// - public partial class TimeSlider : NormalSliderBar + public partial class TimeSlider : RoundedSliderBar { public override LocalisableString TooltipText => $"{Current.Value:N0} ms"; } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index 75aedc298e..e3cd2ae36c 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.FirstRunSetup public override bool? AllowTrackAdjustments => false; } - private partial class UIScaleSlider : NormalSliderBar + private partial class UIScaleSlider : RoundedSliderBar { public override LocalisableString TooltipText => base.TooltipText + "x"; } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs index 0c62cb169f..7066be4f92 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { protected override Drawable CreateControl() { - var sliderBar = (NormalSliderBar)base.CreateControl(); + var sliderBar = (RoundedSliderBar)base.CreateControl(); sliderBar.PlaySamplesOnAdjust = false; return sliderBar; } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 805cf4ca0b..6465d62ef0 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -329,7 +329,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } } - private partial class UIScaleSlider : NormalSliderBar + private partial class UIScaleSlider : RoundedSliderBar { public override LocalisableString TooltipText => base.TooltipText + "x"; } diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index f403012793..dfaeafbf5d 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -135,7 +135,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - public partial class SensitivitySlider : NormalSliderBar + public partial class SensitivitySlider : RoundedSliderBar { public override LocalisableString TooltipText => Current.Disabled ? MouseSettingsStrings.EnableHighPrecisionForSensitivityAdjust : $"{base.TooltipText}x"; } diff --git a/osu.Game/Overlays/Settings/Sections/SizeSlider.cs b/osu.Game/Overlays/Settings/Sections/SizeSlider.cs index b596212007..20d77bef0d 100644 --- a/osu.Game/Overlays/Settings/Sections/SizeSlider.cs +++ b/osu.Game/Overlays/Settings/Sections/SizeSlider.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Settings.Sections /// /// A slider intended to show a "size" multiplier number, where 1x is 1.0. /// - public partial class SizeSlider : NormalSliderBar + public partial class SizeSlider : RoundedSliderBar where T : struct, IEquatable, IComparable, IConvertible, IFormattable { public override LocalisableString TooltipText => Current.Value.ToString(@"0.##x", NumberFormatInfo.CurrentInfo); diff --git a/osu.Game/Overlays/Settings/SettingsSlider.cs b/osu.Game/Overlays/Settings/SettingsSlider.cs index a7305b4e03..e1483d4202 100644 --- a/osu.Game/Overlays/Settings/SettingsSlider.cs +++ b/osu.Game/Overlays/Settings/SettingsSlider.cs @@ -10,14 +10,14 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public partial class SettingsSlider : SettingsSlider> + public partial class SettingsSlider : SettingsSlider> where T : struct, IEquatable, IComparable, IConvertible { } public partial class SettingsSlider : SettingsItem where TValue : struct, IEquatable, IComparable, IConvertible - where TSlider : NormalSliderBar, new() + where TSlider : RoundedSliderBar, new() { protected override Drawable CreateControl() => new TSlider { diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index 58810fc127..a941c0a1db 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Mods { InternalChildren = new Drawable[] { - new NormalSliderBar + new RoundedSliderBar { RelativeSizeAxes = Axes.X, Current = currentNumber, diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index a7b00ac88b..dc7594f469 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mods } } - public partial class PercentSlider : NormalSliderBar + public partial class PercentSlider : RoundedSliderBar { public PercentSlider() { diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index d2d8284083..367ceeb446 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Mods public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; } - public partial class MuteComboSlider : NormalSliderBar + public partial class MuteComboSlider : RoundedSliderBar { public override LocalisableString TooltipText => Current.Value == 0 ? "always muted" : base.TooltipText; } diff --git a/osu.Game/Rulesets/Mods/ModNoScope.cs b/osu.Game/Rulesets/Mods/ModNoScope.cs index 3736eca780..5b9dfc0430 100644 --- a/osu.Game/Rulesets/Mods/ModNoScope.cs +++ b/osu.Game/Rulesets/Mods/ModNoScope.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mods } } - public partial class HiddenComboSlider : NormalSliderBar + public partial class HiddenComboSlider : RoundedSliderBar { public override LocalisableString TooltipText => Current.Value == 0 ? "always hidden" : base.TooltipText; } diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs index 985a414bc0..45009684a6 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs @@ -15,11 +15,11 @@ namespace osu.Game.Screens.Play.PlayerSettings public partial class PlayerSliderBar : SettingsSlider where T : struct, IEquatable, IComparable, IConvertible { - public NormalSliderBar Bar => (NormalSliderBar)Control; + public RoundedSliderBar Bar => (RoundedSliderBar)Control; protected override Drawable CreateControl() => new SliderBar(); - protected partial class SliderBar : NormalSliderBar + protected partial class SliderBar : RoundedSliderBar { public SliderBar() { From 80fd1a0bc7d85e8dae00089cea00bf14a762c7c7 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 2 Feb 2023 18:29:12 +0100 Subject: [PATCH 115/516] 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 f7fa9e3927c7ad65bc631aa7242febb04ffbc823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 2 Feb 2023 18:41:35 +0100 Subject: [PATCH 116/516] Remove outdated comment --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 479a559643..275cbd18d7 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -359,9 +359,7 @@ namespace osu.Game.Overlays.SkinEditor protected override void PopIn() { - this - // align animation to happen after the majority of the ScalingContainer animation completes. - .FadeIn(TRANSITION_DURATION, Easing.OutQuint); + this.FadeIn(TRANSITION_DURATION, Easing.OutQuint); } protected override void PopOut() From f7094567d7268ca663a34b10af4ff1dd182e886c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 15:04:47 +0900 Subject: [PATCH 117/516] Rename and document method to limit scope --- .../Screens/Select/Carousel/DrawableCarouselBeatmap.cs | 2 +- osu.Game/Screens/Select/PlaySongSelect.cs | 6 +++--- osu.Game/Screens/Select/SongSelect.cs | 10 ++++++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 94a91205b9..f08d14720b 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Select.Carousel if (songSelect != null) { - mainMenuItems = songSelect.CreateMenuItemsForBeatmap(beatmapInfo); + mainMenuItems = songSelect.CreateForwardNavigationMenuItemsForBeatmap(beatmapInfo); selectRequested = b => songSelect.FinaliseSelection(b); } diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index b855325d00..b99d949b43 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -34,10 +34,10 @@ namespace osu.Game.Screens.Select public override bool AllowExternalScreenChange => true; - public override MenuItem[] CreateMenuItemsForBeatmap(BeatmapInfo b) => new MenuItem[] + public override MenuItem[] CreateForwardNavigationMenuItemsForBeatmap(BeatmapInfo beatmap) => new MenuItem[] { - new OsuMenuItem(ButtonSystemStrings.Play.ToSentence(), MenuItemType.Highlighted, () => FinaliseSelection(b)), - new OsuMenuItem(ButtonSystemStrings.Edit.ToSentence(), MenuItemType.Standard, () => Edit(b)) + new OsuMenuItem(ButtonSystemStrings.Play.ToSentence(), MenuItemType.Highlighted, () => FinaliseSelection(beatmap)), + new OsuMenuItem(ButtonSystemStrings.Edit.ToSentence(), MenuItemType.Standard, () => Edit(beatmap)) }; protected override UserActivity InitialActivity => new UserActivity.ChoosingBeatmap(); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 56616ea323..8786821c77 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -84,9 +84,15 @@ namespace osu.Game.Screens.Select public bool BeatmapSetsLoaded => IsLoaded && Carousel.BeatmapSetsLoaded; - public virtual MenuItem[] CreateMenuItemsForBeatmap(BeatmapInfo b) => new MenuItem[] + /// + /// Creates any "action" menu items for the provided beatmap (ie. "Select", "Play", "Edit"). + /// These will always be placed at the top of the context menu, with common items added below them. + /// + /// The beatmap to create items for. + /// The menu items. + public virtual MenuItem[] CreateForwardNavigationMenuItemsForBeatmap(BeatmapInfo beatmap) => new MenuItem[] { - new OsuMenuItem(@"Select", MenuItemType.Highlighted, () => FinaliseSelection(b)) + new OsuMenuItem(@"Select", MenuItemType.Highlighted, () => FinaliseSelection(beatmap)) }; [Resolved] From 9c954a93e322095781571638e94beb21e9b710b2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 15:18:01 +0900 Subject: [PATCH 118/516] Update `Save` method xmldoc to make more sense --- osu.Game/Skinning/SkinImporter.cs | 2 +- osu.Game/Skinning/SkinManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index 7485a89404..8ce265719c 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -180,7 +180,7 @@ namespace osu.Game.Skinning private Skin createInstance(SkinInfo item) => item.CreateInstance(skinResources); /// - /// Save a skin. Updates any drawable layouts that are out of date. + /// Save a skin, serialising any changes to skin layouts to relevant JSON structures. /// /// Whether any change actually occurred. public bool Save(Skin skin) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 70173d9c2a..fca7dc0f5e 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -193,7 +193,7 @@ namespace osu.Game.Skinning } /// - /// Save a skin. Updates any drawable layouts that are out of date. + /// Save a skin, serialising any changes to skin layouts to relevant JSON structures. /// /// Whether any change actually occurred. public bool Save(Skin skin) From 5ca5f04794791bc1e7b79b7d1ee7ae42dd4d74ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 15:18:40 +0900 Subject: [PATCH 119/516] Add parameter hint for optional `bool` value --- osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs index b8da3e3f67..c87e60e47f 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs @@ -147,7 +147,7 @@ namespace osu.Game.Overlays.SkinEditor if (skinEditor == null) return; - skinEditor.Save(false); + skinEditor.Save(userTriggered: false); // ensure the toolbar is re-hidden even if a new screen decides to try and show it. updateComponentVisibility(); From 50559643bbb4f104fda7e7a577afbf26b755bdb3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 15:27:11 +0900 Subject: [PATCH 120/516] Fix incorrectly applied enum localisation --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 3507987fe4..f380165a66 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -507,7 +507,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStylesIcons))] Icons, - [LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStylesIcons))] + [LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStylesText))] Text } } From cf8cfe0d2c7678f316faddc77eaff5d787bce6c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 15:34:57 +0900 Subject: [PATCH 121/516] Move skin component localisations to namespaces --- osu.Game/Localisation/{ => HUD}/BarHitErrorMeterStrings.cs | 4 ++-- osu.Game/Localisation/{ => HUD}/ColourHitErrorMeterStrings.cs | 4 ++-- .../Localisation/{ => HUD}/GameplayAccuracyCounterStrings.cs | 4 ++-- .../Localisation/{ => HUD}/JudgementCounterDisplayStrings.cs | 4 ++-- osu.Game/Localisation/{ => HUD}/SongProgressStrings.cs | 4 ++-- .../{ => SkinComponents}/BeatmapAttributeTextStrings.cs | 4 ++-- .../FontAdjustableSkinComponentStrings.cs | 4 ++-- .../{ => SkinComponents}/SkinnableSpriteStrings.cs | 4 ++-- .../Localisation/{ => SkinComponents}/TextElementStrings.cs | 4 ++-- osu.Game/Screens/Play/HUD/ArgonSongProgress.cs | 2 +- osu.Game/Screens/Play/HUD/DefaultSongProgress.cs | 2 +- osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs | 2 +- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 +- .../Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 2 +- .../Play/HUD/JudgementCounter/JudgementCounterDisplay.cs | 2 +- osu.Game/Skinning/Components/BeatmapAttributeText.cs | 1 + osu.Game/Skinning/Components/TextElement.cs | 2 +- osu.Game/Skinning/FontAdjustableSkinComponent.cs | 2 +- osu.Game/Skinning/SkinnableSprite.cs | 2 +- 19 files changed, 28 insertions(+), 27 deletions(-) rename osu.Game/Localisation/{ => HUD}/BarHitErrorMeterStrings.cs (98%) rename osu.Game/Localisation/{ => HUD}/ColourHitErrorMeterStrings.cs (97%) rename osu.Game/Localisation/{ => HUD}/GameplayAccuracyCounterStrings.cs (95%) rename osu.Game/Localisation/{ => HUD}/JudgementCounterDisplayStrings.cs (96%) rename osu.Game/Localisation/{ => HUD}/SongProgressStrings.cs (93%) rename osu.Game/Localisation/{ => SkinComponents}/BeatmapAttributeTextStrings.cs (93%) rename osu.Game/Localisation/{ => SkinComponents}/FontAdjustableSkinComponentStrings.cs (88%) rename osu.Game/Localisation/{ => SkinComponents}/SkinnableSpriteStrings.cs (90%) rename osu.Game/Localisation/{ => SkinComponents}/TextElementStrings.cs (90%) diff --git a/osu.Game/Localisation/BarHitErrorMeterStrings.cs b/osu.Game/Localisation/HUD/BarHitErrorMeterStrings.cs similarity index 98% rename from osu.Game/Localisation/BarHitErrorMeterStrings.cs rename to osu.Game/Localisation/HUD/BarHitErrorMeterStrings.cs index 171c3e223e..2f77a287a0 100644 --- a/osu.Game/Localisation/BarHitErrorMeterStrings.cs +++ b/osu.Game/Localisation/HUD/BarHitErrorMeterStrings.cs @@ -3,11 +3,11 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation +namespace osu.Game.Localisation.HUD { public static class BarHitErrorMeterStrings { - private const string prefix = @"osu.Game.Resources.Localisation.BarHitErrorMeter"; + private const string prefix = @"osu.Game.Resources.Localisation.HUD.BarHitErrorMeter"; /// /// "Judgement line thickness" diff --git a/osu.Game/Localisation/ColourHitErrorMeterStrings.cs b/osu.Game/Localisation/HUD/ColourHitErrorMeterStrings.cs similarity index 97% rename from osu.Game/Localisation/ColourHitErrorMeterStrings.cs rename to osu.Game/Localisation/HUD/ColourHitErrorMeterStrings.cs index 13682c9c85..8fdcb34a49 100644 --- a/osu.Game/Localisation/ColourHitErrorMeterStrings.cs +++ b/osu.Game/Localisation/HUD/ColourHitErrorMeterStrings.cs @@ -3,11 +3,11 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation +namespace osu.Game.Localisation.HUD { public static class ColourHitErrorMeterStrings { - private const string prefix = @"osu.Game.Resources.Localisation.ColourHitError"; + private const string prefix = @"osu.Game.Resources.Localisation.HUD.ColourHitError"; /// /// "Judgement count" diff --git a/osu.Game/Localisation/GameplayAccuracyCounterStrings.cs b/osu.Game/Localisation/HUD/GameplayAccuracyCounterStrings.cs similarity index 95% rename from osu.Game/Localisation/GameplayAccuracyCounterStrings.cs rename to osu.Game/Localisation/HUD/GameplayAccuracyCounterStrings.cs index c9e936d8af..ec7f4a1af3 100644 --- a/osu.Game/Localisation/GameplayAccuracyCounterStrings.cs +++ b/osu.Game/Localisation/HUD/GameplayAccuracyCounterStrings.cs @@ -3,11 +3,11 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation +namespace osu.Game.Localisation.HUD { public static class GameplayAccuracyCounterStrings { - private const string prefix = @"osu.Game.Resources.Localisation.GameplayAccuracyCounter"; + private const string prefix = @"osu.Game.Resources.Localisation.HUD.GameplayAccuracyCounter"; /// /// "Accuracy display mode" diff --git a/osu.Game/Localisation/JudgementCounterDisplayStrings.cs b/osu.Game/Localisation/HUD/JudgementCounterDisplayStrings.cs similarity index 96% rename from osu.Game/Localisation/JudgementCounterDisplayStrings.cs rename to osu.Game/Localisation/HUD/JudgementCounterDisplayStrings.cs index aeba06b2e7..b1c756e48e 100644 --- a/osu.Game/Localisation/JudgementCounterDisplayStrings.cs +++ b/osu.Game/Localisation/HUD/JudgementCounterDisplayStrings.cs @@ -3,11 +3,11 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation +namespace osu.Game.Localisation.HUD { public static class JudgementCounterDisplayStrings { - private const string prefix = @"osu.Game.Resources.Localisation.JudgementCounterDisplay"; + private const string prefix = @"osu.Game.Resources.Localisation.HUD.JudgementCounterDisplay"; /// /// "Display mode" diff --git a/osu.Game/Localisation/SongProgressStrings.cs b/osu.Game/Localisation/HUD/SongProgressStrings.cs similarity index 93% rename from osu.Game/Localisation/SongProgressStrings.cs rename to osu.Game/Localisation/HUD/SongProgressStrings.cs index 033560ebb0..4c621e8e8c 100644 --- a/osu.Game/Localisation/SongProgressStrings.cs +++ b/osu.Game/Localisation/HUD/SongProgressStrings.cs @@ -3,11 +3,11 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation +namespace osu.Game.Localisation.HUD { public static class SongProgressStrings { - private const string prefix = @"osu.Game.Resources.Localisation.SongProgress"; + private const string prefix = @"osu.Game.Resources.Localisation.HUD.SongProgress"; /// /// "Show difficulty graph" diff --git a/osu.Game/Localisation/BeatmapAttributeTextStrings.cs b/osu.Game/Localisation/SkinComponents/BeatmapAttributeTextStrings.cs similarity index 93% rename from osu.Game/Localisation/BeatmapAttributeTextStrings.cs rename to osu.Game/Localisation/SkinComponents/BeatmapAttributeTextStrings.cs index 1ceb482cf4..b2e2285faf 100644 --- a/osu.Game/Localisation/BeatmapAttributeTextStrings.cs +++ b/osu.Game/Localisation/SkinComponents/BeatmapAttributeTextStrings.cs @@ -3,11 +3,11 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation +namespace osu.Game.Localisation.SkinComponents { public static class BeatmapAttributeTextStrings { - private const string prefix = @"osu.Game.Resources.Localisation.BeatmapAttributeText"; + private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.BeatmapAttributeText"; /// /// "Attribute" diff --git a/osu.Game/Localisation/FontAdjustableSkinComponentStrings.cs b/osu.Game/Localisation/SkinComponents/FontAdjustableSkinComponentStrings.cs similarity index 88% rename from osu.Game/Localisation/FontAdjustableSkinComponentStrings.cs rename to osu.Game/Localisation/SkinComponents/FontAdjustableSkinComponentStrings.cs index 76f9f2f8b9..8bcc45998a 100644 --- a/osu.Game/Localisation/FontAdjustableSkinComponentStrings.cs +++ b/osu.Game/Localisation/SkinComponents/FontAdjustableSkinComponentStrings.cs @@ -3,11 +3,11 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation +namespace osu.Game.Localisation.SkinComponents { public static class FontAdjustableSkinComponentStrings { - private const string prefix = @"osu.Game.Resources.Localisation.FontAdjustableSkinComponent"; + private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.FontAdjustableSkinComponent"; /// /// "Font" diff --git a/osu.Game/Localisation/SkinnableSpriteStrings.cs b/osu.Game/Localisation/SkinComponents/SkinnableSpriteStrings.cs similarity index 90% rename from osu.Game/Localisation/SkinnableSpriteStrings.cs rename to osu.Game/Localisation/SkinComponents/SkinnableSpriteStrings.cs index 6192f5e43d..f039c9044f 100644 --- a/osu.Game/Localisation/SkinnableSpriteStrings.cs +++ b/osu.Game/Localisation/SkinComponents/SkinnableSpriteStrings.cs @@ -3,11 +3,11 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation +namespace osu.Game.Localisation.SkinComponents { public static class SkinnableSpriteStrings { - private const string prefix = @"osu.Game.Resources.Localisation.SkinnableSprite"; + private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.SkinnableSprite"; /// /// "Sprite name" diff --git a/osu.Game/Localisation/TextElementStrings.cs b/osu.Game/Localisation/SkinComponents/TextElementStrings.cs similarity index 90% rename from osu.Game/Localisation/TextElementStrings.cs rename to osu.Game/Localisation/SkinComponents/TextElementStrings.cs index 6257b80d72..6417c1d923 100644 --- a/osu.Game/Localisation/TextElementStrings.cs +++ b/osu.Game/Localisation/SkinComponents/TextElementStrings.cs @@ -3,11 +3,11 @@ using osu.Framework.Localisation; -namespace osu.Game.Localisation +namespace osu.Game.Localisation.SkinComponents { public static class TextElementStrings { - private const string prefix = @"osu.Game.Resources.Localisation.TextElement"; + private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.TextElement"; /// /// "Text" diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index 6c5ba52f27..9dce8996c3 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; using osu.Game.Graphics; -using osu.Game.Localisation; +using osu.Game.Localisation.HUD; using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HUD diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index fccefd49a4..6eed563703 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -7,7 +7,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Configuration; using osu.Game.Graphics; -using osu.Game.Localisation; +using osu.Game.Localisation.HUD; using osu.Game.Rulesets.Objects; using osuTK; diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index 3a7c97632d..9da032e489 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -6,7 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; +using osu.Game.Localisation.HUD; using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index f380165a66..eb5221aa45 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -17,7 +17,7 @@ using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Localisation; +using osu.Game.Localisation.HUD; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index ac49e9ca5e..5793713fca 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Game.Configuration; -using osu.Game.Localisation; +using osu.Game.Localisation.HUD; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 31b0b9ebc5..80d2e0863f 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; using osu.Game.Configuration; -using osu.Game.Localisation; +using osu.Game.Localisation.HUD; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; using osuTK; diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index e8b2d547a9..2c16a67cac 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -18,6 +18,7 @@ using osu.Game.Configuration; using osu.Game.Extensions; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; +using osu.Game.Localisation.SkinComponents; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Skinning.Components diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs index c160f3f9d0..1e0a0d0ad1 100644 --- a/osu.Game/Skinning/Components/TextElement.cs +++ b/osu.Game/Skinning/Components/TextElement.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Localisation; +using osu.Game.Localisation.SkinComponents; namespace osu.Game.Skinning.Components { diff --git a/osu.Game/Skinning/FontAdjustableSkinComponent.cs b/osu.Game/Skinning/FontAdjustableSkinComponent.cs index 9c28621d48..11d3e36d9e 100644 --- a/osu.Game/Skinning/FontAdjustableSkinComponent.cs +++ b/osu.Game/Skinning/FontAdjustableSkinComponent.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; -using osu.Game.Localisation; +using osu.Game.Localisation.SkinComponents; namespace osu.Game.Skinning { diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 3deb264bc8..31391755a3 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Configuration; using osu.Game.Graphics.Sprites; -using osu.Game.Localisation; +using osu.Game.Localisation.SkinComponents; using osu.Game.Overlays.Settings; using osuTK; From 92306b912329aec3fdb74a2cf88822b42bf54537 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 16:02:16 +0900 Subject: [PATCH 122/516] Combine localisations for abstract skinnable components into a single file Generally we don't want localisation files with only one to two translations. It makes it harder for translators to handle in crowdin (a lot of file changes for small results). So for cases like this I believe we should be grouping translations where it makes sense. I've left individual components in their own files as I can see potential for more settings to be added in the future. Plus it gives a bit of extra context. --- .../FontAdjustableSkinComponentStrings.cs | 24 ---------- .../SkinnableComponentStrings.cs | 44 +++++++++++++++++++ .../SkinComponents/SkinnableSpriteStrings.cs | 24 ---------- .../SkinComponents/TextElementStrings.cs | 24 ---------- osu.Game/Skinning/Components/TextElement.cs | 2 +- .../Skinning/FontAdjustableSkinComponent.cs | 2 +- osu.Game/Skinning/SkinnableSprite.cs | 2 +- 7 files changed, 47 insertions(+), 75 deletions(-) delete mode 100644 osu.Game/Localisation/SkinComponents/FontAdjustableSkinComponentStrings.cs create mode 100644 osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs delete mode 100644 osu.Game/Localisation/SkinComponents/SkinnableSpriteStrings.cs delete mode 100644 osu.Game/Localisation/SkinComponents/TextElementStrings.cs diff --git a/osu.Game/Localisation/SkinComponents/FontAdjustableSkinComponentStrings.cs b/osu.Game/Localisation/SkinComponents/FontAdjustableSkinComponentStrings.cs deleted file mode 100644 index 8bcc45998a..0000000000 --- a/osu.Game/Localisation/SkinComponents/FontAdjustableSkinComponentStrings.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Localisation; - -namespace osu.Game.Localisation.SkinComponents -{ - public static class FontAdjustableSkinComponentStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.FontAdjustableSkinComponent"; - - /// - /// "Font" - /// - public static LocalisableString Font => new TranslatableString(getKey(@"font"), "Font"); - - /// - /// "The font to use." - /// - public static LocalisableString FontDescription => new TranslatableString(getKey(@"font_description"), "The font to use."); - - private static string getKey(string key) => $"{prefix}:{key}"; - } -} diff --git a/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs b/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs new file mode 100644 index 0000000000..547df86fc7 --- /dev/null +++ b/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs @@ -0,0 +1,44 @@ +// 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.Localisation; + +namespace osu.Game.Localisation.SkinComponents +{ + public static class SkinnableComponentStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.SkinnableComponentStrings"; + + /// + /// "Sprite name" + /// + public static LocalisableString SpriteName => new TranslatableString(getKey(@"sprite_name"), "Sprite name"); + + /// + /// "The filename of the sprite" + /// + public static LocalisableString SpriteNameDescription => new TranslatableString(getKey(@"sprite_name_description"), "The filename of the sprite"); + + /// + /// "Font" + /// + public static LocalisableString Font => new TranslatableString(getKey(@"font"), "Font"); + + /// + /// "The font to use." + /// + public static LocalisableString FontDescription => new TranslatableString(getKey(@"font_description"), "The font to use."); + + /// + /// "Text" + /// + public static LocalisableString TextElementText => new TranslatableString(getKey(@"text_element_text"), "Text"); + + /// + /// "The text to be displayed." + /// + public static LocalisableString TextElementTextDescription => new TranslatableString(getKey(@"text_element_text_description"), "The text to be displayed."); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/SkinComponents/SkinnableSpriteStrings.cs b/osu.Game/Localisation/SkinComponents/SkinnableSpriteStrings.cs deleted file mode 100644 index f039c9044f..0000000000 --- a/osu.Game/Localisation/SkinComponents/SkinnableSpriteStrings.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Localisation; - -namespace osu.Game.Localisation.SkinComponents -{ - public static class SkinnableSpriteStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.SkinnableSprite"; - - /// - /// "Sprite name" - /// - public static LocalisableString SpriteName => new TranslatableString(getKey(@"sprite_name"), "Sprite name"); - - /// - /// "The filename of the sprite" - /// - public static LocalisableString SpriteNameDescription => new TranslatableString(getKey(@"sprite_name_description"), "The filename of the sprite"); - - private static string getKey(string key) => $"{prefix}:{key}"; - } -} diff --git a/osu.Game/Localisation/SkinComponents/TextElementStrings.cs b/osu.Game/Localisation/SkinComponents/TextElementStrings.cs deleted file mode 100644 index 6417c1d923..0000000000 --- a/osu.Game/Localisation/SkinComponents/TextElementStrings.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Localisation; - -namespace osu.Game.Localisation.SkinComponents -{ - public static class TextElementStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.TextElement"; - - /// - /// "Text" - /// - public static LocalisableString TextElementText => new TranslatableString(getKey(@"text_element_text"), "Text"); - - /// - /// "The text to be displayed." - /// - public static LocalisableString TextElementTextDescription => new TranslatableString(getKey(@"text_element_text_description"), "The text to be displayed."); - - private static string getKey(string key) => $"{prefix}:{key}"; - } -} diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs index 1e0a0d0ad1..936f6a529b 100644 --- a/osu.Game/Skinning/Components/TextElement.cs +++ b/osu.Game/Skinning/Components/TextElement.cs @@ -15,7 +15,7 @@ namespace osu.Game.Skinning.Components [UsedImplicitly] public partial class TextElement : FontAdjustableSkinComponent { - [SettingSource(typeof(TextElementStrings), nameof(TextElementStrings.TextElementText), nameof(TextElementStrings.TextElementTextDescription))] + [SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.TextElementText), nameof(SkinnableComponentStrings.TextElementTextDescription))] public Bindable Text { get; } = new Bindable("Circles!"); private readonly OsuSpriteText text; diff --git a/osu.Game/Skinning/FontAdjustableSkinComponent.cs b/osu.Game/Skinning/FontAdjustableSkinComponent.cs index 11d3e36d9e..2e41b35abb 100644 --- a/osu.Game/Skinning/FontAdjustableSkinComponent.cs +++ b/osu.Game/Skinning/FontAdjustableSkinComponent.cs @@ -17,7 +17,7 @@ namespace osu.Game.Skinning { public bool UsesFixedAnchor { get; set; } - [SettingSource(typeof(FontAdjustableSkinComponentStrings), nameof(FontAdjustableSkinComponentStrings.Font), nameof(FontAdjustableSkinComponentStrings.FontDescription))] + [SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.Font), nameof(SkinnableComponentStrings.FontDescription))] public Bindable Font { get; } = new Bindable(Typeface.Torus); /// diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 31391755a3..c3449562c3 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -28,7 +28,7 @@ namespace osu.Game.Skinning [Resolved] private TextureStore textures { get; set; } = null!; - [SettingSource(typeof(SkinnableSpriteStrings), nameof(SkinnableSpriteStrings.SpriteName), nameof(SkinnableSpriteStrings.SpriteNameDescription), SettingControlType = typeof(SpriteSelectorControl))] + [SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.SpriteName), nameof(SkinnableComponentStrings.SpriteNameDescription), SettingControlType = typeof(SpriteSelectorControl))] public Bindable SpriteName { get; } = new Bindable(string.Empty); [Resolved] From a1200b8fe87fb5c56e34469dcc21e9d2470f4584 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 16:24:19 +0900 Subject: [PATCH 123/516] 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 124/516] 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 125/516] 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 14524237acb85e77c8253484d4c78c3adf5b6340 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 3 Feb 2023 10:32:41 +0300 Subject: [PATCH 126/516] Add comment explaining texelSize value --- osu.Game/Graphics/Backgrounds/Triangles.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index ca5f5d06d3..598278b2e4 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -253,7 +253,6 @@ namespace osu.Game.Graphics.Backgrounds private class TrianglesDrawNode : DrawNode { private float fill = 1f; - private float texelSize = 0f; protected new Triangles Source => (Triangles)base.Source; @@ -295,6 +294,11 @@ namespace osu.Game.Graphics.Backgrounds vertexBatch = renderer.CreateQuadBatch(Source.AimCount, 1); } + //Due to triangles having various sizes we would need to set a different "texelSize" value for each of them, which is insanely expensive, thus we should use one single value. + //texelSize computed for an average triangle (size 100) will result in big triangles becoming blurry, so we may just use 0 for all of them. + //But we still need to specify at least something, because otherwise other shader usages will override this value. + float texelSize = 0f; + shader.Bind(); shader.GetUniform("thickness").UpdateValue(ref fill); shader.GetUniform("texelSize").UpdateValue(ref texelSize); From bc02fb0e3280fd2035e26e61168457e5f3c25d9f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 16:37:02 +0900 Subject: [PATCH 127/516] Remove redundant parameter in `DrumSegment` constructor --- .../UI/DrumTouchInputArea.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index cf697cf061..29ccd96675 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -71,27 +71,27 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - leftRim = new DrumSegment(TaikoAction.LeftRim) + leftRim = new DrumSegment { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, }, - rightRim = new DrumSegment(TaikoAction.RightCentre) + rightRim = new DrumSegment { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = 2, Rotation = 90, }, - leftCentre = new DrumSegment(TaikoAction.LeftCentre) + leftCentre = new DrumSegment { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, X = -2, Scale = new Vector2(centre_region), }, - rightCentre = new DrumSegment(TaikoAction.RightRim) + rightCentre = new DrumSegment { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomRight, @@ -192,9 +192,6 @@ namespace osu.Game.Rulesets.Taiko.UI trackedActions.Remove(source); } - private bool validMouse(MouseButtonEvent e) => - leftRim.Contains(e.ScreenSpaceMouseDownPosition) || rightRim.Contains(e.ScreenSpaceMouseDownPosition); - private TaikoAction getTaikoActionFromPosition(Vector2 inputPosition) { bool centreHit = leftCentre.Contains(inputPosition) || rightCentre.Contains(inputPosition); @@ -242,10 +239,8 @@ namespace osu.Game.Rulesets.Taiko.UI public override bool Contains(Vector2 screenSpacePos) => circle.Contains(screenSpacePos); - public DrumSegment(TaikoAction action) + public DrumSegment() { - Action = action; - RelativeSizeAxes = Axes.Both; FillMode = FillMode.Fit; @@ -305,7 +300,7 @@ namespace osu.Game.Rulesets.Taiko.UI if (!IsLoaded) return; - var colour = getColourFromTaikoAction(action); + var colour = getColourFromTaikoAction(Action); circle.Colour = colour.Multiply(1.4f).Darken(2.8f); overlay.Colour = colour; From 7b9239088bca1678a33227ac161f7c2a16cd098d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 16:40:16 +0900 Subject: [PATCH 128/516] Comment space addition --- osu.Game/Graphics/Backgrounds/Triangles.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 598278b2e4..68ece56d8a 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -294,9 +294,9 @@ namespace osu.Game.Graphics.Backgrounds vertexBatch = renderer.CreateQuadBatch(Source.AimCount, 1); } - //Due to triangles having various sizes we would need to set a different "texelSize" value for each of them, which is insanely expensive, thus we should use one single value. - //texelSize computed for an average triangle (size 100) will result in big triangles becoming blurry, so we may just use 0 for all of them. - //But we still need to specify at least something, because otherwise other shader usages will override this value. + // Due to triangles having various sizes we would need to set a different "texelSize" value for each of them, which is insanely expensive, thus we should use one single value. + // texelSize computed for an average triangle (size 100) will result in big triangles becoming blurry, so we may just use 0 for all of them. + // But we still need to specify at least something, because otherwise other shader usages will override this value. float texelSize = 0f; shader.Bind(); From 6135db6bd720eaa92be7204a6dc57dc138100c89 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 2 Feb 2023 23:43:08 -0800 Subject: [PATCH 129/516] Revert moving hover sounds to content container --- osu.Game/Graphics/Containers/OsuClickableContainer.cs | 7 +++++-- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index ce50dbdc39..6fe1de2216 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -44,8 +44,11 @@ namespace osu.Game.Graphics.Containers content.AutoSizeAxes = AutoSizeAxes; } - AddInternal(content); - Add(CreateHoverSounds(sampleSet)); + AddRangeInternal(new Drawable[] + { + content, + CreateHoverSounds(sampleSet) + }); } protected override void ClearInternal(bool disposeChildren = true) => diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 805dfcaa95..6467ae5783 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -116,7 +116,7 @@ namespace osu.Game.Graphics.UserInterface }); if (hoverSounds.HasValue) - Add(new HoverClickSounds(hoverSounds.Value) { Enabled = { BindTarget = Enabled } }); + AddInternal(new HoverClickSounds(hoverSounds.Value) { Enabled = { BindTarget = Enabled } }); } [BackgroundDependencyLoader] From 60ccf35125a5f95b5f6c5b6a973a336fcec07a9d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 16:44:53 +0900 Subject: [PATCH 130/516] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d4ea0abbb5..cdb3d9b66b 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From 77569058cb415970e2fba96c3b174c3dbdcdfbae Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 2 Feb 2023 23:45:54 -0800 Subject: [PATCH 131/516] Alternatively fix hover sounds playing out of clicking bounds --- .../Graphics/UserInterface/HoverSampleDebounceComponent.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs index 53f1c06a67..959b0c6bd4 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Configuration; +using osuTK; namespace osu.Game.Graphics.UserInterface { @@ -18,6 +19,8 @@ namespace osu.Game.Graphics.UserInterface { private Bindable lastPlaybackTime; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; + [BackgroundDependencyLoader] private void load(SessionStatics statics) { From f27bf3ca20d7cf1a8b8d11326e33108795da0f34 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 2 Feb 2023 23:54:57 -0800 Subject: [PATCH 132/516] Fix click sounds potentially not working --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index ed1838abd0..884834ebe8 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -44,7 +44,7 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnClick(ClickEvent e) { - if (buttons.Contains(e.Button) && Contains(e.ScreenSpaceMousePosition)) + if (buttons.Contains(e.Button)) { var channel = Enabled.Value ? sampleClick?.GetChannel() : sampleClickDisabled?.GetChannel(); From b19047b90b9847e58cd2c98a9653aab908474dc9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 16:55:51 +0900 Subject: [PATCH 133/516] Fix skin editor component list having uneven padding --- osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs | 2 +- osu.Game/Screens/Edit/Components/EditorSidebar.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index 6017a98944..a8d64c1de8 100644 --- a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.SkinEditor RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, - Spacing = new Vector2(2) + Spacing = new Vector2(EditorSidebar.PADDING) }; reloadComponents(); diff --git a/osu.Game/Screens/Edit/Components/EditorSidebar.cs b/osu.Game/Screens/Edit/Components/EditorSidebar.cs index 9a8c5115dd..24e21ceafe 100644 --- a/osu.Game/Screens/Edit/Components/EditorSidebar.cs +++ b/osu.Game/Screens/Edit/Components/EditorSidebar.cs @@ -18,6 +18,8 @@ namespace osu.Game.Screens.Edit.Components { public const float WIDTH = 250; + public const float PADDING = 3; + private readonly Box background; protected override Container Content { get; } @@ -35,13 +37,13 @@ namespace osu.Game.Screens.Edit.Components }, new OsuScrollContainer { - Padding = new MarginPadding { Left = 20 }, ScrollbarOverlapsContent = false, RelativeSizeAxes = Axes.Both, Child = Content = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(PADDING), Direction = FillDirection.Vertical, }, } From 554f14151cf69d63379e38b0c301180ad687a2e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 17:13:24 +0900 Subject: [PATCH 134/516] Apply NRT to `EditorChangeHandler` --- osu.Game/Screens/Edit/EditorChangeHandler.cs | 4 +--- osu.Game/Screens/Edit/TransactionalCommitComponent.cs | 8 +++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorChangeHandler.cs b/osu.Game/Screens/Edit/EditorChangeHandler.cs index 964b86cad3..fd954b309c 100644 --- a/osu.Game/Screens/Edit/EditorChangeHandler.cs +++ b/osu.Game/Screens/Edit/EditorChangeHandler.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 System.Collections.Generic; using System.IO; @@ -23,7 +21,7 @@ namespace osu.Game.Screens.Edit public readonly Bindable CanUndo = new Bindable(); public readonly Bindable CanRedo = new Bindable(); - public event Action OnStateChange; + public event Action? OnStateChange; private readonly LegacyEditorBeatmapPatcher patcher; private readonly List savedStates = new List(); diff --git a/osu.Game/Screens/Edit/TransactionalCommitComponent.cs b/osu.Game/Screens/Edit/TransactionalCommitComponent.cs index 55c9cf86c3..f8362523f1 100644 --- a/osu.Game/Screens/Edit/TransactionalCommitComponent.cs +++ b/osu.Game/Screens/Edit/TransactionalCommitComponent.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.Graphics; @@ -16,17 +14,17 @@ namespace osu.Game.Screens.Edit /// /// Fires whenever a transaction begins. Will not fire on nested transactions. /// - public event Action TransactionBegan; + public event Action? TransactionBegan; /// /// Fires when the last transaction completes. /// - public event Action TransactionEnded; + public event Action? TransactionEnded; /// /// Fires when is called and results in a non-transactional state save. /// - public event Action SaveStateTriggered; + public event Action? SaveStateTriggered; public bool TransactionActive => bulkChangesStarted > 0; From b437501b0fff6ee60211eda5c59d008a0db250d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 17:28:55 +0900 Subject: [PATCH 135/516] Fix beatmap editor positional nudging not being undoable --- .../Components/ComposeBlueprintContainer.cs | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 836fceea22..453e4b9130 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -91,6 +91,8 @@ namespace osu.Game.Screens.Edit.Compose.Components blueprint.DrawableObject = drawableObject; } + private bool nudgeMovementActive; + protected override bool OnKeyDown(KeyDownEvent e) { if (e.ControlPressed) @@ -98,19 +100,19 @@ namespace osu.Game.Screens.Edit.Compose.Components switch (e.Key) { case Key.Left: - moveSelection(new Vector2(-1, 0)); + nudgeSelection(new Vector2(-1, 0)); return true; case Key.Right: - moveSelection(new Vector2(1, 0)); + nudgeSelection(new Vector2(1, 0)); return true; case Key.Up: - moveSelection(new Vector2(0, -1)); + nudgeSelection(new Vector2(0, -1)); return true; case Key.Down: - moveSelection(new Vector2(0, 1)); + nudgeSelection(new Vector2(0, 1)); return true; } } @@ -118,12 +120,29 @@ namespace osu.Game.Screens.Edit.Compose.Components return false; } + protected override void OnKeyUp(KeyUpEvent e) + { + base.OnKeyUp(e); + + if (nudgeMovementActive && !e.ControlPressed) + { + Beatmap.EndChange(); + nudgeMovementActive = false; + } + } + /// /// Move the current selection spatially by the specified delta, in gamefield coordinates (ie. the same coordinates as the blueprints). /// /// - private void moveSelection(Vector2 delta) + private void nudgeSelection(Vector2 delta) { + if (!nudgeMovementActive) + { + nudgeMovementActive = true; + Beatmap.BeginChange(); + } + var firstBlueprint = SelectionHandler.SelectedBlueprints.FirstOrDefault(); if (firstBlueprint == null) From 5a76c1ab9c0278bf4323fb222b906de901d874b1 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 3 Feb 2023 00:29:25 -0800 Subject: [PATCH 136/516] Refactor `HoverSampleDebounceComponent` to inherit `Component` --- .../HoverSampleDebounceComponent.cs | 4 ++-- .../Screens/Select/Carousel/CarouselHeader.cs | 22 +++++++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs index 959b0c6bd4..81f146b9ce 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs @@ -5,7 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Game.Configuration; using osuTK; @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface /// /// Handles debouncing hover sounds at a global level to ensure the effects are not overwhelming. /// - public abstract partial class HoverSampleDebounceComponent : CompositeDrawable + public abstract partial class HoverSampleDebounceComponent : Component { private Bindable lastPlaybackTime; diff --git a/osu.Game/Screens/Select/Carousel/CarouselHeader.cs b/osu.Game/Screens/Select/Carousel/CarouselHeader.cs index e46f0da45d..7e668fcd87 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselHeader.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselHeader.cs @@ -46,7 +46,8 @@ namespace osu.Game.Screens.Select.Carousel Children = new Drawable[] { Content, - hoverLayer = new HoverLayer() + hoverLayer = new HoverLayer(), + new HeaderSounds(), } }; } @@ -91,10 +92,8 @@ namespace osu.Game.Screens.Select.Carousel } } - public partial class HoverLayer : HoverSampleDebounceComponent + public partial class HoverLayer : CompositeDrawable { - private Sample? sampleHover; - private Box box = null!; public HoverLayer() @@ -103,7 +102,7 @@ namespace osu.Game.Screens.Select.Carousel } [BackgroundDependencyLoader] - private void load(AudioManager audio, OsuColour colours) + private void load(OsuColour colours) { InternalChild = box = new Box { @@ -112,8 +111,6 @@ namespace osu.Game.Screens.Select.Carousel Blending = BlendingParameters.Additive, RelativeSizeAxes = Axes.Both, }; - - sampleHover = audio.Samples.Get("UI/default-hover"); } public bool InsetForBorder @@ -147,6 +144,17 @@ namespace osu.Game.Screens.Select.Carousel box.FadeOut(1000, Easing.OutQuint); base.OnHoverLost(e); } + } + + private partial class HeaderSounds : HoverSampleDebounceComponent + { + private Sample? sampleHover; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleHover = audio.Samples.Get("UI/default-hover"); + } public override void PlayHoverSample() { From 94d2799b906a80f7131623f8478bd01dc60aba4b Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 3 Feb 2023 00:47:10 -0800 Subject: [PATCH 137/516] Fix comments having too much padding at the bottom --- osu.Game/Overlays/Comments/DrawableComment.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 4cc189f3a2..52a207afcd 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -76,6 +76,7 @@ namespace osu.Game.Overlays.Comments private GridContainer content = null!; private VotePill votePill = null!; private Container replyEditorContainer = null!; + private Container repliesButtonContainer = null!; [Resolved] private IDialogOverlay? dialogOverlay { get; set; } @@ -239,10 +240,12 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, Padding = new MarginPadding { Top = 10 }, + Alpha = 0, }, - new Container + repliesButtonContainer = new Container { AutoSizeAxes = Axes.Both, + Alpha = 0, Children = new Drawable[] { showRepliesButton = new ShowRepliesButton(Comment.RepliesCount) @@ -449,6 +452,7 @@ namespace osu.Game.Overlays.Comments { if (replyEditorContainer.Count == 0) { + replyEditorContainer.Show(); replyEditorContainer.Add(new ReplyCommentEditor(Comment) { OnPost = comments => @@ -462,6 +466,7 @@ namespace osu.Game.Overlays.Comments else { replyEditorContainer.Clear(true); + replyEditorContainer.Hide(); } } @@ -513,9 +518,11 @@ namespace osu.Game.Overlays.Comments int loadedRepliesCount = loadedReplies.Count; bool hasUnloadedReplies = loadedRepliesCount != Comment.RepliesCount; - loadRepliesButton.FadeTo(hasUnloadedReplies && loadedRepliesCount == 0 ? 1 : 0); - showMoreButton.FadeTo(hasUnloadedReplies && loadedRepliesCount > 0 ? 1 : 0); showRepliesButton.FadeTo(loadedRepliesCount != 0 ? 1 : 0); + loadRepliesButton.FadeTo(hasUnloadedReplies && loadedRepliesCount == 0 ? 1 : 0); + repliesButtonContainer.FadeTo(showRepliesButton.IsPresent || loadRepliesButton.IsPresent ? 1 : 0); + + showMoreButton.FadeTo(hasUnloadedReplies && loadedRepliesCount > 0 ? 1 : 0); if (Comment.IsTopLevel) chevronButton.FadeTo(loadedRepliesCount != 0 ? 1 : 0); From 3345e345441db6f089682b1bbb07b1be791fd384 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 17:53:54 +0900 Subject: [PATCH 138/516] Move beatmap specific logic out of `EditorChangeHandler` --- ...t.cs => BeatmapEditorChangeHandlerTest.cs} | 6 +-- .../Edit/BeatmapEditorChangeHandler.cs | 43 +++++++++++++++++++ osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Edit/EditorChangeHandler.cs | 36 ++++------------ 4 files changed, 54 insertions(+), 33 deletions(-) rename osu.Game.Tests/Editing/{EditorChangeHandlerTest.cs => BeatmapEditorChangeHandlerTest.cs} (97%) create mode 100644 osu.Game/Screens/Edit/BeatmapEditorChangeHandler.cs diff --git a/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs b/osu.Game.Tests/Editing/BeatmapEditorChangeHandlerTest.cs similarity index 97% rename from osu.Game.Tests/Editing/EditorChangeHandlerTest.cs rename to osu.Game.Tests/Editing/BeatmapEditorChangeHandlerTest.cs index e1accd5b5f..4746f84fa0 100644 --- a/osu.Game.Tests/Editing/EditorChangeHandlerTest.cs +++ b/osu.Game.Tests/Editing/BeatmapEditorChangeHandlerTest.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 NUnit.Framework; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Beatmaps; @@ -12,7 +10,7 @@ using osu.Game.Screens.Edit; namespace osu.Game.Tests.Editing { [TestFixture] - public class EditorChangeHandlerTest + public class BeatmapEditorChangeHandlerTest { private int stateChangedFired; @@ -169,7 +167,7 @@ namespace osu.Game.Tests.Editing }, }); - var changeHandler = new EditorChangeHandler(beatmap); + var changeHandler = new BeatmapEditorChangeHandler(beatmap); changeHandler.OnStateChange += () => stateChangedFired++; return (changeHandler, beatmap); diff --git a/osu.Game/Screens/Edit/BeatmapEditorChangeHandler.cs b/osu.Game/Screens/Edit/BeatmapEditorChangeHandler.cs new file mode 100644 index 0000000000..b9349a31af --- /dev/null +++ b/osu.Game/Screens/Edit/BeatmapEditorChangeHandler.cs @@ -0,0 +1,43 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.IO; +using System.Text; +using osu.Game.Beatmaps.Formats; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Screens.Edit +{ + public partial class BeatmapEditorChangeHandler : EditorChangeHandler + { + private readonly LegacyEditorBeatmapPatcher patcher; + private readonly EditorBeatmap editorBeatmap; + + /// + /// Creates a new . + /// + /// The to track the s of. + public BeatmapEditorChangeHandler(EditorBeatmap editorBeatmap) + { + this.editorBeatmap = editorBeatmap; + + editorBeatmap.TransactionBegan += BeginChange; + editorBeatmap.TransactionEnded += EndChange; + editorBeatmap.SaveStateTriggered += SaveState; + + patcher = new LegacyEditorBeatmapPatcher(editorBeatmap); + + // Initial state. + SaveState(); + } + + protected override void WriteCurrentStateToStream(MemoryStream stream) + { + using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) + new LegacyBeatmapEncoder(editorBeatmap, editorBeatmap.BeatmapSkin).Encode(sw); + } + + protected override void ApplyStateChange(byte[] previousState, byte[] newState) => + patcher.Patch(previousState, newState); + } +} diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 74ea933255..0622cbebae 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -240,7 +240,7 @@ namespace osu.Game.Screens.Edit if (canSave) { - changeHandler = new EditorChangeHandler(editorBeatmap); + changeHandler = new BeatmapEditorChangeHandler(editorBeatmap); dependencies.CacheAs(changeHandler); } diff --git a/osu.Game/Screens/Edit/EditorChangeHandler.cs b/osu.Game/Screens/Edit/EditorChangeHandler.cs index fd954b309c..0391da6d86 100644 --- a/osu.Game/Screens/Edit/EditorChangeHandler.cs +++ b/osu.Game/Screens/Edit/EditorChangeHandler.cs @@ -5,25 +5,21 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using osu.Framework.Bindables; using osu.Framework.Extensions; -using osu.Game.Beatmaps.Formats; -using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Edit { /// /// Tracks changes to the . /// - public partial class EditorChangeHandler : TransactionalCommitComponent, IEditorChangeHandler + public abstract partial class EditorChangeHandler : TransactionalCommitComponent, IEditorChangeHandler { public readonly Bindable CanUndo = new Bindable(); public readonly Bindable CanRedo = new Bindable(); public event Action? OnStateChange; - private readonly LegacyEditorBeatmapPatcher patcher; private readonly List savedStates = new List(); private int currentState = -1; @@ -40,29 +36,10 @@ namespace osu.Game.Screens.Edit } } - private readonly EditorBeatmap editorBeatmap; private bool isRestoring; public const int MAX_SAVED_STATES = 50; - /// - /// Creates a new . - /// - /// The to track the s of. - public EditorChangeHandler(EditorBeatmap editorBeatmap) - { - this.editorBeatmap = editorBeatmap; - - editorBeatmap.TransactionBegan += BeginChange; - editorBeatmap.TransactionEnded += EndChange; - editorBeatmap.SaveStateTriggered += SaveState; - - patcher = new LegacyEditorBeatmapPatcher(editorBeatmap); - - // Initial state. - SaveState(); - } - protected override void UpdateState() { if (isRestoring) @@ -70,9 +47,7 @@ namespace osu.Game.Screens.Edit using (var stream = new MemoryStream()) { - using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) - new LegacyBeatmapEncoder(editorBeatmap, editorBeatmap.BeatmapSkin).Encode(sw); - + WriteCurrentStateToStream(stream); byte[] newState = stream.ToArray(); // if the previous state is binary equal we don't need to push a new one, unless this is the initial state. @@ -111,7 +86,8 @@ namespace osu.Game.Screens.Edit isRestoring = true; - patcher.Patch(savedStates[currentState], savedStates[newState]); + ApplyStateChange(savedStates[currentState], savedStates[newState]); + currentState = newState; isRestoring = false; @@ -120,6 +96,10 @@ namespace osu.Game.Screens.Edit updateBindables(); } + protected abstract void WriteCurrentStateToStream(MemoryStream stream); + + protected abstract void ApplyStateChange(byte[] previousState, byte[] newState); + private void updateBindables() { CanUndo.Value = savedStates.Count > 0 && currentState > 0; From 2f30306ea204dfe8809ff0cb26effe6284a0d41a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 18:53:09 +0900 Subject: [PATCH 139/516] Expose a method to reload a `SkinnableTargetContainer` from provided info --- osu.Game/Skinning/ISkinnableTarget.cs | 5 ++++ osu.Game/Skinning/SkinnableTargetContainer.cs | 27 +++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISkinnableTarget.cs index 57c78bfe1c..70b80f3fed 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISkinnableTarget.cs @@ -36,6 +36,11 @@ namespace osu.Game.Skinning /// void Reload(); + /// + /// Reload this target from the provided skinnable information. + /// + public void Reload(SkinnableInfo[] skinnableInfo); + /// /// Add a new skinnable component to this target. /// diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index 794a12da82..df5299d427 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Screens.Play.HUD; namespace osu.Game.Skinning { @@ -30,16 +32,31 @@ namespace osu.Game.Skinning Target = target; } - /// - /// Reload all components in this container from the current skin. - /// - public void Reload() + public void Reload(SkinnableInfo[] skinnableInfo) + { + var drawables = new List(); + + foreach (var i in skinnableInfo) + drawables.Add(i.CreateInstance()); + + Reload(new SkinnableTargetComponentsContainer + { + Children = drawables, + }); + } + + public void Reload() => Reload(CurrentSkin.GetDrawableComponent(new GlobalSkinComponentLookup(Target)) as SkinnableTargetComponentsContainer); + + public void Reload(SkinnableTargetComponentsContainer? componentsContainer) { ClearInternal(); components.Clear(); ComponentsLoaded = false; - content = CurrentSkin.GetDrawableComponent(new GlobalSkinComponentLookup(Target)) as SkinnableTargetComponentsContainer; + if (componentsContainer == null) + return; + + content = componentsContainer; cancellationSource?.Cancel(); cancellationSource = null; From 2cda277c091b05f20f4774b5b7eb48f5f0a778f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Feb 2023 18:53:22 +0900 Subject: [PATCH 140/516] Add a basic change handler to the skin editor --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 52 ++++++++++++- .../SkinEditor/SkinEditorChangeHandler.cs | 73 +++++++++++++++++++ osu.Game/Screens/Edit/IEditorChangeHandler.cs | 6 +- 3 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 275cbd18d7..51cca96f4a 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -24,6 +24,7 @@ using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays.OSD; +using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Edit.Components.Menus; using osu.Game.Skinning; @@ -31,7 +32,7 @@ using osu.Game.Skinning; namespace osu.Game.Overlays.SkinEditor { [Cached(typeof(SkinEditor))] - public partial class SkinEditor : VisibilityContainer, ICanAcceptFiles, IKeyBindingHandler + public partial class SkinEditor : VisibilityContainer, ICanAcceptFiles, IKeyBindingHandler, IEditorChangeHandler { public const double TRANSITION_DURATION = 300; @@ -72,6 +73,11 @@ namespace osu.Game.Overlays.SkinEditor private EditorSidebar componentsSidebar = null!; private EditorSidebar settingsSidebar = null!; + private SkinEditorChangeHandler? changeHandler; + + private EditorMenuItem undoMenuItem = null!; + private EditorMenuItem redoMenuItem = null!; + [Resolved] private OnScreenDisplay? onScreenDisplay { get; set; } @@ -131,6 +137,14 @@ namespace osu.Game.Overlays.SkinEditor new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()), }, }, + new MenuItem(CommonStrings.MenuBarEdit) + { + Items = new[] + { + undoMenuItem = new EditorMenuItem(CommonStrings.Undo, MenuItemType.Standard, Undo), + redoMenuItem = new EditorMenuItem(CommonStrings.Redo, MenuItemType.Standard, Redo), + } + }, } }, headerText = new OsuTextFlowContainer @@ -210,6 +224,14 @@ namespace osu.Game.Overlays.SkinEditor { switch (e.Action) { + case PlatformAction.Undo: + Undo(); + return true; + + case PlatformAction.Redo: + Redo(); + return true; + case PlatformAction.Save: if (e.Repeat) return false; @@ -229,6 +251,8 @@ namespace osu.Game.Overlays.SkinEditor { this.targetScreen = targetScreen; + changeHandler?.Dispose(); + SelectedComponents.Clear(); // Immediately clear the previous blueprint container to ensure it doesn't try to interact with the old target. @@ -241,6 +265,10 @@ namespace osu.Game.Overlays.SkinEditor { Debug.Assert(content != null); + changeHandler = new SkinEditorChangeHandler(targetScreen); + changeHandler.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true); + changeHandler.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); + content.Child = new SkinBlueprintContainer(targetScreen); componentsSidebar.Child = new SkinComponentToolbox(getFirstTarget() as CompositeDrawable) @@ -301,6 +329,8 @@ namespace osu.Game.Overlays.SkinEditor SelectedComponents.Clear(); SelectedComponents.Add(component); + + changeHandler?.SaveState(); } private void populateSettings() @@ -333,6 +363,10 @@ namespace osu.Game.Overlays.SkinEditor } } + protected void Undo() => changeHandler?.RestoreState(-1); + + protected void Redo() => changeHandler?.RestoreState(1); + public void Save() { if (!hasBegunMutating) @@ -371,6 +405,8 @@ namespace osu.Game.Overlays.SkinEditor { foreach (var item in items) availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item); + + changeHandler?.SaveState(); } #region Drag & drop import handling @@ -435,5 +471,19 @@ namespace osu.Game.Overlays.SkinEditor { } } + + #region Delegation of IEditorChangeHandler + + public event Action? OnStateChange + { + add => changeHandler!.OnStateChange += value; + remove => changeHandler!.OnStateChange -= value; + } + + public void BeginChange() => changeHandler?.BeginChange(); + public void EndChange() => changeHandler?.EndChange(); + public void SaveState() => changeHandler?.SaveState(); + + #endregion } } diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs new file mode 100644 index 0000000000..95b24bbd6f --- /dev/null +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -0,0 +1,73 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Extensions; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Play.HUD; +using osu.Game.Skinning; + +namespace osu.Game.Overlays.SkinEditor +{ + public partial class SkinEditorChangeHandler : EditorChangeHandler + { + private readonly Drawable targetScreen; + + private ISkinnableTarget? firstTarget => targetScreen.ChildrenOfType().FirstOrDefault(); + + public SkinEditorChangeHandler(Drawable targetScreen) + { + // To keep things simple, we are currently only handling the current target screen for undo / redo. + // In the future we'll want this to cover all changes, even to skin's `InstantiationInfo`. + // We'll also need to consider cases where multiple targets are on screen at the same time. + + this.targetScreen = targetScreen; + + // Save initial state. + SaveState(); + } + + protected override void WriteCurrentStateToStream(MemoryStream stream) + { + if (firstTarget == null) + return; + + var skinnableInfos = firstTarget.CreateSkinnableInfo().ToArray(); + string json = JsonConvert.SerializeObject(skinnableInfos, new JsonSerializerSettings { Formatting = Formatting.Indented }); + stream.Write(Encoding.UTF8.GetBytes(json)); + } + + protected override void ApplyStateChange(byte[] previousState, byte[] newState) + { + if (firstTarget == null) + return; + + var deserializedContent = JsonConvert.DeserializeObject>(Encoding.UTF8.GetString(newState)); + + if (deserializedContent == null) + return; + + SkinnableInfo[] skinnableInfo = deserializedContent.ToArray(); + Drawable[] targetComponents = firstTarget.Components.OfType().ToArray(); + + if (!skinnableInfo.Select(s => s.Type).SequenceEqual(targetComponents.Select(d => d.GetType()))) + { + // Perform a naive full reload for now. + firstTarget.Reload(skinnableInfo); + } + else + { + int i = 0; + + foreach (var drawable in targetComponents) + drawable.ApplySkinnableInfo(skinnableInfo[i++]); + } + } + } +} diff --git a/osu.Game/Screens/Edit/IEditorChangeHandler.cs b/osu.Game/Screens/Edit/IEditorChangeHandler.cs index e7abc1c43d..9fe40ba1b1 100644 --- a/osu.Game/Screens/Edit/IEditorChangeHandler.cs +++ b/osu.Game/Screens/Edit/IEditorChangeHandler.cs @@ -1,9 +1,8 @@ // 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.Game.Rulesets.Objects; namespace osu.Game.Screens.Edit @@ -11,12 +10,13 @@ namespace osu.Game.Screens.Edit /// /// Interface for a component that manages changes in the . /// + [Cached] public interface IEditorChangeHandler { /// /// Fired whenever a state change occurs. /// - event Action OnStateChange; + event Action? OnStateChange; /// /// Begins a bulk state change event. should be invoked soon after. From 461b5c537571d29f1046215030a43fe1907c9705 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 3 Feb 2023 00:48:32 -0800 Subject: [PATCH 141/516] Fix comment cancel button not behaving the same as reply text toggle - Removed the fading animation as it is awkward right now (needs resizing) --- osu.Game/Overlays/Comments/DrawableComment.cs | 3 ++- osu.Game/Overlays/Comments/ReplyCommentEditor.cs | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 52a207afcd..869ed61a9c 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -460,7 +460,8 @@ namespace osu.Game.Overlays.Comments Comment.RepliesCount += comments.Length; showRepliesButton.Count = Comment.RepliesCount; Replies.AddRange(comments); - } + }, + OnCancel = toggleReply }); } else diff --git a/osu.Game/Overlays/Comments/ReplyCommentEditor.cs b/osu.Game/Overlays/Comments/ReplyCommentEditor.cs index e738e6e7ec..8aca183dee 100644 --- a/osu.Game/Overlays/Comments/ReplyCommentEditor.cs +++ b/osu.Game/Overlays/Comments/ReplyCommentEditor.cs @@ -4,7 +4,6 @@ using System; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Online.API; @@ -33,7 +32,6 @@ namespace osu.Game.Overlays.Comments public ReplyCommentEditor(Comment parent) { parentComment = parent; - OnCancel = () => this.FadeOut(200).Expire(); } protected override void LoadComplete() From 8c11e8e6f4994342f466ab1b5228c3d923b50d94 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 3 Feb 2023 11:58:10 +0100 Subject: [PATCH 142/516] Extract ShearedNub.cs implementation into its own entirely independent implementation --- osu.Game/Graphics/UserInterface/ShearedNub.cs | 155 +++++++++++++++++- 1 file changed, 150 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ShearedNub.cs b/osu.Game/Graphics/UserInterface/ShearedNub.cs index 6bee4fc3b7..390d6ff9be 100644 --- a/osu.Game/Graphics/UserInterface/ShearedNub.cs +++ b/osu.Game/Graphics/UserInterface/ShearedNub.cs @@ -1,26 +1,41 @@ // 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.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Overlays; using osuTK; +using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { - public partial class ShearedNub : Nub + public partial class ShearedNub : Container, IHasCurrentValue, IHasAccentColour { + protected const float BORDER_WIDTH = 3; + public const int HEIGHT = 30; public const float EXPANDED_SIZE = 50; public static readonly Vector2 SHEAR = new Vector2(0.15f, 0); + private readonly Box fill; + private readonly Container main; + + /// + /// Implements the shape for the nub, allowing for any type of container to be used. + /// + /// public ShearedNub() { Size = new Vector2(EXPANDED_SIZE, HEIGHT); - } - - protected override Container CreateNubContainer() => - new Container + InternalChild = main = new Container { Shear = SHEAR, BorderColour = Colour4.White, @@ -30,6 +45,136 @@ namespace osu.Game.Graphics.UserInterface RelativeSizeAxes = Axes.Both, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, + Child = fill = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + } }; + } + + [BackgroundDependencyLoader(true)] + private void load(OverlayColourProvider? colourProvider, OsuColour colours) + { + AccentColour = colourProvider?.Highlight1 ?? colours.Pink; + GlowingAccentColour = colourProvider?.Highlight1.Lighten(0.2f) ?? colours.PinkLighter; + GlowColour = colourProvider?.Highlight1 ?? colours.PinkLighter; + + main.EdgeEffect = new EdgeEffectParameters + { + Colour = GlowColour.Opacity(0), + Type = EdgeEffectType.Glow, + Radius = 8, + Roundness = 4, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindValueChanged(onCurrentValueChanged, true); + } + + private bool glowing; + + public bool Glowing + { + get => glowing; + set + { + glowing = value; + + if (value) + { + main.FadeColour(GlowingAccentColour.Lighten(0.5f), 40, Easing.OutQuint) + .Then() + .FadeColour(GlowingAccentColour, 800, Easing.OutQuint); + + main.FadeEdgeEffectTo(Color4.White.Opacity(0.1f), 40, Easing.OutQuint) + .Then() + .FadeEdgeEffectTo(GlowColour.Opacity(0.1f), 800, Easing.OutQuint); + } + else + { + main.FadeEdgeEffectTo(GlowColour.Opacity(0), 800, Easing.OutQuint); + main.FadeColour(AccentColour, 800, Easing.OutQuint); + } + } + } + + private readonly Bindable current = new Bindable(); + + public Bindable Current + { + get => current; + set + { + ArgumentNullException.ThrowIfNull(value); + + current.UnbindBindings(); + current.BindTo(value); + } + } + + private Color4 accentColour; + + public Color4 AccentColour + { + get => accentColour; + set + { + accentColour = value; + if (!Glowing) + main.Colour = value; + } + } + + private Color4 glowingAccentColour; + + public Color4 GlowingAccentColour + { + get => glowingAccentColour; + set + { + glowingAccentColour = value; + if (Glowing) + main.Colour = value; + } + } + + private Color4 glowColour; + + public Color4 GlowColour + { + get => glowColour; + set + { + glowColour = value; + + var effect = main.EdgeEffect; + effect.Colour = Glowing ? value : value.Opacity(0); + main.EdgeEffect = effect; + } + } + + private void onCurrentValueChanged(ValueChangedEvent filled) + { + const double duration = 200; + + fill.FadeTo(filled.NewValue ? 1 : 0, duration, Easing.OutQuint); + + if (filled.NewValue) + { + main.ResizeWidthTo(1, duration, Easing.OutElasticHalf); + main.TransformTo(nameof(BorderThickness), 8.5f, duration, Easing.OutElasticHalf); + } + else + { + main.ResizeWidthTo(0.75f, duration, Easing.OutQuint); + main.TransformTo(nameof(BorderThickness), BORDER_WIDTH, duration, Easing.OutQuint); + } + } } } From e1af5e110aa20f823daa29c959e2159ae15a4443 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 3 Feb 2023 12:19:09 +0100 Subject: [PATCH 143/516] Remove ```RoundedNub.cs``` and make ```Nub.cs``` non abstract again --- .../UserInterface/TestSceneRangeSlider.cs | 2 +- osu.Game/Graphics/UserInterface/Nub.cs | 48 ++++++++++++------- .../Graphics/UserInterface/OsuCheckbox.cs | 8 ++-- .../Graphics/UserInterface/RangeSlider.cs | 2 +- osu.Game/Graphics/UserInterface/RoundedNub.cs | 32 ------------- .../UserInterface/RoundedSliderBar.cs | 8 ++-- 6 files changed, 41 insertions(+), 59 deletions(-) delete mode 100644 osu.Game/Graphics/UserInterface/RoundedNub.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs index 1b91459615..b780764e7f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.UserInterface LowerBound = customStart, UpperBound = customEnd, TooltipSuffix = "suffix", - NubWidth = RoundedNub.HEIGHT * 2, + NubWidth = Nub.HEIGHT * 2, DefaultStringLowerBound = "Start", DefaultStringUpperBound = "End", MinRange = 10 diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 6f875e8594..28a2eb40c3 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osuTK; +using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -11,33 +13,45 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Overlays; -using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { - public abstract partial class Nub : Container, IHasCurrentValue, IHasAccentColour + public partial class Nub : Container, IHasCurrentValue, IHasAccentColour { - protected const float BORDER_WIDTH = 3; + public const float HEIGHT = 15; + + public const float EXPANDED_SIZE = 50; + + private const float border_width = 3; private readonly Box fill; private readonly Container main; - /// - /// Implements the shape for the nub, allowing for any type of container to be used. - /// - /// - protected abstract Container CreateNubContainer(); - - protected Nub() + public Nub() { - InternalChild = main = CreateNubContainer(); + Size = new Vector2(EXPANDED_SIZE, HEIGHT); - main.Add(fill = new Box + InternalChildren = new[] { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true, - }); + main = new CircularContainer + { + BorderColour = Color4.White, + BorderThickness = border_width, + Masking = true, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Children = new Drawable[] + { + fill = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + }, + } + }, + }; } [BackgroundDependencyLoader(true)] @@ -159,7 +173,7 @@ namespace osu.Game.Graphics.UserInterface else { main.ResizeWidthTo(0.75f, duration, Easing.OutQuint); - main.TransformTo(nameof(BorderThickness), BORDER_WIDTH, duration, Easing.OutQuint); + main.TransformTo(nameof(BorderThickness), border_width, duration, Easing.OutQuint); } } } diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs index 2fae4e2cb5..160105af1a 100644 --- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs @@ -41,7 +41,7 @@ namespace osu.Game.Graphics.UserInterface } } - protected readonly RoundedNub Nub; + protected readonly Nub Nub; protected readonly OsuTextFlowContainer LabelTextFlowContainer; private Sample sampleChecked; @@ -61,7 +61,7 @@ namespace osu.Game.Graphics.UserInterface AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, }, - Nub = new RoundedNub(), + Nub = new Nub(), new HoverSounds() }; @@ -70,14 +70,14 @@ namespace osu.Game.Graphics.UserInterface Nub.Anchor = Anchor.CentreRight; Nub.Origin = Anchor.CentreRight; Nub.Margin = new MarginPadding { Right = nub_padding }; - LabelTextFlowContainer.Padding = new MarginPadding { Right = RoundedNub.EXPANDED_SIZE + nub_padding * 2 }; + LabelTextFlowContainer.Padding = new MarginPadding { Right = Nub.EXPANDED_SIZE + nub_padding * 2 }; } else { Nub.Anchor = Anchor.CentreLeft; Nub.Origin = Anchor.CentreLeft; Nub.Margin = new MarginPadding { Left = nub_padding }; - LabelTextFlowContainer.Padding = new MarginPadding { Left = RoundedNub.EXPANDED_SIZE + nub_padding * 2 }; + LabelTextFlowContainer.Padding = new MarginPadding { Left = Nub.EXPANDED_SIZE + nub_padding * 2 }; } Nub.Current.BindTo(Current); diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs index 575327b50b..f83dff6295 100644 --- a/osu.Game/Graphics/UserInterface/RangeSlider.cs +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -163,7 +163,7 @@ namespace osu.Game.Graphics.UserInterface public string? DefaultString; public LocalisableString? DefaultTooltip; public string? TooltipSuffix; - public float NubWidth { get; set; } = RoundedNub.HEIGHT; + public float NubWidth { get; set; } = Nub.HEIGHT; public override LocalisableString TooltipText => (Current.IsDefault ? DefaultTooltip : Current.Value.ToString($@"0.## {TooltipSuffix}")) ?? Current.Value.ToString($@"0.## {TooltipSuffix}"); diff --git a/osu.Game/Graphics/UserInterface/RoundedNub.cs b/osu.Game/Graphics/UserInterface/RoundedNub.cs deleted file mode 100644 index 3bdfadfe22..0000000000 --- a/osu.Game/Graphics/UserInterface/RoundedNub.cs +++ /dev/null @@ -1,32 +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.Graphics; -using osu.Framework.Graphics.Containers; -using osuTK; - -namespace osu.Game.Graphics.UserInterface -{ - public partial class RoundedNub : Nub - { - public const float HEIGHT = 15; - - public const float EXPANDED_SIZE = 50; - - public RoundedNub() - { - Size = new Vector2(EXPANDED_SIZE, HEIGHT); - } - - protected override Container CreateNubContainer() => - new CircularContainer - { - BorderColour = Colour4.White, - BorderThickness = BORDER_WIDTH, - Masking = true, - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }; - } -} diff --git a/osu.Game/Graphics/UserInterface/RoundedSliderBar.cs b/osu.Game/Graphics/UserInterface/RoundedSliderBar.cs index 765e1d5105..a666b83c05 100644 --- a/osu.Game/Graphics/UserInterface/RoundedSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/RoundedSliderBar.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface public partial class RoundedSliderBar : OsuSliderBar where T : struct, IEquatable, IComparable, IConvertible { - protected readonly RoundedNub Nub; + protected readonly Nub Nub; protected readonly Box LeftBox; protected readonly Box RightBox; private readonly Container nubContainer; @@ -50,8 +50,8 @@ namespace osu.Game.Graphics.UserInterface public RoundedSliderBar() { - Height = RoundedNub.HEIGHT; - RangePadding = RoundedNub.EXPANDED_SIZE / 2; + Height = Nub.HEIGHT; + RangePadding = Nub.EXPANDED_SIZE / 2; Children = new Drawable[] { new Container @@ -93,7 +93,7 @@ namespace osu.Game.Graphics.UserInterface nubContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = Nub = new RoundedNub + Child = Nub = new Nub { Origin = Anchor.TopCentre, RelativePositionAxes = Axes.X, From f9809c948120ddccb36bd6e790e223b1503abe44 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Fri, 3 Feb 2023 11:48:11 -0300 Subject: [PATCH 144/516] the comment --- osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index ce1b0db76d..4e17627e04 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -54,6 +54,8 @@ namespace osu.Game.Overlays.Profile.Header.Components RelativeSizeAxes = Axes.Both, Colour = colourProvider?.Background6 ?? Colour4.Black, // Normal badges background opacity is 75%, probationary is full opacity as the whole badge gets a bit transparent + // Goal is to match osu-web so this is the most accurate it can be, its a bit scuffed but it is what it is + // Source: https://github.com/ppy/osu-web/blob/master/resources/css/bem/user-group-badge.less#L50 Alpha = group.IsProbationary ? 1 : 0.75f, }, innerContainer = new FillFlowContainer From 20e220df56894ff137693d649a4d531bd76c736f Mon Sep 17 00:00:00 2001 From: Wleter Date: Fri, 3 Feb 2023 16:05:16 +0100 Subject: [PATCH 145/516] prioritize closest snap position --- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 8a1d8f597c..f5bbac72d7 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -189,11 +189,14 @@ namespace osu.Game.Rulesets.Osu.Edit var snapPositions = b.ScreenSpaceSnapPoints; - var filteredSnapPositions = snapPositions.Cast().FirstOrDefault(p => Vector2.Distance(p.Value, screenSpacePosition) < snapRadius); + if (!snapPositions.Any()) + continue; + + var closestSnapPosition = snapPositions.MinBy(p => Vector2.Distance(p, screenSpacePosition)); - if (filteredSnapPositions.HasValue) + if (Vector2.Distance(closestSnapPosition, screenSpacePosition) < snapRadius) { - var snap = filteredSnapPositions.Value; + var snap = closestSnapPosition; // only return distance portion, since time is not really valid snapResult = new SnapResult(snap, null, playfield); From f7f13cb9d994521b31fb9c2cc9348b8bb3241ae9 Mon Sep 17 00:00:00 2001 From: Wleter Date: Fri, 3 Feb 2023 16:13:04 +0100 Subject: [PATCH 146/516] fix formatting --- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index f5bbac72d7..13e4ece73c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -191,7 +191,7 @@ namespace osu.Game.Rulesets.Osu.Edit if (!snapPositions.Any()) continue; - + var closestSnapPosition = snapPositions.MinBy(p => Vector2.Distance(p, screenSpacePosition)); if (Vector2.Distance(closestSnapPosition, screenSpacePosition) < snapRadius) From 60f648407382b6f38204d418d8cd811fc378482b Mon Sep 17 00:00:00 2001 From: Wleter Date: Fri, 3 Feb 2023 16:13:37 +0100 Subject: [PATCH 147/516] fix spaces --- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 13e4ece73c..1e6be988b4 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -191,7 +191,7 @@ namespace osu.Game.Rulesets.Osu.Edit if (!snapPositions.Any()) continue; - + var closestSnapPosition = snapPositions.MinBy(p => Vector2.Distance(p, screenSpacePosition)); if (Vector2.Distance(closestSnapPosition, screenSpacePosition) < snapRadius) From 13fc649edffb93224056ee49ab34353d661b8ee0 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Fri, 3 Feb 2023 18:22:51 +0100 Subject: [PATCH 148/516] Refactor test to more closely match how OsuGameDesktop works --- .../TestSceneInterProcessCommunication.cs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs index 346f1d9f90..a7a3d644e8 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs @@ -23,11 +23,12 @@ namespace osu.Game.Tests.Visual.Navigation { private HeadlessGameHost ipcSenderHost = null!; - private OsuSchemeLinkIPCChannel osuSchemeLinkIPCReceiver = null!; private OsuSchemeLinkIPCChannel osuSchemeLinkIPCSender = null!; private const int requested_beatmap_set_id = 1; + protected override TestOsuGame CreateTestGame() => new IpcGame(LocalStorage, API); + [Resolved] private GameHost gameHost { get; set; } = null!; @@ -56,7 +57,6 @@ namespace osu.Game.Tests.Visual.Navigation return false; }; }); - AddStep("create IPC receiver channel", () => osuSchemeLinkIPCReceiver = new OsuSchemeLinkIPCChannel(gameHost, Game)); AddStep("create IPC sender channel", () => { ipcSenderHost = new HeadlessGameHost(gameHost.Name, new HostOptions { BindIPC = true }); @@ -74,7 +74,6 @@ namespace osu.Game.Tests.Visual.Navigation public override void TearDownSteps() { - AddStep("dispose IPC receiver", () => osuSchemeLinkIPCReceiver.Dispose()); AddStep("dispose IPC sender", () => { osuSchemeLinkIPCSender.Dispose(); @@ -82,5 +81,27 @@ namespace osu.Game.Tests.Visual.Navigation }); base.TearDownSteps(); } + + private partial class IpcGame : TestOsuGame + { + private OsuSchemeLinkIPCChannel? osuSchemeLinkIPCChannel; + + public IpcGame(Storage storage, IAPIProvider api, string[]? args = null) + : base(storage, api, args) + { + } + + protected override void LoadComplete() + { + base.LoadComplete(); + osuSchemeLinkIPCChannel = new OsuSchemeLinkIPCChannel(Host, this); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + osuSchemeLinkIPCChannel?.Dispose(); + } + } } } From 364217829c8067f74fcfaa99b581dbe28e5ac898 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Fri, 3 Feb 2023 18:38:42 +0100 Subject: [PATCH 149/516] Add test for ArchiveImportIPCChannel --- .../TestSceneInterProcessCommunication.cs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs index a7a3d644e8..1ecd38e1d3 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.IO; using System.Linq; using NUnit.Framework; using osu.Framework; @@ -14,6 +15,8 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; +using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Navigation { @@ -24,6 +27,7 @@ namespace osu.Game.Tests.Visual.Navigation private HeadlessGameHost ipcSenderHost = null!; private OsuSchemeLinkIPCChannel osuSchemeLinkIPCSender = null!; + private ArchiveImportIPCChannel archiveImportIPCSender = null!; private const int requested_beatmap_set_id = 1; @@ -57,10 +61,11 @@ namespace osu.Game.Tests.Visual.Navigation return false; }; }); - AddStep("create IPC sender channel", () => + AddStep("create IPC sender channels", () => { ipcSenderHost = new HeadlessGameHost(gameHost.Name, new HostOptions { BindIPC = true }); osuSchemeLinkIPCSender = new OsuSchemeLinkIPCChannel(ipcSenderHost); + archiveImportIPCSender = new ArchiveImportIPCChannel(ipcSenderHost); }); } @@ -72,11 +77,22 @@ namespace osu.Game.Tests.Visual.Navigation AddUntilStep("beatmap overlay showing content", () => Game.ChildrenOfType().FirstOrDefault()?.Header.BeatmapSet.Value.OnlineID == requested_beatmap_set_id); } + [Test] + public void TestArchiveImportLinkIPCChannel() + { + string? beatmapFilepath = null; + + AddStep("import beatmap via IPC", () => archiveImportIPCSender.ImportAsync(beatmapFilepath = TestResources.GetQuickTestBeatmapForImport()).WaitSafely()); + AddUntilStep("import complete notification was presented", () => Game.Notifications.ChildrenOfType().Count(), () => Is.EqualTo(1)); + AddAssert("original file deleted", () => File.Exists(beatmapFilepath), () => Is.False); + } + public override void TearDownSteps() { - AddStep("dispose IPC sender", () => + AddStep("dispose IPC senders", () => { osuSchemeLinkIPCSender.Dispose(); + archiveImportIPCSender.Dispose(); ipcSenderHost.Dispose(); }); base.TearDownSteps(); @@ -85,6 +101,7 @@ namespace osu.Game.Tests.Visual.Navigation private partial class IpcGame : TestOsuGame { private OsuSchemeLinkIPCChannel? osuSchemeLinkIPCChannel; + private ArchiveImportIPCChannel? archiveImportIPCChannel; public IpcGame(Storage storage, IAPIProvider api, string[]? args = null) : base(storage, api, args) @@ -95,12 +112,14 @@ namespace osu.Game.Tests.Visual.Navigation { base.LoadComplete(); osuSchemeLinkIPCChannel = new OsuSchemeLinkIPCChannel(Host, this); + archiveImportIPCChannel = new ArchiveImportIPCChannel(Host, this); } protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); osuSchemeLinkIPCChannel?.Dispose(); + archiveImportIPCChannel?.Dispose(); } } } From 5087377da67c5c9b96e8bf31cdd1264ca7928c9f Mon Sep 17 00:00:00 2001 From: Susko3 Date: Fri, 3 Feb 2023 18:57:50 +0100 Subject: [PATCH 150/516] Use IPC archive import in `OsuGameDesktop` --- osu.Desktop/OsuGameDesktop.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 4c93c2286f..b3f6370ccb 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -29,6 +29,7 @@ namespace osu.Desktop internal partial class OsuGameDesktop : OsuGame { private OsuSchemeLinkIPCChannel? osuSchemeLinkIPCChannel; + private ArchiveImportIPCChannel? archiveImportIPCChannel; public OsuGameDesktop(string[]? args = null) : base(args) @@ -123,6 +124,7 @@ namespace osu.Desktop LoadComponentAsync(new ElevatedPrivilegesChecker(), Add); osuSchemeLinkIPCChannel = new OsuSchemeLinkIPCChannel(Host, this); + archiveImportIPCChannel = new ArchiveImportIPCChannel(Host, this); } public override void SetHost(GameHost host) @@ -181,6 +183,7 @@ namespace osu.Desktop { base.Dispose(isDisposing); osuSchemeLinkIPCChannel?.Dispose(); + archiveImportIPCChannel?.Dispose(); } private class SDL2BatteryInfo : BatteryInfo From d9bee958dd55cd6dffcf0c4513549ae78fc2090e Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 3 Feb 2023 23:56:34 +0100 Subject: [PATCH 151/516] Stop ```BPMCounter.cs```'s value from going to 0 after failing. --- osu.Game/Screens/Play/HUD/BPMCounter.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/BPMCounter.cs b/osu.Game/Screens/Play/HUD/BPMCounter.cs index c07b203341..5fcac6cd04 100644 --- a/osu.Game/Screens/Play/HUD/BPMCounter.cs +++ b/osu.Game/Screens/Play/HUD/BPMCounter.cs @@ -26,6 +26,9 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private IGameplayClock gameplayClock { get; set; } = null!; + [Resolved] + private Player player { get; set; } = null!; + [BackgroundDependencyLoader] private void load(OsuColour colour) { @@ -38,7 +41,7 @@ namespace osu.Game.Screens.Play.HUD base.Update(); //We don't want it going to 0 when we pause. so we block the updates - if (gameplayClock.IsPaused.Value) return; + if (gameplayClock.IsPaused.Value || player.GameplayState.HasFailed) return; // We want to check Rate every update to cover windup/down Current.Value = beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(gameplayClock.CurrentTime).BPM * gameplayClock.Rate; From 88872cf1cf9dae9c4d9147c366727506db2e4c48 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sat, 4 Feb 2023 00:53:54 +0100 Subject: [PATCH 152/516] Use ```GetTrueGameplayRate()``` to remove need for jank --- osu.Game/Screens/Play/HUD/BPMCounter.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/BPMCounter.cs b/osu.Game/Screens/Play/HUD/BPMCounter.cs index 5fcac6cd04..500ab0169f 100644 --- a/osu.Game/Screens/Play/HUD/BPMCounter.cs +++ b/osu.Game/Screens/Play/HUD/BPMCounter.cs @@ -26,9 +26,6 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private IGameplayClock gameplayClock { get; set; } = null!; - [Resolved] - private Player player { get; set; } = null!; - [BackgroundDependencyLoader] private void load(OsuColour colour) { @@ -40,11 +37,8 @@ namespace osu.Game.Screens.Play.HUD { base.Update(); - //We don't want it going to 0 when we pause. so we block the updates - if (gameplayClock.IsPaused.Value || player.GameplayState.HasFailed) return; - // We want to check Rate every update to cover windup/down - Current.Value = beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(gameplayClock.CurrentTime).BPM * gameplayClock.Rate; + Current.Value = beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(gameplayClock.CurrentTime).BPM * gameplayClock.GetTrueGameplayRate(); } protected override OsuSpriteText CreateSpriteText() From 4192388b20d7a7b00d62965ba5aa2383be3e2046 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 3 Feb 2023 21:29:01 -0800 Subject: [PATCH 153/516] Fix expanded beatmap cards getting cut off at the end of profile sections --- osu.Game/Overlays/Profile/ProfileSection.cs | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Profile/ProfileSection.cs b/osu.Game/Overlays/Profile/ProfileSection.cs index 03917b75a4..4ac86924f8 100644 --- a/osu.Game/Overlays/Profile/ProfileSection.cs +++ b/osu.Game/Overlays/Profile/ProfileSection.cs @@ -36,21 +36,24 @@ namespace osu.Game.Overlays.Profile AutoSizeAxes = Axes.Y; RelativeSizeAxes = Axes.X; - Masking = true; - CornerRadius = 10; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0, 1), - Radius = 3, - Colour = Colour4.Black.Opacity(0.25f) - }; - InternalChildren = new Drawable[] { - background = new Box + new Container { RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 10, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0, 1), + Radius = 3, + Colour = Colour4.Black.Opacity(0.25f) + }, + Child = background = new Box + { + RelativeSizeAxes = Axes.Both, + }, }, new FillFlowContainer { From 49443f0b5538a4bc49512a78bf604f3db682a58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 4 Feb 2023 14:36:30 +0100 Subject: [PATCH 154/516] Inline temporary variable --- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 1e6be988b4..7a70257f3a 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -196,10 +196,8 @@ namespace osu.Game.Rulesets.Osu.Edit if (Vector2.Distance(closestSnapPosition, screenSpacePosition) < snapRadius) { - var snap = closestSnapPosition; - // only return distance portion, since time is not really valid - snapResult = new SnapResult(snap, null, playfield); + snapResult = new SnapResult(closestSnapPosition, null, playfield); return true; } } From 191259c05029ce5b37e4157f2bbbf3dad16214c7 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 4 Feb 2023 19:58:48 -0800 Subject: [PATCH 155/516] Use equals instead and update other usage --- osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs | 2 +- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs index 81f146b9ce..fee81e0e22 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.UserInterface { private Bindable lastPlaybackTime; - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) == true; [BackgroundDependencyLoader] private void load(SessionStatics statics) diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index dd8dd93d66..f810f51027 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Edit /// protected void ApplyDefaultsToHitObject() => HitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.Difficulty); - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) == true; protected override bool Handle(UIEvent e) { From cb8458cceb6e79ad4fc6920d580e4168df607000 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 4 Feb 2023 20:11:29 -0800 Subject: [PATCH 156/516] Use linq and alpha instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 869ed61a9c..c9eb80f676 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -521,7 +521,7 @@ namespace osu.Game.Overlays.Comments showRepliesButton.FadeTo(loadedRepliesCount != 0 ? 1 : 0); loadRepliesButton.FadeTo(hasUnloadedReplies && loadedRepliesCount == 0 ? 1 : 0); - repliesButtonContainer.FadeTo(showRepliesButton.IsPresent || loadRepliesButton.IsPresent ? 1 : 0); + repliesButtonContainer.FadeTo(repliesButtonContainer.Any(child => child.Alpha > 0) ? 1 : 0); showMoreButton.FadeTo(hasUnloadedReplies && loadedRepliesCount > 0 ? 1 : 0); From f58534f60c76e4b0f9874eb91be336a49cb62035 Mon Sep 17 00:00:00 2001 From: Terochi Date: Sun, 5 Feb 2023 16:35:11 +0100 Subject: [PATCH 157/516] Extended the length of replay at the end of map --- osu.Game/Screens/Play/Player.cs | 88 +++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index bf7f38cdd3..fda6bdaa8f 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -613,6 +613,8 @@ namespace osu.Game.Screens.Play // if an exit has been requested, cancel any pending completion (the user has shown intention to exit). resultsDisplayDelegate?.Cancel(); + beginScoreImport(); + // The actual exit is performed if // - the pause / fail dialog was not requested // - the pause / fail dialog was requested but is already displayed (user showing intention to exit). @@ -735,14 +737,9 @@ namespace osu.Game.Screens.Play // is no chance that a user could return to the (already completed) Player instance from a child screen. ValidForResume = false; - // Ensure we are not writing to the replay any more, as we are about to consume and store the score. - DrawableRuleset.SetRecordTarget(null); - if (!Configuration.ShowResults) return; - prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore); - bool storyboardHasOutro = DimmableStoryboard.ContentDisplayed && !DimmableStoryboard.HasStoryboardEnded.Value; if (storyboardHasOutro) @@ -756,6 +753,56 @@ namespace osu.Game.Screens.Play progressToResults(true); } + /// + /// Queue the results screen for display. + /// + /// + /// A final display will only occur once all work is completed in . This means that even after calling this method, the results screen will never be shown until ScoreProcessor.HasCompleted becomes . + /// + /// Whether a minimum delay () should be added before the screen is displayed. + private void progressToResults(bool withDelay) + { + resultsDisplayDelegate?.Cancel(); + + double delay = withDelay ? RESULTS_DISPLAY_DELAY : 0; + + resultsDisplayDelegate = new ScheduledDelegate(() => + { + if (prepareScoreForDisplayTask == null) + { + beginScoreImport(); + return; + } + + if (!prepareScoreForDisplayTask.IsCompleted) + // If the asynchronous preparation has not completed, keep repeating this delegate. + return; + + resultsDisplayDelegate?.Cancel(); + + if (!this.IsCurrentScreen()) + // This player instance may already be in the process of exiting. + return; + + this.Push(CreateResults(prepareScoreForDisplayTask.GetResultSafely())); + }, Time.Current + delay, 50); + + Scheduler.Add(resultsDisplayDelegate); + } + + private void beginScoreImport() + { + // We do not want to import the score in cases where we don't show results + bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed; + if (!canShowResults) + return; + + // Ensure we are not writing to the replay any more, as we are about to consume and store the score. + DrawableRuleset.SetRecordTarget(null); + + prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore); + } + /// /// Asynchronously run score preparation operations (database import, online submission etc.). /// @@ -785,37 +832,6 @@ namespace osu.Game.Screens.Play return scoreCopy.ScoreInfo; } - /// - /// Queue the results screen for display. - /// - /// - /// A final display will only occur once all work is completed in . This means that even after calling this method, the results screen will never be shown until ScoreProcessor.HasCompleted becomes . - /// - /// Whether a minimum delay () should be added before the screen is displayed. - private void progressToResults(bool withDelay) - { - resultsDisplayDelegate?.Cancel(); - - double delay = withDelay ? RESULTS_DISPLAY_DELAY : 0; - - resultsDisplayDelegate = new ScheduledDelegate(() => - { - if (prepareScoreForDisplayTask?.IsCompleted != true) - // If the asynchronous preparation has not completed, keep repeating this delegate. - return; - - resultsDisplayDelegate?.Cancel(); - - if (!this.IsCurrentScreen()) - // This player instance may already be in the process of exiting. - return; - - this.Push(CreateResults(prepareScoreForDisplayTask.GetResultSafely())); - }, Time.Current + delay, 50); - - Scheduler.Add(resultsDisplayDelegate); - } - protected override bool OnScroll(ScrollEvent e) { // During pause, allow global volume adjust regardless of settings. From d5b2d9ce9722c3127d4252e4b6b92388f758ba03 Mon Sep 17 00:00:00 2001 From: tsrk Date: Sun, 5 Feb 2023 23:58:08 +0000 Subject: [PATCH 158/516] 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 159/516] 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 160/516] 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 161/516] 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 701d21c26fd8cc2d9c14a35de25027a7a003caca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 13:52:25 +0900 Subject: [PATCH 162/516] Apply single inspection from newer inspectcode verisons As found in rider EAPs. Appears as a warning and is annoying me occasionally. --- osu.Game/Overlays/ChatOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index c539cdc5ec..b44c7c48f5 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -315,10 +315,10 @@ namespace osu.Game.Overlays channelListing.Hide(); textBar.ShowSearch.Value = false; - if (loadedChannels.ContainsKey(newChannel)) + if (loadedChannels.TryGetValue(newChannel, out var loadedChannel)) { currentChannelContainer.Clear(false); - currentChannelContainer.Add(loadedChannels[newChannel]); + currentChannelContainer.Add(loadedChannel); } else { From e4b17588f52361048a05fea72203e69d97c653ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 14:11:40 +0900 Subject: [PATCH 163/516] Add missing xmldoc to new methods in `EditorChangeHandler` --- osu.Game/Screens/Edit/EditorChangeHandler.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Screens/Edit/EditorChangeHandler.cs b/osu.Game/Screens/Edit/EditorChangeHandler.cs index 0391da6d86..4511b654b6 100644 --- a/osu.Game/Screens/Edit/EditorChangeHandler.cs +++ b/osu.Game/Screens/Edit/EditorChangeHandler.cs @@ -96,8 +96,18 @@ namespace osu.Game.Screens.Edit updateBindables(); } + /// + /// Write a serialised copy of the currently tracked state to the provided stream. + /// This will be stored as a state which can be restored in the future. + /// + /// The stream which the state should be written to. protected abstract void WriteCurrentStateToStream(MemoryStream stream); + /// + /// Given a previous and new state, apply any changes required to bring the current state in line with the new state. + /// + /// The previous (current before this call) serialised state. + /// The new state to be applied. protected abstract void ApplyStateChange(byte[] previousState, byte[] newState); private void updateBindables() From e5f62b0d2e7caa676d983736e496eb0ac377abf0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 14:19:25 +0900 Subject: [PATCH 164/516] Remove `public` access modifier from interface methods --- osu.Game/Skinning/ISkinnableTarget.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISkinnableTarget.cs index 70b80f3fed..3f116f8f76 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISkinnableTarget.cs @@ -39,7 +39,7 @@ namespace osu.Game.Skinning /// /// Reload this target from the provided skinnable information. /// - public void Reload(SkinnableInfo[] skinnableInfo); + void Reload(SkinnableInfo[] skinnableInfo); /// /// Add a new skinnable component to this target. @@ -51,6 +51,6 @@ namespace osu.Game.Skinning /// Remove an existing skinnable component from this target. /// /// The component to remove. - public void Remove(ISkinnableDrawable component); + void Remove(ISkinnableDrawable component); } } From 7445814fc63ad88964fb9dcaefff3e60069143dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 14:42:59 +0900 Subject: [PATCH 165/516] Handle changes to `SettingSource` skin element settings --- .../SkinEditor/SkinSettingsToolbox.cs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinSettingsToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinSettingsToolbox.cs index 5a48dee973..a2b9db2665 100644 --- a/osu.Game/Overlays/SkinEditor/SkinSettingsToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinSettingsToolbox.cs @@ -2,10 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; using osu.Game.Localisation; +using osu.Game.Overlays.Settings; +using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components; using osuTK; @@ -13,19 +16,41 @@ namespace osu.Game.Overlays.SkinEditor { internal partial class SkinSettingsToolbox : EditorSidebarSection { + [Resolved] + private IEditorChangeHandler? changeHandler { get; set; } + protected override Container Content { get; } + private readonly Drawable component; + public SkinSettingsToolbox(Drawable component) : base(SkinEditorStrings.Settings(component.GetType().Name)) { + this.component = component; + base.Content.Add(Content = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, Spacing = new Vector2(10), - Children = component.CreateSettingsControls().ToArray() }); } + + [BackgroundDependencyLoader] + private void load() + { + var controls = component.CreateSettingsControls().ToArray(); + + Content.AddRange(controls); + + // track any changes to update undo states. + foreach (var c in controls.OfType()) + { + // TODO: SettingChanged is called too often for cases like SettingsTextBox and SettingsSlider. + // We will want to expose a SettingCommitted or similar to make this work better. + c.SettingChanged += () => changeHandler?.SaveState(); + } + } } } From 778b8a9bf7f10f2457f39b9d8ea062bfc0fd3a70 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 15:00:42 +0900 Subject: [PATCH 166/516] Fix default settings not being serialised / state tracked correctly --- osu.Game/Extensions/DrawableExtensions.cs | 12 +++++++++--- osu.Game/Screens/Play/HUD/SkinnableInfo.cs | 3 +-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 65b9e46764..375960305c 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -66,10 +66,16 @@ namespace osu.Game.Extensions foreach (var (_, property) in component.GetSettingsSourceProperties()) { - if (!info.Settings.TryGetValue(property.Name.ToSnakeCase(), out object? settingValue)) - continue; + var bindable = ((IBindable)property.GetValue(component)!); - skinnable.CopyAdjustedSetting(((IBindable)property.GetValue(component)!), settingValue); + if (!info.Settings.TryGetValue(property.Name.ToSnakeCase(), out object? settingValue)) + { + // TODO: We probably want to restore default if not included in serialisation information. + // This is not simple to do as SetDefault() is only found in the typed Bindable interface right now. + continue; + } + + skinnable.CopyAdjustedSetting(bindable, settingValue); } } diff --git a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs index da759b4329..9fdae50615 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs @@ -69,8 +69,7 @@ namespace osu.Game.Screens.Play.HUD { var bindable = (IBindable)property.GetValue(component)!; - if (!bindable.IsDefault) - Settings.Add(property.Name.ToSnakeCase(), bindable.GetUnderlyingSettingValue()); + Settings.Add(property.Name.ToSnakeCase(), bindable.GetUnderlyingSettingValue()); } if (component is Container container) From 4c868372a2c7fa5259977f015efcbbbc7e73f0d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 15:05:05 +0900 Subject: [PATCH 167/516] Correctly handle anchor/origin changes as undo states --- osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs index 129b9c1b44..86fcd35e03 100644 --- a/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs @@ -241,6 +241,8 @@ namespace osu.Game.Overlays.SkinEditor private void applyOrigins(Anchor origin) { + OnOperationBegan(); + foreach (var item in SelectedItems) { var drawable = (Drawable)item; @@ -255,6 +257,8 @@ namespace osu.Game.Overlays.SkinEditor ApplyClosestAnchor(drawable); } + + OnOperationEnded(); } /// @@ -266,6 +270,8 @@ namespace osu.Game.Overlays.SkinEditor private void applyFixedAnchors(Anchor anchor) { + OnOperationBegan(); + foreach (var item in SelectedItems) { var drawable = (Drawable)item; @@ -273,15 +279,21 @@ namespace osu.Game.Overlays.SkinEditor item.UsesFixedAnchor = true; applyAnchor(drawable, anchor); } + + OnOperationEnded(); } private void applyClosestAnchors() { + OnOperationBegan(); + foreach (var item in SelectedItems) { item.UsesFixedAnchor = false; ApplyClosestAnchor((Drawable)item); } + + OnOperationEnded(); } private static Anchor getClosestAnchor(Drawable drawable) From 4f23e096d76e9ab33140b77472dd4fa6247d9b0c Mon Sep 17 00:00:00 2001 From: Terochi Date: Mon, 6 Feb 2023 07:59:37 +0100 Subject: [PATCH 168/516] Improved readability --- osu.Game/Screens/Play/Player.cs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index fda6bdaa8f..443108cf34 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -613,6 +613,7 @@ namespace osu.Game.Screens.Play // if an exit has been requested, cancel any pending completion (the user has shown intention to exit). resultsDisplayDelegate?.Cancel(); + // import current score if possible. beginScoreImport(); // The actual exit is performed if @@ -770,7 +771,11 @@ namespace osu.Game.Screens.Play { if (prepareScoreForDisplayTask == null) { - beginScoreImport(); + // Try importing score since the task hasn't been invoked yet. + if (!beginScoreImport()) + // If the task hasn't started, the score will never be imported. + resultsDisplayDelegate?.Cancel(); + return; } @@ -790,17 +795,25 @@ namespace osu.Game.Screens.Play Scheduler.Add(resultsDisplayDelegate); } - private void beginScoreImport() + /// + /// Ends replay recording and runs only when results can be shown + /// + /// + /// Whether the task has been invoked + /// + private bool beginScoreImport() { - // We do not want to import the score in cases where we don't show results - bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed; - if (!canShowResults) - return; - // Ensure we are not writing to the replay any more, as we are about to consume and store the score. DrawableRuleset.SetRecordTarget(null); + // We do not want to import the score in cases where we don't show results + bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed; + if (!canShowResults) + return false; + prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore); + + return true; } /// From 679ec986d5912818dd523ed690c7f14ff9311b52 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 16:39:44 +0900 Subject: [PATCH 169/516] Fix storyboard outro time potentially running too long --- .../Beatmaps/Formats/LegacyStoryboardDecoderTest.cs | 4 +++- osu.Game/Storyboards/CommandLoop.cs | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index d9e80fa111..281ea4e4ff 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -214,7 +214,9 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.That(oneTime.EndTime, Is.EqualTo(4000 + loop_duration)); StoryboardSprite manyTimes = background.Elements.OfType().Single(s => s.Path == "many-times.png"); - Assert.That(manyTimes.EndTime, Is.EqualTo(9000 + 40 * loop_duration)); + // It is intentional that we don't consider the loop count (40) as part of the end time calculation to match stable's handling. + // If we were to include the loop count, storyboards which loop for stupid long loop counts would continue playing the outro forever. + Assert.That(manyTimes.EndTime, Is.EqualTo(9000 + loop_duration)); } } } diff --git a/osu.Game/Storyboards/CommandLoop.cs b/osu.Game/Storyboards/CommandLoop.cs index 0f26ed2c66..29e034d86c 100644 --- a/osu.Game/Storyboards/CommandLoop.cs +++ b/osu.Game/Storyboards/CommandLoop.cs @@ -18,7 +18,12 @@ namespace osu.Game.Storyboards public readonly int TotalIterations; public override double StartTime => LoopStartTime + CommandsStartTime; - public override double EndTime => StartTime + CommandsDuration * TotalIterations; + + public override double EndTime => + // In an ideal world, we would multiply the command duration by TotalIterations here. + // Unfortunately this would clash with how stable handled end times, and results in some storyboards playing outro + // sequences for minutes or hours. + StartTime + CommandsDuration; /// /// Construct a new command loop. From eabd1a0cc1553fb00df7ae9ff92ad66663916c5f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 16:42:39 +0900 Subject: [PATCH 170/516] Remove unused `Duration` property to avoid any misunderstandings --- osu.Game/Storyboards/CommandTimelineGroup.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Storyboards/CommandTimelineGroup.cs b/osu.Game/Storyboards/CommandTimelineGroup.cs index de5da3118a..d198ed68bd 100644 --- a/osu.Game/Storyboards/CommandTimelineGroup.cs +++ b/osu.Game/Storyboards/CommandTimelineGroup.cs @@ -84,9 +84,6 @@ namespace osu.Game.Storyboards [JsonIgnore] public virtual double EndTime => CommandsEndTime; - [JsonIgnore] - public double Duration => EndTime - StartTime; - [JsonIgnore] public bool HasCommands { From 43f7665c9eabe7105bb1a7c1c2ace3784214d28f Mon Sep 17 00:00:00 2001 From: Terochi Date: Mon, 6 Feb 2023 09:49:42 +0100 Subject: [PATCH 171/516] Improved readability again --- osu.Game/Screens/Play/Player.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 443108cf34..2f81b7154a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -614,7 +614,7 @@ namespace osu.Game.Screens.Play resultsDisplayDelegate?.Cancel(); // import current score if possible. - beginScoreImport(); + attemptScoreImport(); // The actual exit is performed if // - the pause / fail dialog was not requested @@ -772,8 +772,8 @@ namespace osu.Game.Screens.Play if (prepareScoreForDisplayTask == null) { // Try importing score since the task hasn't been invoked yet. - if (!beginScoreImport()) - // If the task hasn't started, the score will never be imported. + if (!attemptScoreImport()) + // If attempt failed, trying again is unnecessary resultsDisplayDelegate?.Cancel(); return; @@ -796,12 +796,12 @@ namespace osu.Game.Screens.Play } /// - /// Ends replay recording and runs only when results can be shown + /// Attempts to run /// /// - /// Whether the task has been invoked + /// Whether the attempt was successful /// - private bool beginScoreImport() + private bool attemptScoreImport() { // Ensure we are not writing to the replay any more, as we are about to consume and store the score. DrawableRuleset.SetRecordTarget(null); From b83c8443ea2e5fc52213045d5701a55d0ee30b73 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 18:22:51 +0900 Subject: [PATCH 172/516] Ensure pause sample loop is stopped on exiting player --- osu.Game/Screens/Play/PauseOverlay.cs | 8 ++++++++ osu.Game/Screens/Play/Player.cs | 3 +++ 2 files changed, 11 insertions(+) diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index d9c60519ad..db42998c45 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -44,6 +44,14 @@ namespace osu.Game.Screens.Play }); } + public void StopAllSamples() + { + if (!IsLoaded) + return; + + pauseLoop.Stop(); + } + protected override void PopIn() { base.PopIn(); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index bf7f38cdd3..37b3f906eb 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -1073,7 +1073,10 @@ namespace osu.Game.Screens.Play public override bool OnExiting(ScreenExitEvent e) { screenSuspension?.RemoveAndDisposeImmediately(); + + // Eagerly clean these up as disposal of child components is asynchronous and may leave sounds playing beyond user expectations. failAnimationLayer?.Stop(); + PauseOverlay.StopAllSamples(); if (LoadedBeatmapSuccessfully) { From aaf3ad805c18e1e34cf51c4485d33b05882241e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Feb 2023 19:31:45 +0900 Subject: [PATCH 173/516] Fix potential nullref in tests --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 37b3f906eb..6dc4854e80 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -1076,7 +1076,7 @@ namespace osu.Game.Screens.Play // Eagerly clean these up as disposal of child components is asynchronous and may leave sounds playing beyond user expectations. failAnimationLayer?.Stop(); - PauseOverlay.StopAllSamples(); + PauseOverlay?.StopAllSamples(); if (LoadedBeatmapSuccessfully) { From bc89f8dc5b9d40aa92bcc88249e7165e4b72f9fc Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 12:44:00 +0000 Subject: [PATCH 174/516] 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 175/516] 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 176/516] 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 5cd973fb3490dcc10d10e4775e294d690b0ffda1 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 6 Feb 2023 19:20:43 -0600 Subject: [PATCH 177/516] Add test --- .../TestSceneHitCircleLateFade.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs new file mode 100644 index 0000000000..3195c0b24b --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs @@ -0,0 +1,48 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using NUnit.Framework; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public partial class TestSceneHitCircleLateFade : OsuTestScene + { + [Test] + public void TestFadeOutIntoMiss() + { + float? alphaAtMiss = null; + + AddStep("Create hit circle", () => + { + alphaAtMiss = null; + + DrawableHitCircle drawableHitCircle = new DrawableHitCircle(new HitCircle + { + StartTime = Time.Current + 500, + Position = new Vector2(250) + }); + + drawableHitCircle.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + drawableHitCircle.OnNewResult += (_, _) => + { + alphaAtMiss = drawableHitCircle.Alpha; + }; + + Child = drawableHitCircle; + }); + + AddUntilStep("Wait until circle is missed", () => alphaAtMiss.IsNotNull()); + AddAssert("Transparent when missed", () => alphaAtMiss == 0); + } + } +} From d027d69913610087527c61a7d33939e5bf229b77 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 6 Feb 2023 19:22:47 -0600 Subject: [PATCH 178/516] Make hit circle fade out into late miss judgement --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 3458069dd1..8467d33e9b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -200,6 +200,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables // always fade out at the circle's start time (to match user expectations). ApproachCircle.FadeOut(50); + + double mehWindow = HitObject.HitWindows.WindowFor(HitResult.Meh); + double lateMissFadeTime = mehWindow / 4 + 15; + this.Delay(mehWindow - lateMissFadeTime).FadeOut(lateMissFadeTime); } protected override void UpdateHitStateTransforms(ArmedState state) From 71eef238c4a530d4ef59606feff1c66c862baa4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Feb 2023 16:04:31 +0900 Subject: [PATCH 179/516] Make `OnStateChange` non-implemented rather than wrong --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 3a10e58707..ad031d2c7e 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -477,8 +477,8 @@ namespace osu.Game.Overlays.SkinEditor public event Action? OnStateChange { - add => changeHandler!.OnStateChange += value; - remove => changeHandler!.OnStateChange -= value; + add => throw new NotImplementedException(); + remove => throw new NotImplementedException(); } public void BeginChange() => changeHandler?.BeginChange(); From dad348111d2be5c53d73b8694a378bb81f6be9c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Feb 2023 16:07:33 +0900 Subject: [PATCH 180/516] Fix holding a selection while changing screens causing a crash --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index ad031d2c7e..0716505f26 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -481,8 +481,16 @@ namespace osu.Game.Overlays.SkinEditor remove => throw new NotImplementedException(); } - public void BeginChange() => changeHandler?.BeginChange(); - public void EndChange() => changeHandler?.EndChange(); + private IEditorChangeHandler? beginChangeHandler; + + public void BeginChange() + { + // Change handler may change between begin and end, which can cause unbalanced operations. + // Let's track the one that was used when beginning the change so we can call EndChange on it specifically. + (beginChangeHandler = changeHandler)?.BeginChange(); + } + + public void EndChange() => beginChangeHandler?.EndChange(); public void SaveState() => changeHandler?.SaveState(); #endregion From e162fd56da39f5bcf67ef3a21af13ea08c6cf8ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Feb 2023 16:22:51 +0900 Subject: [PATCH 181/516] Change the way initial state saving works in `EditorChangeHandler` to be closer to first change --- .../Screens/Edit/BeatmapEditorChangeHandler.cs | 3 --- osu.Game/Screens/Edit/EditorChangeHandler.cs | 15 +++++++++++++++ .../Screens/Edit/TransactionalCommitComponent.cs | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/BeatmapEditorChangeHandler.cs b/osu.Game/Screens/Edit/BeatmapEditorChangeHandler.cs index b9349a31af..3c19994a8a 100644 --- a/osu.Game/Screens/Edit/BeatmapEditorChangeHandler.cs +++ b/osu.Game/Screens/Edit/BeatmapEditorChangeHandler.cs @@ -26,9 +26,6 @@ namespace osu.Game.Screens.Edit editorBeatmap.SaveStateTriggered += SaveState; patcher = new LegacyEditorBeatmapPatcher(editorBeatmap); - - // Initial state. - SaveState(); } protected override void WriteCurrentStateToStream(MemoryStream stream) diff --git a/osu.Game/Screens/Edit/EditorChangeHandler.cs b/osu.Game/Screens/Edit/EditorChangeHandler.cs index 4511b654b6..0bb17e4c5d 100644 --- a/osu.Game/Screens/Edit/EditorChangeHandler.cs +++ b/osu.Game/Screens/Edit/EditorChangeHandler.cs @@ -31,6 +31,8 @@ namespace osu.Game.Screens.Edit { get { + ensureStateSaved(); + using (var stream = new MemoryStream(savedStates[currentState])) return stream.ComputeSHA2Hash(); } @@ -40,6 +42,19 @@ namespace osu.Game.Screens.Edit public const int MAX_SAVED_STATES = 50; + public override void BeginChange() + { + ensureStateSaved(); + + base.BeginChange(); + } + + private void ensureStateSaved() + { + if (savedStates.Count == 0) + SaveState(); + } + protected override void UpdateState() { if (isRestoring) diff --git a/osu.Game/Screens/Edit/TransactionalCommitComponent.cs b/osu.Game/Screens/Edit/TransactionalCommitComponent.cs index f8362523f1..92f1e19e6f 100644 --- a/osu.Game/Screens/Edit/TransactionalCommitComponent.cs +++ b/osu.Game/Screens/Edit/TransactionalCommitComponent.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Edit /// /// Signal the beginning of a change. /// - public void BeginChange() + public virtual void BeginChange() { if (bulkChangesStarted++ == 0) TransactionBegan?.Invoke(); From 0320ba770f1824b32fbb1e7d57366e7cf4b41481 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Feb 2023 16:23:24 +0900 Subject: [PATCH 182/516] Handle component changes via `ISkinnableTarget.Components` rather than inside `SkinEditor` directly Seems saner? Maybe? --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 4 ---- .../SkinEditor/SkinEditorChangeHandler.cs | 15 ++++++++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 0716505f26..866de7e621 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -329,8 +329,6 @@ namespace osu.Game.Overlays.SkinEditor SelectedComponents.Clear(); SelectedComponents.Add(component); - - changeHandler?.SaveState(); } private void populateSettings() @@ -406,8 +404,6 @@ namespace osu.Game.Overlays.SkinEditor { foreach (var item in items) availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item); - - changeHandler?.SaveState(); } #region Drag & drop import handling diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs index 95b24bbd6f..dfbd48a285 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Text; using Newtonsoft.Json; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Extensions; @@ -17,9 +18,10 @@ namespace osu.Game.Overlays.SkinEditor { public partial class SkinEditorChangeHandler : EditorChangeHandler { - private readonly Drawable targetScreen; + private readonly ISkinnableTarget? firstTarget; - private ISkinnableTarget? firstTarget => targetScreen.ChildrenOfType().FirstOrDefault(); + // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable + private readonly BindableList? components; public SkinEditorChangeHandler(Drawable targetScreen) { @@ -27,10 +29,13 @@ namespace osu.Game.Overlays.SkinEditor // In the future we'll want this to cover all changes, even to skin's `InstantiationInfo`. // We'll also need to consider cases where multiple targets are on screen at the same time. - this.targetScreen = targetScreen; + firstTarget = targetScreen?.ChildrenOfType().FirstOrDefault(); - // Save initial state. - SaveState(); + if (firstTarget == null) + return; + + components = new BindableList { BindTarget = firstTarget.Components }; + components.BindCollectionChanged((_, _) => SaveState()); } protected override void WriteCurrentStateToStream(MemoryStream stream) From 277f71d36a2609386453a1b2aae38189f4e8f7ec Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 7 Feb 2023 15:15:51 -0800 Subject: [PATCH 183/516] Expire reply editor instead of clearing container --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index c9eb80f676..397dd46cdc 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -466,7 +466,7 @@ namespace osu.Game.Overlays.Comments } else { - replyEditorContainer.Clear(true); + replyEditorContainer.ForEach(e => e.Expire()); replyEditorContainer.Hide(); } } From ee65c658937f3ff845c229bbf5edd97d8e73af17 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Feb 2023 11:31:28 +0900 Subject: [PATCH 184/516] 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 cec1f77e6cbbc7d61e3a71dc54dbfd052b0f9e56 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Feb 2023 13:59:09 +0900 Subject: [PATCH 185/516] Fix glow flash occurring after releasing mouse and adjust transition slightly --- osu.Game/Graphics/UserInterface/ShearedNub.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ShearedNub.cs b/osu.Game/Graphics/UserInterface/ShearedNub.cs index 390d6ff9be..3a09fd7445 100644 --- a/osu.Game/Graphics/UserInterface/ShearedNub.cs +++ b/osu.Game/Graphics/UserInterface/ShearedNub.cs @@ -58,7 +58,7 @@ namespace osu.Game.Graphics.UserInterface private void load(OverlayColourProvider? colourProvider, OsuColour colours) { AccentColour = colourProvider?.Highlight1 ?? colours.Pink; - GlowingAccentColour = colourProvider?.Highlight1.Lighten(0.2f) ?? colours.PinkLighter; + GlowingAccentColour = colourProvider?.Highlight1.Lighten(0.4f) ?? colours.PinkLighter; GlowColour = colourProvider?.Highlight1 ?? colours.PinkLighter; main.EdgeEffect = new EdgeEffectParameters @@ -84,11 +84,14 @@ namespace osu.Game.Graphics.UserInterface get => glowing; set { + if (glowing == value) + return; + glowing = value; if (value) { - main.FadeColour(GlowingAccentColour.Lighten(0.5f), 40, Easing.OutQuint) + main.FadeColour(GlowingAccentColour.Lighten(0.1f), 40, Easing.OutQuint) .Then() .FadeColour(GlowingAccentColour, 800, Easing.OutQuint); From 5cd111e6f13ab9e7a0335b19dee25800b16cb42b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Feb 2023 14:00:45 +0900 Subject: [PATCH 186/516] Fix ordering of methods in `OsuSliderBar` --- .../Graphics/UserInterface/OsuSliderBar.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index ee1f75c419..0c36d73085 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -17,18 +17,12 @@ namespace osu.Game.Graphics.UserInterface public abstract partial class OsuSliderBar : SliderBar, IHasTooltip where T : struct, IEquatable, IComparable, IConvertible { - private Sample sample = null!; - - private double lastSampleTime; - private T lastSampleValue; - public bool PlaySamplesOnAdjust { get; set; } = true; - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - sample = audio.Samples.Get(@"UI/notch-tick"); - } + /// + /// Whether to format the tooltip as a percentage or the actual value. + /// + public bool DisplayAsPercentage { get; set; } public virtual LocalisableString TooltipText { get; private set; } @@ -37,10 +31,16 @@ namespace osu.Game.Graphics.UserInterface /// private const int max_decimal_digits = 5; - /// - /// Whether to format the tooltip as a percentage or the actual value. - /// - public bool DisplayAsPercentage { get; set; } + private Sample sample = null!; + + private double lastSampleTime; + private T lastSampleValue; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sample = audio.Samples.Get(@"UI/notch-tick"); + } protected override void LoadComplete() { From 17ca26ebee29560f507a4556df3b75236f6464a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Feb 2023 15:44:24 +0900 Subject: [PATCH 187/516] Remove unnecessary null check on `targetScreen` --- osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs index dfbd48a285..c8f66f3e56 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.SkinEditor // In the future we'll want this to cover all changes, even to skin's `InstantiationInfo`. // We'll also need to consider cases where multiple targets are on screen at the same time. - firstTarget = targetScreen?.ChildrenOfType().FirstOrDefault(); + firstTarget = targetScreen.ChildrenOfType().FirstOrDefault(); if (firstTarget == null) return; From b0131db1dc5fd09a6cc7a10671b317a69fe9fe01 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Feb 2023 15:55:17 +0900 Subject: [PATCH 188/516] Update test assertions in line with new state saving logic --- .../Editing/BeatmapEditorChangeHandlerTest.cs | 63 ++++++++++++++++--- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Editing/BeatmapEditorChangeHandlerTest.cs b/osu.Game.Tests/Editing/BeatmapEditorChangeHandlerTest.cs index 4746f84fa0..80237fe6c8 100644 --- a/osu.Game.Tests/Editing/BeatmapEditorChangeHandlerTest.cs +++ b/osu.Game.Tests/Editing/BeatmapEditorChangeHandlerTest.cs @@ -21,18 +21,23 @@ namespace osu.Game.Tests.Editing } [Test] - public void TestSaveRestoreState() + public void TestSaveRestoreStateUsingTransaction() { var (handler, beatmap) = createChangeHandler(); Assert.That(handler.CanUndo.Value, Is.False); Assert.That(handler.CanRedo.Value, Is.False); - addArbitraryChange(beatmap); - handler.SaveState(); + handler.BeginChange(); + // Initial state will be saved on BeginChange Assert.That(stateChangedFired, Is.EqualTo(1)); + addArbitraryChange(beatmap); + handler.EndChange(); + + Assert.That(stateChangedFired, Is.EqualTo(2)); + Assert.That(handler.CanUndo.Value, Is.True); Assert.That(handler.CanRedo.Value, Is.False); @@ -41,7 +46,35 @@ namespace osu.Game.Tests.Editing Assert.That(handler.CanUndo.Value, Is.False); Assert.That(handler.CanRedo.Value, Is.True); + Assert.That(stateChangedFired, Is.EqualTo(3)); + } + + [Test] + public void TestSaveRestoreState() + { + var (handler, beatmap) = createChangeHandler(); + + Assert.That(handler.CanUndo.Value, Is.False); + Assert.That(handler.CanRedo.Value, Is.False); + + // Save initial state + handler.SaveState(); + Assert.That(stateChangedFired, Is.EqualTo(1)); + + addArbitraryChange(beatmap); + handler.SaveState(); + Assert.That(stateChangedFired, Is.EqualTo(2)); + + Assert.That(handler.CanUndo.Value, Is.True); + Assert.That(handler.CanRedo.Value, Is.False); + + handler.RestoreState(-1); + + Assert.That(handler.CanUndo.Value, Is.False); + Assert.That(handler.CanRedo.Value, Is.True); + + Assert.That(stateChangedFired, Is.EqualTo(3)); } [Test] @@ -52,6 +85,10 @@ namespace osu.Game.Tests.Editing Assert.That(handler.CanUndo.Value, Is.False); Assert.That(handler.CanRedo.Value, Is.False); + // Save initial state + handler.SaveState(); + Assert.That(stateChangedFired, Is.EqualTo(1)); + string originalHash = handler.CurrentStateHash; addArbitraryChange(beatmap); @@ -59,7 +96,7 @@ namespace osu.Game.Tests.Editing Assert.That(handler.CanUndo.Value, Is.True); Assert.That(handler.CanRedo.Value, Is.False); - Assert.That(stateChangedFired, Is.EqualTo(1)); + Assert.That(stateChangedFired, Is.EqualTo(2)); string hash = handler.CurrentStateHash; @@ -67,7 +104,7 @@ namespace osu.Game.Tests.Editing handler.RestoreState(-1); Assert.That(originalHash, Is.EqualTo(handler.CurrentStateHash)); - Assert.That(stateChangedFired, Is.EqualTo(2)); + Assert.That(stateChangedFired, Is.EqualTo(3)); addArbitraryChange(beatmap); handler.SaveState(); @@ -82,12 +119,16 @@ namespace osu.Game.Tests.Editing Assert.That(handler.CanUndo.Value, Is.False); Assert.That(handler.CanRedo.Value, Is.False); + // Save initial state + handler.SaveState(); + Assert.That(stateChangedFired, Is.EqualTo(1)); + addArbitraryChange(beatmap); handler.SaveState(); Assert.That(handler.CanUndo.Value, Is.True); Assert.That(handler.CanRedo.Value, Is.False); - Assert.That(stateChangedFired, Is.EqualTo(1)); + Assert.That(stateChangedFired, Is.EqualTo(2)); string hash = handler.CurrentStateHash; @@ -95,7 +136,7 @@ namespace osu.Game.Tests.Editing handler.SaveState(); Assert.That(hash, Is.EqualTo(handler.CurrentStateHash)); - Assert.That(stateChangedFired, Is.EqualTo(1)); + Assert.That(stateChangedFired, Is.EqualTo(2)); handler.RestoreState(-1); @@ -104,7 +145,7 @@ namespace osu.Game.Tests.Editing // we should only be able to restore once even though we saved twice. Assert.That(handler.CanUndo.Value, Is.False); Assert.That(handler.CanRedo.Value, Is.True); - Assert.That(stateChangedFired, Is.EqualTo(2)); + Assert.That(stateChangedFired, Is.EqualTo(3)); } [Test] @@ -112,11 +153,15 @@ namespace osu.Game.Tests.Editing { var (handler, beatmap) = createChangeHandler(); + // Save initial state + handler.SaveState(); + Assert.That(stateChangedFired, Is.EqualTo(1)); + Assert.That(handler.CanUndo.Value, Is.False); for (int i = 0; i < EditorChangeHandler.MAX_SAVED_STATES; i++) { - Assert.That(stateChangedFired, Is.EqualTo(i)); + Assert.That(stateChangedFired, Is.EqualTo(i + 1)); addArbitraryChange(beatmap); handler.SaveState(); From 0156ff732ffa40431940a7cb01e6ba0ffada95a8 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 7 Feb 2023 21:55:01 -0800 Subject: [PATCH 189/516] Fix beatmap cards not showing context menu on user profile --- .../Profile/Header/TopHeaderContainer.cs | 120 ++++++++---------- osu.Game/Overlays/UserProfileOverlay.cs | 22 ++-- 2 files changed, 70 insertions(+), 72 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 652ebcec26..2f4f49788f 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays.Profile.Header.Components; @@ -104,76 +103,69 @@ namespace osu.Game.Overlays.Profile.Header Colour = Colour4.Black.Opacity(0.25f), } }, - new OsuContextMenuContainer + new FillFlowContainer { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Child = new FillFlowContainer + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] + new FillFlowContainer { - new FillFlowContainer + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), - Children = new Drawable[] + usernameText = new OsuSpriteText { - usernameText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 24, weight: FontWeight.Regular) - }, - supporterTag = new SupporterIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Height = 15, - }, - openUserExternally = new ExternalLinkButton - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - groupBadgeFlow = new GroupBadgeFlow - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - } - }, - titleText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), - Margin = new MarginPadding { Bottom = 5 } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] + Font = OsuFont.GetFont(size: 24, weight: FontWeight.Regular) + }, + supporterTag = new SupporterIcon { - userFlag = new UpdateableFlag - { - Size = new Vector2(28, 20), - ShowPlaceholderOnUnknown = false, - }, - userCountryText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 14f, weight: FontWeight.Regular), - Margin = new MarginPadding { Left = 5 }, - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - } + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Height = 15, + }, + openUserExternally = new ExternalLinkButton + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + groupBadgeFlow = new GroupBadgeFlow + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + } + }, + titleText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), + Margin = new MarginPadding { Bottom = 5 } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + userFlag = new UpdateableFlag + { + Size = new Vector2(28, 20), + ShowPlaceholderOnUnknown = false, + }, + userCountryText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 14f, weight: FontWeight.Regular), + Margin = new MarginPadding { Left = 5 }, + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, } - }, - } - }, + } + }, + } }, } }, diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 8849c674dc..c5f8a820ea 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -14,6 +14,7 @@ using osu.Framework.Input.Events; using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online; @@ -100,17 +101,22 @@ namespace osu.Game.Overlays Origin = Anchor.TopCentre, }; - Add(sectionsContainer = new ProfileSectionsContainer + Add(new OsuContextMenuContainer { - ExpandableHeader = Header, - FixedHeader = tabs, - HeaderBackground = new Box + RelativeSizeAxes = Axes.Both, + Child = sectionsContainer = new ProfileSectionsContainer { - // this is only visible as the ProfileTabControl background - Colour = ColourProvider.Background5, - RelativeSizeAxes = Axes.Both - }, + ExpandableHeader = Header, + FixedHeader = tabs, + HeaderBackground = new Box + { + // this is only visible as the ProfileTabControl background + Colour = ColourProvider.Background5, + RelativeSizeAxes = Axes.Both + }, + } }); + sectionsContainer.SelectedSection.ValueChanged += section => { if (lastSection != section.NewValue) From df1355ea4be54fac4a7c306892d35111fbe3960f Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Mon, 6 Feb 2023 13:34:54 +0000 Subject: [PATCH 190/516] 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 191/516] 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 192/516] 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 193/516] 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 194/516] 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 195/516] 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 3b5d573db1365dd07b335a2f8be5da60e7b9f67a Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 31 Jan 2023 15:02:59 -0800 Subject: [PATCH 196/516] Display tournament banner on user profile --- .../Online/TestSceneUserProfileOverlay.cs | 6 ++ .../Online/API/Requests/Responses/APIUser.cs | 4 ++ .../Profile/Header/BannerHeaderContainer.cs | 63 +++++++++++++++++++ .../Components/DrawableTournamentBanner.cs | 46 ++++++++++++++ osu.Game/Overlays/Profile/ProfileHeader.cs | 4 ++ osu.Game/Users/TournamentBanner.cs | 23 +++++++ 6 files changed, 146 insertions(+) create mode 100644 osu.Game/Overlays/Profile/Header/BannerHeaderContainer.cs create mode 100644 osu.Game/Overlays/Profile/Header/Components/DrawableTournamentBanner.cs create mode 100644 osu.Game/Users/TournamentBanner.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 91928c1fd2..a97c8aff66 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -121,6 +121,12 @@ namespace osu.Game.Tests.Visual.Online Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray() }, }, + TournamentBanner = new TournamentBanner + { + Id = 13926, + TournamentId = 35, + ImageLowRes = "https://assets.ppy.sh/tournament-banners/official/owc2022/profile/winner_US.jpg", + }, Badges = new[] { new Badge diff --git a/osu.Game/Online/API/Requests/Responses/APIUser.cs b/osu.Game/Online/API/Requests/Responses/APIUser.cs index 0e62b03f1a..e63395fe26 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUser.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUser.cs @@ -234,6 +234,10 @@ namespace osu.Game.Online.API.Requests.Responses set => Statistics.RankHistory = value; } + [JsonProperty(@"active_tournament_banner")] + [CanBeNull] + public TournamentBanner TournamentBanner; + [JsonProperty("badges")] public Badge[] Badges; diff --git a/osu.Game/Overlays/Profile/Header/BannerHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/BannerHeaderContainer.cs new file mode 100644 index 0000000000..8e6648dc4b --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/BannerHeaderContainer.cs @@ -0,0 +1,63 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.Profile.Header.Components; + +namespace osu.Game.Overlays.Profile.Header +{ + public partial class BannerHeaderContainer : CompositeDrawable + { + public readonly Bindable User = new Bindable(); + + [BackgroundDependencyLoader] + private void load() + { + Alpha = 0; + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fit; + FillAspectRatio = 1000 / 60f; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + User.BindValueChanged(u => updateDisplay(u.NewValue?.User), true); + } + + private CancellationTokenSource? cancellationTokenSource; + + private void updateDisplay(APIUser? user) + { + cancellationTokenSource?.Cancel(); + cancellationTokenSource = new CancellationTokenSource(); + + ClearInternal(); + + var banner = user?.TournamentBanner; + + if (banner != null) + { + Show(); + + LoadComponentAsync(new DrawableTournamentBanner(banner), AddInternal, cancellationTokenSource.Token); + } + else + { + Hide(); + } + } + + protected override void Dispose(bool isDisposing) + { + cancellationTokenSource?.Cancel(); + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Overlays/Profile/Header/Components/DrawableTournamentBanner.cs b/osu.Game/Overlays/Profile/Header/Components/DrawableTournamentBanner.cs new file mode 100644 index 0000000000..26d333ff95 --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/DrawableTournamentBanner.cs @@ -0,0 +1,46 @@ +// 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; +using osu.Framework.Graphics.Textures; +using osu.Framework.Localisation; +using osu.Game.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Users; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + [LongRunningLoad] + public partial class DrawableTournamentBanner : OsuClickableContainer + { + private readonly TournamentBanner banner; + + public DrawableTournamentBanner(TournamentBanner banner) + { + this.banner = banner; + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(LargeTextureStore textures, OsuGame? game, IAPIProvider api) + { + Child = new Sprite + { + RelativeSizeAxes = Axes.Both, + Texture = textures.Get(banner.Image), + }; + + Action = () => game?.OpenUrlExternally($@"{api.WebsiteRootUrl}/community/tournaments/{banner.TournamentId}"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + this.FadeInFromZero(200); + } + + public override LocalisableString TooltipText => "view in browser"; + } +} diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 5d753dea7d..363eb5d58e 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -47,6 +47,10 @@ namespace osu.Game.Overlays.Profile RelativeSizeAxes = Axes.X, User = { BindTarget = User }, }, + new BannerHeaderContainer + { + User = { BindTarget = User }, + }, new BadgeHeaderContainer { RelativeSizeAxes = Axes.X, diff --git a/osu.Game/Users/TournamentBanner.cs b/osu.Game/Users/TournamentBanner.cs new file mode 100644 index 0000000000..62e1913412 --- /dev/null +++ b/osu.Game/Users/TournamentBanner.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.IO; +using Newtonsoft.Json; + +namespace osu.Game.Users +{ + public class TournamentBanner + { + [JsonProperty("id")] + public int Id; + + [JsonProperty("tournament_id")] + public int TournamentId; + + [JsonProperty("image")] + public string ImageLowRes = null!; + + // TODO: remove when api returns @2x image link: https://github.com/ppy/osu-web/issues/9816 + public string Image => $@"{Path.ChangeExtension(ImageLowRes, null)}@2x{Path.GetExtension(ImageLowRes)}"; + } +} 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 197/516] 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 f1decb667e431e1adc007d830e3cddd7b836dd75 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 8 Feb 2023 17:51:28 -0800 Subject: [PATCH 198/516] Address todos relating to init-only usages --- .../Profile/Header/Components/RankGraph.cs | 10 ++++++---- .../Sections/Historical/UserHistoryGraph.cs | 10 ++++++---- osu.Game/Overlays/Profile/UserGraph.cs | 14 +++----------- .../Tests/Visual/DependencyProvidingContainer.cs | 3 +-- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index fe1069eea1..4f3f1ac2c3 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -66,10 +66,12 @@ namespace osu.Game.Overlays.Profile.Header.Components { int days = ranked_days - index + 1; - return new UserGraphTooltipContent( - UsersStrings.ShowRankGlobalSimple, - rank.ToLocalisableString("\\##,##0"), - days == 0 ? "now" : $"{"day".ToQuantity(days)} ago"); + return new UserGraphTooltipContent + { + Name = UsersStrings.ShowRankGlobalSimple, + Count = rank.ToLocalisableString("\\##,##0"), + Time = days == 0 ? "now" : $"{"day".ToQuantity(days)} ago", + }; } } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs index 310607e757..0259231001 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs @@ -27,9 +27,11 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override float GetDataPointHeight(long playCount) => playCount; protected override UserGraphTooltipContent GetTooltipContent(DateTime date, long playCount) => - new UserGraphTooltipContent( - tooltipCounterName, - playCount.ToLocalisableString("N0"), - date.ToLocalisableString("MMMM yyyy")); + new UserGraphTooltipContent + { + Name = tooltipCounterName, + Count = playCount.ToLocalisableString("N0"), + Time = date.ToLocalisableString("MMMM yyyy") + }; } } diff --git a/osu.Game/Overlays/Profile/UserGraph.cs b/osu.Game/Overlays/Profile/UserGraph.cs index 63cdbea5a4..0a5e6ca710 100644 --- a/osu.Game/Overlays/Profile/UserGraph.cs +++ b/osu.Game/Overlays/Profile/UserGraph.cs @@ -298,16 +298,8 @@ namespace osu.Game.Overlays.Profile public class UserGraphTooltipContent { - // todo: could use init-only properties on C# 9 which read better than a constructor. - public LocalisableString Name { get; } - public LocalisableString Count { get; } - public LocalisableString Time { get; } - - public UserGraphTooltipContent(LocalisableString name, LocalisableString count, LocalisableString time) - { - Name = name; - Count = count; - Time = time; - } + public LocalisableString Name { get; init; } + public LocalisableString Count { get; init; } + public LocalisableString Time { get; init; } } } diff --git a/osu.Game/Tests/Visual/DependencyProvidingContainer.cs b/osu.Game/Tests/Visual/DependencyProvidingContainer.cs index ae0225d8df..acfff4cefe 100644 --- a/osu.Game/Tests/Visual/DependencyProvidingContainer.cs +++ b/osu.Game/Tests/Visual/DependencyProvidingContainer.cs @@ -20,8 +20,7 @@ namespace osu.Game.Tests.Visual /// /// The dependencies provided to the children. /// - // TODO: should be an init-only property when C# 9 - public (Type, object)[] CachedDependencies { get; set; } = Array.Empty<(Type, object)>(); + public (Type, object)[] CachedDependencies { get; init; } = Array.Empty<(Type, object)>(); protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { From cf009432cc5af59b8a35e809468ece6472eb2561 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Feb 2023 15:41:45 +0900 Subject: [PATCH 199/516] 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 200/516] 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 258de3b2d89cc2a7a4a624202c8460be89e83638 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 9 Feb 2023 17:15:37 +0900 Subject: [PATCH 201/516] Store RawTime in JudgementResult --- .../Rulesets/Judgements/JudgementResult.cs | 33 ++++++++++++------- .../Objects/Drawables/DrawableHitObject.cs | 2 +- osu.Game/Rulesets/UI/Playfield.cs | 12 +++++-- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/JudgementResult.cs b/osu.Game/Rulesets/Judgements/JudgementResult.cs index 6749fd7932..bf29919e34 100644 --- a/osu.Game/Rulesets/Judgements/JudgementResult.cs +++ b/osu.Game/Rulesets/Judgements/JudgementResult.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using JetBrains.Annotations; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -33,19 +34,30 @@ namespace osu.Game.Rulesets.Judgements public readonly Judgement Judgement; /// - /// The offset of from the end time of , clamped by . - /// Populated when this is applied via . - /// - public double TimeOffset { get; internal set; } - - /// - /// The absolute time at which this occurred. + /// The time at which this occurred. /// Populated when this is applied via . /// /// - /// This is initially set to the end time of . + /// This is used instead of to check whether this should be reverted. /// - public double TimeAbsolute { get; internal set; } + internal double? RawTime { get; set; } + + /// + /// The offset of from the end time of , clamped by . + /// + public double TimeOffset + { + get => RawTime != null ? Math.Min(RawTime.Value - HitObject.GetEndTime(), HitObject.MaximumJudgementOffset) : 0; + internal set => RawTime = HitObject.GetEndTime() + value; + } + + /// + /// The absolute time at which this occurred, clamped by the end time of plus . + /// + /// + /// The end time of is returned if this result is not populated yet. + /// + public double TimeAbsolute => RawTime != null ? Math.Min(RawTime.Value, HitObject.GetEndTime() + HitObject.MaximumJudgementOffset) : HitObject.GetEndTime(); /// /// The combo prior to this occurring. @@ -92,8 +104,7 @@ namespace osu.Game.Rulesets.Judgements internal void Reset() { Type = HitResult.None; - TimeOffset = 0; - TimeAbsolute = HitObject.GetEndTime(); + RawTime = null; } public override string ToString() => $"{Type} (Score:{Judgement.NumericResultFor(this)} HP:{Judgement.HealthIncreaseFor(this)} {Judgement})"; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index d30fc00bfc..f7c6340419 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -661,7 +661,7 @@ namespace osu.Game.Rulesets.Objects.Drawables $"{GetType().ReadableName()} applied an invalid hit result (was: {Result.Type}, expected: [{Result.Judgement.MinResult} ... {Result.Judgement.MaxResult}])."); } - Result.TimeOffset = Math.Min(HitObject.MaximumJudgementOffset, Time.Current - HitObject.GetEndTime()); + Result.RawTime = Time.Current; if (Result.HasResult) updateState(Result.IsHit ? ArmedState.Hit : ArmedState.Miss); diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 5d6a8de33c..b1c3b78e67 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -258,8 +258,16 @@ namespace osu.Game.Rulesets.UI } // When rewinding, revert future judgements in the reverse order. - while (judgedEntries.Count > 0 && Time.Current < judgedEntries.Peek().Result.AsNonNull().TimeAbsolute) + while (judgedEntries.Count > 0) + { + var result = judgedEntries.Peek().Result; + Debug.Assert(result?.RawTime != null); + + if (Time.Current >= result.RawTime.Value) + break; + revertResult(judgedEntries.Pop()); + } } /// @@ -453,7 +461,7 @@ namespace osu.Game.Rulesets.UI private void onNewResult(DrawableHitObject drawable, JudgementResult result) { - Debug.Assert(result != null && drawable.Entry?.Result == result); + Debug.Assert(result != null && drawable.Entry?.Result == result && result.RawTime != null); judgedEntries.Push(drawable.Entry.AsNonNull()); NewResult?.Invoke(drawable, result); From 5ddaf8ea3c2d0f79f891a1a8672e534e3e2dc13e Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 9 Feb 2023 17:43:04 +0900 Subject: [PATCH 202/516] Fix test setting invalid TimeOffset --- .../Visual/Gameplay/TestSceneUnstableRateCounter.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs index 2f572b46c9..d0e516ed39 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs @@ -22,12 +22,18 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached(typeof(ScoreProcessor))] private TestScoreProcessor scoreProcessor = new TestScoreProcessor(); - private readonly OsuHitWindows hitWindows = new OsuHitWindows(); + private readonly OsuHitWindows hitWindows; private UnstableRateCounter counter; private double prev; + public TestSceneUnstableRateCounter() + { + hitWindows = new OsuHitWindows(); + hitWindows.SetDifficulty(5); + } + [SetUpSteps] public void SetUp() { From 34d1890f1c85089168b6e69f16532b0edfb09447 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Feb 2023 17:57:51 +0900 Subject: [PATCH 203/516] 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 204/516] 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 205/516] 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 206/516] 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 207/516] 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 7bad0113cddef9dade7c49a8cea1a0b78cdad28c Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 9 Feb 2023 11:15:21 -0600 Subject: [PATCH 208/516] Move early fade effect to classic mod setting --- osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs | 25 +++++++++++++++++++ .../Objects/Drawables/DrawableHitCircle.cs | 4 --- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs index e021992f86..8d79157f82 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; @@ -11,6 +12,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods @@ -31,6 +33,9 @@ namespace osu.Game.Rulesets.Osu.Mods [SettingSource("Always play a slider's tail sample", "Always plays a slider's tail sample regardless of whether it was hit or not.")] public Bindable AlwaysPlayTailSample { get; } = new BindableBool(true); + [SettingSource("Fade out hit circles earlier", "Make hit circles fade out into a miss, rather than after it.")] + public Bindable FadeHitCircleEarly { get; } = new Bindable(true); + public void ApplyToHitObject(HitObject hitObject) { switch (hitObject) @@ -59,12 +64,32 @@ namespace osu.Game.Rulesets.Osu.Mods { case DrawableSliderHead head: head.TrackFollowCircle = !NoSliderHeadMovement.Value; + if (FadeHitCircleEarly.Value) + applyEarlyFading(head); break; case DrawableSliderTail tail: tail.SamplePlaysOnlyOnHit = !AlwaysPlayTailSample.Value; break; + + case DrawableHitCircle circle: + if (FadeHitCircleEarly.Value) + applyEarlyFading(circle); + break; } } + + private void applyEarlyFading(DrawableHitCircle circle) + { + circle.ApplyCustomUpdateState += (o, _) => + { + using (o.BeginAbsoluteSequence(o.StateUpdateTime)) + { + double mehWindow = o.HitObject.HitWindows.WindowFor(HitResult.Meh); + double lateMissFadeTime = mehWindow / 4 + 15; + o.Delay(mehWindow - lateMissFadeTime).FadeOut(lateMissFadeTime); + } + }; + } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 8467d33e9b..3458069dd1 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -200,10 +200,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables // always fade out at the circle's start time (to match user expectations). ApproachCircle.FadeOut(50); - - double mehWindow = HitObject.HitWindows.WindowFor(HitResult.Meh); - double lateMissFadeTime = mehWindow / 4 + 15; - this.Delay(mehWindow - lateMissFadeTime).FadeOut(lateMissFadeTime); } protected override void UpdateHitStateTransforms(ArmedState state) From 51816b92c6a2264653ec553c9509e575af5aa3f1 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Thu, 9 Feb 2023 23:23:58 +0100 Subject: [PATCH 209/516] 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 6d99e099129c9518dadd34c3b1a683ed6c5c33c6 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 9 Feb 2023 16:10:11 -0600 Subject: [PATCH 210/516] Modify tests --- .../TestSceneHitCircleLateFade.cs | 124 +++++++++++++++--- 1 file changed, 104 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs index 3195c0b24b..170c230ef7 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs @@ -3,10 +3,16 @@ #nullable disable +using System; +using System.Linq; using NUnit.Framework; using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; @@ -16,33 +22,111 @@ namespace osu.Game.Rulesets.Osu.Tests { public partial class TestSceneHitCircleLateFade : OsuTestScene { - [Test] - public void TestFadeOutIntoMiss() - { - float? alphaAtMiss = null; + private float? alphaAtMiss; + [Test] + public void TestHitCircleClassicMod() + { AddStep("Create hit circle", () => { - alphaAtMiss = null; - - DrawableHitCircle drawableHitCircle = new DrawableHitCircle(new HitCircle - { - StartTime = Time.Current + 500, - Position = new Vector2(250) - }); - - drawableHitCircle.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - - drawableHitCircle.OnNewResult += (_, _) => - { - alphaAtMiss = drawableHitCircle.Alpha; - }; - - Child = drawableHitCircle; + SelectedMods.Value = new Mod[] { new OsuModClassic() }; + createCircle(); }); AddUntilStep("Wait until circle is missed", () => alphaAtMiss.IsNotNull()); AddAssert("Transparent when missed", () => alphaAtMiss == 0); } + + [Test] + public void TestHitCircleNoMod() + { + AddStep("Create hit circle", () => + { + SelectedMods.Value = Array.Empty(); + createCircle(); + }); + + AddUntilStep("Wait until circle is missed", () => alphaAtMiss.IsNotNull()); + AddAssert("Opaque when missed", () => alphaAtMiss == 1); + } + + [Test] + public void TestSliderClassicMod() + { + AddStep("Create slider", () => + { + SelectedMods.Value = new Mod[] { new OsuModClassic() }; + createSlider(); + }); + + AddUntilStep("Wait until head circle is missed", () => alphaAtMiss.IsNotNull()); + AddAssert("Head circle transparent when missed", () => alphaAtMiss == 0); + } + + [Test] + public void TestSliderNoMod() + { + AddStep("Create slider", () => + { + SelectedMods.Value = Array.Empty(); + createSlider(); + }); + + AddUntilStep("Wait until head circle is missed", () => alphaAtMiss.IsNotNull()); + AddAssert("Head circle opaque when missed", () => alphaAtMiss == 1); + } + + private void createCircle() + { + alphaAtMiss = null; + + DrawableHitCircle drawableHitCircle = new DrawableHitCircle(new HitCircle + { + StartTime = Time.Current + 500, + Position = new Vector2(250) + }); + + foreach (var mod in SelectedMods.Value.OfType()) + mod.ApplyToDrawableHitObject(drawableHitCircle); + + drawableHitCircle.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + drawableHitCircle.OnNewResult += (_, _) => + { + alphaAtMiss = drawableHitCircle.Alpha; + }; + + Child = drawableHitCircle; + } + + private void createSlider() + { + alphaAtMiss = null; + + DrawableSlider drawableSlider = new DrawableSlider(new Slider + { + StartTime = Time.Current + 500, + Position = new Vector2(250), + Path = new SliderPath(PathType.Linear, new[] + { + Vector2.Zero, + new Vector2(0, 100), + }) + }); + + drawableSlider.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + drawableSlider.OnLoadComplete += _ => + { + foreach (var mod in SelectedMods.Value.OfType()) + mod.ApplyToDrawableHitObject(drawableSlider.HeadCircle); + + drawableSlider.HeadCircle.OnNewResult += (_, _) => + { + alphaAtMiss = drawableSlider.HeadCircle.Alpha; + }; + }; + Child = drawableSlider; + } } } 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 211/516] 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 212/516] 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 213/516] 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 214/516] 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 215/516] 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 216/516] 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 217/516] 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 218/516] 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 219/516] 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 220/516] 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 221/516] 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 61c968d7f8bf51692983e1cddaa175a8d1209878 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 19:18:00 +0900 Subject: [PATCH 222/516] Revert completely incorrect change --- osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index 05ba2b8f22..2d466b0da8 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -94,8 +94,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy d.Anchor = Anchor.TopCentre; d.RelativeSizeAxes = Axes.Both; d.Size = Vector2.One; - d.FillMode = FillMode.Stretch; - d.Height = minimumColumnWidth / d.DrawWidth * 1.6f; // constant matching stable. // Todo: Wrap? }); From 5091c5000342f40a28a0f81a556ad224d3fd70cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 19:18:17 +0900 Subject: [PATCH 223/516] Change scroll direction logic to not interfere with scale --- osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index 2d466b0da8..96dbbf6620 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -163,7 +163,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy if (bodySprite != null) { bodySprite.Origin = Anchor.BottomCentre; - bodySprite.Scale = new Vector2(1, -1); + bodySprite.Scale = new Vector2(bodySprite.Scale.X, Math.Abs(bodySprite.Scale.Y) * -1); } if (light != null) @@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy if (bodySprite != null) { bodySprite.Origin = Anchor.TopCentre; - bodySprite.Scale = Vector2.One; + bodySprite.Scale = new Vector2(bodySprite.Scale.X, Math.Abs(bodySprite.Scale.Y)); } if (light != null) From 635e225d19e1a60a9258b6f4274d808004dcf5f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 19:18:41 +0900 Subject: [PATCH 224/516] Add correct lookup for `WidthForNoteHeightScale` --- osu.Game/Skinning/LegacyManiaSkinConfiguration.cs | 2 ++ osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs | 1 + osu.Game/Skinning/LegacyManiaSkinDecoder.cs | 4 +--- osu.Game/Skinning/LegacySkin.cs | 4 ++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs index 5ed2ddc73c..192d00317b 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs @@ -29,6 +29,8 @@ namespace osu.Game.Skinning public Dictionary ImageLookups = new Dictionary(); + public float WidthForNoteHeightScale; + public readonly float[] ColumnLineWidth; public readonly float[] ColumnSpacing; public readonly float[] ColumnWidth; diff --git a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs index 3ec0ee6006..a73412ffc5 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs @@ -54,6 +54,7 @@ namespace osu.Game.Skinning HoldNoteBodyImage, HoldNoteLightImage, HoldNoteLightScale, + WidthForNoteHeightScale, ExplosionImage, ExplosionScale, ColumnLineColour, diff --git a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs index 0aafdd4db0..7f14d46cb9 100644 --- a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs +++ b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs @@ -115,9 +115,7 @@ namespace osu.Game.Skinning break; case "WidthForNoteHeightScale": - float minWidth = float.Parse(pair.Value, CultureInfo.InvariantCulture) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR; - if (minWidth > 0) - currentConfig.MinimumColumnWidth = minWidth; + currentConfig.WidthForNoteHeightScale = (float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR; break; case string when pair.Key.StartsWith("Colour", StringComparison.Ordinal): diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 5f12d2ce23..ec1b1d8425 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -138,6 +138,10 @@ namespace osu.Game.Skinning Debug.Assert(maniaLookup.ColumnIndex != null); return SkinUtils.As(new Bindable(existing.ColumnWidth[maniaLookup.ColumnIndex.Value])); + case LegacyManiaSkinConfigurationLookups.WidthForNoteHeightScale: + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(new Bindable(existing.WidthForNoteHeightScale)); + case LegacyManiaSkinConfigurationLookups.ColumnSpacing: Debug.Assert(maniaLookup.ColumnIndex != null); return SkinUtils.As(new Bindable(existing.ColumnSpacing[maniaLookup.ColumnIndex.Value])); From bfbffc4a68284b2d94a43010c8523825490896b9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 19:30:41 +0900 Subject: [PATCH 225/516] Add parsing support for mania `NoteBodyStyle` --- osu.Game/Skinning/LegacyManiaSkinConfiguration.cs | 2 ++ .../LegacyManiaSkinConfigurationLookup.cs | 1 + osu.Game/Skinning/LegacyManiaSkinDecoder.cs | 5 +++++ osu.Game/Skinning/LegacyNoteBodyStyle.cs | 15 +++++++++++++++ osu.Game/Skinning/LegacySkin.cs | 10 ++++++++++ 5 files changed, 33 insertions(+) create mode 100644 osu.Game/Skinning/LegacyNoteBodyStyle.cs diff --git a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs index 192d00317b..1ff9988332 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs @@ -43,6 +43,8 @@ namespace osu.Game.Skinning public bool ShowJudgementLine = true; public bool KeysUnderNotes; + public LegacyNoteBodyStyle? NoteBodyStyle; + public LegacyManiaSkinConfiguration(int keys) { Keys = keys; diff --git a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs index a73412ffc5..a2408a92bb 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs @@ -72,5 +72,6 @@ namespace osu.Game.Skinning Hit50, Hit0, KeysUnderNotes, + NoteBodyStyle } } diff --git a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs index 7f14d46cb9..e880e3c1ed 100644 --- a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs +++ b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs @@ -114,6 +114,11 @@ namespace osu.Game.Skinning parseArrayValue(pair.Value, currentConfig.HoldNoteLightWidth); break; + case "NoteBodyStyle": + if (Enum.TryParse(pair.Value, out var style)) + currentConfig.NoteBodyStyle = style; + break; + case "WidthForNoteHeightScale": currentConfig.WidthForNoteHeightScale = (float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR; break; diff --git a/osu.Game/Skinning/LegacyNoteBodyStyle.cs b/osu.Game/Skinning/LegacyNoteBodyStyle.cs new file mode 100644 index 0000000000..788bcc5432 --- /dev/null +++ b/osu.Game/Skinning/LegacyNoteBodyStyle.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Skinning +{ + public enum LegacyNoteBodyStyle + { + Stretch = 0, + RepeatTop = 2, + RepeatBottom = 3, + RepeatTopAndBottom = 4, + //Repeat = 1, + //RepeatMiddle = 5, + } +} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index ec1b1d8425..b2619fa55b 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -189,6 +189,16 @@ namespace osu.Game.Skinning case LegacyManiaSkinConfigurationLookups.MinimumColumnWidth: return SkinUtils.As(new Bindable(existing.MinimumColumnWidth)); + case LegacyManiaSkinConfigurationLookups.NoteBodyStyle: + + if (existing.NoteBodyStyle != null) + return SkinUtils.As(new Bindable(existing.NoteBodyStyle.Value)); + + if (GetConfig(SkinConfiguration.LegacySetting.Version)?.Value < 2.5m) + return SkinUtils.As(new Bindable(LegacyNoteBodyStyle.Stretch)); + + return SkinUtils.As(new Bindable(LegacyNoteBodyStyle.RepeatBottom)); + case LegacyManiaSkinConfigurationLookups.NoteImage: Debug.Assert(maniaLookup.ColumnIndex != null); return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.ColumnIndex}")); From b1d2a433f8399b22be74dc79b6fb511307330379 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2023 20:36:58 +0900 Subject: [PATCH 226/516] Apply second attempt at fixing long note bodies --- .../Skinning/Legacy/LegacyBodyPiece.cs | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index 96dbbf6620..b26e33b133 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -2,12 +2,15 @@ // 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.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; +using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Framework.Testing; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; @@ -34,6 +37,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy private Drawable? lightContainer; private Drawable? light; + private LegacyNoteBodyStyle? bodyStyle; public LegacyBodyPiece() { @@ -54,9 +58,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy float lightScale = GetColumnSkinConfig(skin, LegacyManiaSkinConfigurationLookups.HoldNoteLightScale)?.Value ?? 1; - float minimumColumnWidth = GetColumnSkinConfig(skin, LegacyManiaSkinConfigurationLookups.MinimumColumnWidth)?.Value - ?? 1; - // Create a temporary animation to retrieve the number of frames, in an effort to calculate the intended frame length. // This animation is discarded and re-queried with the appropriate frame length afterwards. var tmp = skin.GetAnimation(lightImage, true, false); @@ -83,7 +84,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy }; } - bodySprite = skin.GetAnimation(imageName, WrapMode.ClampToEdge, WrapMode.ClampToEdge, true, true).With(d => + bodyStyle = skin.GetConfig(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.NoteBodyStyle))?.Value; + + var wrapMode = bodyStyle == LegacyNoteBodyStyle.Stretch ? WrapMode.ClampToEdge : WrapMode.Repeat; + + direction.BindTo(scrollingInfo.Direction); + isHitting.BindTo(holdNote.IsHitting); + + bodySprite = skin.GetAnimation(imageName, wrapMode, wrapMode, true, true).With(d => { if (d == null) return; @@ -99,9 +107,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy if (bodySprite != null) InternalChild = bodySprite; - - direction.BindTo(scrollingInfo.Direction); - isHitting.BindTo(holdNote.IsHitting); } protected override void LoadComplete() @@ -205,6 +210,29 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { base.Update(); missFadeTime.Value ??= holdNote.HoldBrokenTime; + + // here we go... + switch (bodyStyle) + { + case LegacyNoteBodyStyle.Stretch: + // this is how lazer works by default. nothing required. + break; + + default: + // this is where things get fucked up. + // honestly there's three modes to handle here but they seem really pointless? + // let's wait to see if anyone actually uses them in skins. + if (bodySprite != null) + { + var sprite = bodySprite as Sprite ?? bodySprite.ChildrenOfType().Single(); + + bodySprite.FillMode = FillMode.Stretch; + // i dunno this looks about right?? + bodySprite.Scale = new Vector2(1, 10000 / sprite.DrawHeight); + } + + break; + } } protected override void Dispose(bool isDisposing) From 81c3e0da317acb6af9b2ec8741f3db105505c821 Mon Sep 17 00:00:00 2001 From: Terochi Date: Fri, 10 Feb 2023 17:58:48 +0100 Subject: [PATCH 227/516] 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 228/516] 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 229/516] 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 230/516] 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 231/516] 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 232/516] 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 233/516] 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 234/516] 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 235/516] 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 236/516] 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 237/516] 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 defe1fbf5032d7120d173571852d5d3f6ae2fe75 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 12 Feb 2023 09:25:28 -0600 Subject: [PATCH 238/516] Remove '#nullable disable' --- osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs index 170c230ef7..615c878014 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.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 System.Linq; using NUnit.Framework; From afb66d8af41517dc1ad85ed2f5798ea997a20193 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 12 Feb 2023 12:32:17 -0800 Subject: [PATCH 239/516] 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 240/516] 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 241/516] 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 ca768ca4464900e158e2997022a93ee252a93c9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Feb 2023 17:43:52 +0900 Subject: [PATCH 242/516] Add comment regarding unused enum members in `LegacyNoteBodyStyle` --- osu.Game/Skinning/LegacyNoteBodyStyle.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/LegacyNoteBodyStyle.cs b/osu.Game/Skinning/LegacyNoteBodyStyle.cs index 788bcc5432..3c1108dcef 100644 --- a/osu.Game/Skinning/LegacyNoteBodyStyle.cs +++ b/osu.Game/Skinning/LegacyNoteBodyStyle.cs @@ -6,10 +6,12 @@ namespace osu.Game.Skinning public enum LegacyNoteBodyStyle { Stretch = 0, + + // listed as the default on https://osu.ppy.sh/wiki/en/Skinning/skin.ini, but is seemingly not according to the source. + // Repeat = 1, + RepeatTop = 2, RepeatBottom = 3, RepeatTopAndBottom = 4, - //Repeat = 1, - //RepeatMiddle = 5, } } From 55358d36c83d8886a047cdeb95d20eaebf154bb5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Feb 2023 17:50:32 +0900 Subject: [PATCH 243/516] Change `MinimumColumnWidth` to remove setter --- osu.Game/Skinning/LegacyManiaSkinConfiguration.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs index 1ff9988332..f460a3d31a 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfiguration.cs @@ -59,12 +59,6 @@ namespace osu.Game.Skinning ColumnWidth.AsSpan().Fill(DEFAULT_COLUMN_SIZE); } - private float? minimumColumnWidth; - - public float MinimumColumnWidth - { - get => minimumColumnWidth ?? ColumnWidth.Min(); - set => minimumColumnWidth = value; - } + public float MinimumColumnWidth => ColumnWidth.Min(); } } From 006356e61777968d96957304cb31233c4587104b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 13 Feb 2023 14:17:33 +0300 Subject: [PATCH 244/516] 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 245/516] 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 246/516] 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 247/516] 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 248/516] 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 249/516] 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 250/516] 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 251/516] 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 252/516] 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 253/516] 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 254/516] 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 255/516] 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 e4b84ebd0b3a89e56c07da34195862bccfbbb38c Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Mon, 13 Feb 2023 23:51:39 +0100 Subject: [PATCH 256/516] Add `UseResumeOverlay` and use it for hiding the `ResumeOverlay` --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 4 ++-- osu.Game/Rulesets/UI/DrawableRuleset.cs | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 276724c169..9eb0a46bfb 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -54,14 +54,14 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.ResumeOverlay = null; - // Grab the input manager to disable the user's cursor, and for future use inputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager; inputManager.AllowUserCursorMovement = false; // Generate the replay frames the cursor should follow replayFrames = new OsuAutoGenerator(drawableRuleset.Beatmap, drawableRuleset.Mods).Generate().Frames.Cast().ToList(); + + drawableRuleset.UseResumeOverlay = false; } } } diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 403dee5651..23e8d1fc2d 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -196,6 +196,8 @@ namespace osu.Game.Rulesets.UI if ((ResumeOverlay = CreateResumeOverlay()) != null) { + UseResumeOverlay = true; + AddInternal(CreateInputManager() .WithChild(CreatePlayfieldAdjustmentContainer() .WithChild(ResumeOverlay))); @@ -230,7 +232,7 @@ namespace osu.Game.Rulesets.UI public override void RequestResume(Action continueResume) { - if (ResumeOverlay != null && (Cursor == null || (Cursor.LastFrameState == Visibility.Visible && Contains(Cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre)))) + if (ResumeOverlay != null && UseResumeOverlay && (Cursor == null || (Cursor.LastFrameState == Visibility.Visible && Contains(Cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre)))) { ResumeOverlay.GameplayCursor = Cursor; ResumeOverlay.ResumeAction = continueResume; @@ -507,6 +509,12 @@ namespace osu.Game.Rulesets.UI /// public ResumeOverlay ResumeOverlay { get; set; } + /// + /// Whether the should be used to return the user's cursor position to its previous location after a pause. + /// + /// Defaults to true if a ruleset returns a non-null overlay via . + public bool UseResumeOverlay { get; set; } + /// /// Returns first available provided by a . /// From a820c0c8ebdc7d1e6ccb5e6a59d0cb5c50851d51 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Mon, 13 Feb 2023 23:55:13 +0100 Subject: [PATCH 257/516] Add `TestSceneInstantResume` --- .../TestSceneInstantResume.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneInstantResume.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneInstantResume.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneInstantResume.cs new file mode 100644 index 0000000000..2bc6386185 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneInstantResume.cs @@ -0,0 +1,34 @@ +// 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.Game.Rulesets.Osu.Mods; +using osu.Game.Tests.Visual; +using osuTK.Input; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public partial class TestSceneInstantResume : TestSceneOsuPlayer + { + protected override bool HasCustomSteps => true; + + protected override TestPlayer CreatePlayer(Ruleset ruleset) + { + SelectedMods.Value = new[] { new OsuModAutopilot() }; + return new TestPlayer(); + } + + [Test] + public void TestInstantResume() + { + CreateTest(); + + AddStep("press pause", () => InputManager.PressKey(Key.Escape)); + AddUntilStep("wait until paused", () => Player.GameplayClockContainer.IsPaused.Value); + AddStep("release pause", () => InputManager.ReleaseKey(Key.Escape)); + AddStep("press resume", () => InputManager.PressKey(Key.Escape)); + AddUntilStep("wait for resume", () => !Player.IsResuming); + AddAssert("resumed", () => !Player.GameplayClockContainer.IsPaused.Value); + } + } +} 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 258/516] 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 259/516] 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 260/516] 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 261/516] 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 262/516] 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 bd8c58dc62f7a97dba8aa8ce0e629f04f2258bf4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 14:34:12 +0900 Subject: [PATCH 263/516] Adjust applied body ratio to ROUGHLY match stable --- osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index b26e33b133..69eacda541 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -228,7 +228,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy bodySprite.FillMode = FillMode.Stretch; // i dunno this looks about right?? - bodySprite.Scale = new Vector2(1, 10000 / sprite.DrawHeight); + bodySprite.Scale = new Vector2(1, 32800 / sprite.DrawHeight); } break; From 9e04a36d86c9a19e37cf470aa4c4505fa9ad4ef9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 15:07:45 +0900 Subject: [PATCH 264/516] Move test to a mod test and add more resilient test logic --- .../TestSceneOsuModAutopilot.cs} | 21 ++++++++----------- osu.Game/Tests/Visual/ModTestScene.cs | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) rename osu.Game.Rulesets.Osu.Tests/{TestSceneInstantResume.cs => Mods/TestSceneOsuModAutopilot.cs} (66%) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneInstantResume.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutopilot.cs similarity index 66% rename from osu.Game.Rulesets.Osu.Tests/TestSceneInstantResume.cs rename to osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutopilot.cs index 2bc6386185..37b31d1d1a 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneInstantResume.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutopilot.cs @@ -3,26 +3,23 @@ using NUnit.Framework; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Tests.Visual; using osuTK.Input; -namespace osu.Game.Rulesets.Osu.Tests +namespace osu.Game.Rulesets.Osu.Tests.Mods { - public partial class TestSceneInstantResume : TestSceneOsuPlayer + public partial class TestSceneOsuModAutopilot : OsuModTestScene { - protected override bool HasCustomSteps => true; - - protected override TestPlayer CreatePlayer(Ruleset ruleset) - { - SelectedMods.Value = new[] { new OsuModAutopilot() }; - return new TestPlayer(); - } - [Test] public void TestInstantResume() { - CreateTest(); + CreateModTest(new ModTestData + { + Mod = new OsuModAutopilot(), + PassCondition = () => true, + Autoplay = false, + }); + AddUntilStep("wait for gameplay start", () => Player.LocalUserPlaying.Value); AddStep("press pause", () => InputManager.PressKey(Key.Escape)); AddUntilStep("wait until paused", () => Player.GameplayClockContainer.IsPaused.Value); AddStep("release pause", () => InputManager.ReleaseKey(Key.Escape)); diff --git a/osu.Game/Tests/Visual/ModTestScene.cs b/osu.Game/Tests/Visual/ModTestScene.cs index 0559d80384..aa5b506343 100644 --- a/osu.Game/Tests/Visual/ModTestScene.cs +++ b/osu.Game/Tests/Visual/ModTestScene.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual protected override bool CheckModsAllowFailure() => allowFail; public ModTestPlayer(ModTestData data, bool allowFail) - : base(false, false) + : base(true, false) { this.allowFail = allowFail; currentTestData = data; From 63f349876290a3d5c07768e75116ae132dbbc2ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 15:11:33 +0900 Subject: [PATCH 265/516] Restructure `UseResumeOverlay` to correctly handle a value change before BDL load --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 23e8d1fc2d..c839062875 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -194,13 +194,16 @@ namespace osu.Game.Rulesets.UI Audio = audioContainer; - if ((ResumeOverlay = CreateResumeOverlay()) != null) + if (UseResumeOverlay) { - UseResumeOverlay = true; - - AddInternal(CreateInputManager() - .WithChild(CreatePlayfieldAdjustmentContainer() - .WithChild(ResumeOverlay))); + if ((ResumeOverlay = CreateResumeOverlay()) == null) + UseResumeOverlay = false; + else + { + AddInternal(CreateInputManager() + .WithChild(CreatePlayfieldAdjustmentContainer() + .WithChild(ResumeOverlay))); + } } applyRulesetMods(Mods, config); @@ -512,8 +515,8 @@ namespace osu.Game.Rulesets.UI /// /// Whether the should be used to return the user's cursor position to its previous location after a pause. /// - /// Defaults to true if a ruleset returns a non-null overlay via . - public bool UseResumeOverlay { get; set; } + /// Defaults to true, but will become false if the ruleset fails to return a non-null overlay via . + public bool UseResumeOverlay { get; set; } = true; /// /// Returns first available provided by a . From ea624b8ad0fa0d9fd78e192edb986abb360f6b3f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 13 Feb 2023 22:39:34 -0800 Subject: [PATCH 266/516] 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 267/516] 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 268/516] 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 269/516] 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); From 7aaaf7fca2d598998d7c407a3b259db985484b06 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 16:55:35 +0900 Subject: [PATCH 270/516] Combine and attempt to simplify the score import / preparation process further --- osu.Game/Rulesets/UI/RulesetInputManager.cs | 3 + osu.Game/Screens/Play/Player.cs | 82 ++++++++++----------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index a5e442b7de..7bf0482673 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -39,6 +39,9 @@ namespace osu.Game.Rulesets.UI { set { + if (value == recorder) + return; + if (value != null && recorder != null) throw new InvalidOperationException("Cannot attach more than one recorder"); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0825f36a0a..bc453d2151 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -276,7 +276,7 @@ namespace osu.Game.Screens.Play }, FailOverlay = new FailOverlay { - SaveReplay = prepareAndImportScore, + SaveReplay = async () => await prepareAndImportScoreAsync(true).ConfigureAwait(false), OnRetry = () => Restart(), OnQuit = () => PerformExit(true), }, @@ -614,7 +614,7 @@ namespace osu.Game.Screens.Play resultsDisplayDelegate?.Cancel(); // import current score if possible. - attemptScoreImport(); + prepareAndImportScoreAsync(); // The actual exit is performed if // - the pause / fail dialog was not requested @@ -772,10 +772,7 @@ namespace osu.Game.Screens.Play if (prepareScoreForDisplayTask == null) { // Try importing score since the task hasn't been invoked yet. - if (!attemptScoreImport()) - // If attempt failed, trying again is unnecessary - resultsDisplayDelegate?.Cancel(); - + prepareAndImportScoreAsync(); return; } @@ -785,6 +782,12 @@ namespace osu.Game.Screens.Play resultsDisplayDelegate?.Cancel(); + if (prepareScoreForDisplayTask.GetResultSafely() == null) + { + // If score import did not occur, we do not want to show the results screen. + return; + } + if (!this.IsCurrentScreen()) // This player instance may already be in the process of exiting. return; @@ -796,53 +799,48 @@ namespace osu.Game.Screens.Play } /// - /// Attempts to run + /// Asynchronously run score preparation operations (database import, online submission etc.). /// - /// - /// Whether the attempt was successful - /// - private bool attemptScoreImport() + /// Whether the score should be imported even if non-passing (or the current configuration doesn't allow for it). + /// The final score. + [ItemCanBeNull] + private Task prepareAndImportScoreAsync(bool forceImport = false) { // Ensure we are not writing to the replay any more, as we are about to consume and store the score. DrawableRuleset.SetRecordTarget(null); + if (prepareScoreForDisplayTask != null) + return prepareScoreForDisplayTask; + // We do not want to import the score in cases where we don't show results bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed; - if (!canShowResults) - return false; + if (!canShowResults && !forceImport) + return Task.FromResult(null); - prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore); - - return true; - } - - /// - /// Asynchronously run score preparation operations (database import, online submission etc.). - /// - /// The final score. - private async Task prepareAndImportScore() - { - var scoreCopy = Score.DeepClone(); - - try + return prepareScoreForDisplayTask = Task.Run(async () => { - await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.Error(ex, @"Score preparation failed!"); - } + var scoreCopy = Score.DeepClone(); - try - { - await ImportScore(scoreCopy).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.Error(ex, @"Score import failed!"); - } + try + { + await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.Error(ex, @"Score preparation failed!"); + } - return scoreCopy.ScoreInfo; + try + { + await ImportScore(scoreCopy).ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.Error(ex, @"Score import failed!"); + } + + return scoreCopy.ScoreInfo; + }); } protected override bool OnScroll(ScrollEvent e) From 970388d4e22ca71b05021f7ee506a29313cfcc14 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 17:35:12 +0900 Subject: [PATCH 271/516] Move `Overlays` container to accept input and be frame-stable --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 71b452c309..c49f2d003f 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -184,11 +184,13 @@ namespace osu.Game.Rulesets.UI { RelativeSizeAxes = Axes.Both, Child = KeyBindingInputManager - .WithChild(CreatePlayfieldAdjustmentContainer() - .WithChild(Playfield) - ), + .WithChildren(new Drawable[] + { + CreatePlayfieldAdjustmentContainer() + .WithChild(Playfield), + Overlays + }), }, - Overlays, } }; From b42b5f97cfc5944b3a3d84d008c88e000d939cad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 17:36:01 +0900 Subject: [PATCH 272/516] Use `Overlays` container rather than `KeyBindingInputManager` for flashlight --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 45fa55c7f2..9fe0864c7a 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Mods flashlight.Colour = Color4.Black; flashlight.Combo.BindTo(Combo); - drawableRuleset.KeyBindingInputManager.Add(flashlight); + drawableRuleset.Overlays.Add(flashlight); } protected abstract Flashlight CreateFlashlight(); From 5ec5222d8acd2f902689e0b0e0eeffd697e46d2a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 17:35:41 +0900 Subject: [PATCH 273/516] Expose and consume `OsuInputManager` explicitly --- osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs | 7 ++++--- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 3 ++- osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs | 4 +++- osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs index 7db4e2625b..b76b8d8cf5 100644 --- a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs +++ b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; @@ -26,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Mods private const double flash_duration = 1000; - private DrawableRuleset ruleset = null!; + private DrawableOsuRuleset ruleset = null!; protected OsuAction? LastAcceptedAction { get; private set; } @@ -42,8 +43,8 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - ruleset = drawableRuleset; - drawableRuleset.KeyBindingInputManager.Add(new InputInterceptor(this)); + ruleset = (DrawableOsuRuleset)drawableRuleset; + ruleset.InputManager.Add(new InputInterceptor(this)); var periods = new List(); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 6772cfe0be..909238954a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -11,6 +11,7 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Replays; +using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods @@ -55,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { // Grab the input manager to disable the user's cursor, and for future use - inputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager; + inputManager = ((DrawableOsuRuleset)drawableRuleset).InputManager; inputManager.AllowUserCursorMovement = false; // Generate the replay frames the cursor should follow diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 753de6231a..4feb0f9537 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; @@ -42,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { // grab the input manager for future use. - osuInputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager; + osuInputManager = ((DrawableOsuRuleset)drawableRuleset).InputManager; } public void ApplyToPlayer(Player player) diff --git a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs index d1fa0d09cc..4ad95a8012 100644 --- a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs @@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Osu.UI { protected new OsuRulesetConfigManager Config => (OsuRulesetConfigManager)base.Config; + public OsuInputManager InputManager { get; private set; } + public new OsuPlayfield Playfield => (OsuPlayfield)base.Playfield; public DrawableOsuRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) @@ -39,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.UI protected override Playfield CreatePlayfield() => new OsuPlayfield(); - protected override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo); + protected override PassThroughInputManager CreateInputManager() => InputManager = new OsuInputManager(Ruleset.RulesetInfo); public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new OsuPlayfieldAdjustmentContainer { AlignWithStoryboard = true }; diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index c49f2d003f..11b238480a 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.UI /// /// The key conversion input manager for this DrawableRuleset. /// - public PassThroughInputManager KeyBindingInputManager; + protected PassThroughInputManager KeyBindingInputManager; public override double GameplayStartTime => Objects.FirstOrDefault()?.StartTime - 2000 ?? 0; From c540d78fbc05065d859a298ebb2c4d717e3fb944 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Feb 2023 18:10:25 +0900 Subject: [PATCH 274/516] Expose the actual `KeyBindingInputManager` Turns out that `CreateInputManager` is called more than once, and some mods (ie. `InputBlockingMod`) rely on consuming the "main" one. So let's go back to accessing and exposing in `DrawableOsuRuleset` rather than storing out own reference. --- osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 2 +- osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs index b76b8d8cf5..b56fdbdf74 100644 --- a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs +++ b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { ruleset = (DrawableOsuRuleset)drawableRuleset; - ruleset.InputManager.Add(new InputInterceptor(this)); + ruleset.KeyBindingInputManager.Add(new InputInterceptor(this)); var periods = new List(); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 909238954a..d39ca06da3 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { // Grab the input manager to disable the user's cursor, and for future use - inputManager = ((DrawableOsuRuleset)drawableRuleset).InputManager; + inputManager = ((DrawableOsuRuleset)drawableRuleset).KeyBindingInputManager; inputManager.AllowUserCursorMovement = false; // Generate the replay frames the cursor should follow diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 4feb0f9537..32ffb545e0 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { // grab the input manager for future use. - osuInputManager = ((DrawableOsuRuleset)drawableRuleset).InputManager; + osuInputManager = ((DrawableOsuRuleset)drawableRuleset).KeyBindingInputManager; } public void ApplyToPlayer(Player player) diff --git a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs index 4ad95a8012..c3efd48053 100644 --- a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.UI { protected new OsuRulesetConfigManager Config => (OsuRulesetConfigManager)base.Config; - public OsuInputManager InputManager { get; private set; } + public new OsuInputManager KeyBindingInputManager => (OsuInputManager)base.KeyBindingInputManager; public new OsuPlayfield Playfield => (OsuPlayfield)base.Playfield; @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.UI protected override Playfield CreatePlayfield() => new OsuPlayfield(); - protected override PassThroughInputManager CreateInputManager() => InputManager = new OsuInputManager(Ruleset.RulesetInfo); + protected override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo); public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new OsuPlayfieldAdjustmentContainer { AlignWithStoryboard = true }; From 19e3c5d33c5495cc17180932806db5e3a1c34c14 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 13:59:24 +0900 Subject: [PATCH 275/516] Adjust song select background dimming to be more evenly applied --- osu.Game/Screens/Select/SongSelect.cs | 2 ++ osu.Game/Screens/Select/WedgeBackground.cs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 8786821c77..5c4a42852c 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -767,6 +767,8 @@ namespace osu.Game.Screens.Select { backgroundModeBeatmap.Beatmap = beatmap; backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; + backgroundModeBeatmap.IgnoreUserSettings.Value = true; + backgroundModeBeatmap.DimWhenUserSettingsIgnored.Value = 0.4f; backgroundModeBeatmap.FadeColour(Color4.White, 250); }); diff --git a/osu.Game/Screens/Select/WedgeBackground.cs b/osu.Game/Screens/Select/WedgeBackground.cs index da12c1a67a..fd4b91bf5f 100644 --- a/osu.Game/Screens/Select/WedgeBackground.cs +++ b/osu.Game/Screens/Select/WedgeBackground.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.Both, Size = new Vector2(1, 0.5f), - Colour = Color4.Black.Opacity(0.5f), + Colour = Color4.Black.Opacity(0.2f), Shear = new Vector2(0.15f, 0), EdgeSmoothness = new Vector2(2, 0), }, @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Select RelativePositionAxes = Axes.Y, Size = new Vector2(1, -0.5f), Position = new Vector2(0, 1), - Colour = Color4.Black.Opacity(0.5f), + Colour = Color4.Black.Opacity(0.2f), Shear = new Vector2(-0.15f, 0), EdgeSmoothness = new Vector2(2, 0), }, From 9ed068c1e67e870f49163620cf95697c5426a108 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 14:16:34 +0900 Subject: [PATCH 276/516] Only apply dim changes when background blur is disabled --- osu.Game/Graphics/Containers/UserDimContainer.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 16 +++++++++++++--- osu.Game/Screens/Select/WedgeBackground.cs | 9 +++------ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs index 25830c9d54..6f6292c3b2 100644 --- a/osu.Game/Graphics/Containers/UserDimContainer.cs +++ b/osu.Game/Graphics/Containers/UserDimContainer.cs @@ -21,7 +21,7 @@ namespace osu.Game.Graphics.Containers /// public const float BREAK_LIGHTEN_AMOUNT = 0.3f; - protected const double BACKGROUND_FADE_DURATION = 800; + public const double BACKGROUND_FADE_DURATION = 800; /// /// Whether or not user-configured settings relating to brightness of elements should be ignored diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 5c4a42852c..8546dfeeaa 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -31,6 +31,7 @@ using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; @@ -148,7 +149,7 @@ namespace osu.Game.Screens.Select if (!this.IsCurrentScreen()) return; - ApplyToBackground(b => b.BlurAmount.Value = e.NewValue ? BACKGROUND_BLUR : 0); + ApplyToBackground(applyBlurToBackground); }); LoadComponentAsync(Carousel = new BeatmapCarousel @@ -194,6 +195,7 @@ namespace osu.Game.Screens.Select { ParallaxAmount = 0.005f, RelativeSizeAxes = Axes.Both, + Alpha = 0, Anchor = Anchor.Centre, Origin = Anchor.Centre, Child = new WedgeBackground @@ -766,10 +768,10 @@ namespace osu.Game.Screens.Select ApplyToBackground(backgroundModeBeatmap => { backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; backgroundModeBeatmap.IgnoreUserSettings.Value = true; - backgroundModeBeatmap.DimWhenUserSettingsIgnored.Value = 0.4f; backgroundModeBeatmap.FadeColour(Color4.White, 250); + + applyBlurToBackground(backgroundModeBeatmap); }); beatmapInfoWedge.Beatmap = beatmap; @@ -787,6 +789,14 @@ namespace osu.Game.Screens.Select } } + private void applyBlurToBackground(BackgroundScreenBeatmap backgroundModeBeatmap) + { + backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; + backgroundModeBeatmap.DimWhenUserSettingsIgnored.Value = configBackgroundBlur.Value ? 0 : 0.4f; + + wedgeBackground.FadeTo(configBackgroundBlur.Value ? 0.5f : 0.2f, UserDimContainer.BACKGROUND_FADE_DURATION, Easing.OutQuint); + } + private readonly WeakReference lastTrack = new WeakReference(null); /// diff --git a/osu.Game/Screens/Select/WedgeBackground.cs b/osu.Game/Screens/Select/WedgeBackground.cs index fd4b91bf5f..2e2b43cd70 100644 --- a/osu.Game/Screens/Select/WedgeBackground.cs +++ b/osu.Game/Screens/Select/WedgeBackground.cs @@ -1,14 +1,11 @@ // 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.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osuTK; using osuTK.Graphics; -using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Select { @@ -22,7 +19,7 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.Both, Size = new Vector2(1, 0.5f), - Colour = Color4.Black.Opacity(0.2f), + Colour = Color4.Black, Shear = new Vector2(0.15f, 0), EdgeSmoothness = new Vector2(2, 0), }, @@ -32,7 +29,7 @@ namespace osu.Game.Screens.Select RelativePositionAxes = Axes.Y, Size = new Vector2(1, -0.5f), Position = new Vector2(0, 1), - Colour = Color4.Black.Opacity(0.2f), + Colour = Color4.Black, Shear = new Vector2(-0.15f, 0), EdgeSmoothness = new Vector2(2, 0), }, From 5e774a28d86f3ad35931d0df5da5a94f084eefc4 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 15 Feb 2023 00:45:58 -0600 Subject: [PATCH 277/516] Correct timings to match stable exactly + don't fade with hidden --- osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs index 8d79157f82..786b89d790 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs @@ -36,6 +36,8 @@ namespace osu.Game.Rulesets.Osu.Mods [SettingSource("Fade out hit circles earlier", "Make hit circles fade out into a miss, rather than after it.")] public Bindable FadeHitCircleEarly { get; } = new Bindable(true); + private bool hiddenModActive; + public void ApplyToHitObject(HitObject hitObject) { switch (hitObject) @@ -56,6 +58,8 @@ namespace osu.Game.Rulesets.Osu.Mods if (ClassicNoteLock.Value) osuRuleset.Playfield.HitPolicy = new ObjectOrderedHitPolicy(); + + hiddenModActive = drawableRuleset.Mods.OfType().Any(); } public void ApplyToDrawableHitObject(DrawableHitObject obj) @@ -64,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Mods { case DrawableSliderHead head: head.TrackFollowCircle = !NoSliderHeadMovement.Value; - if (FadeHitCircleEarly.Value) + if (FadeHitCircleEarly.Value && !hiddenModActive) applyEarlyFading(head); break; @@ -73,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Mods break; case DrawableHitCircle circle: - if (FadeHitCircleEarly.Value) + if (FadeHitCircleEarly.Value && !hiddenModActive) applyEarlyFading(circle); break; } @@ -85,9 +89,9 @@ namespace osu.Game.Rulesets.Osu.Mods { using (o.BeginAbsoluteSequence(o.StateUpdateTime)) { - double mehWindow = o.HitObject.HitWindows.WindowFor(HitResult.Meh); - double lateMissFadeTime = mehWindow / 4 + 15; - o.Delay(mehWindow - lateMissFadeTime).FadeOut(lateMissFadeTime); + double okWindow = o.HitObject.HitWindows.WindowFor(HitResult.Ok); + double lateMissFadeTime = o.HitObject.HitWindows.WindowFor(HitResult.Meh) - okWindow; + o.Delay(okWindow).FadeOut(lateMissFadeTime); } }; } From e71dfd75554c7d162c3d1fa8036859044469e1b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 16:11:16 +0900 Subject: [PATCH 278/516] Fix skin export failing if a directory exists with the proposed filename --- osu.Game/Database/LegacyExporter.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 09d6913dd9..7fe58240a2 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using osu.Framework.Platform; using osu.Game.Extensions; using osu.Game.Utils; @@ -43,7 +44,10 @@ namespace osu.Game.Database { string itemFilename = GetFilename(item).GetValidFilename(); - IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}"); + IEnumerable existingExports = + exportStorage + .GetFiles(string.Empty, $"{itemFilename}*{FileExtension}") + .Concat(exportStorage.GetDirectories(string.Empty)); string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}"); using (var stream = exportStorage.CreateFileSafely(filename)) From 8bbd00822c6ebad41fa036b05ccd966d100a48dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 17:24:34 +0900 Subject: [PATCH 279/516] Simplify and rename `SkinnableTargetComponentsContainer` --- .../Legacy/CatchLegacySkinTransformer.cs | 3 ++- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 4 ++-- osu.Game/Skinning/ArgonSkin.cs | 4 ++-- ...r.cs => DefaultSkinComponentsContainer.cs} | 23 +++++-------------- osu.Game/Skinning/LegacySkin.cs | 2 +- osu.Game/Skinning/Skin.cs | 4 +++- osu.Game/Skinning/SkinnableTargetContainer.cs | 10 ++++---- osu.Game/Skinning/TrianglesSkin.cs | 4 ++-- 8 files changed, 24 insertions(+), 30 deletions(-) rename osu.Game/Skinning/{SkinnableTargetComponentsContainer.cs => DefaultSkinComponentsContainer.cs} (61%) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 08ac55508a..a06435583b 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -4,6 +4,7 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Skinning; using osuTK.Graphics; @@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy switch (targetComponent.Lookup) { case GlobalSkinComponentLookup.LookupType.MainHUDComponents: - var components = base.GetDrawableComponent(lookup) as SkinnableTargetComponentsContainer; + var components = base.GetDrawableComponent(lookup) as Container; if (providesComboCounter && components != null) { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 5cd8c00935..943f1d31ba 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -58,14 +58,14 @@ namespace osu.Game.Tests.Visual.Gameplay protected bool AssertComponentsFromExpectedSource(GlobalSkinComponentLookup.LookupType target, ISkin expectedSource) { var actualComponentsContainer = Player.ChildrenOfType().First(s => s.Target == target) - .ChildrenOfType().SingleOrDefault(); + .ChildrenOfType().SingleOrDefault(); if (actualComponentsContainer == null) return false; var actualInfo = actualComponentsContainer.CreateSkinnableInfo(); - var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new GlobalSkinComponentLookup(target)); + var expectedComponentsContainer = (DefaultSkinComponentsContainer)expectedSource.GetDrawableComponent(new GlobalSkinComponentLookup(target)); if (expectedComponentsContainer == null) return false; diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 53c6c1e5ce..71f0888c6f 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -94,7 +94,7 @@ namespace osu.Game.Skinning switch (globalLookup.Lookup) { case GlobalSkinComponentLookup.LookupType.SongSelect: - var songSelectComponents = new SkinnableTargetComponentsContainer(_ => + var songSelectComponents = new DefaultSkinComponentsContainer(_ => { // do stuff when we need to. }); @@ -102,7 +102,7 @@ namespace osu.Game.Skinning return songSelectComponents; case GlobalSkinComponentLookup.LookupType.MainHUDComponents: - var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => + var skinnableTargetWrapper = new DefaultSkinComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); var accuracy = container.OfType().FirstOrDefault(); diff --git a/osu.Game/Skinning/SkinnableTargetComponentsContainer.cs b/osu.Game/Skinning/DefaultSkinComponentsContainer.cs similarity index 61% rename from osu.Game/Skinning/SkinnableTargetComponentsContainer.cs rename to osu.Game/Skinning/DefaultSkinComponentsContainer.cs index 8c6726c3f4..0d6e6b6ce9 100644 --- a/osu.Game/Skinning/SkinnableTargetComponentsContainer.cs +++ b/osu.Game/Skinning/DefaultSkinComponentsContainer.cs @@ -2,39 +2,28 @@ // See the LICENCE file in the repository root for full licence text. using System; -using Newtonsoft.Json; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; namespace osu.Game.Skinning { /// - /// A container which groups the components of a into a single object. - /// Optionally also applies a default layout to the components. + /// A container which can be used to specify default skin components layouts. + /// Handles applying a default layout to the components. /// - [Serializable] - public partial class SkinnableTargetComponentsContainer : Container, ISkinnableDrawable + public partial class DefaultSkinComponentsContainer : Container { - public bool IsEditable => false; - - public bool UsesFixedAnchor { get; set; } - private readonly Action? applyDefaults; /// /// Construct a wrapper with defaults that should be applied once. /// /// A function to apply the default layout. - public SkinnableTargetComponentsContainer(Action applyDefaults) - : this() - { - this.applyDefaults = applyDefaults; - } - - [JsonConstructor] - public SkinnableTargetComponentsContainer() + public DefaultSkinComponentsContainer(Action applyDefaults) { RelativeSizeAxes = Axes.Both; + + this.applyDefaults = applyDefaults; } protected override void LoadComplete() diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index b2619fa55b..284a938bce 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -347,7 +347,7 @@ namespace osu.Game.Skinning switch (target.Lookup) { case GlobalSkinComponentLookup.LookupType.MainHUDComponents: - var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => + var skinnableTargetWrapper = new DefaultSkinComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); var accuracy = container.OfType().FirstOrDefault(); diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 37e98946c9..c55b4e789c 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -11,6 +11,7 @@ using Newtonsoft.Json; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Framework.Logging; @@ -174,8 +175,9 @@ namespace osu.Game.Skinning foreach (var i in skinnableInfo) components.Add(i.CreateInstance()); - return new SkinnableTargetComponentsContainer + return new Container { + RelativeSizeAxes = Axes.Both, Children = components, }; } diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index df5299d427..b21e51c0cf 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -7,13 +7,14 @@ using System.Linq; using System.Threading; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Screens.Play.HUD; namespace osu.Game.Skinning { public partial class SkinnableTargetContainer : SkinReloadableDrawable, ISkinnableTarget { - private SkinnableTargetComponentsContainer? content; + private Container? content; public GlobalSkinComponentLookup.LookupType Target { get; } @@ -39,15 +40,16 @@ namespace osu.Game.Skinning foreach (var i in skinnableInfo) drawables.Add(i.CreateInstance()); - Reload(new SkinnableTargetComponentsContainer + Reload(new Container { + RelativeSizeAxes = Axes.Both, Children = drawables, }); } - public void Reload() => Reload(CurrentSkin.GetDrawableComponent(new GlobalSkinComponentLookup(Target)) as SkinnableTargetComponentsContainer); + public void Reload() => Reload(CurrentSkin.GetDrawableComponent(new GlobalSkinComponentLookup(Target)) as Container); - public void Reload(SkinnableTargetComponentsContainer? componentsContainer) + public void Reload(Container? componentsContainer) { ClearInternal(); components.Clear(); diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 62ef94691b..7de2b124e7 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -72,7 +72,7 @@ namespace osu.Game.Skinning switch (target.Lookup) { case GlobalSkinComponentLookup.LookupType.SongSelect: - var songSelectComponents = new SkinnableTargetComponentsContainer(_ => + var songSelectComponents = new DefaultSkinComponentsContainer(_ => { // do stuff when we need to. }); @@ -80,7 +80,7 @@ namespace osu.Game.Skinning return songSelectComponents; case GlobalSkinComponentLookup.LookupType.MainHUDComponents: - var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => + var skinnableTargetWrapper = new DefaultSkinComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); var accuracy = container.OfType().FirstOrDefault(); From ca75f0ec7766b21cee79bb035e1cda9e845259fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 17:26:05 +0900 Subject: [PATCH 280/516] Apply NRT to `TestSceneBeatmapSkinFallbacks` --- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 943f1d31ba..2109db81d4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -1,13 +1,12 @@ // 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 System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Graphics.Containers; using osu.Framework.Lists; using osu.Framework.Testing; using osu.Framework.Timing; @@ -28,10 +27,10 @@ namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneBeatmapSkinFallbacks : OsuPlayerTestScene { - private ISkin currentBeatmapSkin; + private ISkin currentBeatmapSkin = null!; [Resolved] - private SkinManager skinManager { get; set; } + private SkinManager skinManager { get; set; } = null!; protected override bool HasCustomSteps => true; @@ -65,7 +64,7 @@ namespace osu.Game.Tests.Visual.Gameplay var actualInfo = actualComponentsContainer.CreateSkinnableInfo(); - var expectedComponentsContainer = (DefaultSkinComponentsContainer)expectedSource.GetDrawableComponent(new GlobalSkinComponentLookup(target)); + var expectedComponentsContainer = expectedSource.GetDrawableComponent(new GlobalSkinComponentLookup(target)) as Container; if (expectedComponentsContainer == null) return false; @@ -92,7 +91,7 @@ namespace osu.Game.Tests.Visual.Gameplay return almostEqual(actualInfo, expectedInfo); } - private static bool almostEqual(SkinnableInfo info, SkinnableInfo other) => + private static bool almostEqual(SkinnableInfo info, SkinnableInfo? other) => other != null && info.Type == other.Type && info.Anchor == other.Anchor @@ -102,7 +101,7 @@ namespace osu.Game.Tests.Visual.Gameplay && Precision.AlmostEquals(info.Rotation, other.Rotation) && info.Children.SequenceEqual(other.Children, new FuncEqualityComparer(almostEqual)); - protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null) => new CustomSkinWorkingBeatmap(beatmap, storyboard, Clock, Audio, currentBeatmapSkin); protected override Ruleset CreatePlayerRuleset() => new TestOsuRuleset(); @@ -111,7 +110,7 @@ namespace osu.Game.Tests.Visual.Gameplay { private readonly ISkin beatmapSkin; - public CustomSkinWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio, ISkin beatmapSkin) + public CustomSkinWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard, IFrameBasedClock referenceClock, AudioManager audio, ISkin beatmapSkin) : base(beatmap, storyboard, referenceClock, audio) { this.beatmapSkin = beatmapSkin; From d9b4d932c97bec043d1fb069dd0d8a4091243d13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 17:47:34 +0900 Subject: [PATCH 281/516] Fix test container lookup failure --- .../Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 2109db81d4..94cb8517e9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -56,8 +56,8 @@ namespace osu.Game.Tests.Visual.Gameplay protected bool AssertComponentsFromExpectedSource(GlobalSkinComponentLookup.LookupType target, ISkin expectedSource) { - var actualComponentsContainer = Player.ChildrenOfType().First(s => s.Target == target) - .ChildrenOfType().SingleOrDefault(); + var targetContainer = Player.ChildrenOfType().First(s => s.Target == target); + var actualComponentsContainer = targetContainer.ChildrenOfType().SingleOrDefault(c => c.Parent == targetContainer); if (actualComponentsContainer == null) return false; From 6010dde86edb4f70a71594f1c771c22bb6683aff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 15:30:29 +0900 Subject: [PATCH 282/516] Move `SkinnableInfo` to better namespace --- .../Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 1 - osu.Game/Extensions/DrawableExtensions.cs | 1 - osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs | 2 -- osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs | 1 - osu.Game/Skinning/ISkinnableTarget.cs | 2 +- osu.Game/Skinning/LegacyComboCounter.cs | 1 - osu.Game/{Screens/Play/HUD => Skinning}/SkinnableInfo.cs | 4 ++-- osu.Game/Skinning/SkinnableTargetContainer.cs | 2 +- 8 files changed, 4 insertions(+), 10 deletions(-) rename osu.Game/{Screens/Play/HUD => Skinning}/SkinnableInfo.cs (98%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 94cb8517e9..615bf609dc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -19,7 +19,6 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; using osu.Game.Storyboards; diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 375960305c..021745e5e1 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -5,7 +5,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; -using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; using osuTK; diff --git a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index 28ceaf09fc..3298c267f3 100644 --- a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -10,9 +10,7 @@ using osu.Framework.Logging; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; using osu.Game.Screens.Edit.Components; -using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; using osuTK; diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs index c8f66f3e56..41b6b24da1 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Extensions; using osu.Game.Screens.Edit; -using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; namespace osu.Game.Overlays.SkinEditor diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISkinnableTarget.cs index 3f116f8f76..6429d116dd 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISkinnableTarget.cs @@ -6,7 +6,7 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Extensions; -using osu.Game.Screens.Play.HUD; +using osu.Game.Rulesets; namespace osu.Game.Skinning { diff --git a/osu.Game/Skinning/LegacyComboCounter.cs b/osu.Game/Skinning/LegacyComboCounter.cs index c132a72001..1de13841fe 100644 --- a/osu.Game/Skinning/LegacyComboCounter.cs +++ b/osu.Game/Skinning/LegacyComboCounter.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Play.HUD; using osuTK; namespace osu.Game.Skinning diff --git a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs b/osu.Game/Skinning/SkinnableInfo.cs similarity index 98% rename from osu.Game/Screens/Play/HUD/SkinnableInfo.cs rename to osu.Game/Skinning/SkinnableInfo.cs index 9fdae50615..96aaed667e 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs +++ b/osu.Game/Skinning/SkinnableInfo.cs @@ -13,10 +13,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Extensions; -using osu.Game.Skinning; +using osu.Game.Rulesets; using osuTK; -namespace osu.Game.Screens.Play.HUD +namespace osu.Game.Skinning { /// /// Serialised information governing custom changes to an . diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index b21e51c0cf..cbc719cef5 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -8,7 +8,7 @@ using System.Threading; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Screens.Play.HUD; +using osu.Game.Skinning.Serialisation; namespace osu.Game.Skinning { From 9e651a7ca26f48eb9a95d770a29fb6bd680173f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 15:36:18 +0900 Subject: [PATCH 283/516] Rename `SkinnableInfo` to `SkinnableDrawableInfo` --- .../Skins/SkinDeserialisationTest.cs | 2 +- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 16 +++++++-------- osu.Game/Extensions/DrawableExtensions.cs | 20 +++++++++---------- .../SkinEditor/SkinComponentToolbox.cs | 2 +- .../SkinEditor/SkinEditorChangeHandler.cs | 4 ++-- osu.Game/Skinning/ISkinnableTarget.cs | 4 ++-- osu.Game/Skinning/LegacyComboCounter.cs | 2 +- ...nnableInfo.cs => SkinnableDrawableInfo.cs} | 8 ++++---- osu.Game/Skinning/SkinnableTargetContainer.cs | 2 +- 9 files changed, 30 insertions(+), 30 deletions(-) rename osu.Game/Skinning/{SkinnableInfo.cs => SkinnableDrawableInfo.cs} (93%) diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 3bab91bd9c..16cae1d34f 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -74,7 +74,7 @@ namespace osu.Game.Tests.Skins } } - var editableTypes = SkinnableInfo.GetAllAvailableDrawables().Where(t => (Activator.CreateInstance(t) as ISkinnableDrawable)?.IsEditable == true); + var editableTypes = SkinnableDrawableInfo.GetAllAvailableDrawables().Where(t => (Activator.CreateInstance(t) as ISkinnableDrawable)?.IsEditable == true); Assert.That(instantiatedTypes, Is.EquivalentTo(editableTypes)); } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 615bf609dc..8318f70e8f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -90,15 +90,15 @@ namespace osu.Game.Tests.Visual.Gameplay return almostEqual(actualInfo, expectedInfo); } - private static bool almostEqual(SkinnableInfo info, SkinnableInfo? other) => + private static bool almostEqual(SkinnableDrawableInfo drawableInfo, SkinnableDrawableInfo? other) => other != null - && info.Type == other.Type - && info.Anchor == other.Anchor - && info.Origin == other.Origin - && Precision.AlmostEquals(info.Position, other.Position, 1) - && Precision.AlmostEquals(info.Scale, other.Scale) - && Precision.AlmostEquals(info.Rotation, other.Rotation) - && info.Children.SequenceEqual(other.Children, new FuncEqualityComparer(almostEqual)); + && drawableInfo.Type == other.Type + && drawableInfo.Anchor == other.Anchor + && drawableInfo.Origin == other.Origin + && Precision.AlmostEquals(drawableInfo.Position, other.Position, 1) + && Precision.AlmostEquals(drawableInfo.Scale, other.Scale) + && Precision.AlmostEquals(drawableInfo.Rotation, other.Rotation) + && drawableInfo.Children.SequenceEqual(other.Children, new FuncEqualityComparer(almostEqual)); protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null) => new CustomSkinWorkingBeatmap(beatmap, storyboard, Clock, Audio, currentBeatmapSkin); diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 021745e5e1..c590d4fa31 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -48,26 +48,26 @@ namespace osu.Game.Extensions public static Vector2 ScreenSpaceDeltaToParentSpace(this Drawable drawable, Vector2 delta) => drawable.Parent.ToLocalSpace(drawable.Parent.ToScreenSpace(Vector2.Zero) + delta); - public static SkinnableInfo CreateSkinnableInfo(this Drawable component) => new SkinnableInfo(component); + public static SkinnableDrawableInfo CreateSkinnableInfo(this Drawable component) => new SkinnableDrawableInfo(component); - public static void ApplySkinnableInfo(this Drawable component, SkinnableInfo info) + public static void ApplySkinnableInfo(this Drawable component, SkinnableDrawableInfo drawableInfo) { // todo: can probably make this better via deserialisation directly using a common interface. - component.Position = info.Position; - component.Rotation = info.Rotation; - component.Scale = info.Scale; - component.Anchor = info.Anchor; - component.Origin = info.Origin; + component.Position = drawableInfo.Position; + component.Rotation = drawableInfo.Rotation; + component.Scale = drawableInfo.Scale; + component.Anchor = drawableInfo.Anchor; + component.Origin = drawableInfo.Origin; if (component is ISkinnableDrawable skinnable) { - skinnable.UsesFixedAnchor = info.UsesFixedAnchor; + skinnable.UsesFixedAnchor = drawableInfo.UsesFixedAnchor; foreach (var (_, property) in component.GetSettingsSourceProperties()) { var bindable = ((IBindable)property.GetValue(component)!); - if (!info.Settings.TryGetValue(property.Name.ToSnakeCase(), out object? settingValue)) + if (!drawableInfo.Settings.TryGetValue(property.Name.ToSnakeCase(), out object? settingValue)) { // TODO: We probably want to restore default if not included in serialisation information. // This is not simple to do as SetDefault() is only found in the typed Bindable interface right now. @@ -80,7 +80,7 @@ namespace osu.Game.Extensions if (component is Container container) { - foreach (var child in info.Children) + foreach (var child in drawableInfo.Children) container.Add(child.CreateInstance()); } } diff --git a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index 3298c267f3..37bc7df4fa 100644 --- a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -48,7 +48,7 @@ namespace osu.Game.Overlays.SkinEditor { fill.Clear(); - var skinnableTypes = SkinnableInfo.GetAllAvailableDrawables(); + var skinnableTypes = SkinnableDrawableInfo.GetAllAvailableDrawables(target?.Ruleset); foreach (var type in skinnableTypes) attemptAddComponent(type); } diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs index 41b6b24da1..2d519d3489 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -52,12 +52,12 @@ namespace osu.Game.Overlays.SkinEditor if (firstTarget == null) return; - var deserializedContent = JsonConvert.DeserializeObject>(Encoding.UTF8.GetString(newState)); + var deserializedContent = JsonConvert.DeserializeObject>(Encoding.UTF8.GetString(newState)); if (deserializedContent == null) return; - SkinnableInfo[] skinnableInfo = deserializedContent.ToArray(); + SkinnableDrawableInfo[] skinnableInfo = deserializedContent.ToArray(); Drawable[] targetComponents = firstTarget.Components.OfType().ToArray(); if (!skinnableInfo.Select(s => s.Type).SequenceEqual(targetComponents.Select(d => d.GetType()))) diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISkinnableTarget.cs index 6429d116dd..4610851216 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISkinnableTarget.cs @@ -29,7 +29,7 @@ namespace osu.Game.Skinning /// Serialise all children as . /// /// The serialised content. - IEnumerable CreateSkinnableInfo() => Components.Select(d => ((Drawable)d).CreateSkinnableInfo()); + IEnumerable CreateSkinnableInfo() => Components.Select(d => ((Drawable)d).CreateSkinnableInfo()); /// /// Reload this target from the current skin. @@ -39,7 +39,7 @@ namespace osu.Game.Skinning /// /// Reload this target from the provided skinnable information. /// - void Reload(SkinnableInfo[] skinnableInfo); + void Reload(SkinnableDrawableInfo[] skinnableInfo); /// /// Add a new skinnable component to this target. diff --git a/osu.Game/Skinning/LegacyComboCounter.cs b/osu.Game/Skinning/LegacyComboCounter.cs index 1de13841fe..c03386266b 100644 --- a/osu.Game/Skinning/LegacyComboCounter.cs +++ b/osu.Game/Skinning/LegacyComboCounter.cs @@ -44,7 +44,7 @@ namespace osu.Game.Skinning private readonly Container counterContainer; /// - /// Hides the combo counter internally without affecting its . + /// Hides the combo counter internally without affecting its . /// /// /// This is used for rulesets that provide their own combo counter and don't want this HUD one to be visible, diff --git a/osu.Game/Skinning/SkinnableInfo.cs b/osu.Game/Skinning/SkinnableDrawableInfo.cs similarity index 93% rename from osu.Game/Skinning/SkinnableInfo.cs rename to osu.Game/Skinning/SkinnableDrawableInfo.cs index 96aaed667e..5e30f94ac6 100644 --- a/osu.Game/Skinning/SkinnableInfo.cs +++ b/osu.Game/Skinning/SkinnableDrawableInfo.cs @@ -22,7 +22,7 @@ namespace osu.Game.Skinning /// Serialised information governing custom changes to an . /// [Serializable] - public class SkinnableInfo + public sealed class SkinnableDrawableInfo { public Type Type { get; set; } @@ -41,10 +41,10 @@ namespace osu.Game.Skinning public Dictionary Settings { get; set; } = new Dictionary(); - public List Children { get; } = new List(); + public List Children { get; } = new List(); [JsonConstructor] - public SkinnableInfo() + public SkinnableDrawableInfo() { } @@ -52,7 +52,7 @@ namespace osu.Game.Skinning /// Construct a new instance populating all attributes from the provided drawable. /// /// The drawable which attributes should be sourced from. - public SkinnableInfo(Drawable component) + public SkinnableDrawableInfo(Drawable component) { Type = component.GetType(); diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index cbc719cef5..586462cb8c 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -33,7 +33,7 @@ namespace osu.Game.Skinning Target = target; } - public void Reload(SkinnableInfo[] skinnableInfo) + public void Reload(SkinnableDrawableInfo[] skinnableInfo) { var drawables = new List(); From 856efd9fd9d04e312e77030d9740e738e1355b95 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 15:47:41 +0900 Subject: [PATCH 284/516] Rename `SkinnableDrawableInfo` to `SerialisedDrawableInfo` --- osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 2 +- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 8 ++++---- osu.Game/Extensions/DrawableExtensions.cs | 4 ++-- .../Overlays/SkinEditor/SkinComponentToolbox.cs | 3 ++- .../Overlays/SkinEditor/SkinEditorChangeHandler.cs | 8 ++++---- osu.Game/Skinning/ISkinnableDrawable.cs | 6 ++++-- osu.Game/Skinning/ISkinnableTarget.cs | 7 +++---- osu.Game/Skinning/LegacyComboCounter.cs | 2 +- ...bleDrawableInfo.cs => SerialisedDrawableInfo.cs} | 13 ++++++------- osu.Game/Skinning/Skin.cs | 9 ++++----- osu.Game/Skinning/SkinnableTargetContainer.cs | 2 +- 11 files changed, 32 insertions(+), 32 deletions(-) rename osu.Game/Skinning/{SkinnableDrawableInfo.cs => SerialisedDrawableInfo.cs} (89%) diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 16cae1d34f..c782fbd084 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -74,7 +74,7 @@ namespace osu.Game.Tests.Skins } } - var editableTypes = SkinnableDrawableInfo.GetAllAvailableDrawables().Where(t => (Activator.CreateInstance(t) as ISkinnableDrawable)?.IsEditable == true); + var editableTypes = SerialisedDrawableInfo.GetAllAvailableDrawables().Where(t => (Activator.CreateInstance(t) as ISkinnableDrawable)?.IsEditable == true); Assert.That(instantiatedTypes, Is.EquivalentTo(editableTypes)); } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 8318f70e8f..5005cff265 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Gameplay if (actualComponentsContainer == null) return false; - var actualInfo = actualComponentsContainer.CreateSkinnableInfo(); + var actualInfo = actualComponentsContainer.CreateSerialisedInfo(); var expectedComponentsContainer = expectedSource.GetDrawableComponent(new GlobalSkinComponentLookup(target)) as Container; if (expectedComponentsContainer == null) @@ -84,13 +84,13 @@ namespace osu.Game.Tests.Visual.Gameplay Add(expectedComponentsAdjustmentContainer); expectedComponentsAdjustmentContainer.UpdateSubTree(); - var expectedInfo = expectedComponentsContainer.CreateSkinnableInfo(); + var expectedInfo = expectedComponentsContainer.CreateSerialisedInfo(); Remove(expectedComponentsAdjustmentContainer, true); return almostEqual(actualInfo, expectedInfo); } - private static bool almostEqual(SkinnableDrawableInfo drawableInfo, SkinnableDrawableInfo? other) => + private static bool almostEqual(SerialisedDrawableInfo drawableInfo, SerialisedDrawableInfo? other) => other != null && drawableInfo.Type == other.Type && drawableInfo.Anchor == other.Anchor @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Gameplay && Precision.AlmostEquals(drawableInfo.Position, other.Position, 1) && Precision.AlmostEquals(drawableInfo.Scale, other.Scale) && Precision.AlmostEquals(drawableInfo.Rotation, other.Rotation) - && drawableInfo.Children.SequenceEqual(other.Children, new FuncEqualityComparer(almostEqual)); + && drawableInfo.Children.SequenceEqual(other.Children, new FuncEqualityComparer(almostEqual)); protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null) => new CustomSkinWorkingBeatmap(beatmap, storyboard, Clock, Audio, currentBeatmapSkin); diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index c590d4fa31..cc561cebc4 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -48,9 +48,9 @@ namespace osu.Game.Extensions public static Vector2 ScreenSpaceDeltaToParentSpace(this Drawable drawable, Vector2 delta) => drawable.Parent.ToLocalSpace(drawable.Parent.ToScreenSpace(Vector2.Zero) + delta); - public static SkinnableDrawableInfo CreateSkinnableInfo(this Drawable component) => new SkinnableDrawableInfo(component); + public static SerialisedDrawableInfo CreateSerialisedInfo(this Drawable component) => new SerialisedDrawableInfo(component); - public static void ApplySkinnableInfo(this Drawable component, SkinnableDrawableInfo drawableInfo) + public static void ApplySerialisedInfo(this Drawable component, SerialisedDrawableInfo drawableInfo) { // todo: can probably make this better via deserialisation directly using a common interface. component.Position = drawableInfo.Position; diff --git a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index 37bc7df4fa..2f3fd8b5e5 100644 --- a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -10,6 +10,7 @@ using osu.Framework.Logging; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Screens.Edit.Components; using osu.Game.Skinning; using osuTK; @@ -48,7 +49,7 @@ namespace osu.Game.Overlays.SkinEditor { fill.Clear(); - var skinnableTypes = SkinnableDrawableInfo.GetAllAvailableDrawables(target?.Ruleset); + var skinnableTypes = SerialisedDrawableInfo.GetAllAvailableDrawables(); foreach (var type in skinnableTypes) attemptAddComponent(type); } diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs index 2d519d3489..77032589a0 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.SkinEditor if (firstTarget == null) return; - var skinnableInfos = firstTarget.CreateSkinnableInfo().ToArray(); + var skinnableInfos = firstTarget.CreateSerialisedInfo().ToArray(); string json = JsonConvert.SerializeObject(skinnableInfos, new JsonSerializerSettings { Formatting = Formatting.Indented }); stream.Write(Encoding.UTF8.GetBytes(json)); } @@ -52,12 +52,12 @@ namespace osu.Game.Overlays.SkinEditor if (firstTarget == null) return; - var deserializedContent = JsonConvert.DeserializeObject>(Encoding.UTF8.GetString(newState)); + var deserializedContent = JsonConvert.DeserializeObject>(Encoding.UTF8.GetString(newState)); if (deserializedContent == null) return; - SkinnableDrawableInfo[] skinnableInfo = deserializedContent.ToArray(); + SerialisedDrawableInfo[] skinnableInfo = deserializedContent.ToArray(); Drawable[] targetComponents = firstTarget.Components.OfType().ToArray(); if (!skinnableInfo.Select(s => s.Type).SequenceEqual(targetComponents.Select(d => d.GetType()))) @@ -70,7 +70,7 @@ namespace osu.Game.Overlays.SkinEditor int i = 0; foreach (var drawable in targetComponents) - drawable.ApplySkinnableInfo(skinnableInfo[i++]); + drawable.ApplySerialisedInfo(skinnableInfo[i++]); } } } diff --git a/osu.Game/Skinning/ISkinnableDrawable.cs b/osu.Game/Skinning/ISkinnableDrawable.cs index 1ecd6f967e..5ec2fa0f43 100644 --- a/osu.Game/Skinning/ISkinnableDrawable.cs +++ b/osu.Game/Skinning/ISkinnableDrawable.cs @@ -13,8 +13,10 @@ namespace osu.Game.Skinning /// Denotes a drawable which, as a drawable, can be adjusted via skinning specifications. /// /// - /// Attaching this interface to any will make it serialisable to skin settings. - /// Adding annotated bindables will also serialise these settings alongside each instance. + /// Attaching this interface to any will make it serialisable to user skins (see ). + /// Adding annotated bindables will also allow serialising settings automatically. + /// + /// Serialisation is done via using . /// public interface ISkinnableDrawable : IDrawable { diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISkinnableTarget.cs index 4610851216..e10fc6e069 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISkinnableTarget.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Extensions; -using osu.Game.Rulesets; namespace osu.Game.Skinning { @@ -26,10 +25,10 @@ namespace osu.Game.Skinning IBindableList Components { get; } /// - /// Serialise all children as . + /// Serialise all children as . /// /// The serialised content. - IEnumerable CreateSkinnableInfo() => Components.Select(d => ((Drawable)d).CreateSkinnableInfo()); + IEnumerable CreateSerialisedInfo() => Components.Select(d => ((Drawable)d).CreateSerialisedInfo()); /// /// Reload this target from the current skin. @@ -39,7 +38,7 @@ namespace osu.Game.Skinning /// /// Reload this target from the provided skinnable information. /// - void Reload(SkinnableDrawableInfo[] skinnableInfo); + void Reload(SerialisedDrawableInfo[] skinnableInfo); /// /// Add a new skinnable component to this target. diff --git a/osu.Game/Skinning/LegacyComboCounter.cs b/osu.Game/Skinning/LegacyComboCounter.cs index c03386266b..f46f5a69f0 100644 --- a/osu.Game/Skinning/LegacyComboCounter.cs +++ b/osu.Game/Skinning/LegacyComboCounter.cs @@ -44,7 +44,7 @@ namespace osu.Game.Skinning private readonly Container counterContainer; /// - /// Hides the combo counter internally without affecting its . + /// Hides the combo counter internally without affecting its . /// /// /// This is used for rulesets that provide their own combo counter and don't want this HUD one to be visible, diff --git a/osu.Game/Skinning/SkinnableDrawableInfo.cs b/osu.Game/Skinning/SerialisedDrawableInfo.cs similarity index 89% rename from osu.Game/Skinning/SkinnableDrawableInfo.cs rename to osu.Game/Skinning/SerialisedDrawableInfo.cs index 5e30f94ac6..8bcfed1dbc 100644 --- a/osu.Game/Skinning/SkinnableDrawableInfo.cs +++ b/osu.Game/Skinning/SerialisedDrawableInfo.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Extensions; -using osu.Game.Rulesets; using osuTK; namespace osu.Game.Skinning @@ -22,7 +21,7 @@ namespace osu.Game.Skinning /// Serialised information governing custom changes to an . /// [Serializable] - public sealed class SkinnableDrawableInfo + public sealed class SerialisedDrawableInfo { public Type Type { get; set; } @@ -41,10 +40,10 @@ namespace osu.Game.Skinning public Dictionary Settings { get; set; } = new Dictionary(); - public List Children { get; } = new List(); + public List Children { get; } = new List(); [JsonConstructor] - public SkinnableDrawableInfo() + public SerialisedDrawableInfo() { } @@ -52,7 +51,7 @@ namespace osu.Game.Skinning /// Construct a new instance populating all attributes from the provided drawable. /// /// The drawable which attributes should be sourced from. - public SkinnableDrawableInfo(Drawable component) + public SerialisedDrawableInfo(Drawable component) { Type = component.GetType(); @@ -75,7 +74,7 @@ namespace osu.Game.Skinning if (component is Container container) { foreach (var child in container.OfType().OfType()) - Children.Add(child.CreateSkinnableInfo()); + Children.Add(child.CreateSerialisedInfo()); } } @@ -88,7 +87,7 @@ namespace osu.Game.Skinning try { Drawable d = (Drawable)Activator.CreateInstance(Type)!; - d.ApplySkinnableInfo(this); + d.ApplySerialisedInfo(this); return d; } catch (Exception e) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index c55b4e789c..44bdcafe4c 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -18,7 +18,6 @@ using osu.Framework.Logging; using osu.Game.Audio; using osu.Game.Database; using osu.Game.IO; -using osu.Game.Screens.Play.HUD; namespace osu.Game.Skinning { @@ -38,9 +37,9 @@ namespace osu.Game.Skinning public SkinConfiguration Configuration { get; set; } - public IDictionary DrawableComponentInfo => drawableComponentInfo; + public IDictionary DrawableComponentInfo => drawableComponentInfo; - private readonly Dictionary drawableComponentInfo = new Dictionary(); + private readonly Dictionary drawableComponentInfo = new Dictionary(); public abstract ISample? GetSample(ISampleInfo sampleInfo); @@ -120,7 +119,7 @@ namespace osu.Game.Skinning jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.SongProgress", @"osu.Game.Screens.Play.HUD.DefaultSongProgress"); jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.LegacyComboCounter", @"osu.Game.Skinning.LegacyComboCounter"); - var deserializedContent = JsonConvert.DeserializeObject>(jsonContent); + var deserializedContent = JsonConvert.DeserializeObject>(jsonContent); if (deserializedContent == null) continue; @@ -155,7 +154,7 @@ namespace osu.Game.Skinning /// The target container to serialise to this skin. public void UpdateDrawableTarget(ISkinnableTarget targetContainer) { - DrawableComponentInfo[targetContainer.Target] = targetContainer.CreateSkinnableInfo().ToArray(); + DrawableComponentInfo[targetContainer.Target] = targetContainer.CreateSerialisedInfo().ToArray(); } public virtual Drawable? GetDrawableComponent(ISkinComponentLookup lookup) diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index 586462cb8c..8b37767113 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -33,7 +33,7 @@ namespace osu.Game.Skinning Target = target; } - public void Reload(SkinnableDrawableInfo[] skinnableInfo) + public void Reload(SerialisedDrawableInfo[] skinnableInfo) { var drawables = new List(); From 8cb5a51aa77d6db5cce44273b7722543d38619a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 15:14:38 +0900 Subject: [PATCH 285/516] Add further documentation to skin classes --- osu.Game/Skinning/ISkin.cs | 2 +- osu.Game/Skinning/ISkinComponentLookup.cs | 3 ++- osu.Game/Skinning/ISkinSource.cs | 10 +++++++++- osu.Game/Skinning/ISkinnableDrawable.cs | 4 ++-- osu.Game/Skinning/SerialisedDrawableInfo.cs | 3 ++- osu.Game/Skinning/SkinProvidingContainer.cs | 7 ++++++- osu.Game/Skinning/SkinReloadableDrawable.cs | 3 ++- osu.Game/Skinning/SkinTransformer.cs | 7 +++++++ 8 files changed, 31 insertions(+), 8 deletions(-) diff --git a/osu.Game/Skinning/ISkin.cs b/osu.Game/Skinning/ISkin.cs index 45be5582f6..fa04dda202 100644 --- a/osu.Game/Skinning/ISkin.cs +++ b/osu.Game/Skinning/ISkin.cs @@ -10,7 +10,7 @@ using osu.Game.Audio; namespace osu.Game.Skinning { /// - /// Provides access to skinnable elements. + /// Provides access to various elements contained by a skin. /// public interface ISkin { diff --git a/osu.Game/Skinning/ISkinComponentLookup.cs b/osu.Game/Skinning/ISkinComponentLookup.cs index be4043d7cf..25ee086707 100644 --- a/osu.Game/Skinning/ISkinComponentLookup.cs +++ b/osu.Game/Skinning/ISkinComponentLookup.cs @@ -4,7 +4,8 @@ namespace osu.Game.Skinning { /// - /// A lookup type which can be used with . + /// The base lookup type to be used with . + /// Should be implemented as necessary to add further criteria to lookups, which are usually consumed by ruleset transformers or legacy lookup cases. /// /// /// Implementations of should match on types implementing this interface diff --git a/osu.Game/Skinning/ISkinSource.cs b/osu.Game/Skinning/ISkinSource.cs index 89f656a12c..b05d52d47c 100644 --- a/osu.Game/Skinning/ISkinSource.cs +++ b/osu.Game/Skinning/ISkinSource.cs @@ -7,8 +7,16 @@ using System.Collections.Generic; namespace osu.Game.Skinning { /// - /// Provides access to skinnable elements. + /// An abstract skin implementation which generally provides access to more than one skins (with fallback logic). /// + /// + /// Common usage is to do an initial lookup via , and use the returned + /// to do further lookups for related components. + /// + /// The initial lookup is used to lock consecutive lookups to the same underlying skin source (as to not get some elements + /// from one skin and others from another, which would be the case if using methods like + /// directly). + /// public interface ISkinSource : ISkin { /// diff --git a/osu.Game/Skinning/ISkinnableDrawable.cs b/osu.Game/Skinning/ISkinnableDrawable.cs index 5ec2fa0f43..48f5b91c29 100644 --- a/osu.Game/Skinning/ISkinnableDrawable.cs +++ b/osu.Game/Skinning/ISkinnableDrawable.cs @@ -10,13 +10,13 @@ using osu.Game.Configuration; namespace osu.Game.Skinning { /// - /// Denotes a drawable which, as a drawable, can be adjusted via skinning specifications. + /// A drawable which can be serialised to a skin, placed and customised via the skin layout editor. /// /// /// Attaching this interface to any will make it serialisable to user skins (see ). /// Adding annotated bindables will also allow serialising settings automatically. /// - /// Serialisation is done via using . + /// Serialisation is done via using . /// public interface ISkinnableDrawable : IDrawable { diff --git a/osu.Game/Skinning/SerialisedDrawableInfo.cs b/osu.Game/Skinning/SerialisedDrawableInfo.cs index 8bcfed1dbc..90762da011 100644 --- a/osu.Game/Skinning/SerialisedDrawableInfo.cs +++ b/osu.Game/Skinning/SerialisedDrawableInfo.cs @@ -18,7 +18,8 @@ using osuTK; namespace osu.Game.Skinning { /// - /// Serialised information governing custom changes to an . + /// Serialised backing data for s. + /// Used for json serialisation in user skins. /// [Serializable] public sealed class SerialisedDrawableInfo diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index afead7b072..2612e0b47c 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -15,8 +15,13 @@ using osu.Game.Audio; namespace osu.Game.Skinning { /// - /// A container which adds a local to the hierarchy. + /// A container which adds a provided to the DI skin lookup hierarchy. /// + /// + /// This container will expose an to its children. + /// The source will first consider the skin provided via the constructor (if any), then fallback + /// to any providers in the parent DI hierarchy. + /// public partial class SkinProvidingContainer : Container, ISkinSource { public event Action? SourceChanged; diff --git a/osu.Game/Skinning/SkinReloadableDrawable.cs b/osu.Game/Skinning/SkinReloadableDrawable.cs index 1c947a4a84..cef1db4bc0 100644 --- a/osu.Game/Skinning/SkinReloadableDrawable.cs +++ b/osu.Game/Skinning/SkinReloadableDrawable.cs @@ -9,7 +9,8 @@ using osu.Framework.Graphics.Pooling; namespace osu.Game.Skinning { /// - /// A drawable which has a callback when the skin changes. + /// A poolable drawable implementation which has a pre-wired callback (see ) that fires + /// once on load and again on any subsequent skin change. /// public abstract partial class SkinReloadableDrawable : PoolableDrawable { diff --git a/osu.Game/Skinning/SkinTransformer.cs b/osu.Game/Skinning/SkinTransformer.cs index e05961d404..ed5b04da1e 100644 --- a/osu.Game/Skinning/SkinTransformer.cs +++ b/osu.Game/Skinning/SkinTransformer.cs @@ -10,6 +10,13 @@ using osu.Game.Audio; namespace osu.Game.Skinning { + /// + /// A default skin transformer, which falls back to the provided skin by default. + /// + /// + /// Implementations of skin transformers should generally derive this class and override + /// individual lookup methods, modifying the lookup flow as required. + /// public abstract class SkinTransformer : ISkinTransformer { public ISkin Skin { get; } From d159d6b9700d90f6a40cda0f832df59f6086e7ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 16:01:26 +0900 Subject: [PATCH 286/516] Rename `ISkinnableDrawable` to `ISerialisableDrawable` --- .../Skins/SkinDeserialisationTest.cs | 2 +- osu.Game/Extensions/DrawableExtensions.cs | 2 +- osu.Game/Overlays/SkinEditor/SkinBlueprint.cs | 4 ++-- .../SkinEditor/SkinBlueprintContainer.cs | 22 +++++++++---------- .../SkinEditor/SkinComponentToolbox.cs | 2 +- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 10 ++++----- .../SkinEditor/SkinEditorChangeHandler.cs | 4 ++-- .../SkinEditor/SkinSelectionHandler.cs | 10 ++++----- osu.Game/Screens/Play/HUD/BPMCounter.cs | 2 +- .../ClicksPerSecond/ClicksPerSecondCounter.cs | 2 +- osu.Game/Screens/Play/HUD/ComboCounter.cs | 2 +- .../Play/HUD/DefaultAccuracyCounter.cs | 2 +- .../Screens/Play/HUD/DefaultHealthDisplay.cs | 2 +- .../Screens/Play/HUD/DefaultScoreCounter.cs | 2 +- .../Play/HUD/HitErrorMeters/HitErrorMeter.cs | 2 +- .../JudgementCounterDisplay.cs | 2 +- .../Play/HUD/PerformancePointsCounter.cs | 2 +- osu.Game/Screens/Play/HUD/SongProgress.cs | 2 +- .../Screens/Play/HUD/UnstableRateCounter.cs | 2 +- osu.Game/Skinning/Components/BigBlackBox.cs | 2 +- .../Skinning/FontAdjustableSkinComponent.cs | 2 +- ...leDrawable.cs => ISerialisableDrawable.cs} | 6 ++--- osu.Game/Skinning/ISkinnableTarget.cs | 8 +++---- osu.Game/Skinning/LegacyAccuracyCounter.cs | 2 +- osu.Game/Skinning/LegacyComboCounter.cs | 2 +- osu.Game/Skinning/LegacyHealthDisplay.cs | 2 +- osu.Game/Skinning/LegacyScoreCounter.cs | 2 +- osu.Game/Skinning/SerialisedDrawableInfo.cs | 14 +++++++----- osu.Game/Skinning/SkinnableSprite.cs | 2 +- osu.Game/Skinning/SkinnableTargetContainer.cs | 10 ++++----- 30 files changed, 67 insertions(+), 63 deletions(-) rename osu.Game/Skinning/{ISkinnableDrawable.cs => ISerialisableDrawable.cs} (87%) diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index c782fbd084..b897523560 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -74,7 +74,7 @@ namespace osu.Game.Tests.Skins } } - var editableTypes = SerialisedDrawableInfo.GetAllAvailableDrawables().Where(t => (Activator.CreateInstance(t) as ISkinnableDrawable)?.IsEditable == true); + var editableTypes = SerialisedDrawableInfo.GetAllAvailableDrawables().Where(t => (Activator.CreateInstance(t) as ISerialisableDrawable)?.IsEditable == true); Assert.That(instantiatedTypes, Is.EquivalentTo(editableTypes)); } diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index cc561cebc4..b6f74f5777 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -59,7 +59,7 @@ namespace osu.Game.Extensions component.Anchor = drawableInfo.Anchor; component.Origin = drawableInfo.Origin; - if (component is ISkinnableDrawable skinnable) + if (component is ISerialisableDrawable skinnable) { skinnable.UsesFixedAnchor = drawableInfo.UsesFixedAnchor; diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs index 893bc4bac2..55ea362873 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.SkinEditor { - public partial class SkinBlueprint : SelectionBlueprint + public partial class SkinBlueprint : SelectionBlueprint { private Container box = null!; @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.SkinEditor [Resolved] private OsuColour colours { get; set; } = null!; - public SkinBlueprint(ISkinnableDrawable component) + public SkinBlueprint(ISerialisableDrawable component) : base(component) { } diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs index a448b3d0c1..1e7bec5417 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs @@ -24,11 +24,11 @@ using osuTK.Input; namespace osu.Game.Overlays.SkinEditor { - public partial class SkinBlueprintContainer : BlueprintContainer + public partial class SkinBlueprintContainer : BlueprintContainer { private readonly Drawable target; - private readonly List> targetComponents = new List>(); + private readonly List> targetComponents = new List>(); [Resolved] private SkinEditor editor { get; set; } = null!; @@ -55,7 +55,7 @@ namespace osu.Game.Overlays.SkinEditor foreach (var targetContainer in targetContainers) { - var bindableList = new BindableList { BindTarget = targetContainer.Components }; + var bindableList = new BindableList { BindTarget = targetContainer.Components }; bindableList.BindCollectionChanged(componentsChanged, true); targetComponents.Add(bindableList); @@ -69,7 +69,7 @@ namespace osu.Game.Overlays.SkinEditor case NotifyCollectionChangedAction.Add: Debug.Assert(e.NewItems != null); - foreach (var item in e.NewItems.Cast()) + foreach (var item in e.NewItems.Cast()) AddBlueprintFor(item); break; @@ -77,7 +77,7 @@ namespace osu.Game.Overlays.SkinEditor case NotifyCollectionChangedAction.Reset: Debug.Assert(e.OldItems != null); - foreach (var item in e.OldItems.Cast()) + foreach (var item in e.OldItems.Cast()) RemoveBlueprintFor(item); break; @@ -85,16 +85,16 @@ namespace osu.Game.Overlays.SkinEditor Debug.Assert(e.NewItems != null); Debug.Assert(e.OldItems != null); - foreach (var item in e.OldItems.Cast()) + foreach (var item in e.OldItems.Cast()) RemoveBlueprintFor(item); - foreach (var item in e.NewItems.Cast()) + foreach (var item in e.NewItems.Cast()) AddBlueprintFor(item); break; } }); - protected override void AddBlueprintFor(ISkinnableDrawable item) + protected override void AddBlueprintFor(ISerialisableDrawable item) { if (!item.IsEditable) return; @@ -145,12 +145,12 @@ namespace osu.Game.Overlays.SkinEditor // convert to game space coordinates delta = firstBlueprint.ToScreenSpace(delta) - firstBlueprint.ToScreenSpace(Vector2.Zero); - SelectionHandler.HandleMovement(new MoveSelectionEvent(firstBlueprint, delta)); + SelectionHandler.HandleMovement(new MoveSelectionEvent(firstBlueprint, delta)); } - protected override SelectionHandler CreateSelectionHandler() => new SkinSelectionHandler(); + protected override SelectionHandler CreateSelectionHandler() => new SkinSelectionHandler(); - protected override SelectionBlueprint CreateBlueprintFor(ISkinnableDrawable component) + protected override SelectionBlueprint CreateBlueprintFor(ISerialisableDrawable component) => new SkinBlueprint(component); protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index 2f3fd8b5e5..cd9f7cc935 100644 --- a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -60,7 +60,7 @@ namespace osu.Game.Overlays.SkinEditor { Drawable instance = (Drawable)Activator.CreateInstance(type)!; - if (!((ISkinnableDrawable)instance).IsEditable) return; + if (!((ISerialisableDrawable)instance).IsEditable) return; fill.Add(new ToolboxComponentButton(instance, target) { diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 866de7e621..aafc97d769 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -38,7 +38,7 @@ namespace osu.Game.Overlays.SkinEditor public const float MENU_HEIGHT = 40; - public readonly BindableList SelectedComponents = new BindableList(); + public readonly BindableList SelectedComponents = new BindableList(); protected override bool StartHidden => true; @@ -302,13 +302,13 @@ namespace osu.Game.Overlays.SkinEditor private void placeComponent(Type type) { - if (!(Activator.CreateInstance(type) is ISkinnableDrawable component)) - throw new InvalidOperationException($"Attempted to instantiate a component for placement which was not an {typeof(ISkinnableDrawable)}."); + if (!(Activator.CreateInstance(type) is ISerialisableDrawable component)) + throw new InvalidOperationException($"Attempted to instantiate a component for placement which was not an {typeof(ISerialisableDrawable)}."); placeComponent(component); } - private void placeComponent(ISkinnableDrawable component, bool applyDefaults = true) + private void placeComponent(ISerialisableDrawable component, bool applyDefaults = true) { var targetContainer = getFirstTarget(); @@ -400,7 +400,7 @@ namespace osu.Game.Overlays.SkinEditor this.FadeOut(TRANSITION_DURATION, Easing.OutQuint); } - public void DeleteItems(ISkinnableDrawable[] items) + public void DeleteItems(ISerialisableDrawable[] items) { foreach (var item in items) availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item); diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs index 77032589a0..65872920f1 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.SkinEditor private readonly ISkinnableTarget? firstTarget; // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable - private readonly BindableList? components; + private readonly BindableList? components; public SkinEditorChangeHandler(Drawable targetScreen) { @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.SkinEditor if (firstTarget == null) return; - components = new BindableList { BindTarget = firstTarget.Components }; + components = new BindableList { BindTarget = firstTarget.Components }; components.BindCollectionChanged((_, _) => SaveState()); } diff --git a/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs index 86fcd35e03..c628ad8480 100644 --- a/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Overlays.SkinEditor { - public partial class SkinSelectionHandler : SelectionHandler + public partial class SkinSelectionHandler : SelectionHandler { [Resolved] private SkinEditor skinEditor { get; set; } = null!; @@ -147,7 +147,7 @@ namespace osu.Game.Overlays.SkinEditor return true; } - public override bool HandleMovement(MoveSelectionEvent moveEvent) + public override bool HandleMovement(MoveSelectionEvent moveEvent) { foreach (var c in SelectedBlueprints) { @@ -178,10 +178,10 @@ namespace osu.Game.Overlays.SkinEditor SelectionBox.CanReverse = false; } - protected override void DeleteItems(IEnumerable items) => + protected override void DeleteItems(IEnumerable items) => skinEditor.DeleteItems(items.ToArray()); - protected override IEnumerable GetContextMenuItemsForSelection(IEnumerable> selection) + protected override IEnumerable GetContextMenuItemsForSelection(IEnumerable> selection) { var closestItem = new TernaryStateRadioMenuItem("Closest", MenuItemType.Standard, _ => applyClosestAnchors()) { @@ -209,7 +209,7 @@ namespace osu.Game.Overlays.SkinEditor foreach (var item in base.GetContextMenuItemsForSelection(selection)) yield return item; - IEnumerable createAnchorItems(Func checkFunction, Action applyFunction) + IEnumerable createAnchorItems(Func checkFunction, Action applyFunction) { var displayableAnchors = new[] { diff --git a/osu.Game/Screens/Play/HUD/BPMCounter.cs b/osu.Game/Screens/Play/HUD/BPMCounter.cs index 500ab0169f..cd24237493 100644 --- a/osu.Game/Screens/Play/HUD/BPMCounter.cs +++ b/osu.Game/Screens/Play/HUD/BPMCounter.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public partial class BPMCounter : RollingCounter, ISkinnableDrawable + public partial class BPMCounter : RollingCounter, ISerialisableDrawable { protected override double RollingDuration => 750; diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs index cb72bb5f6f..1aa7c5e091 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { - public partial class ClicksPerSecondCounter : RollingCounter, ISkinnableDrawable + public partial class ClicksPerSecondCounter : RollingCounter, ISerialisableDrawable { [Resolved] private ClicksPerSecondCalculator calculator { get; set; } = null!; diff --git a/osu.Game/Screens/Play/HUD/ComboCounter.cs b/osu.Game/Screens/Play/HUD/ComboCounter.cs index afccbc4ef0..17531281aa 100644 --- a/osu.Game/Screens/Play/HUD/ComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/ComboCounter.cs @@ -7,7 +7,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public abstract partial class ComboCounter : RollingCounter, ISkinnableDrawable + public abstract partial class ComboCounter : RollingCounter, ISerialisableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs index 1a082e58b7..eb3c71afbb 100644 --- a/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs @@ -9,7 +9,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public partial class DefaultAccuracyCounter : GameplayAccuracyCounter, ISkinnableDrawable + public partial class DefaultAccuracyCounter : GameplayAccuracyCounter, ISerialisableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs index 62d66efb33..2c43905a46 100644 --- a/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs @@ -19,7 +19,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public partial class DefaultHealthDisplay : HealthDisplay, IHasAccentColour, ISkinnableDrawable + public partial class DefaultHealthDisplay : HealthDisplay, IHasAccentColour, ISerialisableDrawable { /// /// The base opacity of the glow. diff --git a/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs b/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs index f116617271..7cc2dc1751 100644 --- a/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs @@ -10,7 +10,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public partial class DefaultScoreCounter : GameplayScoreCounter, ISkinnableDrawable + public partial class DefaultScoreCounter : GameplayScoreCounter, ISerialisableDrawable { public DefaultScoreCounter() { diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index 191f63e97d..5d65208afe 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { - public abstract partial class HitErrorMeter : CompositeDrawable, ISkinnableDrawable + public abstract partial class HitErrorMeter : CompositeDrawable, ISerialisableDrawable { protected HitWindows HitWindows { get; private set; } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 80d2e0863f..a9b59a02b5 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD.JudgementCounter { - public partial class JudgementCounterDisplay : CompositeDrawable, ISkinnableDrawable + public partial class JudgementCounterDisplay : CompositeDrawable, ISerialisableDrawable { public const int TRANSFORM_DURATION = 250; diff --git a/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs b/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs index 15484f2965..4f37c215e9 100644 --- a/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs +++ b/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs @@ -35,7 +35,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public partial class PerformancePointsCounter : RollingCounter, ISkinnableDrawable + public partial class PerformancePointsCounter : RollingCounter, ISerialisableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 4647c0352b..ebe2fb83e6 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -14,7 +14,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public abstract partial class SongProgress : OverlayContainer, ISkinnableDrawable + public abstract partial class SongProgress : OverlayContainer, ISerialisableDrawable { // Some implementations of this element allow seeking during gameplay playback. // Set a sane default of never handling input to override the behaviour provided by OverlayContainer. diff --git a/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs b/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs index f450ae799e..4ceca817e2 100644 --- a/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs +++ b/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public partial class UnstableRateCounter : RollingCounter, ISkinnableDrawable + public partial class UnstableRateCounter : RollingCounter, ISerialisableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Skinning/Components/BigBlackBox.cs b/osu.Game/Skinning/Components/BigBlackBox.cs index 043a276e49..3c63dae8d8 100644 --- a/osu.Game/Skinning/Components/BigBlackBox.cs +++ b/osu.Game/Skinning/Components/BigBlackBox.cs @@ -19,7 +19,7 @@ namespace osu.Game.Skinning.Components /// Intended to be a test bed for skinning. May be removed at some point in the future. /// [UsedImplicitly] - public partial class BigBlackBox : CompositeDrawable, ISkinnableDrawable + public partial class BigBlackBox : CompositeDrawable, ISerialisableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Skinning/FontAdjustableSkinComponent.cs b/osu.Game/Skinning/FontAdjustableSkinComponent.cs index 2e41b35abb..8f3a1d41c6 100644 --- a/osu.Game/Skinning/FontAdjustableSkinComponent.cs +++ b/osu.Game/Skinning/FontAdjustableSkinComponent.cs @@ -13,7 +13,7 @@ namespace osu.Game.Skinning /// /// A skin component that contains text and allows the user to choose its font. /// - public abstract partial class FontAdjustableSkinComponent : Container, ISkinnableDrawable + public abstract partial class FontAdjustableSkinComponent : Container, ISerialisableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Skinning/ISkinnableDrawable.cs b/osu.Game/Skinning/ISerialisableDrawable.cs similarity index 87% rename from osu.Game/Skinning/ISkinnableDrawable.cs rename to osu.Game/Skinning/ISerialisableDrawable.cs index 48f5b91c29..23cbda6344 100644 --- a/osu.Game/Skinning/ISkinnableDrawable.cs +++ b/osu.Game/Skinning/ISerialisableDrawable.cs @@ -18,7 +18,7 @@ namespace osu.Game.Skinning /// /// Serialisation is done via using . /// - public interface ISkinnableDrawable : IDrawable + public interface ISerialisableDrawable : IDrawable { /// /// Whether this component should be editable by an end user. @@ -26,8 +26,8 @@ namespace osu.Game.Skinning bool IsEditable => true; /// - /// In the context of the skin layout editor, whether this has a permanent anchor defined. - /// If , this 's is automatically determined by proximity, + /// In the context of the skin layout editor, whether this has a permanent anchor defined. + /// If , this 's is automatically determined by proximity, /// If , a fixed anchor point has been defined. /// bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISkinnableTarget.cs index e10fc6e069..5833898d81 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISkinnableTarget.cs @@ -10,7 +10,7 @@ using osu.Game.Extensions; namespace osu.Game.Skinning { /// - /// Denotes a container which can house s. + /// Denotes a container which can house s. /// public interface ISkinnableTarget : IDrawable { @@ -22,7 +22,7 @@ namespace osu.Game.Skinning /// /// A bindable list of components which are being tracked by this skinnable target. /// - IBindableList Components { get; } + IBindableList Components { get; } /// /// Serialise all children as . @@ -44,12 +44,12 @@ namespace osu.Game.Skinning /// Add a new skinnable component to this target. /// /// The component to add. - void Add(ISkinnableDrawable drawable); + void Add(ISerialisableDrawable drawable); /// /// Remove an existing skinnable component from this target. /// /// The component to remove. - void Remove(ISkinnableDrawable component); + void Remove(ISerialisableDrawable component); } } diff --git a/osu.Game/Skinning/LegacyAccuracyCounter.cs b/osu.Game/Skinning/LegacyAccuracyCounter.cs index e75fb1e7e9..c99cdba91c 100644 --- a/osu.Game/Skinning/LegacyAccuracyCounter.cs +++ b/osu.Game/Skinning/LegacyAccuracyCounter.cs @@ -8,7 +8,7 @@ using osuTK; namespace osu.Game.Skinning { - public partial class LegacyAccuracyCounter : GameplayAccuracyCounter, ISkinnableDrawable + public partial class LegacyAccuracyCounter : GameplayAccuracyCounter, ISerialisableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Skinning/LegacyComboCounter.cs b/osu.Game/Skinning/LegacyComboCounter.cs index f46f5a69f0..cd72055fce 100644 --- a/osu.Game/Skinning/LegacyComboCounter.cs +++ b/osu.Game/Skinning/LegacyComboCounter.cs @@ -14,7 +14,7 @@ namespace osu.Game.Skinning /// /// Uses the 'x' symbol and has a pop-out effect while rolling over. /// - public partial class LegacyComboCounter : CompositeDrawable, ISkinnableDrawable + public partial class LegacyComboCounter : CompositeDrawable, ISerialisableDrawable { public Bindable Current { get; } = new BindableInt { MinValue = 0 }; diff --git a/osu.Game/Skinning/LegacyHealthDisplay.cs b/osu.Game/Skinning/LegacyHealthDisplay.cs index c3cb9770fa..f785022f84 100644 --- a/osu.Game/Skinning/LegacyHealthDisplay.cs +++ b/osu.Game/Skinning/LegacyHealthDisplay.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Skinning { - public partial class LegacyHealthDisplay : HealthDisplay, ISkinnableDrawable + public partial class LegacyHealthDisplay : HealthDisplay, ISerialisableDrawable { private const double epic_cutoff = 0.5; diff --git a/osu.Game/Skinning/LegacyScoreCounter.cs b/osu.Game/Skinning/LegacyScoreCounter.cs index 88e7bbc23a..d8ee6b21de 100644 --- a/osu.Game/Skinning/LegacyScoreCounter.cs +++ b/osu.Game/Skinning/LegacyScoreCounter.cs @@ -8,7 +8,7 @@ using osuTK; namespace osu.Game.Skinning { - public partial class LegacyScoreCounter : GameplayScoreCounter, ISkinnableDrawable + public partial class LegacyScoreCounter : GameplayScoreCounter, ISerialisableDrawable { protected override double RollingDuration => 1000; protected override Easing RollingEasing => Easing.Out; diff --git a/osu.Game/Skinning/SerialisedDrawableInfo.cs b/osu.Game/Skinning/SerialisedDrawableInfo.cs index 90762da011..f571f1a945 100644 --- a/osu.Game/Skinning/SerialisedDrawableInfo.cs +++ b/osu.Game/Skinning/SerialisedDrawableInfo.cs @@ -18,9 +18,13 @@ using osuTK; namespace osu.Game.Skinning { /// - /// Serialised backing data for s. + /// Serialised backing data for s. /// Used for json serialisation in user skins. /// + /// + /// Can be created using . + /// Can also be applied to an existing drawable using . + /// [Serializable] public sealed class SerialisedDrawableInfo { @@ -36,7 +40,7 @@ namespace osu.Game.Skinning public Anchor Origin { get; set; } - /// + /// public bool UsesFixedAnchor { get; set; } public Dictionary Settings { get; set; } = new Dictionary(); @@ -62,7 +66,7 @@ namespace osu.Game.Skinning Anchor = component.Anchor; Origin = component.Origin; - if (component is ISkinnableDrawable skinnable) + if (component is ISerialisableDrawable skinnable) UsesFixedAnchor = skinnable.UsesFixedAnchor; foreach (var (_, property) in component.GetSettingsSourceProperties()) @@ -74,7 +78,7 @@ namespace osu.Game.Skinning if (component is Container container) { - foreach (var child in container.OfType().OfType()) + foreach (var child in container.OfType().OfType()) Children.Add(child.CreateSerialisedInfo()); } } @@ -102,7 +106,7 @@ namespace osu.Game.Skinning { return typeof(OsuGame).Assembly.GetTypes() .Where(t => !t.IsInterface && !t.IsAbstract) - .Where(t => typeof(ISkinnableDrawable).IsAssignableFrom(t)) + .Where(t => typeof(ISerialisableDrawable).IsAssignableFrom(t)) .OrderBy(t => t.Name) .ToArray(); } diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index c3449562c3..1d97566470 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -21,7 +21,7 @@ namespace osu.Game.Skinning /// /// A skinnable element which uses a single texture backing. /// - public partial class SkinnableSprite : SkinnableDrawable, ISkinnableDrawable + public partial class SkinnableSprite : SkinnableDrawable, ISerialisableDrawable { protected override bool ApplySizeRestrictionsToDefault => true; diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index 8b37767113..7acf83576a 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -18,9 +18,9 @@ namespace osu.Game.Skinning public GlobalSkinComponentLookup.LookupType Target { get; } - public IBindableList Components => components; + public IBindableList Components => components; - private readonly BindableList components = new BindableList(); + private readonly BindableList components = new BindableList(); public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; // ensure that components are loaded even if the target container is hidden (ie. due to user toggle). @@ -68,7 +68,7 @@ namespace osu.Game.Skinning LoadComponentAsync(content, wrapper => { AddInternal(wrapper); - components.AddRange(wrapper.Children.OfType()); + components.AddRange(wrapper.Children.OfType()); ComponentsLoaded = true; }, (cancellationSource = new CancellationTokenSource()).Token); } @@ -79,7 +79,7 @@ namespace osu.Game.Skinning /// /// Thrown when attempting to add an element to a target which is not supported by the current skin. /// Thrown if the provided instance is not a . - public void Add(ISkinnableDrawable component) + public void Add(ISerialisableDrawable component) { if (content == null) throw new NotSupportedException("Attempting to add a new component to a target container which is not supported by the current skin."); @@ -94,7 +94,7 @@ namespace osu.Game.Skinning /// /// Thrown when attempting to add an element to a target which is not supported by the current skin. /// Thrown if the provided instance is not a . - public void Remove(ISkinnableDrawable component) + public void Remove(ISerialisableDrawable component) { if (content == null) throw new NotSupportedException("Attempting to remove a new component from a target container which is not supported by the current skin."); From a7b47f6503e5de4cbaa1674cfa559e7e4e71247d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 16:28:42 +0900 Subject: [PATCH 287/516] Rename `ISkinnableTarget` to `ISerialisableDrawableContainer` --- osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs | 2 +- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 10 +++++----- .../Overlays/SkinEditor/SkinEditorChangeHandler.cs | 4 ++-- ...ableTarget.cs => ISerialisableDrawableContainer.cs} | 5 +++-- osu.Game/Skinning/Skin.cs | 4 ++-- osu.Game/Skinning/SkinnableTargetContainer.cs | 6 +++--- 6 files changed, 16 insertions(+), 15 deletions(-) rename osu.Game/Skinning/{ISkinnableTarget.cs => ISerialisableDrawableContainer.cs} (86%) diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs index 1e7bec5417..08b4c85e4a 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprintContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Overlays.SkinEditor SelectedItems.BindTo(editor.SelectedComponents); // track each target container on the current screen. - var targetContainers = target.ChildrenOfType().ToArray(); + var targetContainers = target.ChildrenOfType().ToArray(); if (targetContainers.Length == 0) { diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index aafc97d769..39187d6471 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -339,18 +339,18 @@ namespace osu.Game.Overlays.SkinEditor settingsSidebar.Add(new SkinSettingsToolbox(component)); } - private IEnumerable availableTargets => targetScreen.ChildrenOfType(); + private IEnumerable availableTargets => targetScreen.ChildrenOfType(); - private ISkinnableTarget? getFirstTarget() => availableTargets.FirstOrDefault(); + private ISerialisableDrawableContainer? getFirstTarget() => availableTargets.FirstOrDefault(); - private ISkinnableTarget? getTarget(GlobalSkinComponentLookup.LookupType target) + private ISerialisableDrawableContainer? getTarget(GlobalSkinComponentLookup.LookupType target) { return availableTargets.FirstOrDefault(c => c.Target == target); } private void revert() { - ISkinnableTarget[] targetContainers = availableTargets.ToArray(); + ISerialisableDrawableContainer[] targetContainers = availableTargets.ToArray(); foreach (var t in targetContainers) { @@ -370,7 +370,7 @@ namespace osu.Game.Overlays.SkinEditor if (!hasBegunMutating) return; - ISkinnableTarget[] targetContainers = availableTargets.ToArray(); + ISerialisableDrawableContainer[] targetContainers = availableTargets.ToArray(); foreach (var t in targetContainers) currentSkin.Value.UpdateDrawableTarget(t); diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs index 65872920f1..6c66714b79 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.SkinEditor { public partial class SkinEditorChangeHandler : EditorChangeHandler { - private readonly ISkinnableTarget? firstTarget; + private readonly ISerialisableDrawableContainer? firstTarget; // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable private readonly BindableList? components; @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.SkinEditor // In the future we'll want this to cover all changes, even to skin's `InstantiationInfo`. // We'll also need to consider cases where multiple targets are on screen at the same time. - firstTarget = targetScreen.ChildrenOfType().FirstOrDefault(); + firstTarget = targetScreen.ChildrenOfType().FirstOrDefault(); if (firstTarget == null) return; diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISerialisableDrawableContainer.cs similarity index 86% rename from osu.Game/Skinning/ISkinnableTarget.cs rename to osu.Game/Skinning/ISerialisableDrawableContainer.cs index 5833898d81..386ebee085 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISerialisableDrawableContainer.cs @@ -10,9 +10,10 @@ using osu.Game.Extensions; namespace osu.Game.Skinning { /// - /// Denotes a container which can house s. + /// A container which can house s. + /// Contains functionality for new drawables to be added, removed, and reloaded from provided . /// - public interface ISkinnableTarget : IDrawable + public interface ISerialisableDrawableContainer : IDrawable { /// /// The definition of this target. diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 44bdcafe4c..ebe9d2bdd3 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -143,7 +143,7 @@ namespace osu.Game.Skinning /// Remove all stored customisations for the provided target. /// /// The target container to reset. - public void ResetDrawableTarget(ISkinnableTarget targetContainer) + public void ResetDrawableTarget(ISerialisableDrawableContainer targetContainer) { DrawableComponentInfo.Remove(targetContainer.Target); } @@ -152,7 +152,7 @@ namespace osu.Game.Skinning /// Update serialised information for the provided target. /// /// The target container to serialise to this skin. - public void UpdateDrawableTarget(ISkinnableTarget targetContainer) + public void UpdateDrawableTarget(ISerialisableDrawableContainer targetContainer) { DrawableComponentInfo[targetContainer.Target] = targetContainer.CreateSerialisedInfo().ToArray(); } diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index 7acf83576a..abed2c09b6 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -12,7 +12,7 @@ using osu.Game.Skinning.Serialisation; namespace osu.Game.Skinning { - public partial class SkinnableTargetContainer : SkinReloadableDrawable, ISkinnableTarget + public partial class SkinnableTargetContainer : SkinReloadableDrawable, ISerialisableDrawableContainer { private Container? content; @@ -76,7 +76,7 @@ namespace osu.Game.Skinning ComponentsLoaded = true; } - /// + /// /// Thrown when attempting to add an element to a target which is not supported by the current skin. /// Thrown if the provided instance is not a . public void Add(ISerialisableDrawable component) @@ -91,7 +91,7 @@ namespace osu.Game.Skinning components.Add(component); } - /// + /// /// Thrown when attempting to add an element to a target which is not supported by the current skin. /// Thrown if the provided instance is not a . public void Remove(ISerialisableDrawable component) From e61d2d571c1b23c6f1e0d4df9f35fdc2f5b93053 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 16:35:23 +0900 Subject: [PATCH 288/516] Move the lookup type out of `ISserialisableDrawableContainer` --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 6 +++--- osu.Game/Skinning/ISerialisableDrawableContainer.cs | 5 ----- osu.Game/Skinning/Skin.cs | 6 +++--- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 39187d6471..25448906b2 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -339,7 +339,7 @@ namespace osu.Game.Overlays.SkinEditor settingsSidebar.Add(new SkinSettingsToolbox(component)); } - private IEnumerable availableTargets => targetScreen.ChildrenOfType(); + private IEnumerable availableTargets => targetScreen.ChildrenOfType(); private ISerialisableDrawableContainer? getFirstTarget() => availableTargets.FirstOrDefault(); @@ -350,7 +350,7 @@ namespace osu.Game.Overlays.SkinEditor private void revert() { - ISerialisableDrawableContainer[] targetContainers = availableTargets.ToArray(); + SkinnableTargetContainer[] targetContainers = availableTargets.ToArray(); foreach (var t in targetContainers) { @@ -370,7 +370,7 @@ namespace osu.Game.Overlays.SkinEditor if (!hasBegunMutating) return; - ISerialisableDrawableContainer[] targetContainers = availableTargets.ToArray(); + SkinnableTargetContainer[] targetContainers = availableTargets.ToArray(); foreach (var t in targetContainers) currentSkin.Value.UpdateDrawableTarget(t); diff --git a/osu.Game/Skinning/ISerialisableDrawableContainer.cs b/osu.Game/Skinning/ISerialisableDrawableContainer.cs index 386ebee085..54d8a68c95 100644 --- a/osu.Game/Skinning/ISerialisableDrawableContainer.cs +++ b/osu.Game/Skinning/ISerialisableDrawableContainer.cs @@ -15,11 +15,6 @@ namespace osu.Game.Skinning /// public interface ISerialisableDrawableContainer : IDrawable { - /// - /// The definition of this target. - /// - GlobalSkinComponentLookup.LookupType Target { get; } - /// /// A bindable list of components which are being tracked by this skinnable target. /// diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index ebe9d2bdd3..b97b167419 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -143,7 +143,7 @@ namespace osu.Game.Skinning /// Remove all stored customisations for the provided target. /// /// The target container to reset. - public void ResetDrawableTarget(ISerialisableDrawableContainer targetContainer) + public void ResetDrawableTarget(SkinnableTargetContainer targetContainer) { DrawableComponentInfo.Remove(targetContainer.Target); } @@ -152,9 +152,9 @@ namespace osu.Game.Skinning /// Update serialised information for the provided target. /// /// The target container to serialise to this skin. - public void UpdateDrawableTarget(ISerialisableDrawableContainer targetContainer) + public void UpdateDrawableTarget(SkinnableTargetContainer targetContainer) { - DrawableComponentInfo[targetContainer.Target] = targetContainer.CreateSerialisedInfo().ToArray(); + DrawableComponentInfo[targetContainer.Target] = ((ISerialisableDrawableContainer)targetContainer).CreateSerialisedInfo().ToArray(); } public virtual Drawable? GetDrawableComponent(ISkinComponentLookup lookup) From b1cf6d83d89050686fb1db8dc8df65d28cf0d42b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 17:51:18 +0900 Subject: [PATCH 289/516] Move extension methods closer to serialisation classes --- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 1 - osu.Game/Extensions/DrawableExtensions.cs | 41 --------------- .../SkinEditor/SkinEditorChangeHandler.cs | 1 - osu.Game/Skinning/ISerialisableDrawable.cs | 2 +- .../ISerialisableDrawableContainer.cs | 1 - .../SerialisableDrawableExtensions.cs | 51 +++++++++++++++++++ osu.Game/Skinning/SkinnableTargetContainer.cs | 1 - 7 files changed, 52 insertions(+), 46 deletions(-) create mode 100644 osu.Game/Skinning/SerialisableDrawableExtensions.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 5005cff265..339b38eacd 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -13,7 +13,6 @@ using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Database; -using osu.Game.Extensions; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Skinning.Legacy; diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index b6f74f5777..915a2292a2 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -1,11 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Configuration; -using osu.Game.Skinning; using osuTK; namespace osu.Game.Extensions @@ -47,42 +43,5 @@ namespace osu.Game.Extensions /// The delta vector in Parent's coordinates. public static Vector2 ScreenSpaceDeltaToParentSpace(this Drawable drawable, Vector2 delta) => drawable.Parent.ToLocalSpace(drawable.Parent.ToScreenSpace(Vector2.Zero) + delta); - - public static SerialisedDrawableInfo CreateSerialisedInfo(this Drawable component) => new SerialisedDrawableInfo(component); - - public static void ApplySerialisedInfo(this Drawable component, SerialisedDrawableInfo drawableInfo) - { - // todo: can probably make this better via deserialisation directly using a common interface. - component.Position = drawableInfo.Position; - component.Rotation = drawableInfo.Rotation; - component.Scale = drawableInfo.Scale; - component.Anchor = drawableInfo.Anchor; - component.Origin = drawableInfo.Origin; - - if (component is ISerialisableDrawable skinnable) - { - skinnable.UsesFixedAnchor = drawableInfo.UsesFixedAnchor; - - foreach (var (_, property) in component.GetSettingsSourceProperties()) - { - var bindable = ((IBindable)property.GetValue(component)!); - - if (!drawableInfo.Settings.TryGetValue(property.Name.ToSnakeCase(), out object? settingValue)) - { - // TODO: We probably want to restore default if not included in serialisation information. - // This is not simple to do as SetDefault() is only found in the typed Bindable interface right now. - continue; - } - - skinnable.CopyAdjustedSetting(bindable, settingValue); - } - } - - if (component is Container container) - { - foreach (var child in drawableInfo.Children) - container.Add(child.CreateInstance()); - } - } } } diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs index 6c66714b79..d1a1850796 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -9,7 +9,6 @@ using Newtonsoft.Json; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Testing; -using osu.Game.Extensions; using osu.Game.Screens.Edit; using osu.Game.Skinning; diff --git a/osu.Game/Skinning/ISerialisableDrawable.cs b/osu.Game/Skinning/ISerialisableDrawable.cs index 23cbda6344..65ece96a67 100644 --- a/osu.Game/Skinning/ISerialisableDrawable.cs +++ b/osu.Game/Skinning/ISerialisableDrawable.cs @@ -16,7 +16,7 @@ namespace osu.Game.Skinning /// Attaching this interface to any will make it serialisable to user skins (see ). /// Adding annotated bindables will also allow serialising settings automatically. /// - /// Serialisation is done via using . + /// Serialisation is done via using . /// public interface ISerialisableDrawable : IDrawable { diff --git a/osu.Game/Skinning/ISerialisableDrawableContainer.cs b/osu.Game/Skinning/ISerialisableDrawableContainer.cs index 54d8a68c95..9f93d8a2e3 100644 --- a/osu.Game/Skinning/ISerialisableDrawableContainer.cs +++ b/osu.Game/Skinning/ISerialisableDrawableContainer.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Extensions; namespace osu.Game.Skinning { diff --git a/osu.Game/Skinning/SerialisableDrawableExtensions.cs b/osu.Game/Skinning/SerialisableDrawableExtensions.cs new file mode 100644 index 0000000000..5e8c2843a9 --- /dev/null +++ b/osu.Game/Skinning/SerialisableDrawableExtensions.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; +using osu.Game.Extensions; + +namespace osu.Game.Skinning +{ + public static class SerialisableDrawableExtensions + { + public static SerialisedDrawableInfo CreateSerialisedInfo(this Drawable component) => new SerialisedDrawableInfo(component); + + public static void ApplySerialisedInfo(this Drawable component, SerialisedDrawableInfo drawableInfo) + { + // todo: can probably make this better via deserialisation directly using a common interface. + component.Position = drawableInfo.Position; + component.Rotation = drawableInfo.Rotation; + component.Scale = drawableInfo.Scale; + component.Anchor = drawableInfo.Anchor; + component.Origin = drawableInfo.Origin; + + if (component is ISerialisableDrawable skinnable) + { + skinnable.UsesFixedAnchor = drawableInfo.UsesFixedAnchor; + + foreach (var (_, property) in component.GetSettingsSourceProperties()) + { + var bindable = ((IBindable)property.GetValue(component)!); + + if (!drawableInfo.Settings.TryGetValue(property.Name.ToSnakeCase(), out object? settingValue)) + { + // TODO: We probably want to restore default if not included in serialisation information. + // This is not simple to do as SetDefault() is only found in the typed Bindable interface right now. + continue; + } + + skinnable.CopyAdjustedSetting(bindable, settingValue); + } + } + + if (component is Container container) + { + foreach (var child in drawableInfo.Children) + container.Add(child.CreateInstance()); + } + } + } +} diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index abed2c09b6..d29152da6c 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -8,7 +8,6 @@ using System.Threading; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Skinning.Serialisation; namespace osu.Game.Skinning { From a92e42bb842ef318c84cbb10306f05042785e441 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 18:31:55 +0900 Subject: [PATCH 290/516] Rename `SkinnableTargetContainer` to `SkinComponentsContainer` Also use full `SkinComponentsContainerLookup` instead of the sub-type. This will potentially be useful once we bring in per-ruleset targets. --- .../TestSceneCatchPlayerLegacySkin.cs | 2 +- .../Legacy/CatchLegacySkinTransformer.cs | 6 +++--- .../Skins/SkinDeserialisationTest.cs | 16 ++++++++-------- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 10 +++++----- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 10 +++++----- .../Visual/Gameplay/TestSceneSkinEditor.cs | 2 +- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 12 ++++++------ osu.Game/Screens/Play/HUDOverlay.cs | 6 +++--- osu.Game/Screens/Select/SongSelect.cs | 2 +- osu.Game/Skinning/ArgonSkin.cs | 8 ++++---- osu.Game/Skinning/LegacyBeatmapSkin.cs | 6 +++--- osu.Game/Skinning/LegacySkin.cs | 6 +++--- osu.Game/Skinning/Skin.cs | 18 +++++++++--------- ...ontainer.cs => SkinComponentsContainer.cs} | 19 ++++++++++++++----- ...up.cs => SkinComponentsContainerLookup.cs} | 10 +++++----- osu.Game/Skinning/TrianglesSkin.cs | 8 ++++---- .../Tests/Visual/LegacySkinPlayerTestScene.cs | 4 ++-- 17 files changed, 77 insertions(+), 68 deletions(-) rename osu.Game/Skinning/{SkinnableTargetContainer.cs => SkinComponentsContainer.cs} (83%) rename osu.Game/Skinning/{GlobalSkinComponentLookup.cs => SkinComponentsContainerLookup.cs} (55%) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index 8f3f39be9b..4c1ba33aa2 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Catch.Tests if (withModifiedSkin) { AddStep("change component scale", () => Player.ChildrenOfType().First().Scale = new Vector2(2f)); - AddStep("update target", () => Player.ChildrenOfType().ForEach(LegacySkin.UpdateDrawableTarget)); + AddStep("update target", () => Player.ChildrenOfType().ForEach(LegacySkin.UpdateDrawableTarget)); AddStep("exit player", () => Player.Exit()); CreateTest(); } diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index a06435583b..6704fd82e9 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -28,11 +28,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { - if (lookup is GlobalSkinComponentLookup targetComponent) + if (lookup is SkinComponentsContainerLookup componentLookup) { - switch (targetComponent.Lookup) + switch (componentLookup.Target) { - case GlobalSkinComponentLookup.LookupType.MainHUDComponents: + case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: var components = base.GetDrawableComponent(lookup) as Container; if (providesComboCounter && components != null) diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index b897523560..5d7cbad46d 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -88,7 +88,7 @@ namespace osu.Game.Tests.Skins var skin = new TestSkin(new SkinInfo(), null, storage); Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); - Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(9)); + Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(9)); } } @@ -101,10 +101,10 @@ namespace osu.Game.Tests.Skins var skin = new TestSkin(new SkinInfo(), null, storage); Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); - Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(6)); - Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.SongSelect], Has.Length.EqualTo(1)); + Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(6)); + Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.SongSelect], Has.Length.EqualTo(1)); - var skinnableInfo = skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.SongSelect].First(); + var skinnableInfo = skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.SongSelect].First(); Assert.That(skinnableInfo.Type, Is.EqualTo(typeof(SkinnableSprite))); Assert.That(skinnableInfo.Settings.First().Key, Is.EqualTo("sprite_name")); @@ -115,10 +115,10 @@ namespace osu.Game.Tests.Skins using (var storage = new ZipArchiveReader(stream)) { var skin = new TestSkin(new SkinInfo(), null, storage); - Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(8)); - Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); - Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); - Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); + Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(8)); + Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); + Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); + Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 339b38eacd..514a2d7e84 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -36,8 +36,8 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestEmptyLegacyBeatmapSkinFallsBack() { CreateSkinTest(TrianglesSkin.CreateInfo(), () => new LegacyBeatmapSkin(new BeatmapInfo(), null)); - AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); - AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(GlobalSkinComponentLookup.LookupType.MainHUDComponents, skinManager.CurrentSkin.Value)); + AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); + AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(SkinComponentsContainerLookup.TargetArea.MainHUDComponents, skinManager.CurrentSkin.Value)); } protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func getBeatmapSkin) @@ -52,9 +52,9 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - protected bool AssertComponentsFromExpectedSource(GlobalSkinComponentLookup.LookupType target, ISkin expectedSource) + protected bool AssertComponentsFromExpectedSource(SkinComponentsContainerLookup.TargetArea target, ISkin expectedSource) { - var targetContainer = Player.ChildrenOfType().First(s => s.Target == target); + var targetContainer = Player.ChildrenOfType().First(s => s.Lookup.Target == target); var actualComponentsContainer = targetContainer.ChildrenOfType().SingleOrDefault(c => c.Parent == targetContainer); if (actualComponentsContainer == null) @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Gameplay var actualInfo = actualComponentsContainer.CreateSerialisedInfo(); - var expectedComponentsContainer = expectedSource.GetDrawableComponent(new GlobalSkinComponentLookup(target)) as Container; + var expectedComponentsContainer = expectedSource.GetDrawableComponent(new SkinComponentsContainerLookup(target)) as Container; if (expectedComponentsContainer == null) return false; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 5e1412d79b..b918c5e64a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -235,8 +235,8 @@ namespace osu.Game.Tests.Visual.Gameplay createNew(); AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded); - AddUntilStep("wait for components to be hidden", () => hudOverlay.ChildrenOfType().Single().Alpha == 0); - AddUntilStep("wait for hud load", () => hudOverlay.ChildrenOfType().All(c => c.ComponentsLoaded)); + AddUntilStep("wait for components to be hidden", () => hudOverlay.ChildrenOfType().Single().Alpha == 0); + AddUntilStep("wait for hud load", () => hudOverlay.ChildrenOfType().All(c => c.ComponentsLoaded)); AddStep("bind on update", () => { @@ -254,10 +254,10 @@ namespace osu.Game.Tests.Visual.Gameplay createNew(); AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded); - AddUntilStep("wait for components to be hidden", () => hudOverlay.ChildrenOfType().Single().Alpha == 0); + AddUntilStep("wait for components to be hidden", () => hudOverlay.ChildrenOfType().Single().Alpha == 0); - AddStep("reload components", () => hudOverlay.ChildrenOfType().Single().Reload()); - AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType().Single().ComponentsLoaded); + AddStep("reload components", () => hudOverlay.ChildrenOfType().Single().Reload()); + AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType().Single().ComponentsLoaded); } private void createNew(Action? action = null) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 86d97b4999..62fdb67a30 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Gameplay { base.SetUpSteps(); - AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); + AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); AddStep("reload skin editor", () => { diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 25448906b2..133ec10202 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -339,25 +339,25 @@ namespace osu.Game.Overlays.SkinEditor settingsSidebar.Add(new SkinSettingsToolbox(component)); } - private IEnumerable availableTargets => targetScreen.ChildrenOfType(); + private IEnumerable availableTargets => targetScreen.ChildrenOfType(); private ISerialisableDrawableContainer? getFirstTarget() => availableTargets.FirstOrDefault(); - private ISerialisableDrawableContainer? getTarget(GlobalSkinComponentLookup.LookupType target) + private ISerialisableDrawableContainer? getTarget(SkinComponentsContainerLookup.TargetArea target) { - return availableTargets.FirstOrDefault(c => c.Target == target); + return availableTargets.FirstOrDefault(c => c.Lookup.Target == target); } private void revert() { - SkinnableTargetContainer[] targetContainers = availableTargets.ToArray(); + SkinComponentsContainer[] targetContainers = availableTargets.ToArray(); foreach (var t in targetContainers) { currentSkin.Value.ResetDrawableTarget(t); // add back default components - getTarget(t.Target)?.Reload(); + getTarget(t.Lookup.Target)?.Reload(); } } @@ -370,7 +370,7 @@ namespace osu.Game.Overlays.SkinEditor if (!hasBegunMutating) return; - SkinnableTargetContainer[] targetContainers = availableTargets.ToArray(); + SkinComponentsContainer[] targetContainers = availableTargets.ToArray(); foreach (var t in targetContainers) currentSkin.Value.UpdateDrawableTarget(t); diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 4d1f0b96b6..e41afd7722 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -88,7 +88,7 @@ namespace osu.Game.Screens.Play private readonly BindableBool holdingForHUD = new BindableBool(); - private readonly SkinnableTargetContainer mainComponents; + private readonly SkinComponentsContainer mainComponents; /// /// A flow which sits at the left side of the screen to house leaderboard (and related) components. @@ -390,7 +390,7 @@ namespace osu.Game.Screens.Play } } - private partial class MainComponentsContainer : SkinnableTargetContainer + private partial class MainComponentsContainer : SkinComponentsContainer { private Bindable scoringMode; @@ -398,7 +398,7 @@ namespace osu.Game.Screens.Play private OsuConfigManager config { get; set; } public MainComponentsContainer() - : base(GlobalSkinComponentLookup.LookupType.MainHUDComponents) + : base(new SkinComponentsContainerLookup(SkinComponentsContainerLookup.TargetArea.MainHUDComponents)) { RelativeSizeAxes = Axes.Both; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 8786821c77..2d3d0f88d7 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -273,7 +273,7 @@ namespace osu.Game.Screens.Select } } }, - new SkinnableTargetContainer(GlobalSkinComponentLookup.LookupType.SongSelect) + new SkinComponentsContainer(new SkinComponentsContainerLookup(SkinComponentsContainerLookup.TargetArea.SongSelect)) { RelativeSizeAxes = Axes.Both, }, diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 71f0888c6f..7b4d51ee83 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -90,10 +90,10 @@ namespace osu.Game.Skinning switch (lookup) { - case GlobalSkinComponentLookup globalLookup: - switch (globalLookup.Lookup) + case SkinComponentsContainerLookup componentLookup: + switch (componentLookup.Target) { - case GlobalSkinComponentLookup.LookupType.SongSelect: + case SkinComponentsContainerLookup.TargetArea.SongSelect: var songSelectComponents = new DefaultSkinComponentsContainer(_ => { // do stuff when we need to. @@ -101,7 +101,7 @@ namespace osu.Game.Skinning return songSelectComponents; - case GlobalSkinComponentLookup.LookupType.MainHUDComponents: + case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: var skinnableTargetWrapper = new DefaultSkinComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 8407b144f8..84ca6ed967 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -45,11 +45,11 @@ namespace osu.Game.Skinning public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { - if (lookup is GlobalSkinComponentLookup targetComponent) + if (lookup is SkinComponentsContainerLookup targetComponent) { - switch (targetComponent.Lookup) + switch (targetComponent.Target) { - case GlobalSkinComponentLookup.LookupType.MainHUDComponents: + case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: // this should exist in LegacySkin instead, but there isn't a fallback skin for LegacySkins yet. // therefore keep the check here until fallback default legacy skin is supported. if (!this.HasFont(LegacyFont.Score)) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 284a938bce..c581fcdfb6 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -343,10 +343,10 @@ namespace osu.Game.Skinning switch (lookup) { - case GlobalSkinComponentLookup target: - switch (target.Lookup) + case SkinComponentsContainerLookup componentLookup: + switch (componentLookup.Target) { - case GlobalSkinComponentLookup.LookupType.MainHUDComponents: + case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: var skinnableTargetWrapper = new DefaultSkinComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index b97b167419..977fab1b7e 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -37,9 +37,9 @@ namespace osu.Game.Skinning public SkinConfiguration Configuration { get; set; } - public IDictionary DrawableComponentInfo => drawableComponentInfo; + public IDictionary DrawableComponentInfo => drawableComponentInfo; - private readonly Dictionary drawableComponentInfo = new Dictionary(); + private readonly Dictionary drawableComponentInfo = new Dictionary(); public abstract ISample? GetSample(ISampleInfo sampleInfo); @@ -100,7 +100,7 @@ namespace osu.Game.Skinning Configuration = new SkinConfiguration(); // skininfo files may be null for default skin. - foreach (GlobalSkinComponentLookup.LookupType skinnableTarget in Enum.GetValues()) + foreach (SkinComponentsContainerLookup.TargetArea skinnableTarget in Enum.GetValues()) { string filename = $"{skinnableTarget}.json"; @@ -143,18 +143,18 @@ namespace osu.Game.Skinning /// Remove all stored customisations for the provided target. /// /// The target container to reset. - public void ResetDrawableTarget(SkinnableTargetContainer targetContainer) + public void ResetDrawableTarget(SkinComponentsContainer targetContainer) { - DrawableComponentInfo.Remove(targetContainer.Target); + DrawableComponentInfo.Remove(targetContainer.Lookup.Target); } /// /// Update serialised information for the provided target. /// /// The target container to serialise to this skin. - public void UpdateDrawableTarget(SkinnableTargetContainer targetContainer) + public void UpdateDrawableTarget(SkinComponentsContainer targetContainer) { - DrawableComponentInfo[targetContainer.Target] = ((ISerialisableDrawableContainer)targetContainer).CreateSerialisedInfo().ToArray(); + DrawableComponentInfo[targetContainer.Lookup.Target] = ((ISerialisableDrawableContainer)targetContainer).CreateSerialisedInfo().ToArray(); } public virtual Drawable? GetDrawableComponent(ISkinComponentLookup lookup) @@ -165,8 +165,8 @@ namespace osu.Game.Skinning case SkinnableSprite.SpriteComponentLookup sprite: return this.GetAnimation(sprite.LookupName, false, false); - case GlobalSkinComponentLookup target: - if (!DrawableComponentInfo.TryGetValue(target.Lookup, out var skinnableInfo)) + case SkinComponentsContainerLookup componentLookup: + if (!DrawableComponentInfo.TryGetValue(componentLookup.Target, out var skinnableInfo)) return null; var components = new List(); diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinComponentsContainer.cs similarity index 83% rename from osu.Game/Skinning/SkinnableTargetContainer.cs rename to osu.Game/Skinning/SkinComponentsContainer.cs index d29152da6c..2620b40729 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinComponentsContainer.cs @@ -11,11 +11,20 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Skinning { - public partial class SkinnableTargetContainer : SkinReloadableDrawable, ISerialisableDrawableContainer + /// + /// A container which holds many skinnable components, with functionality to add, remove and reload layouts. + /// Used to allow user customisation of skin layouts. + /// + /// + /// This is currently used as a means of serialising skin layouts to files. + /// Currently, one json file in a skin will represent one , containing + /// the output of . + /// + public partial class SkinComponentsContainer : SkinReloadableDrawable, ISerialisableDrawableContainer { private Container? content; - public GlobalSkinComponentLookup.LookupType Target { get; } + public SkinComponentsContainerLookup Lookup { get; } public IBindableList Components => components; @@ -27,9 +36,9 @@ namespace osu.Game.Skinning private CancellationTokenSource? cancellationSource; - public SkinnableTargetContainer(GlobalSkinComponentLookup.LookupType target) + public SkinComponentsContainer(SkinComponentsContainerLookup lookup) { - Target = target; + Lookup = lookup; } public void Reload(SerialisedDrawableInfo[] skinnableInfo) @@ -46,7 +55,7 @@ namespace osu.Game.Skinning }); } - public void Reload() => Reload(CurrentSkin.GetDrawableComponent(new GlobalSkinComponentLookup(Target)) as Container); + public void Reload() => Reload(CurrentSkin.GetDrawableComponent(Lookup) as Container); public void Reload(Container? componentsContainer) { diff --git a/osu.Game/Skinning/GlobalSkinComponentLookup.cs b/osu.Game/Skinning/SkinComponentsContainerLookup.cs similarity index 55% rename from osu.Game/Skinning/GlobalSkinComponentLookup.cs rename to osu.Game/Skinning/SkinComponentsContainerLookup.cs index 7dcc3c4f14..ac6e98b23a 100644 --- a/osu.Game/Skinning/GlobalSkinComponentLookup.cs +++ b/osu.Game/Skinning/SkinComponentsContainerLookup.cs @@ -3,16 +3,16 @@ namespace osu.Game.Skinning { - public class GlobalSkinComponentLookup : ISkinComponentLookup + public class SkinComponentsContainerLookup : ISkinComponentLookup { - public readonly LookupType Lookup; + public readonly TargetArea Target; - public GlobalSkinComponentLookup(LookupType lookup) + public SkinComponentsContainerLookup(TargetArea target) { - Lookup = lookup; + Target = target; } - public enum LookupType + public enum TargetArea { MainHUDComponents, SongSelect diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 7de2b124e7..5e0712012e 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -68,10 +68,10 @@ namespace osu.Game.Skinning switch (lookup) { - case GlobalSkinComponentLookup target: - switch (target.Lookup) + case SkinComponentsContainerLookup componentLookup: + switch (componentLookup.Target) { - case GlobalSkinComponentLookup.LookupType.SongSelect: + case SkinComponentsContainerLookup.TargetArea.SongSelect: var songSelectComponents = new DefaultSkinComponentsContainer(_ => { // do stuff when we need to. @@ -79,7 +79,7 @@ namespace osu.Game.Skinning return songSelectComponents; - case GlobalSkinComponentLookup.LookupType.MainHUDComponents: + case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: var skinnableTargetWrapper = new DefaultSkinComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index c5efdf36b4..2e254f5b95 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -45,13 +45,13 @@ namespace osu.Game.Tests.Visual private void addResetTargetsStep() { - AddStep("reset targets", () => this.ChildrenOfType().ForEach(t => + AddStep("reset targets", () => this.ChildrenOfType().ForEach(t => { LegacySkin.ResetDrawableTarget(t); t.Reload(); })); - AddUntilStep("wait for components to load", () => this.ChildrenOfType().All(t => t.ComponentsLoaded)); + AddUntilStep("wait for components to load", () => this.ChildrenOfType().All(t => t.ComponentsLoaded)); } public partial class SkinProvidingPlayer : TestPlayer From 08ed174f61d3547d8019af4a436309e8b2dc1486 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 18:48:13 +0900 Subject: [PATCH 291/516] Change `GameplaySkinComponentLookup`'s generic to always be an `enum` And document the class better. --- osu.Game/Skinning/GameplaySkinComponentLookup.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/GameplaySkinComponentLookup.cs b/osu.Game/Skinning/GameplaySkinComponentLookup.cs index 9247ca0e4d..984df3f5bc 100644 --- a/osu.Game/Skinning/GameplaySkinComponentLookup.cs +++ b/osu.Game/Skinning/GameplaySkinComponentLookup.cs @@ -1,12 +1,23 @@ // 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.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Skinning { + /// + /// A lookup typed intended for use for skinnable gameplay components (not HUD level components). + /// + /// + /// The most common usage of this class is for ruleset-specific skinning implementations, but it can also be used directly + /// (see 's usage for ) where ruleset-agnostic elements are required. + /// + /// An enum lookup type. public class GameplaySkinComponentLookup : ISkinComponentLookup - where T : notnull + where T : Enum { public readonly T Component; @@ -16,7 +27,7 @@ namespace osu.Game.Skinning } protected virtual string RulesetPrefix => string.Empty; - protected virtual string ComponentName => Component.ToString() ?? string.Empty; + protected virtual string ComponentName => Component.ToString(); public string LookupName => string.Join('/', new[] { "Gameplay", RulesetPrefix, ComponentName }.Where(s => !string.IsNullOrEmpty(s))); From d653335b6f22faae7952204d8fe807233f53f01b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 19:26:44 +0900 Subject: [PATCH 292/516] Add basic skin editor clipboard implementation --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 133ec10202..9c5d6677b9 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; +using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -48,6 +49,9 @@ namespace osu.Game.Overlays.SkinEditor private Bindable currentSkin = null!; + [Cached] + public readonly EditorClipboard Clipboard = new EditorClipboard(); + [Resolved] private OsuGame? game { get; set; } @@ -78,6 +82,15 @@ namespace osu.Game.Overlays.SkinEditor private EditorMenuItem undoMenuItem = null!; private EditorMenuItem redoMenuItem = null!; + private EditorMenuItem cutMenuItem = null!; + private EditorMenuItem copyMenuItem = null!; + private EditorMenuItem cloneMenuItem = null!; + private EditorMenuItem pasteMenuItem = null!; + + private readonly BindableWithCurrent canCut = new BindableWithCurrent(); + private readonly BindableWithCurrent canCopy = new BindableWithCurrent(); + private readonly BindableWithCurrent canPaste = new BindableWithCurrent(); + [Resolved] private OnScreenDisplay? onScreenDisplay { get; set; } @@ -143,6 +156,11 @@ namespace osu.Game.Overlays.SkinEditor { undoMenuItem = new EditorMenuItem(CommonStrings.Undo, MenuItemType.Standard, Undo), redoMenuItem = new EditorMenuItem(CommonStrings.Redo, MenuItemType.Standard, Redo), + new EditorMenuItemSpacer(), + cutMenuItem = new EditorMenuItem(CommonStrings.Cut, MenuItemType.Standard, Cut), + copyMenuItem = new EditorMenuItem(CommonStrings.Copy, MenuItemType.Standard, Copy), + pasteMenuItem = new EditorMenuItem(CommonStrings.Paste, MenuItemType.Standard, Paste), + cloneMenuItem = new EditorMenuItem(CommonStrings.Clone, MenuItemType.Standard, Clone), } }, } @@ -201,6 +219,21 @@ namespace osu.Game.Overlays.SkinEditor { base.LoadComplete(); + canCut.Current.BindValueChanged(cut => cutMenuItem.Action.Disabled = !cut.NewValue, true); + canCopy.Current.BindValueChanged(copy => + { + copyMenuItem.Action.Disabled = !copy.NewValue; + cloneMenuItem.Action.Disabled = !copy.NewValue; + }, true); + canPaste.Current.BindValueChanged(paste => pasteMenuItem.Action.Disabled = !paste.NewValue, true); + + SelectedComponents.BindCollectionChanged((_, _) => + { + canCopy.Value = canCut.Value = SelectedComponents.Any(); + }, true); + + Clipboard.Content.BindValueChanged(content => canPaste.Value = !string.IsNullOrEmpty(content.NewValue), true); + Show(); game?.RegisterImportHandler(this); @@ -224,6 +257,18 @@ namespace osu.Game.Overlays.SkinEditor { switch (e.Action) { + case PlatformAction.Cut: + Cut(); + return true; + + case PlatformAction.Copy: + Copy(); + return true; + + case PlatformAction.Paste: + Paste(); + return true; + case PlatformAction.Undo: Undo(); return true; @@ -361,6 +406,50 @@ namespace osu.Game.Overlays.SkinEditor } } + protected void Cut() + { + Copy(); + DeleteItems(SelectedComponents.ToArray()); + } + + protected void Copy() + { + Clipboard.Content.Value = JsonConvert.SerializeObject(SelectedComponents.Cast().Select(s => s.CreateSerialisedInfo()).ToArray()); + } + + protected void Clone() + { + // Avoid attempting to clone if copying is not available (as it may result in pasting something unexpected). + if (!canCopy.Value) + return; + + // This is an initial implementation just to get an idea of how people used this function. + // There are a couple of differences from osu!stable's implementation which will require more work to match: + // - The "clipboard" is not populated during the duplication process. + // - The duplicated hitobjects are inserted after the original pattern (add one beat_length and then quantize using beat snap). + // - The duplicated hitobjects are selected (but this is also applied for all paste operations so should be changed there). + Copy(); + Paste(); + } + + protected void Paste() + { + var drawableInfo = JsonConvert.DeserializeObject(Clipboard.Content.Value); + + if (drawableInfo == null) + return; + + var instances = drawableInfo.Select(d => d.CreateInstance()) + .OfType() + .ToArray(); + + foreach (var i in instances) + placeComponent(i); + + SelectedComponents.Clear(); + SelectedComponents.AddRange(instances); + } + protected void Undo() => changeHandler?.RestoreState(-1); protected void Redo() => changeHandler?.RestoreState(1); From bcf2555545b6250432ffa9b51906f2cc6d6d6b13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 19:34:42 +0900 Subject: [PATCH 293/516] Fix components having incorrect default positions --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 9c5d6677b9..5adbe7273c 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -444,7 +444,7 @@ namespace osu.Game.Overlays.SkinEditor .ToArray(); foreach (var i in instances) - placeComponent(i); + placeComponent(i, false); SelectedComponents.Clear(); SelectedComponents.AddRange(instances); From bc83b0c2642936246e3482ff777474190a3f55f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 19:35:22 +0900 Subject: [PATCH 294/516] Fix clipboard changes not batching as undo steps --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 5adbe7273c..5d061a5851 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -434,7 +434,9 @@ namespace osu.Game.Overlays.SkinEditor protected void Paste() { - var drawableInfo = JsonConvert.DeserializeObject(Clipboard.Content.Value); + changeHandler?.BeginChange(); + + var drawableInfo = JsonConvert.DeserializeObject(clipboard.Content.Value); if (drawableInfo == null) return; @@ -448,6 +450,8 @@ namespace osu.Game.Overlays.SkinEditor SelectedComponents.Clear(); SelectedComponents.AddRange(instances); + + changeHandler?.EndChange(); } protected void Undo() => changeHandler?.RestoreState(-1); @@ -491,8 +495,12 @@ namespace osu.Game.Overlays.SkinEditor public void DeleteItems(ISerialisableDrawable[] items) { + changeHandler?.BeginChange(); + foreach (var item in items) availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item); + + changeHandler?.EndChange(); } #region Drag & drop import handling From 925deb7ca548b7ed3476126af11740b5cb1cc2b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Feb 2023 19:35:37 +0900 Subject: [PATCH 295/516] Make skin editor clipboard shared between screens and skins to allow moving elements over --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 10 +++++----- osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 5d061a5851..ad07099d48 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -49,9 +49,6 @@ namespace osu.Game.Overlays.SkinEditor private Bindable currentSkin = null!; - [Cached] - public readonly EditorClipboard Clipboard = new EditorClipboard(); - [Resolved] private OsuGame? game { get; set; } @@ -64,6 +61,9 @@ namespace osu.Game.Overlays.SkinEditor [Resolved] private RealmAccess realm { get; set; } = null!; + [Resolved] + private EditorClipboard clipboard { get; set; } = null!; + [Resolved] private SkinEditorOverlay? skinEditorOverlay { get; set; } @@ -232,7 +232,7 @@ namespace osu.Game.Overlays.SkinEditor canCopy.Value = canCut.Value = SelectedComponents.Any(); }, true); - Clipboard.Content.BindValueChanged(content => canPaste.Value = !string.IsNullOrEmpty(content.NewValue), true); + clipboard.Content.BindValueChanged(content => canPaste.Value = !string.IsNullOrEmpty(content.NewValue), true); Show(); @@ -414,7 +414,7 @@ namespace osu.Game.Overlays.SkinEditor protected void Copy() { - Clipboard.Content.Value = JsonConvert.SerializeObject(SelectedComponents.Cast().Select(s => s.CreateSerialisedInfo()).ToArray()); + clipboard.Content.Value = JsonConvert.SerializeObject(SelectedComponents.Cast().Select(s => s.CreateSerialisedInfo()).ToArray()); } protected void Clone() diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs index c87e60e47f..1c0ece28fe 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs @@ -11,6 +11,7 @@ using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; using osu.Game.Screens; +using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components; using osuTK; @@ -28,6 +29,9 @@ namespace osu.Game.Overlays.SkinEditor private SkinEditor? skinEditor; + [Cached] + public readonly EditorClipboard Clipboard = new EditorClipboard(); + [Resolved] private OsuGame game { get; set; } = null!; From 1f586c129c1b27fee148db26846e69eb6febc1d8 Mon Sep 17 00:00:00 2001 From: Cootz Date: Wed, 15 Feb 2023 22:15:44 +0300 Subject: [PATCH 296/516] fix applied --- osu.Game/Database/LegacyExporter.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 09d6913dd9..c56c17222d 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using System.Collections.Generic; using System.IO; using osu.Framework.Platform; @@ -18,6 +19,14 @@ namespace osu.Game.Database public abstract class LegacyExporter where TModel : class, IHasNamedFiles { + /// + /// Max length of filename (including extension) + /// + /// + /// This constant is smaller 256 because adds additional "_" to the end of the path + /// + private const int max_path = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) + /// /// The file extension for exports (including the leading '.'). /// @@ -33,7 +42,16 @@ namespace osu.Game.Database UserFileStorage = storage.GetStorageForDirectory(@"files"); } - protected virtual string GetFilename(TModel item) => item.GetDisplayString(); + protected virtual string GetFilename(TModel item) + { + string fileName = item.GetDisplayString(); + + int fileNameLength = fileName.Length - FileExtension.Length; + if (fileNameLength > max_path) + fileName = fileName.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit + + return fileName; + } /// /// Exports an item to a legacy (.zip based) package. From 387a6f1330b3e22360565dd07a4a7048eae3e4d8 Mon Sep 17 00:00:00 2001 From: Cootz Date: Wed, 15 Feb 2023 22:43:43 +0300 Subject: [PATCH 297/516] Move logic to `Export` method --- osu.Game/Database/LegacyExporter.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index cd0b50c109..483c3cbd5c 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -43,16 +43,7 @@ namespace osu.Game.Database UserFileStorage = storage.GetStorageForDirectory(@"files"); } - protected virtual string GetFilename(TModel item) - { - string fileName = item.GetDisplayString(); - - int fileNameLength = fileName.Length - FileExtension.Length; - if (fileNameLength > max_path) - fileName = fileName.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit - - return fileName; - } + protected virtual string GetFilename(TModel item) => item.GetDisplayString(); /// /// Exports an item to a legacy (.zip based) package. @@ -68,6 +59,15 @@ namespace osu.Game.Database .Concat(exportStorage.GetDirectories(string.Empty)); string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}"); + + if (filename.Length > max_path) + { + string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename); + + filenameWithoutExtension = filenameWithoutExtension.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit + filename = $"{filenameWithoutExtension}{FileExtension}"; + } + using (var stream = exportStorage.CreateFileSafely(filename)) ExportModelTo(item, stream); From 2fbaf88a3c8edd6f629b18a81df33acc96138cc4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 15:24:37 +0900 Subject: [PATCH 298/516] Add clipboard dependency to `SkinEditor` specific tests This is usually provided by the `SkinEditorOverlay`, which is not always present in tests. --- osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs | 4 ++++ .../Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 62fdb67a30..2f20d75813 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -12,6 +12,7 @@ using osu.Game.Overlays.Settings; using osu.Game.Overlays.SkinEditor; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Edit; using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Skinning; using osuTK.Input; @@ -27,6 +28,9 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + [Cached] + public readonly EditorClipboard Clipboard = new EditorClipboard(); + [SetUpSteps] public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index d5b6ac38cb..a7da8f9832 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -12,6 +12,7 @@ using osu.Game.Overlays.SkinEditor; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Edit; using osu.Game.Screens.Play; using osu.Game.Tests.Gameplay; using osuTK.Input; @@ -32,6 +33,9 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached(typeof(IGameplayClock))] private readonly IGameplayClock gameplayClock = new GameplayClockContainer(new FramedClock()); + [Cached] + public readonly EditorClipboard Clipboard = new EditorClipboard(); + [SetUpSteps] public void SetUpSteps() { From 0b25f7baeb1e71be25fb7f3db18760493ded2d7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 15:27:30 +0900 Subject: [PATCH 299/516] Reword and fix typos in some new xmldoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Skinning/GameplaySkinComponentLookup.cs | 2 +- osu.Game/Skinning/ISkinSource.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/GameplaySkinComponentLookup.cs b/osu.Game/Skinning/GameplaySkinComponentLookup.cs index 984df3f5bc..a44bf3a43d 100644 --- a/osu.Game/Skinning/GameplaySkinComponentLookup.cs +++ b/osu.Game/Skinning/GameplaySkinComponentLookup.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Skinning { /// - /// A lookup typed intended for use for skinnable gameplay components (not HUD level components). + /// A lookup type intended for use for skinnable gameplay components (not HUD level components). /// /// /// The most common usage of this class is for ruleset-specific skinning implementations, but it can also be used directly diff --git a/osu.Game/Skinning/ISkinSource.cs b/osu.Game/Skinning/ISkinSource.cs index b05d52d47c..0dfc99e3bc 100644 --- a/osu.Game/Skinning/ISkinSource.cs +++ b/osu.Game/Skinning/ISkinSource.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; namespace osu.Game.Skinning { /// - /// An abstract skin implementation which generally provides access to more than one skins (with fallback logic). + /// An abstract skin implementation, whose primary purpose is to properly handle component fallback across multiple layers of skins (e.g.: beatmap skin, user skin, default skin). /// /// /// Common usage is to do an initial lookup via , and use the returned From eea0cd3cf8c29d200cdb685f1c1cd75800165f88 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 15:31:35 +0900 Subject: [PATCH 300/516] Reword xmldoc on `ISerialisableDrawable` to make less skin-centric --- osu.Game/Skinning/ISerialisableDrawable.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Skinning/ISerialisableDrawable.cs b/osu.Game/Skinning/ISerialisableDrawable.cs index 65ece96a67..503b44c2dd 100644 --- a/osu.Game/Skinning/ISerialisableDrawable.cs +++ b/osu.Game/Skinning/ISerialisableDrawable.cs @@ -10,13 +10,14 @@ using osu.Game.Configuration; namespace osu.Game.Skinning { /// - /// A drawable which can be serialised to a skin, placed and customised via the skin layout editor. + /// A drawable which is intended to be serialised to . /// /// - /// Attaching this interface to any will make it serialisable to user skins (see ). - /// Adding annotated bindables will also allow serialising settings automatically. + /// This is currently used exclusively for serialisation to a skin, and leaned on heavily to allow placement and customisation in the skin layout editor. + /// That said, it is intended to be flexible enough to potentially be used in other places we want to serialise drawables in the future. /// - /// Serialisation is done via using . + /// Attaching this interface to any will make it serialisable via . + /// Adding annotated bindables will also allow serialising settings automatically. /// public interface ISerialisableDrawable : IDrawable { From 76f7accd1378be9ca051c0cf3e1b2936d9b14eaf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 15:33:56 +0900 Subject: [PATCH 301/516] Standardise all local `SkinComponentsContainerLookup` variables to `containerLookup` --- .../Skinning/Legacy/CatchLegacySkinTransformer.cs | 4 ++-- osu.Game/Skinning/ArgonSkin.cs | 4 ++-- osu.Game/Skinning/LegacyBeatmapSkin.cs | 4 ++-- osu.Game/Skinning/LegacySkin.cs | 4 ++-- osu.Game/Skinning/Skin.cs | 4 ++-- osu.Game/Skinning/TrianglesSkin.cs | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 6704fd82e9..fb8af9bdb6 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -28,9 +28,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { - if (lookup is SkinComponentsContainerLookup componentLookup) + if (lookup is SkinComponentsContainerLookup containerLookup) { - switch (componentLookup.Target) + switch (containerLookup.Target) { case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: var components = base.GetDrawableComponent(lookup) as Container; diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 7b4d51ee83..737b222b9d 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -90,8 +90,8 @@ namespace osu.Game.Skinning switch (lookup) { - case SkinComponentsContainerLookup componentLookup: - switch (componentLookup.Target) + case SkinComponentsContainerLookup containerLookup: + switch (containerLookup.Target) { case SkinComponentsContainerLookup.TargetArea.SongSelect: var songSelectComponents = new DefaultSkinComponentsContainer(_ => diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 84ca6ed967..1cbfda16cf 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -45,9 +45,9 @@ namespace osu.Game.Skinning public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { - if (lookup is SkinComponentsContainerLookup targetComponent) + if (lookup is SkinComponentsContainerLookup containerLookup) { - switch (targetComponent.Target) + switch (containerLookup.Target) { case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: // this should exist in LegacySkin instead, but there isn't a fallback skin for LegacySkins yet. diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index c581fcdfb6..98d9f1d617 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -343,8 +343,8 @@ namespace osu.Game.Skinning switch (lookup) { - case SkinComponentsContainerLookup componentLookup: - switch (componentLookup.Target) + case SkinComponentsContainerLookup containerLookup: + switch (containerLookup.Target) { case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: var skinnableTargetWrapper = new DefaultSkinComponentsContainer(container => diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 977fab1b7e..f261937012 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -165,8 +165,8 @@ namespace osu.Game.Skinning case SkinnableSprite.SpriteComponentLookup sprite: return this.GetAnimation(sprite.LookupName, false, false); - case SkinComponentsContainerLookup componentLookup: - if (!DrawableComponentInfo.TryGetValue(componentLookup.Target, out var skinnableInfo)) + case SkinComponentsContainerLookup containerLookup: + if (!DrawableComponentInfo.TryGetValue(containerLookup.Target, out var skinnableInfo)) return null; var components = new List(); diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 5e0712012e..12cdb71744 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -68,8 +68,8 @@ namespace osu.Game.Skinning switch (lookup) { - case SkinComponentsContainerLookup componentLookup: - switch (componentLookup.Target) + case SkinComponentsContainerLookup containerLookup: + switch (containerLookup.Target) { case SkinComponentsContainerLookup.TargetArea.SongSelect: var songSelectComponents = new DefaultSkinComponentsContainer(_ => From 81dcc105a96fb72b8cbd066432fc70fef532620a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 15:34:41 +0900 Subject: [PATCH 302/516] Rename left-over `skinnable` naming in `SerialisedDrawableExtensions` --- osu.Game/Skinning/SerialisableDrawableExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Skinning/SerialisableDrawableExtensions.cs b/osu.Game/Skinning/SerialisableDrawableExtensions.cs index 5e8c2843a9..51b57a000d 100644 --- a/osu.Game/Skinning/SerialisableDrawableExtensions.cs +++ b/osu.Game/Skinning/SerialisableDrawableExtensions.cs @@ -22,9 +22,9 @@ namespace osu.Game.Skinning component.Anchor = drawableInfo.Anchor; component.Origin = drawableInfo.Origin; - if (component is ISerialisableDrawable skinnable) + if (component is ISerialisableDrawable serialisableDrawable) { - skinnable.UsesFixedAnchor = drawableInfo.UsesFixedAnchor; + serialisableDrawable.UsesFixedAnchor = drawableInfo.UsesFixedAnchor; foreach (var (_, property) in component.GetSettingsSourceProperties()) { @@ -37,7 +37,7 @@ namespace osu.Game.Skinning continue; } - skinnable.CopyAdjustedSetting(bindable, settingValue); + serialisableDrawable.CopyAdjustedSetting(bindable, settingValue); } } From ce9ef3bc3c0092b99c904ba89c0a7ce99be6cab4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 15:47:20 +0900 Subject: [PATCH 303/516] Always create `ResumeOverlay`, with `UseResumeOverlay` flag only affecting whether it is displayed or not --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index c839062875..d57aec1271 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -194,16 +194,11 @@ namespace osu.Game.Rulesets.UI Audio = audioContainer; - if (UseResumeOverlay) + if ((ResumeOverlay = CreateResumeOverlay()) != null) { - if ((ResumeOverlay = CreateResumeOverlay()) == null) - UseResumeOverlay = false; - else - { - AddInternal(CreateInputManager() - .WithChild(CreatePlayfieldAdjustmentContainer() - .WithChild(ResumeOverlay))); - } + AddInternal(CreateInputManager() + .WithChild(CreatePlayfieldAdjustmentContainer() + .WithChild(ResumeOverlay))); } applyRulesetMods(Mods, config); @@ -515,7 +510,10 @@ namespace osu.Game.Rulesets.UI /// /// Whether the should be used to return the user's cursor position to its previous location after a pause. /// - /// Defaults to true, but will become false if the ruleset fails to return a non-null overlay via . + /// + /// Defaults to true. + /// Even if true, will not have any effect if the ruleset does not have a resume overlay (see ). + /// public bool UseResumeOverlay { get; set; } = true; /// @@ -542,6 +540,11 @@ namespace osu.Game.Rulesets.UI } } + /// + /// Create an optional resume overlay, which is displayed when a player requests to resume gameplay during non-break time. + /// This can be used to force the player to return their hands / cursor to the position they left off, to avoid players + /// using pauses as a means of adjusting their inputs (aka "pause buffering"). + /// protected virtual ResumeOverlay CreateResumeOverlay() => null; /// From 9d02a2ef0e8a17398459403ac71353d4688ad4ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 17:37:46 +0900 Subject: [PATCH 304/516] Apply NRT to `GamepleSampleTriggerSource` tests --- .../Gameplay/TestSceneGameplaySampleTriggerSource.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index e184d50d7c..a9b469fd86 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.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.Linq; using NUnit.Framework; using osu.Game.Audio; @@ -20,10 +18,10 @@ namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneGameplaySampleTriggerSource : PlayerTestScene { - private TestGameplaySampleTriggerSource sampleTriggerSource; + private TestGameplaySampleTriggerSource sampleTriggerSource = null!; protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); - private Beatmap beatmap; + private Beatmap beatmap = null!; protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { @@ -80,7 +78,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestCorrectHitObject() { - HitObjectLifetimeEntry nextObjectEntry = null; + HitObjectLifetimeEntry? nextObjectEntry = null; AddAssert("no alive objects", () => getNextAliveObject() == null); @@ -103,7 +101,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("hit first hitobject", () => { InputManager.Click(MouseButton.Left); - return nextObjectEntry.Result?.HasResult == true; + return nextObjectEntry?.Result?.HasResult == true; }); AddAssert("check correct object after hit", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[1]); @@ -115,7 +113,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("check correct object after none alive", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); } - private DrawableHitObject getNextAliveObject() => + private DrawableHitObject? getNextAliveObject() => Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.FirstOrDefault(); [Test] From 979c079f8b5f852575e9722303173d28facbd31a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 17:58:32 +0900 Subject: [PATCH 305/516] Refactor `GameplaySampleTriggerSource` test to not be realtime dependent --- .../TestSceneGameplaySampleTriggerSource.cs | 79 +++++++++++++------ 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index a9b469fd86..e7bdf7b9ba 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -1,8 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Diagnostics; using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Timing; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -12,6 +16,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.UI; +using osu.Game.Storyboards; using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay @@ -23,6 +28,12 @@ namespace osu.Game.Tests.Visual.Gameplay private Beatmap beatmap = null!; + [Resolved] + private AudioManager audio { get; set; } = null!; + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null) + => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audio); + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { beatmap = new Beatmap @@ -37,12 +48,13 @@ namespace osu.Game.Tests.Visual.Gameplay const double start_offset = 8000; const double spacing = 2000; + // intentionally start objects a bit late so we can test the case of no alive objects. double t = start_offset; + beatmap.HitObjects.AddRange(new[] { new HitCircle { - // intentionally start objects a bit late so we can test the case of no alive objects. StartTime = t += spacing, Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) } }, @@ -78,41 +90,64 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestCorrectHitObject() { - HitObjectLifetimeEntry? nextObjectEntry = null; + waitForAliveObjectIndex(null); - AddAssert("no alive objects", () => getNextAliveObject() == null); + seekBeforeIndex(0); + waitForAliveObjectIndex(0); + checkValidObjectIndex(0); - AddAssert("check initially correct object", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[0]); + AddAssert("first object not hit", () => getNextAliveObject()?.Entry?.Result?.HasResult != true); - AddUntilStep("get next object", () => + AddStep("hit first object", () => { - var nextDrawableObject = getNextAliveObject(); + var next = getNextAliveObject(); - if (nextDrawableObject != null) + if (next != null) { - nextObjectEntry = nextDrawableObject.Entry; - InputManager.MoveMouseTo(nextDrawableObject.ScreenSpaceDrawQuad.Centre); - return true; + Debug.Assert(next.Entry?.Result?.HasResult != true); + + InputManager.MoveMouseTo(next.ScreenSpaceDrawQuad.Centre); + InputManager.Click(MouseButton.Left); } - - return false; }); - AddUntilStep("hit first hitobject", () => - { - InputManager.Click(MouseButton.Left); - return nextObjectEntry?.Result?.HasResult == true; - }); + AddAssert("first object hit", () => getNextAliveObject()?.Entry?.Result?.HasResult == true); - AddAssert("check correct object after hit", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[1]); + checkValidObjectIndex(1); - AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[2]); - AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); + // Still object 1 as it's not hit yet. + seekBeforeIndex(1); + waitForAliveObjectIndex(1); + checkValidObjectIndex(1); - AddUntilStep("no alive objects", () => getNextAliveObject() == null); - AddAssert("check correct object after none alive", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); + seekBeforeIndex(2); + waitForAliveObjectIndex(2); + checkValidObjectIndex(2); + + seekBeforeIndex(3); + waitForAliveObjectIndex(3); + checkValidObjectIndex(3); + + AddStep("Seek into future", () => Beatmap.Value.Track.Seek(beatmap.HitObjects.Last().GetEndTime() + 10000)); + + waitForAliveObjectIndex(null); + checkValidObjectIndex(3); } + private void seekBeforeIndex(int index) => + AddStep($"seek to just before object {index}", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[index].StartTime - 100)); + + private void waitForAliveObjectIndex(int? index) + { + if (index == null) + AddUntilStep("wait for no alive objects", getNextAliveObject, () => Is.Null); + else + AddUntilStep($"wait for next alive to be {index}", () => getNextAliveObject()?.HitObject, () => Is.EqualTo(beatmap.HitObjects[index.Value])); + } + + private void checkValidObjectIndex(int index) => + AddAssert($"check valid object is {index}", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[index])); + private DrawableHitObject? getNextAliveObject() => Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.FirstOrDefault(); From b59ec551f6179d204cf3ee14219e8fe101e2844e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 18:13:11 +0900 Subject: [PATCH 306/516] Add test coverage of `GameplaySampleTriggerSource` not considering nested objects --- .../TestSceneGameplaySampleTriggerSource.cs | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index e7bdf7b9ba..86dfce438a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -10,13 +10,16 @@ using osu.Framework.Timing; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Legacy; using osu.Game.Rulesets; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.UI; using osu.Game.Storyboards; +using osuTK; using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay @@ -36,13 +39,16 @@ namespace osu.Game.Tests.Visual.Gameplay protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { + ControlPointInfo controlPointInfo = new LegacyControlPointInfo(); + beatmap = new Beatmap { BeatmapInfo = new BeatmapInfo { Difficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 }, Ruleset = ruleset - } + }, + ControlPointInfo = controlPointInfo }; const double start_offset = 8000; @@ -51,7 +57,7 @@ namespace osu.Game.Tests.Visual.Gameplay // intentionally start objects a bit late so we can test the case of no alive objects. double t = start_offset; - beatmap.HitObjects.AddRange(new[] + beatmap.HitObjects.AddRange(new HitObject[] { new HitCircle { @@ -71,12 +77,24 @@ namespace osu.Game.Tests.Visual.Gameplay }, new HitCircle { - StartTime = t + spacing, + StartTime = t += spacing, + }, + new Slider + { + StartTime = t += spacing, + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, Vector2.UnitY * 200 }), Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_WHISTLE) }, SampleControlPoint = new SampleControlPoint { SampleBank = "soft" }, }, }); + // Add a change in volume halfway through final slider. + controlPointInfo.Add(t, new SampleControlPoint + { + SampleBank = "normal", + SampleVolume = 20, + }); + return beatmap; } @@ -128,10 +146,23 @@ namespace osu.Game.Tests.Visual.Gameplay waitForAliveObjectIndex(3); checkValidObjectIndex(3); - AddStep("Seek into future", () => Beatmap.Value.Track.Seek(beatmap.HitObjects.Last().GetEndTime() + 10000)); + seekBeforeIndex(4); + waitForAliveObjectIndex(4); + // Even before the object, we should prefer the first nested object's sample. + // This is because the (parent) object will only play its sample at the final EndTime. + AddAssert("check valid object is slider's first nested", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4].NestedHitObjects.First())); + + AddStep("seek to just after slider", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[4].GetEndTime() + 100)); + AddUntilStep("wait until valid object is slider's last nested", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4].NestedHitObjects.Last())); + + // After we get far enough away, the samples of the object itself should be used, not any nested object. + AddStep("seek to further after slider", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[4].GetEndTime() + 1000)); + AddUntilStep("wait until valid object is slider itself", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4])); + + AddStep("Seek into future", () => Beatmap.Value.Track.Seek(beatmap.HitObjects.Last().GetEndTime() + 10000)); waitForAliveObjectIndex(null); - checkValidObjectIndex(3); + checkValidObjectIndex(4); } private void seekBeforeIndex(int index) => From affa9507a1549e0d7393cd244ebc5b1b5195c1b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 17:34:38 +0900 Subject: [PATCH 307/516] Fix `GameplaySampleTriggerSource` not considering nested objects when determining the best sample to play --- .../UI/GameplaySampleTriggerSource.cs | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index d2244df3b8..de16cc05c7 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Graphics.Containers; using osu.Game.Audio; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Skinning; namespace osu.Game.Rulesets.UI @@ -68,27 +69,61 @@ namespace osu.Game.Rulesets.UI protected HitObject GetMostValidObject() { // The most optimal lookup case we have is when an object is alive. There are usually very few alive objects so there's no drawbacks in attempting this lookup each time. - var hitObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.HasResult != true)?.HitObject; + var drawableHitObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.HasResult != true); - // In the case a next object isn't available in drawable form, we need to do a somewhat expensive traversal to get a valid sound to play. - if (hitObject == null) + if (drawableHitObject != null) { - // This lookup can be skipped if the last entry is still valid (in the future and not yet hit). - if (fallbackObject == null || fallbackObject.Result?.HasResult == true) - { - // We need to use lifetime entries to find the next object (we can't just use `hitObjectContainer.Objects` due to pooling - it may even be empty). - // If required, we can make this lookup more efficient by adding support to get next-future-entry in LifetimeEntryManager. - fallbackObject = hitObjectContainer.Entries - .Where(e => e.Result?.HasResult != true).MinBy(e => e.HitObject.StartTime); + // A hit object may have a more valid nested object. + drawableHitObject = getMostValidNestedDrawable(drawableHitObject); - // In the case there are no unjudged objects, the last hit object should be used instead. - fallbackObject ??= hitObjectContainer.Entries.LastOrDefault(); - } - - hitObject = fallbackObject?.HitObject; + return drawableHitObject.HitObject; } - return hitObject; + // In the case a next object isn't available in drawable form, we need to do a somewhat expensive traversal to get a valid sound to play. + // This lookup can be skipped if the last entry is still valid (in the future and not yet hit). + if (fallbackObject == null || fallbackObject.Result?.HasResult == true) + { + // We need to use lifetime entries to find the next object (we can't just use `hitObjectContainer.Objects` due to pooling - it may even be empty). + // If required, we can make this lookup more efficient by adding support to get next-future-entry in LifetimeEntryManager. + fallbackObject = hitObjectContainer.Entries + .Where(e => e.Result?.HasResult != true).MinBy(e => e.HitObject.StartTime); + + if (fallbackObject != null) + return fallbackObject.HitObject; + + // In the case there are no unjudged objects, the last hit object should be used instead. + fallbackObject ??= hitObjectContainer.Entries.LastOrDefault(); + } + + if (fallbackObject == null) + return null; + + bool fallbackHasResult = fallbackObject.Result?.HasResult == true; + + // If the fallback has been judged then we want the sample from the object itself. + if (fallbackHasResult) + return fallbackObject.HitObject; + + // Else we want the earliest (including nested). + // In cases of nested objects, they will always have earlier sample data than their parent object. + return getEarliestNestedObject(fallbackObject.HitObject); + } + + private DrawableHitObject getMostValidNestedDrawable(DrawableHitObject o) + { + var nestedWithoutResult = o.NestedHitObjects.FirstOrDefault(n => n.Result?.HasResult != true); + + if (nestedWithoutResult == null) + return o; + + return getMostValidNestedDrawable(nestedWithoutResult); + } + + private HitObject getEarliestNestedObject(HitObject hitObject) + { + var nested = hitObject.NestedHitObjects.FirstOrDefault(); + + return nested != null ? getEarliestNestedObject(nested) : hitObject; } private SkinnableSound getNextSample() From 394d368f165431e7bb58bc4d365ee7f7fbb6614b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 18:45:22 +0900 Subject: [PATCH 308/516] Fix song select potentially updating background parameters when not the current screen --- .../Screens/Play/ScreenWithBeatmapBackground.cs | 11 ++++++++--- osu.Game/Screens/Select/SongSelect.cs | 16 ++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index d6c8a0ad6a..a5d1961bd8 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -1,9 +1,9 @@ // 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 System.Diagnostics; +using osu.Framework.Screens; using osu.Game.Screens.Backgrounds; namespace osu.Game.Screens.Play @@ -12,6 +12,11 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - public void ApplyToBackground(Action action) => base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b)); + public void ApplyToBackground(Action action) + { + Debug.Assert(this.IsCurrentScreen()); + + base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b)); + } } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 8546dfeeaa..8a9a20261e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -765,14 +765,18 @@ namespace osu.Game.Screens.Select /// The working beatmap. private void updateComponentFromBeatmap(WorkingBeatmap beatmap) { - ApplyToBackground(backgroundModeBeatmap => + // If not the current screen, this will be applied in OnResuming. + if (this.IsCurrentScreen()) { - backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.IgnoreUserSettings.Value = true; - backgroundModeBeatmap.FadeColour(Color4.White, 250); + ApplyToBackground(backgroundModeBeatmap => + { + backgroundModeBeatmap.Beatmap = beatmap; + backgroundModeBeatmap.IgnoreUserSettings.Value = true; + backgroundModeBeatmap.FadeColour(Color4.White, 250); - applyBlurToBackground(backgroundModeBeatmap); - }); + applyBlurToBackground(backgroundModeBeatmap); + }); + } beatmapInfoWedge.Beatmap = beatmap; From cb7df7282b78e9fd3abf05aac19d0fedf515416f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 20:01:59 +0900 Subject: [PATCH 309/516] Apply NRT to `SerialisedDrawableInfo` --- osu.Game/Skinning/SerialisedDrawableInfo.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Skinning/SerialisedDrawableInfo.cs b/osu.Game/Skinning/SerialisedDrawableInfo.cs index f571f1a945..12f6d3ac7e 100644 --- a/osu.Game/Skinning/SerialisedDrawableInfo.cs +++ b/osu.Game/Skinning/SerialisedDrawableInfo.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 System.Collections.Generic; using System.Linq; @@ -28,7 +26,7 @@ namespace osu.Game.Skinning [Serializable] public sealed class SerialisedDrawableInfo { - public Type Type { get; set; } + public Type Type { get; set; } = null!; public Vector2 Position { get; set; } From f1da213beaaaba85b82c785def1c43f6cb1f62ec Mon Sep 17 00:00:00 2001 From: Cootz Date: Thu, 16 Feb 2023 16:26:57 +0300 Subject: [PATCH 310/516] Add tests --- osu.Game.Tests/Database/LegacyExporterTest.cs | 85 +++++++++++++++++++ osu.Game/Database/LegacyExporter.cs | 6 +- 2 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Tests/Database/LegacyExporterTest.cs diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs new file mode 100644 index 0000000000..5f07e6c917 --- /dev/null +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -0,0 +1,85 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using NUnit.Framework; +using osu.Framework.Platform; +using osu.Framework.Testing; +using osu.Game.Database; + +namespace osu.Game.Tests.Database +{ + public class LegacyExporterTest + { + private TestLegacyExporter? legacyExporter; + private TemporaryNativeStorage? storage; + + [SetUp] + public void SetupLegacyExporter() + { + storage = new TemporaryNativeStorage("export-storage"); + legacyExporter = new TestLegacyExporter(storage); + } + + [Test] + public void ExportFileWithNormalName() + { + var exportStorage = storage?.GetStorageForDirectory(@"exports"); + + string filename = "normal file name"; + var item = new TestPathInfo(filename); + + Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True); + Assert.DoesNotThrow(() => legacyExporter?.Export(item)); + Assert.That(exportStorage?.Exists($"{filename}{legacyExporter?.GetExtension()}"), Is.True); + } + + [Test] + public void ExportFileWithSuperLongName() + { + var exportStorage = storage?.GetStorageForDirectory(@"exports"); + + string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; + + int capacity = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0); + string expectedName = fullname.Remove(capacity); + + var item = new TestPathInfo(fullname); + + Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True); + Assert.DoesNotThrow(() => legacyExporter?.Export(item)); + Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True); + } + + [TearDown] + public void CleanupAfterTest() + { + storage?.Dispose(); + } + + private class TestPathInfo : IHasNamedFiles + { + public string FileName { get; set; } = string.Empty; + + public TestPathInfo(string fileName) => FileName = fileName; + + public IEnumerable Files { get; set; } = new List(); + + public override string ToString() => FileName; + } + + private class TestLegacyExporter : LegacyExporter + { + public TestLegacyExporter(Storage storage) : base(storage) { } + + public static int GetMaxPath() => MAX_PATH; + + public string GetExtension() => FileExtension; + + protected override string FileExtension => ".ots"; + } + } +} diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 483c3cbd5c..9041f58368 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -26,7 +26,7 @@ namespace osu.Game.Database /// /// This constant is smaller 256 because adds additional "_" to the end of the path /// - private const int max_path = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) + protected const int MAX_PATH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) /// /// The file extension for exports (including the leading '.'). @@ -60,11 +60,11 @@ namespace osu.Game.Database string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}"); - if (filename.Length > max_path) + if (filename.Length > MAX_PATH) { string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename); - filenameWithoutExtension = filenameWithoutExtension.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit + filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_PATH - FileExtension.Length); //Truncating the name to fit the path limit filename = $"{filenameWithoutExtension}{FileExtension}"; } From 6819a45a1bdba3fdd2b28a6d7983b73116ddbded Mon Sep 17 00:00:00 2001 From: Cootz Date: Thu, 16 Feb 2023 16:42:07 +0300 Subject: [PATCH 311/516] Improve code slightly --- osu.Game.Tests/Database/LegacyExporterTest.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index 5f07e6c917..c464eb5c28 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -2,9 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; using NUnit.Framework; using osu.Framework.Platform; using osu.Framework.Testing; @@ -29,7 +26,7 @@ namespace osu.Game.Tests.Database { var exportStorage = storage?.GetStorageForDirectory(@"exports"); - string filename = "normal file name"; + const string filename = "normal file name"; var item = new TestPathInfo(filename); Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True); @@ -42,7 +39,7 @@ namespace osu.Game.Tests.Database { var exportStorage = storage?.GetStorageForDirectory(@"exports"); - string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; + const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; int capacity = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0); string expectedName = fullname.Remove(capacity); @@ -62,7 +59,7 @@ namespace osu.Game.Tests.Database private class TestPathInfo : IHasNamedFiles { - public string FileName { get; set; } = string.Empty; + public string FileName { get; set; } public TestPathInfo(string fileName) => FileName = fileName; @@ -73,7 +70,10 @@ namespace osu.Game.Tests.Database private class TestLegacyExporter : LegacyExporter { - public TestLegacyExporter(Storage storage) : base(storage) { } + public TestLegacyExporter(Storage storage) + : base(storage) + { + } public static int GetMaxPath() => MAX_PATH; From 5bdc5dfadde8c7b4d32abbd81e2555718f803366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 16 Feb 2023 19:02:51 +0100 Subject: [PATCH 312/516] Add one more assert to keep coverage from previous implementation --- .../Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index e7bdf7b9ba..6770309a7d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -91,6 +91,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestCorrectHitObject() { waitForAliveObjectIndex(null); + checkValidObjectIndex(0); seekBeforeIndex(0); waitForAliveObjectIndex(0); From ad5132ed4194380bae37331b2746333a5acead3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 16 Feb 2023 20:47:51 +0100 Subject: [PATCH 313/516] Remove redundant conditional access qualifier It is impossible for the callback passed to `ApplyToBackground()` to receive a null reference. See `OsuScreen.ApplyToBackground()` - if the background to call the callback on were `null`, then an `InvalidOperationException` would be thrown instead. --- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index d9062da8aa..4f7e4add32 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -417,7 +417,7 @@ namespace osu.Game.Screens.Play lowPassFilter.CutoffTo(1000, 650, Easing.OutQuint); highPassFilter.CutoffTo(300).Then().CutoffTo(0, 1250); // 1250 is to line up with the appearance of MetadataInfo (750 delay + 500 fade-in) - ApplyToBackground(b => b?.FadeColour(Color4.White, 800, Easing.OutQuint)); + ApplyToBackground(b => b.FadeColour(Color4.White, 800, Easing.OutQuint)); } protected virtual void ContentOut() From b8084a15ebc9a5bb278b46c7ea31d478063245e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 16 Feb 2023 21:26:01 +0100 Subject: [PATCH 314/516] Revert `ResumeOverlay` setter accessibility change --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index d57aec1271..2f8b101cfc 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -505,7 +505,7 @@ namespace osu.Game.Rulesets.UI /// /// An optional overlay used when resuming gameplay from a paused state. /// - public ResumeOverlay ResumeOverlay { get; set; } + public ResumeOverlay ResumeOverlay { get; protected set; } /// /// Whether the should be used to return the user's cursor position to its previous location after a pause. From e06502085e57ec6f53a7dc93c78794a6f440bb8a Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 16 Feb 2023 16:31:42 -0600 Subject: [PATCH 315/516] Enable fading when hidden only hides appreach circles --- osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs index 786b89d790..ca2f59cfb7 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Mods [SettingSource("Fade out hit circles earlier", "Make hit circles fade out into a miss, rather than after it.")] public Bindable FadeHitCircleEarly { get; } = new Bindable(true); - private bool hiddenModActive; + private bool usingHiddenFading; public void ApplyToHitObject(HitObject hitObject) { @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (ClassicNoteLock.Value) osuRuleset.Playfield.HitPolicy = new ObjectOrderedHitPolicy(); - hiddenModActive = drawableRuleset.Mods.OfType().Any(); + usingHiddenFading = !drawableRuleset.Mods.OfType().FirstOrDefault()?.OnlyFadeApproachCircles.Value ?? false; } public void ApplyToDrawableHitObject(DrawableHitObject obj) @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Mods { case DrawableSliderHead head: head.TrackFollowCircle = !NoSliderHeadMovement.Value; - if (FadeHitCircleEarly.Value && !hiddenModActive) + if (FadeHitCircleEarly.Value && !usingHiddenFading) applyEarlyFading(head); break; @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Mods break; case DrawableHitCircle circle: - if (FadeHitCircleEarly.Value && !hiddenModActive) + if (FadeHitCircleEarly.Value && !usingHiddenFading) applyEarlyFading(circle); break; } From 6cb00cd42f22b7324df66a2863a0fe333875d2f8 Mon Sep 17 00:00:00 2001 From: Cootz Date: Fri, 17 Feb 2023 01:44:45 +0300 Subject: [PATCH 316/516] Add more test cases --- osu.Game.Tests/Database/LegacyExporterTest.cs | 54 ++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index c464eb5c28..c67ec75e92 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -22,7 +22,7 @@ namespace osu.Game.Tests.Database } [Test] - public void ExportFileWithNormalName() + public void ExportFileWithNormalNameTest() { var exportStorage = storage?.GetStorageForDirectory(@"exports"); @@ -30,23 +30,65 @@ namespace osu.Game.Tests.Database var item = new TestPathInfo(filename); Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True); - Assert.DoesNotThrow(() => legacyExporter?.Export(item)); - Assert.That(exportStorage?.Exists($"{filename}{legacyExporter?.GetExtension()}"), Is.True); + exportItemWithLongNameAndAssert(item, exportStorage, filename); } [Test] - public void ExportFileWithSuperLongName() + public void ExportFileWithNormalNameMultipleTimesTest() + { + var exportStorage = storage?.GetStorageForDirectory(@"exports"); + + const string filename = "normal file name"; + var item = new TestPathInfo(filename); + + Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True); + + //Export multiple times + string expectedFileName; + for (int i = 0; i < 10; i++) + { + expectedFileName = i == 0 ? filename : $"{filename} ({i})"; + exportItemWithLongNameAndAssert(item, exportStorage, expectedFileName); + } + } + + [Test] + public void ExportFileWithSuperLongNameTest() { var exportStorage = storage?.GetStorageForDirectory(@"exports"); const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; - int capacity = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0); - string expectedName = fullname.Remove(capacity); + int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0); + string expectedName = fullname.Remove(expectedLength); var item = new TestPathInfo(fullname); Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True); + exportItemWithLongNameAndAssert(item, exportStorage, expectedName); + } + + [Test] + public void ExportFileWithSuperLongNameMultipleTimesTest() + { + var exportStorage = storage?.GetStorageForDirectory(@"exports"); + + const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; + + int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0); + string expectedName = fullname.Remove(expectedLength); + + var item = new TestPathInfo(fullname); + + Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True); + + //Export multiple times + for (int i = 0; i < 10; i++) + exportItemWithLongNameAndAssert(item, exportStorage, expectedName); + } + + private void exportItemWithLongNameAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName) + { Assert.DoesNotThrow(() => legacyExporter?.Export(item)); Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True); } From 1d8b348e4c72d29d44ce0f56d9d6e71f98000187 Mon Sep 17 00:00:00 2001 From: Cootz Date: Fri, 17 Feb 2023 01:46:15 +0300 Subject: [PATCH 317/516] Improve naming --- osu.Game.Tests/Database/LegacyExporterTest.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index c67ec75e92..97b32b0c51 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Database var item = new TestPathInfo(filename); Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True); - exportItemWithLongNameAndAssert(item, exportStorage, filename); + exportItemAndAssert(item, exportStorage, filename); } [Test] @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Database for (int i = 0; i < 10; i++) { expectedFileName = i == 0 ? filename : $"{filename} ({i})"; - exportItemWithLongNameAndAssert(item, exportStorage, expectedFileName); + exportItemAndAssert(item, exportStorage, expectedFileName); } } @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Database var item = new TestPathInfo(fullname); Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True); - exportItemWithLongNameAndAssert(item, exportStorage, expectedName); + exportItemAndAssert(item, exportStorage, expectedName); } [Test] @@ -84,10 +84,10 @@ namespace osu.Game.Tests.Database //Export multiple times for (int i = 0; i < 10; i++) - exportItemWithLongNameAndAssert(item, exportStorage, expectedName); + exportItemAndAssert(item, exportStorage, expectedName); } - private void exportItemWithLongNameAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName) + private void exportItemAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName) { Assert.DoesNotThrow(() => legacyExporter?.Export(item)); Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True); From f4038a49a17f8670f3b3ed8613e12d197d4e96b6 Mon Sep 17 00:00:00 2001 From: Cootz Date: Fri, 17 Feb 2023 01:50:24 +0300 Subject: [PATCH 318/516] Fix inspectCode issues --- osu.Game.Tests/Database/LegacyExporterTest.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index 97b32b0c51..d67cb8abf1 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -44,10 +44,9 @@ namespace osu.Game.Tests.Database Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True); //Export multiple times - string expectedFileName; for (int i = 0; i < 10; i++) { - expectedFileName = i == 0 ? filename : $"{filename} ({i})"; + string expectedFileName = i == 0 ? filename : $"{filename} ({i})"; exportItemAndAssert(item, exportStorage, expectedFileName); } } From a84f20bf32fbd4639571c4800a77b0233b04e70b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 15 Feb 2023 23:09:55 +0300 Subject: [PATCH 319/516] Add triangles to ModSelectColumn --- osu.Game/Overlays/Mods/ModSelectColumn.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModSelectColumn.cs b/osu.Game/Overlays/Mods/ModSelectColumn.cs index e5154fd631..d9023e8dde 100644 --- a/osu.Game/Overlays/Mods/ModSelectColumn.cs +++ b/osu.Game/Overlays/Mods/ModSelectColumn.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; using osuTK; using osuTK.Graphics; @@ -27,7 +28,12 @@ namespace osu.Game.Overlays.Mods public Color4 AccentColour { get => headerBackground.Colour; - set => headerBackground.Colour = value; + set + { + headerBackground.Colour = value; + var hsv = new Colour4(value.R, value.G, value.B, 1f).ToHSV(); + triangles.Colour = ColourInfo.GradientVertical(Colour4.FromHSV(hsv.X, hsv.Y + 0.2f, hsv.Z - 0.1f), value); + } } /// @@ -44,6 +50,7 @@ namespace osu.Game.Overlays.Mods private readonly Box headerBackground; private readonly Container contentContainer; private readonly Box contentBackground; + private readonly TrianglesV2 triangles; private const float header_height = 42; @@ -73,6 +80,16 @@ namespace osu.Game.Overlays.Mods RelativeSizeAxes = Axes.X, Height = header_height + ModSelectPanel.CORNER_RADIUS }, + triangles = new TrianglesV2 + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.X, + Width = 1.1f, + Height = header_height, + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + Masking = true + }, headerText = new OsuTextFlowContainer(t => { t.Font = OsuFont.TorusAlternate.With(size: 17); From 415220a44769fa8a7027ec8d56eb38b63fac6e04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 13:30:00 +0900 Subject: [PATCH 320/516] Tidy up new test method code quality --- osu.Game.Tests/Database/LegacyExporterTest.cs | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index d67cb8abf1..803cd40132 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using NUnit.Framework; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Database; @@ -11,11 +12,11 @@ namespace osu.Game.Tests.Database { public class LegacyExporterTest { - private TestLegacyExporter? legacyExporter; - private TemporaryNativeStorage? storage; + private TestLegacyExporter legacyExporter = null!; + private TemporaryNativeStorage storage = null!; [SetUp] - public void SetupLegacyExporter() + public void SetUp() { storage = new TemporaryNativeStorage("export-storage"); legacyExporter = new TestLegacyExporter(storage); @@ -24,24 +25,24 @@ namespace osu.Game.Tests.Database [Test] public void ExportFileWithNormalNameTest() { - var exportStorage = storage?.GetStorageForDirectory(@"exports"); + var exportStorage = storage.GetStorageForDirectory(@"exports"); const string filename = "normal file name"; var item = new TestPathInfo(filename); - Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True); + Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True); exportItemAndAssert(item, exportStorage, filename); } [Test] public void ExportFileWithNormalNameMultipleTimesTest() { - var exportStorage = storage?.GetStorageForDirectory(@"exports"); + var exportStorage = storage.GetStorageForDirectory(@"exports"); const string filename = "normal file name"; var item = new TestPathInfo(filename); - Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True); + Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True); //Export multiple times for (int i = 0; i < 10; i++) @@ -54,59 +55,65 @@ namespace osu.Game.Tests.Database [Test] public void ExportFileWithSuperLongNameTest() { - var exportStorage = storage?.GetStorageForDirectory(@"exports"); + var exportStorage = storage.GetStorageForDirectory(@"exports"); - const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; + const string fullname = + "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; - int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0); + int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length); string expectedName = fullname.Remove(expectedLength); var item = new TestPathInfo(fullname); - Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True); + Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True); exportItemAndAssert(item, exportStorage, expectedName); } [Test] public void ExportFileWithSuperLongNameMultipleTimesTest() { - var exportStorage = storage?.GetStorageForDirectory(@"exports"); + var exportStorage = storage.GetStorageForDirectory(@"exports"); - const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; + const string fullname = + "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; - int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0); + int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length); string expectedName = fullname.Remove(expectedLength); var item = new TestPathInfo(fullname); - Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True); + Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True); //Export multiple times for (int i = 0; i < 10; i++) exportItemAndAssert(item, exportStorage, expectedName); } - private void exportItemAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName) + private void exportItemAndAssert(IHasNamedFiles item, Storage exportStorage, string expectedName) { - Assert.DoesNotThrow(() => legacyExporter?.Export(item)); - Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True); + Assert.DoesNotThrow(() => legacyExporter.Export(item)); + Assert.That(exportStorage.Exists($"{expectedName}{legacyExporter.GetExtension()}"), Is.True); } [TearDown] - public void CleanupAfterTest() + public void TearDown() { - storage?.Dispose(); + if (storage.IsNotNull()) + storage.Dispose(); } private class TestPathInfo : IHasNamedFiles { - public string FileName { get; set; } + public string Filename { get; } - public TestPathInfo(string fileName) => FileName = fileName; + public IEnumerable Files { get; } = new List(); - public IEnumerable Files { get; set; } = new List(); + public TestPathInfo(string filename) + { + Filename = filename; + } - public override string ToString() => FileName; + public override string ToString() => Filename; } private class TestLegacyExporter : LegacyExporter From 96b1498932c4b93126a477cf1acc1b93d11c1b57 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 13:33:22 +0900 Subject: [PATCH 321/516] Rename max length variable to make sense (it's a filename limit, not path) --- osu.Game.Tests/Database/LegacyExporterTest.cs | 14 +++++++------- osu.Game/Database/LegacyExporter.cs | 12 +++++++----- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index 803cd40132..6f144ee833 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Database const string filename = "normal file name"; var item = new TestPathInfo(filename); - Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True); + Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.GetMaxPathLength())); exportItemAndAssert(item, exportStorage, filename); } @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Database const string filename = "normal file name"; var item = new TestPathInfo(filename); - Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True); + Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPathLength(), Is.True); //Export multiple times for (int i = 0; i < 10; i++) @@ -60,12 +60,12 @@ namespace osu.Game.Tests.Database const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; - int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length); + int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length); string expectedName = fullname.Remove(expectedLength); var item = new TestPathInfo(fullname); - Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True); + Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True); exportItemAndAssert(item, exportStorage, expectedName); } @@ -77,12 +77,12 @@ namespace osu.Game.Tests.Database const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; - int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length); + int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length); string expectedName = fullname.Remove(expectedLength); var item = new TestPathInfo(fullname); - Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True); + Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True); //Export multiple times for (int i = 0; i < 10; i++) @@ -123,7 +123,7 @@ namespace osu.Game.Tests.Database { } - public static int GetMaxPath() => MAX_PATH; + public static int GetMaxPathLength() => MAX_FILENAME_LENGTH; public string GetExtension() => FileExtension; diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 9041f58368..1b74454027 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -21,12 +21,14 @@ namespace osu.Game.Database where TModel : class, IHasNamedFiles { /// - /// Max length of filename (including extension) + /// Max length of filename (including extension). /// /// - /// This constant is smaller 256 because adds additional "_" to the end of the path + /// TODO: WHY? DOCUMENTATION PER PLATFORM LINKS HERE. + /// + /// This actual usable length is smaller 256 because adds additional "_" to the end of the path /// - protected const int MAX_PATH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) + protected const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) /// /// The file extension for exports (including the leading '.'). @@ -60,11 +62,11 @@ namespace osu.Game.Database string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}"); - if (filename.Length > MAX_PATH) + if (filename.Length > MAX_FILENAME_LENGTH) { string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename); - filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_PATH - FileExtension.Length); //Truncating the name to fit the path limit + filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); //Truncating the name to fit the path limit filename = $"{filenameWithoutExtension}{FileExtension}"; } From 8c772a723f0f8ae52cf3141fab286c64c2eba198 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 13:34:19 +0900 Subject: [PATCH 322/516] Expose constant `public`ly rather than reexposing business --- osu.Game/Database/LegacyExporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 1b74454027..7434a46602 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -28,7 +28,7 @@ namespace osu.Game.Database /// /// This actual usable length is smaller 256 because adds additional "_" to the end of the path /// - protected const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) + public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) /// /// The file extension for exports (including the leading '.'). From 99236f0ae80399d9fade78c7331dff63d59301e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 13:39:24 +0900 Subject: [PATCH 323/516] Move long filename to fixture level --- osu.Game.Tests/Database/LegacyExporterTest.cs | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index 6f144ee833..114872bcf8 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -15,6 +15,9 @@ namespace osu.Game.Tests.Database private TestLegacyExporter legacyExporter = null!; private TemporaryNativeStorage storage = null!; + private const string long_filename = + "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; + [SetUp] public void SetUp() { @@ -30,7 +33,7 @@ namespace osu.Game.Tests.Database const string filename = "normal file name"; var item = new TestPathInfo(filename); - Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.GetMaxPathLength())); + Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH)); exportItemAndAssert(item, exportStorage, filename); } @@ -42,7 +45,7 @@ namespace osu.Game.Tests.Database const string filename = "normal file name"; var item = new TestPathInfo(filename); - Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPathLength(), Is.True); + Assert.That(item.Filename.Length < TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True); //Export multiple times for (int i = 0; i < 10; i++) @@ -57,15 +60,12 @@ namespace osu.Game.Tests.Database { var exportStorage = storage.GetStorageForDirectory(@"exports"); - const string fullname = - "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; + int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length); + string expectedName = long_filename.Remove(expectedLength); - int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length); - string expectedName = fullname.Remove(expectedLength); + var item = new TestPathInfo(long_filename); - var item = new TestPathInfo(fullname); - - Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True); + Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True); exportItemAndAssert(item, exportStorage, expectedName); } @@ -74,15 +74,12 @@ namespace osu.Game.Tests.Database { var exportStorage = storage.GetStorageForDirectory(@"exports"); - const string fullname = - "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; + int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length); + string expectedName = long_filename.Remove(expectedLength); - int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length); - string expectedName = fullname.Remove(expectedLength); + var item = new TestPathInfo(long_filename); - var item = new TestPathInfo(fullname); - - Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True); + Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True); //Export multiple times for (int i = 0; i < 10; i++) @@ -123,8 +120,6 @@ namespace osu.Game.Tests.Database { } - public static int GetMaxPathLength() => MAX_FILENAME_LENGTH; - public string GetExtension() => FileExtension; protected override string FileExtension => ".ots"; From 4560ae6b026bd1ce575713ccab7d9052f73af40b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 13:39:31 +0900 Subject: [PATCH 324/516] Mark test as fixture --- osu.Game.Tests/Database/LegacyExporterTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index 114872bcf8..ec20028a2c 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -10,6 +10,7 @@ using osu.Game.Database; namespace osu.Game.Tests.Database { + [TestFixture] public class LegacyExporterTest { private TestLegacyExporter legacyExporter = null!; From 86d110e893cd2572377c575fc67e5260a1199e27 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 13:43:42 +0900 Subject: [PATCH 325/516] Simplify test storage by removing nested storage --- osu.Game.Tests/Database/LegacyExporterTest.cs | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index ec20028a2c..f38ffb7db6 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -29,20 +29,16 @@ namespace osu.Game.Tests.Database [Test] public void ExportFileWithNormalNameTest() { - var exportStorage = storage.GetStorageForDirectory(@"exports"); - const string filename = "normal file name"; var item = new TestPathInfo(filename); Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH)); - exportItemAndAssert(item, exportStorage, filename); + exportItemAndAssert(item, filename); } [Test] public void ExportFileWithNormalNameMultipleTimesTest() { - var exportStorage = storage.GetStorageForDirectory(@"exports"); - const string filename = "normal file name"; var item = new TestPathInfo(filename); @@ -52,29 +48,25 @@ namespace osu.Game.Tests.Database for (int i = 0; i < 10; i++) { string expectedFileName = i == 0 ? filename : $"{filename} ({i})"; - exportItemAndAssert(item, exportStorage, expectedFileName); + exportItemAndAssert(item, expectedFileName); } } [Test] public void ExportFileWithSuperLongNameTest() { - var exportStorage = storage.GetStorageForDirectory(@"exports"); - int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length); string expectedName = long_filename.Remove(expectedLength); var item = new TestPathInfo(long_filename); Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True); - exportItemAndAssert(item, exportStorage, expectedName); + exportItemAndAssert(item, expectedName); } [Test] public void ExportFileWithSuperLongNameMultipleTimesTest() { - var exportStorage = storage.GetStorageForDirectory(@"exports"); - int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length); string expectedName = long_filename.Remove(expectedLength); @@ -84,13 +76,13 @@ namespace osu.Game.Tests.Database //Export multiple times for (int i = 0; i < 10; i++) - exportItemAndAssert(item, exportStorage, expectedName); + exportItemAndAssert(item, expectedName); } - private void exportItemAndAssert(IHasNamedFiles item, Storage exportStorage, string expectedName) + private void exportItemAndAssert(IHasNamedFiles item, string expectedName) { Assert.DoesNotThrow(() => legacyExporter.Export(item)); - Assert.That(exportStorage.Exists($"{expectedName}{legacyExporter.GetExtension()}"), Is.True); + Assert.That(storage.Exists($"exports/{expectedName}{legacyExporter.GetExtension()}"), Is.True); } [TearDown] From 8ef3fb26e056b2c271a690be5539983f6d9d09b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 13:45:27 +0900 Subject: [PATCH 326/516] More constants and assert fixes --- osu.Game.Tests/Database/LegacyExporterTest.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index f38ffb7db6..b8dca6dc7b 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -16,6 +16,8 @@ namespace osu.Game.Tests.Database private TestLegacyExporter legacyExporter = null!; private TemporaryNativeStorage storage = null!; + private const string short_filename = "normal file name"; + private const string long_filename = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name"; @@ -29,25 +31,24 @@ namespace osu.Game.Tests.Database [Test] public void ExportFileWithNormalNameTest() { - const string filename = "normal file name"; - var item = new TestPathInfo(filename); + var item = new TestPathInfo(short_filename); Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH)); - exportItemAndAssert(item, filename); + + exportItemAndAssert(item, short_filename); } [Test] public void ExportFileWithNormalNameMultipleTimesTest() { - const string filename = "normal file name"; - var item = new TestPathInfo(filename); + var item = new TestPathInfo(short_filename); - Assert.That(item.Filename.Length < TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True); + Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH)); //Export multiple times for (int i = 0; i < 10; i++) { - string expectedFileName = i == 0 ? filename : $"{filename} ({i})"; + string expectedFileName = i == 0 ? short_filename : $"{short_filename} ({i})"; exportItemAndAssert(item, expectedFileName); } } @@ -60,7 +61,7 @@ namespace osu.Game.Tests.Database var item = new TestPathInfo(long_filename); - Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True); + Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH)); exportItemAndAssert(item, expectedName); } @@ -72,7 +73,7 @@ namespace osu.Game.Tests.Database var item = new TestPathInfo(long_filename); - Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True); + Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH)); //Export multiple times for (int i = 0; i < 10; i++) From 372b6b794cae69dc16a882f0caa3b91dcfef0491 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 13:45:43 +0900 Subject: [PATCH 327/516] I don't know what .ots is but let's not use random file extension that make no sense --- osu.Game.Tests/Database/LegacyExporterTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index b8dca6dc7b..c9aea80585 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -116,7 +116,7 @@ namespace osu.Game.Tests.Database public string GetExtension() => FileExtension; - protected override string FileExtension => ".ots"; + protected override string FileExtension => ".test"; } } } From 1a63ca9ecedd280d19b6dbdf48a311c5c56c1ce3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 14:18:05 +0900 Subject: [PATCH 328/516] Add xmldoc around `SkinComponentsContainerLookup` --- osu.Game/Skinning/SkinComponentsContainer.cs | 3 +++ osu.Game/Skinning/SkinComponentsContainerLookup.cs | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/osu.Game/Skinning/SkinComponentsContainer.cs b/osu.Game/Skinning/SkinComponentsContainer.cs index 2620b40729..7d7a4965f6 100644 --- a/osu.Game/Skinning/SkinComponentsContainer.cs +++ b/osu.Game/Skinning/SkinComponentsContainer.cs @@ -24,6 +24,9 @@ namespace osu.Game.Skinning { private Container? content; + /// + /// The lookup criteria which will be used to retrieve components from the active skin. + /// public SkinComponentsContainerLookup Lookup { get; } public IBindableList Components => components; diff --git a/osu.Game/Skinning/SkinComponentsContainerLookup.cs b/osu.Game/Skinning/SkinComponentsContainerLookup.cs index ac6e98b23a..b0b87f18b5 100644 --- a/osu.Game/Skinning/SkinComponentsContainerLookup.cs +++ b/osu.Game/Skinning/SkinComponentsContainerLookup.cs @@ -3,8 +3,14 @@ namespace osu.Game.Skinning { + /// + /// Represents a lookup of a collection of elements that make up a particular skinnable of the game. + /// public class SkinComponentsContainerLookup : ISkinComponentLookup { + /// + /// The target area / layer of the game for which skin components will be returned. + /// public readonly TargetArea Target; public SkinComponentsContainerLookup(TargetArea target) @@ -12,6 +18,9 @@ namespace osu.Game.Skinning Target = target; } + /// + /// Represents a particular area or part of a game screen whose layout can be customised using the skin editor. + /// public enum TargetArea { MainHUDComponents, From 4cc6664dc758bef146f85107d11d015580408626 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 19:20:06 +0900 Subject: [PATCH 329/516] Add optional ruleset identifier to `SkinComponentsContainerLookup` --- osu.Game/Screens/Play/HUDOverlay.cs | 18 ++++++++++-------- .../Skinning/SkinComponentsContainerLookup.cs | 9 ++++++++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index e41afd7722..37a96dc96c 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.EnumExtensions; @@ -26,6 +27,7 @@ using osu.Game.Screens.Play.HUD.JudgementCounter; using osu.Game.Skinning; using osuTK; using osu.Game.Localisation; +using osu.Game.Rulesets; namespace osu.Game.Screens.Play { @@ -100,6 +102,8 @@ namespace osu.Game.Screens.Play public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList mods, bool alwaysShowLeaderboard = true) { + SkinComponentsContainer rulesetComponents; + this.drawableRuleset = drawableRuleset; this.mods = mods; @@ -110,10 +114,8 @@ namespace osu.Game.Screens.Play CreateFailingLayer(), //Needs to be initialized before skinnable drawables. tally = new JudgementTally(), - mainComponents = new MainComponentsContainer - { - AlwaysPresent = true, - }, + mainComponents = new HUDComponentsContainer { AlwaysPresent = true, }, + rulesetComponents = new HUDComponentsContainer(drawableRuleset.Ruleset) { AlwaysPresent = true, }, topRightElements = new FillFlowContainer { Anchor = Anchor.TopRight, @@ -155,7 +157,7 @@ namespace osu.Game.Screens.Play clicksPerSecondCalculator = new ClicksPerSecondCalculator(), }; - hideTargets = new List { mainComponents, KeyCounter, topRightElements }; + hideTargets = new List { mainComponents, rulesetComponents, KeyCounter, topRightElements }; if (!alwaysShowLeaderboard) hideTargets.Add(LeaderboardFlow); @@ -390,15 +392,15 @@ namespace osu.Game.Screens.Play } } - private partial class MainComponentsContainer : SkinComponentsContainer + private partial class HUDComponentsContainer : SkinComponentsContainer { private Bindable scoringMode; [Resolved] private OsuConfigManager config { get; set; } - public MainComponentsContainer() - : base(new SkinComponentsContainerLookup(SkinComponentsContainerLookup.TargetArea.MainHUDComponents)) + public HUDComponentsContainer([CanBeNull] Ruleset ruleset = null) + : base(new SkinComponentsContainerLookup(SkinComponentsContainerLookup.TargetArea.MainHUDComponents, ruleset)) { RelativeSizeAxes = Axes.Both; } diff --git a/osu.Game/Skinning/SkinComponentsContainerLookup.cs b/osu.Game/Skinning/SkinComponentsContainerLookup.cs index b0b87f18b5..90384d7a4d 100644 --- a/osu.Game/Skinning/SkinComponentsContainerLookup.cs +++ b/osu.Game/Skinning/SkinComponentsContainerLookup.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Game.Rulesets; + namespace osu.Game.Skinning { /// @@ -13,9 +15,14 @@ namespace osu.Game.Skinning /// public readonly TargetArea Target; - public SkinComponentsContainerLookup(TargetArea target) + public readonly Ruleset? Ruleset; + + public string GetSerialisableIdentifier() => Ruleset?.ShortName ?? "global"; + + public SkinComponentsContainerLookup(TargetArea target, Ruleset? ruleset = null) { Target = target; + Ruleset = ruleset; } /// From 9685fb2114a8c93d032d71fc09824697a5fd07e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 19:25:55 +0900 Subject: [PATCH 330/516] Always return a non-null container for `SkinComponentsContainerLookup`s --- osu.Game/Skinning/LegacySkin.cs | 4 +--- osu.Game/Skinning/SkinComponentsContainer.cs | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 98d9f1d617..26c2fe2219 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -347,7 +347,7 @@ namespace osu.Game.Skinning switch (containerLookup.Target) { case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: - var skinnableTargetWrapper = new DefaultSkinComponentsContainer(container => + return new DefaultSkinComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); var accuracy = container.OfType().FirstOrDefault(); @@ -387,8 +387,6 @@ namespace osu.Game.Skinning new BarHitErrorMeter(), } }; - - return skinnableTargetWrapper; } return null; diff --git a/osu.Game/Skinning/SkinComponentsContainer.cs b/osu.Game/Skinning/SkinComponentsContainer.cs index 7d7a4965f6..d4e0b2e69b 100644 --- a/osu.Game/Skinning/SkinComponentsContainer.cs +++ b/osu.Game/Skinning/SkinComponentsContainer.cs @@ -66,10 +66,10 @@ namespace osu.Game.Skinning components.Clear(); ComponentsLoaded = false; - if (componentsContainer == null) - return; - - content = componentsContainer; + content = componentsContainer ?? new Container + { + RelativeSizeAxes = Axes.Both + }; cancellationSource?.Cancel(); cancellationSource = null; From 6b3652f5679e783ff139e8249fa6107fb985a6e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 19:58:04 +0900 Subject: [PATCH 331/516] Change serialisation format of skin layouts to allow more flexibility Also adds per-ruleset storage for each container type. --- .../Skins/SkinDeserialisationTest.cs | 22 +++---- osu.Game/Skinning/Skin.cs | 59 +++++++++++++------ osu.Game/Skinning/SkinImporter.cs | 2 +- osu.Game/Skinning/SkinLayoutInfo.cs | 33 +++++++++++ 4 files changed, 85 insertions(+), 31 deletions(-) create mode 100644 osu.Game/Skinning/SkinLayoutInfo.cs diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 5d7cbad46d..30b534869f 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Skins { var skin = new TestSkin(new SkinInfo(), null, storage); - foreach (var target in skin.DrawableComponentInfo) + foreach (var target in skin.LayoutInfos) { foreach (var info in target.Value) instantiatedTypes.Add(info.Type); @@ -87,8 +87,8 @@ namespace osu.Game.Tests.Skins { var skin = new TestSkin(new SkinInfo(), null, storage); - Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); - Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(9)); + Assert.That(skin.LayoutInfos, Has.Count.EqualTo(2)); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(9)); } } @@ -100,11 +100,11 @@ namespace osu.Game.Tests.Skins { var skin = new TestSkin(new SkinInfo(), null, storage); - Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); - Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(6)); - Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.SongSelect], Has.Length.EqualTo(1)); + Assert.That(skin.LayoutInfos, Has.Count.EqualTo(2)); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(6)); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.SongSelect], Has.Length.EqualTo(1)); - var skinnableInfo = skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.SongSelect].First(); + var skinnableInfo = skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.SongSelect].First(); Assert.That(skinnableInfo.Type, Is.EqualTo(typeof(SkinnableSprite))); Assert.That(skinnableInfo.Settings.First().Key, Is.EqualTo("sprite_name")); @@ -115,10 +115,10 @@ namespace osu.Game.Tests.Skins using (var storage = new ZipArchiveReader(stream)) { var skin = new TestSkin(new SkinInfo(), null, storage); - Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(8)); - Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); - Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); - Assert.That(skin.DrawableComponentInfo[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(8)); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); } } diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index f261937012..b55ddf250a 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -37,9 +37,10 @@ namespace osu.Game.Skinning public SkinConfiguration Configuration { get; set; } - public IDictionary DrawableComponentInfo => drawableComponentInfo; + public IDictionary LayoutInfos => layoutInfos; - private readonly Dictionary drawableComponentInfo = new Dictionary(); + private readonly Dictionary layoutInfos = + new Dictionary(); public abstract ISample? GetSample(ISampleInfo sampleInfo); @@ -113,18 +114,37 @@ namespace osu.Game.Skinning { string jsonContent = Encoding.UTF8.GetString(bytes); - // handle namespace changes... + SkinLayoutInfo? layoutInfo = null; - // can be removed 2023-01-31 - jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.SongProgress", @"osu.Game.Screens.Play.HUD.DefaultSongProgress"); - jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.LegacyComboCounter", @"osu.Game.Skinning.LegacyComboCounter"); + try + { + // First attempt to deserialise using the new SkinLayoutInfo format + layoutInfo = JsonConvert.DeserializeObject(jsonContent); + } + catch + { + } - var deserializedContent = JsonConvert.DeserializeObject>(jsonContent); + // if that fails, attempt to deserialise using the old naked list. + if (layoutInfo == null) + { + // handle namespace changes... + // can be removed 2023-01-31 + jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.SongProgress", @"osu.Game.Screens.Play.HUD.DefaultSongProgress"); + jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.LegacyComboCounter", @"osu.Game.Skinning.LegacyComboCounter"); - if (deserializedContent == null) - continue; + var deserializedContent = JsonConvert.DeserializeObject>(jsonContent); - DrawableComponentInfo[skinnableTarget] = deserializedContent.ToArray(); + if (deserializedContent == null) + continue; + + layoutInfo = new SkinLayoutInfo(); + layoutInfo.Update(null, deserializedContent.ToArray()); + + Logger.Log($"Ferrying {deserializedContent.Count()} components in {skinnableTarget} to global section of new {nameof(SkinLayoutInfo)} format"); + } + + LayoutInfos[skinnableTarget] = layoutInfo; } catch (Exception ex) { @@ -145,7 +165,7 @@ namespace osu.Game.Skinning /// The target container to reset. public void ResetDrawableTarget(SkinComponentsContainer targetContainer) { - DrawableComponentInfo.Remove(targetContainer.Lookup.Target); + LayoutInfos.Remove(targetContainer.Lookup.Target); } /// @@ -154,7 +174,10 @@ namespace osu.Game.Skinning /// The target container to serialise to this skin. public void UpdateDrawableTarget(SkinComponentsContainer targetContainer) { - DrawableComponentInfo[targetContainer.Lookup.Target] = ((ISerialisableDrawableContainer)targetContainer).CreateSerialisedInfo().ToArray(); + if (!LayoutInfos.TryGetValue(targetContainer.Lookup.Target, out var layoutInfo)) + layoutInfos[targetContainer.Lookup.Target] = layoutInfo = new SkinLayoutInfo(); + + layoutInfo.Update(targetContainer.Lookup.Ruleset, ((ISerialisableDrawableContainer)targetContainer).CreateSerialisedInfo().ToArray()); } public virtual Drawable? GetDrawableComponent(ISkinComponentLookup lookup) @@ -166,18 +189,16 @@ namespace osu.Game.Skinning return this.GetAnimation(sprite.LookupName, false, false); case SkinComponentsContainerLookup containerLookup: - if (!DrawableComponentInfo.TryGetValue(containerLookup.Target, out var skinnableInfo)) - return null; - var components = new List(); - - foreach (var i in skinnableInfo) - components.Add(i.CreateInstance()); + // It is important to return null if the user has not configured this yet. + // This allows skin transformers the opportunity to provide default components. + if (!LayoutInfos.TryGetValue(containerLookup.Target, out var layoutInfo)) return null; + if (!layoutInfo.TryGetDrawableInfo(containerLookup.Ruleset, out var drawableInfos)) return null; return new Container { RelativeSizeAxes = Axes.Both, - Children = components, + ChildrenEnumerable = drawableInfos.Select(i => i.CreateInstance()) }; } diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index 8ce265719c..9e2e02876d 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -201,7 +201,7 @@ namespace osu.Game.Skinning } // Then serialise each of the drawable component groups into respective files. - foreach (var drawableInfo in skin.DrawableComponentInfo) + foreach (var drawableInfo in skin.LayoutInfos) { string json = JsonConvert.SerializeObject(drawableInfo.Value, new JsonSerializerSettings { Formatting = Formatting.Indented }); diff --git a/osu.Game/Skinning/SkinLayoutInfo.cs b/osu.Game/Skinning/SkinLayoutInfo.cs new file mode 100644 index 0000000000..06fb127d44 --- /dev/null +++ b/osu.Game/Skinning/SkinLayoutInfo.cs @@ -0,0 +1,33 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; +using osu.Game.Rulesets; + +namespace osu.Game.Skinning +{ + /// + /// A serialisable model describing layout of a . + /// May contain multiple configurations for different rulesets, each of which should manifest their own as required. + /// + [Serializable] + public class SkinLayoutInfo + { + private const string global_identifier = "global"; + + [JsonProperty] + public Dictionary DrawableInfo { get; set; } = new Dictionary(); + + public bool TryGetDrawableInfo(Ruleset? ruleset, [NotNullWhen(true)] out SerialisedDrawableInfo[]? components) => + DrawableInfo.TryGetValue(ruleset?.ShortName ?? global_identifier, out components); + + public void Reset(Ruleset? ruleset) => + DrawableInfo.Remove(ruleset?.ShortName ?? global_identifier); + + public void Update(Ruleset? ruleset, SerialisedDrawableInfo[] components) => + DrawableInfo[ruleset?.ShortName ?? global_identifier] = components; + } +} From 979377437775a89ce568cbdf8fb77b211e8738aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 16:22:41 +0900 Subject: [PATCH 332/516] Update `SkinDeserialisationTest` to work with new serialisation structure --- .../Skins/SkinDeserialisationTest.cs | 18 +++++++++--------- osu.Game/Skinning/SkinLayoutInfo.cs | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 30b534869f..04b8c6dd4e 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -68,7 +68,7 @@ namespace osu.Game.Tests.Skins foreach (var target in skin.LayoutInfos) { - foreach (var info in target.Value) + foreach (var info in target.Value.AllDrawables) instantiatedTypes.Add(info.Type); } } @@ -88,7 +88,7 @@ namespace osu.Game.Tests.Skins var skin = new TestSkin(new SkinInfo(), null, storage); Assert.That(skin.LayoutInfos, Has.Count.EqualTo(2)); - Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(9)); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].AllDrawables.ToArray(), Has.Length.EqualTo(9)); } } @@ -101,10 +101,10 @@ namespace osu.Game.Tests.Skins var skin = new TestSkin(new SkinInfo(), null, storage); Assert.That(skin.LayoutInfos, Has.Count.EqualTo(2)); - Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(6)); - Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.SongSelect], Has.Length.EqualTo(1)); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].AllDrawables.ToArray(), Has.Length.EqualTo(6)); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.SongSelect].AllDrawables.ToArray(), Has.Length.EqualTo(1)); - var skinnableInfo = skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.SongSelect].First(); + var skinnableInfo = skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.SongSelect].AllDrawables.First(); Assert.That(skinnableInfo.Type, Is.EqualTo(typeof(SkinnableSprite))); Assert.That(skinnableInfo.Settings.First().Key, Is.EqualTo("sprite_name")); @@ -115,10 +115,10 @@ namespace osu.Game.Tests.Skins using (var storage = new ZipArchiveReader(stream)) { var skin = new TestSkin(new SkinInfo(), null, storage); - Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents], Has.Length.EqualTo(8)); - Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); - Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); - Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].AllDrawables.ToArray(), Has.Length.EqualTo(8)); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].AllDrawables.Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].AllDrawables.Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); + Assert.That(skin.LayoutInfos[SkinComponentsContainerLookup.TargetArea.MainHUDComponents].AllDrawables.Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); } } diff --git a/osu.Game/Skinning/SkinLayoutInfo.cs b/osu.Game/Skinning/SkinLayoutInfo.cs index 06fb127d44..e069fe2457 100644 --- a/osu.Game/Skinning/SkinLayoutInfo.cs +++ b/osu.Game/Skinning/SkinLayoutInfo.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Linq; using Newtonsoft.Json; using osu.Game.Rulesets; @@ -18,6 +19,8 @@ namespace osu.Game.Skinning { private const string global_identifier = "global"; + public IEnumerable AllDrawables => DrawableInfo.Values.SelectMany(v => v); + [JsonProperty] public Dictionary DrawableInfo { get; set; } = new Dictionary(); From 16d94b4ea2ac405a5988b6ebf11c5a7192a0d79f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 17:51:52 +0900 Subject: [PATCH 333/516] Improve visuals of skin blueprint --- osu.Game/Overlays/SkinEditor/SkinBlueprint.cs | 69 ++++++++++++------- .../Compose/Components/SelectionHandler.cs | 7 +- 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs index 55ea362873..fedb1ac8e0 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs @@ -5,12 +5,15 @@ using System; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Edit; +using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Skinning; using osuTK; using osuTK.Graphics; @@ -29,35 +32,36 @@ namespace osu.Game.Overlays.SkinEditor protected override bool ShouldBeAlive => drawable.IsAlive && Item.IsPresent; - [Resolved] - private OsuColour colours { get; set; } = null!; - public SkinBlueprint(ISerialisableDrawable component) : base(component) { } [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colours) { InternalChildren = new Drawable[] { box = new Container { + Padding = new MarginPadding(-SkinSelectionHandler.INFLATE_SIZE), Children = new Drawable[] { outlineBox = new Container { RelativeSizeAxes = Axes.Both, Masking = true, - BorderThickness = 3, - BorderColour = Color4.White, + CornerRadius = 3, + BorderThickness = SelectionBox.BORDER_RADIUS / 2, + BorderColour = ColourInfo.GradientVertical(colours.Pink4.Darken(0.4f), colours.Pink4), Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, - Alpha = 0f, + Blending = BlendingParameters.Additive, + Alpha = 0.2f, + Colour = ColourInfo.GradientVertical(colours.Pink2, colours.Pink4), AlwaysPresent = true, }, } @@ -100,9 +104,6 @@ namespace osu.Game.Overlays.SkinEditor private void updateSelectedState() { - outlineBox.FadeColour(colours.Pink.Opacity(IsSelected ? 1 : 0.5f), 200, Easing.OutQuint); - outlineBox.Child.FadeTo(IsSelected ? 0.2f : 0, 200, Easing.OutQuint); - anchorOriginVisualiser.FadeTo(IsSelected ? 1 : 0, 200, Easing.OutQuint); } @@ -134,39 +135,47 @@ namespace osu.Game.Overlays.SkinEditor { private readonly Drawable drawable; - private readonly Box originBox; + private Drawable originBox = null!; - private readonly Box anchorBox; - private readonly Box anchorLine; + private Drawable anchorBox = null!; + private Drawable anchorLine = null!; public AnchorOriginVisualiser(Drawable drawable) { this.drawable = drawable; + } - InternalChildren = new Drawable[] + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Color4 anchorColour = colours.Red1; + Color4 originColour = colours.Red3; + + InternalChildren = new[] { - anchorLine = new Box + anchorLine = new Circle { - Height = 2, + Height = 3f, Origin = Anchor.CentreLeft, - Colour = Color4.Yellow, - EdgeSmoothness = Vector2.One + Colour = ColourInfo.GradientHorizontal(originColour.Opacity(0.5f), originColour), }, - originBox = new Box + originBox = new Circle { - Colour = Color4.Red, + Colour = originColour, Origin = Anchor.Centre, - Size = new Vector2(5), + Size = new Vector2(7), }, - anchorBox = new Box + anchorBox = new Circle { - Colour = Color4.Red, + Colour = anchorColour, Origin = Anchor.Centre, - Size = new Vector2(5), + Size = new Vector2(10), }, }; } + private Vector2? anchorPosition; + protected override void Update() { base.Update(); @@ -174,8 +183,18 @@ namespace osu.Game.Overlays.SkinEditor if (drawable.Parent == null) return; + var newAnchor = drawable.Parent.ToSpaceOfOtherDrawable(drawable.AnchorPosition, this); + + anchorPosition ??= newAnchor; + + anchorPosition = + new Vector2( + (float)Interpolation.DampContinuously(anchorPosition.Value.X, newAnchor.X, 25, Clock.ElapsedFrameTime), + (float)Interpolation.DampContinuously(anchorPosition.Value.Y, newAnchor.Y, 25, Clock.ElapsedFrameTime) + ); + originBox.Position = drawable.ToSpaceOfOtherDrawable(drawable.OriginPosition, this); - anchorBox.Position = drawable.Parent.ToSpaceOfOtherDrawable(drawable.AnchorPosition, this); + anchorBox.Position = anchorPosition.Value; var point1 = ToLocalSpace(anchorBox.ScreenSpaceDrawQuad.Centre); var point2 = ToLocalSpace(originBox.ScreenSpaceDrawQuad.Centre); diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index a0ac99fec2..9e4fb26688 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -32,6 +32,11 @@ namespace osu.Game.Screens.Edit.Compose.Components /// public abstract partial class SelectionHandler : CompositeDrawable, IKeyBindingHandler, IKeyBindingHandler, IHasContextMenu { + /// + /// How much padding around the selection area is added. + /// + public const float INFLATE_SIZE = 5; + /// /// The currently selected blueprints. /// Should be used when operations are dealing directly with the visible blueprints. @@ -346,7 +351,7 @@ namespace osu.Game.Screens.Edit.Compose.Components for (int i = 1; i < selectedBlueprints.Count; i++) selectionRect = RectangleF.Union(selectionRect, ToLocalSpace(selectedBlueprints[i].SelectionQuad).AABBFloat); - selectionRect = selectionRect.Inflate(5f); + selectionRect = selectionRect.Inflate(INFLATE_SIZE); SelectionBox.Position = selectionRect.Location; SelectionBox.Size = selectionRect.Size; From 6c61c5f4a871b68458487a348aef07c33147468d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 18:17:35 +0900 Subject: [PATCH 334/516] Fix selection on the edge of blueprints (in the new inflation area) failing --- osu.Game/Overlays/SkinEditor/SkinBlueprint.cs | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs index fedb1ac8e0..0ee9f35a62 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs @@ -32,6 +32,18 @@ namespace osu.Game.Overlays.SkinEditor protected override bool ShouldBeAlive => drawable.IsAlive && Item.IsPresent; + private Quad drawableQuad; + + public override Quad ScreenSpaceDrawQuad => drawableQuad; + public override Quad SelectionQuad => drawable.ScreenSpaceDrawQuad; + + public override bool Contains(Vector2 screenSpacePos) => drawableQuad.Contains(screenSpacePos); + + public override Vector2 ScreenSpaceSelectionPoint => drawable.ToScreenSpace(drawable.OriginPosition); + + protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => + drawableQuad.Contains(screenSpacePos); + public SkinBlueprint(ISerialisableDrawable component) : base(component) { @@ -44,7 +56,6 @@ namespace osu.Game.Overlays.SkinEditor { box = new Container { - Padding = new MarginPadding(-SkinSelectionHandler.INFLATE_SIZE), Children = new Drawable[] { outlineBox = new Container @@ -107,28 +118,21 @@ namespace osu.Game.Overlays.SkinEditor anchorOriginVisualiser.FadeTo(IsSelected ? 1 : 0, 200, Easing.OutQuint); } - private Quad drawableQuad; - - public override Quad ScreenSpaceDrawQuad => drawableQuad; - protected override void Update() { base.Update(); - drawableQuad = drawable.ScreenSpaceDrawQuad; - var quad = ToLocalSpace(drawable.ScreenSpaceDrawQuad); + drawableQuad = drawable.ToScreenSpace( + drawable.DrawRectangle + .Inflate(SkinSelectionHandler.INFLATE_SIZE)); - box.Position = drawable.ToSpaceOfOtherDrawable(Vector2.Zero, this); - box.Size = quad.Size; + var localSpaceQuad = ToLocalSpace(drawableQuad); + + box.Position = localSpaceQuad.TopLeft; + box.Size = localSpaceQuad.Size; box.Rotation = drawable.Rotation; box.Scale = new Vector2(MathF.Sign(drawable.Scale.X), MathF.Sign(drawable.Scale.Y)); } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => drawable.ReceivePositionalInputAt(screenSpacePos); - - public override Vector2 ScreenSpaceSelectionPoint => drawable.ToScreenSpace(drawable.OriginPosition); - - public override Quad SelectionQuad => drawable.ScreenSpaceDrawQuad; } internal partial class AnchorOriginVisualiser : CompositeDrawable From ffb99364b95950272073499196c32f014540b4d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 18:22:10 +0900 Subject: [PATCH 335/516] Ensure skin default component layouts only apply to global layout for now --- osu.Game/Skinning/ArgonSkin.cs | 4 ++++ osu.Game/Skinning/LegacySkin.cs | 4 ++++ osu.Game/Skinning/TrianglesSkin.cs | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 737b222b9d..a9b26f13e8 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -91,6 +91,10 @@ namespace osu.Game.Skinning switch (lookup) { case SkinComponentsContainerLookup containerLookup: + // Only handle global level defaults for now. + if (containerLookup.Ruleset != null) + return null; + switch (containerLookup.Target) { case SkinComponentsContainerLookup.TargetArea.SongSelect: diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 26c2fe2219..e46eaf90c1 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -344,6 +344,10 @@ namespace osu.Game.Skinning switch (lookup) { case SkinComponentsContainerLookup containerLookup: + // Only handle global level defaults for now. + if (containerLookup.Ruleset != null) + return null; + switch (containerLookup.Target) { case SkinComponentsContainerLookup.TargetArea.MainHUDComponents: diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 12cdb71744..e88b827807 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -69,6 +69,10 @@ namespace osu.Game.Skinning switch (lookup) { case SkinComponentsContainerLookup containerLookup: + // Only handle global level defaults for now. + if (containerLookup.Ruleset != null) + return null; + switch (containerLookup.Target) { case SkinComponentsContainerLookup.TargetArea.SongSelect: From 2267aa1ac280fc48dba549429eb56fddfce78a8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Feb 2023 20:01:38 +0900 Subject: [PATCH 336/516] Add ability to retrieve serialisable drawables for specific rulesets --- osu.Game/Skinning/SerialisedDrawableInfo.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Skinning/SerialisedDrawableInfo.cs b/osu.Game/Skinning/SerialisedDrawableInfo.cs index 12f6d3ac7e..686fff1e8b 100644 --- a/osu.Game/Skinning/SerialisedDrawableInfo.cs +++ b/osu.Game/Skinning/SerialisedDrawableInfo.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Extensions; +using osu.Game.Rulesets; using osuTK; namespace osu.Game.Skinning @@ -100,13 +101,18 @@ namespace osu.Game.Skinning } } - public static Type[] GetAllAvailableDrawables() + /// + /// Retrieve all types available which support serialisation. + /// + /// The ruleset to filter results to. If null, global components will be returned instead. + public static Type[] GetAllAvailableDrawables(RulesetInfo? ruleset = null) { - return typeof(OsuGame).Assembly.GetTypes() - .Where(t => !t.IsInterface && !t.IsAbstract) - .Where(t => typeof(ISerialisableDrawable).IsAssignableFrom(t)) - .OrderBy(t => t.Name) - .ToArray(); + return (ruleset?.CreateInstance().GetType() ?? typeof(OsuGame)) + .Assembly.GetTypes() + .Where(t => !t.IsInterface && !t.IsAbstract) + .Where(t => typeof(ISerialisableDrawable).IsAssignableFrom(t)) + .OrderBy(t => t.Name) + .ToArray(); } } } From 675e5b81f3799bc1580fed534e9c83fdf2785824 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 18:22:30 +0900 Subject: [PATCH 337/516] Fix `SkinnableLighting` showing up as a user placeable component --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs | 2 +- osu.Game/Skinning/SerialisedDrawableInfo.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index b4004ff572..76ae7340ff 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { public partial class DrawableOsuJudgement : DrawableJudgement { - protected SkinnableLighting Lighting { get; private set; } + internal SkinnableLighting Lighting { get; private set; } [Resolved] private OsuConfigManager config { get; set; } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs index 68b61f9b2b..b39b9c4c54 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public partial class SkinnableLighting : SkinnableSprite + internal partial class SkinnableLighting : SkinnableSprite { private DrawableHitObject targetObject; private JudgementResult targetResult; diff --git a/osu.Game/Skinning/SerialisedDrawableInfo.cs b/osu.Game/Skinning/SerialisedDrawableInfo.cs index 686fff1e8b..c3248fb686 100644 --- a/osu.Game/Skinning/SerialisedDrawableInfo.cs +++ b/osu.Game/Skinning/SerialisedDrawableInfo.cs @@ -109,7 +109,7 @@ namespace osu.Game.Skinning { return (ruleset?.CreateInstance().GetType() ?? typeof(OsuGame)) .Assembly.GetTypes() - .Where(t => !t.IsInterface && !t.IsAbstract) + .Where(t => !t.IsInterface && !t.IsAbstract && t.IsPublic) .Where(t => typeof(ISerialisableDrawable).IsAssignableFrom(t)) .OrderBy(t => t.Name) .ToArray(); From 209d41ee9dcd43b44be2e17659ee5bc3157cad6f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 15:00:57 +0900 Subject: [PATCH 338/516] Use `RulesetInfo` instead of `Ruleset` in skin components lookup --- osu.Game/Screens/Play/HUDOverlay.cs | 4 ++-- osu.Game/Skinning/SkinComponentsContainerLookup.cs | 4 ++-- osu.Game/Skinning/SkinLayoutInfo.cs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 37a96dc96c..1fdeaba1e6 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -115,7 +115,7 @@ namespace osu.Game.Screens.Play //Needs to be initialized before skinnable drawables. tally = new JudgementTally(), mainComponents = new HUDComponentsContainer { AlwaysPresent = true, }, - rulesetComponents = new HUDComponentsContainer(drawableRuleset.Ruleset) { AlwaysPresent = true, }, + rulesetComponents = new HUDComponentsContainer(drawableRuleset.Ruleset.RulesetInfo) { AlwaysPresent = true, }, topRightElements = new FillFlowContainer { Anchor = Anchor.TopRight, @@ -399,7 +399,7 @@ namespace osu.Game.Screens.Play [Resolved] private OsuConfigManager config { get; set; } - public HUDComponentsContainer([CanBeNull] Ruleset ruleset = null) + public HUDComponentsContainer([CanBeNull] RulesetInfo ruleset = null) : base(new SkinComponentsContainerLookup(SkinComponentsContainerLookup.TargetArea.MainHUDComponents, ruleset)) { RelativeSizeAxes = Axes.Both; diff --git a/osu.Game/Skinning/SkinComponentsContainerLookup.cs b/osu.Game/Skinning/SkinComponentsContainerLookup.cs index 90384d7a4d..f6c462ddaa 100644 --- a/osu.Game/Skinning/SkinComponentsContainerLookup.cs +++ b/osu.Game/Skinning/SkinComponentsContainerLookup.cs @@ -15,11 +15,11 @@ namespace osu.Game.Skinning /// public readonly TargetArea Target; - public readonly Ruleset? Ruleset; + public readonly RulesetInfo? Ruleset; public string GetSerialisableIdentifier() => Ruleset?.ShortName ?? "global"; - public SkinComponentsContainerLookup(TargetArea target, Ruleset? ruleset = null) + public SkinComponentsContainerLookup(TargetArea target, RulesetInfo? ruleset = null) { Target = target; Ruleset = ruleset; diff --git a/osu.Game/Skinning/SkinLayoutInfo.cs b/osu.Game/Skinning/SkinLayoutInfo.cs index e069fe2457..ff27a47223 100644 --- a/osu.Game/Skinning/SkinLayoutInfo.cs +++ b/osu.Game/Skinning/SkinLayoutInfo.cs @@ -24,13 +24,13 @@ namespace osu.Game.Skinning [JsonProperty] public Dictionary DrawableInfo { get; set; } = new Dictionary(); - public bool TryGetDrawableInfo(Ruleset? ruleset, [NotNullWhen(true)] out SerialisedDrawableInfo[]? components) => + public bool TryGetDrawableInfo(RulesetInfo? ruleset, [NotNullWhen(true)] out SerialisedDrawableInfo[]? components) => DrawableInfo.TryGetValue(ruleset?.ShortName ?? global_identifier, out components); - public void Reset(Ruleset? ruleset) => + public void Reset(RulesetInfo? ruleset) => DrawableInfo.Remove(ruleset?.ShortName ?? global_identifier); - public void Update(Ruleset? ruleset, SerialisedDrawableInfo[] components) => + public void Update(RulesetInfo? ruleset, SerialisedDrawableInfo[] components) => DrawableInfo[ruleset?.ShortName ?? global_identifier] = components; } } From 19d5293ad1f69a483a7d87df7feecad425589344 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 18:59:31 +0900 Subject: [PATCH 339/516] Change early return to also find the earliest nested object --- osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index de16cc05c7..e1c03e49e3 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -89,9 +89,9 @@ namespace osu.Game.Rulesets.UI .Where(e => e.Result?.HasResult != true).MinBy(e => e.HitObject.StartTime); if (fallbackObject != null) - return fallbackObject.HitObject; + return getEarliestNestedObject(fallbackObject.HitObject); - // In the case there are no unjudged objects, the last hit object should be used instead. + // In the case there are no non-judged objects, the last hit object should be used instead. fallbackObject ??= hitObjectContainer.Entries.LastOrDefault(); } From 814080d9823460fbf93c15ed9bcc1bf141b75308 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 17:56:41 +0900 Subject: [PATCH 340/516] Only show blueprint labels when hovering or selected --- osu.Game/Overlays/SkinEditor/SkinBlueprint.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs index 893bc4bac2..9d2c8368e7 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Edit; @@ -25,6 +26,8 @@ namespace osu.Game.Overlays.SkinEditor private AnchorOriginVisualiser anchorOriginVisualiser = null!; + private OsuSpriteText label = null!; + private Drawable drawable => (Drawable)Item; protected override bool ShouldBeAlive => drawable.IsAlive && Item.IsPresent; @@ -62,7 +65,7 @@ namespace osu.Game.Overlays.SkinEditor }, } }, - new OsuSpriteText + label = new OsuSpriteText { Text = Item.GetType().Name, Font = OsuFont.Default.With(size: 10, weight: FontWeight.Bold), @@ -86,6 +89,18 @@ namespace osu.Game.Overlays.SkinEditor this.FadeInFromZero(200, Easing.OutQuint); } + protected override bool OnHover(HoverEvent e) + { + updateSelectedState(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateSelectedState(); + base.OnHoverLost(e); + } + protected override void OnSelected() { // base logic hides selected blueprints when not selected, but skin blueprints don't do that. @@ -104,6 +119,7 @@ namespace osu.Game.Overlays.SkinEditor outlineBox.Child.FadeTo(IsSelected ? 0.2f : 0, 200, Easing.OutQuint); anchorOriginVisualiser.FadeTo(IsSelected ? 1 : 0, 200, Easing.OutQuint); + label.FadeTo(IsSelected || IsHovered ? 1 : 0, 200, Easing.OutQuint); } private Quad drawableQuad; From 5ed038fbb3b0cddf07a460223312ea52c2ca3d1c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 16:44:48 +0900 Subject: [PATCH 341/516] Improve the feel of hovering toolbox component items --- .../SkinEditor/SkinComponentToolbox.cs | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index 28ceaf09fc..624841a3bc 100644 --- a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -2,12 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Logging; -using osu.Game.Graphics; +using osu.Framework.Threading; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; @@ -65,7 +66,8 @@ namespace osu.Game.Overlays.SkinEditor fill.Add(new ToolboxComponentButton(instance, target) { - RequestPlacement = t => RequestPlacement?.Invoke(t) + RequestPlacement = t => RequestPlacement?.Invoke(t), + Expanding = contractOtherButtons, }); } catch (DependencyNotRegisteredException) @@ -79,15 +81,29 @@ namespace osu.Game.Overlays.SkinEditor } } + private void contractOtherButtons(ToolboxComponentButton obj) + { + foreach (var b in fill.OfType()) + { + if (b == obj) + continue; + + b.Contract(); + } + } + public partial class ToolboxComponentButton : OsuButton { public Action? RequestPlacement; + public Action? Expanding; private readonly Drawable component; private readonly CompositeDrawable? dependencySource; private Container innerContainer = null!; + private ScheduledDelegate? expandContractAction; + private const float contracted_size = 60; private const float expanded_size = 120; @@ -102,20 +118,44 @@ namespace osu.Game.Overlays.SkinEditor Height = contracted_size; } + private const double animation_duration = 500; + protected override bool OnHover(HoverEvent e) { - this.Delay(300).ResizeHeightTo(expanded_size, 500, Easing.OutQuint); + expandContractAction = Scheduler.AddDelayed(() => + { + this.ResizeHeightTo(expanded_size, animation_duration, Easing.OutQuint); + Expanding?.Invoke(this); + }, 100); + return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { base.OnHoverLost(e); - this.ResizeHeightTo(contracted_size, 500, Easing.OutQuint); + + expandContractAction?.Cancel(); + // If no other component is selected for too long, force a contract. + // Otherwise we will generally contract when Contract() is called from outside. + expandContractAction = Scheduler.AddDelayed(Contract, 1000); + } + + public void Contract() + { + // Cheap debouncing to avoid stacking animations. + // The only place this is nulled is at the end of this method. + if (expandContractAction == null) + return; + + this.ResizeHeightTo(contracted_size, animation_duration, Easing.OutQuint); + + expandContractAction?.Cancel(); + expandContractAction = null; } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, OsuColour colours) + private void load(OverlayColourProvider colourProvider) { BackgroundColour = colourProvider.Background3; From a01c3090e4b05885847da579a1cc2a1d02a5628c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 18:40:32 +0900 Subject: [PATCH 342/516] Fix tests which rely on `HUDOverlay`'s `DrawableRuleset` being nullable --- osu.Game/Screens/Play/HUDOverlay.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 1fdeaba1e6..c8d06b82e8 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -102,20 +102,22 @@ namespace osu.Game.Screens.Play public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList mods, bool alwaysShowLeaderboard = true) { - SkinComponentsContainer rulesetComponents; + Drawable rulesetComponents; this.drawableRuleset = drawableRuleset; this.mods = mods; RelativeSizeAxes = Axes.Both; - Children = new Drawable[] + Children = new[] { CreateFailingLayer(), //Needs to be initialized before skinnable drawables. tally = new JudgementTally(), mainComponents = new HUDComponentsContainer { AlwaysPresent = true, }, - rulesetComponents = new HUDComponentsContainer(drawableRuleset.Ruleset.RulesetInfo) { AlwaysPresent = true, }, + rulesetComponents = drawableRuleset != null + ? new HUDComponentsContainer(drawableRuleset.Ruleset.RulesetInfo) { AlwaysPresent = true, } + : Empty(), topRightElements = new FillFlowContainer { Anchor = Anchor.TopRight, From c03b6cec2317c939091cce7880a3d32282d1192b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 15:01:11 +0900 Subject: [PATCH 343/516] Add `IEquatable` and `ToString` support to `SkinComponentsContainerLookup` --- .../Skinning/SkinComponentsContainerLookup.cs | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinComponentsContainerLookup.cs b/osu.Game/Skinning/SkinComponentsContainerLookup.cs index f6c462ddaa..9256c1b547 100644 --- a/osu.Game/Skinning/SkinComponentsContainerLookup.cs +++ b/osu.Game/Skinning/SkinComponentsContainerLookup.cs @@ -1,6 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.ComponentModel; +using osu.Framework.Extensions; using osu.Game.Rulesets; namespace osu.Game.Skinning @@ -8,7 +11,7 @@ namespace osu.Game.Skinning /// /// Represents a lookup of a collection of elements that make up a particular skinnable of the game. /// - public class SkinComponentsContainerLookup : ISkinComponentLookup + public class SkinComponentsContainerLookup : ISkinComponentLookup, IEquatable { /// /// The target area / layer of the game for which skin components will be returned. @@ -25,12 +28,44 @@ namespace osu.Game.Skinning Ruleset = ruleset; } + public override string ToString() + { + if (Ruleset == null) return Target.GetDescription(); + + return $"{Target.GetDescription()} (\"{Ruleset.Name}\" only)"; + } + + public bool Equals(SkinComponentsContainerLookup? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return Target == other.Target && (ReferenceEquals(Ruleset, other.Ruleset) || Ruleset?.Equals(other.Ruleset) == true); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + + return Equals((SkinComponentsContainerLookup)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine((int)Target, Ruleset); + } + /// /// Represents a particular area or part of a game screen whose layout can be customised using the skin editor. /// public enum TargetArea { + [Description("HUD")] MainHUDComponents, + + [Description("Song select")] SongSelect } } From ba5a87ca048bfcf78c82071cf1eda951e31d0048 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 15:02:42 +0900 Subject: [PATCH 344/516] Add basic target layer selection in skin editor --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 29 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 133ec10202..fccddac84f 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -24,6 +24,7 @@ using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays.OSD; +using osu.Game.Overlays.Settings; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Edit.Components.Menus; @@ -66,6 +67,8 @@ namespace osu.Game.Overlays.SkinEditor [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + private readonly Bindable selectedTarget = new Bindable(); + private bool hasBegunMutating; private Container? content; @@ -271,9 +274,27 @@ namespace osu.Game.Overlays.SkinEditor content.Child = new SkinBlueprintContainer(targetScreen); - componentsSidebar.Child = new SkinComponentToolbox(getFirstTarget() as CompositeDrawable) + selectedTarget.Default = getFirstTarget()?.Lookup; + if (!availableTargets.Any(t => t.Lookup.Equals(selectedTarget.Value))) + selectedTarget.Value = getFirstTarget()?.Lookup; + + componentsSidebar.Children = new[] { - RequestPlacement = placeComponent + new EditorSidebarSection("Current working layer") + { + Children = new Drawable[] + { + new SettingsDropdown + { + Items = availableTargets.Select(t => t.Lookup), + Current = selectedTarget, + } + } + }, + new SkinComponentToolbox(getFirstTarget()) + { + RequestPlacement = placeComponent + } }; } } @@ -341,9 +362,9 @@ namespace osu.Game.Overlays.SkinEditor private IEnumerable availableTargets => targetScreen.ChildrenOfType(); - private ISerialisableDrawableContainer? getFirstTarget() => availableTargets.FirstOrDefault(); + private SkinComponentsContainer? getFirstTarget() => availableTargets.FirstOrDefault(); - private ISerialisableDrawableContainer? getTarget(SkinComponentsContainerLookup.TargetArea target) + private SkinComponentsContainer? getTarget(SkinComponentsContainerLookup.TargetArea target) { return availableTargets.FirstOrDefault(c => c.Lookup.Target == target); } From 00fcee0c5a98565122a8ac48fafaf7145bf76dd7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 15:50:48 +0900 Subject: [PATCH 345/516] Add per-ruleset component toolbox and placement support --- .../SkinEditor/SkinComponentToolbox.cs | 9 ++-- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 49 ++++++++++++++----- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index cd9f7cc935..de2bb46611 100644 --- a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -21,12 +22,12 @@ namespace osu.Game.Overlays.SkinEditor { public Action? RequestPlacement; - private readonly CompositeDrawable? target; + private readonly SkinComponentsContainer? target; private FillFlowContainer fill = null!; - public SkinComponentToolbox(CompositeDrawable? target = null) - : base(SkinEditorStrings.Components) + public SkinComponentToolbox(SkinComponentsContainer? target = null) + : base(target?.Lookup.Ruleset == null ? SkinEditorStrings.Components : LocalisableString.Interpolate($"{SkinEditorStrings.Components} ({target.Lookup.Ruleset.Name})")) { this.target = target; } @@ -49,7 +50,7 @@ namespace osu.Game.Overlays.SkinEditor { fill.Clear(); - var skinnableTypes = SerialisedDrawableInfo.GetAllAvailableDrawables(); + var skinnableTypes = SerialisedDrawableInfo.GetAllAvailableDrawables(target?.Lookup.Ruleset); foreach (var type in skinnableTypes) attemptAddComponent(type); } diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index fccddac84f..b3813b4d2c 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -221,6 +221,8 @@ namespace osu.Game.Overlays.SkinEditor }, true); SelectedComponents.BindCollectionChanged((_, _) => Scheduler.AddOnce(populateSettings), true); + + selectedTarget.BindValueChanged(targetChanged, true); } public bool OnPressed(KeyBindingPressEvent e) @@ -274,10 +276,6 @@ namespace osu.Game.Overlays.SkinEditor content.Child = new SkinBlueprintContainer(targetScreen); - selectedTarget.Default = getFirstTarget()?.Lookup; - if (!availableTargets.Any(t => t.Lookup.Equals(selectedTarget.Value))) - selectedTarget.Value = getFirstTarget()?.Lookup; - componentsSidebar.Children = new[] { new EditorSidebarSection("Current working layer") @@ -291,14 +289,41 @@ namespace osu.Game.Overlays.SkinEditor } } }, - new SkinComponentToolbox(getFirstTarget()) - { - RequestPlacement = placeComponent - } }; + + selectedTarget.Default = getFirstTarget()?.Lookup; + + if (!availableTargets.Any(t => t.Lookup.Equals(selectedTarget.Value))) + selectedTarget.Value = getFirstTarget()?.Lookup; + else + selectedTarget.TriggerChange(); } } + private void targetChanged(ValueChangedEvent target) + { + foreach (var toolbox in componentsSidebar.OfType()) + toolbox.Expire(); + + if (target.NewValue == null) + return; + + // If the new target has a ruleset, let's show ruleset-specific items at the top, and the rest below. + if (target.NewValue.Ruleset != null) + { + componentsSidebar.Add(new SkinComponentToolbox(getTarget(target.NewValue)) + { + RequestPlacement = placeComponent + }); + } + + // Remove the ruleset from the lookup to get base components. + componentsSidebar.Add(new SkinComponentToolbox(getTarget(new SkinComponentsContainerLookup(target.NewValue.Target))) + { + RequestPlacement = placeComponent + }); + } + private void skinChanged() { headerText.Clear(); @@ -331,7 +356,7 @@ namespace osu.Game.Overlays.SkinEditor private void placeComponent(ISerialisableDrawable component, bool applyDefaults = true) { - var targetContainer = getFirstTarget(); + var targetContainer = getTarget(selectedTarget.Value); if (targetContainer == null) return; @@ -364,9 +389,9 @@ namespace osu.Game.Overlays.SkinEditor private SkinComponentsContainer? getFirstTarget() => availableTargets.FirstOrDefault(); - private SkinComponentsContainer? getTarget(SkinComponentsContainerLookup.TargetArea target) + private SkinComponentsContainer? getTarget(SkinComponentsContainerLookup? target) { - return availableTargets.FirstOrDefault(c => c.Lookup.Target == target); + return availableTargets.FirstOrDefault(c => c.Lookup.Equals(target)); } private void revert() @@ -378,7 +403,7 @@ namespace osu.Game.Overlays.SkinEditor currentSkin.Value.ResetDrawableTarget(t); // add back default components - getTarget(t.Lookup.Target)?.Reload(); + getTarget(t.Lookup)?.Reload(); } } From 0a018514e167db5c43a03c08cb54b3a921ae3bcd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Feb 2023 16:57:36 +0900 Subject: [PATCH 346/516] Make skin editor focus only one layer at a time --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 57 ++++++++++++---------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index b3813b4d2c..338458c1b2 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -258,8 +258,6 @@ namespace osu.Game.Overlays.SkinEditor changeHandler?.Dispose(); - SelectedComponents.Clear(); - // Immediately clear the previous blueprint container to ensure it doesn't try to interact with the old target. content?.Clear(); @@ -268,29 +266,6 @@ namespace osu.Game.Overlays.SkinEditor void loadBlueprintContainer() { - Debug.Assert(content != null); - - changeHandler = new SkinEditorChangeHandler(targetScreen); - changeHandler.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true); - changeHandler.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); - - content.Child = new SkinBlueprintContainer(targetScreen); - - componentsSidebar.Children = new[] - { - new EditorSidebarSection("Current working layer") - { - Children = new Drawable[] - { - new SettingsDropdown - { - Items = availableTargets.Select(t => t.Lookup), - Current = selectedTarget, - } - } - }, - }; - selectedTarget.Default = getFirstTarget()?.Lookup; if (!availableTargets.Any(t => t.Lookup.Equals(selectedTarget.Value))) @@ -308,10 +283,40 @@ namespace osu.Game.Overlays.SkinEditor if (target.NewValue == null) return; + Debug.Assert(content != null); + + SelectedComponents.Clear(); + + var skinComponentsContainer = getTarget(target.NewValue); + + if (skinComponentsContainer == null) + return; + + changeHandler = new SkinEditorChangeHandler(skinComponentsContainer); + changeHandler.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true); + changeHandler.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); + + content.Child = new SkinBlueprintContainer(skinComponentsContainer); + + componentsSidebar.Children = new[] + { + new EditorSidebarSection("Current working layer") + { + Children = new Drawable[] + { + new SettingsDropdown + { + Items = availableTargets.Select(t => t.Lookup), + Current = selectedTarget, + } + } + }, + }; + // If the new target has a ruleset, let's show ruleset-specific items at the top, and the rest below. if (target.NewValue.Ruleset != null) { - componentsSidebar.Add(new SkinComponentToolbox(getTarget(target.NewValue)) + componentsSidebar.Add(new SkinComponentToolbox(skinComponentsContainer) { RequestPlacement = placeComponent }); From ceed3606cd7a3b0666c345ea768219ac5e65b91d Mon Sep 17 00:00:00 2001 From: Cootz <50776304+Cootz@users.noreply.github.com> Date: Fri, 17 Feb 2023 13:46:06 +0300 Subject: [PATCH 347/516] Remove redundant comment Co-authored-by: Dean Herbert --- osu.Game/Database/LegacyExporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 7434a46602..7fe0428db3 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -66,7 +66,7 @@ namespace osu.Game.Database { string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename); - filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); //Truncating the name to fit the path limit + filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); filename = $"{filenameWithoutExtension}{FileExtension}"; } From 0838fa636fc8dd3fba186383c45deb469efc220a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 17 Feb 2023 15:16:00 +0300 Subject: [PATCH 348/516] Make triangles slower --- osu.Game/Overlays/Mods/ModSelectColumn.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Mods/ModSelectColumn.cs b/osu.Game/Overlays/Mods/ModSelectColumn.cs index d9023e8dde..843f978c13 100644 --- a/osu.Game/Overlays/Mods/ModSelectColumn.cs +++ b/osu.Game/Overlays/Mods/ModSelectColumn.cs @@ -88,6 +88,7 @@ namespace osu.Game.Overlays.Mods Width = 1.1f, Height = header_height, Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + Velocity = 0.7f, Masking = true }, headerText = new OsuTextFlowContainer(t => From 51940133df8f938356295c017a4677058aea358b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 17 Feb 2023 15:18:45 +0300 Subject: [PATCH 349/516] Adjust width and add comment --- osu.Game/Overlays/Mods/ModSelectColumn.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModSelectColumn.cs b/osu.Game/Overlays/Mods/ModSelectColumn.cs index 843f978c13..41a6cbd549 100644 --- a/osu.Game/Overlays/Mods/ModSelectColumn.cs +++ b/osu.Game/Overlays/Mods/ModSelectColumn.cs @@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopRight, Origin = Anchor.TopRight, RelativeSizeAxes = Axes.X, - Width = 1.1f, + Width = 1.03f, // Makes sure the sheared area is fully covered Height = header_height, Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Velocity = 0.7f, From a3b440493aeae5fc3fbea99e36be28758c8fe2ba Mon Sep 17 00:00:00 2001 From: Cootz Date: Fri, 17 Feb 2023 15:23:43 +0300 Subject: [PATCH 350/516] Update xml doc --- osu.Game/Database/LegacyExporter.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 7fe0428db3..2d0a1d3528 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -24,9 +24,18 @@ namespace osu.Game.Database /// Max length of filename (including extension). /// /// - /// TODO: WHY? DOCUMENTATION PER PLATFORM LINKS HERE. - /// - /// This actual usable length is smaller 256 because adds additional "_" to the end of the path + /// + /// Filename limit for most OSs is 255, this actual usable length is smaller because adds additional "_" to the end of the path. + /// + /// + /// For more information see: + ///
+ /// File specification syntax + ///
+ ///
+ /// File systems limitations + ///
+ ///
///
public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) From fd1beaef87ef2156b5f5e56bf6d1656ece326a16 Mon Sep 17 00:00:00 2001 From: Cootz Date: Fri, 17 Feb 2023 15:24:27 +0300 Subject: [PATCH 351/516] Fix typo --- osu.Game/Database/LegacyExporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 2d0a1d3528..04d5a3aebc 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -25,7 +25,7 @@ namespace osu.Game.Database ///
/// /// - /// Filename limit for most OSs is 255, this actual usable length is smaller because adds additional "_" to the end of the path. + /// The filename limit for most OSs is 255. This actual usable length is smaller because adds an additional "_" to the end of the path. /// /// /// For more information see: From e3bdb3d852a85748032ea468d1763849aee74249 Mon Sep 17 00:00:00 2001 From: Cootz Date: Fri, 17 Feb 2023 15:32:36 +0300 Subject: [PATCH 352/516] Align links in one line --- osu.Game/Database/LegacyExporter.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 04d5a3aebc..cf88efb151 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -28,13 +28,7 @@ namespace osu.Game.Database /// The filename limit for most OSs is 255. This actual usable length is smaller because adds an additional "_" to the end of the path. /// /// - /// For more information see: - ///
- /// File specification syntax - ///
- ///
- /// File systems limitations - ///
+ /// For more information see file specification syntax, file systems limitations ///
///
public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) From dbb366e2792e0224cff5d5a0fffc84316b7dc76c Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Fri, 17 Feb 2023 22:32:03 +0900 Subject: [PATCH 353/516] CompletionText can be a LocalisableString I can't find a reason for not doing this, probably this was forgotten in https://github.com/ppy/osu/pull/15440 --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 5cce0f8c5b..e6662e2179 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -49,7 +49,7 @@ namespace osu.Game.Overlays.Notifications } } - public string CompletionText { get; set; } = "Task has completed!"; + public LocalisableString CompletionText { get; set; } = "Task has completed!"; private float progress; From 449e5fa6f82d10a9006db2ed5d96ffbe9ebd0a26 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Feb 2023 22:09:52 +0300 Subject: [PATCH 354/516] Rename one more left-over `skinnable` naming --- osu.Game/Skinning/SerialisedDrawableInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/SerialisedDrawableInfo.cs b/osu.Game/Skinning/SerialisedDrawableInfo.cs index 12f6d3ac7e..29078f0d74 100644 --- a/osu.Game/Skinning/SerialisedDrawableInfo.cs +++ b/osu.Game/Skinning/SerialisedDrawableInfo.cs @@ -64,8 +64,8 @@ namespace osu.Game.Skinning Anchor = component.Anchor; Origin = component.Origin; - if (component is ISerialisableDrawable skinnable) - UsesFixedAnchor = skinnable.UsesFixedAnchor; + if (component is ISerialisableDrawable serialisableDrawable) + UsesFixedAnchor = serialisableDrawable.UsesFixedAnchor; foreach (var (_, property) in component.GetSettingsSourceProperties()) { From ffcca9fd89db75ddf9b28bc00f3de59cdc4d5c78 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 17 Feb 2023 23:23:58 +0300 Subject: [PATCH 355/516] Remove awkward width specification --- osu.Game/Overlays/Mods/ModSelectColumn.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectColumn.cs b/osu.Game/Overlays/Mods/ModSelectColumn.cs index 41a6cbd549..e6d7bcd97d 100644 --- a/osu.Game/Overlays/Mods/ModSelectColumn.cs +++ b/osu.Game/Overlays/Mods/ModSelectColumn.cs @@ -31,8 +31,10 @@ namespace osu.Game.Overlays.Mods set { headerBackground.Colour = value; + var hsv = new Colour4(value.R, value.G, value.B, 1f).ToHSV(); - triangles.Colour = ColourInfo.GradientVertical(Colour4.FromHSV(hsv.X, hsv.Y + 0.2f, hsv.Z - 0.1f), value); + var trianglesColour = Colour4.FromHSV(hsv.X, hsv.Y + 0.2f, hsv.Z - 0.1f); + triangles.Colour = ColourInfo.GradientVertical(trianglesColour, trianglesColour.MultiplyAlpha(0f)); } } @@ -82,14 +84,10 @@ namespace osu.Game.Overlays.Mods }, triangles = new TrianglesV2 { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, RelativeSizeAxes = Axes.X, - Width = 1.03f, // Makes sure the sheared area is fully covered Height = header_height, Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Velocity = 0.7f, - Masking = true }, headerText = new OsuTextFlowContainer(t => { From b390fdb8ccb46f8f257cce6c1a9af7b6281b05c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 17 Feb 2023 21:51:19 +0100 Subject: [PATCH 356/516] Remove unused field --- osu.Game/Overlays/SkinEditor/SkinBlueprint.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs index 0ee9f35a62..2cb14814d1 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs @@ -24,8 +24,6 @@ namespace osu.Game.Overlays.SkinEditor { private Container box = null!; - private Container outlineBox = null!; - private AnchorOriginVisualiser anchorOriginVisualiser = null!; private Drawable drawable => (Drawable)Item; @@ -58,7 +56,7 @@ namespace osu.Game.Overlays.SkinEditor { Children = new Drawable[] { - outlineBox = new Container + new Container { RelativeSizeAxes = Axes.Both, Masking = true, From 2aa4481f6802feed215633d62c43044aa5ef38cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 17 Feb 2023 22:54:11 +0100 Subject: [PATCH 357/516] Fix toolbox items spontaneously contracting after briefly losing hover Reproduction scenario: 1. Hover a toolbox item 2. Unhover the item, but do not hover any other item (can be done by exiting the toolbox completely to the right) 3. Come back to the item hovered in step (1) 4. The item would spontaneously contract after a second --- osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs index 624841a3bc..f5726bf427 100644 --- a/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs +++ b/osu.Game/Overlays/SkinEditor/SkinComponentToolbox.cs @@ -122,6 +122,7 @@ namespace osu.Game.Overlays.SkinEditor protected override bool OnHover(HoverEvent e) { + expandContractAction?.Cancel(); expandContractAction = Scheduler.AddDelayed(() => { this.ResizeHeightTo(expanded_size, animation_duration, Easing.OutQuint); From ddd37bb3190419cc93b9ea49e4ad14e205b61efb Mon Sep 17 00:00:00 2001 From: Maximilian Kruse Date: Sat, 18 Feb 2023 19:43:45 +0100 Subject: [PATCH 358/516] Add setting to disable automatic seeking after object placement --- osu.Game/Configuration/OsuConfigManager.cs | 2 ++ osu.Game/Localisation/EditorStrings.cs | 5 +++++ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 9 ++++++++- osu.Game/Screens/Edit/Editor.cs | 6 ++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 565a919fb8..a4544200c7 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -178,6 +178,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 0.75f, 0.25f); SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f); SetDefault(OsuSetting.EditorShowHitMarkers, true); + SetDefault(OsuSetting.EditorSeekToHitobject, true); SetDefault(OsuSetting.LastProcessedMetadataId, -1); @@ -374,6 +375,7 @@ namespace osu.Game.Configuration SeasonalBackgroundMode, EditorWaveformOpacity, EditorShowHitMarkers, + EditorSeekToHitobject, DiscordRichPresence, AutomaticallyDownloadWhenSpectating, ShowOnlineExplicitContent, diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index 96c08aa6f8..65cecd27d6 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -19,6 +19,11 @@ namespace osu.Game.Localisation ///
public static LocalisableString ShowHitMarkers => new TranslatableString(getKey(@"show_hit_markers"), @"Show hit markers"); + /// + /// "Seek to Object after placement" + /// + public static LocalisableString SeekToHitobject => new TranslatableString(getKey(@"seek_to_hitobject"), @"Seek to Object after placement"); + /// /// "Timing" /// diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index b5b7400f64..528088dbda 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -17,6 +17,7 @@ using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Overlays; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Edit.Tools; @@ -70,6 +71,7 @@ namespace osu.Game.Rulesets.Edit private FillFlowContainer togglesCollection; private IBindable hasTiming; + protected Bindable SeekToHitobject { get; private set; } protected HitObjectComposer(Ruleset ruleset) : base(ruleset) @@ -80,8 +82,10 @@ namespace osu.Game.Rulesets.Edit dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, OsuConfigManager config) { + SeekToHitobject = config.GetBindable(OsuSetting.EditorSeekToHitobject); + Config = Dependencies.Get().GetConfigFor(Ruleset); try @@ -365,6 +369,9 @@ namespace osu.Game.Rulesets.Edit { EditorBeatmap.Add(hitObject); + // conditionally seek based on setting + if (!SeekToHitobject.Value) return; + if (EditorClock.CurrentTime < hitObject.StartTime) EditorClock.SeekSmoothlyTo(hitObject.StartTime); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index bd133383d1..d6c698c139 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -185,6 +185,7 @@ namespace osu.Game.Screens.Edit private Bindable editorBackgroundDim; private Bindable editorHitMarkers; + private Bindable editorSeekToHitobject; public Editor(EditorLoader loader = null) { @@ -272,6 +273,7 @@ namespace osu.Game.Screens.Edit editorBackgroundDim = config.GetBindable(OsuSetting.EditorDim); editorHitMarkers = config.GetBindable(OsuSetting.EditorShowHitMarkers); + editorSeekToHitobject = config.GetBindable(OsuSetting.EditorSeekToHitobject); AddInternal(new OsuContextMenuContainer { @@ -329,6 +331,10 @@ namespace osu.Game.Screens.Edit new ToggleMenuItem(EditorStrings.ShowHitMarkers) { State = { BindTarget = editorHitMarkers }, + }, + new ToggleMenuItem(EditorStrings.SeekToHitobject) + { + State = { BindTarget = editorSeekToHitobject }, } } }, From 55e9a71f388a7c5aed00f8fadcb1ce76bd725a73 Mon Sep 17 00:00:00 2001 From: Maximilian Kruse Date: Sat, 18 Feb 2023 20:42:13 +0100 Subject: [PATCH 359/516] Add test for seeking setting in mania placement test --- .../TestScenePlacementBeforeTrackStart.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs index 00dd75ceee..4c48a361b8 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs @@ -3,8 +3,11 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Tests.Visual; using osuTK.Input; @@ -14,6 +17,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { protected override Ruleset CreateEditorRuleset() => new ManiaRuleset(); + [Resolved] + private OsuConfigManager config { get; set; } = null!; + [Test] public void TestPlacement() { @@ -26,5 +32,36 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor AddStep("Click", () => InputManager.Click(MouseButton.Left)); AddAssert("No notes placed", () => EditorBeatmap.HitObjects.All(x => x.StartTime >= 0)); } + + [Test] + public void TestSeekOnNotePlacement() + { + AddStep("Seek to 1935", () => EditorClock.Seek(1935)); + AddStep("Change seek setting to true", () => config.SetValue(OsuSetting.EditorSeekToHitobject, true)); + seekSetup(); + AddUntilStep("Wait for seeking to end", () => !EditorClock.IsSeeking); + AddAssert("Seeked to object", () => + { + return EditorClock.CurrentTimeAccurate == 2287.1875; + }); + } + + [Test] + public void TestNoSeekOnNotePlacement() + { + AddStep("Seek to 1935", () => EditorClock.Seek(1935)); + AddStep("Change seek setting to false", () => config.SetValue(OsuSetting.EditorSeekToHitobject, false)); + seekSetup(); + AddAssert("Not seeking", () => !EditorClock.IsSeeking); + AddAssert("Not seeked to object", () => EditorClock.CurrentTime == 1935); + } + + private void seekSetup() + { + AddStep("Seek to 1935", () => EditorClock.Seek(1935)); + AddStep("Select note", () => InputManager.Key(Key.Number2)); + AddStep("Place note", () => InputManager.MoveMouseTo(this.ChildrenOfType().First(x => x.HitObject.StartTime == 2170))); + AddStep("Click", () => InputManager.Click(MouseButton.Left)); + } } } From 58d64cdbd04e07f56c50913efab939b664204751 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 18 Feb 2023 17:31:18 -0600 Subject: [PATCH 360/516] Clarify usingHiddenFading logic --- osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs index ca2f59cfb7..a337634e9a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (ClassicNoteLock.Value) osuRuleset.Playfield.HitPolicy = new ObjectOrderedHitPolicy(); - usingHiddenFading = !drawableRuleset.Mods.OfType().FirstOrDefault()?.OnlyFadeApproachCircles.Value ?? false; + usingHiddenFading = (drawableRuleset.Mods.OfType().SingleOrDefault()?.OnlyFadeApproachCircles.Value ?? true) != true; } public void ApplyToDrawableHitObject(DrawableHitObject obj) From 025061ba66766fad6a1b3521693956c09d69592e Mon Sep 17 00:00:00 2001 From: Maximilian Kruse Date: Sun, 19 Feb 2023 10:17:33 +0100 Subject: [PATCH 361/516] fix formating in SeekOnNote test --- .../Editor/TestScenePlacementBeforeTrackStart.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs index 4c48a361b8..142fa5ce07 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs @@ -37,20 +37,17 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor public void TestSeekOnNotePlacement() { AddStep("Seek to 1935", () => EditorClock.Seek(1935)); - AddStep("Change seek setting to true", () => config.SetValue(OsuSetting.EditorSeekToHitobject, true)); + AddStep("Change seek setting to true", () => config.SetValue(OsuSetting.EditorSeekToHitObject, true)); seekSetup(); AddUntilStep("Wait for seeking to end", () => !EditorClock.IsSeeking); - AddAssert("Seeked to object", () => - { - return EditorClock.CurrentTimeAccurate == 2287.1875; - }); + AddAssert("Seeked to object", () => EditorClock.CurrentTimeAccurate == 2287.1875); } [Test] public void TestNoSeekOnNotePlacement() { AddStep("Seek to 1935", () => EditorClock.Seek(1935)); - AddStep("Change seek setting to false", () => config.SetValue(OsuSetting.EditorSeekToHitobject, false)); + AddStep("Change seek setting to false", () => config.SetValue(OsuSetting.EditorSeekToHitObject, false)); seekSetup(); AddAssert("Not seeking", () => !EditorClock.IsSeeking); AddAssert("Not seeked to object", () => EditorClock.CurrentTime == 1935); From f3522c41629ea1f4ba1cde94b4b4b1509d7074c9 Mon Sep 17 00:00:00 2001 From: Maximilian Kruse Date: Sun, 19 Feb 2023 10:18:02 +0100 Subject: [PATCH 362/516] change bindable seekToHitObject to private --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 528088dbda..f989c81da8 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Edit private FillFlowContainer togglesCollection; private IBindable hasTiming; - protected Bindable SeekToHitobject { get; private set; } + private Bindable seekToHitObject; protected HitObjectComposer(Ruleset ruleset) : base(ruleset) @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Edit [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuConfigManager config) { - SeekToHitobject = config.GetBindable(OsuSetting.EditorSeekToHitobject); + seekToHitObject = config.GetBindable(OsuSetting.EditorSeekToHitObject); Config = Dependencies.Get().GetConfigFor(Ruleset); @@ -369,8 +369,7 @@ namespace osu.Game.Rulesets.Edit { EditorBeatmap.Add(hitObject); - // conditionally seek based on setting - if (!SeekToHitobject.Value) return; + if (!seekToHitObject.Value) return; if (EditorClock.CurrentTime < hitObject.StartTime) EditorClock.SeekSmoothlyTo(hitObject.StartTime); From 723a043c4351da62b8c16913b42d3e27f2e1b843 Mon Sep 17 00:00:00 2001 From: Maximilian Kruse Date: Sun, 19 Feb 2023 10:18:22 +0100 Subject: [PATCH 363/516] naming change from Hitobject to HitObject --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- osu.Game/Localisation/EditorStrings.cs | 4 ++-- osu.Game/Screens/Edit/Editor.cs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index a4544200c7..9093c017d2 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -178,7 +178,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 0.75f, 0.25f); SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f); SetDefault(OsuSetting.EditorShowHitMarkers, true); - SetDefault(OsuSetting.EditorSeekToHitobject, true); + SetDefault(OsuSetting.EditorSeekToHitObject, true); SetDefault(OsuSetting.LastProcessedMetadataId, -1); @@ -375,7 +375,7 @@ namespace osu.Game.Configuration SeasonalBackgroundMode, EditorWaveformOpacity, EditorShowHitMarkers, - EditorSeekToHitobject, + EditorSeekToHitObject, DiscordRichPresence, AutomaticallyDownloadWhenSpectating, ShowOnlineExplicitContent, diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index 65cecd27d6..4557cb532f 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -20,9 +20,9 @@ namespace osu.Game.Localisation public static LocalisableString ShowHitMarkers => new TranslatableString(getKey(@"show_hit_markers"), @"Show hit markers"); /// - /// "Seek to Object after placement" + /// "Seek to object after placement" /// - public static LocalisableString SeekToHitobject => new TranslatableString(getKey(@"seek_to_hitobject"), @"Seek to Object after placement"); + public static LocalisableString SeekToHitObject => new TranslatableString(getKey(@"seek_to_hit_object"), @"Seek to object after placement"); /// /// "Timing" diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index d6c698c139..e9a0fbf6fa 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -185,7 +185,7 @@ namespace osu.Game.Screens.Edit private Bindable editorBackgroundDim; private Bindable editorHitMarkers; - private Bindable editorSeekToHitobject; + private Bindable editorSeekToHitObject; public Editor(EditorLoader loader = null) { @@ -273,7 +273,7 @@ namespace osu.Game.Screens.Edit editorBackgroundDim = config.GetBindable(OsuSetting.EditorDim); editorHitMarkers = config.GetBindable(OsuSetting.EditorShowHitMarkers); - editorSeekToHitobject = config.GetBindable(OsuSetting.EditorSeekToHitobject); + editorSeekToHitObject = config.GetBindable(OsuSetting.EditorSeekToHitObject); AddInternal(new OsuContextMenuContainer { @@ -332,9 +332,9 @@ namespace osu.Game.Screens.Edit { State = { BindTarget = editorHitMarkers }, }, - new ToggleMenuItem(EditorStrings.SeekToHitobject) + new ToggleMenuItem(EditorStrings.SeekToHitObject) { - State = { BindTarget = editorSeekToHitobject }, + State = { BindTarget = editorSeekToHitObject }, } } }, From aac32a2c9f49795e60a2f397bf833060299f2d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Feb 2023 13:14:51 +0100 Subject: [PATCH 364/516] Combine config and time checks into one Functionally equivalent right now, but the combined variant is more localised to what it actually needs to do, and less error-prone if any new code gets appended to the method. --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index f989c81da8..eb10d09560 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -369,9 +369,7 @@ namespace osu.Game.Rulesets.Edit { EditorBeatmap.Add(hitObject); - if (!seekToHitObject.Value) return; - - if (EditorClock.CurrentTime < hitObject.StartTime) + if (seekToHitObject.Value && EditorClock.CurrentTime < hitObject.StartTime) EditorClock.SeekSmoothlyTo(hitObject.StartTime); } } From 80b329f06924952df70fcb926cf2cc4fdaaf6fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Feb 2023 13:16:40 +0100 Subject: [PATCH 365/516] Rename test scene to match contents It does not only test "placement before track start" anymore. --- ...PlacementBeforeTrackStart.cs => TestSceneObjectPlacement.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename osu.Game.Rulesets.Mania.Tests/Editor/{TestScenePlacementBeforeTrackStart.cs => TestSceneObjectPlacement.cs} (97%) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs similarity index 97% rename from osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs rename to osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs index 142fa5ce07..02980f3ac8 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs @@ -13,7 +13,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public partial class TestScenePlacementBeforeTrackStart : EditorTestScene + public partial class TestSceneObjectPlacement : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new ManiaRuleset(); From 80ee917c7780e0e5da061312312430ead795f44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Feb 2023 13:33:06 +0100 Subject: [PATCH 366/516] Rewrite test cases - Depend less on arbitrary timings - Remove unnecessary seeks - Change method name to make more sense - Use nunit style assertions --- .../Editor/TestSceneObjectPlacement.cs | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs index 02980f3ac8..ec2995924d 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs @@ -7,7 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Configuration; -using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Tests.Visual; using osuTK.Input; @@ -36,29 +36,32 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor [Test] public void TestSeekOnNotePlacement() { - AddStep("Seek to 1935", () => EditorClock.Seek(1935)); - AddStep("Change seek setting to true", () => config.SetValue(OsuSetting.EditorSeekToHitObject, true)); - seekSetup(); - AddUntilStep("Wait for seeking to end", () => !EditorClock.IsSeeking); - AddAssert("Seeked to object", () => EditorClock.CurrentTimeAccurate == 2287.1875); + double? initialTime = null; + + AddStep("store initial time", () => initialTime = EditorClock.CurrentTime); + AddStep("change seek setting to true", () => config.SetValue(OsuSetting.EditorSeekToHitObject, true)); + placeObject(); + AddUntilStep("wait for seek to complete", () => !EditorClock.IsSeeking); + AddAssert("seeked forward to object", () => EditorClock.CurrentTime, () => Is.GreaterThan(initialTime)); } [Test] public void TestNoSeekOnNotePlacement() { - AddStep("Seek to 1935", () => EditorClock.Seek(1935)); - AddStep("Change seek setting to false", () => config.SetValue(OsuSetting.EditorSeekToHitObject, false)); - seekSetup(); - AddAssert("Not seeking", () => !EditorClock.IsSeeking); - AddAssert("Not seeked to object", () => EditorClock.CurrentTime == 1935); + double? initialTime = null; + + AddStep("store initial time", () => initialTime = EditorClock.CurrentTime); + AddStep("change seek setting to false", () => config.SetValue(OsuSetting.EditorSeekToHitObject, false)); + placeObject(); + AddAssert("not seeking", () => !EditorClock.IsSeeking); + AddAssert("time is unchanged", () => EditorClock.CurrentTime, () => Is.EqualTo(initialTime)); } - private void seekSetup() + private void placeObject() { - AddStep("Seek to 1935", () => EditorClock.Seek(1935)); - AddStep("Select note", () => InputManager.Key(Key.Number2)); - AddStep("Place note", () => InputManager.MoveMouseTo(this.ChildrenOfType().First(x => x.HitObject.StartTime == 2170))); - AddStep("Click", () => InputManager.Click(MouseButton.Left)); + AddStep("select note placement tool", () => InputManager.Key(Key.Number2)); + AddStep("move mouse to centre of last column", () => InputManager.MoveMouseTo(this.ChildrenOfType().Last().ScreenSpaceDrawQuad.Centre)); + AddStep("place note", () => InputManager.Click(MouseButton.Left)); } } } From 8b25598d8251b0459528ea69053b25bcb62f923b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Feb 2023 13:54:48 +0100 Subject: [PATCH 367/516] Rename moved test method to describe its purpose better --- .../Editor/TestSceneObjectPlacement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs index ec2995924d..6ddcabfc4d 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor private OsuConfigManager config { get; set; } = null!; [Test] - public void TestPlacement() + public void TestPlacementBeforeTrackStart() { AddStep("Seek to 0", () => EditorClock.Seek(0)); AddStep("Select note", () => InputManager.Key(Key.Number2)); From d9ca7102f048e1deb0ba79493866998043cde238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Feb 2023 15:06:40 +0100 Subject: [PATCH 368/516] Use more generic wording for future-proofing --- .../Editor/TestSceneObjectPlacement.cs | 4 ++-- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- osu.Game/Localisation/EditorStrings.cs | 4 ++-- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 6 +++--- osu.Game/Screens/Edit/Editor.cs | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs index 6ddcabfc4d..13a116b209 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor double? initialTime = null; AddStep("store initial time", () => initialTime = EditorClock.CurrentTime); - AddStep("change seek setting to true", () => config.SetValue(OsuSetting.EditorSeekToHitObject, true)); + AddStep("change seek setting to true", () => config.SetValue(OsuSetting.EditorAutoSeekOnPlacement, true)); placeObject(); AddUntilStep("wait for seek to complete", () => !EditorClock.IsSeeking); AddAssert("seeked forward to object", () => EditorClock.CurrentTime, () => Is.GreaterThan(initialTime)); @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor double? initialTime = null; AddStep("store initial time", () => initialTime = EditorClock.CurrentTime); - AddStep("change seek setting to false", () => config.SetValue(OsuSetting.EditorSeekToHitObject, false)); + AddStep("change seek setting to false", () => config.SetValue(OsuSetting.EditorAutoSeekOnPlacement, false)); placeObject(); AddAssert("not seeking", () => !EditorClock.IsSeeking); AddAssert("time is unchanged", () => EditorClock.CurrentTime, () => Is.EqualTo(initialTime)); diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 9093c017d2..70ad6bfc96 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -178,7 +178,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 0.75f, 0.25f); SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f); SetDefault(OsuSetting.EditorShowHitMarkers, true); - SetDefault(OsuSetting.EditorSeekToHitObject, true); + SetDefault(OsuSetting.EditorAutoSeekOnPlacement, true); SetDefault(OsuSetting.LastProcessedMetadataId, -1); @@ -375,7 +375,7 @@ namespace osu.Game.Configuration SeasonalBackgroundMode, EditorWaveformOpacity, EditorShowHitMarkers, - EditorSeekToHitObject, + EditorAutoSeekOnPlacement, DiscordRichPresence, AutomaticallyDownloadWhenSpectating, ShowOnlineExplicitContent, diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index 4557cb532f..f4e23ae7cb 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -20,9 +20,9 @@ namespace osu.Game.Localisation public static LocalisableString ShowHitMarkers => new TranslatableString(getKey(@"show_hit_markers"), @"Show hit markers"); /// - /// "Seek to object after placement" + /// "Automatically seek after placing objects" /// - public static LocalisableString SeekToHitObject => new TranslatableString(getKey(@"seek_to_hit_object"), @"Seek to object after placement"); + public static LocalisableString AutoSeekOnPlacement => new TranslatableString(getKey(@"auto_seek_on_placement"), @"Automatically seek after placing objects"); /// /// "Timing" diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index eb10d09560..aee86fd942 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Edit private FillFlowContainer togglesCollection; private IBindable hasTiming; - private Bindable seekToHitObject; + private Bindable autoSeekOnPlacement; protected HitObjectComposer(Ruleset ruleset) : base(ruleset) @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Edit [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuConfigManager config) { - seekToHitObject = config.GetBindable(OsuSetting.EditorSeekToHitObject); + autoSeekOnPlacement = config.GetBindable(OsuSetting.EditorAutoSeekOnPlacement); Config = Dependencies.Get().GetConfigFor(Ruleset); @@ -369,7 +369,7 @@ namespace osu.Game.Rulesets.Edit { EditorBeatmap.Add(hitObject); - if (seekToHitObject.Value && EditorClock.CurrentTime < hitObject.StartTime) + if (autoSeekOnPlacement.Value && EditorClock.CurrentTime < hitObject.StartTime) EditorClock.SeekSmoothlyTo(hitObject.StartTime); } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index e9a0fbf6fa..d89392f757 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -185,7 +185,7 @@ namespace osu.Game.Screens.Edit private Bindable editorBackgroundDim; private Bindable editorHitMarkers; - private Bindable editorSeekToHitObject; + private Bindable editorAutoSeekOnPlacement; public Editor(EditorLoader loader = null) { @@ -273,7 +273,7 @@ namespace osu.Game.Screens.Edit editorBackgroundDim = config.GetBindable(OsuSetting.EditorDim); editorHitMarkers = config.GetBindable(OsuSetting.EditorShowHitMarkers); - editorSeekToHitObject = config.GetBindable(OsuSetting.EditorSeekToHitObject); + editorAutoSeekOnPlacement = config.GetBindable(OsuSetting.EditorAutoSeekOnPlacement); AddInternal(new OsuContextMenuContainer { @@ -332,9 +332,9 @@ namespace osu.Game.Screens.Edit { State = { BindTarget = editorHitMarkers }, }, - new ToggleMenuItem(EditorStrings.SeekToHitObject) + new ToggleMenuItem(EditorStrings.AutoSeekOnPlacement) { - State = { BindTarget = editorSeekToHitObject }, + State = { BindTarget = editorAutoSeekOnPlacement }, } } }, From d7381b762ca33dffb6980f9d92e5e3eec5c269d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 19 Feb 2023 23:52:21 +0900 Subject: [PATCH 369/516] Also tween origin position --- osu.Game/Overlays/SkinEditor/SkinBlueprint.cs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs index 2cb14814d1..f5814b4c01 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs @@ -177,6 +177,7 @@ namespace osu.Game.Overlays.SkinEditor } private Vector2? anchorPosition; + private Vector2? originPositionInDrawableSpace; protected override void Update() { @@ -186,18 +187,13 @@ namespace osu.Game.Overlays.SkinEditor return; var newAnchor = drawable.Parent.ToSpaceOfOtherDrawable(drawable.AnchorPosition, this); - - anchorPosition ??= newAnchor; - - anchorPosition = - new Vector2( - (float)Interpolation.DampContinuously(anchorPosition.Value.X, newAnchor.X, 25, Clock.ElapsedFrameTime), - (float)Interpolation.DampContinuously(anchorPosition.Value.Y, newAnchor.Y, 25, Clock.ElapsedFrameTime) - ); - - originBox.Position = drawable.ToSpaceOfOtherDrawable(drawable.OriginPosition, this); + anchorPosition = tweenPosition(anchorPosition ?? newAnchor, newAnchor); anchorBox.Position = anchorPosition.Value; + // for the origin, tween in the drawable's local space to avoid unwanted tweening when the drawable is being dragged. + originPositionInDrawableSpace = originPositionInDrawableSpace != null ? tweenPosition(originPositionInDrawableSpace.Value, drawable.OriginPosition) : drawable.OriginPosition; + originBox.Position = drawable.ToSpaceOfOtherDrawable(originPositionInDrawableSpace.Value, this); + var point1 = ToLocalSpace(anchorBox.ScreenSpaceDrawQuad.Centre); var point2 = ToLocalSpace(originBox.ScreenSpaceDrawQuad.Centre); @@ -205,5 +201,11 @@ namespace osu.Game.Overlays.SkinEditor anchorLine.Width = (point2 - point1).Length; anchorLine.Rotation = MathHelper.RadiansToDegrees(MathF.Atan2(point2.Y - point1.Y, point2.X - point1.X)); } + + private Vector2 tweenPosition(Vector2 oldPosition, Vector2 newPosition) + => new Vector2( + (float)Interpolation.DampContinuously(oldPosition.X, newPosition.X, 25, Clock.ElapsedFrameTime), + (float)Interpolation.DampContinuously(oldPosition.Y, newPosition.Y, 25, Clock.ElapsedFrameTime) + ); } } From 0611fd40350632d0bdf2b4af807990e50653a7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Feb 2023 16:39:16 +0100 Subject: [PATCH 370/516] Add coverage for classic/hidden interactions --- .../TestSceneHitCircleLateFade.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs index 615c878014..3c32b4fa65 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs @@ -35,6 +35,32 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("Transparent when missed", () => alphaAtMiss == 0); } + [Test] + public void TestHitCircleClassicAndFullHiddenMods() + { + AddStep("Create hit circle", () => + { + SelectedMods.Value = new Mod[] { new OsuModHidden(), new OsuModClassic() }; + createCircle(); + }); + + AddUntilStep("Wait until circle is missed", () => alphaAtMiss.IsNotNull()); + AddAssert("Transparent when missed", () => alphaAtMiss == 0); + } + + [Test] + public void TestHitCircleClassicAndApproachCircleOnlyHiddenMods() + { + AddStep("Create hit circle", () => + { + SelectedMods.Value = new Mod[] { new OsuModHidden { OnlyFadeApproachCircles = { Value = true } }, new OsuModClassic() }; + createCircle(); + }); + + AddUntilStep("Wait until circle is missed", () => alphaAtMiss.IsNotNull()); + AddAssert("Transparent when missed", () => alphaAtMiss == 0); + } + [Test] public void TestHitCircleNoMod() { From 8a488ebccc4274c3bc8692513239b0f10fd903ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Feb 2023 16:12:10 +0100 Subject: [PATCH 371/516] Actually simplify condition --- osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs index a337634e9a..250d97c537 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (ClassicNoteLock.Value) osuRuleset.Playfield.HitPolicy = new ObjectOrderedHitPolicy(); - usingHiddenFading = (drawableRuleset.Mods.OfType().SingleOrDefault()?.OnlyFadeApproachCircles.Value ?? true) != true; + usingHiddenFading = drawableRuleset.Mods.OfType().SingleOrDefault()?.OnlyFadeApproachCircles.Value == false; } public void ApplyToDrawableHitObject(DrawableHitObject obj) From c86c1a902984a4e9c67b8b070b4b18565eb25dc1 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Mon, 20 Feb 2023 00:06:20 -0500 Subject: [PATCH 372/516] allow tablet area to be dragged --- .../Sections/Input/TabletAreaSelection.cs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index 6f7faf535b..8b15bc8f72 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Utils; using osu.Game.Graphics; @@ -66,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input RelativeSizeAxes = Axes.Both, Colour = colour.Gray1, }, - usableAreaContainer = new Container + usableAreaContainer = new UsableAreaContainer(handler) { Origin = Anchor.Centre, Children = new Drawable[] @@ -225,4 +226,28 @@ namespace osu.Game.Overlays.Settings.Sections.Input tabletContainer.Scale = new Vector2(1 / adjust); } } + + public partial class UsableAreaContainer : Container + { + private readonly Bindable areaOffset; + + public UsableAreaContainer(ITabletHandler tabletHandler) + { + areaOffset = tabletHandler.AreaOffset.GetBoundCopy(); + } + + protected override bool OnDragStart(DragStartEvent e) => true; + + protected override void OnDrag(DragEvent e) + { + var newPos = Position + e.Delta; + this.MoveTo(Vector2.Clamp(newPos, Vector2.Zero, Parent.Size)); + } + + protected override void OnDragEnd(DragEndEvent e) + { + areaOffset.Value = Position; + base.OnDragEnd(e); + } + } } From 5f7a6d13c35fb898cc9f72bf82c574499cff3a03 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Feb 2023 19:47:17 +0900 Subject: [PATCH 373/516] Remove unused `GetSerialisableIdentifier` for now --- osu.Game/Skinning/SkinComponentsContainerLookup.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Skinning/SkinComponentsContainerLookup.cs b/osu.Game/Skinning/SkinComponentsContainerLookup.cs index f6c462ddaa..c7fc30f724 100644 --- a/osu.Game/Skinning/SkinComponentsContainerLookup.cs +++ b/osu.Game/Skinning/SkinComponentsContainerLookup.cs @@ -17,8 +17,6 @@ namespace osu.Game.Skinning public readonly RulesetInfo? Ruleset; - public string GetSerialisableIdentifier() => Ruleset?.ShortName ?? "global"; - public SkinComponentsContainerLookup(TargetArea target, RulesetInfo? ruleset = null) { Target = target; From 0ddda018fdd0c8ee1b47906848f6c7e3f3344a21 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Feb 2023 19:48:18 +0900 Subject: [PATCH 374/516] Add xmldoc for `SkinComponentsContainerLookup.Ruleset` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Skinning/SkinComponentsContainerLookup.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Skinning/SkinComponentsContainerLookup.cs b/osu.Game/Skinning/SkinComponentsContainerLookup.cs index c7fc30f724..812ba5d495 100644 --- a/osu.Game/Skinning/SkinComponentsContainerLookup.cs +++ b/osu.Game/Skinning/SkinComponentsContainerLookup.cs @@ -15,6 +15,10 @@ namespace osu.Game.Skinning /// public readonly TargetArea Target; + /// + /// The ruleset for which skin components should be returned. + /// A value means that returned components are global and should be applied for all rulesets. + /// public readonly RulesetInfo? Ruleset; public SkinComponentsContainerLookup(TargetArea target, RulesetInfo? ruleset = null) From 1629c86b5d55caf1ad7d8083ed78015066322a65 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Feb 2023 19:48:39 +0900 Subject: [PATCH 375/516] Mark constant identifier as non-localisable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Skinning/SkinLayoutInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinLayoutInfo.cs b/osu.Game/Skinning/SkinLayoutInfo.cs index ff27a47223..3b91987b7c 100644 --- a/osu.Game/Skinning/SkinLayoutInfo.cs +++ b/osu.Game/Skinning/SkinLayoutInfo.cs @@ -17,7 +17,7 @@ namespace osu.Game.Skinning [Serializable] public class SkinLayoutInfo { - private const string global_identifier = "global"; + private const string global_identifier = @"global"; public IEnumerable AllDrawables => DrawableInfo.Values.SelectMany(v => v); From 18700b4daa2c061f2f9798c0954003cd71450da1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Feb 2023 19:51:54 +0900 Subject: [PATCH 376/516] Add note about skin migrations being on read and remove an older deprecation notice --- osu.Game/Skinning/Skin.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index b55ddf250a..ad7c3bdff1 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -125,11 +125,15 @@ namespace osu.Game.Skinning { } + // Of note, the migration code below runs on read of skins, but there's nothing to + // force a rewrite after migration. Let's not remove these migration rules until we + // have something in place to ensure we don't end up breaking skins of users that haven't + // manually saved their skin since a change was implemented. + // if that fails, attempt to deserialise using the old naked list. if (layoutInfo == null) { // handle namespace changes... - // can be removed 2023-01-31 jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.SongProgress", @"osu.Game.Screens.Play.HUD.DefaultSongProgress"); jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.LegacyComboCounter", @"osu.Game.Skinning.LegacyComboCounter"); From ec12186d6333988cb58c3113de9468750b7a1a5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Feb 2023 19:53:04 +0900 Subject: [PATCH 377/516] Remove unnecesasry null check on `content` --- osu.Game/Skinning/SkinComponentsContainer.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game/Skinning/SkinComponentsContainer.cs b/osu.Game/Skinning/SkinComponentsContainer.cs index d4e0b2e69b..d18e9023cd 100644 --- a/osu.Game/Skinning/SkinComponentsContainer.cs +++ b/osu.Game/Skinning/SkinComponentsContainer.cs @@ -74,17 +74,12 @@ namespace osu.Game.Skinning cancellationSource?.Cancel(); cancellationSource = null; - if (content != null) + LoadComponentAsync(content, wrapper => { - LoadComponentAsync(content, wrapper => - { - AddInternal(wrapper); - components.AddRange(wrapper.Children.OfType()); - ComponentsLoaded = true; - }, (cancellationSource = new CancellationTokenSource()).Token); - } - else + AddInternal(wrapper); + components.AddRange(wrapper.Children.OfType()); ComponentsLoaded = true; + }, (cancellationSource = new CancellationTokenSource()).Token); } /// From a9c7edd08787a442e8390f453043ccbed0350d43 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Feb 2023 19:57:16 +0900 Subject: [PATCH 378/516] Remove copy pasted comment --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index ad07099d48..ae831f4d66 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -423,11 +423,6 @@ namespace osu.Game.Overlays.SkinEditor if (!canCopy.Value) return; - // This is an initial implementation just to get an idea of how people used this function. - // There are a couple of differences from osu!stable's implementation which will require more work to match: - // - The "clipboard" is not populated during the duplication process. - // - The duplicated hitobjects are inserted after the original pattern (add one beat_length and then quantize using beat snap). - // - The duplicated hitobjects are selected (but this is also applied for all paste operations so should be changed there). Copy(); Paste(); } From b68562b03359e5e8832df72f4cc6d3a4e3731486 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Feb 2023 20:00:12 +0900 Subject: [PATCH 379/516] Make `placeComponent` resilient to missing dependencies --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index ae831f4d66..8177c31058 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -353,12 +353,18 @@ namespace osu.Game.Overlays.SkinEditor placeComponent(component); } - private void placeComponent(ISerialisableDrawable component, bool applyDefaults = true) + /// + /// Attempt to place a given component in the current target. + /// + /// The component to be placed. + /// Whether to apply default anchor / origin / position values. + /// Whether placement succeeded. Could fail if no target is available, or if the current target has missing dependency requirements for the component. + private bool placeComponent(ISerialisableDrawable component, bool applyDefaults = true) { var targetContainer = getFirstTarget(); if (targetContainer == null) - return; + return false; var drawableComponent = (Drawable)component; @@ -370,10 +376,19 @@ namespace osu.Game.Overlays.SkinEditor drawableComponent.Y = targetContainer.DrawSize.Y / 2; } - targetContainer.Add(component); + try + { + targetContainer.Add(component); + } + catch + { + // May fail if dependencies are not available, for instance. + return false; + } SelectedComponents.Clear(); SelectedComponents.Add(component); + return true; } private void populateSettings() From 43d33d45caa852707a1b5064f8cb23549ddc45de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Feb 2023 20:02:43 +0900 Subject: [PATCH 380/516] Only add valid placed components to selected collection on paste --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 8177c31058..944a64d131 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -455,11 +455,13 @@ namespace osu.Game.Overlays.SkinEditor .OfType() .ToArray(); - foreach (var i in instances) - placeComponent(i, false); - SelectedComponents.Clear(); - SelectedComponents.AddRange(instances); + + foreach (var i in instances) + { + if (placeComponent(i, false)) + SelectedComponents.Add(i); + } changeHandler?.EndChange(); } From 43724472c4c7a793c58e57c3083895d5e3e7ee76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 20 Feb 2023 20:07:17 +0100 Subject: [PATCH 381/516] Clarify comment to avoid playing pronoun game --- osu.Game/Skinning/Skin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index ad7c3bdff1..a6250d7488 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -130,7 +130,7 @@ namespace osu.Game.Skinning // have something in place to ensure we don't end up breaking skins of users that haven't // manually saved their skin since a change was implemented. - // if that fails, attempt to deserialise using the old naked list. + // If deserialisation using SkinLayoutInfo fails, attempt to deserialise using the old naked list. if (layoutInfo == null) { // handle namespace changes... From 86a7f4dfd0f4f7bf389e0177c326c748b99f0fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 20 Feb 2023 20:33:54 +0100 Subject: [PATCH 382/516] Do not serialise `SkinLayoutInfo.AllDrawables` - It is entirely derived from `SkinLayoutInfo.DrawableInfo`, which is the actual primary thing we want to serialise. - It will never get read out from any serialised files anyway (corollary of the previous point - it is a get-only property derived from another). - It is only used in tests. All of the three reasons above make serialising the property out to skin files nothing more than a waste of space. --- osu.Game/Skinning/SkinLayoutInfo.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Skinning/SkinLayoutInfo.cs b/osu.Game/Skinning/SkinLayoutInfo.cs index 3b91987b7c..115d59b9d0 100644 --- a/osu.Game/Skinning/SkinLayoutInfo.cs +++ b/osu.Game/Skinning/SkinLayoutInfo.cs @@ -19,6 +19,7 @@ namespace osu.Game.Skinning { private const string global_identifier = @"global"; + [JsonIgnore] public IEnumerable AllDrawables => DrawableInfo.Values.SelectMany(v => v); [JsonProperty] From 0d229d959bff7eb55eb05623e8c414b085ceed74 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Feb 2023 13:50:19 +0900 Subject: [PATCH 383/516] Remove unnecessary `TriggerChange` call --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 338458c1b2..0caea4d0c7 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -269,9 +269,7 @@ namespace osu.Game.Overlays.SkinEditor selectedTarget.Default = getFirstTarget()?.Lookup; if (!availableTargets.Any(t => t.Lookup.Equals(selectedTarget.Value))) - selectedTarget.Value = getFirstTarget()?.Lookup; - else - selectedTarget.TriggerChange(); + selectedTarget.SetDefault(); } } From e686b4393ef9b3c6d9a27636a824a9bb8c76f0d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Feb 2023 14:04:19 +0900 Subject: [PATCH 384/516] Add wait steps to ensure frame-stable clock has caught up before checking state --- .../Gameplay/TestSceneGameplaySampleTriggerSource.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index f9f5581b43..f7641c0cc9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Timing; +using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -155,19 +156,28 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("check valid object is slider's first nested", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4].NestedHitObjects.First())); AddStep("seek to just after slider", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[4].GetEndTime() + 100)); + waitForCatchUp(); AddUntilStep("wait until valid object is slider's last nested", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4].NestedHitObjects.Last())); // After we get far enough away, the samples of the object itself should be used, not any nested object. AddStep("seek to further after slider", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[4].GetEndTime() + 1000)); + waitForCatchUp(); AddUntilStep("wait until valid object is slider itself", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4])); AddStep("Seek into future", () => Beatmap.Value.Track.Seek(beatmap.HitObjects.Last().GetEndTime() + 10000)); + waitForCatchUp(); waitForAliveObjectIndex(null); checkValidObjectIndex(4); } - private void seekBeforeIndex(int index) => + private void seekBeforeIndex(int index) + { AddStep($"seek to just before object {index}", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[index].StartTime - 100)); + waitForCatchUp(); + } + + private void waitForCatchUp() => + AddUntilStep("wait for frame stable clock to catch up", () => Precision.AlmostEquals(Beatmap.Value.Track.CurrentTime, Player.DrawableRuleset.FrameStableClock.CurrentTime)); private void waitForAliveObjectIndex(int? index) { From 9321ec29dc942b109f885c9d0b34302d581f7998 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Feb 2023 14:04:37 +0900 Subject: [PATCH 385/516] Update slider sample source asserts to match expected behaviour As pointed out in review, if the current time is after the end of the slider, the correct hit object to use for sample retrieval is the object itself, not any nested object. --- .../Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index f7641c0cc9..7f4f1ed027 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -155,7 +155,7 @@ namespace osu.Game.Tests.Visual.Gameplay // This is because the (parent) object will only play its sample at the final EndTime. AddAssert("check valid object is slider's first nested", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4].NestedHitObjects.First())); - AddStep("seek to just after slider", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[4].GetEndTime() + 100)); + AddStep("seek to just before slider ends", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[4].GetEndTime() - 100)); waitForCatchUp(); AddUntilStep("wait until valid object is slider's last nested", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4].NestedHitObjects.Last())); From af062e7a68c7b21ce9c8250c7f13bace75c19e2d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Feb 2023 14:07:47 +0900 Subject: [PATCH 386/516] Change `placeComponent` to only add to selection, not clear an existing selection --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 26 +++++++++------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 944a64d131..d6521e759e 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -318,7 +318,14 @@ namespace osu.Game.Overlays.SkinEditor componentsSidebar.Child = new SkinComponentToolbox(getFirstTarget() as CompositeDrawable) { - RequestPlacement = placeComponent + RequestPlacement = type => + { + if (!(Activator.CreateInstance(type) is ISerialisableDrawable component)) + throw new InvalidOperationException($"Attempted to instantiate a component for placement which was not an {typeof(ISerialisableDrawable)}."); + + SelectedComponents.Clear(); + placeComponent(component); + } }; } } @@ -345,16 +352,8 @@ namespace osu.Game.Overlays.SkinEditor hasBegunMutating = true; } - private void placeComponent(Type type) - { - if (!(Activator.CreateInstance(type) is ISerialisableDrawable component)) - throw new InvalidOperationException($"Attempted to instantiate a component for placement which was not an {typeof(ISerialisableDrawable)}."); - - placeComponent(component); - } - /// - /// Attempt to place a given component in the current target. + /// Attempt to place a given component in the current target. If successful, the new component will be added to . /// /// The component to be placed. /// Whether to apply default anchor / origin / position values. @@ -386,7 +385,6 @@ namespace osu.Game.Overlays.SkinEditor return false; } - SelectedComponents.Clear(); SelectedComponents.Add(component); return true; } @@ -458,10 +456,7 @@ namespace osu.Game.Overlays.SkinEditor SelectedComponents.Clear(); foreach (var i in instances) - { - if (placeComponent(i, false)) - SelectedComponents.Add(i); - } + placeComponent(i, false); changeHandler?.EndChange(); } @@ -549,6 +544,7 @@ namespace osu.Game.Overlays.SkinEditor Position = skinnableTarget.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position), }; + SelectedComponents.Clear(); placeComponent(sprite, false); SkinSelectionHandler.ApplyClosestAnchor(sprite); From 1acc5362480b5eec0f8f150d2f44a6755b47f76a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Feb 2023 19:03:52 +0900 Subject: [PATCH 387/516] Move `DrawableRuleset.Audio` to a less generic level --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 44 +++++++++++-------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 11b238480a..7d7361b9b6 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -66,6 +66,10 @@ namespace osu.Game.Rulesets.UI public override Container Overlays { get; } = new Container { RelativeSizeAxes = Axes.Both }; + public override IAdjustableAudioComponent Audio => audioContainer; + + private readonly AudioContainer audioContainer = new AudioContainer { RelativeSizeAxes = Axes.Both }; + public override Container FrameStableComponents { get; } = new Container { RelativeSizeAxes = Axes.Both }; public override IFrameStableClock FrameStableClock => frameStabilityContainer; @@ -102,14 +106,6 @@ namespace osu.Game.Rulesets.UI private DrawableRulesetDependencies dependencies; - /// - /// Audio adjustments which are applied to the playfield. - /// - /// - /// Does not affect . - /// - public IAdjustableAudioComponent Audio { get; private set; } - /// /// Creates a ruleset visualisation for the provided ruleset and beatmap. /// @@ -172,30 +168,22 @@ namespace osu.Game.Rulesets.UI [BackgroundDependencyLoader] private void load(CancellationToken? cancellationToken) { - AudioContainer audioContainer; - InternalChild = frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime) { FrameStablePlayback = FrameStablePlayback, Children = new Drawable[] { FrameStableComponents, - audioContainer = new AudioContainer - { - RelativeSizeAxes = Axes.Both, - Child = KeyBindingInputManager - .WithChildren(new Drawable[] - { - CreatePlayfieldAdjustmentContainer() - .WithChild(Playfield), - Overlays - }), - }, + audioContainer.WithChild(KeyBindingInputManager + .WithChildren(new Drawable[] + { + CreatePlayfieldAdjustmentContainer() + .WithChild(Playfield), + Overlays + })), } }; - Audio = audioContainer; - if ((ResumeOverlay = CreateResumeOverlay()) != null) { AddInternal(CreateInputManager() @@ -438,13 +426,21 @@ namespace osu.Game.Rulesets.UI /// public readonly BindableBool IsPaused = new BindableBool(); + /// + /// Audio adjustments which are applied to the playfield. + /// + /// + /// Does not affect . + /// + public abstract IAdjustableAudioComponent Audio { get; } + /// /// The playfield. /// public abstract Playfield Playfield { get; } /// - /// Content to be placed above hitobjects. Will be affected by frame stability. + /// Content to be placed above hitobjects. Will be affected by frame stability and adjustments applied to . /// public abstract Container Overlays { get; } From 9384687d6d38f02e98af67975b008abfde406167 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Feb 2023 19:04:06 +0900 Subject: [PATCH 388/516] Switch `ModMuted` to add its metronome to components rather than overlays --- osu.Game/Rulesets/Mods/ModMuted.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 367ceeb446..131f501630 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -67,7 +67,8 @@ namespace osu.Game.Rulesets.Mods { MetronomeBeat metronomeBeat; - drawableRuleset.Overlays.Add(metronomeBeat = new MetronomeBeat(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + // Importantly, this is added to FrameStableComponents and not Overlays as the latter would cause it to be self-muted by the mod's volume adjustment. + drawableRuleset.FrameStableComponents.Add(metronomeBeat = new MetronomeBeat(drawableRuleset.Beatmap.HitObjects.First().StartTime)); metronomeBeat.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); } From 90aa4288d0a9a265d666c8e66545108bce4d8edd Mon Sep 17 00:00:00 2001 From: Cootz Date: Tue, 21 Feb 2023 18:35:53 +0300 Subject: [PATCH 389/516] Reduce the allowed length by 5 to account for (99) suffix. Move truncating logic to `GetFilename`. Update tests. --- osu.Game.Tests/Database/LegacyExporterTest.cs | 9 ++++++--- osu.Game/Database/LegacyExporter.cs | 20 +++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs index c9aea80585..d41b3a5017 100644 --- a/osu.Game.Tests/Database/LegacyExporterTest.cs +++ b/osu.Game.Tests/Database/LegacyExporterTest.cs @@ -46,7 +46,7 @@ namespace osu.Game.Tests.Database Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH)); //Export multiple times - for (int i = 0; i < 10; i++) + for (int i = 0; i < 100; i++) { string expectedFileName = i == 0 ? short_filename : $"{short_filename} ({i})"; exportItemAndAssert(item, expectedFileName); @@ -76,8 +76,11 @@ namespace osu.Game.Tests.Database Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH)); //Export multiple times - for (int i = 0; i < 10; i++) - exportItemAndAssert(item, expectedName); + for (int i = 0; i < 100; i++) + { + string expectedFilename = i == 0 ? expectedName : $"{expectedName} ({i})"; + exportItemAndAssert(item, expectedFilename); + } } private void exportItemAndAssert(IHasNamedFiles item, string expectedName) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index cf88efb151..0fa7b9e03c 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -31,7 +31,7 @@ namespace osu.Game.Database /// For more information see file specification syntax, file systems limitations /// /// - public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars) + public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2 + 5); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars + account for ' (99)' suffix) /// /// The file extension for exports (including the leading '.'). @@ -48,7 +48,15 @@ namespace osu.Game.Database UserFileStorage = storage.GetStorageForDirectory(@"files"); } - protected virtual string GetFilename(TModel item) => item.GetDisplayString(); + protected virtual string GetFilename(TModel item) + { + string filename = item.GetDisplayString(); + + if (filename.Length > MAX_FILENAME_LENGTH - FileExtension.Length) + return filename.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); + + return filename; + } /// /// Exports an item to a legacy (.zip based) package. @@ -65,14 +73,6 @@ namespace osu.Game.Database string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}"); - if (filename.Length > MAX_FILENAME_LENGTH) - { - string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename); - - filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); - filename = $"{filenameWithoutExtension}{FileExtension}"; - } - using (var stream = exportStorage.CreateFileSafely(filename)) ExportModelTo(item, stream); From fc3d74472cc52b6e06cd1c0791f7277d7ed77744 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 21 Feb 2023 15:55:46 +0300 Subject: [PATCH 390/516] Add mobile local framework reference support --- UseLocalFramework.ps1 | 48 ++++++++++++++++++++++++++++++++++++++----- UseLocalFramework.sh | 39 +++++++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/UseLocalFramework.ps1 b/UseLocalFramework.ps1 index 837685f310..9f4547d980 100644 --- a/UseLocalFramework.ps1 +++ b/UseLocalFramework.ps1 @@ -3,15 +3,53 @@ # # https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects -$CSPROJ="osu.Game/osu.Game.csproj" +$GAME_CSPROJ="osu.Game/osu.Game.csproj" +$ANDROID_PROPS="osu.Android.props" +$IOS_PROPS="osu.iOS.props" $SLN="osu.sln" -dotnet remove $CSPROJ package ppy.osu.Framework; -dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj; -dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj +dotnet remove $GAME_CSPROJ reference ppy.osu.Framework; +dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android; +dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS; + +dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ` + ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj ` + ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj ` + ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj; + +dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj; +dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj; +dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj; + +# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files +(Get-Content "osu.Android.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.Android.props" +(Get-Content "osu.iOS.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.iOS.props" + +# needed because iOS framework nupkg includes a set of properties to work around certain issues during building, +# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference. +(Get-Content "osu.iOS.props") | + Foreach-Object { + if ($_ -match "") + { + " " + } + + $_ + } | Set-Content "osu.iOS.props" + +$TMP=New-TemporaryFile $SLNF=Get-Content "osu.Desktop.slnf" | ConvertFrom-Json -$TMP=New-TemporaryFile $SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj") ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8 Move-Item -Path $TMP -Destination "osu.Desktop.slnf" -Force + +$SLNF=Get-Content "osu.Android.slnf" | ConvertFrom-Json +$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj") +ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8 +Move-Item -Path $TMP -Destination "osu.Android.slnf" -Force + +$SLNF=Get-Content "osu.iOS.slnf" | ConvertFrom-Json +$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj") +ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8 +Move-Item -Path $TMP -Destination "osu.iOS.slnf" -Force diff --git a/UseLocalFramework.sh b/UseLocalFramework.sh index 4fd1fdfd1b..c12b388e96 100755 --- a/UseLocalFramework.sh +++ b/UseLocalFramework.sh @@ -5,14 +5,41 @@ # # https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects -CSPROJ="osu.Game/osu.Game.csproj" +GAME_CSPROJ="osu.Game/osu.Game.csproj" +ANDROID_PROPS="osu.Android.props" +IOS_PROPS="osu.iOS.props" SLN="osu.sln" -dotnet remove $CSPROJ package ppy.osu.Framework -dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj -dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj +dotnet remove $GAME_CSPROJ reference ppy.osu.Framework +dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android +dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS + +dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj \ + ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj \ + ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj \ + ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj + +dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj +dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj +dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj + +# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files +sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.Android.props && rm osu.Android.props.bak +sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.iOS.props && rm osu.iOS.props.bak + +# needed because iOS framework nupkg includes a set of properties to work around certain issues during building, +# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference. +sed -i.bak '/<\/Project>/i\ + \ +' ./osu.iOS.props && rm osu.iOS.props.bak -SLNF="osu.Desktop.slnf" tmp=$(mktemp) + jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj"]' osu.Desktop.slnf > $tmp -mv -f $tmp $SLNF +mv -f $tmp osu.Desktop.slnf + +jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj"]' osu.Android.slnf > $tmp +mv -f $tmp osu.Android.slnf + +jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj"]' osu.iOS.slnf > $tmp +mv -f $tmp osu.iOS.slnf From d59d153654f6543e2f51556454964c51bb9c8f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Feb 2023 21:03:00 +0100 Subject: [PATCH 391/516] Fix test compile failures from `Audio` hoisting --- osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs | 2 ++ osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs index 9a32b8e894..0bdd0ceae6 100644 --- a/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs +++ b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using NUnit.Framework; +using osu.Framework.Audio; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; @@ -93,6 +94,7 @@ namespace osu.Game.Tests.NonVisual remove => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); } + public override IAdjustableAudioComponent Audio { get; } public override Playfield Playfield { get; } public override Container Overlays { get; } public override Container FrameStableComponents { get; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index e2ff2780e0..56900a0549 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -281,6 +282,7 @@ namespace osu.Game.Tests.Visual.Gameplay remove => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); } + public override IAdjustableAudioComponent Audio { get; } public override Playfield Playfield { get; } public override Container Overlays { get; } public override Container FrameStableComponents { get; } From ab97b022355abdc2bfd33473d0f102af9d8baa62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Feb 2023 21:05:46 +0100 Subject: [PATCH 392/516] Remove contradictory remark from xmldoc --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 7d7361b9b6..df482a6459 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -429,9 +429,6 @@ namespace osu.Game.Rulesets.UI /// /// Audio adjustments which are applied to the playfield. /// - /// - /// Does not affect . - /// public abstract IAdjustableAudioComponent Audio { get; } /// From a511e64fa5badba12ca279f0f90409a52883e9d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Feb 2023 14:41:20 +0900 Subject: [PATCH 393/516] Seek using `GameplayClockContainer` --- .../Gameplay/TestSceneGameplaySampleTriggerSource.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index 7f4f1ed027..b30bef7c30 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -155,16 +155,16 @@ namespace osu.Game.Tests.Visual.Gameplay // This is because the (parent) object will only play its sample at the final EndTime. AddAssert("check valid object is slider's first nested", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4].NestedHitObjects.First())); - AddStep("seek to just before slider ends", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[4].GetEndTime() - 100)); + AddStep("seek to just before slider ends", () => Player.GameplayClockContainer.Seek(beatmap.HitObjects[4].GetEndTime() - 100)); waitForCatchUp(); AddUntilStep("wait until valid object is slider's last nested", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4].NestedHitObjects.Last())); // After we get far enough away, the samples of the object itself should be used, not any nested object. - AddStep("seek to further after slider", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[4].GetEndTime() + 1000)); + AddStep("seek to further after slider", () => Player.GameplayClockContainer.Seek(beatmap.HitObjects[4].GetEndTime() + 1000)); waitForCatchUp(); AddUntilStep("wait until valid object is slider itself", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[4])); - AddStep("Seek into future", () => Beatmap.Value.Track.Seek(beatmap.HitObjects.Last().GetEndTime() + 10000)); + AddStep("Seek into future", () => Player.GameplayClockContainer.Seek(beatmap.HitObjects.Last().GetEndTime() + 10000)); waitForCatchUp(); waitForAliveObjectIndex(null); checkValidObjectIndex(4); @@ -172,7 +172,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void seekBeforeIndex(int index) { - AddStep($"seek to just before object {index}", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[index].StartTime - 100)); + AddStep($"seek to just before object {index}", () => Player.GameplayClockContainer.Seek(beatmap.HitObjects[index].StartTime - 100)); waitForCatchUp(); } From f61fbcf3fc28ef676f7eb28d14e5a557100ef4bb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Feb 2023 15:26:09 +0900 Subject: [PATCH 394/516] Update assertion to also check `GameplayClockContainer`'s current time --- .../Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index b30bef7c30..31133f00d9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -177,7 +177,7 @@ namespace osu.Game.Tests.Visual.Gameplay } private void waitForCatchUp() => - AddUntilStep("wait for frame stable clock to catch up", () => Precision.AlmostEquals(Beatmap.Value.Track.CurrentTime, Player.DrawableRuleset.FrameStableClock.CurrentTime)); + AddUntilStep("wait for frame stable clock to catch up", () => Precision.AlmostEquals(Player.GameplayClockContainer.CurrentTime, Player.DrawableRuleset.FrameStableClock.CurrentTime)); private void waitForAliveObjectIndex(int? index) { From 16c8a392a1c7c73d0aeae9aa02edcd1a6e4d2f7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Feb 2023 17:45:38 +0900 Subject: [PATCH 395/516] Add ability to send selected skin components to front or back --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 37 ++++++++++++++++++- .../SkinEditor/SkinSelectionHandler.cs | 9 +++++ .../ISerialisableDrawableContainer.cs | 3 +- osu.Game/Skinning/SkinComponentsContainer.cs | 4 +- 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 9d470f58f1..95b88b141f 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -556,11 +556,46 @@ namespace osu.Game.Overlays.SkinEditor changeHandler?.BeginChange(); foreach (var item in items) - availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item); + availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item, true); changeHandler?.EndChange(); } + public void BringSelectionToFront() + { + if (getTarget(selectedTarget.Value) is not SkinComponentsContainer target) + return; + + // Iterating by target components order ensures we maintain the same order across selected components, regardless + // of the order they were selected in. + foreach (var d in target.Components.ToArray()) + { + if (!SelectedComponents.Contains(d)) + continue; + + target.Remove(d, false); + + // Selection would be reset by the remove. + SelectedComponents.Add(d); + target.Add(d); + } + } + + public void SendSelectionToBack() + { + if (getTarget(selectedTarget.Value) is not SkinComponentsContainer target) + return; + + foreach (var d in target.Components.ToArray()) + { + if (SelectedComponents.Contains(d)) + continue; + + target.Remove(d, false); + target.Add(d); + } + } + #region Drag & drop import handling public Task Import(params string[] paths) diff --git a/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs index c628ad8480..b43f4eeb00 100644 --- a/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs @@ -13,6 +13,7 @@ using osu.Framework.Utils; using osu.Game.Extensions; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; +using osu.Game.Screens.Edit.Components.Menus; using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Skinning; using osuTK; @@ -206,6 +207,14 @@ namespace osu.Game.Overlays.SkinEditor ((Drawable)blueprint.Item).Position = Vector2.Zero; }); + yield return new EditorMenuItemSpacer(); + + yield return new OsuMenuItem("Bring to front", MenuItemType.Standard, () => skinEditor.BringSelectionToFront()); + + yield return new OsuMenuItem("Send to back", MenuItemType.Standard, () => skinEditor.SendSelectionToBack()); + + yield return new EditorMenuItemSpacer(); + foreach (var item in base.GetContextMenuItemsForSelection(selection)) yield return item; diff --git a/osu.Game/Skinning/ISerialisableDrawableContainer.cs b/osu.Game/Skinning/ISerialisableDrawableContainer.cs index 9f93d8a2e3..a19c8c5162 100644 --- a/osu.Game/Skinning/ISerialisableDrawableContainer.cs +++ b/osu.Game/Skinning/ISerialisableDrawableContainer.cs @@ -45,6 +45,7 @@ namespace osu.Game.Skinning /// Remove an existing skinnable component from this target. /// /// The component to remove. - void Remove(ISerialisableDrawable component); + /// Whether removed items should be immediately disposed. + void Remove(ISerialisableDrawable component, bool disposeImmediately); } } diff --git a/osu.Game/Skinning/SkinComponentsContainer.cs b/osu.Game/Skinning/SkinComponentsContainer.cs index d18e9023cd..adf0a288b4 100644 --- a/osu.Game/Skinning/SkinComponentsContainer.cs +++ b/osu.Game/Skinning/SkinComponentsContainer.cs @@ -100,7 +100,7 @@ namespace osu.Game.Skinning /// /// Thrown when attempting to add an element to a target which is not supported by the current skin. /// Thrown if the provided instance is not a . - public void Remove(ISerialisableDrawable component) + public void Remove(ISerialisableDrawable component, bool disposeImmediately) { if (content == null) throw new NotSupportedException("Attempting to remove a new component from a target container which is not supported by the current skin."); @@ -108,7 +108,7 @@ namespace osu.Game.Skinning if (!(component is Drawable drawable)) throw new ArgumentException($"Provided argument must be of type {nameof(Drawable)}.", nameof(component)); - content.Remove(drawable, true); + content.Remove(drawable, disposeImmediately); components.Remove(component); } From 90ca635a1771d9953f3891656296b7b7d98dda84 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Feb 2023 17:56:59 +0900 Subject: [PATCH 396/516] Fix weird nullability in `TestSceneSkinEditor` --- .../Visual/Gameplay/TestSceneSkinEditor.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 2f20d75813..83609b9ae7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -4,6 +4,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; @@ -21,7 +22,7 @@ namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneSkinEditor : PlayerTestScene { - private SkinEditor? skinEditor; + private SkinEditor skinEditor = null!; protected override bool Autoplay => true; @@ -40,17 +41,18 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("reload skin editor", () => { - skinEditor?.Expire(); + if (skinEditor.IsNotNull()) + skinEditor.Expire(); Player.ScaleTo(0.4f); LoadComponentAsync(skinEditor = new SkinEditor(Player), Add); }); - AddUntilStep("wait for loaded", () => skinEditor!.IsLoaded); + AddUntilStep("wait for loaded", () => skinEditor.IsLoaded); } [Test] public void TestToggleEditor() { - AddToggleStep("toggle editor visibility", _ => skinEditor!.ToggleVisibility()); + AddToggleStep("toggle editor visibility", _ => skinEditor.ToggleVisibility()); } [Test] @@ -63,7 +65,7 @@ namespace osu.Game.Tests.Visual.Gameplay var blueprint = skinEditor.ChildrenOfType().First(b => b.Item is BarHitErrorMeter); hitErrorMeter = (BarHitErrorMeter)blueprint.Item; - skinEditor!.SelectedComponents.Clear(); + skinEditor.SelectedComponents.Clear(); skinEditor.SelectedComponents.Add(blueprint.Item); }); From 32a9c066dfd2a02c0cc40f5554417ab5bd8e8c97 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Feb 2023 18:17:03 +0900 Subject: [PATCH 397/516] Add test coverage of bring-to-front / send-to-back operations --- .../Visual/Gameplay/TestSceneSkinEditor.cs | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 83609b9ae7..9690d00d4c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -32,12 +33,14 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached] public readonly EditorClipboard Clipboard = new EditorClipboard(); + private SkinComponentsContainer targetContainer => Player.ChildrenOfType().First(); + [SetUpSteps] public override void SetUpSteps() { base.SetUpSteps(); - AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); + AddUntilStep("wait for hud load", () => targetContainer.ComponentsLoaded); AddStep("reload skin editor", () => { @@ -49,6 +52,52 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for loaded", () => skinEditor.IsLoaded); } + [TestCase(false)] + [TestCase(true)] + public void TestBringToFront(bool alterSelectionOrder) + { + AddAssert("Ensure over three components available", () => targetContainer.Components.Count, () => Is.GreaterThan(3)); + + IEnumerable originalOrder = null!; + + AddStep("Save order of components before operation", () => originalOrder = targetContainer.Components.Take(3).ToArray()); + + if (alterSelectionOrder) + AddStep("Select first three components in reverse order", () => skinEditor.SelectedComponents.AddRange(originalOrder.Reverse())); + else + AddStep("Select first three components", () => skinEditor.SelectedComponents.AddRange(originalOrder)); + + AddAssert("Components are not front-most", () => targetContainer.Components.TakeLast(3).ToArray(), () => Is.Not.EqualTo(skinEditor.SelectedComponents)); + + AddStep("Bring to front", () => skinEditor.BringSelectionToFront()); + AddAssert("Ensure components are now front-most in original order", () => targetContainer.Components.TakeLast(3).ToArray(), () => Is.EqualTo(originalOrder)); + AddStep("Bring to front again", () => skinEditor.BringSelectionToFront()); + AddAssert("Ensure components are still front-most in original order", () => targetContainer.Components.TakeLast(3).ToArray(), () => Is.EqualTo(originalOrder)); + } + + [TestCase(false)] + [TestCase(true)] + public void TestSendToBack(bool alterSelectionOrder) + { + AddAssert("Ensure over three components available", () => targetContainer.Components.Count, () => Is.GreaterThan(3)); + + IEnumerable originalOrder = null!; + + AddStep("Save order of components before operation", () => originalOrder = targetContainer.Components.TakeLast(3).ToArray()); + + if (alterSelectionOrder) + AddStep("Select last three components in reverse order", () => skinEditor.SelectedComponents.AddRange(originalOrder.Reverse())); + else + AddStep("Select last three components", () => skinEditor.SelectedComponents.AddRange(originalOrder)); + + AddAssert("Components are not back-most", () => targetContainer.Components.Take(3).ToArray(), () => Is.Not.EqualTo(skinEditor.SelectedComponents)); + + AddStep("Send to back", () => skinEditor.SendSelectionToBack()); + AddAssert("Ensure components are now back-most in original order", () => targetContainer.Components.Take(3).ToArray(), () => Is.EqualTo(originalOrder)); + AddStep("Send to back again", () => skinEditor.SendSelectionToBack()); + AddAssert("Ensure components are still back-most in original order", () => targetContainer.Components.Take(3).ToArray(), () => Is.EqualTo(originalOrder)); + } + [Test] public void TestToggleEditor() { From c48aceb055433f57bd00d885691d8a61e8317460 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Feb 2023 20:03:36 +0900 Subject: [PATCH 398/516] Fix undo history not being batched correctly for depth change operations --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 95b88b141f..02ede8c08b 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -566,6 +566,8 @@ namespace osu.Game.Overlays.SkinEditor if (getTarget(selectedTarget.Value) is not SkinComponentsContainer target) return; + changeHandler?.BeginChange(); + // Iterating by target components order ensures we maintain the same order across selected components, regardless // of the order they were selected in. foreach (var d in target.Components.ToArray()) @@ -579,6 +581,8 @@ namespace osu.Game.Overlays.SkinEditor SelectedComponents.Add(d); target.Add(d); } + + changeHandler?.EndChange(); } public void SendSelectionToBack() @@ -586,6 +590,8 @@ namespace osu.Game.Overlays.SkinEditor if (getTarget(selectedTarget.Value) is not SkinComponentsContainer target) return; + changeHandler?.BeginChange(); + foreach (var d in target.Components.ToArray()) { if (SelectedComponents.Contains(d)) @@ -594,6 +600,8 @@ namespace osu.Game.Overlays.SkinEditor target.Remove(d, false); target.Add(d); } + + changeHandler?.EndChange(); } #region Drag & drop import handling From dc3c1150b8401b4f4d49b1ecb6c8ba30663fe217 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Feb 2023 21:10:15 +0900 Subject: [PATCH 399/516] Set better defaults for `SkinBlueprint` transforms --- osu.Game/Overlays/SkinEditor/SkinBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs index 034ca11c5c..c090878899 100644 --- a/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs +++ b/osu.Game/Overlays/SkinEditor/SkinBlueprint.cs @@ -82,6 +82,7 @@ namespace osu.Game.Overlays.SkinEditor { Text = Item.GetType().Name, Font = OsuFont.Default.With(size: 10, weight: FontWeight.Bold), + Alpha = 0, Anchor = Anchor.BottomRight, Origin = Anchor.TopRight, }, @@ -99,7 +100,6 @@ namespace osu.Game.Overlays.SkinEditor base.LoadComplete(); updateSelectedState(); - this.FadeInFromZero(200, Easing.OutQuint); } protected override bool OnHover(HoverEvent e) From dd9748a25cb3d29537b3abf01a382a9f2be2d7e9 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 25 Feb 2023 01:21:37 +0900 Subject: [PATCH 400/516] Adjust DrawNodes to use UBOs --- .../UI/Cursor/CursorTrail.cs | 22 ++++++++++++-- .../TestSceneTriangleBorderShader.cs | 19 ++++++++++-- .../Backgrounds/TriangleBorderData.cs | 16 ++++++++++ osu.Game/Graphics/Backgrounds/Triangles.cs | 17 +++++++---- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 13 ++++++-- osu.Game/Graphics/Sprites/LogoAnimation.cs | 22 +++++++++++++- osu.Game/Rulesets/Mods/ModFlashlight.cs | 30 +++++++++++++++---- 7 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 osu.Game/Graphics/Backgrounds/TriangleBorderData.cs diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 9ecabd1d5e..a29faac5a0 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Shaders.Types; using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Events; @@ -255,15 +256,23 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor Source.parts.CopyTo(parts, 0); } + private IUniformBuffer cursorTrailParameters; + public override void Draw(IRenderer renderer) { base.Draw(renderer); vertexBatch ??= renderer.CreateQuadBatch(max_sprites, 1); + cursorTrailParameters ??= renderer.CreateUniformBuffer(); + cursorTrailParameters.Data = cursorTrailParameters.Data with + { + FadeClock = time, + FadeExponent = fadeExponent + }; + shader.Bind(); - shader.GetUniform("g_FadeClock").UpdateValue(ref time); - shader.GetUniform("g_FadeExponent").UpdateValue(ref fadeExponent); + shader.BindUniformBlock("m_CursorTrailParameters", cursorTrailParameters); texture.Bind(); @@ -323,6 +332,15 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor base.Dispose(isDisposing); vertexBatch?.Dispose(); + cursorTrailParameters?.Dispose(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct CursorTrailParameters + { + public UniformFloat FadeClock; + public UniformFloat FadeExponent; + private readonly UniformPadding8 pad1; } } diff --git a/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs index 271642edd1..07427c242f 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs @@ -9,6 +9,7 @@ using osuTK; using osuTK.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Rendering; +using osu.Game.Graphics.Backgrounds; namespace osu.Game.Tests.Visual.Background { @@ -97,15 +98,29 @@ namespace osu.Game.Tests.Visual.Background texelSize = Source.texelSize; } + private IUniformBuffer? borderDataBuffer; + public override void Draw(IRenderer renderer) { - TextureShader.GetUniform("thickness").UpdateValue(ref thickness); - TextureShader.GetUniform("texelSize").UpdateValue(ref texelSize); + borderDataBuffer ??= renderer.CreateUniformBuffer(); + borderDataBuffer.Data = borderDataBuffer.Data with + { + Thickness = thickness, + TexelSize = texelSize + }; + + TextureShader.BindUniformBlock("m_BorderData", borderDataBuffer); base.Draw(renderer); } protected override bool CanDrawOpaqueInterior => false; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + borderDataBuffer?.Dispose(); + } } } } diff --git a/osu.Game/Graphics/Backgrounds/TriangleBorderData.cs b/osu.Game/Graphics/Backgrounds/TriangleBorderData.cs new file mode 100644 index 0000000000..f4d327dc8e --- /dev/null +++ b/osu.Game/Graphics/Backgrounds/TriangleBorderData.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Runtime.InteropServices; +using osu.Framework.Graphics.Shaders.Types; + +namespace osu.Game.Graphics.Backgrounds +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public record struct TriangleBorderData + { + public UniformFloat Thickness; + public UniformFloat TexelSize; + private readonly UniformPadding8 pad1; + } +} diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 68ece56d8a..f3ebdd875a 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -284,6 +284,8 @@ namespace osu.Game.Graphics.Backgrounds parts.AddRange(Source.parts); } + private IUniformBuffer borderDataBuffer; + public override void Draw(IRenderer renderer) { base.Draw(renderer); @@ -294,14 +296,16 @@ namespace osu.Game.Graphics.Backgrounds vertexBatch = renderer.CreateQuadBatch(Source.AimCount, 1); } - // Due to triangles having various sizes we would need to set a different "texelSize" value for each of them, which is insanely expensive, thus we should use one single value. - // texelSize computed for an average triangle (size 100) will result in big triangles becoming blurry, so we may just use 0 for all of them. - // But we still need to specify at least something, because otherwise other shader usages will override this value. - float texelSize = 0f; + borderDataBuffer ??= renderer.CreateUniformBuffer(); + borderDataBuffer.Data = borderDataBuffer.Data with + { + Thickness = fill, + // Due to triangles having various sizes we would need to set a different "TexelSize" value for each of them, which is insanely expensive, thus we should use one single value. + // TexelSize computed for an average triangle (size 100) will result in big triangles becoming blurry, so we may just use 0 for all of them. + TexelSize = 0 + }; shader.Bind(); - shader.GetUniform("thickness").UpdateValue(ref fill); - shader.GetUniform("texelSize").UpdateValue(ref texelSize); foreach (TriangleParticle particle in parts) { @@ -352,6 +356,7 @@ namespace osu.Game.Graphics.Backgrounds base.Dispose(isDisposing); vertexBatch?.Dispose(); + borderDataBuffer?.Dispose(); } } diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 3bc8bb6df1..b108649ce4 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -227,6 +227,8 @@ namespace osu.Game.Graphics.Backgrounds parts.AddRange(Source.parts); } + private IUniformBuffer? borderDataBuffer; + public override void Draw(IRenderer renderer) { base.Draw(renderer); @@ -240,9 +242,15 @@ namespace osu.Game.Graphics.Backgrounds vertexBatch = renderer.CreateQuadBatch(Source.AimCount, 1); } + borderDataBuffer ??= renderer.CreateUniformBuffer(); + borderDataBuffer.Data = borderDataBuffer.Data with + { + Thickness = thickness, + TexelSize = texelSize + }; + shader.Bind(); - shader.GetUniform("thickness").UpdateValue(ref thickness); - shader.GetUniform("texelSize").UpdateValue(ref texelSize); + shader.BindUniformBlock("m_BorderData", borderDataBuffer); Vector2 relativeSize = Vector2.Divide(triangleSize, size); @@ -303,6 +311,7 @@ namespace osu.Game.Graphics.Backgrounds base.Dispose(isDisposing); vertexBatch?.Dispose(); + borderDataBuffer?.Dispose(); } } diff --git a/osu.Game/Graphics/Sprites/LogoAnimation.cs b/osu.Game/Graphics/Sprites/LogoAnimation.cs index e177cc604b..220f57e9fa 100644 --- a/osu.Game/Graphics/Sprites/LogoAnimation.cs +++ b/osu.Game/Graphics/Sprites/LogoAnimation.cs @@ -3,10 +3,12 @@ #nullable disable +using System.Runtime.InteropServices; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Shaders.Types; using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.Sprites @@ -55,14 +57,32 @@ namespace osu.Game.Graphics.Sprites progress = source.animationProgress; } + private IUniformBuffer animationDataBuffer; + protected override void Blit(IRenderer renderer) { - TextureShader.GetUniform("progress").UpdateValue(ref progress); + animationDataBuffer ??= renderer.CreateUniformBuffer(); + animationDataBuffer.Data = animationDataBuffer.Data with { Progress = progress }; + + TextureShader.BindUniformBlock("m_AnimationData", animationDataBuffer); base.Blit(renderer); } protected override bool CanDrawOpaqueInterior => false; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + animationDataBuffer?.Dispose(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct AnimationData + { + public UniformFloat Progress; + private readonly UniformPadding12 pad1; + } } } } diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 45fa55c7f2..d1446444bf 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Runtime.InteropServices; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -9,6 +10,7 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Shaders.Types; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Configuration; @@ -245,6 +247,8 @@ namespace osu.Game.Rulesets.Mods flashlightSmoothness = Source.flashlightSmoothness; } + private IUniformBuffer? flashlightParametersBuffer; + public override void Draw(IRenderer renderer) { base.Draw(renderer); @@ -259,12 +263,17 @@ namespace osu.Game.Rulesets.Mods }); } - shader.Bind(); + flashlightParametersBuffer ??= renderer.CreateUniformBuffer(); + flashlightParametersBuffer.Data = flashlightParametersBuffer.Data with + { + Position = flashlightPosition, + Size = flashlightSize, + Dim = flashlightDim, + Smoothness = flashlightSmoothness + }; - shader.GetUniform("flashlightPos").UpdateValue(ref flashlightPosition); - shader.GetUniform("flashlightSize").UpdateValue(ref flashlightSize); - shader.GetUniform("flashlightDim").UpdateValue(ref flashlightDim); - shader.GetUniform("flashlightSmoothness").UpdateValue(ref flashlightSmoothness); + shader.Bind(); + shader.BindUniformBlock("m_FlashlightParameters", flashlightParametersBuffer); renderer.DrawQuad(renderer.WhitePixel, screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: addAction); @@ -275,6 +284,17 @@ namespace osu.Game.Rulesets.Mods { base.Dispose(isDisposing); quadBatch?.Dispose(); + flashlightParametersBuffer?.Dispose(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct FlashlightParameters + { + public UniformVector2 Position; + public UniformVector2 Size; + public UniformFloat Dim; + public UniformFloat Smoothness; + private readonly UniformPadding8 pad1; } } } From 069b77dd23ffc9aaa04ebd1995f9fd37f1a1c076 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 25 Feb 2023 02:15:56 +0900 Subject: [PATCH 401/516] Update language version --- osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj | 1 + osu.Game/osu.Game.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index bf776fe5dd..75656e2976 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -4,6 +4,7 @@ Library true click the circles. to the beat. + 10 diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 65ea301cbd..c5001cdc93 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -3,6 +3,7 @@ net6.0 Library true + 10 osu! From a44c9d10d77047669db8e67f474c4427f1afe4db Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 25 Feb 2023 02:18:40 +0900 Subject: [PATCH 402/516] Fix buffer not being bound --- osu.Game/Graphics/Backgrounds/Triangles.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index f3ebdd875a..5b7b94ff4c 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -306,6 +306,7 @@ namespace osu.Game.Graphics.Backgrounds }; shader.Bind(); + shader.BindUniformBlock("m_BorderData", borderDataBuffer); foreach (TriangleParticle particle in parts) { From a705698ab64c7cfe63c82f7be048ed03de54aed8 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Sun, 26 Feb 2023 21:13:05 +0900 Subject: [PATCH 403/516] beatmapset that already deletePending should not be fetched --- osu.Game/Scoring/Legacy/DatabasedLegacyScoreDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Scoring/Legacy/DatabasedLegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/DatabasedLegacyScoreDecoder.cs index 8908163646..8ee2cc6241 100644 --- a/osu.Game/Scoring/Legacy/DatabasedLegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/DatabasedLegacyScoreDecoder.cs @@ -24,6 +24,6 @@ namespace osu.Game.Scoring.Legacy } protected override Ruleset GetRuleset(int rulesetId) => rulesets.GetRuleset(rulesetId)?.CreateInstance(); - protected override WorkingBeatmap GetBeatmap(string md5Hash) => beatmaps.GetWorkingBeatmap(beatmaps.QueryBeatmap(b => b.MD5Hash == md5Hash)); + protected override WorkingBeatmap GetBeatmap(string md5Hash) => beatmaps.GetWorkingBeatmap(beatmaps.QueryBeatmap(b => b.MD5Hash == md5Hash && !b.BeatmapSet.DeletePending)); } } From ff0d1aa9f704560a96f6a3f1d048d44f70e33af8 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sun, 26 Feb 2023 20:38:50 +0100 Subject: [PATCH 404/516] Make reverting changes to a given skin into a "dangerous action" --- osu.Game/Localisation/SkinEditorStrings.cs | 12 +++++++- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 32 +++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/SkinEditorStrings.cs b/osu.Game/Localisation/SkinEditorStrings.cs index 5cf2e5b5c5..029d50df32 100644 --- a/osu.Game/Localisation/SkinEditorStrings.cs +++ b/osu.Game/Localisation/SkinEditorStrings.cs @@ -42,7 +42,17 @@ namespace osu.Game.Localisation /// /// "Currently editing" /// - public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), "Currently editing"); + public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), @"Currently editing"); + + /// + /// "Revert?" + /// + public static LocalisableString Revert => new TranslatableString(getKey(@"revert"), @"Revert?"); + + /// + /// "The skin will return to the state it was in upon import" + /// + public static LocalisableString ResetDialogue => new TranslatableString(getKey(@"the_skin_will_return_to"), @"The skin will return to the state it was in upon import"); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 9d470f58f1..936dc7fa84 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -12,11 +12,13 @@ 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.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using web = osu.Game.Resources.Localisation.Web; using osu.Framework.Testing; using osu.Game.Database; using osu.Game.Graphics; @@ -24,6 +26,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; +using osu.Game.Overlays.Dialog; using osu.Game.Overlays.OSD; using osu.Game.Overlays.Settings; using osu.Game.Screens.Edit; @@ -97,6 +100,9 @@ namespace osu.Game.Overlays.SkinEditor [Resolved] private OnScreenDisplay? onScreenDisplay { get; set; } + [Resolved] + private IDialogOverlay? dialogOverlay { get; set; } + public SkinEditor() { } @@ -148,7 +154,7 @@ namespace osu.Game.Overlays.SkinEditor Items = new[] { new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), - new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, revert), + new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, () => dialogOverlay?.Push(new ResetConfirmDialog(revert))), new EditorMenuItemSpacer(), new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()), }, @@ -625,6 +631,30 @@ namespace osu.Game.Overlays.SkinEditor } } + public partial class ResetConfirmDialog : PopupDialog + { + public ResetConfirmDialog(Action reset) + { + HeaderText = SkinEditorStrings.Revert; + BodyText = SkinEditorStrings.ResetDialogue; + + Icon = FontAwesome.Solid.ExclamationTriangle; + + Buttons = new PopupDialogButton[] + { + new PopupDialogDangerousButton + { + Text = BeatmapOverlayStrings.UserContentConfirmButtonText, + Action = reset + }, + new PopupDialogCancelButton + { + Text = web.CommonStrings.ButtonsCancel, + }, + }; + } + } + #region Delegation of IEditorChangeHandler public event Action? OnStateChange From d98d330da20e2bced3a4d753f40c6a50f614f926 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 26 Feb 2023 14:30:46 -0800 Subject: [PATCH 405/516] Add expected behavior test for scroll back to previous position --- .../TestSceneOverlayScrollContainer.cs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs index 926bc01aea..ade950e2d5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs @@ -61,6 +61,18 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("scroll to 500", () => scroll.ScrollTo(500)); AddUntilStep("scrolled to 500", () => Precision.AlmostEquals(scroll.Current, 500, 0.1f)); AddAssert("button is visible", () => scroll.Button.State == Visibility.Visible); + + AddStep("click button", () => + { + InputManager.MoveMouseTo(scroll.Button); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("button is visible", () => scroll.Button.State == Visibility.Visible); + + AddStep("user scroll down by 1", () => InputManager.ScrollVerticalBy(-1)); + + AddAssert("button is hidden", () => scroll.Button.State == Visibility.Hidden); } [Test] @@ -71,6 +83,10 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("invoke action", () => scroll.Button.Action.Invoke()); AddUntilStep("scrolled back to start", () => Precision.AlmostEquals(scroll.Current, 0, 0.1f)); + + AddStep("invoke action", () => scroll.Button.Action.Invoke()); + + AddAssert("scrolled to end", () => scroll.IsScrolledToEnd()); } [Test] @@ -85,6 +101,14 @@ namespace osu.Game.Tests.Visual.UserInterface }); AddUntilStep("scrolled back to start", () => Precision.AlmostEquals(scroll.Current, 0, 0.1f)); + + AddStep("click button", () => + { + InputManager.MoveMouseTo(scroll.Button); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("scrolled to end", () => scroll.IsScrolledToEnd()); } [Test] @@ -97,7 +121,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("hover button", () => InputManager.MoveMouseTo(scroll.Button)); AddRepeatStep("click button", () => InputManager.Click(MouseButton.Left), 3); - AddAssert("invocation count is 1", () => invocationCount == 1); + AddAssert("invocation count is 3", () => invocationCount == 3); } private partial class TestScrollContainer : OverlayScrollContainer From dc00905f8df0b24f974315a7efdac099373f09eb Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 26 Feb 2023 14:38:51 -0800 Subject: [PATCH 406/516] Add ability to scroll back to previous position after scrolling to top via button on overlays --- osu.Game/Overlays/OverlayScrollContainer.cs | 50 +++++++++++++++++---- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/OverlayScrollContainer.cs b/osu.Game/Overlays/OverlayScrollContainer.cs index 5bd7f014a9..8176ddb370 100644 --- a/osu.Game/Overlays/OverlayScrollContainer.cs +++ b/osu.Game/Overlays/OverlayScrollContainer.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -30,16 +31,20 @@ namespace osu.Game.Overlays /// private const int button_scroll_position = 200; - protected readonly ScrollToTopButton Button; + protected ScrollToTopButton Button; - public OverlayScrollContainer() + private readonly Bindable lastScrollTarget = new Bindable(); + + [BackgroundDependencyLoader] + private void load() { AddInternal(Button = new ScrollToTopButton { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, Margin = new MarginPadding(20), - Action = scrollToTop + Action = scrollBack, + LastScrollTarget = { BindTarget = lastScrollTarget } }); } @@ -53,13 +58,28 @@ namespace osu.Game.Overlays return; } - Button.State = Target > button_scroll_position ? Visibility.Visible : Visibility.Hidden; + Button.State = Target > button_scroll_position || lastScrollTarget.Value != null ? Visibility.Visible : Visibility.Hidden; } - private void scrollToTop() + protected override void OnUserScroll(float value, bool animated = true, double? distanceDecay = default) { - ScrollToStart(); - Button.State = Visibility.Hidden; + base.OnUserScroll(value, animated, distanceDecay); + + lastScrollTarget.Value = null; + } + + private void scrollBack() + { + if (lastScrollTarget.Value == null) + { + lastScrollTarget.Value = Target; + ScrollToStart(); + } + else + { + ScrollTo(lastScrollTarget.Value.Value); + lastScrollTarget.Value = null; + } } public partial class ScrollToTopButton : OsuHoverContainer @@ -88,6 +108,9 @@ namespace osu.Game.Overlays private readonly Container content; private readonly Box background; + private readonly SpriteIcon spriteIcon; + + public Bindable LastScrollTarget = new Bindable(); public ScrollToTopButton() : base(HoverSampleSet.ScrollToTop) @@ -113,7 +136,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both }, - new SpriteIcon + spriteIcon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -134,6 +157,17 @@ namespace osu.Game.Overlays flashColour = colourProvider.Light1; } + protected override void LoadComplete() + { + base.LoadComplete(); + + LastScrollTarget.BindValueChanged(target => + { + spriteIcon.RotateTo(target.NewValue != null ? 180 : 0, fade_duration, Easing.OutQuint); + TooltipText = target.NewValue != null ? CommonStrings.ButtonsBackToPrevious : CommonStrings.ButtonsBackToTop; + }, true); + } + protected override bool OnClick(ClickEvent e) { background.FlashColour(flashColour, 800, Easing.OutQuint); From fa710ae1b00dd9f618e481271b25aa2df5d558a4 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 26 Feb 2023 14:39:34 -0800 Subject: [PATCH 407/516] Rename `ScrollToTopButton` to `ScrollBackButton` --- .../UserInterface/TestSceneOverlayScrollContainer.cs | 2 +- osu.Game/Overlays/OverlayScrollContainer.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs index ade950e2d5..77e7178c9e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Visual.UserInterface private partial class TestScrollContainer : OverlayScrollContainer { - public new ScrollToTopButton Button => base.Button; + public new ScrollBackButton Button => base.Button; } } } diff --git a/osu.Game/Overlays/OverlayScrollContainer.cs b/osu.Game/Overlays/OverlayScrollContainer.cs index 8176ddb370..9752e04f44 100644 --- a/osu.Game/Overlays/OverlayScrollContainer.cs +++ b/osu.Game/Overlays/OverlayScrollContainer.cs @@ -22,23 +22,23 @@ using osuTK.Graphics; namespace osu.Game.Overlays { /// - /// which provides . Mostly used in . + /// which provides . Mostly used in . /// public partial class OverlayScrollContainer : UserTrackingScrollContainer { /// - /// Scroll position at which the will be shown. + /// Scroll position at which the will be shown. /// private const int button_scroll_position = 200; - protected ScrollToTopButton Button; + protected ScrollBackButton Button; private readonly Bindable lastScrollTarget = new Bindable(); [BackgroundDependencyLoader] private void load() { - AddInternal(Button = new ScrollToTopButton + AddInternal(Button = new ScrollBackButton { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, @@ -82,7 +82,7 @@ namespace osu.Game.Overlays } } - public partial class ScrollToTopButton : OsuHoverContainer + public partial class ScrollBackButton : OsuHoverContainer { private const int fade_duration = 500; @@ -112,7 +112,7 @@ namespace osu.Game.Overlays public Bindable LastScrollTarget = new Bindable(); - public ScrollToTopButton() + public ScrollBackButton() : base(HoverSampleSet.ScrollToTop) { Size = new Vector2(50); From 2b9d13cfee0e3c7fc46a2bf9d25077e75e01f02d Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 26 Feb 2023 20:58:20 -0300 Subject: [PATCH 408/516] Add group badges to list view --- .../Visual/Online/TestSceneFriendDisplay.cs | 17 +++++++++++++++-- .../Profile/Header/Components/GroupBadgeFlow.cs | 6 ++++++ osu.Game/Users/ExtendedUserPanel.cs | 8 ++++++++ osu.Game/Users/UserListPanel.cs | 5 +++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs index 7925b252b6..5028a532b7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs @@ -56,7 +56,13 @@ namespace osu.Game.Tests.Visual.Online IsOnline = true, Statistics = new UserStatistics { GlobalRank = 1111 }, CountryCode = CountryCode.JP, - CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" + CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c6.jpg", + IsSupporter = true, + SupportLevel = 1, + Groups = new[] + { + new APIUserGroup { Colour = "#EB47D0", ShortName = "DEV", Name = "Developers" } + } }, new APIUser { @@ -68,6 +74,11 @@ namespace osu.Game.Tests.Visual.Online CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", IsSupporter = true, SupportLevel = 3, + Groups = new[] + { + new APIUserGroup { Colour = "#0066FF", ShortName = "PPY", Name = "peppy" }, + new APIUserGroup { Colour = "#EB47D0", ShortName = "DEV", Name = "Developers" } + } }, new APIUser { @@ -76,7 +87,9 @@ namespace osu.Game.Tests.Visual.Online CountryCode = CountryCode.BY, CoverUrl = "https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg", IsOnline = false, - LastVisit = DateTimeOffset.Now + LastVisit = DateTimeOffset.Now, + IsSupporter = true, + SupportLevel = 2 } }; } diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadgeFlow.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadgeFlow.cs index 33b3de94db..2498543b11 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadgeFlow.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadgeFlow.cs @@ -25,8 +25,14 @@ namespace osu.Game.Overlays.Profile.Header.Components Clear(true); if (user.NewValue?.Groups != null) + { AddRange(user.NewValue.Groups.Select(g => new GroupBadge(g))); + Show(); + } + else + Hide(); }); + } } } diff --git a/osu.Game/Users/ExtendedUserPanel.cs b/osu.Game/Users/ExtendedUserPanel.cs index 3c1b68f9ef..af4da22906 100644 --- a/osu.Game/Users/ExtendedUserPanel.cs +++ b/osu.Game/Users/ExtendedUserPanel.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Users.Drawables; using osu.Framework.Input.Events; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.Profile.Header.Components; namespace osu.Game.Users { @@ -97,6 +98,13 @@ namespace osu.Game.Users return statusContainer; } + protected FillFlowContainer CreateGroupBadges() + { + var groupBadgeFlow = new GroupBadgeFlow(); + groupBadgeFlow.User.Value = User; + return groupBadgeFlow; + } + private void displayStatus(UserStatus status, UserActivity activity = null) { if (status != null) diff --git a/osu.Game/Users/UserListPanel.cs b/osu.Game/Users/UserListPanel.cs index bbd3c60a33..ebe58c2b93 100644 --- a/osu.Game/Users/UserListPanel.cs +++ b/osu.Game/Users/UserListPanel.cs @@ -67,6 +67,11 @@ namespace osu.Game.Users { username.Anchor = Anchor.CentreLeft; username.Origin = Anchor.CentreLeft; + }), + CreateGroupBadges().With(badges => + { + badges.Anchor = Anchor.CentreLeft; + badges.Origin = Anchor.CentreLeft; }) } }, From d722e09b2cc2840edfc540e9b52de00370930fe3 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 26 Feb 2023 21:05:41 -0300 Subject: [PATCH 409/516] oops --- osu.Game/Overlays/Profile/Header/Components/GroupBadgeFlow.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadgeFlow.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadgeFlow.cs index 2498543b11..4d4b16d7f5 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadgeFlow.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadgeFlow.cs @@ -32,7 +32,6 @@ namespace osu.Game.Overlays.Profile.Header.Components else Hide(); }); - } } } From 17a05de107f15a3336b3410ce87c4c276e22f2ac Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 13 Feb 2023 21:25:52 +0000 Subject: [PATCH 410/516] Initial Taiko single tap implementation (still needs code to allow for Strong hits) --- .../Mods/InputBlockingMod.cs | 131 ++++++++++++++++++ .../Mods/TaikoModSingleTap.cs | 16 +++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 1 + 3 files changed, 148 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs create mode 100644 osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs diff --git a/osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs b/osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs new file mode 100644 index 0000000000..c815d62336 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs @@ -0,0 +1,131 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play; +using osu.Game.Utils; +using osu.Game.Rulesets.Taiko.Mods; +using osu.Game.Rulesets.Taiko; + +namespace osu.Game.Rulesets.Taiko.Mods +{ + public abstract partial class InputBlockingMod : Mod, IApplicableToDrawableRuleset, IUpdatableByPlayfield + { + public override double ScoreMultiplier => 1.0; + public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax), typeof(TaikoModCinema) }; + public override ModType Type => ModType.Conversion; + + private const double flash_duration = 1000; + + private DrawableRuleset ruleset = null!; + + protected TaikoAction? LastAcceptedDonAction { get; private set; } + protected TaikoAction? LastAcceptedKatAction { get; private set; } + + /// + /// A tracker for periods where alternate should not be forced (i.e. non-gameplay periods). + /// + /// + /// This is different from in that the periods here end strictly at the first object after the break, rather than the break's end time. + /// + private PeriodTracker nonGameplayPeriods = null!; + + private IFrameStableClock gameplayClock = null!; + + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + ruleset = drawableRuleset; + drawableRuleset.KeyBindingInputManager.Add(new InputInterceptor(this)); + + var periods = new List(); + + if (drawableRuleset.Objects.Any()) + { + periods.Add(new Period(int.MinValue, getValidJudgementTime(ruleset.Objects.First()) - 1)); + + foreach (BreakPeriod b in drawableRuleset.Beatmap.Breaks) + periods.Add(new Period(b.StartTime, getValidJudgementTime(ruleset.Objects.First(h => h.StartTime >= b.EndTime)) - 1)); + + static double getValidJudgementTime(HitObject hitObject) => hitObject.StartTime - hitObject.HitWindows.WindowFor(HitResult.Meh); + } + + nonGameplayPeriods = new PeriodTracker(periods); + + gameplayClock = drawableRuleset.FrameStableClock; + } + + public void Update(Playfield playfield) + { + if (nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) + { + if (LastAcceptedDonAction != null) + LastAcceptedDonAction = null; + + if (LastAcceptedKatAction != null) + LastAcceptedKatAction = null; + } + } + + protected abstract bool CheckValidNewAction(TaikoAction action); + + private bool checkCorrectAction(TaikoAction action) + { + if (nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) + return true; + + switch (action) + { + case TaikoAction.LeftCentre: + case TaikoAction.RightCentre: + case TaikoAction.LeftRim: + case TaikoAction.RightRim: + break; + + // Any action which is not left or right button should be ignored. + default: + return true; + } + + if (CheckValidNewAction(action)) + { + if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) + LastAcceptedDonAction = action; + if (action == TaikoAction.LeftRim || action == TaikoAction.RightRim) + LastAcceptedKatAction = action; + return true; + } + + //ruleset.Cursor.FlashColour(Colour4.Red, flash_duration, Easing.OutQuint); + return false; + } + + private partial class InputInterceptor : Component, IKeyBindingHandler + { + private readonly InputBlockingMod mod; + + public InputInterceptor(InputBlockingMod mod) + { + this.mod = mod; + } + + public bool OnPressed(KeyBindingPressEvent e) + // if the pressed action is incorrect, block it from reaching gameplay. + => !mod.checkCorrectAction(e.Action); + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs new file mode 100644 index 0000000000..20c37fcb71 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Rulesets.Taiko.Mods +{ + public class TaikoModSingleTap : InputBlockingMod + { + public override string Name => @"Single Tap"; + public override string Acronym => @"SG"; + public override LocalisableString Description => @"You must only use one key!"; + + protected override bool CheckValidNewAction(TaikoAction action) => LastAcceptedDonAction == null || LastAcceptedDonAction == action || LastAcceptedKatAction == null || LastAcceptedKatAction == action; + } +} diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 4f435e73b3..a35fdb890d 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -158,6 +158,7 @@ namespace osu.Game.Rulesets.Taiko new TaikoModDifficultyAdjust(), new TaikoModClassic(), new TaikoModSwap(), + new TaikoModSingleTap(), }; case ModType.Automation: From 715df42a690ca1d33792f8be5b1d0e860c700d77 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Sun, 26 Feb 2023 22:22:45 +0000 Subject: [PATCH 411/516] Strong hits are now allowed to be hit --- osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs b/osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs index c815d62336..7613ce7c67 100644 --- a/osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs +++ b/osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs @@ -15,8 +15,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osu.Game.Utils; -using osu.Game.Rulesets.Taiko.Mods; -using osu.Game.Rulesets.Taiko; +using osu.Game.Rulesets.Taiko.UI; namespace osu.Game.Rulesets.Taiko.Mods { @@ -30,6 +29,8 @@ namespace osu.Game.Rulesets.Taiko.Mods private DrawableRuleset ruleset = null!; + private TaikoPlayfield playfield { get; set; } = null!; + protected TaikoAction? LastAcceptedDonAction { get; private set; } protected TaikoAction? LastAcceptedKatAction { get; private set; } @@ -46,6 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { ruleset = drawableRuleset; + playfield = (TaikoPlayfield)ruleset.Playfield; drawableRuleset.KeyBindingInputManager.Add(new InputInterceptor(this)); var periods = new List(); @@ -97,6 +99,10 @@ namespace osu.Game.Rulesets.Taiko.Mods return true; } + // If next hit object is strong, allow usage of all actions + if (playfield.HitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.HasResult != true)?.HitObject is TaikoStrongableHitObject hitObject && hitObject.IsStrong) + return true; + if (CheckValidNewAction(action)) { if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) @@ -106,7 +112,6 @@ namespace osu.Game.Rulesets.Taiko.Mods return true; } - //ruleset.Cursor.FlashColour(Colour4.Red, flash_duration, Easing.OutQuint); return false; } From b883c6af34a7601023d7fe84c37cd3ae8f96d652 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 27 Feb 2023 10:30:57 +0000 Subject: [PATCH 412/516] Renamed all instances of Taiko's InputBlockingMod to TaikoInputBlockingMod --- .../Mods/{InputBlockingMod.cs => TaikoInputBlockingMod.cs} | 6 +++--- osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename osu.Game.Rulesets.Taiko/Mods/{InputBlockingMod.cs => TaikoInputBlockingMod.cs} (95%) diff --git a/osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs similarity index 95% rename from osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs rename to osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs index 7613ce7c67..a843e99671 100644 --- a/osu.Game.Rulesets.Taiko/Mods/InputBlockingMod.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs @@ -19,7 +19,7 @@ using osu.Game.Rulesets.Taiko.UI; namespace osu.Game.Rulesets.Taiko.Mods { - public abstract partial class InputBlockingMod : Mod, IApplicableToDrawableRuleset, IUpdatableByPlayfield + public abstract partial class TaikoInputBlockingMod : Mod, IApplicableToDrawableRuleset, IUpdatableByPlayfield { public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax), typeof(TaikoModCinema) }; @@ -117,9 +117,9 @@ namespace osu.Game.Rulesets.Taiko.Mods private partial class InputInterceptor : Component, IKeyBindingHandler { - private readonly InputBlockingMod mod; + private readonly TaikoInputBlockingMod mod; - public InputInterceptor(InputBlockingMod mod) + public InputInterceptor(TaikoInputBlockingMod mod) { this.mod = mod; } diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs index 20c37fcb71..57e041f151 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -5,7 +5,7 @@ using osu.Framework.Localisation; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModSingleTap : InputBlockingMod + public class TaikoModSingleTap : TaikoInputBlockingMod { public override string Name => @"Single Tap"; public override string Acronym => @"SG"; From f2cada4584db82428ebcee47914084fc4bdad7e7 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 27 Feb 2023 12:22:38 +0000 Subject: [PATCH 413/516] Strong drumrolls no longer allow all actions to be used --- osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs index a843e99671..fe9f190d91 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs @@ -99,8 +99,10 @@ namespace osu.Game.Rulesets.Taiko.Mods return true; } - // If next hit object is strong, allow usage of all actions - if (playfield.HitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.HasResult != true)?.HitObject is TaikoStrongableHitObject hitObject && hitObject.IsStrong) + // If next hit object is strong, allow usage of all actions. Strong drumrolls are ignored in this check. + if (playfield.HitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.HasResult != true)?.HitObject is TaikoStrongableHitObject hitObject + && hitObject.IsStrong + && hitObject as DrumRoll == null) return true; if (CheckValidNewAction(action)) From 12b983495c9883ca0fd691f95ec93143a7688096 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 27 Feb 2023 13:40:55 +0000 Subject: [PATCH 414/516] Fixed issues caused by branch being stale --- osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs | 6 +++--- osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs index fe9f190d91..eecb8c0bbd 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Mods private const double flash_duration = 1000; - private DrawableRuleset ruleset = null!; + private DrawableTaikoRuleset ruleset = null!; private TaikoPlayfield playfield { get; set; } = null!; @@ -46,9 +46,9 @@ namespace osu.Game.Rulesets.Taiko.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - ruleset = drawableRuleset; + ruleset = (DrawableTaikoRuleset)drawableRuleset; + ruleset.InputManager.Add(new InputInterceptor(this)); playfield = (TaikoPlayfield)ruleset.Playfield; - drawableRuleset.KeyBindingInputManager.Add(new InputInterceptor(this)); var periods = new List(); diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 40203440c5..5390d3b138 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -33,6 +33,8 @@ namespace osu.Game.Rulesets.Taiko.UI public readonly BindableBool LockPlayfieldMaxAspect = new BindableBool(true); + public TaikoInputManager InputManager { get; private set; } + protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; protected override bool UserScrollSpeedAdjustment => false; @@ -93,7 +95,7 @@ namespace osu.Game.Rulesets.Taiko.UI LockPlayfieldMaxAspect = { BindTarget = LockPlayfieldMaxAspect } }; - protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo); + protected override PassThroughInputManager CreateInputManager() => InputManager = new TaikoInputManager(Ruleset.RulesetInfo); protected override Playfield CreatePlayfield() => new TaikoPlayfield(); From dd9194b976089afc985589fa3100338b896e1596 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 27 Feb 2023 13:58:40 +0000 Subject: [PATCH 415/516] Code formatting fix --- osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs index eecb8c0bbd..63bc156d2d 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs @@ -101,8 +101,8 @@ namespace osu.Game.Rulesets.Taiko.Mods // If next hit object is strong, allow usage of all actions. Strong drumrolls are ignored in this check. if (playfield.HitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.HasResult != true)?.HitObject is TaikoStrongableHitObject hitObject - && hitObject.IsStrong - && hitObject as DrumRoll == null) + && hitObject.IsStrong + && hitObject as DrumRoll == null) return true; if (CheckValidNewAction(action)) From d823faed081db916e967747ac0076bb631e8c0d1 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 27 Feb 2023 14:33:47 +0000 Subject: [PATCH 416/516] Remove unused `flash_duration` const --- osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs index 63bc156d2d..5512a7d775 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs @@ -25,8 +25,6 @@ namespace osu.Game.Rulesets.Taiko.Mods public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax), typeof(TaikoModCinema) }; public override ModType Type => ModType.Conversion; - private const double flash_duration = 1000; - private DrawableTaikoRuleset ruleset = null!; private TaikoPlayfield playfield { get; set; } = null!; From 12a2037086c8878173f85c8af60a14dad0fec538 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 27 Feb 2023 14:39:12 +0000 Subject: [PATCH 417/516] Removed useless TaikoAction check from TaikoInputBlockingMod --- .../Mods/TaikoInputBlockingMod.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs index 5512a7d775..f437d53b93 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs @@ -84,19 +84,6 @@ namespace osu.Game.Rulesets.Taiko.Mods if (nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) return true; - switch (action) - { - case TaikoAction.LeftCentre: - case TaikoAction.RightCentre: - case TaikoAction.LeftRim: - case TaikoAction.RightRim: - break; - - // Any action which is not left or right button should be ignored. - default: - return true; - } - // If next hit object is strong, allow usage of all actions. Strong drumrolls are ignored in this check. if (playfield.HitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.HasResult != true)?.HitObject is TaikoStrongableHitObject hitObject && hitObject.IsStrong From bf1897a98fc5d215c9c75a1faffba4d853bf4b9e Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 27 Feb 2023 16:08:14 +0100 Subject: [PATCH 418/516] Adjust warning text slightly. --- osu.Game/Localisation/SkinEditorStrings.cs | 4 ++-- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/SkinEditorStrings.cs b/osu.Game/Localisation/SkinEditorStrings.cs index 029d50df32..b83a105c14 100644 --- a/osu.Game/Localisation/SkinEditorStrings.cs +++ b/osu.Game/Localisation/SkinEditorStrings.cs @@ -45,9 +45,9 @@ namespace osu.Game.Localisation public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), @"Currently editing"); /// - /// "Revert?" + /// "Revert to default?" /// - public static LocalisableString Revert => new TranslatableString(getKey(@"revert"), @"Revert?"); + public static LocalisableString RevertToDefault => new TranslatableString(getKey(@"revert_to_default"), @"Revert to default?"); /// /// "The skin will return to the state it was in upon import" diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 936dc7fa84..7661abc551 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -635,7 +635,7 @@ namespace osu.Game.Overlays.SkinEditor { public ResetConfirmDialog(Action reset) { - HeaderText = SkinEditorStrings.Revert; + HeaderText = SkinEditorStrings.RevertToDefault; BodyText = SkinEditorStrings.ResetDialogue; Icon = FontAwesome.Solid.ExclamationTriangle; From 25ef1f199d64c32760ad694826970e90a74761f3 Mon Sep 17 00:00:00 2001 From: OpenSauce <48618519+OpenSauce04@users.noreply.github.com> Date: Mon, 27 Feb 2023 15:22:06 +0000 Subject: [PATCH 419/516] Update description for Taiko Single Tap mod --- osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs index 57e041f151..666e550c93 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public override string Name => @"Single Tap"; public override string Acronym => @"SG"; - public override LocalisableString Description => @"You must only use one key!"; + public override LocalisableString Description => @"One key for dons, one key for kats."; protected override bool CheckValidNewAction(TaikoAction action) => LastAcceptedDonAction == null || LastAcceptedDonAction == action || LastAcceptedKatAction == null || LastAcceptedKatAction == action; } From 8d747f240220e98cb40a9edd567f6778c31115e0 Mon Sep 17 00:00:00 2001 From: OpenSauce <48618519+OpenSauce04@users.noreply.github.com> Date: Mon, 27 Feb 2023 16:06:33 +0000 Subject: [PATCH 420/516] Fixed grammar mistake in Taiko Relax mod description --- osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs index d1e9ab1428..69a98f8372 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs @@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.Taiko.Mods { public class TaikoModRelax : ModRelax { - public override LocalisableString Description => @"No ninja-like spinners, demanding drumrolls or unexpected katu's."; + public override LocalisableString Description => @"No ninja-like spinners, demanding drumrolls or unexpected katus."; } } From 1239de6f41fd36b0fca8d3e41708e0f8095d30fd Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 27 Feb 2023 21:34:07 +0100 Subject: [PATCH 421/516] Upper case web `using` alias --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 7661abc551..53669e9f9c 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -18,7 +18,7 @@ using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using web = osu.Game.Resources.Localisation.Web; +using Web = osu.Game.Resources.Localisation.Web; using osu.Framework.Testing; using osu.Game.Database; using osu.Game.Graphics; @@ -153,7 +153,7 @@ namespace osu.Game.Overlays.SkinEditor { Items = new[] { - new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), + new EditorMenuItem(Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, () => dialogOverlay?.Push(new ResetConfirmDialog(revert))), new EditorMenuItemSpacer(), new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()), @@ -649,7 +649,7 @@ namespace osu.Game.Overlays.SkinEditor }, new PopupDialogCancelButton { - Text = web.CommonStrings.ButtonsCancel, + Text = Web.CommonStrings.ButtonsCancel, }, }; } From 00a00ead225c8426e83582a88969cb2e39418ebc Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 27 Feb 2023 21:50:27 +0100 Subject: [PATCH 422/516] Make `ResetConfirmDialog` inherit from `DeleteConfirmationDialog` --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 53669e9f9c..bab5344e1e 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -631,7 +631,7 @@ namespace osu.Game.Overlays.SkinEditor } } - public partial class ResetConfirmDialog : PopupDialog + public partial class ResetConfirmDialog : DeleteConfirmationDialog { public ResetConfirmDialog(Action reset) { From 90227a64966383e7a313132d339c84c434ad8be0 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 27 Feb 2023 21:57:59 +0100 Subject: [PATCH 423/516] Rename `DeleteConfirmationDialog.cs` into `DangerousActionDialog.cs` --- osu.Game/Collections/DeleteCollectionDialog.cs | 2 +- .../{DeleteConfirmationDialog.cs => DangerousActionDialog.cs} | 4 ++-- osu.Game/Overlays/Mods/DeleteModPresetDialog.cs | 2 +- .../Sections/Maintenance/MassDeleteConfirmationDialog.cs | 2 +- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 2 +- osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs | 2 +- osu.Game/Screens/Select/BeatmapClearScoresDialog.cs | 2 +- osu.Game/Screens/Select/BeatmapDeleteDialog.cs | 2 +- .../Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs | 2 +- osu.Game/Screens/Select/LocalScoreDeleteDialog.cs | 2 +- osu.Game/Screens/Select/SkinDeleteDialog.cs | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) rename osu.Game/Overlays/Dialog/{DeleteConfirmationDialog.cs => DangerousActionDialog.cs} (91%) diff --git a/osu.Game/Collections/DeleteCollectionDialog.cs b/osu.Game/Collections/DeleteCollectionDialog.cs index 4b23f661f9..4da2979481 100644 --- a/osu.Game/Collections/DeleteCollectionDialog.cs +++ b/osu.Game/Collections/DeleteCollectionDialog.cs @@ -8,7 +8,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Collections { - public partial class DeleteCollectionDialog : DeleteConfirmationDialog + public partial class DeleteCollectionDialog : DangerousActionDialog { public DeleteCollectionDialog(Live collection, Action deleteAction) { diff --git a/osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs b/osu.Game/Overlays/Dialog/DangerousActionDialog.cs similarity index 91% rename from osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs rename to osu.Game/Overlays/Dialog/DangerousActionDialog.cs index ddb59c4c9e..aaec72fc4d 100644 --- a/osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Dialog/DangerousActionDialog.cs @@ -12,14 +12,14 @@ namespace osu.Game.Overlays.Dialog /// Differs from in that the confirmation button is a "dangerous" one /// (requires the confirm button to be held). /// - public abstract partial class DeleteConfirmationDialog : PopupDialog + public abstract partial class DangerousActionDialog : PopupDialog { /// /// The action which performs the deletion. /// protected Action? DeleteAction { get; set; } - protected DeleteConfirmationDialog() + protected DangerousActionDialog() { HeaderText = DeleteConfirmationDialogStrings.HeaderText; diff --git a/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs b/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs index 800ebe8b4e..5b329a32d5 100644 --- a/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs +++ b/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Overlays.Mods { - public partial class DeleteModPresetDialog : DeleteConfirmationDialog + public partial class DeleteModPresetDialog : DangerousActionDialog { public DeleteModPresetDialog(Live modPreset) { diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs index 948d646e3d..71226803c8 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs @@ -6,7 +6,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public partial class MassDeleteConfirmationDialog : DeleteConfirmationDialog + public partial class MassDeleteConfirmationDialog : DangerousActionDialog { public MassDeleteConfirmationDialog(Action deleteAction) { diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index bab5344e1e..770a3c5930 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -631,7 +631,7 @@ namespace osu.Game.Overlays.SkinEditor } } - public partial class ResetConfirmDialog : DeleteConfirmationDialog + public partial class ResetConfirmDialog : DangerousActionDialog { public ResetConfirmDialog(Action reset) { diff --git a/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs index 68a0ef4250..6db31967d6 100644 --- a/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs +++ b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Edit { - public partial class DeleteDifficultyConfirmationDialog : DeleteConfirmationDialog + public partial class DeleteDifficultyConfirmationDialog : DangerousActionDialog { public DeleteDifficultyConfirmationDialog(BeatmapInfo beatmapInfo, Action deleteAction) { diff --git a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs index c0f97a05e2..2704a1afb4 100644 --- a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs +++ b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs @@ -10,7 +10,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.Select { - public partial class BeatmapClearScoresDialog : DeleteConfirmationDialog + public partial class BeatmapClearScoresDialog : DangerousActionDialog { [Resolved] private ScoreManager scoreManager { get; set; } = null!; diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs index 4ab23c3a3a..0692cc3745 100644 --- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs +++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Select { - public partial class BeatmapDeleteDialog : DeleteConfirmationDialog + public partial class BeatmapDeleteDialog : DangerousActionDialog { private readonly BeatmapSetInfo beatmapSet; diff --git a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs b/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs index e1aa662942..ecb21d4e2c 100644 --- a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs +++ b/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs @@ -8,7 +8,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Select.Carousel { - public partial class UpdateLocalConfirmationDialog : DeleteConfirmationDialog + public partial class UpdateLocalConfirmationDialog : DangerousActionDialog { public UpdateLocalConfirmationDialog(Action onConfirm) { diff --git a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs index 6349e9e5eb..660122c80e 100644 --- a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs +++ b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps; namespace osu.Game.Screens.Select { - public partial class LocalScoreDeleteDialog : DeleteConfirmationDialog + public partial class LocalScoreDeleteDialog : DangerousActionDialog { private readonly ScoreInfo score; diff --git a/osu.Game/Screens/Select/SkinDeleteDialog.cs b/osu.Game/Screens/Select/SkinDeleteDialog.cs index 9e11629890..3c95de0620 100644 --- a/osu.Game/Screens/Select/SkinDeleteDialog.cs +++ b/osu.Game/Screens/Select/SkinDeleteDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Select { - public partial class SkinDeleteDialog : DeleteConfirmationDialog + public partial class SkinDeleteDialog : DangerousActionDialog { private readonly Skin skin; From beb04379f9a518c78802da385caa92f5f05c3670 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 27 Feb 2023 22:36:09 +0000 Subject: [PATCH 424/516] Inverted an if statement for code clarity --- .../Mods/TaikoInputBlockingMod.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs index f437d53b93..16d885b5d5 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoInputBlockingMod.cs @@ -67,14 +67,13 @@ namespace osu.Game.Rulesets.Taiko.Mods public void Update(Playfield playfield) { - if (nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) - { - if (LastAcceptedDonAction != null) - LastAcceptedDonAction = null; + if (!nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) return; - if (LastAcceptedKatAction != null) - LastAcceptedKatAction = null; - } + if (LastAcceptedDonAction != null) + LastAcceptedDonAction = null; + + if (LastAcceptedKatAction != null) + LastAcceptedKatAction = null; } protected abstract bool CheckValidNewAction(TaikoAction action); From 2615453b3143e59886a56adb2f5d835a241a2a5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Feb 2023 11:45:32 +0900 Subject: [PATCH 425/516] Rename `SettingSource` tests to match attribute name --- ...ingsSourceAttributeTest.cs => SettingSourceAttributeTest.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename osu.Game.Tests/Mods/{SettingsSourceAttributeTest.cs => SettingSourceAttributeTest.cs} (98%) diff --git a/osu.Game.Tests/Mods/SettingsSourceAttributeTest.cs b/osu.Game.Tests/Mods/SettingSourceAttributeTest.cs similarity index 98% rename from osu.Game.Tests/Mods/SettingsSourceAttributeTest.cs rename to osu.Game.Tests/Mods/SettingSourceAttributeTest.cs index bf59862787..5da303d3a7 100644 --- a/osu.Game.Tests/Mods/SettingsSourceAttributeTest.cs +++ b/osu.Game.Tests/Mods/SettingSourceAttributeTest.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Tests.Mods { [TestFixture] - public partial class SettingsSourceAttributeTest + public partial class SettingSourceAttributeTest { [Test] public void TestOrdering() From bd1460a8d5726a67acfdfbfb08568b872fcc8d83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Feb 2023 14:32:58 +0900 Subject: [PATCH 426/516] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 4bdf5d68c5..abd8406cf7 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + true true + manifestmerger.jar + + + diff --git a/osu.Android/AndroidManifest.xml b/osu.Android/AndroidManifest.xml index 9ea57969b7..bc2f49b1a9 100644 --- a/osu.Android/AndroidManifest.xml +++ b/osu.Android/AndroidManifest.xml @@ -2,16 +2,4 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/osu.Android/Properties/AndroidManifestOverlay.xml b/osu.Android/Properties/AndroidManifestOverlay.xml new file mode 100644 index 0000000000..815f935383 --- /dev/null +++ b/osu.Android/Properties/AndroidManifestOverlay.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml index 22b4ea9191..bf7c0bfeca 100644 --- a/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml +++ b/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml @@ -3,16 +3,4 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml index c8b0de9f42..4a1545a423 100644 --- a/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml +++ b/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml @@ -2,16 +2,4 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml index d91fc062fe..45d27dda70 100644 --- a/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml +++ b/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml @@ -2,16 +2,4 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml index f678d63dbb..452b9683ec 100644 --- a/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml +++ b/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml @@ -2,16 +2,4 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/osu.Game.Tests.Android/AndroidManifest.xml b/osu.Game.Tests.Android/AndroidManifest.xml index 105f2b1e8b..f25b2e5328 100644 --- a/osu.Game.Tests.Android/AndroidManifest.xml +++ b/osu.Game.Tests.Android/AndroidManifest.xml @@ -2,16 +2,4 @@ - - - - - - - - - - - - \ No newline at end of file From 908651cc11251cf80e13b8b539abcfc0bd4454a2 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sun, 5 Mar 2023 20:57:26 +0100 Subject: [PATCH 473/516] make `ResetConfirmDialog` properly utilise its parent's logic Adjust name of `DeleteAction` to `DangerousAction` --- .../Collections/DeleteCollectionDialog.cs | 2 +- .../Overlays/Dialog/DangerousActionDialog.cs | 4 ++-- .../Overlays/Mods/DeleteModPresetDialog.cs | 2 +- .../MassDeleteConfirmationDialog.cs | 2 +- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 19 ++----------------- .../DeleteDifficultyConfirmationDialog.cs | 2 +- .../Select/BeatmapClearScoresDialog.cs | 2 +- .../Screens/Select/BeatmapDeleteDialog.cs | 2 +- .../Carousel/UpdateLocalConfirmationDialog.cs | 2 +- .../Screens/Select/LocalScoreDeleteDialog.cs | 2 +- osu.Game/Screens/Select/SkinDeleteDialog.cs | 2 +- 11 files changed, 13 insertions(+), 28 deletions(-) diff --git a/osu.Game/Collections/DeleteCollectionDialog.cs b/osu.Game/Collections/DeleteCollectionDialog.cs index 4da2979481..9edc213077 100644 --- a/osu.Game/Collections/DeleteCollectionDialog.cs +++ b/osu.Game/Collections/DeleteCollectionDialog.cs @@ -13,7 +13,7 @@ namespace osu.Game.Collections public DeleteCollectionDialog(Live collection, Action deleteAction) { BodyText = collection.PerformRead(c => $"{c.Name} ({"beatmap".ToQuantity(c.BeatmapMD5Hashes.Count)})"); - DeleteAction = deleteAction; + DangerousAction = deleteAction; } } } diff --git a/osu.Game/Overlays/Dialog/DangerousActionDialog.cs b/osu.Game/Overlays/Dialog/DangerousActionDialog.cs index aaec72fc4d..85cae5e0d2 100644 --- a/osu.Game/Overlays/Dialog/DangerousActionDialog.cs +++ b/osu.Game/Overlays/Dialog/DangerousActionDialog.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Dialog /// /// The action which performs the deletion. /// - protected Action? DeleteAction { get; set; } + protected Action? DangerousAction { get; set; } protected DangerousActionDialog() { @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Dialog new PopupDialogDangerousButton { Text = DeleteConfirmationDialogStrings.Confirm, - Action = () => DeleteAction?.Invoke() + Action = () => DangerousAction?.Invoke() }, new PopupDialogCancelButton { diff --git a/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs b/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs index 5b329a32d5..9788764453 100644 --- a/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs +++ b/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Mods public DeleteModPresetDialog(Live modPreset) { BodyText = modPreset.PerformRead(preset => preset.Name); - DeleteAction = () => modPreset.PerformWrite(preset => preset.DeletePending = true); + DangerousAction = () => modPreset.PerformWrite(preset => preset.DeletePending = true); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs index 71226803c8..99ef62d94b 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs @@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public MassDeleteConfirmationDialog(Action deleteAction) { BodyText = "Everything?"; - DeleteAction = deleteAction; + DangerousAction = deleteAction; } } } diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index 5ffdaa11d4..a7fe459aa4 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -12,7 +12,6 @@ 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.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Input.Bindings; @@ -633,25 +632,11 @@ namespace osu.Game.Overlays.SkinEditor public partial class ResetConfirmDialog : DangerousActionDialog { - public ResetConfirmDialog(Action reset) + public ResetConfirmDialog(Action revert) { HeaderText = SkinEditorStrings.RevertToDefaultDescription; BodyText = SkinEditorStrings.ResetDialogue; - - Icon = FontAwesome.Solid.ExclamationTriangle; - - Buttons = new PopupDialogButton[] - { - new PopupDialogDangerousButton - { - Text = BeatmapOverlayStrings.UserContentConfirmButtonText, - Action = reset - }, - new PopupDialogCancelButton - { - Text = Web.CommonStrings.ButtonsCancel, - }, - }; + DangerousAction = revert; } } diff --git a/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs index 6db31967d6..8556949528 100644 --- a/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs +++ b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.Edit public DeleteDifficultyConfirmationDialog(BeatmapInfo beatmapInfo, Action deleteAction) { BodyText = $"\"{beatmapInfo.DifficultyName}\" difficulty"; - DeleteAction = deleteAction; + DangerousAction = deleteAction; } } } diff --git a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs index 2704a1afb4..8efad451df 100644 --- a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs +++ b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Select public BeatmapClearScoresDialog(BeatmapInfo beatmapInfo, Action onCompletion) { BodyText = $"All local scores on {beatmapInfo.GetDisplayTitle()}"; - DeleteAction = () => + DangerousAction = () => { Task.Run(() => scoreManager.Delete(beatmapInfo)) .ContinueWith(_ => onCompletion); diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs index 0692cc3745..e98af8cca2 100644 --- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs +++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader] private void load(BeatmapManager beatmapManager) { - DeleteAction = () => beatmapManager.Delete(beatmapSet); + DangerousAction = () => beatmapManager.Delete(beatmapSet); } } } diff --git a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs b/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs index ecb21d4e2c..6157e8f6a5 100644 --- a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs +++ b/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Select.Carousel HeaderText = PopupDialogStrings.UpdateLocallyModifiedText; BodyText = PopupDialogStrings.UpdateLocallyModifiedDescription; Icon = FontAwesome.Solid.ExclamationTriangle; - DeleteAction = onConfirm; + DangerousAction = onConfirm; } } } diff --git a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs index 660122c80e..c4add31a4f 100644 --- a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs +++ b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select BodyText = $"{score.User} ({score.DisplayAccuracy}, {score.Rank})"; Icon = FontAwesome.Regular.TrashAlt; - DeleteAction = () => scoreManager.Delete(score); + DangerousAction = () => scoreManager.Delete(score); } } } diff --git a/osu.Game/Screens/Select/SkinDeleteDialog.cs b/osu.Game/Screens/Select/SkinDeleteDialog.cs index 3c95de0620..6612ae837a 100644 --- a/osu.Game/Screens/Select/SkinDeleteDialog.cs +++ b/osu.Game/Screens/Select/SkinDeleteDialog.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader] private void load(SkinManager manager) { - DeleteAction = () => + DangerousAction = () => { manager.Delete(skin.SkinInfo.Value); manager.CurrentSkinInfo.SetDefault(); From 082bfe3621f8502b81376f5a92e031cf3c7d4803 Mon Sep 17 00:00:00 2001 From: tsrk Date: Sun, 5 Mar 2023 23:09:02 +0000 Subject: [PATCH 474/516] refactor: `SkinnableAvatar` to `PlayerAvatar` --- .../Screens/Play/HUD/{SkinnableAvatar.cs => PlayerAvatar.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename osu.Game/Screens/Play/HUD/{SkinnableAvatar.cs => PlayerAvatar.cs} (92%) diff --git a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs similarity index 92% rename from osu.Game/Screens/Play/HUD/SkinnableAvatar.cs rename to osu.Game/Screens/Play/HUD/PlayerAvatar.cs index 41fe8c6a06..d4ab555d04 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs +++ b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public partial class SkinnableAvatar : CompositeDrawable, ISerialisableDrawable + public partial class PlayerAvatar : CompositeDrawable, ISerialisableDrawable { [SettingSource("Corner radius", "How much the edges should be rounded.")] public new BindableFloat CornerRadius { get; set; } = new BindableFloat @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play.HUD private readonly UpdateableAvatar avatar; - public SkinnableAvatar() + public PlayerAvatar() { Size = new Vector2(128f); InternalChild = avatar = new UpdateableAvatar(isInteractive: false) From 654eacd4496cde2601015abc053d8d081f25869d Mon Sep 17 00:00:00 2001 From: tsrk Date: Sun, 5 Mar 2023 23:10:42 +0000 Subject: [PATCH 475/516] feat(l10n): localise `CornerRadius` --- .../SkinComponents/SkinnableComponentStrings.cs | 10 ++++++++++ osu.Game/Screens/Play/HUD/PlayerAvatar.cs | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs b/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs index 547df86fc7..5cec9442e4 100644 --- a/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs +++ b/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs @@ -39,6 +39,16 @@ namespace osu.Game.Localisation.SkinComponents /// public static LocalisableString TextElementTextDescription => new TranslatableString(getKey(@"text_element_text_description"), "The text to be displayed."); + /// + /// "Corner Radius" + /// + public static LocalisableString CornerRadius => new TranslatableString(getKey(@"corner_radius"), "Corner Radius"); + + /// + /// "How rounded the corners should be." + /// + public static LocalisableString CornerRadiusDescription => new TranslatableString(getKey(@"corner_radius_description"), "How rounded the corners should be."); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs index d4ab555d04..6cea463193 100644 --- a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs +++ b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs @@ -6,6 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; +using osu.Game.Localisation.SkinComponents; using osu.Game.Skinning; using osu.Game.Users.Drawables; using osuTK; @@ -14,7 +15,7 @@ namespace osu.Game.Screens.Play.HUD { public partial class PlayerAvatar : CompositeDrawable, ISerialisableDrawable { - [SettingSource("Corner radius", "How much the edges should be rounded.")] + [SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.CornerRadius), nameof(SkinnableComponentStrings.CornerRadiusDescription))] public new BindableFloat CornerRadius { get; set; } = new BindableFloat { MinValue = 0, From 20a610ea6c4c407cedcdffc8a9ac3ae0fbd1f8b0 Mon Sep 17 00:00:00 2001 From: tsrk Date: Sun, 5 Mar 2023 23:15:58 +0000 Subject: [PATCH 476/516] style: a NRT pass on `UpdateableFlag` --- osu.Game/Users/Drawables/UpdateableFlag.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Users/Drawables/UpdateableFlag.cs b/osu.Game/Users/Drawables/UpdateableFlag.cs index a208f3c7c4..8f8d7052e5 100644 --- a/osu.Game/Users/Drawables/UpdateableFlag.cs +++ b/osu.Game/Users/Drawables/UpdateableFlag.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.Graphics; @@ -30,14 +28,14 @@ namespace osu.Game.Users.Drawables /// Perform an action in addition to showing the country ranking. /// This should be used to perform auxiliary tasks and not as a primary action for clicking a flag (to maintain a consistent UX). ///
- public Action Action; + public Action? Action; public UpdateableFlag(CountryCode countryCode = CountryCode.Unknown) { CountryCode = countryCode; } - protected override Drawable CreateDrawable(CountryCode countryCode) + protected override Drawable? CreateDrawable(CountryCode countryCode) { if (countryCode == CountryCode.Unknown && !ShowPlaceholderOnUnknown) return null; @@ -56,8 +54,8 @@ namespace osu.Game.Users.Drawables }; } - [Resolved(canBeNull: true)] - private RankingsOverlay rankingsOverlay { get; set; } + [Resolved] + private RankingsOverlay? rankingsOverlay { get; set; } protected override bool OnClick(ClickEvent e) { From 07bde4990d50836a64e62f61a60f991165bb6436 Mon Sep 17 00:00:00 2001 From: tsrk Date: Sun, 5 Mar 2023 23:17:30 +0000 Subject: [PATCH 477/516] feat: implement `PlayerAvatar` --- osu.Game/Screens/Play/HUD/PlayerFlag.cs | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 osu.Game/Screens/Play/HUD/PlayerFlag.cs diff --git a/osu.Game/Screens/Play/HUD/PlayerFlag.cs b/osu.Game/Screens/Play/HUD/PlayerFlag.cs new file mode 100644 index 0000000000..17188d0009 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/PlayerFlag.cs @@ -0,0 +1,38 @@ +// 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.Game.Skinning; +using osu.Game.Users.Drawables; +using osuTK; + +namespace osu.Game.Screens.Play.HUD +{ + public partial class PlayerFlag : CompositeDrawable, ISerialisableDrawable + { + [Resolved] + private GameplayState gameplayState { get; set; } = null!; + + private readonly UpdateableFlag flag; + + public PlayerFlag() + { + Size = new Vector2(114, 80); + InternalChild = flag = new UpdateableFlag + { + RelativeSizeAxes = Axes.Both, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + flag.CountryCode = gameplayState.Score.ScoreInfo.User.CountryCode; + } + + public bool UsesFixedAnchor { get; set; } + } +} From ddee6400dfa3c28f476e0c9fea11a17874c82257 Mon Sep 17 00:00:00 2001 From: tsrk Date: Sun, 5 Mar 2023 23:46:51 +0000 Subject: [PATCH 478/516] test: add coverage for `Player{Avatar,Flag}` --- .../Archives/modified-argon-20230305.osk | Bin 0 -> 1897 bytes osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 7 ++++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-argon-20230305.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-argon-20230305.osk b/osu.Game.Tests/Resources/Archives/modified-argon-20230305.osk new file mode 100644 index 0000000000000000000000000000000000000000..c85f3b6352af3357089a797c287659a0d8e848f7 GIT binary patch literal 1897 zcmZ`)2{ha37XJrDwM>j<6dg)aofm6Nl`=@FlHetRpxP!SwNw*ZQW6}y5s4*KF={EH zN^R8^#bCygmIl?)Djh?_UPTSDj7j_Ey*c&X`@VC}J@-4`@1A?V@7~`N?B_rB4NU|rVlAmS1QZ5D)sBQZsC%Y@)DD`?fvQgW%$c95cG#nwX5eaNBy!>}^x zSMnoc3Ae1r;c-(M3B@4=N}}*4N1bz$rM~DOQvG&rj>c9JM;D3N!SAoqeU77@MDnSzO%AM%6NUOL18A1WCPf&1x=^Hr@-YKH;#HEae+Y?K$)9#Y zp;nQ74leahsHb|mF3#Vh5!whYHwEo9pbyiB4LJ|=_WzS(|IFS21k?HUW@x)deu|SE zay7-W`RrQ#+Um2lqAv@=yCBKoklbWQt{}W1+)sdtTOW(bo;~2>!=EPb*$XDIi@-{# zJdTBE@q7q;9w5sc$)t(`K$Q{zC<+5~!21zxU97E0*8@pJ0x>k?Q>067Xwn-aaFkl@ z9*+0=gl%$GFDSe>pM2y|arf9e_DM01wq8$Pm^!<`W^m8^Y2CufVp;Vdp8Vb2E8{mN zZwtncE^kiH6pF`XhGLyWl%Go~&CPFdp0mECH6>MyEWXe-D>w<=HN&b+n zHvTxQ&#A2@r^Q?FE^O+n-!W*D@YYu?FVAORzPojLrfOT|EO}!VJ9mclb(~0#l>XZb z(c4ukV&`+0>4li7y=#00?T+CDS8+PE_$gE_IC#8$Y^|wb)Tlbg4m)q;`(f9V$V8vB(W^<3RQMb^q4L(#q25!yjaJWPgxI?H|lk0dHv z69fR(A^`A(uv;-Cq7Q};K=2Cv)TZPNB(YN;oVan5Dgj;SmGVPav9<4gD884XAvs>8 zYp)cWU}zI{S3OH~UA5KiwxyKpxwm~0duCDLlo4!vSQCT-xC(8*>Fw(iJ434N=Sk_qq46_?0cwbTrb3fm^Ie z_w9``>IV!Cb~kcIe9W1q@W}E(?v0LzBjo0Ex0GAwih;z|%R|JIw ziO2*0f5ZqM^wjSYAg1##)PG2RKXgCg{tfjKe(e9I-~B%Jm%-mY YWDopTQJ|0q#6MmT6Yf=^#(%Q@1WNchY5)KL literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 04b8c6dd4e..eb1df954aa 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -9,6 +9,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Framework.Logging; using osu.Game.Audio; using osu.Game.IO; using osu.Game.IO.Archives; @@ -48,7 +49,9 @@ namespace osu.Game.Tests.Skins // Covers BPM counter. "Archives/modified-default-20221205.osk", // Covers judgement counter. - "Archives/modified-default-20230117.osk" + "Archives/modified-default-20230117.osk", + // Covers player avatar and flag. + "Archives/modified-argon-20230305.osk", }; /// @@ -61,6 +64,8 @@ namespace osu.Game.Tests.Skins foreach (string oskFile in available_skins) { + Logger.Log($"Testing file {oskFile}..."); + using (var stream = TestResources.OpenResource(oskFile)) using (var storage = new ZipArchiveReader(stream)) { From 87d0bef313fc9e5563dc3d368f3daf59b437c6aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Mar 2023 15:16:31 +0900 Subject: [PATCH 479/516] Use nullable comparison helper method instead of manual implementation --- .../Screens/Select/Carousel/CarouselBeatmapSet.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 63493a3b02..67822a27ee 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Select.Carousel break; case SortMode.DateRanked: - comparison = compareNullableDateTimeOffset(BeatmapSet.DateRanked, otherSet.BeatmapSet.DateRanked); + comparison = Nullable.Compare(otherSet.BeatmapSet.DateRanked, BeatmapSet.DateRanked); break; case SortMode.LastPlayed: @@ -107,7 +107,7 @@ namespace osu.Game.Screens.Select.Carousel break; case SortMode.DateSubmitted: - comparison = compareNullableDateTimeOffset(BeatmapSet.DateSubmitted, otherSet.BeatmapSet.DateSubmitted); + comparison = Nullable.Compare(otherSet.BeatmapSet.DateSubmitted, BeatmapSet.DateSubmitted); break; } @@ -124,14 +124,6 @@ namespace osu.Game.Screens.Select.Carousel return otherSet.BeatmapSet.ID.CompareTo(BeatmapSet.ID); } - private static int compareNullableDateTimeOffset(DateTimeOffset? x, DateTimeOffset? y) - { - if (x == null) return 1; - if (y == null) return -1; - - return y.Value.CompareTo(x.Value); - } - /// /// All beatmaps which are not filtered and valid for display. /// From 3a240aaa5fa1e55bcc9b50c26345ebdf0c001d99 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Mar 2023 10:27:59 +0000 Subject: [PATCH 480/516] style: use 64 radius --- osu.Game/Screens/Play/HUD/PlayerAvatar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs index 6cea463193..32ed045df7 100644 --- a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs +++ b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Play.HUD public new BindableFloat CornerRadius { get; set; } = new BindableFloat { MinValue = 0, - MaxValue = 63, + MaxValue = 64, Precision = 0.01f }; From df34bdc825e5496339de30ad3173f93dd28f40df Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 6 Mar 2023 19:31:45 +0900 Subject: [PATCH 481/516] Use lang version 10 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 3b6b985961..734374c840 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@  - 9.0 + 10.0 true enable From a7be59175d15298d1a7eff2c9e090dca03c8492f Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 6 Mar 2023 10:57:09 +0000 Subject: [PATCH 482/516] Made private + renamed Taiko Single Tap tracking variables for better readability --- .../Mods/TaikoModSingleTap.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs index 1130338521..30e4946833 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -29,9 +29,9 @@ namespace osu.Game.Rulesets.Taiko.Mods protected bool CheckValidNewAction(TaikoAction action) { if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - return LastAcceptedDonAction == null || LastAcceptedDonAction == action; + return lastAcceptedCentreAction == null || lastAcceptedCentreAction == action; if (action == TaikoAction.LeftRim || action == TaikoAction.RightRim) - return LastAcceptedKatAction == null || LastAcceptedKatAction == action; + return lastAcceptedRimAction == null || lastAcceptedRimAction == action; return true; } @@ -44,8 +44,8 @@ namespace osu.Game.Rulesets.Taiko.Mods private TaikoPlayfield playfield { get; set; } = null!; - protected TaikoAction? LastAcceptedDonAction { get; private set; } - protected TaikoAction? LastAcceptedKatAction { get; private set; } + private TaikoAction? lastAcceptedCentreAction { get; set; } + private TaikoAction? lastAcceptedRimAction { get; set; } /// /// A tracker for periods where alternate should not be forced (i.e. non-gameplay periods). @@ -84,11 +84,11 @@ namespace osu.Game.Rulesets.Taiko.Mods { if (!nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) return; - if (LastAcceptedDonAction != null) - LastAcceptedDonAction = null; + if (lastAcceptedCentreAction != null) + lastAcceptedCentreAction = null; - if (LastAcceptedKatAction != null) - LastAcceptedKatAction = null; + if (lastAcceptedRimAction != null) + lastAcceptedRimAction = null; } private bool checkCorrectAction(TaikoAction action) @@ -105,9 +105,9 @@ namespace osu.Game.Rulesets.Taiko.Mods if (CheckValidNewAction(action)) { if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - LastAcceptedDonAction = action; + lastAcceptedCentreAction = action; if (action == TaikoAction.LeftRim || action == TaikoAction.RightRim) - LastAcceptedKatAction = action; + lastAcceptedRimAction = action; return true; } From ac6c8e600a4ef58cedae8f19b8fabf50fa8aa6fc Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 6 Mar 2023 10:59:47 +0000 Subject: [PATCH 483/516] Updated a comment for correctness --- osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs index 30e4946833..9b411b49d4 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Taiko.Mods private TaikoAction? lastAcceptedRimAction { get; set; } /// - /// A tracker for periods where alternate should not be forced (i.e. non-gameplay periods). + /// A tracker for periods where single tap should not be enforced (i.e. non-gameplay periods). /// /// /// This is different from in that the periods here end strictly at the first object after the break, rather than the break's end time. From 4ae2661f1bd90181b54917ef55df431c7622ad57 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 6 Mar 2023 11:00:37 +0000 Subject: [PATCH 484/516] Removed useless null checks --- osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs index 9b411b49d4..92aff90ae0 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -84,11 +84,8 @@ namespace osu.Game.Rulesets.Taiko.Mods { if (!nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) return; - if (lastAcceptedCentreAction != null) - lastAcceptedCentreAction = null; - - if (lastAcceptedRimAction != null) - lastAcceptedRimAction = null; + lastAcceptedCentreAction = null; + lastAcceptedRimAction = null; } private bool checkCorrectAction(TaikoAction action) From 36108ea841603febdc2602e9f4a85ad69c25f34a Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 6 Mar 2023 11:10:57 +0000 Subject: [PATCH 485/516] Moved `CheckValidNewAction` checks into `checkCorrectAction` --- .../Mods/TaikoModSingleTap.cs | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs index 92aff90ae0..556e31d2c2 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -26,16 +26,6 @@ namespace osu.Game.Rulesets.Taiko.Mods public override string Acronym => @"SG"; public override LocalisableString Description => @"One key for dons, one key for kats."; - protected bool CheckValidNewAction(TaikoAction action) - { - if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - return lastAcceptedCentreAction == null || lastAcceptedCentreAction == action; - if (action == TaikoAction.LeftRim || action == TaikoAction.RightRim) - return lastAcceptedRimAction == null || lastAcceptedRimAction == action; - - return true; - } - public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax), typeof(TaikoModCinema) }; public override ModType Type => ModType.Conversion; @@ -99,13 +89,17 @@ namespace osu.Game.Rulesets.Taiko.Mods && hitObject is not DrumRoll) return true; - if (CheckValidNewAction(action)) + if ((action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) + && (lastAcceptedCentreAction == null || lastAcceptedCentreAction == action)) { - if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - lastAcceptedCentreAction = action; - if (action == TaikoAction.LeftRim || action == TaikoAction.RightRim) - lastAcceptedRimAction = action; + lastAcceptedCentreAction = action; + return true; + } + if ((action == TaikoAction.LeftRim || action == TaikoAction.RightRim) + && (lastAcceptedRimAction == null || lastAcceptedRimAction == action)) + { + lastAcceptedRimAction = action; return true; } From b2d453fd2edae6478bb0dfbfa860bea39a8251c3 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 6 Mar 2023 11:44:00 +0000 Subject: [PATCH 486/516] Fixed indentation --- osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs index 556e31d2c2..fa876555e1 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -90,14 +90,14 @@ namespace osu.Game.Rulesets.Taiko.Mods return true; if ((action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - && (lastAcceptedCentreAction == null || lastAcceptedCentreAction == action)) + && (lastAcceptedCentreAction == null || lastAcceptedCentreAction == action)) { lastAcceptedCentreAction = action; return true; } if ((action == TaikoAction.LeftRim || action == TaikoAction.RightRim) - && (lastAcceptedRimAction == null || lastAcceptedRimAction == action)) + && (lastAcceptedRimAction == null || lastAcceptedRimAction == action)) { lastAcceptedRimAction = action; return true; From 1fcf41379d5d5c37d211644fc96e4e99c4710ab0 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 6 Mar 2023 16:20:36 +0100 Subject: [PATCH 487/516] Added maintainability patch by bdach --- osu.Game/Beatmaps/BeatmapInfoExtensions.cs | 22 +++++------- .../Beatmaps/BeatmapMetadataInfoExtensions.cs | 35 +++++++++++++------ 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapInfoExtensions.cs index 460944d2fa..3aab9a24e1 100644 --- a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs +++ b/osu.Game/Beatmaps/BeatmapInfoExtensions.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; +using System.Collections.Generic; using osu.Framework.Localisation; namespace osu.Game.Beatmaps @@ -29,25 +29,19 @@ namespace osu.Game.Beatmaps return new RomanisableString($"{metadata.GetPreferred(true)}".Trim(), $"{metadata.GetPreferred(false)}".Trim()); } - public static ReadOnlySpan GetSearchableTerms(this IBeatmapInfo beatmapInfo) + public static List GetSearchableTerms(this IBeatmapInfo beatmapInfo) { - string[] terms = new string[8]; - int i = 0; - var metadata = beatmapInfo.Metadata; + var termsList = new List(BeatmapMetadataInfoExtensions.MAX_SEARCHABLE_TERM_COUNT + 1); + addIfNotNull(beatmapInfo.DifficultyName); - addIfNotNull(metadata.Author.Username); - addIfNotNull(metadata.Artist); - addIfNotNull(metadata.ArtistUnicode); - addIfNotNull(metadata.Title); - addIfNotNull(metadata.TitleUnicode); - addIfNotNull(metadata.Source); - addIfNotNull(metadata.Tags); - return terms.AsSpan(0, i); + + BeatmapMetadataInfoExtensions.CollectSearchableTerms(beatmapInfo.Metadata, termsList); + return termsList; void addIfNotNull(string? s) { if (!string.IsNullOrEmpty(s)) - terms[i++] = s; + termsList.Add(s); } } diff --git a/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs index 738bdb0839..fe4e815e62 100644 --- a/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs +++ b/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs @@ -3,7 +3,7 @@ #nullable disable -using System.Linq; +using System.Collections.Generic; using osu.Framework.Localisation; namespace osu.Game.Beatmaps @@ -13,16 +13,31 @@ namespace osu.Game.Beatmaps /// /// An array of all searchable terms provided in contained metadata. /// - public static string[] GetSearchableTerms(this IBeatmapMetadataInfo metadataInfo) => new[] + public static string[] GetSearchableTerms(this IBeatmapMetadataInfo metadataInfo) { - metadataInfo.Author.Username, - metadataInfo.Artist, - metadataInfo.ArtistUnicode, - metadataInfo.Title, - metadataInfo.TitleUnicode, - metadataInfo.Source, - metadataInfo.Tags - }.Where(s => !string.IsNullOrEmpty(s)).ToArray(); + var termsList = new List(MAX_SEARCHABLE_TERM_COUNT); + CollectSearchableTerms(metadataInfo, termsList); + return termsList.ToArray(); + } + + internal const int MAX_SEARCHABLE_TERM_COUNT = 7; + + internal static void CollectSearchableTerms(IBeatmapMetadataInfo metadataInfo, IList termsList) + { + addIfNotNull(metadataInfo.Author.Username); + addIfNotNull(metadataInfo.Artist); + addIfNotNull(metadataInfo.ArtistUnicode); + addIfNotNull(metadataInfo.Title); + addIfNotNull(metadataInfo.TitleUnicode); + addIfNotNull(metadataInfo.Source); + addIfNotNull(metadataInfo.Tags); + + void addIfNotNull(string s) + { + if (!string.IsNullOrEmpty(s)) + termsList.Add(s); + } + } /// /// A user-presentable display title representing this metadata. From 952814604ed43ab85b799198268cd222b7f9b9a9 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Mar 2023 20:06:56 +0000 Subject: [PATCH 488/516] style: fix late night oopsies --- osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 3 --- osu.Game/Screens/Play/HUD/PlayerAvatar.cs | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index eb1df954aa..bd8088cfb6 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -9,7 +9,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; -using osu.Framework.Logging; using osu.Game.Audio; using osu.Game.IO; using osu.Game.IO.Archives; @@ -64,8 +63,6 @@ namespace osu.Game.Tests.Skins foreach (string oskFile in available_skins) { - Logger.Log($"Testing file {oskFile}..."); - using (var stream = TestResources.OpenResource(oskFile)) using (var storage = new ZipArchiveReader(stream)) { diff --git a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs index 32ed045df7..d2f4f0be17 100644 --- a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs +++ b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs @@ -43,8 +43,7 @@ namespace osu.Game.Screens.Play.HUD base.LoadComplete(); avatar.User = gameplayState.Score.ScoreInfo.User; - avatar.CornerRadius = CornerRadius.Value; - CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue); + CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue, true); } public bool UsesFixedAnchor { get; set; } From fc0e27fb15e3eb1a143e5924a9adf3f472944a06 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Mar 2023 20:11:52 +0000 Subject: [PATCH 489/516] style: use normalised `CornerRadius` values --- osu.Game/Screens/Play/HUD/PlayerAvatar.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs index d2f4f0be17..f293199911 100644 --- a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs +++ b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs @@ -16,10 +16,10 @@ namespace osu.Game.Screens.Play.HUD public partial class PlayerAvatar : CompositeDrawable, ISerialisableDrawable { [SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.CornerRadius), nameof(SkinnableComponentStrings.CornerRadiusDescription))] - public new BindableFloat CornerRadius { get; set; } = new BindableFloat + public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0.25f) { MinValue = 0, - MaxValue = 64, + MaxValue = 0.5f, Precision = 0.01f }; @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Play.HUD base.LoadComplete(); avatar.User = gameplayState.Score.ScoreInfo.User; - CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue, true); + CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue * 128f, true); } public bool UsesFixedAnchor { get; set; } From 2cce785fa5bb7fd1ab6b77d1a757a76a6fc3f94b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Mar 2023 15:54:33 +0900 Subject: [PATCH 490/516] Fix storyboard videos not fading out on completion Closes https://github.com/ppy/osu/issues/22802. Stable uses a 1,000 ms fade-in / out. Rather than matching that, I've stuck with 500ms (what lazer was already using for the fade-in) because I think it feels better. Tested using the beatmap linked in the issue thread. --- osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs index f4b0692619..eec2cd6a60 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs @@ -58,7 +58,11 @@ namespace osu.Game.Storyboards.Drawables using (drawableVideo.BeginAbsoluteSequence(Video.StartTime)) { Schedule(() => drawableVideo.PlaybackPosition = Time.Current - Video.StartTime); + drawableVideo.FadeIn(500); + + using (drawableVideo.BeginDelayedSequence(drawableVideo.Duration - 500)) + drawableVideo.FadeOut(500); } } } From f7f1dff6471784c79a14c27e79f168597ca30a0c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Mar 2023 16:45:33 +0900 Subject: [PATCH 491/516] Fix incorrect case of localisable string for "corner radius" --- .../Localisation/SkinComponents/SkinnableComponentStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs b/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs index 5cec9442e4..7c11ea6ac6 100644 --- a/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs +++ b/osu.Game/Localisation/SkinComponents/SkinnableComponentStrings.cs @@ -40,9 +40,9 @@ namespace osu.Game.Localisation.SkinComponents public static LocalisableString TextElementTextDescription => new TranslatableString(getKey(@"text_element_text_description"), "The text to be displayed."); /// - /// "Corner Radius" + /// "Corner radius" /// - public static LocalisableString CornerRadius => new TranslatableString(getKey(@"corner_radius"), "Corner Radius"); + public static LocalisableString CornerRadius => new TranslatableString(getKey(@"corner_radius"), "Corner radius"); /// /// "How rounded the corners should be." From d98199961b2d0820a3e4ff12816ac1c8e2190004 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Mar 2023 17:00:10 +0900 Subject: [PATCH 492/516] Adjust default sizing to fit a bit better with existing elements --- osu.Game/Screens/Play/HUD/PlayerAvatar.cs | 7 +++++-- osu.Game/Screens/Play/HUD/PlayerFlag.cs | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs index f293199911..1c558aaa8a 100644 --- a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs +++ b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs @@ -28,9 +28,12 @@ namespace osu.Game.Screens.Play.HUD private readonly UpdateableAvatar avatar; + private const float default_size = 80f; + public PlayerAvatar() { - Size = new Vector2(128f); + Size = new Vector2(default_size); + InternalChild = avatar = new UpdateableAvatar(isInteractive: false) { RelativeSizeAxes = Axes.Both, @@ -43,7 +46,7 @@ namespace osu.Game.Screens.Play.HUD base.LoadComplete(); avatar.User = gameplayState.Score.ScoreInfo.User; - CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue * 128f, true); + CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue * default_size, true); } public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Screens/Play/HUD/PlayerFlag.cs b/osu.Game/Screens/Play/HUD/PlayerFlag.cs index 17188d0009..bf65ee23d8 100644 --- a/osu.Game/Screens/Play/HUD/PlayerFlag.cs +++ b/osu.Game/Screens/Play/HUD/PlayerFlag.cs @@ -17,9 +17,11 @@ namespace osu.Game.Screens.Play.HUD private readonly UpdateableFlag flag; + private const float default_size = 40f; + public PlayerFlag() { - Size = new Vector2(114, 80); + Size = new Vector2(default_size, default_size / 1.4f); InternalChild = flag = new UpdateableFlag { RelativeSizeAxes = Axes.Both, From 5e90b67be09b842a9fb4b7114f49e4463afdce52 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Mar 2023 17:01:29 +0900 Subject: [PATCH 493/516] Move `GameplayState` usage to BDL --- osu.Game/Screens/Play/HUD/PlayerFlag.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/PlayerFlag.cs b/osu.Game/Screens/Play/HUD/PlayerFlag.cs index bf65ee23d8..85799c03d3 100644 --- a/osu.Game/Screens/Play/HUD/PlayerFlag.cs +++ b/osu.Game/Screens/Play/HUD/PlayerFlag.cs @@ -12,9 +12,6 @@ namespace osu.Game.Screens.Play.HUD { public partial class PlayerFlag : CompositeDrawable, ISerialisableDrawable { - [Resolved] - private GameplayState gameplayState { get; set; } = null!; - private readonly UpdateableFlag flag; private const float default_size = 40f; @@ -28,10 +25,9 @@ namespace osu.Game.Screens.Play.HUD }; } - protected override void LoadComplete() + [BackgroundDependencyLoader] + private void load(GameplayState gameplayState) { - base.LoadComplete(); - flag.CountryCode = gameplayState.Score.ScoreInfo.User.CountryCode; } From 5af41bb1c81054205c4cb77ccc9b0faf4686288d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Mar 2023 17:24:17 +0900 Subject: [PATCH 494/516] Move filter matching code into own method to simplify early returns --- .../Select/Carousel/CarouselBeatmap.cs | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 2cfa163b7a..7e48bc5cdd 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -26,6 +26,11 @@ namespace osu.Game.Screens.Select.Carousel { base.Filter(criteria); + Filtered.Value = !checkMatch(criteria); + } + + private bool checkMatch(FilterCriteria criteria) + { bool match = criteria.Ruleset == null || BeatmapInfo.Ruleset.ShortName == criteria.Ruleset.ShortName || @@ -34,8 +39,7 @@ namespace osu.Game.Screens.Select.Carousel if (BeatmapInfo.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true) { // only check ruleset equality or convertability for selected beatmap - Filtered.Value = !match; - return; + return match; } match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(BeatmapInfo.StarRating); @@ -49,11 +53,7 @@ namespace osu.Game.Screens.Select.Carousel match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor); match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status); - if (!match) - { - Filtered.Value = !match; - return; - } + if (!match) return false; match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username); match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) || @@ -61,11 +61,7 @@ namespace osu.Game.Screens.Select.Carousel match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating); - if (!match) - { - Filtered.Value = !match; - return; - } + if (!match) return false; if (criteria.SearchTerms.Length > 0) { @@ -99,18 +95,14 @@ namespace osu.Game.Screens.Select.Carousel } } - if (!match) - { - Filtered.Value = !match; - return; - } + if (!match) return false; match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true; if (match && criteria.RulesetCriteria != null) match &= criteria.RulesetCriteria.Matches(BeatmapInfo); - Filtered.Value = !match; + return match; } public override int CompareTo(FilterCriteria criteria, CarouselItem other) From dc2945f4f8635a08c83c84fd57f65c6da4eb8e47 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Mar 2023 17:39:21 +0900 Subject: [PATCH 495/516] Move avatar user loading to BDL also --- osu.Game/Screens/Play/HUD/PlayerAvatar.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs index 1c558aaa8a..e3fab499f3 100644 --- a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs +++ b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs @@ -23,9 +23,6 @@ namespace osu.Game.Screens.Play.HUD Precision = 0.01f }; - [Resolved] - private GameplayState gameplayState { get; set; } = null!; - private readonly UpdateableAvatar avatar; private const float default_size = 80f; @@ -41,11 +38,16 @@ namespace osu.Game.Screens.Play.HUD }; } + [BackgroundDependencyLoader] + private void load(GameplayState gameplayState) + { + avatar.User = gameplayState.Score.ScoreInfo.User; + } + protected override void LoadComplete() { base.LoadComplete(); - avatar.User = gameplayState.Score.ScoreInfo.User; CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue * default_size, true); } From 55467fcbe35cc6c8c7a94740c372b665eaa77519 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Mar 2023 18:00:37 +0900 Subject: [PATCH 496/516] Update xmldoc for `DangerousActionDialog` to match new behaviour --- osu.Game/Overlays/Dialog/DangerousActionDialog.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Dialog/DangerousActionDialog.cs b/osu.Game/Overlays/Dialog/DangerousActionDialog.cs index 85cae5e0d2..c86570386f 100644 --- a/osu.Game/Overlays/Dialog/DangerousActionDialog.cs +++ b/osu.Game/Overlays/Dialog/DangerousActionDialog.cs @@ -8,10 +8,14 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Dialog { /// - /// Base class for various confirmation dialogs that concern deletion actions. + /// A dialog which provides confirmation for actions which result in permanent consequences. /// Differs from in that the confirmation button is a "dangerous" one /// (requires the confirm button to be held). /// + /// + /// The default implementation comes with text for a generic deletion operation. + /// This can be further customised by specifying custom . + /// public abstract partial class DangerousActionDialog : PopupDialog { /// From 26ef7c2637ddde346c65ff6bd853a48c03d5863e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Mar 2023 18:01:13 +0900 Subject: [PATCH 497/516] Rename confirmation dialog class to mention `revert` not `reset` --- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index a7fe459aa4..c6d190502b 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -153,7 +153,7 @@ namespace osu.Game.Overlays.SkinEditor Items = new[] { new EditorMenuItem(Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), - new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, () => dialogOverlay?.Push(new ResetConfirmDialog(revert))), + new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, () => dialogOverlay?.Push(new RevertConfirmDialog(revert))), new EditorMenuItemSpacer(), new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()), }, @@ -630,9 +630,9 @@ namespace osu.Game.Overlays.SkinEditor } } - public partial class ResetConfirmDialog : DangerousActionDialog + public partial class RevertConfirmDialog : DangerousActionDialog { - public ResetConfirmDialog(Action revert) + public RevertConfirmDialog(Action revert) { HeaderText = SkinEditorStrings.RevertToDefaultDescription; BodyText = SkinEditorStrings.ResetDialogue; From 97bee4db89048419265aeb9a1a6c9ffa478cc68a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Mar 2023 18:07:53 +0900 Subject: [PATCH 498/516] Fix localisations --- osu.Game/Localisation/SkinEditorStrings.cs | 9 ++------- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game/Localisation/SkinEditorStrings.cs b/osu.Game/Localisation/SkinEditorStrings.cs index a6b59418fd..3c1d1ff40d 100644 --- a/osu.Game/Localisation/SkinEditorStrings.cs +++ b/osu.Game/Localisation/SkinEditorStrings.cs @@ -45,14 +45,9 @@ namespace osu.Game.Localisation public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), @"Currently editing"); /// - /// "Revert to default." + /// "All layout elements for layers in the current screen will be reset to defaults." /// - public static LocalisableString RevertToDefaultDescription => new TranslatableString(getKey(@"revert_to_default"), @"Revert to default."); - - /// - /// "Return the skin to its default state" - /// - public static LocalisableString ResetDialogue => new TranslatableString(getKey(@"return_the_skin_to_its"), @"Return the skin to its default state"); + public static LocalisableString RevertToDefaultDescription => new TranslatableString(getKey(@"revert_to_default_description"), @"All layout elements for layers in the current screen will be reset to defaults."); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index c6d190502b..ac40d1335e 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -634,8 +634,8 @@ namespace osu.Game.Overlays.SkinEditor { public RevertConfirmDialog(Action revert) { - HeaderText = SkinEditorStrings.RevertToDefaultDescription; - BodyText = SkinEditorStrings.ResetDialogue; + HeaderText = CommonStrings.RevertToDefault; + BodyText = SkinEditorStrings.RevertToDefaultDescription; DangerousAction = revert; } } From 5191204569241e0e92c93b51681a9384d711a019 Mon Sep 17 00:00:00 2001 From: Cootz Date: Tue, 7 Mar 2023 15:39:43 +0300 Subject: [PATCH 499/516] Bring truncating logic back to `Export` method --- osu.Game/Database/LegacyExporter.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 0fa7b9e03c..9981e08442 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -48,15 +48,7 @@ namespace osu.Game.Database UserFileStorage = storage.GetStorageForDirectory(@"files"); } - protected virtual string GetFilename(TModel item) - { - string filename = item.GetDisplayString(); - - if (filename.Length > MAX_FILENAME_LENGTH - FileExtension.Length) - return filename.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); - - return filename; - } + protected virtual string GetFilename(TModel item) => item.GetDisplayString(); /// /// Exports an item to a legacy (.zip based) package. @@ -73,6 +65,14 @@ namespace osu.Game.Database string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}"); + if (filename.Length > MAX_FILENAME_LENGTH) + { + string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename); + + filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); + filename = $"{filenameWithoutExtension}{FileExtension}"; + } + using (var stream = exportStorage.CreateFileSafely(filename)) ExportModelTo(item, stream); From 7107834b9ec297062ff29442fa1a550c03ff5a94 Mon Sep 17 00:00:00 2001 From: Cootz Date: Tue, 7 Mar 2023 15:43:03 +0300 Subject: [PATCH 500/516] Fix truncating bug --- osu.Game/Database/LegacyExporter.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 9981e08442..8da285daa3 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -58,6 +58,9 @@ namespace osu.Game.Database { string itemFilename = GetFilename(item).GetValidFilename(); + if (itemFilename.Length > MAX_FILENAME_LENGTH - FileExtension.Length) + itemFilename = itemFilename.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); + IEnumerable existingExports = exportStorage .GetFiles(string.Empty, $"{itemFilename}*{FileExtension}") @@ -65,14 +68,6 @@ namespace osu.Game.Database string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}"); - if (filename.Length > MAX_FILENAME_LENGTH) - { - string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename); - - filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); - filename = $"{filenameWithoutExtension}{FileExtension}"; - } - using (var stream = exportStorage.CreateFileSafely(filename)) ExportModelTo(item, stream); From 7ade525eef4a3c887de1d50123682140ee9c605a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 7 Mar 2023 19:43:52 +0100 Subject: [PATCH 501/516] Display corner radius setting as percentage --- .../Settings/SettingsPercentageSlider.cs | 20 +++++++++++++++++++ .../Rulesets/Mods/ModAccuracyChallenge.cs | 11 +--------- osu.Game/Screens/Play/HUD/PlayerAvatar.cs | 4 +++- 3 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Overlays/Settings/SettingsPercentageSlider.cs diff --git a/osu.Game/Overlays/Settings/SettingsPercentageSlider.cs b/osu.Game/Overlays/Settings/SettingsPercentageSlider.cs new file mode 100644 index 0000000000..fa59d18de1 --- /dev/null +++ b/osu.Game/Overlays/Settings/SettingsPercentageSlider.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Graphics; +using osu.Game.Configuration; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Settings +{ + /// + /// A that displays its value as a percentage by default. + /// Mostly provided for convenience of use with . + /// + public partial class SettingsPercentageSlider : SettingsSlider + where TValue : struct, IEquatable, IComparable, IConvertible + { + protected override Drawable CreateControl() => ((RoundedSliderBar)base.CreateControl()).With(sliderBar => sliderBar.DisplayAsPercentage = true); + } +} diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index dc7594f469..d4223a80c2 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -7,7 +7,6 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Judgements; @@ -33,7 +32,7 @@ namespace osu.Game.Rulesets.Mods public override string SettingDescription => base.SettingDescription.Replace(MinimumAccuracy.ToString(), MinimumAccuracy.Value.ToString("##%", NumberFormatInfo.InvariantInfo)); - [SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsSlider))] + [SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsPercentageSlider))] public BindableNumber MinimumAccuracy { get; } = new BindableDouble { MinValue = 0.60, @@ -69,12 +68,4 @@ namespace osu.Game.Rulesets.Mods return scoreProcessor.ComputeAccuracy(score); } } - - public partial class PercentSlider : RoundedSliderBar - { - public PercentSlider() - { - DisplayAsPercentage = true; - } - } } diff --git a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs index e3fab499f3..1d0331593a 100644 --- a/osu.Game/Screens/Play/HUD/PlayerAvatar.cs +++ b/osu.Game/Screens/Play/HUD/PlayerAvatar.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; using osu.Game.Localisation.SkinComponents; +using osu.Game.Overlays.Settings; using osu.Game.Skinning; using osu.Game.Users.Drawables; using osuTK; @@ -15,7 +16,8 @@ namespace osu.Game.Screens.Play.HUD { public partial class PlayerAvatar : CompositeDrawable, ISerialisableDrawable { - [SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.CornerRadius), nameof(SkinnableComponentStrings.CornerRadiusDescription))] + [SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.CornerRadius), nameof(SkinnableComponentStrings.CornerRadiusDescription), + SettingControlType = typeof(SettingsPercentageSlider))] public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0.25f) { MinValue = 0, From 686259a33c62aed9ce227001f8cedccdf3031f56 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Wed, 8 Mar 2023 13:57:20 -0300 Subject: [PATCH 502/516] Make support badge in list match groups --- osu.Game/Users/UserListPanel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Users/UserListPanel.cs b/osu.Game/Users/UserListPanel.cs index 9b5b0e9f6d..3047e70a1a 100644 --- a/osu.Game/Users/UserListPanel.cs +++ b/osu.Game/Users/UserListPanel.cs @@ -67,6 +67,7 @@ namespace osu.Game.Users { username.Anchor = Anchor.CentreLeft; username.Origin = Anchor.CentreLeft; + username.UseFullGlyphHeight = false; }) } }, @@ -111,7 +112,7 @@ namespace osu.Game.Users { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Height = 20, + Height = 16, SupportLevel = User.SupportLevel }); } From 430b09acb211f1b8ab44c7e889d7b2d22cc7ea0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 8 Mar 2023 22:52:06 +0100 Subject: [PATCH 503/516] Expose taiko input manager in same manner as osu! --- osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs | 2 +- osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs index fa876555e1..a5cffca06f 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSingleTap.cs @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Taiko.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { ruleset = (DrawableTaikoRuleset)drawableRuleset; - ruleset.InputManager.Add(new InputInterceptor(this)); + ruleset.KeyBindingInputManager.Add(new InputInterceptor(this)); playfield = (TaikoPlayfield)ruleset.Playfield; var periods = new List(); diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 5390d3b138..a08877e2dd 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Taiko.UI public readonly BindableBool LockPlayfieldMaxAspect = new BindableBool(true); - public TaikoInputManager InputManager { get; private set; } + public new TaikoInputManager KeyBindingInputManager => (TaikoInputManager)base.KeyBindingInputManager; protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Taiko.UI LockPlayfieldMaxAspect = { BindTarget = LockPlayfieldMaxAspect } }; - protected override PassThroughInputManager CreateInputManager() => InputManager = new TaikoInputManager(Ruleset.RulesetInfo); + protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo); protected override Playfield CreatePlayfield() => new TaikoPlayfield(); From febdca45470f34a7cdfc493cddc13f371593099c Mon Sep 17 00:00:00 2001 From: Derrick Timmermans Date: Sun, 12 Mar 2023 02:08:00 +0100 Subject: [PATCH 504/516] Fix argon progress bar fill being oversized --- osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs index 6db1072fbb..dd6e10ba5d 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -242,7 +242,6 @@ namespace osu.Game.Screens.Play.HUD { length = value; mask.Width = value * DrawWidth; - fill.Width = value * DrawWidth; } } From 0cf69a10846b59934a837d3a39b43c812092f848 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 11 Mar 2023 21:35:52 -0800 Subject: [PATCH 505/516] Make yaml line strings verbatim --- osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs index 5f8bee7558..8dc058bd69 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -30,11 +30,11 @@ namespace osu.Game.Overlays.Wiki.Markdown { switch (line.ToString()) { - case "outdated: true": + case @"outdated: true": isOutdated = true; break; - case "needs_cleanup: true": + case @"needs_cleanup: true": needsCleanup = true; break; } From ea88aee41f27491d4022c5bb38a4661f55661e3c Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 11 Mar 2023 21:36:15 -0800 Subject: [PATCH 506/516] Display stub notice in marked wiki articles --- .../Overlays/Wiki/Markdown/WikiNoticeContainer.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs index 8dc058bd69..df800f47b1 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -19,6 +19,7 @@ namespace osu.Game.Overlays.Wiki.Markdown { private readonly bool isOutdated; private readonly bool needsCleanup; + private readonly bool isStub; public WikiNoticeContainer(YamlFrontMatterBlock yamlFrontMatterBlock) { @@ -37,6 +38,10 @@ namespace osu.Game.Overlays.Wiki.Markdown case @"needs_cleanup: true": needsCleanup = true; break; + + case @"stub: true": + isStub = true; + break; } } } @@ -60,6 +65,14 @@ namespace osu.Game.Overlays.Wiki.Markdown Text = WikiStrings.ShowNeedsCleanupOrRewrite, }); } + + if (isStub) + { + Add(new NoticeBox + { + Text = WikiStrings.ShowStub, + }); + } } private partial class NoticeBox : Container From 6e5b1280b7261d37e89a494b973f35905099d630 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 11 Mar 2023 21:18:56 -0800 Subject: [PATCH 507/516] Fix multiple notice boxes having no spacing --- osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs index df800f47b1..a40bd14878 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Resources.Localisation.Web; +using osuTK; namespace osu.Game.Overlays.Wiki.Markdown { @@ -26,6 +27,7 @@ namespace osu.Game.Overlays.Wiki.Markdown RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Direction = FillDirection.Vertical; + Spacing = new Vector2(10); foreach (object line in yamlFrontMatterBlock.Lines) { From c1618a7a16f923cf57f891150d19fd9afde06aa7 Mon Sep 17 00:00:00 2001 From: Rovearix Date: Sun, 12 Mar 2023 10:57:53 -0400 Subject: [PATCH 508/516] Prevent elements that are anchored in the center from blocking loading --- osu.Game/Graphics/UserInterface/LoadingLayer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 9059b61a33..7cd54304b7 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -69,6 +69,10 @@ namespace osu.Game.Graphics.UserInterface // note that this will not work well if touch handling elements are beneath this loading layer (something to consider for the future). case TouchEvent: return false; + + // blocking drag events to prevent unintended ui pausing while loading a beat map (see https://github.com/ppy/osu/issues/22657) + case DragEvent: + return false; } return true; From 1f7721786b02d628d2b2c7c1d16c83b2d1a4a170 Mon Sep 17 00:00:00 2001 From: rozukke Date: Mon, 13 Mar 2023 22:01:26 +1100 Subject: [PATCH 509/516] Perform check to account for non-ASCII characters --- osu.Game/Skinning/SkinImporter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index 9e2e02876d..43760c4a19 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -101,7 +101,8 @@ namespace osu.Game.Skinning // In both of these cases, the expectation from the user is that the filename or folder name is displayed somewhere to identify the skin. if (archiveName != item.Name // lazer exports use this format - && archiveName != item.GetDisplayString()) + // GetValidFilename accounts for skins with non-ASCII characters in the name that have been exported by lazer. + && archiveName != item.GetDisplayString().GetValidFilename()) item.Name = @$"{item.Name} [{archiveName}]"; } From ba728bdab1b4662366e3737fd4f84cf413e2d0e1 Mon Sep 17 00:00:00 2001 From: Rovearix Date: Mon, 13 Mar 2023 07:49:51 -0400 Subject: [PATCH 510/516] Changed the event to be the more correct one to block --- osu.Game/Graphics/UserInterface/LoadingLayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 7cd54304b7..3f9856eddd 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -71,7 +71,7 @@ namespace osu.Game.Graphics.UserInterface return false; // blocking drag events to prevent unintended ui pausing while loading a beat map (see https://github.com/ppy/osu/issues/22657) - case DragEvent: + case DragStartEvent: return false; } From 9ac9287dbd89051a685d9821cbbf951bdef37d7d Mon Sep 17 00:00:00 2001 From: Rovearix Date: Mon, 13 Mar 2023 08:07:55 -0400 Subject: [PATCH 511/516] Switched the implementation to set the blockInput flag for the BeatmapMetadataDisplay's LoadingLayer. This prevents the UIEvents from being being handled in this case without modifying the class --- osu.Game/Graphics/UserInterface/LoadingLayer.cs | 4 ---- osu.Game/Screens/Play/BeatmapMetadataDisplay.cs | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 3f9856eddd..9059b61a33 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -69,10 +69,6 @@ namespace osu.Game.Graphics.UserInterface // note that this will not work well if touch handling elements are beneath this loading layer (something to consider for the future). case TouchEvent: return false; - - // blocking drag events to prevent unintended ui pausing while loading a beat map (see https://github.com/ppy/osu/issues/22657) - case DragStartEvent: - return false; } return true; diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 06509b6465..a152f4be19 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -114,7 +114,7 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, FillMode = FillMode.Fill, }, - loading = new LoadingLayer(true) + loading = new LoadingLayer(dimBackground: true, blockInput: false) } }, versionFlow = new FillFlowContainer From 4570c0030f1211bc166eff6be86ced372c1e0907 Mon Sep 17 00:00:00 2001 From: rozukke Date: Mon, 13 Mar 2023 23:37:45 +1100 Subject: [PATCH 512/516] Add test to check for import of exported skin with non-ASCII name --- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index 0bd40e9962..81ebc59729 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -133,6 +133,25 @@ namespace osu.Game.Tests.Skins.IO assertImportedOnce(import1, import2); }); + [Test] + public Task TestImportExportedNonAsciiSkinFilename() => runSkinTest(async osu => + { + MemoryStream exportStream = new MemoryStream(); + + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 『1』", "author 1"), "custom.osk")); + assertCorrectMetadata(import1, "name 『1』 [custom]", "author 1", osu); + + import1.PerformRead(s => + { + new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream); + }); + + string exportFilename = import1.GetDisplayString().GetValidFilename(); + + var import2 = await loadSkinIntoOsu(osu, new ImportTask(exportStream, $"{exportFilename}.osk")); + assertCorrectMetadata(import2, "name 『1』 [custom]", "author 1", osu); + }); + [Test] public Task TestSameMetadataNameSameFolderName([Values] bool batchImport) => runSkinTest(async osu => { From 48d11610b344ac23dd0ff3628b90ee4b4b40402d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Mar 2023 17:44:51 +0900 Subject: [PATCH 513/516] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 234575fc62..4e580a6919 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -11,7 +11,7 @@ manifestmerger.jar - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 103ac99172..a84b42d9a4 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index fde45817cf..8738979c57 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -16,6 +16,6 @@ iossimulator-x64 - + From 0b23809585d73617942c7f5a0edebfcab2ca02ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Mar 2023 17:52:17 +0900 Subject: [PATCH 514/516] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a84b42d9a4..c08dc9ed8f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + From d65d09e45f9c02186bec88fcb9ab01867ead71b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Mar 2023 20:24:39 +0900 Subject: [PATCH 515/516] Change field to `const` --- osu.Game/Graphics/Backgrounds/Triangles.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 5b7b94ff4c..28a715ca0b 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -252,7 +252,7 @@ namespace osu.Game.Graphics.Backgrounds private class TrianglesDrawNode : DrawNode { - private float fill = 1f; + private const float fill = 1f; protected new Triangles Source => (Triangles)base.Source; From b5ea855b6cf8ff9faa5659c1a2e6f4e41b5f5739 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Mar 2023 20:37:50 +0900 Subject: [PATCH 516/516] Fix failing `DrawableRulesetDependencies` test --- .../Rulesets/TestSceneDrawableRulesetDependencies.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs index 5cfcca303f..f8248e88bb 100644 --- a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs +++ b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Rulesets dependencies.CacheAs(ParentTextureStore = new TestTextureStore(parent.Get().Renderer)); dependencies.CacheAs(ParentSampleStore = new TestSampleStore()); - dependencies.CacheAs(ParentShaderManager = new TestShaderManager(parent.Get().Renderer)); + dependencies.CacheAs(ParentShaderManager = new TestShaderManager(parent.Get().Renderer, parent.Get())); return new DrawableRulesetDependencies(new OsuRuleset(), dependencies); } @@ -156,12 +156,15 @@ namespace osu.Game.Tests.Rulesets private class TestShaderManager : ShaderManager { - public TestShaderManager(IRenderer renderer) + private readonly ShaderManager parentManager; + + public TestShaderManager(IRenderer renderer, ShaderManager parentManager) : base(renderer, new ResourceStore()) { + this.parentManager = parentManager; } - public override byte[] LoadRaw(string name) => null; + public override byte[] LoadRaw(string name) => parentManager.LoadRaw(name); public bool IsDisposed { get; private set; }